@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.
- package/dist-lib/components/AfleverbriefBuilderPage.d.ts +10 -0
- package/dist-lib/components/AfleverbriefBuilderPage.d.ts.map +1 -0
- package/dist-lib/components/AfleverbriefBuilderPage.js +101 -0
- package/dist-lib/components/BlokOntwerperPage.d.ts.map +1 -1
- package/dist-lib/components/BlokOntwerperPage.js +8 -3
- package/dist-lib/components/ComputersLijst.d.ts.map +1 -1
- package/dist-lib/components/ComputersLijst.js +1 -1
- package/dist-lib/components/FustKolomVolgorde.d.ts +11 -0
- package/dist-lib/components/FustKolomVolgorde.d.ts.map +1 -0
- package/dist-lib/components/FustKolomVolgorde.js +52 -0
- package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
- package/dist-lib/components/LayoutsPage.js +10 -9
- package/dist-lib/components/PaginaDocument.d.ts +4 -1
- package/dist-lib/components/PaginaDocument.d.ts.map +1 -1
- package/dist-lib/components/PaginaDocument.js +10 -5
- package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
- package/dist-lib/components/PakbonBuilderPage.js +34 -14
- package/dist-lib/components/PakbonPreview.d.ts +4 -2
- package/dist-lib/components/PakbonPreview.d.ts.map +1 -1
- package/dist-lib/components/PakbonPreview.js +74 -24
- package/dist-lib/components/PakbonSectiesPanel.d.ts +5 -3
- package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
- package/dist-lib/components/PakbonSectiesPanel.js +8 -5
- package/dist-lib/components/PdfMapToestemmingBanner.d.ts +2 -1
- package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -1
- package/dist-lib/components/PdfMapToestemmingBanner.js +73 -14
- package/dist-lib/components/PdfVoorbeeld.d.ts +20 -0
- package/dist-lib/components/PdfVoorbeeld.d.ts.map +1 -0
- package/dist-lib/components/PdfVoorbeeld.js +95 -0
- package/dist-lib/components/PrintProgrammaUitleg.d.ts.map +1 -1
- package/dist-lib/components/PrintProgrammaUitleg.js +1 -1
- package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
- package/dist-lib/components/PrintQueuePage.js +81 -43
- package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
- package/dist-lib/components/PrintplekDetailPage.js +2 -2
- package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
- package/dist-lib/components/PrintplekWizard.js +6 -2
- package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
- package/dist-lib/components/ProductiebonBuilderPage.js +13 -7
- package/dist-lib/index.d.ts +16 -6
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +11 -5
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +3585 -1267
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +3585 -1267
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +25898 -0
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -0
- package/dist-lib/integrations/supabase/moduleClient.js +29 -0
- package/dist-lib/integrations/supabase/types.d.ts +3607 -1265
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.js +1 -0
- package/dist-lib/lib/aiLayout.functions.d.ts +3585 -1267
- package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
- package/dist-lib/lib/code128.d.ts +5 -0
- package/dist-lib/lib/code128.d.ts.map +1 -0
- package/dist-lib/lib/code128.js +51 -0
- package/dist-lib/lib/documentVoorbeeld.functions.d.ts +23 -0
- package/dist-lib/lib/documentVoorbeeld.functions.d.ts.map +1 -0
- package/dist-lib/lib/documentVoorbeeld.functions.js +37 -0
- package/dist-lib/lib/fontMetrics.d.ts +15 -0
- package/dist-lib/lib/fontMetrics.d.ts.map +1 -0
- package/dist-lib/lib/fontMetrics.js +118 -0
- package/dist-lib/lib/htmlNaarPdf.server.d.ts +2 -2
- package/dist-lib/lib/htmlNaarPdf.server.d.ts.map +1 -1
- package/dist-lib/lib/htmlNaarPdf.server.js +2 -1
- package/dist-lib/lib/htmlPdf.server.d.ts +11 -0
- package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
- package/dist-lib/lib/htmlPdf.server.js +170 -9
- package/dist-lib/lib/layoutPreview.d.ts.map +1 -1
- package/dist-lib/lib/layoutPreview.js +6 -3
- package/dist-lib/lib/orderData.server.d.ts.map +1 -1
- package/dist-lib/lib/orderData.server.js +49 -16
- package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts +39 -0
- package/dist-lib/lib/pakbonBarcodeVerzoek.d.ts.map +1 -0
- package/dist-lib/lib/pakbonBarcodeVerzoek.js +80 -0
- package/dist-lib/lib/pakbonBuilder.d.ts +90 -5
- package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
- package/dist-lib/lib/pakbonBuilder.js +455 -58
- package/dist-lib/lib/pakbonContent.d.ts +41 -0
- package/dist-lib/lib/pakbonContent.d.ts.map +1 -0
- package/dist-lib/lib/pakbonContent.js +668 -0
- package/dist-lib/lib/pakbonDocument.d.ts +199 -0
- package/dist-lib/lib/pakbonDocument.d.ts.map +1 -0
- package/dist-lib/lib/pakbonDocument.js +735 -0
- package/dist-lib/lib/pakbonHtml.d.ts +21 -2
- package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
- package/dist-lib/lib/pakbonHtml.js +144 -36
- package/dist-lib/lib/pakbonPresentation.d.ts +8 -0
- package/dist-lib/lib/pakbonPresentation.d.ts.map +1 -0
- package/dist-lib/lib/pakbonPresentation.js +31 -0
- package/dist-lib/lib/pakbonScan.d.ts +44 -0
- package/dist-lib/lib/pakbonScan.d.ts.map +1 -0
- package/dist-lib/lib/pakbonScan.js +87 -0
- package/dist-lib/lib/pdfJobSaver.d.ts +10 -6
- package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -1
- package/dist-lib/lib/pdfJobSaver.js +302 -99
- package/dist-lib/lib/pdfMap.d.ts +37 -2
- package/dist-lib/lib/pdfMap.d.ts.map +1 -1
- package/dist-lib/lib/pdfMap.js +120 -7
- package/dist-lib/lib/pdfOpslagStatus.d.ts +23 -0
- package/dist-lib/lib/pdfOpslagStatus.d.ts.map +1 -0
- package/dist-lib/lib/pdfOpslagStatus.js +74 -0
- package/dist-lib/lib/printApi.d.ts +31 -0
- package/dist-lib/lib/printApi.d.ts.map +1 -1
- package/dist-lib/lib/printApi.js +62 -1
- package/dist-lib/lib/printQueue.server.d.ts +13 -0
- package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/printQueue.server.js +673 -96
- package/dist-lib/lib/printService.functions.d.ts +11840 -2568
- package/dist-lib/lib/printService.functions.d.ts.map +1 -1
- package/dist-lib/lib/profielHtml.d.ts.map +1 -1
- package/dist-lib/lib/profielHtml.js +8 -1
- package/dist-lib/lib/supabaseClient.d.ts +1 -3
- package/dist-lib/lib/supabaseClient.d.ts.map +1 -1
- package/dist-lib/lib/supabaseClient.js +4 -8
- package/dist-lib/lib/useDocumentData.d.ts +8 -0
- package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
- package/dist-lib/lib/useDocumentData.js +1 -1
- package/dist-lib/lib/voorbeeldPrint.d.ts +3 -0
- package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
- package/dist-lib/lib/voorbeeldPrint.js +65 -17
- package/package.json +9 -2
|
@@ -2,14 +2,34 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { PaginaDocument } from "./PaginaDocument.js";
|
|
4
4
|
import { useLogos } from "../lib/logoLibrary.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { code128Bars } from "../lib/code128.js";
|
|
6
|
+
import { karMetadata } from "../lib/pakbonPresentation.js";
|
|
7
|
+
import { DEMO_ORDER, deelkarVoorbeeldOrder, conditieContext, groepeerIdentiekeKarren, groepeerIdentiekeLagen, karBundelTekst, fustVerzamellijst, fustRegels, FUSTREGEL_LABELS, FUSTREGEL_RECHTS, pickMethode, pakbonLayoutVariant, productVeldBreedtes, sectieOnderdruktVoorVariant, kolomLabel, laagBundelTekst, sectieZichtbaar, sorteerProducten, totalen, vulVeldcodes, } from "../lib/pakbonBuilder.js";
|
|
8
|
+
/** Voorbeeldbarcode: alleen bedoeld om de plek en hoogte te tonen. */
|
|
9
|
+
function BarcodeStrepen({ waarde, hoogteMm = 15 }) {
|
|
10
|
+
const bars = code128Bars(waarde);
|
|
11
|
+
if (!bars)
|
|
12
|
+
return null;
|
|
13
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "flex w-48 bg-white", style: { height: `${hoogteMm}mm` }, children: bars.split("").map((bar, i) => (_jsx("span", { className: `block h-full ${bar === "1" ? "bg-foreground" : "bg-transparent"}`, style: { flex: `0 0 ${100 / bars.length}%` } }, i))) }), _jsx("div", { className: "text-[9px]", children: waarde })] }));
|
|
14
|
+
}
|
|
15
|
+
export function PakbonPreview({ config, breedteMm = 210, hoogteMm = 297, variant = null, }) {
|
|
16
|
+
// De deelkarweergave gebruikt bewust een beperkte demo-order. Daardoor zie
|
|
17
|
+
// je in het voorbeeld alleen de fusten die voor deze deelkar verzameld
|
|
18
|
+
// moeten worden, nooit een misleidende volledige karindeling.
|
|
19
|
+
const order = variant === "partial_order" ? deelkarVoorbeeldOrder() : DEMO_ORDER;
|
|
8
20
|
const ctx = conditieContext(order);
|
|
9
21
|
const alleSecties = Array.isArray(config?.secties) ? config.secties : [];
|
|
10
22
|
const methode = pickMethode(alleSecties);
|
|
11
|
-
const
|
|
23
|
+
const actieveVariant = pakbonLayoutVariant(variant);
|
|
24
|
+
const secties = alleSecties.filter((s) => sectieZichtbaar(s, ctx) && !sectieOnderdruktVoorVariant(s.type, methode, actieveVariant));
|
|
12
25
|
const zoek = (type) => secties.find((s) => s.type === type);
|
|
26
|
+
const pickSectie = alleSecties.find((s) => s.type === "pickmethode");
|
|
27
|
+
const barcodeAan = !alleSecties.some((s) => s.type === "barcode") &&
|
|
28
|
+
(pickSectie ? opt(pickSectie, "toonBarcode", true) !== false : true);
|
|
29
|
+
const barcodeHoogte = pickSectie ? Number(opt(pickSectie, "barcodeHoogte", 15)) : 15;
|
|
30
|
+
const heeftKarBarcodes = secties.some((s) => s.type === "karren") &&
|
|
31
|
+
order.karren.some((kar) => Boolean(String(kar.barcode ?? "").trim()));
|
|
32
|
+
const paginaLabel = actieveVariant === "partial_order" ? "Deelkar" : "Hele kar";
|
|
13
33
|
const segmenten = [];
|
|
14
34
|
if (config?.logo?.logoId) {
|
|
15
35
|
segmenten.push({
|
|
@@ -28,23 +48,47 @@ export function PakbonPreview({ config, breedteMm = 210, hoogteMm = 297, }) {
|
|
|
28
48
|
if (s.type === "karren") {
|
|
29
49
|
segmenten.push(...karSegmenten(s, order, zoek));
|
|
30
50
|
}
|
|
51
|
+
else if (s.type === "barcode" && heeftKarBarcodes) {
|
|
52
|
+
// De barcode wordt binnen ieder afzonderlijk karblok getoond.
|
|
53
|
+
}
|
|
31
54
|
else if (s.type === "totalen" && (totalenElkePagina || toonPaginanummer)) {
|
|
32
55
|
// wordt als voettekst onder elke pagina getoond
|
|
33
56
|
}
|
|
34
57
|
else {
|
|
35
58
|
segmenten.push({
|
|
36
59
|
key: s.id,
|
|
60
|
+
pageLabel: paginaLabel,
|
|
37
61
|
node: (_jsx(BlokFrame, { sectie: s, children: _jsx(SectieView, { sectie: s, order: order, zoek: zoek }) })),
|
|
38
62
|
});
|
|
39
63
|
}
|
|
40
64
|
}
|
|
65
|
+
if (barcodeAan && !heeftKarBarcodes) {
|
|
66
|
+
segmenten.push({
|
|
67
|
+
key: "engine-barcode",
|
|
68
|
+
pageLabel: paginaLabel,
|
|
69
|
+
node: (_jsxs("div", { className: "space-y-1 pt-2", children: [_jsx(BarcodeStrepen, { waarde: "VOORBEELD-BARCODE", hoogteMm: barcodeHoogte }), _jsx("div", { className: "text-[8px] text-muted-foreground", children: "Voorbeeld \u2014 de echte barcode komt uit de opdracht van de Engine." })] })),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// Het volle-karvoorbeeld is bewust een complete serie: vier hele karren en
|
|
73
|
+
// als vijfde pagina één deelkar zonder karindeling. Zo is het verschil in
|
|
74
|
+
// dezelfde voorbeeldreeks direct zichtbaar.
|
|
75
|
+
if (actieveVariant === "full_cart" && methode === "beide" && pickSectie) {
|
|
76
|
+
const deelOrder = deelkarVoorbeeldOrder();
|
|
77
|
+
segmenten.push({
|
|
78
|
+
key: "deelkar-voorbeeldpagina",
|
|
79
|
+
breakBefore: true,
|
|
80
|
+
pageLabel: "Deelkar",
|
|
81
|
+
node: (_jsxs("div", { className: "space-y-3", children: [_jsx(BlokFrame, { sectie: pickSectie, children: _jsx(SectieView, { sectie: pickSectie, order: deelOrder, zoek: zoek }) }), _jsxs("div", { className: "space-y-1 pt-2", children: [_jsx(BarcodeStrepen, { waarde: "VOORBEELD-DEELKAR", hoogteMm: barcodeHoogte }), _jsx("div", { className: "text-[8px] text-muted-foreground", children: "Voorbeeld \u2014 de echte barcode komt uit de opdracht van de Engine." })] })] })),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
41
84
|
const voet = totalenSectie && (totalenElkePagina || toonPaginanummer)
|
|
42
85
|
? (pagina, totaalPaginas) => (_jsxs("div", { className: "space-y-1", children: [totalenElkePagina && (_jsx(BlokFrame, { sectie: totalenSectie, children: _jsx(SectieView, { sectie: totalenSectie, order: order, zoek: zoek }) })), toonPaginanummer && (_jsxs("div", { className: "text-right text-[9px] text-neutral-500", children: ["Pagina ", pagina, " van ", totaalPaginas] }))] }))
|
|
43
86
|
: undefined;
|
|
44
|
-
return (_jsx(PaginaDocument, { breedteMm: breedteMm, hoogteMm: hoogteMm, leeg: "Nog geen zichtbare secties.", voet: voet, items: segmenten.map((seg) => ({
|
|
87
|
+
return (_jsx(PaginaDocument, { breedteMm: breedteMm, hoogteMm: hoogteMm, leeg: "Nog geen zichtbare secties.", voet: voet, kop: (label) => (_jsx("div", { className: "mb-3 border-y-2 border-neutral-900 py-2 text-center text-base font-bold uppercase", children: label ?? paginaLabel })), items: segmenten.map((seg) => ({
|
|
45
88
|
id: seg.key,
|
|
46
89
|
node: seg.node,
|
|
47
90
|
breakBefore: seg.breakBefore,
|
|
91
|
+
pageLabel: seg.pageLabel ?? paginaLabel,
|
|
48
92
|
})) }));
|
|
49
93
|
}
|
|
50
94
|
/** Bouwt de segmenten voor de karrensectie, inclusief pagina-afbrekingen. */
|
|
@@ -68,6 +112,7 @@ function karSegmenten(s, order, zoek) {
|
|
|
68
112
|
return [
|
|
69
113
|
{
|
|
70
114
|
key: s.id,
|
|
115
|
+
pageLabel: "Hele kar",
|
|
71
116
|
node: wrap(_jsx("div", { className: "grid grid-cols-2 gap-3", children: karGroepen.map((g) => (_jsx(KarBlok, { sectie: s, kar: g.kar, aantal: g.aantal, velden: velden, lagen: g.kar.lagen, lagenSectie: lagenSectie, productSectie: productSectie, fustSectie: fustSectie, omkaderd: false }, g.kar.karnummer))) })),
|
|
72
117
|
},
|
|
73
118
|
];
|
|
@@ -82,6 +127,7 @@ function karSegmenten(s, order, zoek) {
|
|
|
82
127
|
segmenten.push({
|
|
83
128
|
key: `${s.id}-${kar.karnummer}-${lg.laag.laagnummer}`,
|
|
84
129
|
breakBefore: i > 0 || j > 0,
|
|
130
|
+
pageLabel: "Hele kar",
|
|
85
131
|
node: wrap(_jsx(KarBlok, { sectie: s, kar: kar, aantal: groep.aantal, velden: velden, lagen: [lg.laag], lagenSectie: lagenSectie, productSectie: productSectie, fustSectie: fustSectie, omkaderd: modus === "blok" || modus === "passend" })),
|
|
86
132
|
});
|
|
87
133
|
});
|
|
@@ -90,6 +136,7 @@ function karSegmenten(s, order, zoek) {
|
|
|
90
136
|
segmenten.push({
|
|
91
137
|
key: `${s.id}-${kar.karnummer}`,
|
|
92
138
|
breakBefore: i > 0 && nieuwePaginaPerKar,
|
|
139
|
+
pageLabel: "Hele kar",
|
|
93
140
|
node: wrap(_jsxs("div", { className: "space-y-2", children: [i > 0 && !nieuwePaginaPerKar && _jsx(Scheiding, { modus: scheiding }), _jsx(KarBlok, { sectie: s, kar: kar, aantal: groep.aantal, velden: velden, lagen: lagenVanKar, lagenSectie: lagenSectie, productSectie: productSectie, fustSectie: fustSectie, omkaderd: modus === "blok" || modus === "passend" })] })),
|
|
94
141
|
});
|
|
95
142
|
});
|
|
@@ -100,7 +147,7 @@ function BundelMelding({ tekst }) {
|
|
|
100
147
|
return (_jsx("div", { className: "rounded border border-dashed px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide", children: tekst }));
|
|
101
148
|
}
|
|
102
149
|
function KarBlok({ sectie, kar, velden, lagen, lagenSectie, productSectie, fustSectie, omkaderd, aantal = 1, }) {
|
|
103
|
-
return (_jsxs("div", { className: `space-y-2 ${omkaderd ? "rounded border p-2" : ""}`, children: [_jsx(KarKop, { sectie: sectie, kar: kar, velden: velden, bundelTekst: karBundelTekst(aantal) }), lagen.length > 0 && lagenSectie && (_jsx(LagenView, { sectie: lagenSectie, lagen: lagen, productSectie: productSectie, fustSectie: fustSectie })), fustSectie && optS(fustSectie, "modus", "totaal") === "kar" && (_jsx(FustTabel, { velden: lijst(fustSectie, "velden"), fusten: lagen.flatMap((l) => l.fusten), titel: `Fusten kar ${kar.karnummer}` }))] }));
|
|
150
|
+
return (_jsxs("div", { className: `space-y-2 ${omkaderd ? "rounded border p-2" : ""}`, children: [_jsx(KarKop, { sectie: sectie, kar: kar, velden: velden, bundelTekst: karBundelTekst(aantal) }), kar.barcode ? (_jsxs("div", { className: "space-y-1 py-1", children: [_jsx(BarcodeStrepen, { waarde: kar.barcode, hoogteMm: Number(opt(sectie, "barcodeHoogte", 15)) }), _jsx("div", { className: "text-[8px] text-muted-foreground", children: "Voorbeeld \u2014 iedere kar krijgt de eigen barcode van de Engine." })] })) : null, lagen.length > 0 && lagenSectie && (_jsx(LagenView, { sectie: lagenSectie, lagen: lagen, productSectie: productSectie, fustSectie: fustSectie })), fustSectie && optS(fustSectie, "modus", "totaal") === "kar" && (_jsx(FustTabel, { velden: lijst(fustSectie, "velden"), fusten: lagen.flatMap((l) => l.fusten), titel: `Fusten kar ${kar.karnummer}` }))] }));
|
|
104
151
|
}
|
|
105
152
|
/** Losse weergave van één blok — gebruikt door de blokontwerper. */
|
|
106
153
|
export function PakbonSectiePreview({ sectie, config, breedteMm, }) {
|
|
@@ -168,8 +215,23 @@ function SectieView({ sectie, order, zoek, }) {
|
|
|
168
215
|
const groepen = groepeer(order, groepering, optS(s, "sortering", "eigen"));
|
|
169
216
|
return (_jsx("div", { className: "space-y-2", children: groepen.map((g) => (_jsxs("div", { className: "space-y-1", children: [g.titel !== "—" && _jsx("div", { className: "font-semibold", children: g.titel }), _jsx(RegelWeergave, { producten: g.producten, kolommen: kolommen, weergave: optS(s, "weergave", "tabel"), toonKoppen: opt(s, "toonKoppen", true), zebra: opt(s, "zebra", false), randen: opt(s, "randen", true) })] }, g.titel))) }));
|
|
170
217
|
}
|
|
218
|
+
case "fustregels": {
|
|
219
|
+
const velden = lijst(s, "velden").filter((v) => FUSTREGEL_LABELS[v]);
|
|
220
|
+
const regels = fustRegels(order.karren, {
|
|
221
|
+
comprimeren: opt(s, "comprimeren", true) !== false,
|
|
222
|
+
sortering: optS(s, "sortering", "fustsoort"),
|
|
223
|
+
});
|
|
224
|
+
if (!velden.length || !regels.length)
|
|
225
|
+
return null;
|
|
226
|
+
const randen = opt(s, "randen", true) !== false;
|
|
227
|
+
const zebra = opt(s, "zebra", false);
|
|
228
|
+
const cel = randen ? "border-b border-neutral-300 px-1 py-0.5" : "px-1 py-0.5";
|
|
229
|
+
const totaalFusten = regels.reduce((n, r) => n + r.fust_aantal, 0);
|
|
230
|
+
const totaalPlanten = regels.reduce((n, r) => n + r.aantal, 0);
|
|
231
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsxs("table", { className: "w-full border-collapse", children: [opt(s, "toonKoppen", true) !== false && (_jsx("thead", { children: _jsx("tr", { children: velden.map((v) => (_jsx("th", { className: `${cel} font-semibold ${FUSTREGEL_RECHTS.has(v) ? "text-right" : "text-left"}`, children: FUSTREGEL_LABELS[v] }, v))) }) })), _jsx("tbody", { children: regels.map((r, i) => (_jsx("tr", { className: zebra && i % 2 === 1 ? "bg-neutral-100" : undefined, children: velden.map((v) => (_jsx("td", { className: `${cel} ${FUSTREGEL_RECHTS.has(v) ? "text-right" : "text-left"}`, children: String(r[v] ?? "") }, v))) }, i))) })] }), opt(s, "toonTotaal", true) !== false && (_jsxs("div", { className: "flex justify-end gap-3 font-semibold", children: [_jsxs("span", { children: [totaalFusten, " fusten"] }), _jsxs("span", { children: [totaalPlanten, " planten"] })] }))] }));
|
|
232
|
+
}
|
|
171
233
|
case "pickmethode":
|
|
172
|
-
if (optS(s, "methode", "kar")
|
|
234
|
+
if (optS(s, "methode", "kar") === "kar")
|
|
173
235
|
return null;
|
|
174
236
|
return (_jsx(FustVerzamellijst, { order: order, kop: String(s.opties?.["kop"] ?? "Te verzamelen fusten — karindeling zelf bepalen"), velden: lijst(s, "velden"), toonFusthoogte: opt(s, "toonFusthoogte", true) !== false, toonTotaal: opt(s, "toonTotaal", true) !== false }));
|
|
175
237
|
case "karren":
|
|
@@ -199,10 +261,7 @@ function SectieView({ sectie, order, zoek, }) {
|
|
|
199
261
|
case "qrcode":
|
|
200
262
|
return (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "flex items-center justify-center border border-dashed text-muted-foreground", style: { width: `${opt(s, "grootte", 25)}mm`, height: `${opt(s, "grootte", 25)}mm` }, children: "QR" }), _jsx("div", { className: "text-[8px] text-muted-foreground", children: vulVeldcodes(String(opt(s, "waarde", "")), order) })] }));
|
|
201
263
|
case "barcode":
|
|
202
|
-
return (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "
|
|
203
|
-
height: `${opt(s, "hoogte", 15)}mm`,
|
|
204
|
-
backgroundImage: "repeating-linear-gradient(to right, currentColor 0 2px, transparent 2px 5px)",
|
|
205
|
-
} }), _jsx("div", { children: vulVeldcodes(String(opt(s, "waarde", "")), order) })] }));
|
|
264
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx(BarcodeStrepen, { waarde: "VOORBEELD-BARCODE", hoogteMm: Number(opt(s, "hoogte", 15)) }), _jsx("div", { className: "text-[8px] text-muted-foreground", children: "Voorbeeld \u2014 de echte barcode komt uitsluitend uit de Engine-opdracht." })] }));
|
|
206
265
|
case "afbeelding": {
|
|
207
266
|
const url = String(opt(s, "url", ""));
|
|
208
267
|
return url ? (_jsx("img", { src: url, alt: s.titel, style: { height: `${opt(s, "hoogte", 25)}mm` } })) : (_jsx("div", { className: "flex items-center justify-center rounded border border-dashed text-muted-foreground", style: { height: `${opt(s, "hoogte", 25)}mm` }, children: "Afbeelding" }));
|
|
@@ -236,17 +295,7 @@ function KarKop({ sectie, kar, velden, bundelTekst = "" }) {
|
|
|
236
295
|
.replace(/{chauffeur}/g, kar.chauffeur)
|
|
237
296
|
.replace(/{lagen}/g, String(kar.lagen.length))
|
|
238
297
|
.replace(/{producten}/g, String(kar.lagen.reduce((n, l) => n + l.producten.length, 0)));
|
|
239
|
-
const info =
|
|
240
|
-
if (velden.includes("lagen"))
|
|
241
|
-
info.push(`${kar.lagen.length} lagen`);
|
|
242
|
-
if (velden.includes("producten"))
|
|
243
|
-
info.push(`${kar.lagen.reduce((n, l) => n + l.producten.reduce((m, p) => m + p.aantal, 0), 0)} producten`);
|
|
244
|
-
if (velden.includes("gewicht"))
|
|
245
|
-
info.push(kar.gewicht);
|
|
246
|
-
if (velden.includes("chauffeur"))
|
|
247
|
-
info.push(kar.chauffeur);
|
|
248
|
-
if (velden.includes("route"))
|
|
249
|
-
info.push(kar.route);
|
|
298
|
+
const info = karMetadata(kar, velden);
|
|
250
299
|
const groot = scheiding === "kop";
|
|
251
300
|
const gekleurd = scheiding === "kleur" || groot;
|
|
252
301
|
const toonNummer = velden.includes("karnummer");
|
|
@@ -256,7 +305,7 @@ function KarKop({ sectie, kar, velden, bundelTekst = "" }) {
|
|
|
256
305
|
!velden.includes("barcode") &&
|
|
257
306
|
!velden.includes("qrcode"))
|
|
258
307
|
return null;
|
|
259
|
-
return (_jsxs("div", { className: `flex items-center justify-between rounded px-2 py-1 ${groot ? "text-[13px] font-bold" : "font-semibold"}`, style: gekleurd ? { background: String(opt(sectie, "kleur", "#e8eef7")) } : undefined, children: [_jsxs("span", { className: "flex items-center gap-2", children: [toonNummer && _jsx("span", { children: tekst }), bundelTekst && _jsx(BundelMelding, { tekst: bundelTekst })] }), _jsxs("span", { className: "flex gap-3 text-[9px] font-normal", children: [info.map((t) => (_jsx("span", { children: t }, t))), velden.includes("barcode") &&
|
|
308
|
+
return (_jsxs("div", { className: `flex items-center justify-between rounded px-2 py-1 ${groot ? "text-[13px] font-bold" : "font-semibold"}`, style: gekleurd ? { background: String(opt(sectie, "kleur", "#e8eef7")) } : undefined, children: [_jsxs("span", { className: "flex items-center gap-2", children: [toonNummer && _jsx("span", { children: tekst }), bundelTekst && _jsx(BundelMelding, { tekst: bundelTekst })] }), _jsxs("span", { className: "flex gap-3 text-[9px] font-normal", children: [info.map((t) => (_jsx("span", { children: t }, t))), velden.includes("barcode") && kar.barcode ? (_jsx(BarcodeStrepen, { waarde: kar.barcode, hoogteMm: Number(opt(sectie, "barcodeHoogte", 15)) })) : null, velden.includes("qrcode") && _jsx("span", { children: "[QR]" })] })] }));
|
|
260
309
|
}
|
|
261
310
|
function LagenView({ sectie, lagen, productSectie, fustSectie, }) {
|
|
262
311
|
const modus = optS(sectie, "modus", "apart");
|
|
@@ -329,9 +378,10 @@ const FUST_KOLOM_LABELS = {
|
|
|
329
378
|
locatie: "Locatie",
|
|
330
379
|
fustsoort: "Tray/fust",
|
|
331
380
|
planten_per_fust: "Pl./fust",
|
|
381
|
+
fust_aantal: "Fusten",
|
|
332
382
|
aantal: "Planten",
|
|
333
383
|
};
|
|
334
|
-
const FUST_RECHTS = new Set(["planten_per_fust", "aantal"]);
|
|
384
|
+
const FUST_RECHTS = new Set(["planten_per_fust", "fust_aantal", "aantal"]);
|
|
335
385
|
/** Verzamellijst met alle te picken fusten per fusttype, incl. producten. */
|
|
336
386
|
function FustVerzamellijst({ order, kop = "Te verzamelen fusten — karindeling zelf bepalen", velden, toonFusthoogte = true, toonTotaal = true, }) {
|
|
337
387
|
const groepen = fustVerzamellijst(order?.karren);
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { type PakbonConfig, type PakbonSectie } from "../lib/pakbonBuilder.js";
|
|
1
|
+
import { type PakbonConfig, type PakbonSectie, type PakbonSectieType, type PickMethode } from "../lib/pakbonBuilder.js";
|
|
2
2
|
/** Beheer van de secties waaruit de pakbon is opgebouwd. */
|
|
3
|
-
export declare function PakbonSectiesPanel({ config, onChange, }: {
|
|
3
|
+
export declare function PakbonSectiesPanel({ config, onChange, beschikbareTypes, }: {
|
|
4
4
|
config: PakbonConfig;
|
|
5
5
|
onChange: (c: PakbonConfig) => void;
|
|
6
|
+
/** Beperkt de keuzelijst met blokken (bijvoorbeeld voor de afleverbrief). */
|
|
7
|
+
beschikbareTypes?: PakbonSectieType[];
|
|
6
8
|
}): import("react").JSX.Element;
|
|
7
9
|
/** Volledige instellingen van één blok — herbruikt in de blokontwerper. */
|
|
8
10
|
export declare function PakbonSectieEditor({ sectie, onChange, methode, }: {
|
|
9
11
|
sectie: PakbonSectie;
|
|
10
12
|
onChange: (patch: Partial<PakbonSectie>) => void;
|
|
11
|
-
methode?:
|
|
13
|
+
methode?: PickMethode;
|
|
12
14
|
}): import("react").JSX.Element;
|
|
13
15
|
/** Kaderinstellingen (breedte, uitlijning, marges, opmaak) van één blok. */
|
|
14
16
|
export declare function PakbonBlokKaderEditor({ sectie, onChange, }: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PakbonSectiesPanel.d.ts","sourceRoot":"","sources":["../../src/components/PakbonSectiesPanel.tsx"],"names":[],"mappings":"AAmBA,OAAO,EASL,KAAK,YAAY,EAEjB,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"PakbonSectiesPanel.d.ts","sourceRoot":"","sources":["../../src/components/PakbonSectiesPanel.tsx"],"names":[],"mappings":"AAmBA,OAAO,EASL,KAAK,YAAY,EAEjB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAE9B,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,QAAQ,EACR,gBAAgB,GACjB,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;IACpC,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACvC,+BAkLA;AA0TD,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,QAAQ,EACR,OAAe,GAChB,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB,+BAuHA;AAED,4EAA4E;AAC5E,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;CAClD,+BA4FA"}
|
|
@@ -7,12 +7,14 @@ import { LogoBibliotheekDialog } from "./LogoBibliotheekDialog.js";
|
|
|
7
7
|
import { LogoThumbnail } from "./LogosPage.js";
|
|
8
8
|
import { BESCHIKBARE_KOLOMMEN, CONDITIE_VELDEN, SECTIE_REGISTER, nieuweKolom, nieuweSectie, pickMethode, sectieDef, sectieOnderdrukt, } from "../lib/pakbonBuilder.js";
|
|
9
9
|
/** Beheer van de secties waaruit de pakbon is opgebouwd. */
|
|
10
|
-
export function PakbonSectiesPanel({ config, onChange, }) {
|
|
10
|
+
export function PakbonSectiesPanel({ config, onChange, beschikbareTypes, }) {
|
|
11
11
|
const alleSecties = Array.isArray(config?.secties) ? config.secties : [];
|
|
12
12
|
const methode = pickMethode(alleSecties);
|
|
13
|
+
const toegestaan = (t) => !beschikbareTypes || beschikbareTypes.includes(t);
|
|
13
14
|
const secties = alleSecties.filter((s) => !sectieOnderdrukt(s.type, methode));
|
|
14
15
|
const [open, setOpen] = useState(secties[0]?.id ?? null);
|
|
15
|
-
const
|
|
16
|
+
const keuzes = SECTIE_REGISTER.filter((d) => !sectieOnderdrukt(d.type, methode) && toegestaan(d.type));
|
|
17
|
+
const [toevoegen, setToevoegen] = useState(keuzes.find((d) => d.type === "orderregels")?.type ?? keuzes[0]?.type ?? "tekstblok");
|
|
16
18
|
// Onderdrukte blokken blijven bewaard in de configuratie, ook al staan ze niet in de lijst.
|
|
17
19
|
const verborgen = alleSecties.filter((s) => sectieOnderdrukt(s.type, methode));
|
|
18
20
|
const zet = (nieuw) => onChange({ ...config, secties: [...nieuw, ...verborgen] });
|
|
@@ -43,7 +45,7 @@ export function PakbonSectiesPanel({ config, onChange, }) {
|
|
|
43
45
|
...(config.logo ?? { logoId: null }),
|
|
44
46
|
uitlijning: v,
|
|
45
47
|
},
|
|
46
|
-
}), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "left", children: "Links" }), _jsx(SelectItem, { value: "center", children: "Midden" }), _jsx(SelectItem, { value: "right", children: "Rechts" })] })] })] })] }))] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Select, { value: toevoegen, onValueChange: (v) => setToevoegen(v), children: [_jsx(SelectTrigger, { className: "h-9", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children:
|
|
48
|
+
}), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "left", children: "Links" }), _jsx(SelectItem, { value: "center", children: "Midden" }), _jsx(SelectItem, { value: "right", children: "Rechts" })] })] })] })] }))] }), _jsxs("div", { className: "flex gap-2", children: [_jsxs(Select, { value: toevoegen, onValueChange: (v) => setToevoegen(v), children: [_jsx(SelectTrigger, { className: "h-9", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: keuzes.map((d) => (_jsx(SelectItem, { value: d.type, children: d.label }, d.type))) })] }), _jsx(Button, { size: "sm", onClick: () => {
|
|
47
49
|
const s = nieuweSectie(toevoegen);
|
|
48
50
|
zet([...secties, s]);
|
|
49
51
|
setOpen(s.id);
|
|
@@ -93,7 +95,8 @@ export function PakbonSectieEditor({ sectie, onChange, methode = "kar", }) {
|
|
|
93
95
|
const s = sectie;
|
|
94
96
|
const def = sectieDef(s.type);
|
|
95
97
|
const bundelAan = s.type === "karren" && (s.opties?.bundel_identiek ?? true);
|
|
96
|
-
// Instellingen van de fustverzamellijst gelden alleen bij picken per fust
|
|
98
|
+
// Instellingen van de fustverzamellijst gelden alleen bij picken per fust
|
|
99
|
+
// of bij de gecombineerde methode.
|
|
97
100
|
const verzamellijstUit = s.type === "pickmethode" && methode === "kar";
|
|
98
101
|
const aangepasteOpties = def.opties
|
|
99
102
|
.filter((o) => !(verzamellijstUit && o.key !== "methode"))
|
|
@@ -119,7 +122,7 @@ export function PakbonSectieEditor({ sectie, onChange, methode = "kar", }) {
|
|
|
119
122
|
logoId: logo?.id ?? null,
|
|
120
123
|
logoNaam: logo?.naam ?? null,
|
|
121
124
|
},
|
|
122
|
-
}) })),
|
|
125
|
+
}) })), s.type === "pickmethode" && methode === "beide" && (_jsxs("p", { className: "rounded border border-dashed px-3 py-2 text-xs text-muted-foreground", children: ["De Logistics Engine kiest per opdracht de variant: ", _jsx("span", { className: "font-medium", children: "volle kar" }), "toont de karrenindeling; ", _jsx("span", { className: "font-medium", children: "deelkar" }), " toont alleen de te verzamelen fusten. De barcode hieronder wordt alleen gevuld met de barcode uit die opdracht."] })), verzamellijstUit && (_jsxs("p", { className: "rounded border border-dashed px-3 py-2 text-xs text-muted-foreground", children: ["De instellingen voor de fustverzamellijst gelden bij picken per fusten of bij de gecombineerde methode. Bij picken per kar stel je de fustgegevens in bij het blok", _jsx("span", { className: "font-medium", children: " Fusten" }), "."] })), aangepasteOpties.map((o) => {
|
|
123
126
|
const isVelden = o.key === "velden";
|
|
124
127
|
const basisWaarde = s.opties?.[o.key] ?? o.standaard;
|
|
125
128
|
const waarde = isVelden && bundelAan
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
type PdfMapToestemmingBannerProps = {
|
|
2
2
|
alleenActieNodig?: boolean;
|
|
3
3
|
zwevend?: boolean;
|
|
4
|
+
printplekId?: string;
|
|
4
5
|
};
|
|
5
|
-
export declare function PdfMapToestemmingBanner({ alleenActieNodig, zwevend, }?: PdfMapToestemmingBannerProps): import("react").JSX.Element | null;
|
|
6
|
+
export declare function PdfMapToestemmingBanner({ alleenActieNodig, zwevend, printplekId, }?: PdfMapToestemmingBannerProps): import("react").JSX.Element | null;
|
|
6
7
|
export {};
|
|
7
8
|
//# sourceMappingURL=PdfMapToestemmingBanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PdfMapToestemmingBanner.d.ts","sourceRoot":"","sources":["../../src/components/PdfMapToestemmingBanner.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PdfMapToestemmingBanner.d.ts","sourceRoot":"","sources":["../../src/components/PdfMapToestemmingBanner.tsx"],"names":[],"mappings":"AA0BA,KAAK,4BAA4B,GAAG;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,EACtC,gBAAwB,EACxB,OAAe,EACf,WAAW,GACZ,GAAE,4BAAiC,sCAuQnC"}
|
|
@@ -10,12 +10,24 @@ import { Button, toast } from "@flowselections/core";
|
|
|
10
10
|
import { FolderCheck, FolderOpen, ShieldAlert, ShieldCheck } from "lucide-react";
|
|
11
11
|
import { usePrinters } from "../lib/useDocumentData.js";
|
|
12
12
|
import { zorgVoorPdfPrinter } from "../lib/pdfPrinter.js";
|
|
13
|
-
import {
|
|
14
|
-
|
|
13
|
+
import { supabase } from "../lib/supabaseClient.js";
|
|
14
|
+
import { draaitInIframe, herstelPdfMapToestemming, kiesPdfMap, mapKiezenMogelijk, openInEigenTabblad, lokalePdfPrintplek, pdfMapKoppeling, pdfMapNaam, pdfMapToestemming, } from "../lib/pdfMap.js";
|
|
15
|
+
export function PdfMapToestemmingBanner({ alleenActieNodig = false, zwevend = false, printplekId, } = {}) {
|
|
15
16
|
const { printers, reload } = usePrinters();
|
|
16
17
|
const pdfPrinter = printers.find((p) => p.afdrukmethode === "pdf");
|
|
17
18
|
const [naam, setNaam] = useState(null);
|
|
18
19
|
const [toestand, setToestand] = useState("laden");
|
|
20
|
+
const [gekoppeldePrintplek, setGekoppeldePrintplek] = useState(null);
|
|
21
|
+
const [persistent, setPersistent] = useState(null);
|
|
22
|
+
const [instellingOpen, setInstellingOpen] = useState(false);
|
|
23
|
+
const [aangevraagdePrintplek, setAangevraagdePrintplek] = useState(null);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const params = new URLSearchParams(window.location.search);
|
|
26
|
+
const gevraagd = params.get("pdf-printplek")?.trim() || null;
|
|
27
|
+
setInstellingOpen(params.get("pdf-map-instellen") === "1");
|
|
28
|
+
setAangevraagdePrintplek(gevraagd);
|
|
29
|
+
void lokalePdfPrintplek().then((lokaal) => setGekoppeldePrintplek(gevraagd ?? lokaal));
|
|
30
|
+
}, []);
|
|
19
31
|
// Zorg dat de virtuele PDF-printer bestaat, ook als de gebruiker nog geen
|
|
20
32
|
// wizard heeft doorlopen. Daarna herladen zodat de banner direct zichtbaar is.
|
|
21
33
|
useEffect(() => {
|
|
@@ -44,7 +56,23 @@ export function PdfMapToestemmingBanner({ alleenActieNodig = false, zwevend = fa
|
|
|
44
56
|
}
|
|
45
57
|
setNaam(await pdfMapNaam(pdfPrinter.id));
|
|
46
58
|
setToestand(await pdfMapToestemming(pdfPrinter.id));
|
|
47
|
-
|
|
59
|
+
const koppeling = await pdfMapKoppeling();
|
|
60
|
+
let doelPrintplek = printplekId ?? aangevraagdePrintplek ?? koppeling?.printPlekId ?? null;
|
|
61
|
+
if (!doelPrintplek) {
|
|
62
|
+
const { data } = await supabase
|
|
63
|
+
.from("document_printplek_printers")
|
|
64
|
+
.select("print_plek_id")
|
|
65
|
+
.eq("printer_id", pdfPrinter.id);
|
|
66
|
+
const ids = [
|
|
67
|
+
...new Set((Array.isArray(data) ? data : [])
|
|
68
|
+
.map((rij) => String(rij.print_plek_id ?? "").trim())
|
|
69
|
+
.filter(Boolean)),
|
|
70
|
+
];
|
|
71
|
+
doelPrintplek = ids.length === 1 ? ids[0] ?? null : null;
|
|
72
|
+
}
|
|
73
|
+
setGekoppeldePrintplek(doelPrintplek);
|
|
74
|
+
setPersistent(koppeling?.persistent ?? null);
|
|
75
|
+
}, [aangevraagdePrintplek, pdfPrinter, printplekId]);
|
|
48
76
|
useEffect(() => {
|
|
49
77
|
void laad();
|
|
50
78
|
}, [laad]);
|
|
@@ -58,14 +86,24 @@ export function PdfMapToestemmingBanner({ alleenActieNodig = false, zwevend = fa
|
|
|
58
86
|
document.removeEventListener("visibilitychange", h);
|
|
59
87
|
};
|
|
60
88
|
}, [laad]);
|
|
61
|
-
|
|
89
|
+
// In een iframe (o.a. de Lovable-preview) heeft de balk geen nut: de
|
|
90
|
+
// mappenverkenner werkt daar niet en de gebruiker kan alleen via "Open in
|
|
91
|
+
// eigen tabblad" verder. De balk daar niet tonen houdt de preview schoon;
|
|
92
|
+
// in een eigen tabblad blijft hij volledig zichtbaar.
|
|
93
|
+
const inIframe = draaitInIframe();
|
|
94
|
+
if (inIframe)
|
|
62
95
|
return null;
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
96
|
+
// De banner mag nooit onzichtbaar zijn: zonder PDF-printer is de mapkeuze
|
|
97
|
+
// onmogelijk en zonder mapkeuze mislukt elke lokale PDF-opslag. Toon daarom
|
|
98
|
+
// ook een waarschuwing terwijl de printer nog (aan)ge(maakt) wordt.
|
|
99
|
+
const vereistePrintplek = printplekId ?? aangevraagdePrintplek ?? gekoppeldePrintplek;
|
|
100
|
+
const inOrde = !!pdfPrinter &&
|
|
101
|
+
toestand === "granted" &&
|
|
102
|
+
!!naam &&
|
|
103
|
+
!!gekoppeldePrintplek &&
|
|
104
|
+
(!vereistePrintplek || gekoppeldePrintplek === vereistePrintplek);
|
|
105
|
+
if (alleenActieNodig && !instellingOpen && (!pdfPrinter ? false : toestand === "laden" || inOrde))
|
|
67
106
|
return null;
|
|
68
|
-
const inIframe = draaitInIframe();
|
|
69
107
|
const ondersteund = mapKiezenMogelijk();
|
|
70
108
|
const geefToestemming = async () => {
|
|
71
109
|
if (!pdfPrinter)
|
|
@@ -94,13 +132,14 @@ export function PdfMapToestemmingBanner({ alleenActieNodig = false, zwevend = fa
|
|
|
94
132
|
description: "Open de app in een eigen tabblad om de mappenverkenner te gebruiken.",
|
|
95
133
|
action: {
|
|
96
134
|
label: "Open in eigen tabblad",
|
|
97
|
-
onClick: openInEigenTabblad,
|
|
135
|
+
onClick: () => openInEigenTabblad(printplekId ?? gekoppeldePrintplek ?? undefined),
|
|
98
136
|
},
|
|
99
137
|
duration: 15000,
|
|
100
138
|
});
|
|
101
139
|
return;
|
|
102
140
|
}
|
|
103
|
-
const
|
|
141
|
+
const doelPrintplek = printplekId ?? gekoppeldePrintplek ?? undefined;
|
|
142
|
+
const uitkomst = await kiesPdfMap(pdfPrinter.id, doelPrintplek);
|
|
104
143
|
if (uitkomst.status === "gekozen") {
|
|
105
144
|
toast.success("Map gekozen", { description: `PDF's worden opgeslagen in “${uitkomst.naam}”.` });
|
|
106
145
|
await laad();
|
|
@@ -113,7 +152,10 @@ export function PdfMapToestemmingBanner({ alleenActieNodig = false, zwevend = fa
|
|
|
113
152
|
else if (uitkomst.status === "iframe-geblokkeerd") {
|
|
114
153
|
toast.error("Map kiezen werkt niet in een iframe", {
|
|
115
154
|
description: "Open de app in een eigen tabblad.",
|
|
116
|
-
action: {
|
|
155
|
+
action: {
|
|
156
|
+
label: "Open in eigen tabblad",
|
|
157
|
+
onClick: () => openInEigenTabblad(printplekId ?? gekoppeldePrintplek ?? undefined),
|
|
158
|
+
},
|
|
117
159
|
duration: 15000,
|
|
118
160
|
});
|
|
119
161
|
}
|
|
@@ -121,12 +163,27 @@ export function PdfMapToestemmingBanner({ alleenActieNodig = false, zwevend = fa
|
|
|
121
163
|
toast.error("Map kiezen is mislukt", { description: uitkomst.melding });
|
|
122
164
|
}
|
|
123
165
|
};
|
|
124
|
-
const icoon =
|
|
166
|
+
const icoon = inOrde
|
|
125
167
|
? ShieldCheck
|
|
126
168
|
: toestand === "denied"
|
|
127
169
|
? ShieldAlert
|
|
128
170
|
: FolderOpen;
|
|
129
171
|
const Icoon = icoon;
|
|
172
|
+
if (!pdfPrinter) {
|
|
173
|
+
return (_jsxs("div", { role: "status", "aria-live": "polite", className: `${zwevend ? "fixed inset-x-4 top-4 z-[100] mx-auto max-w-4xl shadow-lg" : ""} flex flex-wrap items-center justify-between gap-3 rounded-lg border border-amber-300/60 bg-amber-50 p-3 dark:border-amber-700/60 dark:bg-amber-950/30`, children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(ShieldAlert, { className: "h-4 w-4 text-amber-600 dark:text-amber-400" }), _jsx("span", { className: "font-medium", children: "PDF-maptoestemming" }), _jsx("span", { className: "text-muted-foreground", children: "De virtuele \u201COpslaan als PDF\u201D-printer wordt aangemaakt of kon nog niet worden geladen." })] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
174
|
+
void (async () => {
|
|
175
|
+
try {
|
|
176
|
+
await zorgVoorPdfPrinter();
|
|
177
|
+
await reload(true);
|
|
178
|
+
}
|
|
179
|
+
catch (fout) {
|
|
180
|
+
toast.error("PDF-printer kon niet worden aangemaakt", {
|
|
181
|
+
description: fout instanceof Error ? fout.message : undefined,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
})();
|
|
185
|
+
}, children: [_jsx(FolderOpen, { className: "mr-2 h-4 w-4" }), " PDF-printer aanmaken"] })] }));
|
|
186
|
+
}
|
|
130
187
|
return (_jsxs("div", { role: "status", "aria-live": "polite", className: `${inOrde
|
|
131
188
|
? "border-emerald-300/60 bg-emerald-50 dark:border-emerald-700/60 dark:bg-emerald-950/30"
|
|
132
189
|
: "border-amber-300/60 bg-amber-50 dark:border-amber-700/60 dark:bg-amber-950/30"} ${zwevend
|
|
@@ -135,5 +192,7 @@ export function PdfMapToestemmingBanner({ alleenActieNodig = false, zwevend = fa
|
|
|
135
192
|
? "h-4 w-4 text-emerald-600 dark:text-emerald-400"
|
|
136
193
|
: "h-4 w-4 text-amber-600 dark:text-amber-400" }), _jsx("span", { className: "font-medium", children: "PDF-maptoestemming" }), _jsxs("span", { className: "text-muted-foreground", children: [naam
|
|
137
194
|
? `Map “${naam}” — toestemming ${toestand === "granted" ? "verleend" : "vereist vernieuwen"}`
|
|
138
|
-
: "Nog geen map gekozen op deze computer", !ondersteund ? " (browser ondersteunt geen mapkeuze)" : ""
|
|
195
|
+
: "Nog geen map gekozen op deze computer", !ondersteund ? " (browser ondersteunt geen mapkeuze)" : "", inIframe
|
|
196
|
+
? " — de preview draait in een iframe; de mapkeuze geldt per webadres en moet hier opnieuw worden gezet"
|
|
197
|
+
: "", !inIframe && gekoppeldePrintplek ? " — gekoppeld aan deze printplek" : "", !inIframe && persistent === false ? " — browseropslag is niet permanent gegarandeerd" : ""] })] }), _jsxs("div", { className: "flex gap-2", children: [naam ? (_jsxs(Button, { size: "sm", variant: inOrde ? "outline" : "default", onClick: () => void geefToestemming(), children: [_jsx(FolderCheck, { className: "mr-2 h-4 w-4" }), inOrde ? "Toestemming controleren" : "Maptoestemming geven"] })) : null, _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void kiesNieuweMap(), children: [_jsx(FolderOpen, { className: "mr-2 h-4 w-4" }), " ", naam ? "Andere map kiezen" : "Map kiezen"] }), inIframe ? (_jsx(Button, { size: "sm", variant: "outline", onClick: () => openInEigenTabblad(printplekId ?? gekoppeldePrintplek ?? undefined), children: "Open in eigen tabblad" })) : null] })] }));
|
|
139
198
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** Print-HTML, exact zoals die ook naar de printwachtrij gaat. */
|
|
3
|
+
html: string;
|
|
4
|
+
breedteMm: number;
|
|
5
|
+
hoogteMm: number;
|
|
6
|
+
margeMm: number;
|
|
7
|
+
onControle?: (status: "controleren" | "gereed" | "afwijking", fout?: string) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Toont het voorbeeld altijd: de print-HTML wordt direct getoond op ware
|
|
11
|
+
* papiergrootte (werkt ook binnen een shell-iframe, waar Chrome ingesloten
|
|
12
|
+
* PDF's blokkeert). De echte print-PDF blijft opvraagbaar in een eigen tabblad.
|
|
13
|
+
*
|
|
14
|
+
* Pagina's stapelen verticaal; het hele kader wordt met een CSS-schaling op
|
|
15
|
+
* de beschikbare breedte passend gemaakt, zodat het document altijd volledig
|
|
16
|
+
* zichtbaar is (met verticaal scrollen bij meerdere pagina's).
|
|
17
|
+
*/
|
|
18
|
+
export declare function PdfVoorbeeld({ html, breedteMm, hoogteMm, margeMm, onControle }: Props): import("react").JSX.Element;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=PdfVoorbeeld.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PdfVoorbeeld.d.ts","sourceRoot":"","sources":["../../src/components/PdfVoorbeeld.tsx"],"names":[],"mappings":"AAKA,UAAU,KAAK;IACb,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,GAAG,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtF;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,+BAyGrF"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { Button } from "@flowselections/core";
|
|
4
|
+
import { AlertTriangle, ExternalLink, Loader2 } from "lucide-react";
|
|
5
|
+
import { maakVoorbeeldPdf } from "../lib/documentVoorbeeld.functions.js";
|
|
6
|
+
/**
|
|
7
|
+
* Toont het voorbeeld altijd: de print-HTML wordt direct getoond op ware
|
|
8
|
+
* papiergrootte (werkt ook binnen een shell-iframe, waar Chrome ingesloten
|
|
9
|
+
* PDF's blokkeert). De echte print-PDF blijft opvraagbaar in een eigen tabblad.
|
|
10
|
+
*
|
|
11
|
+
* Pagina's stapelen verticaal; het hele kader wordt met een CSS-schaling op
|
|
12
|
+
* de beschikbare breedte passend gemaakt, zodat het document altijd volledig
|
|
13
|
+
* zichtbaar is (met verticaal scrollen bij meerdere pagina's).
|
|
14
|
+
*/
|
|
15
|
+
export function PdfVoorbeeld({ html, breedteMm, hoogteMm, margeMm, onControle }) {
|
|
16
|
+
const renderVolgorde = useRef(0);
|
|
17
|
+
const controleCallback = useRef(onControle);
|
|
18
|
+
const [paginas, setPaginas] = useState([]);
|
|
19
|
+
const [bezigPdf, setBezigPdf] = useState(false);
|
|
20
|
+
const [fout, setFout] = useState(null);
|
|
21
|
+
const [pdfBase64, setPdfBase64] = useState(null);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
controleCallback.current = onControle;
|
|
24
|
+
}, [onControle]);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const volgorde = ++renderVolgorde.current;
|
|
27
|
+
const timer = window.setTimeout(() => {
|
|
28
|
+
setBezigPdf(true);
|
|
29
|
+
setFout(null);
|
|
30
|
+
controleCallback.current?.("controleren");
|
|
31
|
+
void maakVoorbeeldPdf({ data: { html, breedteMm, hoogteMm, margeMm } })
|
|
32
|
+
.then(async (res) => {
|
|
33
|
+
if (volgorde !== renderVolgorde.current)
|
|
34
|
+
return;
|
|
35
|
+
const bin = atob(res.pdfBase64);
|
|
36
|
+
const bytes = new Uint8Array(bin.length);
|
|
37
|
+
for (let i = 0; i < bin.length; i += 1)
|
|
38
|
+
bytes[i] = bin.charCodeAt(i);
|
|
39
|
+
const pdfjs = await import("pdfjs-dist");
|
|
40
|
+
pdfjs.GlobalWorkerOptions.workerSrc = new URL("pdfjs-dist/build/pdf.worker.min.mjs", import.meta.url).toString();
|
|
41
|
+
const taak = pdfjs.getDocument({ data: bytes });
|
|
42
|
+
const pdf = await taak.promise;
|
|
43
|
+
const nieuw = [];
|
|
44
|
+
for (let nummer = 1; nummer <= pdf.numPages; nummer += 1) {
|
|
45
|
+
const pagina = await pdf.getPage(nummer);
|
|
46
|
+
const viewport = pagina.getViewport({ scale: 1.5 });
|
|
47
|
+
const canvas = document.createElement("canvas");
|
|
48
|
+
canvas.width = viewport.width;
|
|
49
|
+
canvas.height = viewport.height;
|
|
50
|
+
const context = canvas.getContext("2d");
|
|
51
|
+
if (!context)
|
|
52
|
+
throw new Error("De afdrukpagina kon niet worden getoond.");
|
|
53
|
+
await pagina.render({ canvas, canvasContext: context, viewport }).promise;
|
|
54
|
+
nieuw.push(canvas.toDataURL("image/png"));
|
|
55
|
+
}
|
|
56
|
+
if (volgorde !== renderVolgorde.current)
|
|
57
|
+
return;
|
|
58
|
+
setPaginas(nieuw);
|
|
59
|
+
setPdfBase64(res.pdfBase64);
|
|
60
|
+
controleCallback.current?.("gereed");
|
|
61
|
+
})
|
|
62
|
+
.catch((e) => {
|
|
63
|
+
if (volgorde !== renderVolgorde.current)
|
|
64
|
+
return;
|
|
65
|
+
const melding = e instanceof Error ? e.message : "Afdrukcontrole mislukt";
|
|
66
|
+
setPaginas([]);
|
|
67
|
+
setPdfBase64(null);
|
|
68
|
+
setFout(melding);
|
|
69
|
+
controleCallback.current?.("afwijking", melding);
|
|
70
|
+
})
|
|
71
|
+
.finally(() => {
|
|
72
|
+
if (volgorde === renderVolgorde.current)
|
|
73
|
+
setBezigPdf(false);
|
|
74
|
+
});
|
|
75
|
+
}, 350);
|
|
76
|
+
return () => window.clearTimeout(timer);
|
|
77
|
+
}, [html, breedteMm, hoogteMm, margeMm]);
|
|
78
|
+
const openPdf = async () => {
|
|
79
|
+
if (!pdfBase64)
|
|
80
|
+
return;
|
|
81
|
+
try {
|
|
82
|
+
const bin = atob(pdfBase64);
|
|
83
|
+
const bytes = new Uint8Array(bin.length);
|
|
84
|
+
for (let i = 0; i < bin.length; i += 1)
|
|
85
|
+
bytes[i] = bin.charCodeAt(i);
|
|
86
|
+
const url = URL.createObjectURL(new Blob([bytes], { type: "application/pdf" }));
|
|
87
|
+
window.open(url, "_blank", "noopener,noreferrer");
|
|
88
|
+
setTimeout(() => URL.revokeObjectURL(url), 60000);
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
setFout(e instanceof Error ? e.message : "PDF kon niet worden geopend");
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
return (_jsxs("div", { className: "relative h-full w-full overflow-hidden", children: [_jsx("div", { className: "h-full w-full overflow-y-auto overflow-x-hidden rounded-md bg-muted p-3", children: _jsxs("div", { className: "mx-auto flex max-w-full flex-col items-center gap-4", children: [paginas.map((src, index) => (_jsx("img", { src: src, alt: `Afdrukpagina ${index + 1}`, className: "h-auto max-w-full border bg-background shadow-sm" }, `${index}-${src.length}`))), bezigPdf ? _jsx(Loader2, { className: "mt-8 h-6 w-6 animate-spin text-muted-foreground" }) : null, fout ? _jsxs("div", { className: "mt-8 flex max-w-md items-start gap-2 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), fout] }) : null] }) }), _jsx("div", { className: "pointer-events-none absolute right-3 top-3 flex flex-col items-end gap-2", children: _jsxs(Button, { size: "sm", variant: "outline", className: "pointer-events-auto", onClick: () => void openPdf(), disabled: bezigPdf || !pdfBase64, children: [bezigPdf ? (_jsx(Loader2, { className: "mr-2 h-3 w-3 animate-spin" })) : (_jsx(ExternalLink, { className: "mr-2 h-3 w-3" })), "Print-PDF openen"] }) })] }));
|
|
95
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PrintProgrammaUitleg.d.ts","sourceRoot":"","sources":["../../src/components/PrintProgrammaUitleg.tsx"],"names":[],"mappings":"AAgBA,wBAAgB,oBAAoB,CAAC,EAAE,OAAe,EAAE,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,+BAmC9E;AAED,wBAAgB,YAAY,
|
|
1
|
+
{"version":3,"file":"PrintProgrammaUitleg.d.ts","sourceRoot":"","sources":["../../src/components/PrintProgrammaUitleg.tsx"],"names":[],"mappings":"AAgBA,wBAAgB,oBAAoB,CAAC,EAAE,OAAe,EAAE,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,+BAmC9E;AAED,wBAAgB,YAAY,gCAc3B"}
|
|
@@ -15,5 +15,5 @@ export function PrintProgrammaUitleg({ compact = false }) {
|
|
|
15
15
|
return (_jsxs("div", { className: "bg-muted/40 space-y-4 rounded-xl border p-5", children: [!compact && (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "bg-background rounded-lg border p-2", children: _jsx(MonitorSmartphone, { className: "text-muted-foreground h-5 w-5" }) }), _jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium", children: "We zien nog geen printers" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Zet de computer klaar in drie korte stappen." })] })] })), _jsx("ol", { className: "space-y-3", children: STAPPEN.map((tekst, i) => (_jsxs("li", { className: "flex gap-3", children: [_jsx("span", { className: "bg-background text-foreground flex h-6 w-6 shrink-0 items-center justify-center rounded-full border text-xs font-medium", children: i + 1 }), _jsx("span", { className: "text-sm", children: tekst })] }, tekst))) }), _jsx(Button, { asChild: true, variant: "outline", children: _jsxs("a", { href: DOWNLOAD_URL, target: "_blank", rel: "noreferrer", children: [_jsx(Download, { className: "mr-2 h-4 w-4" }), " Printprogramma downloaden"] }) })] }));
|
|
16
16
|
}
|
|
17
17
|
export function WerktHetNiet() {
|
|
18
|
-
return (_jsxs("details", { className: "group rounded-lg border p-3", children: [_jsxs("summary", { className: "flex cursor-pointer items-center gap-2 text-sm font-medium", children: [_jsx(HelpCircle, { className: "text-muted-foreground h-4 w-4" }), " Werkt het niet?"] }), _jsxs("ul", { className: "text-muted-foreground mt-3 space-y-2 text-sm", children: [_jsx("li", { children: "De computer staat uit
|
|
18
|
+
return (_jsxs("details", { className: "group rounded-lg border p-3", children: [_jsxs("summary", { className: "flex cursor-pointer items-center gap-2 text-sm font-medium", children: [_jsx(HelpCircle, { className: "text-muted-foreground h-4 w-4" }), " Werkt het niet?"] }), _jsxs("ul", { className: "text-muted-foreground mt-3 space-y-2 text-sm", children: [_jsx("li", { children: "De computer staat uit, is in slaapstand of heeft geen internet." }), _jsx("li", { children: "Het printprogramma is nog niet gestart op die computer." }), _jsx("li", { children: "Er is ingelogd met een eigen/ander PrintNode-account in plaats van de beheerdergegevens \u2014 alleen computers onder het gekoppelde account verschijnen hier." }), _jsx("li", { children: "De computer heet anders dan je verwacht: de naam in de lijst is de naam zoals macOS die aan PrintNode doorgeeft." })] })] }));
|
|
19
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PrintQueuePage.d.ts","sourceRoot":"","sources":["../../src/components/PrintQueuePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PrintQueuePage.d.ts","sourceRoot":"","sources":["../../src/components/PrintQueuePage.tsx"],"names":[],"mappings":"AAuFA,wBAAgB,cAAc,gCA2X7B"}
|