"use client" import { addComment, listCommentsByPost, toggleCommentLike } from "@/lib/api/comments" import { toApiError } from "@/lib/errors" import { notifyInfo } from "@/lib/toast" import type { Comment } from "@/lib/types" import { useRequireAuth } from "@/lib/use-require-auth" import { Heart } from "lucide-react" import { useCallback, useEffect, useState } from "react" import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar" import { Button } from "./ui/button" import { Textarea } from "./ui/textarea" interface PostCommentsProps { postId: string } export function PostComments({ postId }: PostCommentsProps) { const [comments, setComments] = useState([]) const [loading, setLoading] = useState(true) const [loadError, setLoadError] = useState(null) const [content, setContent] = useState("") const [submitting, setSubmitting] = useState(false) const [pendingLike, setPendingLike] = useState>({}) const { requireAuth } = useRequireAuth() const refresh = useCallback( async (showLoading = true) => { if (showLoading) { setLoading(true) setLoadError(null) } try { const items = await listCommentsByPost(postId) setComments(items) } catch (err: unknown) { setLoadError(toApiError(err).msg) } finally { setLoading(false) } }, [postId], ) useEffect(() => { let cancelled = false void (async () => { try { const items = await listCommentsByPost(postId) if (cancelled) return setComments(items) } catch (err: unknown) { if (cancelled) return setLoadError(toApiError(err).msg) } finally { if (!cancelled) setLoading(false) } })() return () => { cancelled = true } }, [postId]) return (

评论 ({loading && comments.length === 0 ? "..." : comments.length})

{ event.preventDefault() requireAuth(async () => { if (submitting) return const nextContent = content.trim() if (!nextContent) return setSubmitting(true) const decision = await addComment(postId, nextContent) if (!decision.ok) { notifyInfo(decision.error.msg) setSubmitting(false) return } setContent("") await refresh() setSubmitting(false) }) }} >