Barazo default frontend
barazo.forum
1/**
2 * ReplyThread - Displays a threaded tree of replies.
3 * Reconstructs tree from flat API response, assigns depth-first post numbers.
4 * Post numbers start at 2 (post #1 is the topic itself).
5 * Uses viewport-aware indent steps for responsive nesting.
6 * @see specs/prd-web.md Section 4 (Topic Components)
7 */
8
9'use client'
10
11import { useMemo } from 'react'
12import type { Reply } from '@/lib/api/types'
13import { cn } from '@/lib/utils'
14import { buildReplyTree, flattenReplyTree } from '@/lib/build-reply-tree'
15import { useThreadIndent } from '@/hooks/use-thread-indent'
16import { ThreadHoverProvider } from '@/context/thread-hover-context'
17import { ReplyBranch } from './reply-branch'
18
19interface ReplyThreadProps {
20 replies: Reply[]
21 topicUri: string
22 onReply?: (target: { uri: string; cid: string; authorHandle: string; snippet: string }) => void
23 onDeleteReply?: () => void
24 currentUserDid?: string
25 className?: string
26}
27
28export function ReplyThread({
29 replies,
30 topicUri,
31 onReply,
32 onDeleteReply,
33 currentUserDid,
34 className,
35}: ReplyThreadProps) {
36 const replyCount = replies.length
37 const heading =
38 replyCount === 0 ? 'Replies' : replyCount === 1 ? '1 Reply' : `${replyCount} Replies`
39
40 const { indentStep, showChevron } = useThreadIndent()
41
42 const { tree, postNumberMap, allReplies } = useMemo(() => {
43 const builtTree = buildReplyTree(replies, topicUri)
44 const flat = flattenReplyTree(builtTree)
45 const map = new Map<string, number>()
46 flat.forEach((reply, index) => {
47 map.set(reply.uri, index + 2)
48 })
49 const replyMap = new Map(replies.map((r) => [r.uri, r]))
50 return { tree: builtTree, postNumberMap: map, allReplies: replyMap }
51 }, [replies, topicUri])
52
53 return (
54 <section className={cn('space-y-4', className)} aria-label="Replies">
55 <h2 className="text-lg font-semibold text-foreground">{heading}</h2>
56
57 {replyCount === 0 ? (
58 <div className="rounded-lg border border-border bg-card p-6 text-center">
59 <p className="text-muted-foreground">No replies yet. Be the first to respond!</p>
60 </div>
61 ) : (
62 <ThreadHoverProvider>
63 <ReplyBranch
64 nodes={tree}
65 postNumberMap={postNumberMap}
66 topicUri={topicUri}
67 allReplies={allReplies}
68 indentStep={indentStep}
69 showChevron={showChevron}
70 onReply={onReply}
71 onDeleteReply={onDeleteReply}
72 currentUserDid={currentUserDid}
73 />
74 </ThreadHoverProvider>
75 )}
76 </section>
77 )
78}