From 6bb0af937a78f84d360c88e8f60ecdfac0540957 Mon Sep 17 00:00:00 2001 From: fullsizemalt <106900403+fullsizemalt@users.noreply.github.com> Date: Sun, 21 Dec 2025 02:44:26 -0800 Subject: [PATCH] feat(frontend): Implement threaded comment UI --- .../components/social/comment-section.tsx | 177 ++++++++++++++---- 1 file changed, 144 insertions(+), 33 deletions(-) diff --git a/frontend/components/social/comment-section.tsx b/frontend/components/social/comment-section.tsx index adf07e1..a8faeea 100644 --- a/frontend/components/social/comment-section.tsx +++ b/frontend/components/social/comment-section.tsx @@ -3,15 +3,18 @@ import { useState, useEffect } from "react" import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Card, CardContent } from "@/components/ui/card" import { formatDistanceToNow } from "date-fns" import { getApiUrl } from "@/lib/api-config" +import { MessageCircle, CornerDownRight, Heart } from "lucide-react" +import { cn } from "@/lib/utils" interface Comment { id: number user_id: number content: string created_at: string + parent_id: number | null } interface CommentSectionProps { @@ -30,7 +33,7 @@ export function CommentSection({ entityType, entityId }: CommentSectionProps) { const fetchComments = async () => { try { - const res = await fetch(`${getApiUrl()}/social/comments?${entityType}_id=${entityId}`) + const res = await fetch(`${getApiUrl()}/social/comments?${entityType}_id=${entityId}&limit=100`) if (res.ok) { const data = await res.json() setComments(data) @@ -40,9 +43,9 @@ export function CommentSection({ entityType, entityId }: CommentSectionProps) { } } - const handleSubmit = async (e: React.FormEvent) => { + const handleSubmit = async (e: React.FormEvent, parentId: number | null = null, content: string = newComment) => { e.preventDefault() - if (!newComment.trim()) return + if (!content.trim()) return const token = localStorage.getItem("token") if (!token) { @@ -52,7 +55,10 @@ export function CommentSection({ entityType, entityId }: CommentSectionProps) { setLoading(true) try { - const body: any = { content: newComment } + const body: any = { + content: content, + parent_id: parentId + } body[`${entityType}_id`] = entityId const res = await fetch(`${getApiUrl()}/social/comments`, { @@ -77,41 +83,146 @@ export function CommentSection({ entityType, entityId }: CommentSectionProps) { } } + // Tree builder + const rootComments = comments.filter(c => c.parent_id === null) + const getReplies = (parentId: number) => comments.filter(c => c.parent_id === parentId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime()) + return ( -
No comments yet.
+No comments yet. Be the first!
) : ( - comments.map(comment => ( -{comment.content}
-