import { useState, useRef, useEffect } from "react"; import { Check, RotateCcw, Reply } from "lucide-react"; import { Button } from "@/components/ui/button"; import { CommentForm } from "./CommentForm"; import type { ReviewComment } from "./types"; interface CommentThreadProps { comments: ReviewComment[]; onResolve: (commentId: string) => void; onUnresolve: (commentId: string) => void; onReply?: (parentCommentId: string, body: string) => void; } export function CommentThread({ comments, onResolve, onUnresolve, onReply }: CommentThreadProps) { // Group: root comments (no parentCommentId) and their replies const rootComments = comments.filter((c) => !c.parentCommentId); const repliesByParent = new Map(); for (const c of comments) { if (c.parentCommentId) { const arr = repliesByParent.get(c.parentCommentId) ?? []; arr.push(c); repliesByParent.set(c.parentCommentId, arr); } } return (
{rootComments.map((comment) => ( ))}
); } function RootComment({ comment, replies, onResolve, onUnresolve, onReply, }: { comment: ReviewComment; replies: ReviewComment[]; onResolve: (id: string) => void; onUnresolve: (id: string) => void; onReply?: (parentCommentId: string, body: string) => void; }) { const [isReplying, setIsReplying] = useState(false); const replyRef = useRef(null); useEffect(() => { if (isReplying) replyRef.current?.focus(); }, [isReplying]); return (
{/* Root comment */}
{comment.author} {formatTime(comment.createdAt)} {comment.resolved && ( Resolved )}
{onReply && !comment.resolved && ( )} {comment.resolved ? ( ) : ( )}

{comment.body}

{/* Replies */} {replies.length > 0 && (
{replies.map((reply) => (
{reply.author} {formatTime(reply.createdAt)}

{reply.body}

))}
)} {/* Reply form */} {isReplying && onReply && (
{ onReply(comment.id, body); setIsReplying(false); }} onCancel={() => setIsReplying(false)} placeholder="Write a reply..." submitLabel="Reply" />
)}
); } function formatTime(iso: string): string { const d = new Date(iso); return d.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" }); }