import { useCallback, useEffect, useRef, useState } from "react"; import { useSearchParams } from "react-router"; import { FilePlus2, PenTool, RefreshCw, Trash2 } from "lucide-react"; import { useClient } from "hooks/useClient"; import { NEW_DOC } from "./doc-param"; /** * The list of designs — the one concept upstream does not have. * * Standalone M3E Canvas holds exactly one document, in one browser, in `localStorage`. Everything here * exists because Officer gives it several, belonging to a person rather than to a browser. * * Selection is `?doc=` in the URL rather than a channel, so a design is addressable and survives a * reload — `docs/navigation-audit.md`. The canvas panel reads the same parameter rather than being * handed the id. */ type Row = { id: number; title: string; updatedAt: string }; export const DesignsPanel = () => { const client = useClient(); const clientRef = useRef(client); clientRef.current = client; const [rows, setRows] = useState(null); const [error, setError] = useState(null); const [params, setParams] = useSearchParams(); const selected = params.get("doc"); const load = useCallback(async () => { try { setRows(await clientRef.current.get("/m3e-canvas/documents")); setError(null); } catch { setError("Could not load designs."); setRows(null); } }, []); useEffect(() => { void load(); }, [load]); /* The canvas creates the row on its first save, so New only has to ask for a blank one — a design with nothing drawn in it should not exist, and creating one here would leave empties behind every time somebody clicked New and changed their mind. `?doc=new`, and NOT clearing the parameter, which is what this did. No parameter means "open what I was last working on", which the canvas answers with `/documents/latest` — so New handed back the design already on screen and pointed the next save at it. The sentinel says the thing the absence could not: an empty one, on purpose. */ const startNew = () => setParams((p) => { p.set("doc", NEW_DOC); return p; }, { replace: true }); const remove = async (id: number, title: string) => { if (!confirm(`Delete "${title}"? This cannot be undone.`)) return; try { await clientRef.current.delete(`/m3e-canvas/documents/${id}`); if (selected === String(id)) startNew(); await load(); } catch { setError("Could not delete that design."); } }; return (
{error ?

{error}

: null} {rows === null ? ( Loading… ) : rows.length === 0 ? ( No designs yet. Draw something and it saves itself. ) : (
    {rows.map((row) => (
  • ))}
)}
); }; const Centred = ({ children }: { children: React.ReactNode }) => (
{children}
);