@flowselections/layout-maker 1.69.5 → 1.69.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist-lib/components/AfleverbriefBuilderPage.d.ts.map +1 -1
  2. package/dist-lib/components/AfleverbriefBuilderPage.js +16 -8
  3. package/dist-lib/components/BlokOntwerperPage.d.ts.map +1 -1
  4. package/dist-lib/components/BlokOntwerperPage.js +15 -8
  5. package/dist-lib/components/FormaatOrientatieBar.d.ts +2 -1
  6. package/dist-lib/components/FormaatOrientatieBar.d.ts.map +1 -1
  7. package/dist-lib/components/FormaatOrientatieBar.js +6 -4
  8. package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
  9. package/dist-lib/components/PakbonBuilderPage.js +16 -8
  10. package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
  11. package/dist-lib/components/ProductiebonBuilderPage.js +16 -10
  12. package/dist-lib/components/SysteemLayoutMelding.d.ts +6 -0
  13. package/dist-lib/components/SysteemLayoutMelding.d.ts.map +1 -0
  14. package/dist-lib/components/SysteemLayoutMelding.js +29 -0
  15. package/dist-lib/integrations/supabase/types.d.ts +220 -10
  16. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  17. package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
  18. package/dist-lib/lib/htmlPdf.server.js +46 -4
  19. package/dist-lib/lib/layoutOpslaan.d.ts +16 -0
  20. package/dist-lib/lib/layoutOpslaan.d.ts.map +1 -0
  21. package/dist-lib/lib/layoutOpslaan.js +56 -0
  22. package/dist-lib/lib/orderData.server.d.ts.map +1 -1
  23. package/dist-lib/lib/orderData.server.js +7 -3
  24. package/dist-lib/lib/pakbonBuilder.d.ts +13 -0
  25. package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
  26. package/dist-lib/lib/pakbonBuilder.js +49 -5
  27. package/dist-lib/lib/pakbonHtml.d.ts +2 -0
  28. package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
  29. package/dist-lib/lib/pakbonHtml.js +35 -7
  30. package/dist-lib/lib/useDocumentData.d.ts +1 -0
  31. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  32. package/dist-lib/lib/useDocumentData.js +9 -2
  33. package/dist-lib/lib/versie.generated.d.ts +1 -1
  34. package/dist-lib/lib/versie.generated.js +1 -1
  35. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"AfleverbriefBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/AfleverbriefBuilderPage.tsx"],"names":[],"mappings":"AA8BA;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA+K7F"}
1
+ {"version":3,"file":"AfleverbriefBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/AfleverbriefBuilderPage.tsx"],"names":[],"mappings":"AAgCA;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BAsL7F"}
@@ -11,7 +11,9 @@ import { AFLEVERBRIEF_SECTIE_TYPES, leesAfleverbriefConfig, } from "../lib/pakbo
11
11
  import { renderPakbonDocument, voorbeeldPakbonOrder } from "../lib/pakbonHtml.js";
12
12
  import { voorbeeldPrint } from "../lib/voorbeeldPrint.js";
13
13
  import { haalPrintLogos } from "../lib/logoLibrary.js";
14
- import { updateLayout, useLayoutDetail } from "../lib/useDocumentData.js";
14
+ import { useLayoutDetail } from "../lib/useDocumentData.js";
15
+ import { bewaarIndeling, foutTekstVan, opgeslagenMelding } from "../lib/layoutOpslaan.js";
16
+ import { SysteemLayoutMelding } from "./SysteemLayoutMelding.js";
15
17
  import { LayoutPrinterSelect } from "./LayoutPrinterSelect.js";
16
18
  import { useLayoutIdParam } from "../lib/useLayoutIdParam.js";
17
19
  /**
@@ -28,6 +30,7 @@ export function AfleverbriefBuilderPage({ layoutId: layoutIdProp } = {}) {
28
30
  const [printen, setPrinten] = useState(false);
29
31
  const [logos, setLogos] = useState([]);
30
32
  const [controle, setControle] = useState("controleren");
33
+ const [controleFout, setControleFout] = useState(null);
31
34
  useEffect(() => {
32
35
  void haalPrintLogos()
33
36
  .then((l) => setLogos(Array.isArray(l) ? l : []))
@@ -41,15 +44,20 @@ export function AfleverbriefBuilderPage({ layoutId: layoutIdProp } = {}) {
41
44
  const hoogte = useMemo(() => (layout?.orientatie === "landscape" ? layout?.breedte_mm : layout?.hoogte_mm) ?? 297, [layout]);
42
45
  const marge = Number(layout?.marge_boven ?? 10);
43
46
  const opslaan = async () => {
44
- if (!layout || !config || controle !== "gereed")
47
+ if (!layout || !config || layout.systeem)
45
48
  return;
46
49
  setBezig(true);
47
50
  try {
48
- await updateLayout(layout.id, { config: { ...(layout.config ?? {}), afleverbrief: config } });
49
- toast.success("Afleverbriefopbouw opgeslagen");
51
+ const opgeslagen = await bewaarIndeling(layout.id, layout.config, "afleverbrief", config);
52
+ setLayout((l) => (l ? { ...l, config: opgeslagen } : l));
53
+ const melding = opgeslagenMelding("Afleverbriefopbouw opgeslagen", controle, controleFout);
54
+ if (melding.soort === "succes")
55
+ toast.success(melding.tekst);
56
+ else
57
+ toast.warning(melding.tekst);
50
58
  }
51
- catch {
52
- toast.error("Opslaan mislukt");
59
+ catch (e) {
60
+ toast.error(foutTekstVan(e));
53
61
  }
54
62
  finally {
55
63
  setBezig(false);
@@ -92,10 +100,10 @@ export function AfleverbriefBuilderPage({ layoutId: layoutIdProp } = {}) {
92
100
  }
93
101
  };
94
102
  if (!layoutId)
95
- return (_jsxs("main", { className: "p-6 text-sm text-muted-foreground", children: ["Kies eerst een layout via ", _jsx(Link, { to: "/layouts-printers", className: "underline", children: "Layouts" }), "."] }));
103
+ return (_jsxs("main", { className: "p-6 text-sm text-muted-foreground", children: ["Kies eerst een layout via ", _jsx(Link, { to: "/layouts-printers/documenten", className: "underline", children: "Layouts" }), "."] }));
96
104
  if (loading)
97
105
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout laden\u2026" });
98
106
  if (!layout || !config)
99
107
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout niet gevonden." });
100
- return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: _jsxs(Link, { to: "/layouts-printers", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Layouts"] }) }), _jsxs("div", { children: [_jsx("h1", { className: "text-lg font-semibold", children: layout.naam }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Afleverbrief per kar \u00B7 ", config.secties.length, " secties"] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(LayoutPrinterSelect, { layoutId: layoutId }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void voorbeeldPrinten(), disabled: printen || controle !== "gereed", children: [printen ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Voorbeeld printen"] }), _jsx(Button, { size: "sm", variant: "outline", asChild: true, children: _jsx(Link, { to: "/layouts-printers/blokken/$layoutId", params: { layoutId }, children: "Blokken ontwerpen" }) }), _jsxs(Button, { size: "sm", onClick: opslaan, disabled: bezig || controle !== "gereed", children: [_jsx(Save, { className: "mr-2 h-4 w-4" }), " Opslaan"] })] })] }), _jsx(FormaatOrientatieBar, { layout: layout, onChange: (patch) => setLayout((l) => (l ? { ...l, ...patch } : l)) }), _jsxs("div", { className: "grid items-start gap-4 lg:grid-cols-[400px_1fr]", children: [_jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden lg:sticky lg:top-4", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Secties" }), _jsx(CardDescription, { children: "Voeg blokken toe, wijzig de volgorde en stel elk blok afzonderlijk in." })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx(PakbonSectiesPanel, { config: config, onChange: setConfig, beschikbareTypes: AFLEVERBRIEF_SECTIE_TYPES }) })] }), _jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden", children: [_jsxs(CardHeader, { className: "flex-row items-center justify-between space-y-0 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Live voorbeeld" }), _jsx(CardDescription, { children: "Voorbeeld van de afleverbrief van \u00E9\u00E9n kar." })] }), _jsxs(Badge, { variant: controle === "afwijking" ? "destructive" : "secondary", children: [controle === "controleren" ? _jsx(Loader2, { className: "mr-1 h-3 w-3 animate-spin" }) : controle === "gereed" ? _jsx(CheckCircle2, { className: "mr-1 h-3 w-3" }) : _jsx(AlertTriangle, { className: "mr-1 h-3 w-3" }), controle === "controleren" ? "Controleren" : controle === "gereed" ? "Afdruk gereed" : "Afwijking gevonden"] })] }), _jsxs(CardContent, { className: "flex min-h-0 flex-1 flex-col overflow-hidden p-0", children: [_jsx(FustKolomVolgorde, { config: config, onChange: setConfig }), _jsx("div", { className: "min-h-0 flex-1 p-4 pt-3", children: _jsx("div", { className: "h-full rounded-md border bg-muted/30 p-2", children: voorbeeldHtml ? (_jsx(PdfVoorbeeld, { html: voorbeeldHtml, breedteMm: breedte, hoogteMm: hoogte, margeMm: marge, onControle: (status) => setControle(status) })) : null }) })] })] })] })] }));
108
+ return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: _jsxs(Link, { to: "/layouts-printers/documenten", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Layouts"] }) }), _jsxs("div", { children: [_jsx("h1", { className: "text-lg font-semibold", children: layout.naam }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Afleverbrief per kar \u00B7 ", config.secties.length, " secties"] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(LayoutPrinterSelect, { layoutId: layoutId }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void voorbeeldPrinten(), disabled: printen || controle !== "gereed", children: [printen ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Voorbeeld printen"] }), _jsx(Button, { size: "sm", variant: "outline", asChild: true, children: _jsx(Link, { to: "/layouts-printers/blokken/$layoutId", params: { layoutId }, children: "Blokken ontwerpen" }) }), _jsxs(Button, { size: "sm", onClick: opslaan, disabled: bezig || Boolean(layout.systeem), children: [_jsx(Save, { className: "mr-2 h-4 w-4" }), " Opslaan"] })] })] }), layout.systeem ? _jsx(SysteemLayoutMelding, { layoutId: layout.id, route: "afleverbrief" }) : null, _jsx(FormaatOrientatieBar, { layout: layout, onChange: (patch) => setLayout((l) => (l ? { ...l, ...patch } : l)), vergrendeld: Boolean(layout.systeem) }), _jsxs("div", { className: "grid items-start gap-4 lg:grid-cols-[400px_1fr]", children: [_jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden lg:sticky lg:top-4", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Secties" }), _jsx(CardDescription, { children: "Voeg blokken toe, wijzig de volgorde en stel elk blok afzonderlijk in." })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx(PakbonSectiesPanel, { config: config, onChange: setConfig, beschikbareTypes: AFLEVERBRIEF_SECTIE_TYPES }) })] }), _jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden", children: [_jsxs(CardHeader, { className: "flex-row items-center justify-between space-y-0 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Live voorbeeld" }), _jsx(CardDescription, { children: "Voorbeeld van de afleverbrief van \u00E9\u00E9n kar." })] }), _jsxs(Badge, { variant: controle === "afwijking" ? "destructive" : "secondary", children: [controle === "controleren" ? _jsx(Loader2, { className: "mr-1 h-3 w-3 animate-spin" }) : controle === "gereed" ? _jsx(CheckCircle2, { className: "mr-1 h-3 w-3" }) : _jsx(AlertTriangle, { className: "mr-1 h-3 w-3" }), controle === "controleren" ? "Controleren" : controle === "gereed" ? "Afdruk gereed" : "Afwijking gevonden"] })] }), _jsxs(CardContent, { className: "flex min-h-0 flex-1 flex-col overflow-hidden p-0", children: [_jsx(FustKolomVolgorde, { config: config, onChange: setConfig }), _jsx("div", { className: "min-h-0 flex-1 p-4 pt-3", children: _jsx("div", { className: "h-full rounded-md border bg-muted/30 p-2", children: voorbeeldHtml ? (_jsx(PdfVoorbeeld, { html: voorbeeldHtml, breedteMm: breedte, hoogteMm: hoogte, margeMm: marge, onControle: (status, fout) => { setControle(status); setControleFout(fout ?? null); } })) : null }) })] })] })] })] }));
101
109
  }
@@ -1 +1 @@
1
- {"version":3,"file":"BlokOntwerperPage.d.ts","sourceRoot":"","sources":["../../src/components/BlokOntwerperPage.tsx"],"names":[],"mappings":"AAkCA,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BAoMvF"}
1
+ {"version":3,"file":"BlokOntwerperPage.d.ts","sourceRoot":"","sources":["../../src/components/BlokOntwerperPage.tsx"],"names":[],"mappings":"AAoCA,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA+MvF"}
@@ -6,12 +6,14 @@ import { ArrowLeft, Plus, Save } from "lucide-react";
6
6
  import { PakbonSectieEditor, PakbonBlokKaderEditor } from "./PakbonSectiesPanel.js";
7
7
  import { PakbonSectiePreview } from "./PakbonPreview.js";
8
8
  import { SECTIE_REGISTER, leesAfleverbriefConfig, leesPakbonConfig, nieuweSectie, sectieDef, } from "../lib/pakbonBuilder.js";
9
- import { updateLayout, useLayoutDetail } from "../lib/useDocumentData.js";
9
+ import { useLayoutDetail } from "../lib/useDocumentData.js";
10
+ import { bewaarIndeling, foutTekstVan, opgeslagenMelding } from "../lib/layoutOpslaan.js";
11
+ import { SysteemLayoutMelding } from "./SysteemLayoutMelding.js";
10
12
  import { useLayoutIdParam } from "../lib/useLayoutIdParam.js";
11
13
  /** Ontwerp elk pakbon-blok afzonderlijk, los van de volledige pagina. */
12
14
  export function BlokOntwerperPage({ layoutId: layoutIdProp } = {}) {
13
15
  const layoutId = useLayoutIdParam(layoutIdProp);
14
- const { layout, loading } = useLayoutDetail(layoutId ?? "");
16
+ const { layout, setLayout, loading } = useLayoutDetail(layoutId ?? "");
15
17
  const [config, setConfig] = useState(null);
16
18
  const [actief, setActief] = useState(null);
17
19
  const [toevoegen, setToevoegen] = useState("orderregels");
@@ -44,23 +46,28 @@ export function BlokOntwerperPage({ layoutId: layoutIdProp } = {}) {
44
46
  const sleutel = layout.documenttype === "afleverbrief" || layout.documenttype === "veilingbrief"
45
47
  ? "afleverbrief"
46
48
  : "pakbon";
47
- await updateLayout(layout.id, { config: { ...(layout.config ?? {}), [sleutel]: config } });
48
- toast.success("Blokontwerp opgeslagen");
49
+ const opgeslagen = await bewaarIndeling(layout.id, layout.config, sleutel, config);
50
+ setLayout((l) => (l ? { ...l, config: opgeslagen } : l));
51
+ const melding = opgeslagenMelding("Blokontwerp opgeslagen", "gereed");
52
+ if (melding.soort === "succes")
53
+ toast.success(melding.tekst);
54
+ else
55
+ toast.warning(melding.tekst);
49
56
  }
50
- catch {
51
- toast.error("Opslaan mislukt");
57
+ catch (e) {
58
+ toast.error(foutTekstVan(e));
52
59
  }
53
60
  finally {
54
61
  setBezig(false);
55
62
  }
56
63
  };
57
64
  if (!layoutId)
58
- return (_jsxs("main", { className: "p-6 text-sm text-muted-foreground", children: ["Kies eerst een layout via ", _jsx(Link, { to: "/layouts-printers", className: "underline", children: "Layouts" }), "."] }));
65
+ return (_jsxs("main", { className: "p-6 text-sm text-muted-foreground", children: ["Kies eerst een layout via ", _jsx(Link, { to: "/layouts-printers/documenten", className: "underline", children: "Layouts" }), "."] }));
59
66
  if (loading)
60
67
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout laden\u2026" });
61
68
  if (!layout || !config)
62
69
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout niet gevonden." });
63
- return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: _jsxs(Link, { to: "/layouts-printers/pakbon/$layoutId", params: { layoutId }, children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Pakbonopbouw"] }) }), _jsxs("div", { children: [_jsx("h1", { className: "text-lg font-semibold", children: "Blokken ontwerpen" }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [layout.naam, " \u00B7 elk blok afzonderlijk vormgeven"] })] })] }), _jsxs(Button, { size: "sm", onClick: opslaan, disabled: bezig, children: [_jsx(Save, { className: "mr-2 h-4 w-4" }), " Opslaan"] })] }), _jsxs("div", { className: "grid gap-4 lg:grid-cols-[240px_1fr_360px]", children: [_jsxs(Card, { className: "h-fit", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Blokken" }), _jsx(CardDescription, { children: "Kies welk blok je wilt ontwerpen." })] }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "space-y-1", children: [secties.map((s) => (_jsxs("button", { type: "button", onClick: () => setActief(s.id), className: `flex w-full items-center justify-between rounded-md border px-2 py-1.5 text-left text-sm ${s.id === actief ? "border-primary bg-accent" : "hover:bg-accent/50"}`, children: [_jsx("span", { className: "truncate", children: s.titel }), !s.zichtbaar && _jsx(Badge, { variant: "outline", children: "verborgen" })] }, s.id))), secties.length === 0 && (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen blokken." }))] }), _jsx(Separator, {}), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Select, { value: toevoegen, onValueChange: (v) => setToevoegen(v), children: [_jsx(SelectTrigger, { className: "h-8", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: SECTIE_REGISTER.map((d) => (_jsx(SelectItem, { value: d.type, children: d.label }, d.type))) })] }), _jsx(Button, { size: "sm", onClick: () => {
70
+ return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: layout.documenttype === "afleverbrief" || layout.documenttype === "veilingbrief" ? (_jsxs(Link, { to: "/layouts-printers/afleverbrief/$layoutId", params: { layoutId }, children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Afleverbriefopbouw"] })) : (_jsxs(Link, { to: "/layouts-printers/pakbon/$layoutId", params: { layoutId }, children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Pakbonopbouw"] })) }), _jsxs("div", { children: [_jsx("h1", { className: "text-lg font-semibold", children: "Blokken ontwerpen" }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [layout.naam, " \u00B7 elk blok afzonderlijk vormgeven"] })] })] }), _jsxs(Button, { size: "sm", onClick: opslaan, disabled: bezig, children: [_jsx(Save, { className: "mr-2 h-4 w-4" }), " Opslaan"] })] }), layout.systeem ? _jsx(SysteemLayoutMelding, { layoutId: layout.id, route: "blokken" }) : null, _jsxs("div", { className: "grid gap-4 lg:grid-cols-[240px_1fr_360px]", children: [_jsxs(Card, { className: "h-fit", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Blokken" }), _jsx(CardDescription, { children: "Kies welk blok je wilt ontwerpen." })] }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "space-y-1", children: [secties.map((s) => (_jsxs("button", { type: "button", onClick: () => setActief(s.id), className: `flex w-full items-center justify-between rounded-md border px-2 py-1.5 text-left text-sm ${s.id === actief ? "border-primary bg-accent" : "hover:bg-accent/50"}`, children: [_jsx("span", { className: "truncate", children: s.titel }), !s.zichtbaar && _jsx(Badge, { variant: "outline", children: "verborgen" })] }, s.id))), secties.length === 0 && (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen blokken." }))] }), _jsx(Separator, {}), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Select, { value: toevoegen, onValueChange: (v) => setToevoegen(v), children: [_jsx(SelectTrigger, { className: "h-8", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: SECTIE_REGISTER.map((d) => (_jsx(SelectItem, { value: d.type, children: d.label }, d.type))) })] }), _jsx(Button, { size: "sm", onClick: () => {
64
71
  const s = nieuweSectie(toevoegen);
65
72
  setConfig({ ...config, secties: [...secties, s] });
66
73
  setActief(s.id);
@@ -3,8 +3,9 @@ import { type LayoutModel } from "../lib/documentTypes.js";
3
3
  * Formaat- en oriëntatiekeuze die in elke ontwerp-editor beschikbaar is.
4
4
  * Wijzigingen worden direct opgeslagen en lokaal doorgegeven aan de preview.
5
5
  */
6
- export declare function FormaatOrientatieBar({ layout, onChange, }: {
6
+ export declare function FormaatOrientatieBar({ layout, onChange, vergrendeld, }: {
7
7
  layout: LayoutModel;
8
8
  onChange: (patch: Partial<LayoutModel>) => void;
9
+ vergrendeld?: boolean;
9
10
  }): import("react").JSX.Element;
10
11
  //# sourceMappingURL=FormaatOrientatieBar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FormaatOrientatieBar.d.ts","sourceRoot":"","sources":["../../src/components/FormaatOrientatieBar.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGxE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;CACjD,+BAgHA"}
1
+ {"version":3,"file":"FormaatOrientatieBar.d.ts","sourceRoot":"","sources":["../../src/components/FormaatOrientatieBar.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIxE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,QAAQ,EACR,WAAmB,GACpB,EAAE;IACD,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,+BAiHA"}
@@ -4,12 +4,14 @@ import { Button, Input, Label, Select, SelectContent, SelectItem, SelectTrigger,
4
4
  import { RectangleHorizontal, RectangleVertical } from "lucide-react";
5
5
  import { PAPIERFORMATEN } from "../lib/documentTypes.js";
6
6
  import { updateLayout } from "../lib/useDocumentData.js";
7
+ import { foutTekstVan } from "../lib/layoutOpslaan.js";
7
8
  /**
8
9
  * Formaat- en oriëntatiekeuze die in elke ontwerp-editor beschikbaar is.
9
10
  * Wijzigingen worden direct opgeslagen en lokaal doorgegeven aan de preview.
10
11
  */
11
- export function FormaatOrientatieBar({ layout, onChange, }) {
12
- const [bezig, setBezig] = useState(false);
12
+ export function FormaatOrientatieBar({ layout, onChange, vergrendeld = false, }) {
13
+ const [opslaanBezig, setBezig] = useState(false);
14
+ const bezig = opslaanBezig || vergrendeld;
13
15
  const vrij = layout.papierformaat === "VRIJ";
14
16
  const bewaar = async (patch) => {
15
17
  onChange(patch);
@@ -17,8 +19,8 @@ export function FormaatOrientatieBar({ layout, onChange, }) {
17
19
  try {
18
20
  await updateLayout(layout.id, patch);
19
21
  }
20
- catch {
21
- toast.error("Formaat opslaan mislukt");
22
+ catch (e) {
23
+ toast.error(`Formaat opslaan mislukt: ${foutTekstVan(e)}`);
22
24
  }
23
25
  finally {
24
26
  setBezig(false);
@@ -1 +1 @@
1
- {"version":3,"file":"PakbonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/PakbonBuilderPage.tsx"],"names":[],"mappings":"AA+BA,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA8LvF"}
1
+ {"version":3,"file":"PakbonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/PakbonBuilderPage.tsx"],"names":[],"mappings":"AAiCA,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BAqMvF"}
@@ -10,7 +10,9 @@ import { leesPakbonConfig, pickMethode } from "../lib/pakbonBuilder.js";
10
10
  import { renderPakbonDocument, voorbeeldPakbonOrder } from "../lib/pakbonHtml.js";
11
11
  import { voorbeeldPrint } from "../lib/voorbeeldPrint.js";
12
12
  import { haalPrintLogos } from "../lib/logoLibrary.js";
13
- import { updateLayout, useLayoutDetail } from "../lib/useDocumentData.js";
13
+ import { useLayoutDetail } from "../lib/useDocumentData.js";
14
+ import { bewaarIndeling, foutTekstVan, opgeslagenMelding } from "../lib/layoutOpslaan.js";
15
+ import { SysteemLayoutMelding } from "./SysteemLayoutMelding.js";
14
16
  import { LayoutPrinterSelect } from "./LayoutPrinterSelect.js";
15
17
  import { useLayoutIdParam } from "../lib/useLayoutIdParam.js";
16
18
  /** Sectiegebaseerde pakbon-builder met live voorbeeld op echte ordergegevens. */
@@ -23,6 +25,7 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
23
25
  const [voorbeeldVariant, setVoorbeeldVariant] = useState("full_cart");
24
26
  const [logos, setLogos] = useState([]);
25
27
  const [controle, setControle] = useState("controleren");
28
+ const [controleFout, setControleFout] = useState(null);
26
29
  useEffect(() => {
27
30
  void haalPrintLogos()
28
31
  .then((l) => setLogos(Array.isArray(l) ? l : []))
@@ -36,15 +39,20 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
36
39
  const hoogte = useMemo(() => (layout?.orientatie === "landscape" ? layout?.breedte_mm : layout?.hoogte_mm) ?? 297, [layout]);
37
40
  const marge = Number(layout?.marge_boven ?? 10);
38
41
  const opslaan = async () => {
39
- if (!layout || !config || controle !== "gereed")
42
+ if (!layout || !config || layout.systeem)
40
43
  return;
41
44
  setBezig(true);
42
45
  try {
43
- await updateLayout(layout.id, { config: { ...(layout.config ?? {}), pakbon: config } });
44
- toast.success("Pakbonopbouw opgeslagen");
46
+ const opgeslagen = await bewaarIndeling(layout.id, layout.config, "pakbon", config);
47
+ setLayout((l) => (l ? { ...l, config: opgeslagen } : l));
48
+ const melding = opgeslagenMelding("Pakbonopbouw opgeslagen", controle, controleFout);
49
+ if (melding.soort === "succes")
50
+ toast.success(melding.tekst);
51
+ else
52
+ toast.warning(melding.tekst);
45
53
  }
46
- catch {
47
- toast.error("Opslaan mislukt");
54
+ catch (e) {
55
+ toast.error(foutTekstVan(e));
48
56
  }
49
57
  finally {
50
58
  setBezig(false);
@@ -89,10 +97,10 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
89
97
  }
90
98
  };
91
99
  if (!layoutId)
92
- return (_jsxs("main", { className: "p-6 text-sm text-muted-foreground", children: ["Kies eerst een layout via ", _jsx(Link, { to: "/layouts-printers", className: "underline", children: "Layouts" }), "."] }));
100
+ return (_jsxs("main", { className: "p-6 text-sm text-muted-foreground", children: ["Kies eerst een layout via ", _jsx(Link, { to: "/layouts-printers/documenten", className: "underline", children: "Layouts" }), "."] }));
93
101
  if (loading)
94
102
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout laden\u2026" });
95
103
  if (!layout || !config)
96
104
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout niet gevonden." });
97
- return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: _jsxs(Link, { to: "/layouts-printers", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Layouts"] }) }), _jsxs("div", { children: [_jsx("h1", { className: "text-lg font-semibold", children: layout.naam }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Pakbon opbouwen uit secties \u00B7 ", config.secties.length, " secties"] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(LayoutPrinterSelect, { layoutId: layoutId }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void voorbeeldPrinten(), disabled: printen || controle !== "gereed", children: [printen ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Voorbeeld printen"] }), _jsx(Button, { size: "sm", variant: "outline", asChild: true, children: _jsx(Link, { to: "/layouts-printers/blokken/$layoutId", params: { layoutId }, children: "Blokken ontwerpen" }) }), _jsxs(Button, { size: "sm", onClick: opslaan, disabled: bezig || controle !== "gereed", children: [_jsx(Save, { className: "mr-2 h-4 w-4" }), " Opslaan"] })] })] }), _jsx(FormaatOrientatieBar, { layout: layout, onChange: (patch) => setLayout((l) => (l ? { ...l, ...patch } : l)) }), _jsxs("div", { className: "grid items-start gap-4 lg:grid-cols-[400px_1fr]", children: [_jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden lg:sticky lg:top-4", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Secties" }), _jsx(CardDescription, { children: "Voeg blokken toe, wijzig de volgorde en stel elk blok afzonderlijk in." })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx(PakbonSectiesPanel, { config: config, onChange: setConfig }) })] }), _jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden", children: [_jsxs(CardHeader, { className: "flex-row items-center justify-between space-y-0 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Live voorbeeld" }), _jsx(CardDescription, { children: "Bekijk een volle kar of een deelkar met alleen de te verzamelen fusten." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Select, { value: voorbeeldVariant, onValueChange: (value) => setVoorbeeldVariant(value), children: [_jsx(SelectTrigger, { className: "w-48", "aria-label": "Voorbeeldvariant", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "full_cart", children: "Volle kar" }), _jsx(SelectItem, { value: "partial_order", children: "Deelkar" })] })] }), _jsxs(Badge, { variant: controle === "afwijking" ? "destructive" : "secondary", children: [controle === "controleren" ? _jsx(Loader2, { className: "mr-1 h-3 w-3 animate-spin" }) : controle === "gereed" ? _jsx(CheckCircle2, { className: "mr-1 h-3 w-3" }) : _jsx(AlertTriangle, { className: "mr-1 h-3 w-3" }), controle === "controleren" ? "Controleren" : controle === "gereed" ? "Afdruk gereed" : "Afwijking gevonden"] })] })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-hidden", children: _jsx("div", { className: "h-full rounded-md border bg-muted/30 p-2", children: voorbeeldHtml ? (_jsx(PdfVoorbeeld, { html: voorbeeldHtml, breedteMm: breedte, hoogteMm: hoogte, margeMm: marge, onControle: (status) => setControle(status) })) : null }) })] })] })] }));
105
+ return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: _jsxs(Link, { to: "/layouts-printers/documenten", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Layouts"] }) }), _jsxs("div", { children: [_jsx("h1", { className: "text-lg font-semibold", children: layout.naam }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Pakbon opbouwen uit secties \u00B7 ", config.secties.length, " secties"] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(LayoutPrinterSelect, { layoutId: layoutId }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void voorbeeldPrinten(), disabled: printen || controle !== "gereed", children: [printen ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Voorbeeld printen"] }), _jsx(Button, { size: "sm", variant: "outline", asChild: true, children: _jsx(Link, { to: "/layouts-printers/blokken/$layoutId", params: { layoutId }, children: "Blokken ontwerpen" }) }), _jsxs(Button, { size: "sm", onClick: opslaan, disabled: bezig || Boolean(layout.systeem), children: [_jsx(Save, { className: "mr-2 h-4 w-4" }), " Opslaan"] })] })] }), layout.systeem ? _jsx(SysteemLayoutMelding, { layoutId: layout.id, route: "pakbon" }) : null, _jsx(FormaatOrientatieBar, { layout: layout, onChange: (patch) => setLayout((l) => (l ? { ...l, ...patch } : l)), vergrendeld: Boolean(layout.systeem) }), _jsxs("div", { className: "grid items-start gap-4 lg:grid-cols-[400px_1fr]", children: [_jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden lg:sticky lg:top-4", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Secties" }), _jsx(CardDescription, { children: "Voeg blokken toe, wijzig de volgorde en stel elk blok afzonderlijk in." })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx(PakbonSectiesPanel, { config: config, onChange: setConfig }) })] }), _jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden", children: [_jsxs(CardHeader, { className: "flex-row items-center justify-between space-y-0 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Live voorbeeld" }), _jsx(CardDescription, { children: "Bekijk een volle kar of een deelkar met alleen de te verzamelen fusten." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Select, { value: voorbeeldVariant, onValueChange: (value) => setVoorbeeldVariant(value), children: [_jsx(SelectTrigger, { className: "w-48", "aria-label": "Voorbeeldvariant", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "full_cart", children: "Volle kar" }), _jsx(SelectItem, { value: "partial_order", children: "Deelkar" })] })] }), _jsxs(Badge, { variant: controle === "afwijking" ? "destructive" : "secondary", children: [controle === "controleren" ? _jsx(Loader2, { className: "mr-1 h-3 w-3 animate-spin" }) : controle === "gereed" ? _jsx(CheckCircle2, { className: "mr-1 h-3 w-3" }) : _jsx(AlertTriangle, { className: "mr-1 h-3 w-3" }), controle === "controleren" ? "Controleren" : controle === "gereed" ? "Afdruk gereed" : "Afwijking gevonden"] })] })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-hidden", children: _jsx("div", { className: "h-full rounded-md border bg-muted/30 p-2", children: voorbeeldHtml ? (_jsx(PdfVoorbeeld, { html: voorbeeldHtml, breedteMm: breedte, hoogteMm: hoogte, margeMm: marge, onControle: (status, fout) => { setControle(status); setControleFout(fout ?? null); } })) : null }) })] })] })] }));
98
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ProductiebonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/ProductiebonBuilderPage.tsx"],"names":[],"mappings":"AAuBA,+EAA+E;AAC/E,wBAAgB,uBAAuB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BAsJ7F"}
1
+ {"version":3,"file":"ProductiebonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/ProductiebonBuilderPage.tsx"],"names":[],"mappings":"AAyBA,+EAA+E;AAC/E,wBAAgB,uBAAuB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA2J7F"}
@@ -7,7 +7,9 @@ import { ProductiebonBlokkenPanel } from "./ProductiebonBlokkenPanel.js";
7
7
  import { PdfVoorbeeld } from "./PdfVoorbeeld.js";
8
8
  import { FormaatOrientatieBar } from "./FormaatOrientatieBar.js";
9
9
  import { leesProductiebonConfig } from "../lib/productiebonBuilder.js";
10
- import { updateLayout, useLayoutDetail } from "../lib/useDocumentData.js";
10
+ import { useLayoutDetail } from "../lib/useDocumentData.js";
11
+ import { bewaarIndeling, foutTekstVan, opgeslagenMelding } from "../lib/layoutOpslaan.js";
12
+ import { SysteemLayoutMelding } from "./SysteemLayoutMelding.js";
11
13
  import { LayoutPrinterSelect } from "./LayoutPrinterSelect.js";
12
14
  import { useLayoutIdParam } from "../lib/useLayoutIdParam.js";
13
15
  import { renderProductiebonDocument } from "../lib/productiebonHtml.js";
@@ -20,6 +22,7 @@ export function ProductiebonBuilderPage({ layoutId: layoutIdProp } = {}) {
20
22
  const [bezig, setBezig] = useState(false);
21
23
  const [printen, setPrinten] = useState(false);
22
24
  const [controle, setControle] = useState("controleren");
25
+ const [controleFout, setControleFout] = useState(null);
23
26
  useEffect(() => {
24
27
  if (layout)
25
28
  setConfig(leesProductiebonConfig(layout.config));
@@ -33,17 +36,20 @@ export function ProductiebonBuilderPage({ layoutId: layoutIdProp } = {}) {
33
36
  return renderProductiebonDocument({ productiebon: config }, {}, { breedteMm: breedte, hoogteMm: hoogte, margeMm: marge, titel: layout?.naam ?? "Productiebon" });
34
37
  }, [config, breedte, hoogte, marge, layout?.naam]);
35
38
  const opslaan = async () => {
36
- if (!layout || !config || controle !== "gereed")
39
+ if (!layout || !config || layout.systeem)
37
40
  return;
38
41
  setBezig(true);
39
42
  try {
40
- await updateLayout(layout.id, {
41
- config: { ...(layout.config ?? {}), productiebon: config },
42
- });
43
- toast.success("Productiebon opgeslagen");
43
+ const opgeslagen = await bewaarIndeling(layout.id, layout.config, "productiebon", config);
44
+ setLayout((l) => (l ? { ...l, config: opgeslagen } : l));
45
+ const melding = opgeslagenMelding("Productiebon opgeslagen", controle, controleFout);
46
+ if (melding.soort === "succes")
47
+ toast.success(melding.tekst);
48
+ else
49
+ toast.warning(melding.tekst);
44
50
  }
45
- catch {
46
- toast.error("Opslaan mislukt");
51
+ catch (e) {
52
+ toast.error(foutTekstVan(e));
47
53
  }
48
54
  finally {
49
55
  setBezig(false);
@@ -70,10 +76,10 @@ export function ProductiebonBuilderPage({ layoutId: layoutIdProp } = {}) {
70
76
  }
71
77
  };
72
78
  if (!layoutId)
73
- return (_jsxs("main", { className: "p-6 text-sm text-muted-foreground", children: ["Kies eerst een layout via ", _jsx(Link, { to: "/layouts-printers", className: "underline", children: "Layouts" }), "."] }));
79
+ return (_jsxs("main", { className: "p-6 text-sm text-muted-foreground", children: ["Kies eerst een layout via ", _jsx(Link, { to: "/layouts-printers/documenten", className: "underline", children: "Layouts" }), "."] }));
74
80
  if (loading)
75
81
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout laden\u2026" });
76
82
  if (!layout || !config)
77
83
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout niet gevonden." });
78
- return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: _jsxs(Link, { to: "/layouts-printers", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Layouts"] }) }), _jsxs("div", { children: [_jsx("h1", { className: "text-lg font-semibold", children: layout.naam }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Productiebon opbouwen uit blokken \u00B7 ", config.blokken.length, " blokken"] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [layoutId ? _jsx(LayoutPrinterSelect, { layoutId: layoutId }) : null, _jsxs(Button, { size: "sm", variant: "outline", onClick: voorbeeldPrinten, disabled: printen || controle !== "gereed", children: [printen ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Voorbeeld printen"] }), _jsxs(Button, { size: "sm", onClick: opslaan, disabled: bezig || controle !== "gereed", children: [_jsx(Save, { className: "mr-2 h-4 w-4" }), " Opslaan"] })] })] }), _jsx(FormaatOrientatieBar, { layout: layout, onChange: (patch) => setLayout((l) => (l ? { ...l, ...patch } : l)) }), _jsxs("div", { className: "grid items-start gap-4 lg:grid-cols-[400px_1fr]", children: [_jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden lg:sticky lg:top-4", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Blokken" }), _jsx(CardDescription, { children: "Voeg blokken toe, wijzig de volgorde en stel elk blok afzonderlijk in." })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx(ProductiebonBlokkenPanel, { config: config, onChange: setConfig }) })] }), _jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden", children: [_jsxs(CardHeader, { className: "flex-row items-center justify-between space-y-0 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Live voorbeeld" }), _jsx(CardDescription, { children: "Voorbeeldproductieorder met samenstelling en belading." })] }), _jsxs(Badge, { variant: controle === "afwijking" ? "destructive" : "secondary", children: [controle === "controleren" ? _jsx(Loader2, { className: "mr-1 h-3 w-3 animate-spin" }) : controle === "gereed" ? _jsx(CheckCircle2, { className: "mr-1 h-3 w-3" }) : _jsx(AlertTriangle, { className: "mr-1 h-3 w-3" }), controle === "controleren" ? "Controleren" : controle === "gereed" ? "Afdruk gereed" : "Afwijking gevonden"] })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-hidden", children: _jsx("div", { className: "h-full overflow-hidden rounded-md border bg-muted/30 p-2", children: voorbeeldHtml ? _jsx(PdfVoorbeeld, { html: voorbeeldHtml, breedteMm: breedte, hoogteMm: hoogte, margeMm: marge, onControle: (status) => setControle(status) }) : null }) })] })] })] }));
84
+ return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, children: _jsxs(Link, { to: "/layouts-printers/documenten", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Layouts"] }) }), _jsxs("div", { children: [_jsx("h1", { className: "text-lg font-semibold", children: layout.naam }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Productiebon opbouwen uit blokken \u00B7 ", config.blokken.length, " blokken"] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [layoutId ? _jsx(LayoutPrinterSelect, { layoutId: layoutId }) : null, _jsxs(Button, { size: "sm", variant: "outline", onClick: voorbeeldPrinten, disabled: printen || controle !== "gereed", children: [printen ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Voorbeeld printen"] }), _jsxs(Button, { size: "sm", onClick: opslaan, disabled: bezig || Boolean(layout.systeem), children: [_jsx(Save, { className: "mr-2 h-4 w-4" }), " Opslaan"] })] })] }), layout.systeem ? _jsx(SysteemLayoutMelding, { layoutId: layout.id, route: "productiebon" }) : null, _jsx(FormaatOrientatieBar, { layout: layout, onChange: (patch) => setLayout((l) => (l ? { ...l, ...patch } : l)), vergrendeld: Boolean(layout.systeem) }), _jsxs("div", { className: "grid items-start gap-4 lg:grid-cols-[400px_1fr]", children: [_jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden lg:sticky lg:top-4", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Blokken" }), _jsx(CardDescription, { children: "Voeg blokken toe, wijzig de volgorde en stel elk blok afzonderlijk in." })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-y-auto", children: _jsx(ProductiebonBlokkenPanel, { config: config, onChange: setConfig }) })] }), _jsxs(Card, { className: "flex h-[calc(100vh-14rem)] min-h-[420px] flex-col overflow-hidden", children: [_jsxs(CardHeader, { className: "flex-row items-center justify-between space-y-0 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Live voorbeeld" }), _jsx(CardDescription, { children: "Voorbeeldproductieorder met samenstelling en belading." })] }), _jsxs(Badge, { variant: controle === "afwijking" ? "destructive" : "secondary", children: [controle === "controleren" ? _jsx(Loader2, { className: "mr-1 h-3 w-3 animate-spin" }) : controle === "gereed" ? _jsx(CheckCircle2, { className: "mr-1 h-3 w-3" }) : _jsx(AlertTriangle, { className: "mr-1 h-3 w-3" }), controle === "controleren" ? "Controleren" : controle === "gereed" ? "Afdruk gereed" : "Afwijking gevonden"] })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-hidden", children: _jsx("div", { className: "h-full overflow-hidden rounded-md border bg-muted/30 p-2", children: voorbeeldHtml ? _jsx(PdfVoorbeeld, { html: voorbeeldHtml, breedteMm: breedte, hoogteMm: hoogte, margeMm: marge, onControle: (status, fout) => { setControle(status); setControleFout(fout ?? null); } }) : null }) })] })] })] }));
79
85
  }
@@ -0,0 +1,6 @@
1
+ /** Melding in de builders: een systeemlayout is niet aanpasbaar; maak een kopie. */
2
+ export declare function SysteemLayoutMelding({ layoutId, route, }: {
3
+ layoutId: string;
4
+ route: "pakbon" | "afleverbrief" | "productiebon" | "blokken";
5
+ }): import("react").JSX.Element;
6
+ //# sourceMappingURL=SysteemLayoutMelding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SysteemLayoutMelding.d.ts","sourceRoot":"","sources":["../../src/components/SysteemLayoutMelding.tsx"],"names":[],"mappings":"AAOA,oFAAoF;AACpF,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,QAAQ,GAAG,cAAc,GAAG,cAAc,GAAG,SAAS,CAAC;CAC/D,+BA0BA"}
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { useNavigate } from "@tanstack/react-router";
4
+ import { Button, toast } from "@flowselections/core";
5
+ import { Copy, Lock } from "lucide-react";
6
+ import { dupliceerLayout } from "../lib/useDocumentData.js";
7
+ import { foutTekstVan } from "../lib/layoutOpslaan.js";
8
+ /** Melding in de builders: een systeemlayout is niet aanpasbaar; maak een kopie. */
9
+ export function SysteemLayoutMelding({ layoutId, route, }) {
10
+ const navigate = useNavigate();
11
+ const [bezig, setBezig] = useState(false);
12
+ const kopie = async () => {
13
+ setBezig(true);
14
+ try {
15
+ const nieuwId = await dupliceerLayout(layoutId);
16
+ if (!nieuwId)
17
+ throw new Error("Kopie maken mislukt");
18
+ toast.success("Kopie gemaakt");
19
+ void navigate({ to: `/layouts-printers/${route}/$layoutId`, params: { layoutId: String(nieuwId) } });
20
+ }
21
+ catch (e) {
22
+ toast.error(foutTekstVan(e, "Kopie maken mislukt"));
23
+ }
24
+ finally {
25
+ setBezig(false);
26
+ }
27
+ };
28
+ return (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-md border bg-muted/40 p-3 text-sm", children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx(Lock, { className: "h-4 w-4" }), " Systeemlayout \u2013 niet aanpasbaar. Maak een kopie om te wijzigen."] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void kopie(), disabled: bezig, children: [_jsx(Copy, { className: "mr-2 h-4 w-4" }), " Kopie maken"] })] }));
29
+ }