import React, { useState } from "react"; import { Plus, Pencil, Trash2, Save, Layers } from "lucide-react"; import MarkdownView from "./MarkdownView"; import PermissionGuard from "../PermissionGuard"; import { usePatches, useCreatePatch, useUpdatePatch, useDeletePatch, } from "../../utils/queries/patch-queries"; import { Button } from "../ui/button"; import { Input, Textarea, Label } from "../ui/input"; import { Spinner } from "../ui/misc"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "../ui/dialog"; const PatchCards = ({ markdownId }) => { const { data: patches, isLoading, isError } = usePatches(markdownId); const createPatch = useCreatePatch(); const updatePatch = useUpdatePatch(); const deletePatch = useDeletePatch(); // editor dialog state — `editing` is null for "create", or the patch object const [open, setOpen] = useState(false); const [editing, setEditing] = useState(null); const [title, setTitle] = useState(""); const [content, setContent] = useState(""); const openCreate = () => { setEditing(null); setTitle(""); setContent(""); setOpen(true); }; const openEdit = (patch) => { setEditing(patch); setTitle(patch.title || ""); setContent(patch.content || ""); setOpen(true); }; const handleSave = () => { if (!content.trim()) { alert("Patch content cannot be empty"); return; } const payload = { title: title.trim() || null, content }; if (editing) { updatePatch.mutate( { id: editing.id, data: payload }, { onSuccess: () => setOpen(false), onError: () => alert("Failed to update patch"), } ); } else { createPatch.mutate( { markdown_id: markdownId, ...payload }, { onSuccess: () => setOpen(false), onError: () => alert("Failed to create patch"), } ); } }; const handleDelete = (patch) => { if (!window.confirm("Delete this patch card?")) return; deletePatch.mutate( { id: patch.id, markdownId }, { onError: () => alert("Failed to delete patch") } ); }; // Non-admins on a restricted parent get an error here — fail silently so // the main markdown page is never broken by patches. if (isError) return null; const list = patches || []; const saving = createPatch.isPending || updatePatch.isPending; return (
{(isLoading || list.length > 0) && (

Patch Cards {list.length > 0 && ( {list.length} )}

)} {isLoading && }
{list.map((patch, i) => (
{patch.title || `Patch ${i + 1}`}
))}
{ if (!o) setOpen(false); }} > {editing ? "Edit Patch Card" : "New Patch Card"}
setTitle(e.target.value)} placeholder="e.g. Update 2026-05" />