import { useState, useCallback } from "react"; import { ChevronDown, ChevronRight, Undo2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { trpc } from "@/lib/trpc"; import type { ChangeSet } from "@codewalk-district/shared"; interface ChangeSetBannerProps { changeSet: ChangeSet; onDismiss: () => void; } const MODE_LABELS: Record = { breakdown: "phases", decompose: "tasks", refine: "pages", }; export function ChangeSetBanner({ changeSet, onDismiss }: ChangeSetBannerProps) { const [expanded, setExpanded] = useState(false); const [conflicts, setConflicts] = useState(null); const detailQuery = trpc.getChangeSet.useQuery( { id: changeSet.id }, { enabled: expanded }, ); const revertMutation = trpc.revertChangeSet.useMutation({ onSuccess: (result) => { if (!result.success && "conflicts" in result) { setConflicts(result.conflicts); } else { setConflicts(null); } }, }); const handleRevert = useCallback( (force?: boolean) => { revertMutation.mutate({ id: changeSet.id, force }); }, [changeSet.id, revertMutation], ); const entries = detailQuery.data?.entries ?? []; const entityLabel = MODE_LABELS[changeSet.mode] ?? "entities"; const isReverted = changeSet.status === "reverted"; return (
{isReverted && ( (reverted) )}
{!isReverted && ( )}
{conflicts && (

Conflicts detected:

    {conflicts.map((c, i) => (
  • {c}
  • ))}
)} {expanded && (
{detailQuery.isLoading &&

Loading entries...

} {entries.map((entry) => (
{entry.action === "create" ? "+" : entry.action === "delete" ? "-" : "~"} {entry.entityType} {entry.newState && (() => { try { const parsed = JSON.parse(entry.newState); return parsed.name || parsed.title ? `: ${parsed.name || parsed.title}` : ""; } catch { return ""; } })()}
))} {entries.length === 0 && !detailQuery.isLoading && (

No entries

)}
)}
); }