'use client'; import { useCallback, useEffect, useState } from 'react'; import type { PlazaComment } from '@/types/plaza'; import { LoginPrompt } from '@/components/auth/LoginPrompt'; import { CommentInput } from '@/components/comment/CommentInput'; import { CommentList } from '@/components/comment/CommentList'; import { PlazaApiError, createComment, fetchComments, toggleCommentLike, } from '@/lib/api'; type CommentSectionProps = { postId: string; allowComment?: boolean; }; export function CommentSection({ postId, allowComment = true }: CommentSectionProps) { const [comments, setComments] = useState([]); const [cursor, setCursor] = useState(null); const [hasMore, setHasMore] = useState(false); const [loading, setLoading] = useState(true); const [loadingMore, setLoadingMore] = useState(false); const [replyTo, setReplyTo] = useState(null); const [loginOpen, setLoginOpen] = useState(false); const loadComments = useCallback( async (nextCursor?: string | null) => { const data = await fetchComments(postId, { cursor: nextCursor ?? undefined }); if (nextCursor) { setComments((current) => [...current, ...data.comments]); } else { setComments(data.comments); } setCursor(data.next_cursor); setHasMore(data.has_more); }, [postId], ); useEffect(() => { let cancelled = false; setLoading(true); loadComments() .catch(() => { if (!cancelled) setComments([]); }) .finally(() => { if (!cancelled) setLoading(false); }); return () => { cancelled = true; }; }, [loadComments]); const handleCreate = async (content: string) => { try { await createComment(postId, content, replyTo?.id ?? null); setReplyTo(null); await loadComments(); } catch (error) { if (error instanceof PlazaApiError && error.code === 'unauthorized') { setLoginOpen(true); } throw error; } }; const handleToggleLike = async (comment: PlazaComment) => { try { const liked = !comment.viewer_liked; await toggleCommentLike(comment.id, liked); setComments((current) => current.map((item) => item.id === comment.id ? { ...item, viewer_liked: liked, like_count: Math.max(0, item.like_count + (liked ? 1 : -1)), } : item, ), ); } catch (error) { if (error instanceof PlazaApiError && error.code === 'unauthorized') { setLoginOpen(true); } } }; const handleLoadMore = async () => { if (!cursor || loadingMore) return; setLoadingMore(true); try { await loadComments(cursor); } finally { setLoadingMore(false); } }; if (!allowComment) { return (
作者已关闭评论
); } return (

评论

{replyTo ? (

回复 @{replyTo.author.display_name}

) : null} setReplyTo(null) : undefined} />
{loading ? (

加载评论中…

) : ( )} {hasMore ? ( ) : null}
setLoginOpen(false)} message="登录后即可发表评论" />
); }