@flowselections/layout-maker 1.32.0 → 1.38.4
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/README.md +139 -139
- package/dist-lib/components/AfdrukKnop.d.ts +19 -19
- package/dist-lib/components/ComputersLijst.d.ts.map +1 -1
- package/dist-lib/components/ComputersLijst.js +5 -5
- package/dist-lib/components/DocumentenPage.d.ts.map +1 -1
- package/dist-lib/components/DocumentenPage.js +3 -2
- package/dist-lib/components/LayoutPrinterSelect.d.ts +8 -0
- package/dist-lib/components/LayoutPrinterSelect.d.ts.map +1 -0
- package/dist-lib/components/LayoutPrinterSelect.js +23 -0
- package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
- package/dist-lib/components/LayoutsPage.js +16 -3
- package/dist-lib/components/NetwerkPrintersDialog.d.ts +7 -7
- 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 +6 -2
- 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 +55 -12
- package/dist-lib/components/PakbonSectiesPanel.d.ts +2 -2
- package/dist-lib/components/PakbonSectiesPanel.d.ts.map +1 -1
- package/dist-lib/components/PakbonSectiesPanel.js +7 -2
- package/dist-lib/components/PdfMapAutoSaver.d.ts +6 -0
- package/dist-lib/components/PdfMapAutoSaver.d.ts.map +1 -0
- package/dist-lib/components/PdfMapAutoSaver.js +12 -0
- package/dist-lib/components/PdfMapGlobaleBanner.d.ts +12 -0
- package/dist-lib/components/PdfMapGlobaleBanner.d.ts.map +1 -0
- package/dist-lib/components/PdfMapGlobaleBanner.js +30 -0
- package/dist-lib/components/PdfMapToestemmingBanner.d.ts +7 -0
- package/dist-lib/components/PdfMapToestemmingBanner.d.ts.map +1 -0
- package/dist-lib/components/PdfMapToestemmingBanner.js +139 -0
- package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
- package/dist-lib/components/PrintQueuePage.js +42 -3
- package/dist-lib/components/PrintenPage.d.ts.map +1 -1
- package/dist-lib/components/PrintenPage.js +3 -2
- package/dist-lib/components/PrinterSetupWizard.d.ts.map +1 -1
- package/dist-lib/components/PrinterSetupWizard.js +28 -5
- package/dist-lib/components/PrintersRedirectPage.d.ts +1 -1
- package/dist-lib/components/PrintersRedirectPage.js +14 -14
- package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
- package/dist-lib/components/PrintplekDetailPage.js +30 -4
- package/dist-lib/components/PrintplekWizard.d.ts.map +1 -1
- package/dist-lib/components/PrintplekWizard.js +81 -3
- package/dist-lib/components/ProductiebonBuilderPage.d.ts.map +1 -1
- package/dist-lib/components/ProductiebonBuilderPage.js +3 -1
- package/dist-lib/index.d.ts +10 -2
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +13 -2
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +1396 -727
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +1396 -727
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.js +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +24008 -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 +1403 -750
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/aiLayout.functions.d.ts +1396 -727
- package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
- package/dist-lib/lib/aiLayout.server.js +9 -9
- package/dist-lib/lib/browserPrint.js +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/htmlPdf.server.d.ts.map +1 -1
- package/dist-lib/lib/htmlPdf.server.js +101 -6
- package/dist-lib/lib/layoutPreview.d.ts.map +1 -1
- package/dist-lib/lib/layoutPreview.js +11 -8
- package/dist-lib/lib/orderData.server.d.ts.map +1 -1
- package/dist-lib/lib/orderData.server.js +123 -10
- package/dist-lib/lib/pakbonBuilder.d.ts +28 -2
- package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
- package/dist-lib/lib/pakbonBuilder.js +69 -8
- package/dist-lib/lib/pakbonHtml.d.ts +14 -2
- package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
- package/dist-lib/lib/pakbonHtml.js +155 -63
- 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 +105 -0
- package/dist-lib/lib/pdfJobSaver.d.ts +20 -0
- package/dist-lib/lib/pdfJobSaver.d.ts.map +1 -0
- package/dist-lib/lib/pdfJobSaver.js +173 -0
- package/dist-lib/lib/pdfMap.d.ts +48 -0
- package/dist-lib/lib/pdfMap.d.ts.map +1 -0
- package/dist-lib/lib/pdfMap.js +219 -0
- package/dist-lib/lib/pdfPrinter.d.ts +9 -0
- package/dist-lib/lib/pdfPrinter.d.ts.map +1 -0
- package/dist-lib/lib/pdfPrinter.js +34 -0
- package/dist-lib/lib/previewPdf.d.ts.map +1 -1
- package/dist-lib/lib/previewPdf.js +41 -9
- package/dist-lib/lib/printApi.d.ts.map +1 -1
- package/dist-lib/lib/printApi.js +9 -1
- package/dist-lib/lib/printQueue.server.d.ts +7 -0
- package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/printQueue.server.js +346 -52
- package/dist-lib/lib/printService.functions.d.ts +5365 -2689
- package/dist-lib/lib/printService.functions.d.ts.map +1 -1
- package/dist-lib/lib/productiebonHtml.js +15 -15
- package/dist-lib/lib/profielHtml.js +18 -18
- package/dist-lib/lib/supabaseAdmin.server.d.ts +5 -5
- package/dist-lib/lib/supabaseAdmin.server.js +43 -43
- 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/testpagina.js +3 -3
- package/dist-lib/lib/testprint.js +4 -4
- package/dist-lib/lib/useDocumentData.d.ts +10 -0
- package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
- package/dist-lib/lib/useDocumentData.js +19 -0
- package/dist-lib/lib/voorbeeldPrint.d.ts +4 -0
- package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
- package/dist-lib/lib/voorbeeldPrint.js +13 -2
- package/package.json +151 -151
|
@@ -1,7 +1,7 @@
|
|
|
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";
|
|
4
|
+
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "@flowselections/core";
|
|
5
5
|
import { ArrowLeft, Loader2, Printer, Save } from "lucide-react";
|
|
6
6
|
import { PakbonSectiesPanel } from "./PakbonSectiesPanel.js";
|
|
7
7
|
import { PakbonPreview } from "./PakbonPreview.js";
|
|
@@ -11,6 +11,7 @@ import { renderPakbonDocument, voorbeeldPakbonOrder } from "../lib/pakbonHtml.js
|
|
|
11
11
|
import { voorbeeldPrint } from "../lib/voorbeeldPrint.js";
|
|
12
12
|
import { haalPrintLogos } from "../lib/logoLibrary.js";
|
|
13
13
|
import { updateLayout, useLayoutDetail } from "../lib/useDocumentData.js";
|
|
14
|
+
import { LayoutPrinterSelect } from "./LayoutPrinterSelect.js";
|
|
14
15
|
import { useLayoutIdParam } from "../lib/useLayoutIdParam.js";
|
|
15
16
|
/** Sectiegebaseerde pakbon-builder met live voorbeeld op echte ordergegevens. */
|
|
16
17
|
export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
|
|
@@ -19,6 +20,7 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
|
|
|
19
20
|
const [config, setConfig] = useState(null);
|
|
20
21
|
const [bezig, setBezig] = useState(false);
|
|
21
22
|
const [printen, setPrinten] = useState(false);
|
|
23
|
+
const [voorbeeldVariant, setVoorbeeldVariant] = useState("full_cart");
|
|
22
24
|
useEffect(() => {
|
|
23
25
|
if (layout)
|
|
24
26
|
setConfig(leesPakbonConfig(layout.config));
|
|
@@ -50,9 +52,11 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
|
|
|
50
52
|
logos,
|
|
51
53
|
breedteMm: breedte,
|
|
52
54
|
hoogteMm: hoogte,
|
|
55
|
+
layoutVariant: voorbeeldVariant,
|
|
53
56
|
titel: layout?.naam ?? "Pakbon",
|
|
54
57
|
});
|
|
55
58
|
await voorbeeldPrint({
|
|
59
|
+
...(layout ?? {}),
|
|
56
60
|
id: layout?.id ?? layoutId,
|
|
57
61
|
naam: layout?.naam,
|
|
58
62
|
documenttype: layout?.documenttype ?? "pakbon",
|
|
@@ -72,5 +76,5 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
|
|
|
72
76
|
return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout laden\u2026" });
|
|
73
77
|
if (!layout || !config)
|
|
74
78
|
return _jsx("main", { className: "p-6 text-sm text-muted-foreground", children: "Layout niet gevonden." });
|
|
75
|
-
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 gap-2", children: [_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: "
|
|
79
|
+
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: "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" })] })] }), _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, variant: voorbeeldVariant }) }) })] })] })] }));
|
|
76
80
|
}
|
|
@@ -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":"
|
|
1
|
+
{"version":3,"file":"PakbonPreview.d.ts","sourceRoot":"","sources":["../../src/components/PakbonPreview.tsx"],"names":[],"mappings":"AAIA,OAAO,EAsBL,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"}
|
|
@@ -2,14 +2,33 @@ 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 { DEMO_ORDER, deelkarVoorbeeldOrder, conditieContext, groepeerIdentiekeKarren, groepeerIdentiekeLagen, karBundelTekst, fustVerzamellijst, pickMethode, pakbonLayoutVariant, productVeldBreedtes, sectieOnderdruktVoorVariant, kolomLabel, laagBundelTekst, sectieZichtbaar, sorteerProducten, totalen, vulVeldcodes, } from "../lib/pakbonBuilder.js";
|
|
7
|
+
/** Voorbeeldbarcode: alleen bedoeld om de plek en hoogte te tonen. */
|
|
8
|
+
function BarcodeStrepen({ waarde, hoogteMm = 15 }) {
|
|
9
|
+
const bars = code128Bars(waarde);
|
|
10
|
+
if (!bars)
|
|
11
|
+
return null;
|
|
12
|
+
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 })] }));
|
|
13
|
+
}
|
|
14
|
+
export function PakbonPreview({ config, breedteMm = 210, hoogteMm = 297, variant = null, }) {
|
|
15
|
+
// De deelkarweergave gebruikt bewust een beperkte demo-order. Daardoor zie
|
|
16
|
+
// je in het voorbeeld alleen de fusten die voor deze deelkar verzameld
|
|
17
|
+
// moeten worden, nooit een misleidende volledige karindeling.
|
|
18
|
+
const order = variant === "partial_order" ? deelkarVoorbeeldOrder() : DEMO_ORDER;
|
|
8
19
|
const ctx = conditieContext(order);
|
|
9
20
|
const alleSecties = Array.isArray(config?.secties) ? config.secties : [];
|
|
10
21
|
const methode = pickMethode(alleSecties);
|
|
11
|
-
const
|
|
22
|
+
const actieveVariant = pakbonLayoutVariant(variant);
|
|
23
|
+
const secties = alleSecties.filter((s) => sectieZichtbaar(s, ctx) && !sectieOnderdruktVoorVariant(s.type, methode, actieveVariant));
|
|
12
24
|
const zoek = (type) => secties.find((s) => s.type === type);
|
|
25
|
+
const pickSectie = alleSecties.find((s) => s.type === "pickmethode");
|
|
26
|
+
const barcodeAan = !alleSecties.some((s) => s.type === "barcode") &&
|
|
27
|
+
(pickSectie ? opt(pickSectie, "toonBarcode", true) !== false : true);
|
|
28
|
+
const barcodeHoogte = pickSectie ? Number(opt(pickSectie, "barcodeHoogte", 15)) : 15;
|
|
29
|
+
const heeftKarBarcodes = secties.some((s) => s.type === "karren") &&
|
|
30
|
+
order.karren.some((kar) => Boolean(String(kar.barcode ?? "").trim()));
|
|
31
|
+
const paginaLabel = actieveVariant === "partial_order" ? "Deelkar" : "Hele kar";
|
|
13
32
|
const segmenten = [];
|
|
14
33
|
if (config?.logo?.logoId) {
|
|
15
34
|
segmenten.push({
|
|
@@ -28,23 +47,47 @@ export function PakbonPreview({ config, breedteMm = 210, hoogteMm = 297, }) {
|
|
|
28
47
|
if (s.type === "karren") {
|
|
29
48
|
segmenten.push(...karSegmenten(s, order, zoek));
|
|
30
49
|
}
|
|
50
|
+
else if (s.type === "barcode" && heeftKarBarcodes) {
|
|
51
|
+
// De barcode wordt binnen ieder afzonderlijk karblok getoond.
|
|
52
|
+
}
|
|
31
53
|
else if (s.type === "totalen" && (totalenElkePagina || toonPaginanummer)) {
|
|
32
54
|
// wordt als voettekst onder elke pagina getoond
|
|
33
55
|
}
|
|
34
56
|
else {
|
|
35
57
|
segmenten.push({
|
|
36
58
|
key: s.id,
|
|
59
|
+
pageLabel: paginaLabel,
|
|
37
60
|
node: (_jsx(BlokFrame, { sectie: s, children: _jsx(SectieView, { sectie: s, order: order, zoek: zoek }) })),
|
|
38
61
|
});
|
|
39
62
|
}
|
|
40
63
|
}
|
|
64
|
+
if (barcodeAan && !heeftKarBarcodes) {
|
|
65
|
+
segmenten.push({
|
|
66
|
+
key: "engine-barcode",
|
|
67
|
+
pageLabel: paginaLabel,
|
|
68
|
+
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." })] })),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Het volle-karvoorbeeld is bewust een complete serie: vier hele karren en
|
|
72
|
+
// als vijfde pagina één deelkar zonder karindeling. Zo is het verschil in
|
|
73
|
+
// dezelfde voorbeeldreeks direct zichtbaar.
|
|
74
|
+
if (actieveVariant === "full_cart" && methode === "beide" && pickSectie) {
|
|
75
|
+
const deelOrder = deelkarVoorbeeldOrder();
|
|
76
|
+
segmenten.push({
|
|
77
|
+
key: "deelkar-voorbeeldpagina",
|
|
78
|
+
breakBefore: true,
|
|
79
|
+
pageLabel: "Deelkar",
|
|
80
|
+
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." })] })] })),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
41
83
|
const voet = totalenSectie && (totalenElkePagina || toonPaginanummer)
|
|
42
84
|
? (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
85
|
: undefined;
|
|
44
|
-
return (_jsx(PaginaDocument, { breedteMm: breedteMm, hoogteMm: hoogteMm, leeg: "Nog geen zichtbare secties.", voet: voet, items: segmenten.map((seg) => ({
|
|
86
|
+
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
87
|
id: seg.key,
|
|
46
88
|
node: seg.node,
|
|
47
89
|
breakBefore: seg.breakBefore,
|
|
90
|
+
pageLabel: seg.pageLabel ?? paginaLabel,
|
|
48
91
|
})) }));
|
|
49
92
|
}
|
|
50
93
|
/** Bouwt de segmenten voor de karrensectie, inclusief pagina-afbrekingen. */
|
|
@@ -68,6 +111,7 @@ function karSegmenten(s, order, zoek) {
|
|
|
68
111
|
return [
|
|
69
112
|
{
|
|
70
113
|
key: s.id,
|
|
114
|
+
pageLabel: "Hele kar",
|
|
71
115
|
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
116
|
},
|
|
73
117
|
];
|
|
@@ -82,6 +126,7 @@ function karSegmenten(s, order, zoek) {
|
|
|
82
126
|
segmenten.push({
|
|
83
127
|
key: `${s.id}-${kar.karnummer}-${lg.laag.laagnummer}`,
|
|
84
128
|
breakBefore: i > 0 || j > 0,
|
|
129
|
+
pageLabel: "Hele kar",
|
|
85
130
|
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
131
|
});
|
|
87
132
|
});
|
|
@@ -90,6 +135,7 @@ function karSegmenten(s, order, zoek) {
|
|
|
90
135
|
segmenten.push({
|
|
91
136
|
key: `${s.id}-${kar.karnummer}`,
|
|
92
137
|
breakBefore: i > 0 && nieuwePaginaPerKar,
|
|
138
|
+
pageLabel: "Hele kar",
|
|
93
139
|
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
140
|
});
|
|
95
141
|
});
|
|
@@ -100,7 +146,7 @@ function BundelMelding({ tekst }) {
|
|
|
100
146
|
return (_jsx("div", { className: "rounded border border-dashed px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide", children: tekst }));
|
|
101
147
|
}
|
|
102
148
|
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}` }))] }));
|
|
149
|
+
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}` })), kar.barcode ? (_jsxs("div", { className: "space-y-1 pt-2", 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] }));
|
|
104
150
|
}
|
|
105
151
|
/** Losse weergave van één blok — gebruikt door de blokontwerper. */
|
|
106
152
|
export function PakbonSectiePreview({ sectie, config, breedteMm, }) {
|
|
@@ -169,7 +215,7 @@ function SectieView({ sectie, order, zoek, }) {
|
|
|
169
215
|
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
216
|
}
|
|
171
217
|
case "pickmethode":
|
|
172
|
-
if (optS(s, "methode", "kar")
|
|
218
|
+
if (optS(s, "methode", "kar") === "kar")
|
|
173
219
|
return null;
|
|
174
220
|
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
221
|
case "karren":
|
|
@@ -199,10 +245,7 @@ function SectieView({ sectie, order, zoek, }) {
|
|
|
199
245
|
case "qrcode":
|
|
200
246
|
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
247
|
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) })] }));
|
|
248
|
+
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
249
|
case "afbeelding": {
|
|
207
250
|
const url = String(opt(s, "url", ""));
|
|
208
251
|
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" }));
|
|
@@ -256,7 +299,7 @@ function KarKop({ sectie, kar, velden, bundelTekst = "" }) {
|
|
|
256
299
|
!velden.includes("barcode") &&
|
|
257
300
|
!velden.includes("qrcode"))
|
|
258
301
|
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") &&
|
|
302
|
+
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
303
|
}
|
|
261
304
|
function LagenView({ sectie, lagen, productSectie, fustSectie, }) {
|
|
262
305
|
const modus = optS(sectie, "modus", "apart");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type PakbonConfig, type PakbonSectie } from "../lib/pakbonBuilder.js";
|
|
1
|
+
import { type PakbonConfig, type PakbonSectie, type PickMethode } from "../lib/pakbonBuilder.js";
|
|
2
2
|
/** Beheer van de secties waaruit de pakbon is opgebouwd. */
|
|
3
3
|
export declare function PakbonSectiesPanel({ config, onChange, }: {
|
|
4
4
|
config: PakbonConfig;
|
|
@@ -8,7 +8,7 @@ export declare function PakbonSectiesPanel({ config, onChange, }: {
|
|
|
8
8
|
export declare function PakbonSectieEditor({ sectie, onChange, methode, }: {
|
|
9
9
|
sectie: PakbonSectie;
|
|
10
10
|
onChange: (patch: Partial<PakbonSectie>) => void;
|
|
11
|
-
methode?:
|
|
11
|
+
methode?: PickMethode;
|
|
12
12
|
}): import("react").JSX.Element;
|
|
13
13
|
/** Kaderinstellingen (breedte, uitlijning, marges, opmaak) van één blok. */
|
|
14
14
|
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,EAEjB,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAE9B,4DAA4D;AAC5D,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;CACrC,+BA6KA;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"}
|
|
@@ -93,7 +93,12 @@ export function PakbonSectieEditor({ sectie, onChange, methode = "kar", }) {
|
|
|
93
93
|
const s = sectie;
|
|
94
94
|
const def = sectieDef(s.type);
|
|
95
95
|
const bundelAan = s.type === "karren" && (s.opties?.bundel_identiek ?? true);
|
|
96
|
-
|
|
96
|
+
// Instellingen van de fustverzamellijst gelden alleen bij picken per fust
|
|
97
|
+
// of bij de gecombineerde methode.
|
|
98
|
+
const verzamellijstUit = s.type === "pickmethode" && methode === "kar";
|
|
99
|
+
const aangepasteOpties = def.opties
|
|
100
|
+
.filter((o) => !(verzamellijstUit && o.key !== "methode"))
|
|
101
|
+
.map((o) => {
|
|
97
102
|
if (s.type === "karren" && o.key === "velden" && bundelAan) {
|
|
98
103
|
return {
|
|
99
104
|
...o,
|
|
@@ -115,7 +120,7 @@ export function PakbonSectieEditor({ sectie, onChange, methode = "kar", }) {
|
|
|
115
120
|
logoId: logo?.id ?? null,
|
|
116
121
|
logoNaam: logo?.naam ?? null,
|
|
117
122
|
},
|
|
118
|
-
}) })), aangepasteOpties.map((o) => {
|
|
123
|
+
}) })), 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) => {
|
|
119
124
|
const isVelden = o.key === "velden";
|
|
120
125
|
const basisWaarde = s.opties?.[o.key] ?? o.standaard;
|
|
121
126
|
const waarde = isVelden && bundelAan
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PdfMapAutoSaver.d.ts","sourceRoot":"","sources":["../../src/components/PdfMapAutoSaver.tsx"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,eAAe,SAM9B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { startPdfMapService } from "../lib/pdfJobSaver.js";
|
|
3
|
+
/**
|
|
4
|
+
* Schrijft voltooide opdrachten van de virtuele PDF-printer naar de map die
|
|
5
|
+
* in deze browser op deze computer is gekozen. Dit component rendert niets.
|
|
6
|
+
*/
|
|
7
|
+
export function PdfMapAutoSaver() {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
startPdfMapService();
|
|
10
|
+
}, []);
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Root } from "react-dom/client";
|
|
2
|
+
declare global {
|
|
3
|
+
interface Window {
|
|
4
|
+
__layoutMakerPdfBannerRoot?: Root;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Monteert de mapmelding één keer boven de volledige shell. Zo is de actie ook
|
|
9
|
+
* zichtbaar in modules die alleen de print-API gebruiken, zoals Pickstation.
|
|
10
|
+
*/
|
|
11
|
+
export declare function startPdfMapGlobaleBanner(): void;
|
|
12
|
+
//# sourceMappingURL=PdfMapGlobaleBanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PdfMapGlobaleBanner.d.ts","sourceRoot":"","sources":["../../src/components/PdfMapGlobaleBanner.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAKzD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,0BAA0B,CAAC,EAAE,IAAI,CAAC;KACnC;CACF;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAoB/C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { PdfMapToestemmingBanner } from "./PdfMapToestemmingBanner.js";
|
|
4
|
+
const CONTAINER_ID = "layout-maker-pdf-map-banner";
|
|
5
|
+
/**
|
|
6
|
+
* Monteert de mapmelding één keer boven de volledige shell. Zo is de actie ook
|
|
7
|
+
* zichtbaar in modules die alleen de print-API gebruiken, zoals Pickstation.
|
|
8
|
+
*/
|
|
9
|
+
export function startPdfMapGlobaleBanner() {
|
|
10
|
+
if (typeof window === "undefined" || window.__layoutMakerPdfBannerRoot)
|
|
11
|
+
return;
|
|
12
|
+
const monteer = () => {
|
|
13
|
+
if (window.__layoutMakerPdfBannerRoot)
|
|
14
|
+
return;
|
|
15
|
+
const bestaand = document.getElementById(CONTAINER_ID);
|
|
16
|
+
const container = bestaand ?? document.createElement("div");
|
|
17
|
+
container.id = CONTAINER_ID;
|
|
18
|
+
if (!bestaand)
|
|
19
|
+
document.body.appendChild(container);
|
|
20
|
+
const root = createRoot(container);
|
|
21
|
+
window.__layoutMakerPdfBannerRoot = root;
|
|
22
|
+
root.render(_jsx(PdfMapToestemmingBanner, { alleenActieNodig: true, zwevend: true }));
|
|
23
|
+
};
|
|
24
|
+
if (document.readyState === "loading") {
|
|
25
|
+
document.addEventListener("DOMContentLoaded", monteer, { once: true });
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
monteer();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type PdfMapToestemmingBannerProps = {
|
|
2
|
+
alleenActieNodig?: boolean;
|
|
3
|
+
zwevend?: boolean;
|
|
4
|
+
};
|
|
5
|
+
export declare function PdfMapToestemmingBanner({ alleenActieNodig, zwevend, }?: PdfMapToestemmingBannerProps): import("react").JSX.Element | null;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=PdfMapToestemmingBanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PdfMapToestemmingBanner.d.ts","sourceRoot":"","sources":["../../src/components/PdfMapToestemmingBanner.tsx"],"names":[],"mappings":"AAuBA,KAAK,4BAA4B,GAAG;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,EACtC,gBAAwB,EACxB,OAAe,GAChB,GAAE,4BAAiC,sCAwKnC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/PdfMapToestemmingBanner.tsx — permanente, zichtbare controle om
|
|
4
|
+
// de maptoestemming voor de virtuele "Opslaan als PDF"-printer te beheren.
|
|
5
|
+
// Getoond op de Printplek-detailpagina en de Printwachtrij, zodat een gebruiker
|
|
6
|
+
// altijd proactief toestemming kan (her)geven zonder op een toast te wachten.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
import { useCallback, useEffect, useState } from "react";
|
|
9
|
+
import { Button, toast } from "@flowselections/core";
|
|
10
|
+
import { FolderCheck, FolderOpen, ShieldAlert, ShieldCheck } from "lucide-react";
|
|
11
|
+
import { usePrinters } from "../lib/useDocumentData.js";
|
|
12
|
+
import { zorgVoorPdfPrinter } from "../lib/pdfPrinter.js";
|
|
13
|
+
import { draaitInIframe, herstelPdfMapToestemming, kiesPdfMap, mapKiezenMogelijk, openInEigenTabblad, pdfMapNaam, pdfMapToestemming, } from "../lib/pdfMap.js";
|
|
14
|
+
export function PdfMapToestemmingBanner({ alleenActieNodig = false, zwevend = false, } = {}) {
|
|
15
|
+
const { printers, reload } = usePrinters();
|
|
16
|
+
const pdfPrinter = printers.find((p) => p.afdrukmethode === "pdf");
|
|
17
|
+
const [naam, setNaam] = useState(null);
|
|
18
|
+
const [toestand, setToestand] = useState("laden");
|
|
19
|
+
// Zorg dat de virtuele PDF-printer bestaat, ook als de gebruiker nog geen
|
|
20
|
+
// wizard heeft doorlopen. Daarna herladen zodat de banner direct zichtbaar is.
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (pdfPrinter)
|
|
23
|
+
return;
|
|
24
|
+
let actief = true;
|
|
25
|
+
void (async () => {
|
|
26
|
+
try {
|
|
27
|
+
await zorgVoorPdfPrinter();
|
|
28
|
+
if (actief)
|
|
29
|
+
await reload(true);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// RLS of netwerkfout — stil negeren, banner blijft verborgen.
|
|
33
|
+
}
|
|
34
|
+
})();
|
|
35
|
+
return () => {
|
|
36
|
+
actief = false;
|
|
37
|
+
};
|
|
38
|
+
}, [pdfPrinter, reload]);
|
|
39
|
+
const laad = useCallback(async () => {
|
|
40
|
+
if (!pdfPrinter) {
|
|
41
|
+
setNaam(null);
|
|
42
|
+
setToestand("ontbreekt");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
setNaam(await pdfMapNaam(pdfPrinter.id));
|
|
46
|
+
setToestand(await pdfMapToestemming(pdfPrinter.id));
|
|
47
|
+
}, [pdfPrinter]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
void laad();
|
|
50
|
+
}, [laad]);
|
|
51
|
+
// Herverfris na focus zodat een net verleende toestemming meteen zichtbaar is.
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
const h = () => void laad();
|
|
54
|
+
window.addEventListener("focus", h);
|
|
55
|
+
document.addEventListener("visibilitychange", h);
|
|
56
|
+
return () => {
|
|
57
|
+
window.removeEventListener("focus", h);
|
|
58
|
+
document.removeEventListener("visibilitychange", h);
|
|
59
|
+
};
|
|
60
|
+
}, [laad]);
|
|
61
|
+
if (!pdfPrinter)
|
|
62
|
+
return null;
|
|
63
|
+
// Banner blijft altijd zichtbaar zolang er een PDF-printer is, zodat de
|
|
64
|
+
// maptoestemming ook proactief te vernieuwen is (groen = in orde).
|
|
65
|
+
const inOrde = toestand === "granted" && !!naam;
|
|
66
|
+
if (alleenActieNodig && (toestand === "laden" || inOrde))
|
|
67
|
+
return null;
|
|
68
|
+
const inIframe = draaitInIframe();
|
|
69
|
+
const ondersteund = mapKiezenMogelijk();
|
|
70
|
+
const geefToestemming = async () => {
|
|
71
|
+
if (!pdfPrinter)
|
|
72
|
+
return;
|
|
73
|
+
const resultaat = await herstelPdfMapToestemming(pdfPrinter.id);
|
|
74
|
+
if (resultaat === "granted") {
|
|
75
|
+
toast.success("Maptoestemming verleend", {
|
|
76
|
+
description: "Gereedstaande PDF's worden nu naar de map opgeslagen.",
|
|
77
|
+
});
|
|
78
|
+
await laad();
|
|
79
|
+
}
|
|
80
|
+
else if (resultaat === "ontbreekt") {
|
|
81
|
+
// Nog geen map gekozen — open de verkenner.
|
|
82
|
+
await kiesNieuweMap();
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
toast.error("Maptoestemming is niet verleend");
|
|
86
|
+
await laad();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const kiesNieuweMap = async () => {
|
|
90
|
+
if (!pdfPrinter)
|
|
91
|
+
return;
|
|
92
|
+
if (inIframe) {
|
|
93
|
+
toast.error("Map kiezen werkt niet in een iframe", {
|
|
94
|
+
description: "Open de app in een eigen tabblad om de mappenverkenner te gebruiken.",
|
|
95
|
+
action: {
|
|
96
|
+
label: "Open in eigen tabblad",
|
|
97
|
+
onClick: openInEigenTabblad,
|
|
98
|
+
},
|
|
99
|
+
duration: 15000,
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const uitkomst = await kiesPdfMap(pdfPrinter.id);
|
|
104
|
+
if (uitkomst.status === "gekozen") {
|
|
105
|
+
toast.success("Map gekozen", { description: `PDF's worden opgeslagen in “${uitkomst.naam}”.` });
|
|
106
|
+
await laad();
|
|
107
|
+
}
|
|
108
|
+
else if (uitkomst.status === "niet-ondersteund") {
|
|
109
|
+
toast.error("Deze browser ondersteunt geen mapkeuze", {
|
|
110
|
+
description: "Gebruik Chrome, Edge of Safari op desktop.",
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else if (uitkomst.status === "iframe-geblokkeerd") {
|
|
114
|
+
toast.error("Map kiezen werkt niet in een iframe", {
|
|
115
|
+
description: "Open de app in een eigen tabblad.",
|
|
116
|
+
action: { label: "Open in eigen tabblad", onClick: openInEigenTabblad },
|
|
117
|
+
duration: 15000,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else if (uitkomst.status === "fout") {
|
|
121
|
+
toast.error("Map kiezen is mislukt", { description: uitkomst.melding });
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
const icoon = toestand === "granted"
|
|
125
|
+
? ShieldCheck
|
|
126
|
+
: toestand === "denied"
|
|
127
|
+
? ShieldAlert
|
|
128
|
+
: FolderOpen;
|
|
129
|
+
const Icoon = icoon;
|
|
130
|
+
return (_jsxs("div", { role: "status", "aria-live": "polite", className: `${inOrde
|
|
131
|
+
? "border-emerald-300/60 bg-emerald-50 dark:border-emerald-700/60 dark:bg-emerald-950/30"
|
|
132
|
+
: "border-amber-300/60 bg-amber-50 dark:border-amber-700/60 dark:bg-amber-950/30"} ${zwevend
|
|
133
|
+
? "fixed inset-x-4 top-4 z-[100] mx-auto max-w-4xl shadow-lg"
|
|
134
|
+
: ""} flex flex-wrap items-center justify-between gap-3 rounded-lg border p-3`, children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Icoon, { className: inOrde
|
|
135
|
+
? "h-4 w-4 text-emerald-600 dark:text-emerald-400"
|
|
136
|
+
: "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
|
+
? `Map “${naam}” — toestemming ${toestand === "granted" ? "verleend" : "vereist vernieuwen"}`
|
|
138
|
+
: "Nog geen map gekozen op deze computer", !ondersteund ? " (browser ondersteunt geen mapkeuze)" : ""] })] }), _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"] })] })] }));
|
|
139
|
+
}
|
|
@@ -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":"AAoFA,wBAAgB,cAAc,gCAsT7B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useRef, useState } from "react";
|
|
3
3
|
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, toast, } from "@flowselections/core";
|
|
4
|
-
import { RotateCcw, Search, XCircle } from "lucide-react";
|
|
4
|
+
import { FileDown, RotateCcw, Search, XCircle } from "lucide-react";
|
|
5
5
|
import { bijgewerktTekst, useAutoRefresh } from "../lib/useAutoRefresh.js";
|
|
6
6
|
import { PrintStatusBanner } from "./PrintStatusBanner.js";
|
|
7
7
|
import { maakPrintJob, updateJobStatus, useLayouts, usePrinters, usePrintJobs, usePrintPlekNamen, } from "../lib/useDocumentData.js";
|
|
@@ -9,6 +9,10 @@ import { printStatus } from "../lib/printService.functions.js";
|
|
|
9
9
|
import { vraagWachtrijRonde } from "../lib/queueTickClient.js";
|
|
10
10
|
import { documentTypeLabel } from "../lib/documentTypes.js";
|
|
11
11
|
import { jobPlekLabel } from "../lib/printQueue.js";
|
|
12
|
+
import { bewaarInPdfMap } from "../lib/pdfMap.js";
|
|
13
|
+
import { PdfMapAutoSaver } from "./PdfMapAutoSaver.js";
|
|
14
|
+
import { PdfMapToestemmingBanner } from "./PdfMapToestemmingBanner.js";
|
|
15
|
+
import { supabase } from "../lib/supabaseClient.js";
|
|
12
16
|
const STATUS_VARIANT = {
|
|
13
17
|
wachtend: "outline",
|
|
14
18
|
bezig: "secondary",
|
|
@@ -23,6 +27,14 @@ const BRON_LABEL = {
|
|
|
23
27
|
render_html: "meegestuurde opmaak",
|
|
24
28
|
klantlayout: "klantlayout",
|
|
25
29
|
};
|
|
30
|
+
const LOKALE_PDF_LABEL = {
|
|
31
|
+
gereed: "PDF gereed — lokaal opslaan",
|
|
32
|
+
opgeslagen: "opgeslagen op Mac",
|
|
33
|
+
map_ontbreekt: "PDF-map ontbreekt",
|
|
34
|
+
toestemming_nodig: "maptoestemming nodig",
|
|
35
|
+
schrijffout: "opslaan mislukt",
|
|
36
|
+
timeout: "wachten op PDF verlopen",
|
|
37
|
+
};
|
|
26
38
|
/**
|
|
27
39
|
* Heeft deze opdracht een kenmerk waarmee hij van andere orders te
|
|
28
40
|
* onderscheiden is? Zo niet, dan valt de dubbelbescherming terug op het
|
|
@@ -103,11 +115,38 @@ export function PrintQueuePage() {
|
|
|
103
115
|
await reload(true);
|
|
104
116
|
};
|
|
105
117
|
const bijgewerkt = useAutoRefresh(ronde, lopende ? 5000 : 20000);
|
|
106
|
-
return (_jsxs("main", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-end justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold", children: "Printwachtrij" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Volg printopdrachten, herstart mislukte prints en print documenten opnieuw." })] }), _jsx("span", { className: "text-muted-foreground text-xs", children: bijgewerktTekst(bijgewerkt) })] }), _jsx(PrintStatusBanner, { fout: tickFout }), _jsx("div", { className: "grid gap-4 md:grid-cols-4", children: ["wachtend", "bezig", "voltooid", "mislukt"].map((s) => (_jsx(Card, { children: _jsxs(CardHeader, { className: "pb-2", children: [_jsx(CardDescription, { className: "capitalize", children: s }), _jsx(CardTitle, { className: "text-2xl", children: tellingen[s] ?? 0 })] }) }, s))) }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Opdrachten" }), _jsx(CardDescription, { children: loading ? "Laden…" : `${gefilterd.length} opdrachten` })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-3 md:grid-cols-4", children: [_jsxs("div", { className: "relative md:col-span-2", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "pl-9", placeholder: "Zoek op document of gebruiker", value: zoek, onChange: (e) => setZoek(e.target.value) })] }), _jsxs(Select, { value: status, onValueChange: setStatus, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle statussen" }), ["wachtend", "bezig", "voltooid", "mislukt", "geannuleerd"].map((s) => (_jsx(SelectItem, { value: s, children: s }, s)))] })] }), _jsxs(Select, { value: plekFilter, onValueChange: setPlekFilter, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle printplekken" }), plekOpties.map((p) => (_jsx(SelectItem, { value: p, children: p }, p))), _jsx(SelectItem, { value: "\u2014", children: "Zonder printplek" })] })] })] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Document" }), _jsx(TableHead, { children: "Printplek" }), _jsx(TableHead, { children: "Layout (aangeleverd \u2192 gebruikt)" }), _jsx(TableHead, { children: "Printer" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { children: "Tijdstip" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsxs(TableBody, { children: [gefilterd.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 7, className: "py-10 text-center text-sm text-muted-foreground", children: "Geen printopdrachten." }) })), gefilterd.map((j) => (_jsxs(TableRow, { children: [_jsxs(TableCell, { children: [_jsx("span", { className: "font-medium", children: j.documentnaam ?? documentTypeLabel(j.documenttype) }), j.is_herprint && (_jsx(Badge, { variant: "outline", className: "ml-2", children: "herprint" })), !heeftOrderKenmerk(j) && (_jsx(Badge, { variant: "outline", className: "ml-2 text-amber-600", children: "geen orderkenmerk" })), j.foutmelding && (_jsx("span", { className: "block text-xs text-destructive", children: j.foutmelding }))] }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: plekPerJob.get(j.id) || "—" }), _jsxs(TableCell, { className: "text-sm text-muted-foreground", children: [_jsx("span", { title: "Aangeleverd door de module", children: j.layout_id ? layoutNaam.get(j.layout_id) ?? "Onbekende layout" : "geen" }), _jsxs("span", { className: "block text-xs", children: ["\u2192", " ", _jsx("span", { title: "Layout die de wachtrij gebruikte", children: j.gebruikte_layout_id
|
|
118
|
+
return (_jsxs("main", { className: "space-y-6 p-6", children: [_jsx(PdfMapAutoSaver, {}), _jsx(PdfMapToestemmingBanner, {}), _jsxs("div", { className: "flex flex-wrap items-end justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold", children: "Printwachtrij" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Volg printopdrachten, herstart mislukte prints en print documenten opnieuw." })] }), _jsx("span", { className: "text-muted-foreground text-xs", children: bijgewerktTekst(bijgewerkt) })] }), _jsx(PrintStatusBanner, { fout: tickFout }), _jsx("div", { className: "grid gap-4 md:grid-cols-4", children: ["wachtend", "bezig", "voltooid", "mislukt"].map((s) => (_jsx(Card, { children: _jsxs(CardHeader, { className: "pb-2", children: [_jsx(CardDescription, { className: "capitalize", children: s }), _jsx(CardTitle, { className: "text-2xl", children: tellingen[s] ?? 0 })] }) }, s))) }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Opdrachten" }), _jsx(CardDescription, { children: loading ? "Laden…" : `${gefilterd.length} opdrachten` })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-3 md:grid-cols-4", children: [_jsxs("div", { className: "relative md:col-span-2", children: [_jsx(Search, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { className: "pl-9", placeholder: "Zoek op document of gebruiker", value: zoek, onChange: (e) => setZoek(e.target.value) })] }), _jsxs(Select, { value: status, onValueChange: setStatus, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle statussen" }), ["wachtend", "bezig", "voltooid", "mislukt", "geannuleerd"].map((s) => (_jsx(SelectItem, { value: s, children: s }, s)))] })] }), _jsxs(Select, { value: plekFilter, onValueChange: setPlekFilter, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle printplekken" }), plekOpties.map((p) => (_jsx(SelectItem, { value: p, children: p }, p))), _jsx(SelectItem, { value: "\u2014", children: "Zonder printplek" })] })] })] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Document" }), _jsx(TableHead, { children: "Printplek" }), _jsx(TableHead, { children: "Layout (aangeleverd \u2192 gebruikt)" }), _jsx(TableHead, { children: "Printer" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { children: "Tijdstip" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsxs(TableBody, { children: [gefilterd.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 7, className: "py-10 text-center text-sm text-muted-foreground", children: "Geen printopdrachten." }) })), gefilterd.map((j) => (_jsxs(TableRow, { children: [_jsxs(TableCell, { children: [_jsx("span", { className: "font-medium", children: j.documentnaam ?? documentTypeLabel(j.documenttype) }), j.is_herprint && (_jsx(Badge, { variant: "outline", className: "ml-2", children: "herprint" })), !heeftOrderKenmerk(j) && (_jsx(Badge, { variant: "outline", className: "ml-2 text-amber-600", children: "geen orderkenmerk" })), j.foutmelding && (_jsx("span", { className: "block text-xs text-destructive", children: j.foutmelding })), j.lokale_pdf_fout && (_jsx("span", { className: "block text-xs text-destructive", children: j.lokale_pdf_fout }))] }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: plekPerJob.get(j.id) || "—" }), _jsxs(TableCell, { className: "text-sm text-muted-foreground", children: [_jsx("span", { title: "Aangeleverd door de module", children: j.layout_id ? layoutNaam.get(j.layout_id) ?? "Onbekende layout" : "geen" }), _jsxs("span", { className: "block text-xs", children: ["\u2192", " ", _jsx("span", { title: "Layout die de wachtrij gebruikte", children: j.gebruikte_layout_id
|
|
107
119
|
? layoutNaam.get(j.gebruikte_layout_id) ?? "Onbekende layout"
|
|
108
120
|
: j.gebruikte_bron
|
|
109
121
|
? "geen layout"
|
|
110
|
-
: "nog niet verwerkt" }), j.gebruikte_bron && (_jsx(Badge, { variant: "outline", className: "ml-2", children: BRON_LABEL[j.gebruikte_bron] ?? j.gebruikte_bron }))] })] }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: j.printer_id ? printerNaam.get(j.printer_id) ?? "—" : "—" }), _jsx(TableCell, { children: _jsx(Badge, { variant: STATUS_VARIANT[j.status] ?? "outline", children: j.status }) }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: new Date(j.created_at).toLocaleString("nl-NL") }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsxs(Button, { variant: "ghost", size: "sm", onClick: async () => {
|
|
122
|
+
: "nog niet verwerkt" }), j.gebruikte_bron && (_jsx(Badge, { variant: "outline", className: "ml-2", children: BRON_LABEL[j.gebruikte_bron] ?? j.gebruikte_bron }))] })] }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: j.printer_id ? printerNaam.get(j.printer_id) ?? "—" : "—" }), _jsx(TableCell, { children: _jsx(Badge, { variant: STATUS_VARIANT[j.status] ?? "outline", children: (j.lokale_pdf_status && LOKALE_PDF_LABEL[j.lokale_pdf_status]) ?? j.status }) }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: new Date(j.created_at).toLocaleString("nl-NL") }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [j.resultaat_pdf_base64 && (_jsxs(Button, { variant: "ghost", size: "sm", title: "Bewaar de opgemaakte PDF", onClick: async () => {
|
|
123
|
+
const bytes = Uint8Array.from(atob(j.resultaat_pdf_base64), (c) => c.charCodeAt(0));
|
|
124
|
+
const blob = new Blob([bytes], { type: "application/pdf" });
|
|
125
|
+
const bestandsnaam = `${j.documentnaam ?? "document"}.pdf`;
|
|
126
|
+
const inMap = j.printer_id
|
|
127
|
+
? await bewaarInPdfMap(j.printer_id, bestandsnaam, blob)
|
|
128
|
+
: false;
|
|
129
|
+
if (inMap) {
|
|
130
|
+
await supabase
|
|
131
|
+
.from("print_jobs")
|
|
132
|
+
.update({
|
|
133
|
+
status: "voltooid",
|
|
134
|
+
lokale_pdf_status: "opgeslagen",
|
|
135
|
+
lokaal_opgeslagen_op: new Date().toISOString(),
|
|
136
|
+
lokale_pdf_fout: null,
|
|
137
|
+
})
|
|
138
|
+
.eq("id", j.id);
|
|
139
|
+
toast.success("PDF opgeslagen in de ingestelde map");
|
|
140
|
+
void reload(true);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const url = URL.createObjectURL(blob);
|
|
144
|
+
const a = document.createElement("a");
|
|
145
|
+
a.href = url;
|
|
146
|
+
a.download = bestandsnaam;
|
|
147
|
+
a.click();
|
|
148
|
+
URL.revokeObjectURL(url);
|
|
149
|
+
}, children: [_jsx(FileDown, { className: "mr-2 h-4 w-4" }), " PDF"] })), _jsxs(Button, { variant: "ghost", size: "sm", onClick: async () => {
|
|
111
150
|
if (!j.layout_id)
|
|
112
151
|
return;
|
|
113
152
|
try {
|