@flowselections/layout-maker 1.36.7 → 1.45.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 (123) hide show
  1. package/dist-lib/components/AfleverbriefBuilderPage.d.ts +10 -0
  2. package/dist-lib/components/AfleverbriefBuilderPage.d.ts.map +1 -0
  3. package/dist-lib/components/AfleverbriefBuilderPage.js +101 -0
  4. package/dist-lib/components/BlokOntwerperPage.d.ts.map +1 -1
  5. package/dist-lib/components/BlokOntwerperPage.js +8 -3
  6. package/dist-lib/components/ComputersLijst.d.ts.map +1 -1
  7. package/dist-lib/components/ComputersLijst.js +1 -1
  8. package/dist-lib/components/FustKolomVolgorde.d.ts +11 -0
  9. package/dist-lib/components/FustKolomVolgorde.d.ts.map +1 -0
  10. package/dist-lib/components/FustKolomVolgorde.js +52 -0
  11. package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
  12. package/dist-lib/components/LayoutsPage.js +10 -9
  13. package/dist-lib/components/PaginaDocument.d.ts +4 -1
  14. package/dist-lib/components/PaginaDocument.d.ts.map +1 -1
  15. package/dist-lib/components/PaginaDocument.js +10 -5
  16. package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
  17. package/dist-lib/components/PakbonBuilderPage.js +34 -14
  18. package/dist-lib/components/PakbonPreview.d.ts +4 -2
  19. package/dist-lib/components/PakbonPreview.d.ts.map +1 -1
  20. package/dist-lib/components/PakbonPreview.js +74 -24
  21. package/dist-lib/components/PakbonSectiesPanel.d.ts +5 -3
  22. package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
  23. package/dist-lib/components/PakbonSectiesPanel.js +8 -5
  24. package/dist-lib/components/PdfMapToestemmingBanner.d.ts +2 -1
  25. package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -1
  26. package/dist-lib/components/PdfMapToestemmingBanner.js +73 -14
  27. package/dist-lib/components/PdfVoorbeeld.d.ts +20 -0
  28. package/dist-lib/components/PdfVoorbeeld.d.ts.map +1 -0
  29. package/dist-lib/components/PdfVoorbeeld.js +95 -0
  30. package/dist-lib/components/PrintProgrammaUitleg.d.ts.map +1 -1
  31. package/dist-lib/components/PrintProgrammaUitleg.js +1 -1
  32. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  33. package/dist-lib/components/PrintQueuePage.js +81 -43
  34. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  35. package/dist-lib/components/PrintplekDetailPage.js +2 -2
  36. package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
  37. package/dist-lib/components/PrintplekWizard.js +6 -2
  38. package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
  39. package/dist-lib/components/ProductiebonBuilderPage.js +13 -7
  40. package/dist-lib/index.d.ts +16 -6
  41. package/dist-lib/index.d.ts.map +1 -1
  42. package/dist-lib/index.js +11 -5
  43. package/dist-lib/integrations/supabase/auth-middleware.d.ts +3585 -1267
  44. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  45. package/dist-lib/integrations/supabase/client.server.d.ts +3585 -1267
  46. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  47. package/dist-lib/integrations/supabase/moduleClient.d.ts +25898 -0
  48. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -0
  49. package/dist-lib/integrations/supabase/moduleClient.js +29 -0
  50. package/dist-lib/integrations/supabase/types.d.ts +3607 -1265
  51. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  52. package/dist-lib/integrations/supabase/types.js +1 -0
  53. package/dist-lib/lib/aiLayout.functions.d.ts +3585 -1267
  54. package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
  55. package/dist-lib/lib/code128.d.ts +5 -0
  56. package/dist-lib/lib/code128.d.ts.map +1 -0
  57. package/dist-lib/lib/code128.js +51 -0
  58. package/dist-lib/lib/documentVoorbeeld.functions.d.ts +23 -0
  59. package/dist-lib/lib/documentVoorbeeld.functions.d.ts.map +1 -0
  60. package/dist-lib/lib/documentVoorbeeld.functions.js +37 -0
  61. package/dist-lib/lib/fontMetrics.d.ts +15 -0
  62. package/dist-lib/lib/fontMetrics.d.ts.map +1 -0
  63. package/dist-lib/lib/fontMetrics.js +118 -0
  64. package/dist-lib/lib/htmlNaarPdf.server.d.ts +2 -2
  65. package/dist-lib/lib/htmlNaarPdf.server.d.ts.map +1 -1
  66. package/dist-lib/lib/htmlNaarPdf.server.js +2 -1
  67. package/dist-lib/lib/htmlPdf.server.d.ts +11 -0
  68. package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
  69. package/dist-lib/lib/htmlPdf.server.js +170 -9
  70. package/dist-lib/lib/layoutPreview.d.ts.map +1 -1
  71. package/dist-lib/lib/layoutPreview.js +6 -3
  72. package/dist-lib/lib/orderData.server.d.ts.map +1 -1
  73. package/dist-lib/lib/orderData.server.js +49 -16
  74. package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts +39 -0
  75. package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts.map +1 -0
  76. package/dist-lib/lib/pakbonBarcodeVerzoek.js +80 -0
  77. package/dist-lib/lib/pakbonBuilder.d.ts +90 -5
  78. package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
  79. package/dist-lib/lib/pakbonBuilder.js +455 -58
  80. package/dist-lib/lib/pakbonContent.d.ts +41 -0
  81. package/dist-lib/lib/pakbonContent.d.ts.map +1 -0
  82. package/dist-lib/lib/pakbonContent.js +668 -0
  83. package/dist-lib/lib/pakbonDocument.d.ts +199 -0
  84. package/dist-lib/lib/pakbonDocument.d.ts.map +1 -0
  85. package/dist-lib/lib/pakbonDocument.js +735 -0
  86. package/dist-lib/lib/pakbonHtml.d.ts +21 -2
  87. package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
  88. package/dist-lib/lib/pakbonHtml.js +144 -36
  89. package/dist-lib/lib/pakbonPresentation.d.ts +8 -0
  90. package/dist-lib/lib/pakbonPresentation.d.ts.map +1 -0
  91. package/dist-lib/lib/pakbonPresentation.js +31 -0
  92. package/dist-lib/lib/pakbonScan.d.ts +44 -0
  93. package/dist-lib/lib/pakbonScan.d.ts.map +1 -0
  94. package/dist-lib/lib/pakbonScan.js +87 -0
  95. package/dist-lib/lib/pdfJobSaver.d.ts +10 -6
  96. package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -1
  97. package/dist-lib/lib/pdfJobSaver.js +302 -99
  98. package/dist-lib/lib/pdfMap.d.ts +37 -2
  99. package/dist-lib/lib/pdfMap.d.ts.map +1 -1
  100. package/dist-lib/lib/pdfMap.js +120 -7
  101. package/dist-lib/lib/pdfOpslagStatus.d.ts +23 -0
  102. package/dist-lib/lib/pdfOpslagStatus.d.ts.map +1 -0
  103. package/dist-lib/lib/pdfOpslagStatus.js +74 -0
  104. package/dist-lib/lib/printApi.d.ts +31 -0
  105. package/dist-lib/lib/printApi.d.ts.map +1 -1
  106. package/dist-lib/lib/printApi.js +62 -1
  107. package/dist-lib/lib/printQueue.server.d.ts +13 -0
  108. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  109. package/dist-lib/lib/printQueue.server.js +673 -96
  110. package/dist-lib/lib/printService.functions.d.ts +11840 -2568
  111. package/dist-lib/lib/printService.functions.d.ts.map +1 -1
  112. package/dist-lib/lib/profielHtml.d.ts.map +1 -1
  113. package/dist-lib/lib/profielHtml.js +8 -1
  114. package/dist-lib/lib/supabaseClient.d.ts +1 -3
  115. package/dist-lib/lib/supabaseClient.d.ts.map +1 -1
  116. package/dist-lib/lib/supabaseClient.js +4 -8
  117. package/dist-lib/lib/useDocumentData.d.ts +8 -0
  118. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  119. package/dist-lib/lib/useDocumentData.js +1 -1
  120. package/dist-lib/lib/voorbeeldPrint.d.ts +3 -0
  121. package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
  122. package/dist-lib/lib/voorbeeldPrint.js +65 -17
  123. package/package.json +9 -2
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sectiegebaseerde afleverbrief-builder. Deelt het sectiesysteem met de
3
+ * pakbon-opbouw, maar slaat de indeling onder de eigen sleutel "afleverbrief"
4
+ * op en kent geen kar-, laag- of fustvarianten: een afleverbrief geldt altijd
5
+ * voor de hele levering.
6
+ */
7
+ export declare function AfleverbriefBuilderPage({ layoutId: layoutIdProp }?: {
8
+ layoutId?: string;
9
+ }): import("react").JSX.Element;
10
+ //# sourceMappingURL=AfleverbriefBuilderPage.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,101 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useState } from "react";
3
+ import { Link } from "@tanstack/react-router";
4
+ import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, toast, } from "@flowselections/core";
5
+ import { AlertTriangle, ArrowLeft, CheckCircle2, Loader2, Printer, Save } from "lucide-react";
6
+ import { PakbonSectiesPanel } from "./PakbonSectiesPanel.js";
7
+ import { PdfVoorbeeld } from "./PdfVoorbeeld.js";
8
+ import { FormaatOrientatieBar } from "./FormaatOrientatieBar.js";
9
+ import { FustKolomVolgorde } from "./FustKolomVolgorde.js";
10
+ import { AFLEVERBRIEF_SECTIE_TYPES, leesAfleverbriefConfig, } from "../lib/pakbonBuilder.js";
11
+ import { renderPakbonDocument, voorbeeldPakbonOrder } from "../lib/pakbonHtml.js";
12
+ import { voorbeeldPrint } from "../lib/voorbeeldPrint.js";
13
+ import { haalPrintLogos } from "../lib/logoLibrary.js";
14
+ import { updateLayout, useLayoutDetail } from "../lib/useDocumentData.js";
15
+ import { LayoutPrinterSelect } from "./LayoutPrinterSelect.js";
16
+ import { useLayoutIdParam } from "../lib/useLayoutIdParam.js";
17
+ /**
18
+ * Sectiegebaseerde afleverbrief-builder. Deelt het sectiesysteem met de
19
+ * pakbon-opbouw, maar slaat de indeling onder de eigen sleutel "afleverbrief"
20
+ * op en kent geen kar-, laag- of fustvarianten: een afleverbrief geldt altijd
21
+ * voor de hele levering.
22
+ */
23
+ export function AfleverbriefBuilderPage({ layoutId: layoutIdProp } = {}) {
24
+ const layoutId = useLayoutIdParam(layoutIdProp);
25
+ const { layout, setLayout, loading } = useLayoutDetail(layoutId ?? "");
26
+ const [config, setConfig] = useState(null);
27
+ const [bezig, setBezig] = useState(false);
28
+ const [printen, setPrinten] = useState(false);
29
+ const [logos, setLogos] = useState([]);
30
+ const [controle, setControle] = useState("controleren");
31
+ useEffect(() => {
32
+ void haalPrintLogos()
33
+ .then((l) => setLogos(Array.isArray(l) ? l : []))
34
+ .catch(() => setLogos([]));
35
+ }, []);
36
+ useEffect(() => {
37
+ if (layout)
38
+ setConfig(leesAfleverbriefConfig(layout.config));
39
+ }, [layout?.id]);
40
+ const breedte = useMemo(() => (layout?.orientatie === "landscape" ? layout?.hoogte_mm : layout?.breedte_mm) ?? 210, [layout]);
41
+ const hoogte = useMemo(() => (layout?.orientatie === "landscape" ? layout?.breedte_mm : layout?.hoogte_mm) ?? 297, [layout]);
42
+ const marge = Number(layout?.marge_boven ?? 10);
43
+ const opslaan = async () => {
44
+ if (!layout || !config || controle !== "gereed")
45
+ return;
46
+ setBezig(true);
47
+ try {
48
+ await updateLayout(layout.id, { config: { ...(layout.config ?? {}), afleverbrief: config } });
49
+ toast.success("Afleverbriefopbouw opgeslagen");
50
+ }
51
+ catch {
52
+ toast.error("Opslaan mislukt");
53
+ }
54
+ finally {
55
+ setBezig(false);
56
+ }
57
+ };
58
+ // Eén bron voor scherm én print: exact dezelfde HTML gaat naar de
59
+ // server-PDF van het voorbeeld en naar de printopdracht.
60
+ const voorbeeldHtml = useMemo(() => {
61
+ if (!config)
62
+ return "";
63
+ // Een afleverbrief geldt altijd voor één kar: het voorbeeld toont er dus ook maar één.
64
+ const basis = voorbeeldPakbonOrder();
65
+ const order = { ...basis, karren: (basis.karren ?? []).slice(0, 1) };
66
+ return renderPakbonDocument(config, order, {
67
+ logos: logos,
68
+ breedteMm: breedte,
69
+ hoogteMm: hoogte,
70
+ margeMm: marge,
71
+ titel: layout?.naam ?? "Afleverbrief",
72
+ });
73
+ }, [config, logos, breedte, hoogte, marge, layout?.naam]);
74
+ const voorbeeldPrinten = async () => {
75
+ if (!config || controle !== "gereed")
76
+ return;
77
+ setPrinten(true);
78
+ try {
79
+ await voorbeeldPrint({
80
+ ...(layout ?? {}),
81
+ id: layout?.id ?? layoutId,
82
+ naam: layout?.naam,
83
+ documenttype: layout?.documenttype ?? "afleverbrief",
84
+ papierformaat: layout?.papierformaat,
85
+ }, voorbeeldHtml);
86
+ }
87
+ catch (e) {
88
+ toast.error(e instanceof Error ? e.message : "Voorbeeld printen mislukt");
89
+ }
90
+ finally {
91
+ setPrinten(false);
92
+ }
93
+ };
94
+ 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" }), "."] }));
96
+ if (loading)
97
+ return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout laden\u2026" });
98
+ if (!layout || !config)
99
+ 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 }) })] })] })] })] }));
101
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"BlokOntwerperPage.d.ts","sourceRoot":"","sources":["../../src/components/BlokOntwerperPage.tsx"],"names":[],"mappings":"AAiCA,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA6LvF"}
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"}
@@ -5,7 +5,7 @@ import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitl
5
5
  import { ArrowLeft, Plus, Save } from "lucide-react";
6
6
  import { PakbonSectieEditor, PakbonBlokKaderEditor } from "./PakbonSectiesPanel.js";
7
7
  import { PakbonSectiePreview } from "./PakbonPreview.js";
8
- import { SECTIE_REGISTER, leesPakbonConfig, nieuweSectie, sectieDef, } from "../lib/pakbonBuilder.js";
8
+ import { SECTIE_REGISTER, leesAfleverbriefConfig, leesPakbonConfig, nieuweSectie, sectieDef, } from "../lib/pakbonBuilder.js";
9
9
  import { updateLayout, useLayoutDetail } from "../lib/useDocumentData.js";
10
10
  import { useLayoutIdParam } from "../lib/useLayoutIdParam.js";
11
11
  /** Ontwerp elk pakbon-blok afzonderlijk, los van de volledige pagina. */
@@ -20,7 +20,9 @@ export function BlokOntwerperPage({ layoutId: layoutIdProp } = {}) {
20
20
  useEffect(() => {
21
21
  if (!layout)
22
22
  return;
23
- const c = leesPakbonConfig(layout.config);
23
+ const c = layout.documenttype === "afleverbrief" || layout.documenttype === "veilingbrief"
24
+ ? leesAfleverbriefConfig(layout.config)
25
+ : leesPakbonConfig(layout.config);
24
26
  setConfig(c);
25
27
  setActief((huidig) => huidig ?? c.secties[0]?.id ?? null);
26
28
  }, [layout?.id]);
@@ -39,7 +41,10 @@ export function BlokOntwerperPage({ layoutId: layoutIdProp } = {}) {
39
41
  return;
40
42
  setBezig(true);
41
43
  try {
42
- await updateLayout(layout.id, { config: { ...(layout.config ?? {}), pakbon: config } });
44
+ const sleutel = layout.documenttype === "afleverbrief" || layout.documenttype === "veilingbrief"
45
+ ? "afleverbrief"
46
+ : "pakbon";
47
+ await updateLayout(layout.id, { config: { ...(layout.config ?? {}), [sleutel]: config } });
43
48
  toast.success("Blokontwerp opgeslagen");
44
49
  }
45
50
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"ComputersLijst.d.ts","sourceRoot":"","sources":["../../src/components/ComputersLijst.tsx"],"names":[],"mappings":"AAoBA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,YAAY;;;;;EA6C3B;AAED,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,OAAO,EACP,IAAI,EACJ,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,qBAAqB,EACrB,YAAoB,GACrB,EAAE;IACD,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,aAAa,EAAE,OAAO,CAAC;IACvB,qBAAqB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,+BAwIA"}
1
+ {"version":3,"file":"ComputersLijst.d.ts","sourceRoot":"","sources":["../../src/components/ComputersLijst.tsx"],"names":[],"mappings":"AAoBA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,YAAY;;;;;EA6C3B;AAED,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,OAAO,EACP,IAAI,EACJ,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,qBAAqB,EACrB,YAAoB,GACrB,EAAE;IACD,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,mBAAmB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,aAAa,EAAE,OAAO,CAAC;IACvB,qBAAqB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,+BA0IA"}
@@ -71,5 +71,5 @@ export function ComputersLijst({ computers, loading, fout, onVernieuw, onPrinter
71
71
  return (_jsxs("div", { className: alleenDialog ? "" : "space-y-3", children: [!alleenDialog && loading && _jsx("p", { className: "text-muted-foreground text-sm", children: "Laden\u2026" }), !alleenDialog && !loading && fout && (_jsx(Card, { children: _jsxs(CardContent, { className: "space-y-3 py-6", children: [_jsx("p", { className: "font-medium", children: "Geen verbinding" }), _jsx("p", { className: "text-muted-foreground text-sm", children: fout }), _jsxs(Button, { variant: "outline", onClick: onVernieuw, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), " Opnieuw proberen"] })] }) })), !alleenDialog && !loading && !fout && computers.length === 0 && (_jsx(Card, { children: _jsxs(CardContent, { className: "space-y-4 py-8", children: [_jsx(PrintProgrammaUitleg, {}), _jsxs(Button, { onClick: () => onToevoegenOpenChange(true), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Computer toevoegen"] })] }) })), !alleenDialog && computers.map((c) => (_jsxs("div", { className: "bg-card flex items-center gap-4 rounded-xl border p-4", children: [_jsx("div", { className: "bg-muted rounded-lg p-2.5", children: _jsx(Monitor, { className: "text-muted-foreground h-5 w-5" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "truncate font-medium", children: c.naam }), _jsxs("p", { className: "text-muted-foreground text-sm", children: [c.aantalGevonden, " ", c.aantalGevonden === 1 ? "printer gevonden" : "printers gevonden"] })] }), _jsx("span", { className: `rounded-full px-2.5 py-1 text-xs font-medium ${c.online ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground"}`, children: c.online ? "Aan" : "Uit" }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => onPrintersToevoegen(c.naam), children: "Printers toevoegen" })] }, c.id))), !alleenDialog && computers.length > 0 && _jsx(WerktHetNiet, {}), _jsx(Dialog, { open: toevoegenOpen, onOpenChange: onToevoegenOpenChange, children: _jsxs(DialogContent, { className: "sm:max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Computer toevoegen" }), _jsx(DialogDescription, { children: "Zet het printprogramma klaar op de computer waar de printers aan hangen." })] }), _jsx(PrintProgrammaUitleg, { compact: true }), _jsx("div", { className: "space-y-2 rounded-lg border p-4 text-sm", children: computers.length === 0 ? (_jsxs("p", { className: "text-muted-foreground flex items-center gap-2", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " We wachten tot de computer zich meldt\u2026"] })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "font-medium", children: nieuw ? `Nieuwe computer gevonden: ${nieuw.naam}` : "Gevonden computers" }), computers.map((c) => (_jsxs("div", { className: "flex items-center gap-3 rounded-md border p-2", children: [_jsx(Monitor, { className: "text-muted-foreground h-4 w-4" }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: c.naam }), _jsx("span", { className: "text-muted-foreground text-xs", children: c.online ? "Aan" : "Uit" }), _jsx(Button, { size: "sm", onClick: () => {
72
72
  onToevoegenOpenChange(false);
73
73
  onPrintersToevoegen(c.naam);
74
- }, children: "Printers toevoegen" })] }, c.id))), _jsx("p", { className: "text-muted-foreground text-xs", children: "Staat jouw Mac er niet bij? Controleer of het printprogramma draait en of je daar met dezelfde beheerdergegevens bent ingelogd." })] })) }), _jsx("div", { className: "flex justify-end", children: _jsx(Button, { variant: "outline", onClick: () => onToevoegenOpenChange(false), children: "Sluiten" }) }), _jsx(WerktHetNiet, {})] }) })] }));
74
+ }, children: "Printers toevoegen" })] }, c.id))), _jsx("p", { className: "text-muted-foreground text-xs", children: "Staat jouw Mac er niet bij? Dan kent de printdienst hem nog niet: start het printprogramma op die Mac en log daar in met dezelfde beheerdergegevens (geen eigen PrintNode-account). De naam in de lijst is de macOS-computernaam \u2014 die kan anders heten dan je verwacht." })] })) }), _jsx("div", { className: "flex justify-end", children: _jsx(Button, { variant: "outline", onClick: () => onToevoegenOpenChange(false), children: "Sluiten" }) }), _jsx(WerktHetNiet, {})] }) })] }));
75
75
  }
@@ -0,0 +1,11 @@
1
+ import { type PakbonConfig } from "../lib/pakbonBuilder.js";
2
+ /**
3
+ * Sleepbalk boven het live voorbeeld: elke fustkolom is een chip die je naar
4
+ * voren, naar het midden of naar achteren kunt slepen. De volgorde van de
5
+ * chips is exact de kolomvolgorde op de afdruk.
6
+ */
7
+ export declare function FustKolomVolgorde({ config, onChange, }: {
8
+ config: PakbonConfig;
9
+ onChange: (c: PakbonConfig) => void;
10
+ }): import("react").JSX.Element | null;
11
+ //# sourceMappingURL=FustKolomVolgorde.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FustKolomVolgorde.d.ts","sourceRoot":"","sources":["../../src/components/FustKolomVolgorde.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE3E;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;CACrC,sCAoEA"}
@@ -0,0 +1,52 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { GripVertical } from "lucide-react";
4
+ import { Button } from "@flowselections/core";
5
+ import { FUSTREGEL_LABELS } from "../lib/pakbonBuilder.js";
6
+ /**
7
+ * Sleepbalk boven het live voorbeeld: elke fustkolom is een chip die je naar
8
+ * voren, naar het midden of naar achteren kunt slepen. De volgorde van de
9
+ * chips is exact de kolomvolgorde op de afdruk.
10
+ */
11
+ export function FustKolomVolgorde({ config, onChange, }) {
12
+ const [sleep, setSleep] = useState(null);
13
+ const [over, setOver] = useState(null);
14
+ const secties = Array.isArray(config?.secties) ? config.secties : [];
15
+ const sectie = secties.find((s) => s.type === "fustregels" && s.zichtbaar !== false);
16
+ const velden = Array.isArray(sectie?.opties?.["velden"])
17
+ ? sectie.opties["velden"]
18
+ : [];
19
+ if (!sectie || velden.length < 2)
20
+ return null;
21
+ const zetVolgorde = (nieuw) => {
22
+ onChange({
23
+ ...config,
24
+ secties: secties.map((s) => s.id === sectie.id ? { ...s, opties: { ...s.opties, velden: nieuw } } : s),
25
+ });
26
+ };
27
+ const verplaats = (van, naar) => {
28
+ if (van === naar || van < 0 || naar < 0)
29
+ return;
30
+ const nieuw = [...velden];
31
+ const [item] = nieuw.splice(van, 1);
32
+ if (item === undefined)
33
+ return;
34
+ nieuw.splice(naar, 0, item);
35
+ zetVolgorde(nieuw);
36
+ };
37
+ return (_jsxs("div", { className: "flex flex-wrap items-center gap-1.5 border-b px-3 py-2", children: [_jsx("span", { className: "mr-1 text-xs font-medium text-muted-foreground", children: "Fustkolommen:" }), velden.map((veld, i) => (_jsxs(Button, { type: "button", size: "sm", variant: "outline", draggable: true, onDragStart: () => setSleep(i), onDragOver: (e) => {
38
+ e.preventDefault();
39
+ setOver(i);
40
+ }, onDrop: (e) => {
41
+ e.preventDefault();
42
+ if (sleep !== null)
43
+ verplaats(sleep, i);
44
+ setSleep(null);
45
+ setOver(null);
46
+ }, onDragEnd: () => {
47
+ setSleep(null);
48
+ setOver(null);
49
+ }, className: `h-7 cursor-grab gap-1 px-2 text-xs active:cursor-grabbing ${over === i && sleep !== null && sleep !== i
50
+ ? "border-primary bg-primary/10"
51
+ : ""} ${sleep === i ? "opacity-50" : ""}`, title: `Sleep ${FUSTREGEL_LABELS[veld] ?? veld} naar de gewenste positie`, children: [_jsx(GripVertical, { className: "h-3 w-3 text-muted-foreground" }), FUSTREGEL_LABELS[veld] ?? veld] }, veld)))] }));
52
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"LayoutsPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPage.tsx"],"names":[],"mappings":"AAkEA,wBAAgB,WAAW,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BA8mB1E"}
1
+ {"version":3,"file":"LayoutsPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPage.tsx"],"names":[],"mappings":"AA2EA,wBAAgB,WAAW,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BAimB1E"}
@@ -7,6 +7,14 @@ import { Copy, FileText, Pencil, Plus, Search, Settings2, Trash2 } from "lucide-
7
7
  import { dupliceerLayout, maakLayout, updateLayout, useLayouts, usePrinters, zetLayoutPrinter, verwijderLayout, } from "../lib/useDocumentData.js";
8
8
  import { DOCUMENT_TYPES, FLORIDAY_LAYOUT_TOELICHTING, PAPIERFORMATEN, documentTypeLabel, isFloridayLayout, } from "../lib/documentTypes.js";
9
9
  import { DOCUMENT_PROFIELEN, documentProfiel, primaireProfielen, standaardConfig, } from "../lib/documentProfiles.js";
10
+ /** Elk documenttype krijgt zijn eigen opbouwpagina. */
11
+ function builderRoute(documenttype, layoutId) {
12
+ if (documenttype === "productiebon")
13
+ return { to: "/layouts-printers/productiebon/$layoutId", params: { layoutId } };
14
+ if (documenttype === "afleverbrief" || documenttype === "veilingbrief")
15
+ return { to: "/layouts-printers/afleverbrief/$layoutId", params: { layoutId } };
16
+ return { to: "/layouts-printers/pakbon/$layoutId", params: { layoutId } };
17
+ }
10
18
  function klantOntwerpLayout(l) {
11
19
  if (l.documenttype !== "sticker")
12
20
  return false;
@@ -137,9 +145,7 @@ export function LayoutsPage({ ingebed = false } = {}) {
137
145
  void reload();
138
146
  if (wasKlantOntwerp)
139
147
  return;
140
- void navigate(documenttype === "productiebon"
141
- ? { to: "/layouts-printers/productiebon/$layoutId", params: { layoutId: id } }
142
- : { to: "/layouts-printers/pakbon/$layoutId", params: { layoutId: id } });
148
+ void navigate(builderRoute(documenttype, id));
143
149
  }
144
150
  catch {
145
151
  toast.error("Aanmaken mislukt");
@@ -161,12 +167,7 @@ export function LayoutsPage({ ingebed = false } = {}) {
161
167
  }, children: [_jsx(SelectTrigger, { "aria-label": `Printer voor ${l.naam}`, children: _jsx(SelectValue, { placeholder: "Geen printer" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "geen", children: "Geen printer" }), printers.filter((p) => p.actief).map((printer) => (_jsx(SelectItem, { value: printer.id, children: printer.naam }, printer.id)))] })] }) }), _jsx(TableCell, { children: _jsx(Switch, { checked: l.actief, onCheckedChange: async (v) => {
162
168
  await updateLayout(l.id, { actief: v });
163
169
  void reload();
164
- } }) }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [isFloridayLayout(l) ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "Niet aanpasbaar \u2014 komt uit Floriday" })) : klantOntwerpLayout(l) ? (_jsx(Badge, { variant: "outline", children: "Ontwerp van klant" })) : (_jsxs(Button, { variant: "ghost", size: "sm", onClick: () => navigate(l.documenttype === "productiebon"
165
- ? {
166
- to: "/layouts-printers/productiebon/$layoutId",
167
- params: { layoutId: l.id },
168
- }
169
- : { to: "/layouts-printers/pakbon/$layoutId", params: { layoutId: l.id } }), children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), " Ontwerpen"] })), !isFloridayLayout(l) && (_jsx(Button, { variant: "ghost", size: "sm", title: "Naam, documenttype en formaat wijzigen", onClick: () => openBewerken(l), children: _jsx(Settings2, { className: "h-4 w-4" }) })), !isFloridayLayout(l) && (_jsx(Button, { variant: "ghost", size: "sm", title: "Kopie maken", onClick: async () => {
170
+ } }) }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [isFloridayLayout(l) ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "Niet aanpasbaar \u2014 komt uit Floriday" })) : klantOntwerpLayout(l) ? (_jsx(Badge, { variant: "outline", children: "Ontwerp van klant" })) : (_jsxs(Button, { variant: "ghost", size: "sm", onClick: () => navigate(builderRoute(l.documenttype, l.id)), children: [_jsx(Pencil, { className: "mr-2 h-4 w-4" }), " Ontwerpen"] })), !isFloridayLayout(l) && (_jsx(Button, { variant: "ghost", size: "sm", title: "Naam, documenttype en formaat wijzigen", onClick: () => openBewerken(l), children: _jsx(Settings2, { className: "h-4 w-4" }) })), !isFloridayLayout(l) && (_jsx(Button, { variant: "ghost", size: "sm", title: "Kopie maken", onClick: async () => {
170
171
  try {
171
172
  await dupliceerLayout(l.id);
172
173
  toast.success("Layout gedupliceerd");
@@ -3,13 +3,14 @@ type Item = {
3
3
  id: string;
4
4
  node: ReactNode;
5
5
  breakBefore?: boolean;
6
+ pageLabel?: string;
6
7
  };
7
8
  /**
8
9
  * Verdeelt losse blokken over echte pagina's van het gekozen formaat en toont
9
10
  * er telkens één, met pijltjes om te bladeren. De pagina schaalt automatisch
10
11
  * mee zodat hij volledig binnen het kader past.
11
12
  */
12
- export declare function PaginaDocument({ items, breedteMm, hoogteMm, padMm, leeg, voet, }: {
13
+ export declare function PaginaDocument({ items, breedteMm, hoogteMm, padMm, leeg, voet, kop, }: {
13
14
  items: Item[];
14
15
  breedteMm: number;
15
16
  hoogteMm: number;
@@ -17,6 +18,8 @@ export declare function PaginaDocument({ items, breedteMm, hoogteMm, padMm, leeg
17
18
  leeg?: ReactNode;
18
19
  /** Voettekst die onder elke pagina komt te staan. */
19
20
  voet?: (pagina: number, totaal: number) => ReactNode;
21
+ /** Kop die op iedere pagina opnieuw wordt getoond. */
22
+ kop?: (label?: string) => ReactNode;
20
23
  }): import("react").JSX.Element;
21
24
  export {};
22
25
  //# sourceMappingURL=PaginaDocument.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PaginaDocument.d.ts","sourceRoot":"","sources":["../../src/components/PaginaDocument.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIrF,KAAK,IAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnE;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,SAAS,EACT,QAAQ,EACR,KAAU,EACV,IAAI,EACJ,IAAI,GACL,EAAE;IACD,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC;CACtD,+BA0IA"}
1
+ {"version":3,"file":"PaginaDocument.d.ts","sourceRoot":"","sources":["../../src/components/PaginaDocument.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIrF,KAAK,IAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,SAAS,EACT,QAAQ,EACR,KAAU,EACV,IAAI,EACJ,IAAI,EACJ,GAAG,GACJ,EAAE;IACD,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC;IACrD,sDAAsD;IACtD,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,SAAS,CAAC;CACrC,+BAwJA"}
@@ -7,10 +7,11 @@ import { ChevronLeft, ChevronRight } from "lucide-react";
7
7
  * er telkens één, met pijltjes om te bladeren. De pagina schaalt automatisch
8
8
  * mee zodat hij volledig binnen het kader past.
9
9
  */
10
- export function PaginaDocument({ items, breedteMm, hoogteMm, padMm = 12, leeg, voet, }) {
10
+ export function PaginaDocument({ items, breedteMm, hoogteMm, padMm = 12, leeg, voet, kop, }) {
11
11
  const meetRef = useRef(null);
12
12
  const mmRef = useRef(null);
13
13
  const voetMeetRef = useRef(null);
14
+ const kopMeetRef = useRef(null);
14
15
  const buiten = useRef(null);
15
16
  const pagina = useRef(null);
16
17
  const [paginas, setPaginas] = useState([items]);
@@ -26,7 +27,10 @@ export function PaginaDocument({ items, breedteMm, hoogteMm, padMm = 12, leeg, v
26
27
  if (!pxPerMm)
27
28
  return;
28
29
  const voetPx = voetMeetRef.current?.getBoundingClientRect().height ?? 0;
29
- const maxPx = (hoogteMm - padMm * 2) * pxPerMm - (voetPx ? voetPx + 8 : 0);
30
+ const kopPx = kopMeetRef.current?.getBoundingClientRect().height ?? 0;
31
+ const maxPx = (hoogteMm - padMm * 2) * pxPerMm -
32
+ (voetPx ? voetPx + 8 : 0) -
33
+ (kopPx ? kopPx + 12 : 0);
30
34
  const kinderen = Array.from(meet.children);
31
35
  const result = [];
32
36
  let huidig = [];
@@ -49,7 +53,7 @@ export function PaginaDocument({ items, breedteMm, hoogteMm, padMm = 12, leeg, v
49
53
  result.push(huidig);
50
54
  setPaginas(result.length ? result : [[]]);
51
55
  setIndex((i) => Math.min(i, Math.max(0, result.length - 1)));
52
- }, [items, hoogteMm, breedteMm, padMm, voet]);
56
+ }, [items, hoogteMm, breedteMm, padMm, voet, kop]);
53
57
  // Pagina passend schalen op breedte; hoogte mag doorlopen zodat je kunt scrollen.
54
58
  const pas = () => {
55
59
  const b = buiten.current;
@@ -69,12 +73,13 @@ export function PaginaDocument({ items, breedteMm, hoogteMm, padMm = 12, leeg, v
69
73
  }, []);
70
74
  const totaal = paginas.length;
71
75
  const huidige = paginas[Math.min(index, totaal - 1)] ?? [];
72
- return (_jsxs("div", { className: "flex h-full w-full flex-col gap-2", children: [_jsxs("div", { className: "pointer-events-none absolute -z-10 opacity-0", "aria-hidden": true, children: [_jsx("div", { ref: mmRef, style: { height: "100mm", width: "1px" } }), _jsx("div", { ref: meetRef, className: "bg-white text-[11px] text-neutral-900", style: { width: `${breedteMm - padMm * 2}mm` }, children: items.map((it) => (_jsx("div", { children: it.node }, it.id))) }), _jsx("div", { ref: voetMeetRef, className: "bg-white text-[11px] text-neutral-900", style: { width: `${breedteMm - padMm * 2}mm` }, children: voet?.(1, 1) })] }), _jsx("div", { ref: buiten, className: "flex min-h-0 flex-1 items-start justify-center overflow-auto", children: _jsxs("div", { ref: pagina, className: "flex flex-col bg-white text-[11px] text-neutral-900 shadow-sm", style: {
76
+ const huidigLabel = huidige.find((item) => item.pageLabel)?.pageLabel;
77
+ return (_jsxs("div", { className: "flex h-full w-full flex-col gap-2", children: [_jsxs("div", { className: "pointer-events-none absolute -z-10 opacity-0", "aria-hidden": true, children: [_jsx("div", { ref: mmRef, style: { height: "100mm", width: "1px" } }), _jsx("div", { ref: meetRef, className: "bg-white text-[11px] text-neutral-900", style: { width: `${breedteMm - padMm * 2}mm` }, children: items.map((it) => (_jsx("div", { children: it.node }, it.id))) }), _jsx("div", { ref: kopMeetRef, className: "bg-white text-[11px] text-neutral-900", style: { width: `${breedteMm - padMm * 2}mm` }, children: kop?.("Hele kar") }), _jsx("div", { ref: voetMeetRef, className: "bg-white text-[11px] text-neutral-900", style: { width: `${breedteMm - padMm * 2}mm` }, children: voet?.(1, 1) })] }), _jsx("div", { ref: buiten, className: "flex min-h-0 flex-1 items-start justify-center overflow-auto", children: _jsxs("div", { ref: pagina, className: "flex flex-col bg-white text-[11px] text-neutral-900 shadow-sm", style: {
73
78
  width: `${breedteMm}mm`,
74
79
  height: `${hoogteMm}mm`,
75
80
  padding: `${padMm}mm`,
76
81
  transform: `scale(${schaal})`,
77
82
  transformOrigin: "top center",
78
83
  overflow: "hidden",
79
- }, children: [_jsxs("div", { className: "min-h-0 flex-1 space-y-3", children: [huidige.map((it) => (_jsx("div", { children: it.node }, it.id))), huidige.length === 0 && (_jsx("p", { className: "py-10 text-center text-neutral-400", children: leeg ?? "Nog niets te tonen." }))] }), voet && _jsx("div", { className: "mt-2 shrink-0", children: voet(Math.min(index + 1, totaal), totaal) })] }) }), _jsxs("div", { className: "flex shrink-0 items-center justify-center gap-3", children: [_jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => setIndex((i) => Math.max(0, i - 1)), disabled: index <= 0, "aria-label": "Vorige pagina", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Pagina ", Math.min(index + 1, totaal), " van ", totaal] }), _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => setIndex((i) => Math.min(totaal - 1, i + 1)), disabled: index >= totaal - 1, "aria-label": "Volgende pagina", children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] })] }));
84
+ }, children: [kop?.(huidigLabel), _jsxs("div", { className: "min-h-0 flex-1 space-y-3", children: [huidige.map((it) => (_jsx("div", { children: it.node }, it.id))), huidige.length === 0 && (_jsx("p", { className: "py-10 text-center text-neutral-400", children: leeg ?? "Nog niets te tonen." }))] }), voet && _jsx("div", { className: "mt-2 shrink-0", children: voet(Math.min(index + 1, totaal), totaal) })] }) }), _jsxs("div", { className: "flex shrink-0 items-center justify-center gap-3", children: [_jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => setIndex((i) => Math.max(0, i - 1)), disabled: index <= 0, "aria-label": "Vorige pagina", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Pagina ", Math.min(index + 1, totaal), " van ", totaal] }), _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: () => setIndex((i) => Math.min(totaal - 1, i + 1)), disabled: index >= totaal - 1, "aria-label": "Volgende pagina", children: _jsx(ChevronRight, { className: "h-4 w-4" }) })] })] }));
80
85
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PakbonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/PakbonBuilderPage.tsx"],"names":[],"mappings":"AA0BA,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BAwJvF"}
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,12 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
3
  import { Link } from "@tanstack/react-router";
4
- import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, toast, } from "@flowselections/core";
5
- import { ArrowLeft, Loader2, Printer, Save } from "lucide-react";
4
+ import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "@flowselections/core";
5
+ import { AlertTriangle, ArrowLeft, CheckCircle2, Loader2, Printer, Save } from "lucide-react";
6
6
  import { PakbonSectiesPanel } from "./PakbonSectiesPanel.js";
7
- import { PakbonPreview } from "./PakbonPreview.js";
7
+ import { PdfVoorbeeld } from "./PdfVoorbeeld.js";
8
8
  import { FormaatOrientatieBar } from "./FormaatOrientatieBar.js";
9
- import { leesPakbonConfig } from "../lib/pakbonBuilder.js";
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";
@@ -20,14 +20,23 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
20
20
  const [config, setConfig] = useState(null);
21
21
  const [bezig, setBezig] = useState(false);
22
22
  const [printen, setPrinten] = useState(false);
23
+ const [voorbeeldVariant, setVoorbeeldVariant] = useState("full_cart");
24
+ const [logos, setLogos] = useState([]);
25
+ const [controle, setControle] = useState("controleren");
26
+ useEffect(() => {
27
+ void haalPrintLogos()
28
+ .then((l) => setLogos(Array.isArray(l) ? l : []))
29
+ .catch(() => setLogos([]));
30
+ }, []);
23
31
  useEffect(() => {
24
32
  if (layout)
25
33
  setConfig(leesPakbonConfig(layout.config));
26
34
  }, [layout?.id]);
27
35
  const breedte = useMemo(() => (layout?.orientatie === "landscape" ? layout?.hoogte_mm : layout?.breedte_mm) ?? 210, [layout]);
28
36
  const hoogte = useMemo(() => (layout?.orientatie === "landscape" ? layout?.breedte_mm : layout?.hoogte_mm) ?? 297, [layout]);
37
+ const marge = Number(layout?.marge_boven ?? 10);
29
38
  const opslaan = async () => {
30
- if (!layout || !config)
39
+ if (!layout || !config || controle !== "gereed")
31
40
  return;
32
41
  setBezig(true);
33
42
  try {
@@ -41,18 +50,29 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
41
50
  setBezig(false);
42
51
  }
43
52
  };
44
- const voorbeeldPrinten = async () => {
53
+ // Eén bron voor scherm én print: exact dezelfde HTML gaat naar de
54
+ // server-PDF van het voorbeeld en naar de printopdracht.
55
+ const voorbeeldHtml = useMemo(() => {
45
56
  if (!config)
57
+ return "";
58
+ const beideVarianten = voorbeeldVariant === "full_cart" &&
59
+ pickMethode(Array.isArray(config?.secties) ? config.secties : []) === "beide";
60
+ return renderPakbonDocument(config, voorbeeldPakbonOrder(), {
61
+ logos: logos,
62
+ breedteMm: breedte,
63
+ hoogteMm: hoogte,
64
+ margeMm: marge,
65
+ layoutVariant: voorbeeldVariant,
66
+ voorbeeldBeideVarianten: beideVarianten,
67
+ titel: layout?.naam ?? "Pakbon",
68
+ });
69
+ }, [config, logos, breedte, hoogte, marge, voorbeeldVariant, layout?.naam]);
70
+ const voorbeeldPrinten = async () => {
71
+ if (!config || controle !== "gereed")
46
72
  return;
47
73
  setPrinten(true);
48
74
  try {
49
- const logos = await haalPrintLogos();
50
- const html = renderPakbonDocument(config, voorbeeldPakbonOrder(), {
51
- logos,
52
- breedteMm: breedte,
53
- hoogteMm: hoogte,
54
- titel: layout?.naam ?? "Pakbon",
55
- });
75
+ const html = voorbeeldHtml;
56
76
  await voorbeeldPrint({
57
77
  ...(layout ?? {}),
58
78
  id: layout?.id ?? layoutId,
@@ -74,5 +94,5 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
74
94
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout laden\u2026" });
75
95
  if (!layout || !config)
76
96
  return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout niet gevonden." });
77
- 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, 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, 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: "Voorbeeldorder met 2 karren, 3 lagen en fusten." })] }), _jsx(Badge, { variant: "secondary", children: "Direct bijgewerkt" })] }), _jsx(CardContent, { className: "min-h-0 flex-1 overflow-hidden", children: _jsx("div", { className: "h-full overflow-auto rounded-md border bg-muted/30 p-2", children: _jsx(PakbonPreview, { config: config, breedteMm: breedte, hoogteMm: hoogte }) }) })] })] })] }));
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 }) })] })] })] }));
78
98
  }
@@ -1,8 +1,10 @@
1
- import { type PakbonConfig, type PakbonSectie } from "../lib/pakbonBuilder.js";
2
- export declare function PakbonPreview({ config, breedteMm, hoogteMm, }: {
1
+ import { type PakbonConfig, type PakbonSectie, type PakbonLayoutVariant } from "../lib/pakbonBuilder.js";
2
+ export declare function PakbonPreview({ config, breedteMm, hoogteMm, variant, }: {
3
3
  config: PakbonConfig;
4
4
  breedteMm?: number;
5
5
  hoogteMm?: number;
6
+ /** Alleen voor het voorbeeld; echte opdrachten krijgen de variant van de Engine. */
7
+ variant?: PakbonLayoutVariant | null;
6
8
  }): import("react").JSX.Element;
7
9
  /** Losse weergave van één blok — gebruikt door de blokontwerper. */
8
10
  export declare function PakbonSectiePreview({ sectie, config, breedteMm, }: {
@@ -1 +1 @@
1
- {"version":3,"file":"PakbonPreview.d.ts","sourceRoot":"","sources":["../../src/components/PakbonPreview.tsx"],"names":[],"mappings":"AAGA,OAAO,EAoBL,KAAK,YAAY,EAEjB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAS9B,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,SAAe,EACf,QAAc,GACf,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,+BAgFA;AAsKD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAmCA"}
1
+ {"version":3,"file":"PakbonPreview.d.ts","sourceRoot":"","sources":["../../src/components/PakbonPreview.tsx"],"names":[],"mappings":"AAKA,OAAO,EAyBL,KAAK,YAAY,EAEjB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACzB,MAAM,sBAAsB,CAAC;AA6B9B,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,SAAe,EACf,QAAc,EACd,OAAc,GACf,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oFAAoF;IACpF,OAAO,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACtC,+BAiJA;AAiLD,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAmCA"}