Skip to content

Commit

Permalink
refactor: minor improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
hermanwikner committed Oct 9, 2023
1 parent 58fe5b3 commit 0e51065
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react/jsx-handler-names */
import React, {useMemo} from 'react'
import React from 'react'
import {useString} from '@sanity/ui-workshop'
import {useCurrentUser} from '../../store'
import {CommentsList} from '../components'
Expand All @@ -10,19 +10,8 @@ export default function CommentsProviderStory() {
const _type = useString('_type', 'author') || 'author'
const _id = useString('_id', 'grrm') || 'grrm'

const documentValue = useMemo(
() => ({
_id,
_type,
_createdAt: '2021-01-01T00:00:00Z',
_updatedAt: '2021-01-01T00:00:00Z',
_rev: '',
}),
[_id, _type],
)

return (
<CommentsProvider documentValue={documentValue}>
<CommentsProvider documentType={_type} documentId={_id}>
<Inner />
</CommentsProvider>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ interface CommentsListItemProps {
replies: CommentDocument[] | undefined
}

export function CommentsListItem(props: CommentsListItemProps) {
export const CommentsListItem = React.memo(function CommentsListItem(props: CommentsListItemProps) {
const {
canReply,
currentUser,
Expand Down Expand Up @@ -214,4 +214,4 @@ export function CommentsListItem(props: CommentsListItemProps) {
</StyledThreadCard>
</Stack>
)
}
})
198 changes: 115 additions & 83 deletions packages/sanity/src/core/comments/context/CommentsProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, {memo, useCallback, useMemo, useState} from 'react'
import {SanityDocument} from '@sanity/client'
import {orderBy} from 'lodash'
import {CommentStatus, CommentsContextValue} from '../types'
import {CommentStatus, CommentThreadItem, CommentsContextValue} from '../types'
import {useCommentOperations, useCommentsEnabled, useMentionOptions} from '../hooks'
import {useCommentsStore} from '../store'
import {useSchema} from '../../hooks'
import {useEditState, useSchema} from '../../hooks'
import {useCurrentUser} from '../../store'
import {useWorkspace} from '../../studio'
import {getPublishedId} from '../../util'
Expand All @@ -18,13 +17,19 @@ const EMPTY_COMMENTS_DATA = {
resolved: EMPTY_ARRAY,
}

interface ThreadItemsByStatus {
open: CommentThreadItem[]
resolved: CommentThreadItem[]
}

/**
* @beta
* @hidden
*/
export interface CommentsProviderProps {
children: React.ReactNode
documentValue: SanityDocument
documentId: string
documentType: string
}

const EMPTY_COMMENTS = {
Expand Down Expand Up @@ -64,11 +69,11 @@ const COMMENTS_DISABLED_CONTEXT: CommentsContextValue = {
* @hidden
*/
export const CommentsProvider = memo(function CommentsProvider(props: CommentsProviderProps) {
const {children, documentValue} = props
const {children, documentId, documentType} = props

const {isEnabled} = useCommentsEnabled({
documentId: documentValue._id,
documentType: documentValue._type,
documentId,
documentType,
})

if (!isEnabled) {
Expand All @@ -82,90 +87,117 @@ export const CommentsProvider = memo(function CommentsProvider(props: CommentsPr
return <CommentsProviderInner {...props} />
})

const EMPTY = {}
const CommentsProviderInner = memo(function CommentsProviderInner(
props: Omit<CommentsProviderProps, 'enabled'>,
) {
const {children, documentId, documentType} = props

const publishedId = getPublishedId(documentId)
const editState = useEditState(publishedId, documentType, 'low')

function CommentsProviderInner(props: Omit<CommentsProviderProps, 'enabled'>) {
const {children, documentValue} = props
const {_id: documentId, _type: documentType} = documentValue || EMPTY
const documentValue = useMemo(() => {
return editState.draft || editState.published
}, [editState.draft, editState.published])

const [status, setStatus] = useState<CommentStatus>('open')

const {dispatch, data = EMPTY_ARRAY, error, loading} = useCommentsStore({documentId})
const mentionOptions = useMentionOptions({documentValue})
const {
dispatch,
data = EMPTY_ARRAY,
error,
loading,
} = useCommentsStore(useMemo(() => ({documentId: publishedId}), [publishedId]))

const mentionOptions = useMentionOptions(useMemo(() => ({documentValue}), [documentValue]))

const schemaType = useSchema().get(documentType)
const currentUser = useCurrentUser()
const {name: workspaceName, dataset, projectId} = useWorkspace()

const {operation} = useCommentOperations({
currentUser,
dataset,
documentId: getPublishedId(documentId),
documentType,
projectId,
schemaType,
workspace: workspaceName,

// The following callbacks runs when the comment operations are executed.
// They are used to update the local state of the comments immediately after
// a comment operation has been executed. This is done to avoid waiting for
// the real time listener to update the comments and make the UI feel more
// responsive. The comment will be updated again when we receive an mutation
// event from the real time listener.

onCreate: (payload) => {
// If the comment we try to create already exists in the local state and has
// the 'createError' state, we know that we are retrying a comment creation.
// In that case, we want to change the state to 'createRetrying'.
const hasError = data?.find((c) => c._id === payload._id)?._state?.type === 'createError'

dispatch({
type: 'COMMENT_ADDED',
payload: {
...payload,
_state: hasError ? {type: 'createRetrying'} : undefined,
const {operation} = useCommentOperations(
useMemo(
() => ({
currentUser,
dataset,
documentId: publishedId,
documentType,
projectId,
schemaType,
workspace: workspaceName,

// The following callbacks runs when the comment operations are executed.
// They are used to update the local state of the comments immediately after
// a comment operation has been executed. This is done to avoid waiting for
// the real time listener to update the comments and make the UI feel more
// responsive. The comment will be updated again when we receive an mutation
// event from the real time listener.

onCreate: (payload) => {
// If the comment we try to create already exists in the local state and has
// the 'createError' state, we know that we are retrying a comment creation.
// In that case, we want to change the state to 'createRetrying'.
const hasError = data?.find((c) => c._id === payload._id)?._state?.type === 'createError'

dispatch({
type: 'COMMENT_ADDED',
payload: {
...payload,
_state: hasError ? {type: 'createRetrying'} : undefined,
},
})
},
})
},

// When an error occurs during comment creation, we update the comment state
// to `createError`. This will make the comment appear in the UI as a comment
// that failed to be created. The user can then retry the comment creation.
onCreateError: (id, err) => {
dispatch({
type: 'COMMENT_UPDATED',
payload: {
_id: id,
_state: {
error: err,
type: 'createError',
},

// When an error occurs during comment creation, we update the comment state
// to `createError`. This will make the comment appear in the UI as a comment
// that failed to be created. The user can then retry the comment creation.
onCreateError: (id, err) => {
dispatch({
type: 'COMMENT_UPDATED',
payload: {
_id: id,
_state: {
error: err,
type: 'createError',
},
},
})
},
})
},

onEdit: (id, payload) => {
dispatch({
type: 'COMMENT_UPDATED',
payload: {
_id: id,
...payload,

onEdit: (id, payload) => {
dispatch({
type: 'COMMENT_UPDATED',
payload: {
_id: id,
...payload,
},
})
},
})
},

onUpdate: (id, payload) => {
dispatch({
type: 'COMMENT_UPDATED',
payload: {
_id: id,
...payload,

onUpdate: (id, payload) => {
dispatch({
type: 'COMMENT_UPDATED',
payload: {
_id: id,
...payload,
},
})
},
})
},
})
}),
[
currentUser,
data,
dataset,
dispatch,
documentType,
projectId,
publishedId,
schemaType,
workspaceName,
],
),
)

const threadItemsByStatus = useMemo(() => {
const threadItemsByStatus: ThreadItemsByStatus = useMemo(() => {
if (!schemaType || !currentUser) return EMPTY_COMMENTS_DATA

// Since we only make one query to get all comments using the order `_createdAt desc` – we
Expand Down Expand Up @@ -216,18 +248,18 @@ function CommentsProviderInner(props: Omit<CommentsProviderProps, 'enabled'>) {
mentionOptions,
}) satisfies CommentsContextValue,
[
error,
status,
getComment,
threadItemsByStatus,
error,
loading,
mentionOptions,
operation.create,
operation.edit,
operation.remove,
operation.edit,
operation.update,
status,
threadItemsByStatus,
mentionOptions,
],
)

return <CommentsContext.Provider value={ctxValue}>{children}</CommentsContext.Provider>
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const INITIAL_STATE: MentionOptionsHookValue = {
}

interface MentionHookOptions {
documentValue: SanityDocument
documentValue: SanityDocument | null
}

export function useMentionOptions(opts: MentionHookOptions): MentionOptionsHookValue {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Flex} from '@sanity/ui'
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'
import React, {Fragment, useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {Path} from '@sanity/types'
import {useDocumentPane} from '../../panes/document/useDocumentPane'
import {usePaneRouter} from '../../components'
Expand Down Expand Up @@ -149,7 +149,7 @@ export function CommentsInspector(props: DocumentInspectorProps) {
)

return (
<>
<Fragment>
{commentToDelete && showDeleteDialog && (
<CommentDeleteDialog
{...commentToDelete}
Expand Down Expand Up @@ -182,6 +182,6 @@ export function CommentsInspector(props: DocumentInspectorProps) {
/>
)}
</Flex>
</>
</Fragment>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,9 @@ export const DocumentPaneProvider = memo((props: DocumentPaneProviderProps) => {
)}

<FieldActionsProvider actions={rootFieldActionNodes} path={EMPTY_ARRAY}>
<CommentsProvider documentValue={displayed as SanityDocument}>{children}</CommentsProvider>
<CommentsProvider documentId={documentId} documentType={documentType}>
{children}
</CommentsProvider>
</FieldActionsProvider>
</DocumentPaneContext.Provider>
)
Expand Down

0 comments on commit 0e51065

Please sign in to comment.