diff --git a/surfsense_web/components/chat-comments/comment-panel-container/comment-panel-container.tsx b/surfsense_web/components/chat-comments/comment-panel-container/comment-panel-container.tsx new file mode 100644 index 000000000..c92bfdef0 --- /dev/null +++ b/surfsense_web/components/chat-comments/comment-panel-container/comment-panel-container.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { useAtom } from "jotai"; +import { useMemo } from "react"; +import { + createCommentMutationAtom, + createReplyMutationAtom, + deleteCommentMutationAtom, + updateCommentMutationAtom, +} from "@/atoms/chat-comments/comments-mutation.atoms"; +import { membersAtom } from "@/atoms/members/members-query.atoms"; +import { useComments } from "@/hooks/use-comments"; +import { CommentPanel } from "../comment-panel/comment-panel"; +import type { CommentPanelContainerProps } from "./types"; +import { transformComment, transformMember } from "./utils"; + +export function CommentPanelContainer({ + messageId, + isOpen, + maxHeight = 400, +}: CommentPanelContainerProps) { + const { data: commentsData, isLoading: isCommentsLoading } = useComments({ + messageId, + enabled: isOpen, + }); + + const [{ data: membersData, isLoading: isMembersLoading }] = useAtom(membersAtom); + + const [{ mutate: createComment, isPending: isCreating }] = useAtom(createCommentMutationAtom); + const [{ mutate: createReply, isPending: isCreatingReply }] = useAtom(createReplyMutationAtom); + const [{ mutate: updateComment, isPending: isUpdating }] = useAtom(updateCommentMutationAtom); + const [{ mutate: deleteComment, isPending: isDeleting }] = useAtom(deleteCommentMutationAtom); + + const commentThreads = useMemo(() => { + if (!commentsData?.comments) return []; + return commentsData.comments.map(transformComment); + }, [commentsData]); + + const members = useMemo(() => { + if (!membersData) return []; + return membersData.map(transformMember); + }, [membersData]); + + const isSubmitting = isCreating || isCreatingReply || isUpdating || isDeleting; + + const handleCreateComment = (content: string) => { + createComment({ message_id: messageId, content }); + }; + + const handleCreateReply = (commentId: number, content: string) => { + createReply({ comment_id: commentId, content, message_id: messageId }); + }; + + const handleEditComment = (commentId: number, content: string) => { + updateComment({ comment_id: commentId, content, message_id: messageId }); + }; + + const handleDeleteComment = (commentId: number) => { + deleteComment({ comment_id: commentId, message_id: messageId }); + }; + + if (!isOpen) return null; + + return ( + + ); +} + diff --git a/surfsense_web/components/chat-comments/comment-panel-container/types.ts b/surfsense_web/components/chat-comments/comment-panel-container/types.ts new file mode 100644 index 000000000..12d701309 --- /dev/null +++ b/surfsense_web/components/chat-comments/comment-panel-container/types.ts @@ -0,0 +1,8 @@ +export interface CommentPanelContainerProps { + messageId: number; + searchSpaceId: number; + isOpen: boolean; + onClose?: () => void; + maxHeight?: number; +} + diff --git a/surfsense_web/components/chat-comments/comment-panel-container/utils.ts b/surfsense_web/components/chat-comments/comment-panel-container/utils.ts new file mode 100644 index 000000000..b046c4ff1 --- /dev/null +++ b/surfsense_web/components/chat-comments/comment-panel-container/utils.ts @@ -0,0 +1,56 @@ +import type { Comment, CommentReply } from "@/contracts/types/chat-comments.types"; +import type { Membership } from "@/contracts/types/members.types"; +import type { CommentData } from "../comment-item/types"; +import type { CommentThreadData } from "../comment-thread/types"; +import type { MemberOption } from "../member-mention-picker/types"; + +export function transformAuthor(author: Comment["author"]): CommentData["author"] { + if (!author) return null; + return { + id: author.id, + displayName: author.display_name, + email: author.email, + avatarUrl: author.avatar_url, + }; +} + +export function transformReply(reply: CommentReply): CommentData { + return { + id: reply.id, + content: reply.content, + contentRendered: reply.content_rendered, + author: transformAuthor(reply.author), + createdAt: reply.created_at, + updatedAt: reply.updated_at, + isEdited: reply.is_edited, + canEdit: reply.can_edit, + canDelete: reply.can_delete, + }; +} + +export function transformComment(comment: Comment): CommentThreadData { + return { + id: comment.id, + messageId: comment.message_id, + content: comment.content, + contentRendered: comment.content_rendered, + author: transformAuthor(comment.author), + createdAt: comment.created_at, + updatedAt: comment.updated_at, + isEdited: comment.is_edited, + canEdit: comment.can_edit, + canDelete: comment.can_delete, + replyCount: comment.reply_count, + replies: comment.replies.map(transformReply), + }; +} + +export function transformMember(membership: Membership): MemberOption { + return { + id: membership.user_id, + displayName: membership.user_email ?? "", + email: membership.user_email ?? "", + avatarUrl: null, + }; +} +