'use client'; import { useCallback, useMemo } from 'react'; import { toast } from 'sonner'; import type { SelectedLineRange } from '@pierre/diffs'; import { useCommentsStore } from '@/lib/state/slices/comments'; import { useDiffFileComments } from '@/hooks/domains/comments/use-diff-comments'; import { commentsToAnnotations, extractCodeFromDiff, extractCodeFromContent, } from '@/lib/diff'; import type { DiffComment, AnnotationSide, CommentAnnotation } from '@/lib/diff/types'; interface UseDiffCommentsOptions { sessionId: string; filePath: string; /** Diff string for extracting code from line selection */ diff?: string; /** New content for extracting code from line selection */ newContent?: string; /** Old content for extracting code from line selection */ oldContent?: string; } interface UseDiffCommentsReturn { /** Comments for this file */ comments: DiffComment[]; /** Annotations formatted for @pierre/diffs */ annotations: CommentAnnotation[]; /** Add a new comment */ addComment: ( range: SelectedLineRange, text: string ) => void; /** Remove a comment */ removeComment: (commentId: string) => void; /** Update a comment */ updateComment: (commentId: string, updates: Partial) => void; /** Currently editing comment ID */ editingCommentId: string | null; /** Set the editing comment ID */ setEditingComment: (commentId: string | null) => void; } /** * Hook to manage comments for a specific file's diff */ export function useDiffComments({ sessionId, filePath, diff, newContent, oldContent, }: UseDiffCommentsOptions): UseDiffCommentsReturn { const comments = useDiffFileComments(sessionId, filePath); const editingCommentId = useCommentsStore( (state) => state.editingCommentId ); const storeAddComment = useCommentsStore((state) => state.addComment); const storeRemoveComment = useCommentsStore((state) => state.removeComment); const storeUpdateComment = useCommentsStore((state) => state.updateComment); const storeSetEditingComment = useCommentsStore((state) => state.setEditingComment); const annotations = useMemo( () => commentsToAnnotations(comments), [comments] ); const addComment = useCallback( (range: SelectedLineRange, text: string) => { const side = (range.side || 'additions') as AnnotationSide; const startLine = Math.min(range.start, range.end); const endLine = Math.max(range.start, range.end); // Extract the code content from the selected lines let codeContent = ''; if (diff) { codeContent = extractCodeFromDiff(diff, startLine, endLine, side); } else { const content = side === 'additions' ? newContent : oldContent; if (content) { codeContent = extractCodeFromContent(content, startLine, endLine); } } const comment: DiffComment = { id: `${filePath}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, source: 'diff', sessionId, filePath, startLine, endLine, side, codeContent, text, createdAt: new Date().toISOString(), status: 'pending', }; storeAddComment(comment); toast.success('Comment added', { description: 'Your comment will be sent with your next message.', duration: 2000, }); }, [sessionId, filePath, diff, newContent, oldContent, storeAddComment] ); const removeComment = useCallback( (commentId: string) => { storeRemoveComment(commentId); }, [storeRemoveComment] ); const updateComment = useCallback( (commentId: string, updates: Partial) => { storeUpdateComment(commentId, updates); }, [storeUpdateComment] ); const setEditingComment = useCallback( (commentId: string | null) => { storeSetEditingComment(commentId); }, [storeSetEditingComment] ); return { comments, annotations, addComment, removeComment, updateComment, editingCommentId, setEditingComment, }; }