Skip to content

Commit c105115

Browse files
authoredMar 18, 2024
feat(tasks): add comment delete confirm dialog (#6009)
* feat(tasks): add comment delete confirm dialog * refactor(tasks): create dedicated comment activity item component
1 parent 217a47d commit c105115

File tree

2 files changed

+129
-81
lines changed

2 files changed

+129
-81
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {CommentsListItem, type CommentsListItemProps} from '../../../../../structure/comments'
2+
import {ActivityItem} from './TasksActivityItem'
3+
4+
const COMMENTS_LIST_ITEM_AVATAR_CONFIG: CommentsListItemProps['avatarConfig'] = {
5+
parentCommentAvatar: false,
6+
threadCommentsAvatar: true,
7+
replyAvatar: true,
8+
avatarSize: 0,
9+
}
10+
11+
interface TasksActivityCommentItemProps extends Omit<CommentsListItemProps, 'mode' | 'isSelected'> {
12+
// ...
13+
}
14+
15+
export function TasksActivityCommentItem(props: TasksActivityCommentItemProps) {
16+
const {parentComment} = props
17+
18+
return (
19+
<ActivityItem userId={parentComment.authorId}>
20+
<CommentsListItem
21+
{...props}
22+
avatarConfig={COMMENTS_LIST_ITEM_AVATAR_CONFIG}
23+
canReply
24+
innerPadding={1}
25+
isSelected={false}
26+
mode="default" // TODO: set dynamic mode?
27+
/>
28+
</ActivityItem>
29+
)
30+
}

‎packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx

+99-81
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ import {getJsonStream} from '../../../../../core/store/_legacy/history/history/g
2020
import {
2121
type CommentBaseCreatePayload,
2222
type CommentCreatePayload,
23+
CommentDeleteDialog,
2324
type CommentInputProps,
2425
type CommentReactionOption,
25-
CommentsListItem,
26-
type CommentsListItemProps,
2726
type CommentThreadItem,
2827
type CommentUpdatePayload,
2928
useComments,
@@ -35,8 +34,8 @@ import {getMentionedUsers} from '../form/utils'
3534
import {type FieldChange, trackFieldChanges} from './helpers/parseTransactions'
3635
import {EditedAt} from './TaskActivityEditedAt'
3736
import {TasksActivityCommentInput} from './TasksActivityCommentInput'
37+
import {TasksActivityCommentItem} from './TasksActivityCommentItem'
3838
import {TasksActivityCreatedAt} from './TasksActivityCreatedAt'
39-
import {ActivityItem} from './TasksActivityItem'
4039
import {TasksSubscribers} from './TasksSubscribers'
4140

4241
function useActivityLog(task: TaskDocument) {
@@ -107,13 +106,6 @@ const VARIANTS: Variants = {
107106
visible: {opacity: 1, x: 0},
108107
}
109108

110-
const COMMENTS_LIST_ITEM_AVATAR_CONFIG: CommentsListItemProps['avatarConfig'] = {
111-
parentCommentAvatar: false,
112-
threadCommentsAvatar: true,
113-
replyAvatar: true,
114-
avatarSize: 0,
115-
}
116-
117109
const MotionStack = styled(motion(Stack))``
118110

119111
interface TasksActivityLogProps {
@@ -140,6 +132,10 @@ export function TasksActivityLog(props: TasksActivityLogProps) {
140132
const {title: workspaceTitle, basePath} = useWorkspace()
141133

142134
const {comments, mentionOptions, operation, getComment} = useComments()
135+
const [commentToDeleteId, setCommentToDeleteId] = useState<string | null>(null)
136+
const [commentDeleteError, setCommentDeleteError] = useState<Error | null>(null)
137+
const [commentDeleteLoading, setCommentDeleteLoading] = useState(false)
138+
143139
const loading = comments.loading
144140
const taskComments = comments.data.open
145141

@@ -247,13 +243,21 @@ export function TasksActivityLog(props: TasksActivityLogProps) {
247243
[operation],
248244
)
249245

250-
const handleCommentRemove = useCallback(
251-
(id: string) => {
252-
// TODO:
253-
// The remove operation is not optimistic. We should display a
254-
// dialog to confirm the removal and wait for the server to respond
255-
// before removing the comment from the UI. (See `CommentsDocumentInspector`)
256-
operation.remove(id)
246+
const handleDeleteCommentStart = useCallback((id: string) => setCommentToDeleteId(id), [])
247+
const handleDeleteCommentCancel = useCallback(() => setCommentToDeleteId(null), [])
248+
249+
const handleDeleteCommentConfirm = useCallback(
250+
async (id: string) => {
251+
try {
252+
setCommentDeleteLoading(true)
253+
setCommentDeleteError(null)
254+
await operation.remove(id)
255+
setCommentToDeleteId(null)
256+
} catch (err) {
257+
setCommentDeleteError(err)
258+
} finally {
259+
setCommentDeleteLoading(false)
260+
}
257261
},
258262
[operation],
259263
)
@@ -284,80 +288,94 @@ export function TasksActivityLog(props: TasksActivityLogProps) {
284288
.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime())
285289
}, [activityData, taskComments])
286290

291+
const commentToDeleteIsParent = useMemo(() => {
292+
const parent = taskComments.find((c) => c.parentComment?._id === commentToDeleteId)
293+
const isParent = Boolean(parent && parent?.replies?.length > 0)
294+
295+
return isParent
296+
}, [commentToDeleteId, taskComments])
297+
287298
return (
288-
<Stack space={5}>
289-
<Flex align="center">
290-
<Box flex={1}>
291-
<Text size={2} weight="semibold">
292-
Activity
293-
</Text>
294-
</Box>
295-
296-
{currentUser?.id && (
297-
<TasksSubscribers
298-
currentUserId={currentUser.id}
299-
value={value}
300-
onChange={onChange}
301-
path={path}
302-
/>
303-
)}
304-
</Flex>
305-
306-
{loading && <LoadingBlock showText title="Loading activity" />}
307-
308-
<AnimatePresence>
309-
{!loading && (
310-
<MotionStack animate="visible" initial="hidden" space={3} variants={VARIANTS}>
311-
{value.createdByUser && (
312-
<Stack paddingBottom={1}>
313-
<TasksActivityCreatedAt createdAt={value.createdByUser} authorId={value.authorId} />
314-
</Stack>
315-
)}
316-
317-
{currentUser && (
318-
<CurrentWorkspaceProvider>
319-
<Stack space={4} marginTop={1}>
320-
{activity.map((item) => {
321-
if (item._type === 'activity') {
322-
return <EditedAt key={item.timestamp} activity={item.payload} />
323-
}
324-
return (
325-
<ActivityItem
326-
key={item.payload.parentComment._id}
327-
userId={item.payload.parentComment.authorId}
328-
>
329-
<CommentsListItem
330-
avatarConfig={COMMENTS_LIST_ITEM_AVATAR_CONFIG}
331-
canReply
299+
<>
300+
{commentToDeleteId && (
301+
<CommentDeleteDialog
302+
commentId={commentToDeleteId}
303+
error={commentDeleteError}
304+
isParent={commentToDeleteIsParent}
305+
loading={commentDeleteLoading}
306+
onClose={handleDeleteCommentCancel}
307+
onConfirm={handleDeleteCommentConfirm}
308+
/>
309+
)}
310+
311+
<Stack space={5}>
312+
<Flex align="center">
313+
<Box flex={1}>
314+
<Text size={2} weight="semibold">
315+
Activity
316+
</Text>
317+
</Box>
318+
319+
{currentUser?.id && (
320+
<TasksSubscribers
321+
currentUserId={currentUser.id}
322+
value={value}
323+
onChange={onChange}
324+
path={path}
325+
/>
326+
)}
327+
</Flex>
328+
329+
{loading && <LoadingBlock showText title="Loading activity" />}
330+
331+
<AnimatePresence>
332+
{!loading && (
333+
<MotionStack animate="visible" initial="hidden" space={3} variants={VARIANTS}>
334+
{value.createdByUser && (
335+
<Stack paddingBottom={1}>
336+
<TasksActivityCreatedAt
337+
createdAt={value.createdByUser}
338+
authorId={value.authorId}
339+
/>
340+
</Stack>
341+
)}
342+
343+
{currentUser && (
344+
<CurrentWorkspaceProvider>
345+
<Stack space={4} marginTop={1}>
346+
{activity.map((item) => {
347+
if (item._type === 'activity') {
348+
return <EditedAt key={item.timestamp} activity={item.payload} />
349+
}
350+
351+
return (
352+
<TasksActivityCommentItem
332353
currentUser={currentUser}
333-
innerPadding={1}
334-
isSelected={false}
335354
key={item.payload.parentComment._id}
336355
mentionOptions={mentionOptions}
337-
mode="default" // TODO: set dynamic mode?
338356
onCreateRetry={handleCommentCreateRetry}
339-
onDelete={handleCommentRemove}
357+
onDelete={handleDeleteCommentStart}
340358
onEdit={handleCommentEdit}
341359
onReactionSelect={handleCommentReact}
342360
onReply={handleCommentReply}
343361
parentComment={item.payload.parentComment}
344362
replies={item.payload.replies}
345363
/>
346-
</ActivityItem>
347-
)
348-
})}
349-
350-
<TasksActivityCommentInput
351-
currentUser={currentUser}
352-
mentionOptions={mentionOptions}
353-
onSubmit={handleCommentCreate}
354-
/>
355-
</Stack>
356-
</CurrentWorkspaceProvider>
357-
)}
358-
</MotionStack>
359-
)}
360-
</AnimatePresence>
361-
</Stack>
364+
)
365+
})}
366+
367+
<TasksActivityCommentInput
368+
currentUser={currentUser}
369+
mentionOptions={mentionOptions}
370+
onSubmit={handleCommentCreate}
371+
/>
372+
</Stack>
373+
</CurrentWorkspaceProvider>
374+
)}
375+
</MotionStack>
376+
)}
377+
</AnimatePresence>
378+
</Stack>
379+
</>
362380
)
363381
}

0 commit comments

Comments
 (0)
Please sign in to comment.