import { useState } from "react"; import { replyReviewComment, resolveReviewThread } from "~/fns/reviews"; import { useAction } from "~/hooks/use-action"; import { ReactionBar } from "./ReactionBar"; 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; suggestion?: SuggestionControls; }; export type SuggestionControls = { inBatch: boolean; pending: boolean; onCommit: () => void; onToggleBatch: () => void; }; function rangeLabel(comment: ReviewComment): string | null { if (!comment.startLine) return null; const prefix = (side: string | null) => (side === "LEFT" ? "L" : "R"); return `Lines ${prefix(comment.startSide)}${comment.startLine}–${prefix(comment.side)}${comment.line}`; } function SuggestionBar({ comment, controls }: { comment: ReviewComment; controls?: SuggestionControls }) { if (!comment.hasSuggestion) return null; if (comment.suggestionApplied) return Suggestion applied; if (!controls) return Suggested change; return ( ); } export function ReviewThread({ owner, repo, number, root, replies, canReply, suggestion }: Props) { const [reply, setReply] = useState(""); const [collapsed, setCollapsed] = useState(root.resolved); const send = useAction(replyReviewComment); const resolve = useAction(resolveReviewThread); return (
{rangeLabel(root) && {rangeLabel(root)}} {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")} />
)} )}
); }