From d40e914877c015683d48bb4dc0bf83c4ec8f523f Mon Sep 17 00:00:00 2001 From: Herman Wikner Date: Fri, 15 Mar 2024 11:46:05 +0100 Subject: [PATCH 1/2] feat(tasks): add comment delete confirm dialog --- .../components/activity/TasksActivityLog.tsx | 194 +++++++++++------- 1 file changed, 115 insertions(+), 79 deletions(-) diff --git a/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx b/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx index 4e39ec47bf2..8318e52d13c 100644 --- a/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx +++ b/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx @@ -20,6 +20,7 @@ import {getJsonStream} from '../../../../../core/store/_legacy/history/history/g import { type CommentBaseCreatePayload, type CommentCreatePayload, + CommentDeleteDialog, type CommentInputProps, type CommentReactionOption, CommentsListItem, @@ -140,6 +141,10 @@ export function TasksActivityLog(props: TasksActivityLogProps) { const {title: workspaceTitle, basePath} = useWorkspace() const {comments, mentionOptions, operation, getComment} = useComments() + const [commentToDeleteId, setCommentToDeleteId] = useState(null) + const [commentDeleteError, setCommentDeleteError] = useState(null) + const [commentDeleteLoading, setCommentDeleteLoading] = useState(false) + const loading = comments.loading const taskComments = comments.data.open @@ -247,13 +252,21 @@ export function TasksActivityLog(props: TasksActivityLogProps) { [operation], ) - const handleCommentRemove = useCallback( - (id: string) => { - // TODO: - // The remove operation is not optimistic. We should display a - // dialog to confirm the removal and wait for the server to respond - // before removing the comment from the UI. (See `CommentsDocumentInspector`) - operation.remove(id) + const handleDeleteCommentStart = useCallback((id: string) => setCommentToDeleteId(id), []) + const handleDeleteCommentCancel = useCallback(() => setCommentToDeleteId(null), []) + + const handleDeleteCommentConfirm = useCallback( + async (id: string) => { + try { + setCommentDeleteLoading(true) + setCommentDeleteError(null) + await operation.remove(id) + setCommentToDeleteId(null) + } catch (err) { + setCommentDeleteError(err) + } finally { + setCommentDeleteLoading(false) + } }, [operation], ) @@ -284,80 +297,103 @@ export function TasksActivityLog(props: TasksActivityLogProps) { .sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()) }, [activityData, taskComments]) + const commentToDeleteIsParent = useMemo(() => { + const parent = taskComments.find((c) => c.parentComment?._id === commentToDeleteId) + const isParent = Boolean(parent && parent?.replies?.length > 0) + + return isParent + }, [commentToDeleteId, taskComments]) + return ( - - - - - Activity - - - - {currentUser?.id && ( - - )} - - - {loading && } - - - {!loading && ( - - {value.createdByUser && ( - - - - )} - - {currentUser && ( - - - {activity.map((item) => { - if (item._type === 'activity') { - return - } - return ( - - - - ) - })} - - + {commentToDeleteId && ( + + )} + + + + + + Activity + + + + {currentUser?.id && ( + + )} + + + {loading && } + + + {!loading && ( + + {value.createdByUser && ( + + - - )} - - )} - - + )} + + {currentUser && ( + + + {activity.map((item) => { + if (item._type === 'activity') { + return + } + return ( + + + + ) + })} + + + + + )} + + )} + + + ) } From 8405dd782b881fb84cfd6340dd50f207ca0672ca Mon Sep 17 00:00:00 2001 From: Herman Wikner Date: Mon, 18 Mar 2024 12:59:29 +0100 Subject: [PATCH 2/2] refactor(tasks): create dedicated comment activity item component --- .../activity/TasksActivityCommentItem.tsx | 30 +++++++++++++ .../components/activity/TasksActivityLog.tsx | 44 ++++++------------- 2 files changed, 43 insertions(+), 31 deletions(-) create mode 100644 packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityCommentItem.tsx diff --git a/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityCommentItem.tsx b/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityCommentItem.tsx new file mode 100644 index 00000000000..975a2b10d77 --- /dev/null +++ b/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityCommentItem.tsx @@ -0,0 +1,30 @@ +import {CommentsListItem, type CommentsListItemProps} from '../../../../../structure/comments' +import {ActivityItem} from './TasksActivityItem' + +const COMMENTS_LIST_ITEM_AVATAR_CONFIG: CommentsListItemProps['avatarConfig'] = { + parentCommentAvatar: false, + threadCommentsAvatar: true, + replyAvatar: true, + avatarSize: 0, +} + +interface TasksActivityCommentItemProps extends Omit { + // ... +} + +export function TasksActivityCommentItem(props: TasksActivityCommentItemProps) { + const {parentComment} = props + + return ( + + + + ) +} diff --git a/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx b/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx index 8318e52d13c..71573f358bc 100644 --- a/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx +++ b/packages/sanity/src/tasks/src/tasks/components/activity/TasksActivityLog.tsx @@ -23,8 +23,6 @@ import { CommentDeleteDialog, type CommentInputProps, type CommentReactionOption, - CommentsListItem, - type CommentsListItemProps, type CommentThreadItem, type CommentUpdatePayload, useComments, @@ -36,8 +34,8 @@ import {getMentionedUsers} from '../form/utils' import {type FieldChange, trackFieldChanges} from './helpers/parseTransactions' import {EditedAt} from './TaskActivityEditedAt' import {TasksActivityCommentInput} from './TasksActivityCommentInput' +import {TasksActivityCommentItem} from './TasksActivityCommentItem' import {TasksActivityCreatedAt} from './TasksActivityCreatedAt' -import {ActivityItem} from './TasksActivityItem' import {TasksSubscribers} from './TasksSubscribers' function useActivityLog(task: TaskDocument) { @@ -108,13 +106,6 @@ const VARIANTS: Variants = { visible: {opacity: 1, x: 0}, } -const COMMENTS_LIST_ITEM_AVATAR_CONFIG: CommentsListItemProps['avatarConfig'] = { - parentCommentAvatar: false, - threadCommentsAvatar: true, - replyAvatar: true, - avatarSize: 0, -} - const MotionStack = styled(motion(Stack))`` interface TasksActivityLogProps { @@ -356,29 +347,20 @@ export function TasksActivityLog(props: TasksActivityLogProps) { if (item._type === 'activity') { return } + return ( - - - + mentionOptions={mentionOptions} + onCreateRetry={handleCommentCreateRetry} + onDelete={handleDeleteCommentStart} + onEdit={handleCommentEdit} + onReactionSelect={handleCommentReact} + onReply={handleCommentReply} + parentComment={item.payload.parentComment} + replies={item.payload.replies} + /> ) })}