Skip to content

Commit

Permalink
feat: implement comment discard logic
Browse files Browse the repository at this point in the history
  • Loading branch information
hermanwikner committed Oct 30, 2023
1 parent a1c2b05 commit 02eecfc
Show file tree
Hide file tree
Showing 14 changed files with 392 additions and 215 deletions.
45 changes: 13 additions & 32 deletions packages/sanity/src/desk/comments/plugin/field/CommentField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,13 @@ function CommentFieldInner(props: FieldProps) {
setStatus('open')
}

if (hasComments) {
setOpen(false)
openInspector(COMMENTS_INSPECTOR_NAME)
} else {
setOpen((v) => !v)
}

// If the field has comments, we want to open the inspector, scroll to the comment
// thread and set the path as selected so that the comment is highlighted when the
// user clicks the button.
Expand All @@ -152,6 +159,7 @@ function CommentFieldInner(props: FieldProps) {
status,
currentThreadId,
setStatus,
openInspector,
handleScrollToThread,
setSelectedPath,
props.path,
Expand Down Expand Up @@ -210,7 +218,7 @@ function CommentFieldInner(props: FieldProps) {
value,
])

const handleEditDiscard = useCallback(() => setValue(null), [])
const handleDiscard = useCallback(() => setValue(null), [])

useEffect(() => {
if (currentThreadId) {
Expand All @@ -229,23 +237,6 @@ function CommentFieldInner(props: FieldProps) {
}
}, [boundaryElement, isSelected, props.path, selectedPath])

// Give the user a way to deselect the path by clicking outside the field
// to get rid of the highlight.
useClickOutside(() => {
if (isSelected) {
setSelectedPath(null)
}
}, [rootElementRef.current])

useEffect(() => {
return () => {
// Clear the selected path when the field is unmounted
setSelectedPath(null)
}
// Intentionally omitting `setSelectedPath` from the deps array
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

useEffect(() => {
const showHighlight = inView && isSelected

Expand All @@ -267,26 +258,16 @@ function CommentFieldInner(props: FieldProps) {
onChange={setValue}
onClick={handleClick}
onCommentAdd={handleCommentAdd}
onDiscardEdit={handleEditDiscard}
onOpenChange={setOpen}
openInspector={handleOpenInspector}
onDiscard={handleDiscard}
open={open}
setOpen={setOpen}
value={value}
/>
),
hasComments,
isAddingComment: open,
}),
[
currentUser,
count,
hasComments,
handleClick,
handleCommentAdd,
handleEditDiscard,
handleOpenInspector,
value,
open,
],
[currentUser, count, hasComments, handleClick, handleCommentAdd, handleDiscard, value, open],
)

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useState} from 'react'
import React, {useCallback, useEffect, useRef, useState} from 'react'
import {
Box,
Button,
Expand All @@ -9,12 +9,11 @@ import {
Tooltip,
TooltipProps,
useClickOutside,
useGlobalKeyDown,
} from '@sanity/ui'
import styled, {css} from 'styled-components'
import {CommentIcon} from '../common/CommentIcon'
import {CommentMessage, useComments, CommentInput} from '../../src'
import {CurrentUser, PortableTextBlock, useDidUpdate} from 'sanity'
import {CommentMessage, useComments, CommentInput, CommentInputHandle} from '../../src'
import {CurrentUser, PortableTextBlock} from 'sanity'

const TOOLTIP_DELAY: TooltipProps['delay'] = {open: 500}

Expand Down Expand Up @@ -48,64 +47,47 @@ interface CommentFieldButtonProps {
onChange: (value: PortableTextBlock[]) => void
onClick?: () => void
onCommentAdd: () => void
onDiscardEdit: () => void
onOpenChange: (open: boolean) => void
openInspector: () => void
onDiscard: () => void
open: boolean
setOpen: (open: boolean) => void
value: CommentMessage
}

export function CommentFieldButton(props: CommentFieldButtonProps) {
const {
count,
currentUser,
onChange,
onClick,
onCommentAdd,
onDiscardEdit,
onOpenChange,
openInspector,
value,
} = props
const {count, currentUser, onChange, onClick, onCommentAdd, onDiscard, value, open, setOpen} =
props
const [mentionMenuOpen, setMentionMenuOpen] = useState<boolean>(false)
const [open, setOpen] = useState<boolean>(false)
const [popoverElement, setPopoverElement] = useState<HTMLDivElement | null>(null)

const commentInputHandle = useRef<CommentInputHandle | null>(null)
const {mentionOptions} = useComments()

const hasComments = Boolean(count > 0)

const close = useCallback(() => setOpen(false), [])

const conditionalClose = useCallback(() => {
if (mentionMenuOpen) return
close()
}, [close, mentionMenuOpen])

const handleClick = useCallback(() => {
onClick?.()

if (hasComments) {
openInspector()
setOpen(false)
return
}
setOpen((prev) => !prev)
}, [hasComments, onClick, openInspector])
const closePopover = useCallback(() => setOpen(false), [setOpen])

const handleSubmit = useCallback(() => {
onCommentAdd()
close()
}, [close, onCommentAdd])
closePopover()
}, [closePopover, onCommentAdd])

useDidUpdate(open, () => onOpenChange?.(open))
const startDiscard = useCallback(() => {
commentInputHandle.current?.discardController.start().callback((needsConfirm) => {
if (needsConfirm || mentionMenuOpen) return
closePopover()
})
}, [closePopover, mentionMenuOpen])

useClickOutside(conditionalClose, [popoverElement])
const handleDiscardCancel = useCallback(() => {
commentInputHandle.current?.discardController.cancel()
}, [])

useGlobalKeyDown((event) => {
if (event.key === 'Escape') {
conditionalClose()
}
})
const handleDiscardConfirm = useCallback(() => {
commentInputHandle.current?.discardController.confirm().callback(() => {
closePopover()
onDiscard()
})
}, [closePopover, onDiscard])

useClickOutside(startDiscard, [popoverElement])

if (!hasComments) {
const content = (
Expand All @@ -116,9 +98,12 @@ export function CommentFieldButton(props: CommentFieldButtonProps) {
focusOnMount
mentionOptions={mentionOptions}
onChange={onChange}
onEditDiscard={onDiscardEdit}
onDiscardCancel={handleDiscardCancel}
onDiscardConfirm={handleDiscardConfirm}
onEscapeKeyDown={startDiscard}
onMentionMenuOpenChange={setMentionMenuOpen}
onSubmit={handleSubmit}
ref={commentInputHandle}
value={value}
/>
</ContentStack>
Expand Down Expand Up @@ -151,7 +136,7 @@ export function CommentFieldButton(props: CommentFieldButtonProps) {
fontSize={1}
icon={CommentIcon}
mode="bleed"
onClick={handleClick}
onClick={onClick}
padding={2}
selected={open}
/>
Expand All @@ -173,7 +158,7 @@ export function CommentFieldButton(props: CommentFieldButtonProps) {
delay={TOOLTIP_DELAY}
fallbackPlacements={['bottom']}
>
<Button aria-label="Open comments" mode="bleed" onClick={handleClick} padding={2}>
<Button aria-label="Open comments" mode="bleed" onClick={onClick} padding={2}>
<Flex align="center" gap={2}>
<Text size={1}>
<CommentIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export function CommentsInspector(props: DocumentInspectorProps) {
setCommentToDelete(null)
}, [deleteLoading])

const handlePathFocus = useCallback(
const handlePathSelect = useCallback(
(path: Path) => {
onPathOpen(path)
setSelectedPath({
Expand Down Expand Up @@ -251,7 +251,7 @@ export function CommentsInspector(props: DocumentInspectorProps) {
onDelete={onDeleteStart}
onEdit={handleEdit}
onNewThreadCreate={handleNewThreadCreate}
onPathFocus={handlePathFocus}
onPathSelect={handlePathSelect}
onReply={handleReply}
onStatusChange={handleStatusChange}
ref={commentsListHandleRef}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import {CommentInput} from '../components'
import {CommentMessageSerializer} from '../components/pte'
import {useCurrentUser} from 'sanity'

const noop = () => {
// ...
}

export default function CommentsInputStory() {
const [value, setValue] = useState<PortableTextBlock[] | null>(null)
const currentUser = useCurrentUser()
Expand All @@ -19,16 +23,13 @@ export default function CommentsInputStory() {
<Container width={0}>
<CommentInput
currentUser={currentUser}
onChange={setValue}
value={value}
expandOnFocus={expandOnFocus}
mentionOptions={{data: [], error: null, loading: false}}
onEditDiscard={() => {
// ...
}}
onSubmit={() => {
// ...
}}
onChange={setValue}
onDiscardCancel={noop}
onDiscardConfirm={noop}
onSubmit={noop}
value={value}
/>
</Container>
</Card>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import {CurrentUser} from '@sanity/types'
import {Box, Breadcrumbs, Button, Flex, Stack, Text} from '@sanity/ui'
import React, {useCallback, useRef, useState} from 'react'
import React, {useCallback, useState} from 'react'
import {uuid} from '@sanity/uuid'
import styled from 'styled-components'
import {ChevronRightIcon} from '@sanity/icons'
import {AddCommentIcon} from '../icons'
import {CommentInputHandle} from '../pte'
import {
CommentMessage,
CommentCreatePayload,
Expand Down Expand Up @@ -40,7 +39,6 @@ export function CommentThreadLayout(props: CommentThreadLayoutProps) {
onNewThreadCreate,
fieldPath,
} = props
const createNewThreadInputRef = useRef<CommentInputHandle>(null)
const [displayNewThreadInput, setDisplayNewThreadInput] = useState<boolean>(false)
const [newThreadButtonElement, setNewThreadButtonElement] = useState<HTMLButtonElement | null>(
null,
Expand Down Expand Up @@ -122,7 +120,7 @@ export function CommentThreadLayout(props: CommentThreadLayoutProps) {
mentionOptions={mentionOptions}
onEditDiscard={handleNewThreadCreateDiscard}
onNewThreadCreate={handleNewThreadCreate}
ref={createNewThreadInputRef}
openButtonElement={newThreadButtonElement}
/>
</ThreadCard>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export interface CommentsListProps {
onDelete: (id: string) => void
onEdit: (id: string, payload: CommentEditPayload) => void
onNewThreadCreate: (payload: CommentCreatePayload) => void
onPathFocus?: (path: Path) => void
onPathSelect?: (path: Path) => void
onReply: (payload: CommentCreatePayload) => void
onStatusChange?: (id: string, status: CommentStatus) => void
selectedPath: SelectedPath
Expand Down Expand Up @@ -80,7 +80,7 @@ const CommentsListInner = forwardRef<CommentsListHandle, CommentsListProps>(
onDelete,
onEdit,
onNewThreadCreate,
onPathFocus,
onPathSelect,
onReply,
onStatusChange,
selectedPath,
Expand Down Expand Up @@ -207,7 +207,7 @@ const CommentsListInner = forwardRef<CommentsListHandle, CommentsListProps>(
onCreateRetry={onCreateRetry}
onDelete={onDelete}
onEdit={onEdit}
onPathFocus={onPathFocus}
onPathSelect={onPathSelect}
onReply={onReply}
onStatusChange={onStatusChange}
parentComment={item.parentComment}
Expand Down
Loading

0 comments on commit 02eecfc

Please sign in to comment.