"use client"; import dynamic from "@/lib/routing/client-dynamic"; import { useEffect, useState, type ReactNode } from "react"; import { IconLoader2, IconRestore } from "@tabler/icons-react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@kandev/ui/dialog"; import { Button } from "@kandev/ui/button"; import { Badge } from "@kandev/ui/badge"; import type { TaskPlanRevision } from "@/lib/types/http"; import { formatPreciseTime } from "@/lib/utils"; const PlanReadOnlyMarkdown = dynamic( () => import("@/components/editors/tiptap/tiptap-plan-readonly").then( (mod) => mod.PlanReadOnlyMarkdown, ), { ssr: false }, ); type Props = { revision: TaskPlanRevision | null; authorLabel: string; loadContent: (revisionId: string) => Promise; onClose: () => void; onRestore: () => void; /** Open the diff dialog comparing the previewed revision with the previous * revision (vN-1). Disabled if the previewed one is the oldest. */ onCompareWithPrevious: (() => void) | null; /** Open the diff dialog comparing the previewed revision with current HEAD. */ onCompareWithCurrent: () => void; /** True when the revision is the current HEAD — Restore + Compare-with-current * CTAs hide. */ isCurrent: boolean; }; /** Read-only modal preview of a single plan revision. The parent should give * this component a `key` derived from the revision id so it remounts (and * resets its loader state) when the user opens a different revision. */ export function PlanRevisionPreviewDialog({ revision, authorLabel, loadContent, onClose, onRestore, onCompareWithPrevious, onCompareWithCurrent, isCurrent, }: Props): ReactNode { const open = revision !== null; return ( { if (!v) onClose(); }} > Version {revision?.revision_number} {isCurrent && ( current )} {authorLabel} · {revision ? formatPreciseTime(revision.updated_at) : ""} {revision?.revert_of_revision_id && ( restored from earlier version )} {!isCurrent && revision && ( <> {onCompareWithPrevious && ( )} )} ); } function PreviewBody({ revision, loadContent, }: { revision: TaskPlanRevision | null; loadContent: (revisionId: string) => Promise; }) { const [content, setContent] = useState(null); const [error, setError] = useState(null); useEffect(() => { if (!revision) return; let cancelled = false; loadContent(revision.id) .then((c) => { if (!cancelled) setContent(c); }) .catch((err) => { if (!cancelled) { setError(err instanceof Error ? err.message : "Failed to load revision"); } }); return () => { cancelled = true; }; }, [revision, loadContent]); return (
); } function PreviewBodyInner({ content, error }: { content: string | null; error: string | null }) { if (error) { return
{error}
; } if (content === null) { return (
Loading…
); } if (content.trim() === "") { return
(empty plan)
; } return ; }