import { useState } from "react"; import { replyReviewComment, resolveReviewThread } from "~/fns/reviews"; import { useAction } from "~/hooks/use-action"; import { Avatar, Badge, Markdown, RelativeTime } from "./ui/Primitives"; import { Button } from "./ui/Button"; import { inputClass } from "./ui/Field"; import type { getPullFiles } from "~/fns/pulls"; import { cn } from "~/utils/cn"; export type ReviewComment = Awaited>["comments"][number]; type Props = { owner: string; repo: string; number: number; root: ReviewComment; replies: ReviewComment[]; canReply: boolean; }; export function ReviewThread({ owner, repo, number, root, replies, canReply }: Props) { const [reply, setReply] = useState(""); const [collapsed, setCollapsed] = useState(root.resolved); const send = useAction(replyReviewComment); const resolve = useAction(resolveReviewThread); return (
{root.outdated && Outdated} {root.resolved && Resolved} {canReply && ( )}
{!collapsed && ( <> {[root, ...replies].map((comment) => (
{comment.author.name}{" "}
))} {canReply && (
{ event.preventDefault(); if (!reply.trim()) return; const ok = await send.run({ data: { owner, repo, number, commentId: root.id, comment: { path: root.path, line: root.line, side: root.side, body: reply }, }, }); if (ok) setReply(""); }} > setReply(event.target.value)} placeholder="Reply…" className={cn(inputClass, "h-8 text-xs")} />
)} )}
); }