"use client"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { RefreshCwIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Empty, EmptyHeader, EmptyTitle, EmptyDescription } from "@/components/ui/empty"; import type { CommentItem, CommentPage } from "@/lib/comments/types"; import { CommentComposer } from "./comment-composer"; import { CommentCard } from "./comment-card"; import { commentRequest, commentSignInHref } from "./client"; import { CommentSkeleton } from "./comment-skeleton"; import { useCommentEvents } from "./use-comment-events"; import { useCommentFeed } from "./use-comment-feed"; export function CommentBoard({ target, initial }: { target: string; initial: CommentPage }) { const router = useRouter(); const [sort, setSort] = useState("top"); const [linkedReply, setLinkedReply] = useState(null); const [linkedThread, setLinkedThread] = useState(null); const [linkedResult, setLinkedResult] = useState<{ rootId: string; target: string; item: CommentItem | null; error: string } | null>(null); const feed = useCommentFeed(`/api/comments?target=${encodeURIComponent(target)}&sort=${sort}`, initial); const loadedThread = feed.page.items.find((item) => item.id === linkedThread && item.target === target && !item.rootId); const threadLoaded = Boolean(loadedThread); useEffect(() => { if (!linkedThread || threadLoaded) return; const controller = new AbortController(); void Promise.resolve().then(async () => { if (controller.signal.aborted) return; setLinkedResult((current) => ({ rootId: linkedThread, target, item: current?.rootId === linkedThread && current.target === target ? current.item : null, error: "" })); try { const result = await commentRequest<{ item: CommentItem }>(`/api/comments/${linkedThread}`, { signal: controller.signal }); if (!result.item || result.item.id !== linkedThread || result.item.target !== target || result.item.rootId) throw new Error("ไม่พบการสนทนาที่เลือก"); if (!controller.signal.aborted) setLinkedResult({ rootId: linkedThread, target, item: result.item, error: "" }); } catch (cause) { if (!controller.signal.aborted) setLinkedResult({ rootId: linkedThread, target, item: null, error: cause instanceof Error ? cause.message : "ไม่สามารถโหลดการสนทนาได้" }); } }); return () => controller.abort(); }, [linkedThread, target, threadLoaded, feed.revision]); const result = linkedResult?.rootId === linkedThread && linkedResult.target === target ? linkedResult : null; const selectedItem = linkedThread ? loadedThread ?? result?.item : null; const selectedError = linkedThread && !threadLoaded ? result?.error : ""; const selectedBusy = Boolean(linkedThread && !selectedItem && !selectedError); const items = selectedItem ? [selectedItem, ...feed.page.items.filter((item) => item.id !== linkedThread)] : feed.page.items; useCommentEvents({ target }, (changed) => feed.refresh({ silent: true, forceRevision: changed })); useEffect(() => { const showThread = () => { const match = /^#comment-([0-9a-f-]{36})$/i.exec(window.location.hash); setLinkedThread(match?.[1] ?? null); const reply = new URLSearchParams(window.location.search).get("reply"); setLinkedReply(match && reply && /^[0-9a-f-]{36}$/i.test(reply) ? reply : null); }; showThread(); window.addEventListener("hashchange", showThread); return () => window.removeEventListener("hashchange", showThread); }, []); return
{feed.page.viewer?.name?.slice(0, 2) || "คุณ"}
{feed.page.viewer ? void feed.refresh({ silent: true, forceRevision: true })} /> :

{"เข้าสู่ระบบเพื่อแสดงความคิดเห็น ตอบกลับ และกดถูกใจ"}

}

{"ความคิดเห็น"}

{ if (values[0] && values[0] !== sort) { setLinkedThread(null); setLinkedReply(null); setSort(values[0]); const url = new URL(window.location.href); url.hash = ""; url.searchParams.delete("reply"); window.history.replaceState(null, "", url.pathname + url.search); } }} variant="outline" aria-label={"เรียงความคิดเห็น"}> {"ล่าสุด"}{"ยอดนิยม"}
{feed.error && {feed.error}} {selectedError && {selectedError}} {selectedBusy && } {items.map((item) => feed.refresh({ silent: true, forceRevision: true })} revision={feed.revision} />)} {!items.length && !feed.busy && !feed.error && !selectedBusy && !selectedError && {"ยังไม่มีความคิดเห็น"}{"เป็นคนแรกที่ร่วมพูดคุยเกี่ยวกับไกด์นี้"}} {feed.busy && } {feed.page.nextCursor && }
; }