Spaces:
Sleeping
Sleeping
File size: 3,501 Bytes
05c5ed5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | "use client";
import { ChatExportCommentWithUser } from "app-types/chat-export";
import { Avatar, AvatarFallback, AvatarImage } from "ui/avatar";
import { Button } from "ui/button";
import { formatDistanceToNow } from "date-fns";
import { useState } from "react";
import { mutate } from "swr";
import MentionInput from "../mention-input";
import { CornerDownRightIcon } from "lucide-react";
import { notify } from "lib/notify";
export default function Comment({
comment,
exportId,
depth = 0,
maxReplyDepth = Infinity,
onReply,
}: {
comment: ChatExportCommentWithUser;
exportId: string;
depth?: number;
maxReplyDepth?: number;
onReply?: () => void;
}) {
const [isDeleting, setIsDeleting] = useState(false);
const handleDelete = async () => {
const answer = await notify.confirm({
title: "Delete Comment",
description: "Are you sure you want to delete this comment?",
});
if (!answer) return;
try {
setIsDeleting(true);
const response = await fetch(
`/api/export/${exportId}/comments/${comment.id}`,
{
method: "DELETE",
},
);
if (!response.ok) {
throw new Error("Failed to delete comment");
}
// Refresh comments
mutate(`/api/export/${exportId}/comments`);
} catch (error) {
console.error("Failed to delete comment:", error);
} finally {
setIsDeleting(false);
}
};
return (
<div className="flex items-start gap-3">
<Avatar className="size-6 rounded-full">
<AvatarImage src={comment.authorImage} />
<AvatarFallback>
{comment.authorName?.[0]?.toUpperCase()}
</AvatarFallback>
</Avatar>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<span className="font-medium text-xs">{comment.authorName}</span>
<span className="text-xs text-muted-foreground">
{formatDistanceToNow(new Date(comment.createdAt), {
addSuffix: true,
})}
</span>
</div>
<div className="text-sm">
<MentionInput content={comment.content} disabled className="p-0" />
</div>
<div className="flex items-center text-muted-foreground gap-2">
{depth < maxReplyDepth && (
<Button
variant="ghost"
size="sm"
onClick={() => onReply?.()}
className="text-xs! p-0! hover:bg-transparent!"
>
<CornerDownRightIcon className="size-3" />
Reply
</Button>
)}
{comment.isOwner && (
<Button
variant="ghost"
size="sm"
onClick={handleDelete}
disabled={isDeleting}
className="text-xs! hover:text-destructive p-0! hover:bg-transparent!"
>
{isDeleting ? "Deleting..." : "Delete"}
</Button>
)}
</div>
{/* Render replies */}
{comment.replies && comment.replies.length > 0 && (
<div className="mt-2 border-l-1 border-border/30 pl-4">
{comment.replies.map((reply) => (
<Comment
key={reply.id}
comment={reply}
exportId={exportId}
maxReplyDepth={maxReplyDepth}
depth={depth + 1}
/>
))}
</div>
)}
</div>
</div>
);
}
|