@flowselections/layout-maker 1.69.19 → 1.69.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist-lib/components/FormaatOrientatieBar.d.ts.map +1 -1
  2. package/dist-lib/components/FormaatOrientatieBar.js +10 -7
  3. package/dist-lib/components/GeladenEtiketTab.d.ts.map +1 -1
  4. package/dist-lib/components/GeladenEtiketTab.js +3 -1
  5. package/dist-lib/components/InstelOverzichtKaart.d.ts +12 -0
  6. package/dist-lib/components/InstelOverzichtKaart.d.ts.map +1 -0
  7. package/dist-lib/components/InstelOverzichtKaart.js +78 -0
  8. package/dist-lib/components/KlaarOmTePrintenBlok.d.ts.map +1 -1
  9. package/dist-lib/components/KlaarOmTePrintenBlok.js +2 -1
  10. package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
  11. package/dist-lib/components/LayoutsPage.js +29 -5
  12. package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
  13. package/dist-lib/components/PakbonBuilderPage.js +9 -1
  14. package/dist-lib/components/PrintersPage.d.ts.map +1 -1
  15. package/dist-lib/components/PrintersPage.js +3 -2
  16. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  17. package/dist-lib/components/PrintplekDetailPage.js +5 -9
  18. package/dist-lib/components/RolKeuze.d.ts +9 -0
  19. package/dist-lib/components/RolKeuze.d.ts.map +1 -0
  20. package/dist-lib/components/RolKeuze.js +91 -0
  21. package/dist-lib/components/StickerOntwerpPage.d.ts +4 -0
  22. package/dist-lib/components/StickerOntwerpPage.d.ts.map +1 -0
  23. package/dist-lib/components/StickerOntwerpPage.js +77 -0
  24. package/dist-lib/components/SysteemLayoutMelding.d.ts +1 -1
  25. package/dist-lib/components/SysteemLayoutMelding.d.ts.map +1 -1
  26. package/dist-lib/components/WerkplekConfiguratiePage.d.ts.map +1 -1
  27. package/dist-lib/components/WerkplekConfiguratiePage.js +15 -7
  28. package/dist-lib/index.d.ts +5 -0
  29. package/dist-lib/index.d.ts.map +1 -1
  30. package/dist-lib/index.js +5 -0
  31. package/dist-lib/integrations/supabase/types.d.ts +621 -120
  32. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  33. package/dist-lib/lib/directPrint.d.ts.map +1 -1
  34. package/dist-lib/lib/directPrint.js +19 -0
  35. package/dist-lib/lib/etiketRollen.d.ts +41 -0
  36. package/dist-lib/lib/etiketRollen.d.ts.map +1 -0
  37. package/dist-lib/lib/etiketRollen.js +64 -0
  38. package/dist-lib/lib/formaatWeergave.d.ts +24 -0
  39. package/dist-lib/lib/formaatWeergave.d.ts.map +1 -0
  40. package/dist-lib/lib/formaatWeergave.js +24 -0
  41. package/dist-lib/lib/instelOverzicht.d.ts +45 -0
  42. package/dist-lib/lib/instelOverzicht.d.ts.map +1 -0
  43. package/dist-lib/lib/instelOverzicht.js +106 -0
  44. package/dist-lib/lib/ontwerpKeuze.d.ts +80 -0
  45. package/dist-lib/lib/ontwerpKeuze.d.ts.map +1 -0
  46. package/dist-lib/lib/ontwerpKeuze.js +193 -0
  47. package/dist-lib/lib/pakbonBuilder.d.ts +6 -0
  48. package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
  49. package/dist-lib/lib/pakbonBuilder.js +15 -0
  50. package/dist-lib/lib/pakbonContent.d.ts.map +1 -1
  51. package/dist-lib/lib/pakbonContent.js +2 -1
  52. package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
  53. package/dist-lib/lib/pakbonHtml.js +3 -1
  54. package/dist-lib/lib/pakbonPresentation.d.ts.map +1 -1
  55. package/dist-lib/lib/pakbonPresentation.js +3 -0
  56. package/dist-lib/lib/printQueue.server.d.ts +4 -0
  57. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  58. package/dist-lib/lib/printQueue.server.js +274 -5
  59. package/dist-lib/lib/stickerOntwerp.d.ts +67 -0
  60. package/dist-lib/lib/stickerOntwerp.d.ts.map +1 -0
  61. package/dist-lib/lib/stickerOntwerp.js +109 -0
  62. package/dist-lib/lib/stickerRoute.d.ts +3 -0
  63. package/dist-lib/lib/stickerRoute.d.ts.map +1 -0
  64. package/dist-lib/lib/stickerRoute.js +5 -0
  65. package/dist-lib/lib/stickerUitwijk.d.ts +5 -0
  66. package/dist-lib/lib/stickerUitwijk.d.ts.map +1 -1
  67. package/dist-lib/lib/stickerUitwijk.js +12 -1
  68. package/dist-lib/lib/testpagina.d.ts +7 -1
  69. package/dist-lib/lib/testpagina.d.ts.map +1 -1
  70. package/dist-lib/lib/testpagina.js +39 -5
  71. package/dist-lib/lib/useNetwerkPrinters.d.ts +1 -0
  72. package/dist-lib/lib/useNetwerkPrinters.d.ts.map +1 -1
  73. package/dist-lib/lib/useNetwerkPrinters.js +11 -3
  74. package/dist-lib/lib/versie.generated.d.ts +1 -1
  75. package/dist-lib/lib/versie.generated.js +1 -1
  76. package/dist-lib/lib/voorbeeldPrint.d.ts.map +1 -1
  77. package/dist-lib/lib/voorbeeldPrint.js +53 -3
  78. package/dist-lib/lib/werkplekken.d.ts +5 -1
  79. package/dist-lib/lib/werkplekken.d.ts.map +1 -1
  80. package/dist-lib/lib/werkplekken.js +1 -1
  81. package/package.json +6 -1
  82. package/sql/print-schema.sql +320 -162
  83. package/sql/print-schema.verslag.md +5 -2
@@ -1 +1 @@
1
- {"version":3,"file":"FormaatOrientatieBar.d.ts","sourceRoot":"","sources":["../../src/components/FormaatOrientatieBar.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAIxE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,QAAQ,EACR,WAAmB,GACpB,EAAE;IACD,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,+BAiHA"}
1
+ {"version":3,"file":"FormaatOrientatieBar.d.ts","sourceRoot":"","sources":["../../src/components/FormaatOrientatieBar.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKxE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,MAAM,EACN,QAAQ,EACR,WAAmB,GACpB,EAAE;IACD,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAChD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,+BAiHA"}
@@ -5,6 +5,7 @@ import { RectangleHorizontal, RectangleVertical } from "lucide-react";
5
5
  import { PAPIERFORMATEN } from "../lib/documentTypes.js";
6
6
  import { updateLayout } from "../lib/useDocumentData.js";
7
7
  import { foutTekstVan } from "../lib/layoutOpslaan.js";
8
+ import { afdrukMaat, maatTekst, opslagVoorAfdrukMaat } from "../lib/formaatWeergave.js";
8
9
  /**
9
10
  * Formaat- en oriëntatiekeuze die in elke ontwerp-editor beschikbaar is.
10
11
  * Wijzigingen worden direct opgeslagen en lokaal doorgegeven aan de preview.
@@ -41,13 +42,15 @@ export function FormaatOrientatieBar({ layout, onChange, vergrendeld = false, })
41
42
  return;
42
43
  void bewaar({ orientatie });
43
44
  };
44
- const maat = (veld, waarde) => {
45
- const n = Number(waarde);
46
- if (!Number.isFinite(n) || n <= 0)
45
+ // Vrij formaat: breedte × hoogte zoals ingevuld; de oriëntatie volgt uit de maat.
46
+ const afdruk = afdrukMaat(layout);
47
+ const [invoer, setInvoer] = useState({ b: String(afdruk.breedte_mm || ""), h: String(afdruk.hoogte_mm || "") });
48
+ const bewaarVrij = (b, h) => {
49
+ const nb = Number(b.replace(",", "."));
50
+ const nh = Number(h.replace(",", "."));
51
+ if (!(nb > 0) || !(nh > 0))
47
52
  return;
48
- void bewaar({ [veld]: n });
53
+ void bewaar(opslagVoorAfdrukMaat(nb, nh));
49
54
  };
50
- return (_jsxs("div", { className: "flex flex-wrap items-end gap-3 rounded-md border bg-muted/30 p-3", children: [_jsxs("div", { className: "w-52 space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Papierformaat" }), _jsxs(Select, { value: layout.papierformaat, onValueChange: kiesFormaat, disabled: bezig, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Kies formaat" }) }), _jsx(SelectContent, { children: PAPIERFORMATEN.map((p) => (_jsx(SelectItem, { value: p.code, children: p.label }, p.code))) })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Breedte (mm)" }), _jsx(Input, { type: "number", className: "w-28", value: layout.breedte_mm, disabled: !vrij || bezig, onChange: (e) => onChange({ breedte_mm: Number(e.target.value) }), onBlur: (e) => maat("breedte_mm", e.target.value) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Hoogte (mm)" }), _jsx(Input, { type: "number", className: "w-28", value: layout.hoogte_mm, disabled: !vrij || bezig, onChange: (e) => onChange({ hoogte_mm: Number(e.target.value) }), onBlur: (e) => maat("hoogte_mm", e.target.value) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Ori\u00EBntatie" }), _jsxs("div", { className: "flex gap-1", children: [_jsxs(Button, { type: "button", size: "sm", variant: layout.orientatie === "portrait" ? "default" : "outline", onClick: () => kiesOrientatie("portrait"), disabled: bezig, children: [_jsx(RectangleVertical, { className: "mr-2 h-4 w-4" }), " Staand"] }), _jsxs(Button, { type: "button", size: "sm", variant: layout.orientatie === "landscape" ? "default" : "outline", onClick: () => kiesOrientatie("landscape"), disabled: bezig, children: [_jsx(RectangleHorizontal, { className: "mr-2 h-4 w-4" }), " Liggend"] })] })] }), _jsxs("p", { className: "ml-auto text-xs text-muted-foreground", children: ["Afdrukgebied:", " ", layout.orientatie === "landscape"
51
- ? `${layout.hoogte_mm} × ${layout.breedte_mm}`
52
- : `${layout.breedte_mm} × ${layout.hoogte_mm}`, " ", "mm"] })] }));
55
+ return (_jsxs("div", { className: "flex flex-wrap items-end gap-3 rounded-md border bg-muted/30 p-3", children: [_jsxs("div", { className: "w-52 space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Papierformaat" }), _jsxs(Select, { value: layout.papierformaat, onValueChange: kiesFormaat, disabled: bezig, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Kies formaat" }) }), _jsx(SelectContent, { children: PAPIERFORMATEN.map((p) => (_jsx(SelectItem, { value: p.code, children: p.label }, p.code))) })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Breedte (mm)" }), _jsx(Input, { type: "number", className: "w-28", value: vrij ? invoer.b : afdruk.breedte_mm, disabled: !vrij || bezig, onChange: (e) => setInvoer((v) => ({ ...v, b: e.target.value })), onBlur: () => bewaarVrij(invoer.b, invoer.h) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Hoogte (mm)" }), _jsx(Input, { type: "number", className: "w-28", value: vrij ? invoer.h : afdruk.hoogte_mm, disabled: !vrij || bezig, onChange: (e) => setInvoer((v) => ({ ...v, h: e.target.value })), onBlur: () => bewaarVrij(invoer.b, invoer.h) })] }), !vrij ? (_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Ori\u00EBntatie" }), _jsxs("div", { className: "flex gap-1", children: [_jsxs(Button, { type: "button", size: "sm", variant: layout.orientatie === "portrait" ? "default" : "outline", onClick: () => kiesOrientatie("portrait"), disabled: bezig, children: [_jsx(RectangleVertical, { className: "mr-2 h-4 w-4" }), " Staand"] }), _jsxs(Button, { type: "button", size: "sm", variant: layout.orientatie === "landscape" ? "default" : "outline", onClick: () => kiesOrientatie("landscape"), disabled: bezig, children: [_jsx(RectangleHorizontal, { className: "mr-2 h-4 w-4" }), " Liggend"] })] })] })) : null, _jsxs("p", { className: "ml-auto text-xs text-muted-foreground", children: ["Afdrukgebied: ", maatTekst(afdruk)] })] }));
53
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"GeladenEtiketTab.d.ts","sourceRoot":"","sources":["../../src/components/GeladenEtiketTab.tsx"],"names":[],"mappings":"AASA,OAAO,EAAgE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGnH,qGAAqG;AACrG,eAAO,MAAM,6BAA6B,iDAAiD,CAAC;AAC5F,eAAO,MAAM,mBAAmB,qDAAqD,CAAC;AAEtF,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,GAAE,GAAG,CAAC,MAAM,CAAa,EAAE,KAAK,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,OAAO,CAM3H;AAED,wBAAgB,gBAAgB,gCA0C/B"}
1
+ {"version":3,"file":"GeladenEtiketTab.d.ts","sourceRoot":"","sources":["../../src/components/GeladenEtiketTab.tsx"],"names":[],"mappings":"AASA,OAAO,EAAgE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAInH,qGAAqG;AACrG,eAAO,MAAM,6BAA6B,iDAAiD,CAAC;AAC5F,eAAO,MAAM,mBAAmB,qDAAqD,CAAC;AAEtF,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,GAAE,GAAG,CAAC,MAAM,CAAa,EAAE,KAAK,GAAE,GAAG,CAAC,MAAM,CAAa,GAAG,OAAO,CAM3H;AAED,wBAAgB,gBAAgB,gCAiD/B"}
@@ -9,6 +9,7 @@ import { AlertTriangle } from "lucide-react";
9
9
  import { maatNl } from "../lib/etiketControle.js";
10
10
  import { formaatKlasse, printerTitel, usePrinterLijst, useWerkplekken } from "../lib/werkplekken.js";
11
11
  import { GeladenEtiketKeuze } from "./WerkplekkenTab.js";
12
+ import { RolKeuze, useEtiketRollen } from "./RolKeuze.js";
12
13
  /** Relatief pad binnen de Shell (leading slash, geen domein). Gelijk aan de waarde in het schema. */
13
14
  export const LAYOUTS_PRINTER_SETTINGS_PATH = "/layouts-printers/printplekken?tab=etiketten";
14
15
  export const GEEN_ETIKET_MELDING = "Stel bij je labelprinter in welk etiket erin zit";
@@ -26,9 +27,10 @@ export function isLabelprinterRij(p, labelIds = new Set(), a4Ids = new Set()) {
26
27
  export function GeladenEtiketTab() {
27
28
  const { printers, reload } = usePrinterLijst();
28
29
  const { werkplekken } = useWerkplekken();
30
+ const rollen = useEtiketRollen();
29
31
  const actief = werkplekken.filter((w) => w.actief);
30
32
  const labelIds = new Set(actief.map((w) => w.label_printer_id).filter(Boolean));
31
33
  const a4Ids = new Set(actief.map((w) => w.a4_printer_id).filter(Boolean));
32
34
  const labels = printers.filter((p) => isLabelprinterRij(p, labelIds, a4Ids));
33
- return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Geladen etiket" }), _jsx(CardDescription, { children: "Stel per labelprinter in welk etiket erin zit (breedte \u00D7 hoogte in mm). Zonder etiket worden er geen stickers op die printer geprint." })] }), _jsx(CardContent, { className: "space-y-3", children: labels.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Er is nog geen labelprinter gevonden." })) : (labels.map((p) => (_jsxs("div", { className: "rounded-md border p-3", children: [_jsx("div", { className: "font-medium", children: printerTitel(p) }), _jsxs("div", { className: "mt-1 text-sm", children: [_jsx("span", { className: "font-semibold", children: "Geladen etiket: " }), p.geladen_etiket ? (maatNl(p.geladen_etiket.breedte_mm, p.geladen_etiket.hoogte_mm)) : (_jsxs("span", { className: "text-destructive inline-flex items-center gap-1", children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), " ", GEEN_ETIKET_MELDING] }))] }), _jsx("div", { className: "mt-2", children: _jsx(GeladenEtiketKeuze, { printer: p, onGewijzigd: () => void reload() }) })] }, p.id)))) })] }));
35
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Geladen etiket" }), _jsx(CardDescription, { children: "Stel per labelprinter in welk etiket erin zit (breedte \u00D7 hoogte in mm). Zonder etiket worden er geen stickers op die printer geprint." })] }), _jsx(CardContent, { className: "space-y-3", children: labels.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Er is nog geen labelprinter gevonden." })) : (labels.map((p) => (_jsxs("div", { className: "rounded-md border p-3", children: [_jsx("div", { className: "font-medium", children: printerTitel(p) }), _jsxs("div", { className: "mt-1 text-sm", children: [_jsx("span", { className: "font-semibold", children: "Geladen etiket: " }), p.geladen_etiket ? (maatNl(p.geladen_etiket.breedte_mm, p.geladen_etiket.hoogte_mm)) : (_jsxs("span", { className: "text-destructive inline-flex items-center gap-1", children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), " ", GEEN_ETIKET_MELDING] }))] }), _jsx("div", { className: "mt-2", children: _jsx(RolKeuze, { printer: p, rollen: rollen, onGewijzigd: () => void reload() }, `${p.id}:${p.rol_id ?? ""}`) }), _jsxs("details", { className: "mt-2", children: [_jsx("summary", { className: "text-muted-foreground cursor-pointer text-xs", children: "Papiermaat zoals de printer die meldt" }), _jsx("div", { className: "mt-2", children: _jsx(GeladenEtiketKeuze, { printer: p, onGewijzigd: () => void reload() }) })] })] }, p.id)))) })] }));
34
36
  }
@@ -0,0 +1,12 @@
1
+ import { type OverzichtRegel } from "../lib/instelOverzicht.js";
2
+ export declare function laadInstelOverzicht(plekId: string): Promise<{
3
+ regels: OverzichtRegel[];
4
+ waarschuwingen: string[];
5
+ }>;
6
+ export declare function InstelOverzichtKaart({ plekId, titel }: {
7
+ plekId: string;
8
+ titel?: string;
9
+ }): import("react").JSX.Element;
10
+ /** Startlijst: het overzicht voor elke printplek. */
11
+ export declare function InstelOverzichtAllePlekken(): import("react").JSX.Element | null;
12
+ //# sourceMappingURL=InstelOverzichtKaart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstelOverzichtKaart.d.ts","sourceRoot":"","sources":["../../src/components/InstelOverzichtKaart.tsx"],"names":[],"mappings":"AASA,OAAO,EAAoD,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAQ/G,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA4BzH;AAED,wBAAgB,oBAAoB,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,+BAkDzF;AAED,qDAAqD;AACrD,wBAAgB,0BAA0B,uCAiBzC"}
@@ -0,0 +1,78 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/InstelOverzichtKaart.tsx — per printplek: wat gebeurt er per
4
+ // documentsoort (1.69.20). Zelfde keuzeregel als de printwachtrij.
5
+ // ============================================================================
6
+ import { useCallback, useEffect, useState } from "react";
7
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@flowselections/core";
8
+ import { AlertTriangle, CheckCircle2, XCircle } from "lucide-react";
9
+ import { supabase } from "../lib/supabaseClient.js";
10
+ import { berekenInstelOverzicht, ondergrensWaarschuwingen } from "../lib/instelOverzicht.js";
11
+ import { leesStickerInstellingenStrikt } from "../lib/stickerUitwijk.js";
12
+ const db = supabase;
13
+ const arr = (v) => (Array.isArray(v) ? v : []);
14
+ const naamVan = (p) => String(p.weergavenaam || p.naam || "Printer");
15
+ export async function laadInstelOverzicht(plekId) {
16
+ const [{ data: lijst }, { data: perSoort }, { data: plek }, { data: layouts }, a4Res, instRes] = await Promise.all([
17
+ db.from("print_plek_printers").select("printer_id").eq("print_plek_id", plekId),
18
+ db.from("document_printplek_printers").select("printer_id, documenttype").eq("print_plek_id", plekId),
19
+ db.from("print_plekken").select("a4_terugval").eq("id", plekId).maybeSingle(),
20
+ db.from("document_layouts").select("id, naam, documenttype, bron, actief, systeem, breedte_mm, hoogte_mm, orientatie, config"),
21
+ db.rpc("printplek_printer", { _plek: plekId, _documenttype: "pakbon" }),
22
+ db.rpc("layouts_sticker_verkleinen"),
23
+ ]);
24
+ const ids = new Set();
25
+ for (const r of [...arr(lijst), ...arr(perSoort)])
26
+ if (r.printer_id)
27
+ ids.add(String(r.printer_id));
28
+ const a4Id = typeof a4Res?.data === "string" ? a4Res.data : null;
29
+ if (a4Id)
30
+ ids.add(a4Id);
31
+ const { data: pr } = ids.size
32
+ ? await db.from("printers").select("id, naam, weergavenaam, geladen_etiket, actief").in("id", [...ids])
33
+ : { data: [] };
34
+ const printers = arr(pr).filter((p) => p.actief !== false);
35
+ const a4 = a4Id ? printers.find((p) => String(p.id) === a4Id) : null;
36
+ const regels = berekenInstelOverzicht({
37
+ printers: printers.map((p) => ({ id: String(p.id), naam: naamVan(p), geladen_etiket: p.geladen_etiket })),
38
+ perSoort: arr(perSoort).map((r) => ({ documenttype: String(r.documenttype), printer_id: r.printer_id ? String(r.printer_id) : null })),
39
+ a4Printer: a4 ? { id: String(a4.id), naam: naamVan(a4) } : null,
40
+ a4Terugval: plek?.a4_terugval !== false,
41
+ layouts: arr(layouts),
42
+ });
43
+ const inst = instRes?.error ? null : leesStickerInstellingenStrikt(instRes?.data);
44
+ const waarschuwingen = [...new Set([...regels.flatMap((r) => r.keuze.waarschuwingen), ...ondergrensWaarschuwingen(inst)])];
45
+ return { regels, waarschuwingen };
46
+ }
47
+ export function InstelOverzichtKaart({ plekId, titel }) {
48
+ const [data, setData] = useState(null);
49
+ const [fout, setFout] = useState(null);
50
+ const laad = useCallback(async () => {
51
+ try {
52
+ setData(await laadInstelOverzicht(plekId));
53
+ setFout(null);
54
+ }
55
+ catch (e) {
56
+ setFout(e instanceof Error ? e.message : "Overzicht laden mislukt");
57
+ }
58
+ }, [plekId]);
59
+ useEffect(() => {
60
+ if (plekId)
61
+ void laad();
62
+ }, [laad, plekId]);
63
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: titel ?? "Wat gebeurt er per documentsoort" }), _jsx(CardDescription, { children: "Dezelfde regel als bij het printen: eerst een ontwerp dat past, dan het standaardontwerp, dan A4 of weigeren." })] }), _jsxs(CardContent, { className: "space-y-2 text-sm", children: [fout ? _jsx("p", { className: "text-destructive", children: fout }) : null, !data && !fout ? _jsx("p", { className: "text-muted-foreground", children: "Controleren\u2026" }) : null, data && !data.regels.length ? _jsx("p", { className: "text-muted-foreground", children: "Geen stickerdocumenten om te controleren." }) : null, data?.regels.map((r) => (_jsxs("div", { className: "flex items-start gap-2", children: [r.keuze.stap === 5 ? (_jsx(XCircle, { className: "text-destructive mt-0.5 h-4 w-4 shrink-0" })) : r.keuze.stap === 4 ? (_jsx(AlertTriangle, { className: "text-muted-foreground mt-0.5 h-4 w-4 shrink-0" })) : (_jsx(CheckCircle2, { className: "text-primary mt-0.5 h-4 w-4 shrink-0" })), _jsxs("div", { children: [_jsx("span", { className: "font-medium", children: r.document }), " ", r.kort, _jsx("div", { className: "text-muted-foreground text-xs", children: r.keuze.reden })] })] }, r.sleutel))), data?.waarschuwingen.length ? (_jsx("ul", { className: "text-muted-foreground list-disc space-y-1 pl-5 text-xs", children: data.waarschuwingen.map((w) => (_jsx("li", { children: w }, w))) })) : null] })] }));
64
+ }
65
+ /** Startlijst: het overzicht voor elke printplek. */
66
+ export function InstelOverzichtAllePlekken() {
67
+ const [plekken, setPlekken] = useState([]);
68
+ useEffect(() => {
69
+ void db
70
+ .from("print_plekken")
71
+ .select("id, naam")
72
+ .order("naam")
73
+ .then(({ data }) => setPlekken(arr(data).map((p) => ({ id: String(p.id), naam: String(p.naam ?? "Printplek") }))));
74
+ }, []);
75
+ if (!plekken.length)
76
+ return null;
77
+ return (_jsx("div", { className: "space-y-3", children: plekken.map((p) => (_jsx(InstelOverzichtKaart, { plekId: p.id, titel: `${p.naam}: wat gebeurt er per documentsoort` }, p.id))) }));
78
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"KlaarOmTePrintenBlok.d.ts","sourceRoot":"","sources":["../../src/components/KlaarOmTePrintenBlok.tsx"],"names":[],"mappings":"AAwBA,2DAA2D;AAC3D,wBAAgB,oBAAoB,gCAsLnC"}
1
+ {"version":3,"file":"KlaarOmTePrintenBlok.d.ts","sourceRoot":"","sources":["../../src/components/KlaarOmTePrintenBlok.tsx"],"names":[],"mappings":"AAyBA,2DAA2D;AAC3D,wBAAgB,oBAAoB,gCA4LnC"}
@@ -3,6 +3,7 @@ import { useCallback, useEffect, useState } from "react";
3
3
  import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle } from "@flowselections/core";
4
4
  import { CheckCircle2, RefreshCw, XCircle } from "lucide-react";
5
5
  import { supabase } from "../lib/supabaseClient.js";
6
+ import { InstelOverzichtAllePlekken } from "./InstelOverzichtKaart.js";
6
7
  import { documentTypeLabel } from "../lib/documentTypes.js";
7
8
  import { routeringVoor } from "../lib/printRoutering.js";
8
9
  import { leesGeladenEtiket } from "../lib/etiketControle.js";
@@ -108,5 +109,5 @@ export function KlaarOmTePrintenBlok() {
108
109
  void load();
109
110
  }, [load]);
110
111
  const Vak = ({ v, naar }) => !v ? (_jsx("span", { className: "text-muted-foreground", children: "\u2014" })) : (_jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [v.ok ? _jsx(CheckCircle2, { className: "h-4 w-4 text-primary" }) : _jsx(XCircle, { className: "h-4 w-4 text-destructive" }), _jsx("span", { children: v.tekst }), !v.ok && (_jsx(Button, { asChild: true, size: "sm", variant: "outline", children: _jsx("a", { href: naar, children: "Instellen" }) }))] }));
111
- return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-2 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Klaar om te printen" }), _jsx(CardDescription, { children: "Per documentsoort: is er een layout, een printer en (bij etiketten) het juiste etiket?" })] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => void load(), disabled: laden, "aria-label": "Opnieuw controleren", children: _jsx(RefreshCw, { className: `h-4 w-4 ${laden ? "animate-spin" : ""}` }) })] }), _jsxs(CardContent, { children: [_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "py-2 pr-4 font-medium", children: "Document" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Layout" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Printer" }), _jsx("th", { className: "py-2 font-medium", children: "Etiketmaat" })] }) }), _jsxs("tbody", { children: [regels.map((r) => (_jsxs("tr", { className: "border-t", children: [_jsx("td", { className: "py-2 pr-4 font-medium", children: documentTypeLabel(r.soort) }), _jsx("td", { className: "py-2 pr-4", children: _jsx(Vak, { v: r.layout, naar: NAAR_LAYOUTS }) }), _jsx("td", { className: "py-2 pr-4", children: _jsx(Vak, { v: r.printer, naar: NAAR_PRINTEN }) }), _jsx("td", { className: "py-2", children: _jsx(Vak, { v: r.etiket, naar: NAAR_PRINTEN }) })] }, r.soort))), !regels.length && (_jsx("tr", { children: _jsx("td", { colSpan: 4, className: "py-3 text-muted-foreground", children: laden ? "Controleren…" : "Niets te tonen." }) }))] })] }) }), functies.length > 0 && (_jsxs("details", { className: "mt-4 text-sm", children: [_jsxs("summary", { className: "cursor-pointer text-muted-foreground", children: ["Installatiecontrole databasefuncties (", functies.filter((f) => f.in_orde).length, " van ", functies.length, " in orde)"] }), _jsxs("table", { className: "mt-2 w-full text-xs", children: [_jsx("thead", { className: "text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "py-1 pr-3 font-medium", children: "Functie" }), _jsx("th", { className: "py-1 pr-3 font-medium", children: "Aanwezig" }), _jsx("th", { className: "py-1 font-medium", children: "Interne controle" })] }) }), _jsx("tbody", { children: functies.map((f) => (_jsxs("tr", { className: "border-t", children: [_jsx("td", { className: "py-1 pr-3 font-mono", children: f.functie }), _jsx("td", { className: "py-1 pr-3", children: f.aanwezig ? "ja" : "nee" }), _jsx("td", { className: `py-1 ${f.in_orde ? "" : "text-destructive"}`, children: f.interne_controle })] }, f.functie))) })] })] })), waarschuwingen.length > 0 && (_jsxs("div", { className: "mt-4 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm", role: "status", children: [_jsx("div", { className: "mb-1 font-medium", children: "Let op (waarschuwing, er wordt wel geprint)" }), _jsx("ul", { className: "list-disc space-y-1 pl-5", children: waarschuwingen.map((w) => _jsx("li", { children: w }, w)) })] }))] })] }));
112
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-2 pb-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Klaar om te printen" }), _jsx(CardDescription, { children: "Per documentsoort: is er een layout, een printer en (bij etiketten) het juiste etiket?" })] }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => void load(), disabled: laden, "aria-label": "Opnieuw controleren", children: _jsx(RefreshCw, { className: `h-4 w-4 ${laden ? "animate-spin" : ""}` }) })] }), _jsxs(CardContent, { children: [_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "py-2 pr-4 font-medium", children: "Document" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Layout" }), _jsx("th", { className: "py-2 pr-4 font-medium", children: "Printer" }), _jsx("th", { className: "py-2 font-medium", children: "Etiketmaat" })] }) }), _jsxs("tbody", { children: [regels.map((r) => (_jsxs("tr", { className: "border-t", children: [_jsx("td", { className: "py-2 pr-4 font-medium", children: documentTypeLabel(r.soort) }), _jsx("td", { className: "py-2 pr-4", children: _jsx(Vak, { v: r.layout, naar: NAAR_LAYOUTS }) }), _jsx("td", { className: "py-2 pr-4", children: _jsx(Vak, { v: r.printer, naar: NAAR_PRINTEN }) }), _jsx("td", { className: "py-2", children: _jsx(Vak, { v: r.etiket, naar: NAAR_PRINTEN }) })] }, r.soort))), !regels.length && (_jsx("tr", { children: _jsx("td", { colSpan: 4, className: "py-3 text-muted-foreground", children: laden ? "Controleren…" : "Niets te tonen." }) }))] })] }) }), functies.length > 0 && (_jsxs("details", { className: "mt-4 text-sm", children: [_jsxs("summary", { className: "cursor-pointer text-muted-foreground", children: ["Installatiecontrole databasefuncties (", functies.filter((f) => f.in_orde).length, " van ", functies.length, " in orde)"] }), _jsxs("table", { className: "mt-2 w-full text-xs", children: [_jsx("thead", { className: "text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "py-1 pr-3 font-medium", children: "Functie" }), _jsx("th", { className: "py-1 pr-3 font-medium", children: "Aanwezig" }), _jsx("th", { className: "py-1 font-medium", children: "Interne controle" })] }) }), _jsx("tbody", { children: functies.map((f) => (_jsxs("tr", { className: "border-t", children: [_jsx("td", { className: "py-1 pr-3 font-mono", children: f.functie }), _jsx("td", { className: "py-1 pr-3", children: f.aanwezig ? "ja" : "nee" }), _jsx("td", { className: `py-1 ${f.in_orde ? "" : "text-destructive"}`, children: f.interne_controle })] }, f.functie))) })] })] })), _jsxs("details", { className: "mt-4 text-sm", open: true, children: [_jsx("summary", { className: "text-muted-foreground cursor-pointer", children: "Per printplek: wat gebeurt er per documentsoort" }), _jsx("div", { className: "mt-2", children: _jsx(InstelOverzichtAllePlekken, {}) })] }), waarschuwingen.length > 0 && (_jsxs("div", { className: "mt-4 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm", role: "status", children: [_jsx("div", { className: "mb-1 font-medium", children: "Let op (waarschuwing, er wordt wel geprint)" }), _jsx("ul", { className: "list-disc space-y-1 pl-5", children: waarschuwingen.map((w) => _jsx("li", { children: w }, w)) })] }))] })] }));
112
113
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LayoutsPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPage.tsx"],"names":[],"mappings":"AAmFA,wBAAgB,WAAW,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BAkpB1E"}
1
+ {"version":3,"file":"LayoutsPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPage.tsx"],"names":[],"mappings":"AAyFA,wBAAgB,WAAW,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BA+qB1E"}
@@ -13,6 +13,10 @@ import { ontbrekendeStandaarden, soortenZonderKeuze } from "../lib/klaarOmTePrin
13
13
  import { documentTypeLabel as soortLabel } from "../lib/documentTypes.js";
14
14
  import { dupliceerLayout, maakLayout, updateLayout, useLayouts, laatsteLayoutBeheerMelding, verwijderLayout, } from "../lib/useDocumentData.js";
15
15
  import { LayoutPrinterSelect } from "./LayoutPrinterSelect.js";
16
+ import { afdrukMaat, maatTekst, opslagVoorAfdrukMaat } from "../lib/formaatWeergave.js";
17
+ import { VELDEN_PER_KLASSE } from "../lib/stickerOntwerp.js";
18
+ import { formaatKlasse } from "../lib/etiketRollen.js";
19
+ import { isStickerOntwerpSoort } from "../lib/stickerRoute.js";
16
20
  import { DOCUMENT_TYPES, FLORIDAY_LAYOUT_TOELICHTING, PAPIERFORMATEN, documentTypeLabel, isFloridayLayout, } from "../lib/documentTypes.js";
17
21
  import { DOCUMENT_PROFIELEN, documentProfiel, primaireProfielen, standaardConfig, } from "../lib/documentProfiles.js";
18
22
  /** Elk documenttype krijgt zijn eigen opbouwpagina. */
@@ -21,6 +25,8 @@ function builderRoute(documenttype, layoutId) {
21
25
  return { to: "/layouts-printers/productiebon/$layoutId", params: { layoutId } };
22
26
  if (documenttype === "afleverbrief" || documenttype === "veilingbrief")
23
27
  return { to: "/layouts-printers/afleverbrief/$layoutId", params: { layoutId } };
28
+ if (isStickerOntwerpSoort(documenttype))
29
+ return { to: "/layouts-printers/sticker/$layoutId", params: { layoutId } };
24
30
  return { to: "/layouts-printers/pakbon/$layoutId", params: { layoutId } };
25
31
  }
26
32
  function klantOntwerpLayout(l) {
@@ -53,6 +59,8 @@ export function LayoutsPage({ ingebed = false } = {}) {
53
59
  const [omschrijving, setOmschrijving] = useState("");
54
60
  const [formaatCode, setFormaatCode] = useState("A4");
55
61
  const [orientatie, setOrientatie] = useState("portrait");
62
+ const [vrijB, setVrijB] = useState("");
63
+ const [vrijH, setVrijH] = useState("");
56
64
  const [klantLayout, setKlantLayout] = useState(false);
57
65
  const [bezig, setBezig] = useState(false);
58
66
  const klantOntwerp = documenttype === "sticker" && klantLayout;
@@ -130,6 +138,20 @@ export function LayoutsPage({ ingebed = false } = {}) {
130
138
  const formaat = profiel.formaten.find((f) => f.code === formaatCode) ??
131
139
  PAPIERFORMATEN.find((f) => f.code === formaatCode) ??
132
140
  profiel.formaten[0];
141
+ let maat = {
142
+ breedte_mm: formaat.breedte,
143
+ hoogte_mm: formaat.hoogte,
144
+ orientatie,
145
+ };
146
+ if (formaat.code === "VRIJ" && !klantOntwerp) {
147
+ const b = Number(vrijB.replace(",", "."));
148
+ const h = Number(vrijH.replace(",", "."));
149
+ if (!(b > 0) || !(h > 0)) {
150
+ toast.error("Vul bij Vrij formaat de breedte en hoogte in mm in");
151
+ return;
152
+ }
153
+ maat = opslagVoorAfdrukMaat(b, h);
154
+ }
133
155
  setBezig(true);
134
156
  try {
135
157
  const id = await maakLayout({
@@ -137,14 +159,16 @@ export function LayoutsPage({ ingebed = false } = {}) {
137
159
  documenttype,
138
160
  omschrijving: omschrijving.trim(),
139
161
  papierformaat: formaat.code,
140
- breedte_mm: formaat.breedte,
141
- hoogte_mm: formaat.hoogte,
142
- orientatie,
162
+ ...maat,
143
163
  config: (() => {
144
164
  const c = standaardConfig(profiel);
145
165
  if (documenttype === "sticker") {
146
166
  c.klantlayout = { ...(c.klantlayout ?? {}), gebruik_klantlayout: klantLayout };
147
167
  }
168
+ if (isStickerOntwerpSoort(documenttype) && !klantOntwerp) {
169
+ const a = afdrukMaat(maat);
170
+ c.fs_sticker = { velden: VELDEN_PER_KLASSE[formaatKlasse(a.breedte_mm, a.hoogte_mm)] };
171
+ }
148
172
  return c;
149
173
  })(),
150
174
  });
@@ -177,7 +201,7 @@ export function LayoutsPage({ ingebed = false } = {}) {
177
201
  catch (e) {
178
202
  toast.error(e instanceof Error ? e.message : "Standaard maken mislukt");
179
203
  }
180
- }, children: "Maak standaard" })] }, o.soort))), soortenZonderKeuze(layouts).map((o) => (_jsxs("div", { className: "flex items-center gap-2 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), _jsxs("span", { children: ["Geen standaardlayout voor ", soortLabel(o.soort), " \u2013 er zijn ", o.aantal, " actieve layouts. Kies er zelf \u00E9\u00E9n met ", _jsx("strong", { children: "Maak standaard" }), "."] })] }, `keuze-${o.soort}-${o.bron}`))), _jsx(LayoutVerwijzingenKaart, { onGewijzigd: () => void reload() }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Overzicht" }), _jsx(CardDescription, { children: loading ? "Laden…" : `${gefilterd.length} van ${layouts.length} layouts` })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-3 md:grid-cols-5", 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 naam of omschrijving", value: zoek, onChange: (e) => setZoek(e.target.value) })] }), _jsxs(Select, { value: typeFilter, onValueChange: setTypeFilter, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Documenttype" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle documenttypes" }), DOCUMENT_TYPES.map((d) => (_jsx(SelectItem, { value: d.value, children: d.label }, d.value)))] })] }), _jsxs(Select, { value: statusFilter, onValueChange: setStatusFilter, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Status" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle statussen" }), _jsx(SelectItem, { value: "actief", children: "Actief" }), _jsx(SelectItem, { value: "inactief", children: "Inactief" })] })] }), _jsxs(Select, { value: bronFilter, onValueChange: setBronFilter, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Herkomst" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle herkomsten" }), _jsx(SelectItem, { value: "eigen", children: "Eigen ontwerp" }), _jsx(SelectItem, { value: "floriday", children: "Uit Floriday" })] })] })] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Naam" }), _jsx(TableHead, { children: "Documenttype" }), _jsx(TableHead, { children: "Formaat" }), _jsxs(TableHead, { children: [_jsx("div", { children: "Printer nu" }), _jsxs("div", { className: "text-xs font-normal", children: ["bedrijfsstandaard, in te stellen op", " ", _jsx(Link, { to: "/layouts-printers/printplekken", className: "text-primary underline", children: "Printen" })] })] }), _jsx(TableHead, { children: "Actief" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsxs(TableBody, { children: [gefilterd.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 6, className: "py-10 text-center text-sm text-muted-foreground", children: "Geen layouts gevonden." }) })), gefilterd.map((l) => (_jsxs(TableRow, { children: [_jsxs(TableCell, { children: [_jsxs("div", { className: "flex items-center gap-2 font-medium", children: [_jsx(FileText, { className: "h-4 w-4 text-muted-foreground" }), l.naam, l.is_standaard && _jsx(Badge, { variant: "secondary", children: "Standaard" }), isFloridayLayout(l) && _jsx(Badge, { variant: "outline", children: "Uit Floriday" })] }), (l.omschrijving || isFloridayLayout(l)) && (_jsx("span", { className: "text-xs text-muted-foreground", children: isFloridayLayout(l) ? FLORIDAY_LAYOUT_TOELICHTING : l.omschrijving })), !isFloridayLayout(l) && !klantOntwerpLayout(l) && (_jsx(StandaardLayoutActies, { layout: l, standaarden: standaarden, onGewijzigd: () => void reload() }))] }), _jsx(TableCell, { children: documentTypeLabel(l.documenttype) }), _jsxs(TableCell, { className: "text-sm text-muted-foreground", children: [l.papierformaat, " \u00B7 ", Number(l.breedte_mm), " \u00D7 ", Number(l.hoogte_mm), " mm"] }), _jsx(TableCell, { className: "min-w-52", children: _jsx(LayoutPrinterSelect, { layoutId: l.id, documenttype: l.documenttype }) }), _jsx(TableCell, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { checked: l.actief, onCheckedChange: async (v) => {
204
+ }, children: "Maak standaard" })] }, o.soort))), soortenZonderKeuze(layouts).map((o) => (_jsxs("div", { className: "flex items-center gap-2 rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), _jsxs("span", { children: ["Geen standaardlayout voor ", soortLabel(o.soort), " \u2013 er zijn ", o.aantal, " actieve layouts. Kies er zelf \u00E9\u00E9n met ", _jsx("strong", { children: "Maak standaard" }), "."] })] }, `keuze-${o.soort}-${o.bron}`))), _jsx(LayoutVerwijzingenKaart, { onGewijzigd: () => void reload() }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Overzicht" }), _jsx(CardDescription, { children: loading ? "Laden…" : `${gefilterd.length} van ${layouts.length} layouts` })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-3 md:grid-cols-5", 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 naam of omschrijving", value: zoek, onChange: (e) => setZoek(e.target.value) })] }), _jsxs(Select, { value: typeFilter, onValueChange: setTypeFilter, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Documenttype" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle documenttypes" }), DOCUMENT_TYPES.map((d) => (_jsx(SelectItem, { value: d.value, children: d.label }, d.value)))] })] }), _jsxs(Select, { value: statusFilter, onValueChange: setStatusFilter, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Status" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle statussen" }), _jsx(SelectItem, { value: "actief", children: "Actief" }), _jsx(SelectItem, { value: "inactief", children: "Inactief" })] })] }), _jsxs(Select, { value: bronFilter, onValueChange: setBronFilter, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Herkomst" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle herkomsten" }), _jsx(SelectItem, { value: "eigen", children: "Eigen ontwerp" }), _jsx(SelectItem, { value: "floriday", children: "Uit Floriday" })] })] })] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Naam" }), _jsx(TableHead, { children: "Documenttype" }), _jsx(TableHead, { children: "Formaat" }), _jsxs(TableHead, { children: [_jsx("div", { children: "Printer nu" }), _jsxs("div", { className: "text-xs font-normal", children: ["bedrijfsstandaard, in te stellen op", " ", _jsx(Link, { to: "/layouts-printers/printplekken", className: "text-primary underline", children: "Printen" })] })] }), _jsx(TableHead, { children: "Actief" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsxs(TableBody, { children: [gefilterd.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 6, className: "py-10 text-center text-sm text-muted-foreground", children: "Geen layouts gevonden." }) })), gefilterd.map((l) => (_jsxs(TableRow, { children: [_jsxs(TableCell, { children: [_jsxs("div", { className: "flex items-center gap-2 font-medium", children: [_jsx(FileText, { className: "h-4 w-4 text-muted-foreground" }), l.naam, l.is_standaard && _jsx(Badge, { variant: "secondary", children: "Standaard" }), isFloridayLayout(l) && _jsx(Badge, { variant: "outline", children: "Uit Floriday" })] }), (l.omschrijving || isFloridayLayout(l)) && (_jsx("span", { className: "text-xs text-muted-foreground", children: isFloridayLayout(l) ? FLORIDAY_LAYOUT_TOELICHTING : l.omschrijving })), !isFloridayLayout(l) && !klantOntwerpLayout(l) && (_jsx(StandaardLayoutActies, { layout: l, standaarden: standaarden, onGewijzigd: () => void reload() }))] }), _jsx(TableCell, { children: documentTypeLabel(l.documenttype) }), _jsxs(TableCell, { className: "text-sm text-muted-foreground", children: [l.papierformaat, " \u00B7 ", maatTekst(afdrukMaat(l))] }), _jsx(TableCell, { className: "min-w-52", children: _jsx(LayoutPrinterSelect, { layoutId: l.id, documenttype: l.documenttype }) }), _jsx(TableCell, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { checked: l.actief, onCheckedChange: async (v) => {
181
205
  await updateLayout(l.id, { actief: v });
182
206
  void reload();
183
207
  } }), !l.is_standaard && (_jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
@@ -224,7 +248,7 @@ export function LayoutsPage({ ingebed = false } = {}) {
224
248
  setFormaatCode(p.standaardFormaat);
225
249
  setOrientatie(p.standaardOrientatie);
226
250
  setStap(2);
227
- }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Kies documentsoort" }) }), _jsx(SelectContent, { children: DOCUMENT_PROFIELEN.filter((p) => !p.primair).map((p) => (_jsx(SelectItem, { value: p.id, children: p.label }, p.id))) })] })] })] })) : (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "l-naam", children: "Naam" }), _jsx(Input, { id: "l-naam", value: naam, onChange: (e) => setNaam(e.target.value), placeholder: `${documentProfiel(documenttype).label} 2026` })] }), documenttype === "sticker" && (_jsxs("div", { className: "flex items-start justify-between gap-4 rounded-lg border p-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: "l-klantlayout", children: "Kies altijd de layout van de klant" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "De klant levert het ontwerp aan. Formaat en ontwerpen zijn dan niet nodig." })] }), _jsx(Switch, { id: "l-klantlayout", checked: klantLayout, onCheckedChange: setKlantLayout })] })), !klantOntwerp && (_jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Formaat" }), _jsxs(Select, { value: formaatCode, onValueChange: setFormaatCode, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: documentProfiel(documenttype).formaten.map((f) => (_jsx(SelectItem, { value: f.code, children: f.label }, f.code))) })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Ori\u00EBntatie" }), _jsxs(Select, { value: orientatie, onValueChange: (v) => setOrientatie(v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "portrait", children: "Staand" }), _jsx(SelectItem, { value: "landscape", children: "Liggend" })] })] })] })] })), _jsx(Separator, {}), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "l-oms", children: "Omschrijving" }), _jsx(Textarea, { id: "l-oms", value: omschrijving, onChange: (e) => setOmschrijving(e.target.value), placeholder: "Waar wordt dit document voor gebruikt?" })] })] })), _jsx(DialogFooter, { children: stap === 2 ? (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => setStap(1), children: "Vorige" }), _jsx(Button, { onClick: aanmaken, disabled: bezig, children: klantOntwerp ? "Aanmaken" : "Aanmaken en ontwerpen" })] })) : (_jsx(Button, { variant: "outline", onClick: () => setWizardOpen(false), children: "Annuleren" })) })] }) }), _jsx(Dialog, { open: bewerkId !== null, onOpenChange: (v) => !v && setBewerkId(null), children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Layout wijzigen" }), _jsx(DialogDescription, { children: "Pas de naam, het documenttype en het formaat aan." })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "b-naam", children: "Naam" }), _jsx(Input, { id: "b-naam", value: bNaam, onChange: (e) => setBNaam(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Documenttype" }), _jsxs(Select, { value: bType, onValueChange: (v) => {
251
+ }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Kies documentsoort" }) }), _jsx(SelectContent, { children: DOCUMENT_PROFIELEN.filter((p) => !p.primair).map((p) => (_jsx(SelectItem, { value: p.id, children: p.label }, p.id))) })] })] })] })) : (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "l-naam", children: "Naam" }), _jsx(Input, { id: "l-naam", value: naam, onChange: (e) => setNaam(e.target.value), placeholder: `${documentProfiel(documenttype).label} 2026` })] }), documenttype === "sticker" && (_jsxs("div", { className: "flex items-start justify-between gap-4 rounded-lg border p-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { htmlFor: "l-klantlayout", children: "Kies altijd de layout van de klant" }), _jsx("p", { className: "text-xs text-muted-foreground", children: "De klant levert het ontwerp aan. Formaat en ontwerpen zijn dan niet nodig." })] }), _jsx(Switch, { id: "l-klantlayout", checked: klantLayout, onCheckedChange: setKlantLayout })] })), !klantOntwerp && (_jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Formaat" }), _jsxs(Select, { value: formaatCode, onValueChange: setFormaatCode, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: documentProfiel(documenttype).formaten.map((f) => (_jsx(SelectItem, { value: f.code, children: f.label }, f.code))) })] })] }), formaatCode === "VRIJ" ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Maat (breedte \u00D7 hoogte, mm)" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { "aria-label": "Breedte in mm", inputMode: "decimal", value: vrijB, onChange: (e) => setVrijB(e.target.value), placeholder: "breedte" }), _jsx("span", { children: "\u00D7" }), _jsx(Input, { "aria-label": "Hoogte in mm", inputMode: "decimal", value: vrijH, onChange: (e) => setVrijH(e.target.value), placeholder: "hoogte" })] })] })) : (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Ori\u00EBntatie" }), _jsxs(Select, { value: orientatie, onValueChange: (v) => setOrientatie(v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "portrait", children: "Staand" }), _jsx(SelectItem, { value: "landscape", children: "Liggend" })] })] })] }))] })), _jsx(Separator, {}), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "l-oms", children: "Omschrijving" }), _jsx(Textarea, { id: "l-oms", value: omschrijving, onChange: (e) => setOmschrijving(e.target.value), placeholder: "Waar wordt dit document voor gebruikt?" })] })] })), _jsx(DialogFooter, { children: stap === 2 ? (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", onClick: () => setStap(1), children: "Vorige" }), _jsx(Button, { onClick: aanmaken, disabled: bezig, children: klantOntwerp ? "Aanmaken" : "Aanmaken en ontwerpen" })] })) : (_jsx(Button, { variant: "outline", onClick: () => setWizardOpen(false), children: "Annuleren" })) })] }) }), _jsx(Dialog, { open: bewerkId !== null, onOpenChange: (v) => !v && setBewerkId(null), children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Layout wijzigen" }), _jsx(DialogDescription, { children: "Pas de naam, het documenttype en het formaat aan." })] }), _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "b-naam", children: "Naam" }), _jsx(Input, { id: "b-naam", value: bNaam, onChange: (e) => setBNaam(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Documenttype" }), _jsxs(Select, { value: bType, onValueChange: (v) => {
228
252
  const p = documentProfiel(v);
229
253
  setBType(v);
230
254
  if (!p.formaten.some((f) => f.code === bFormaat)) {
@@ -1 +1 @@
1
- {"version":3,"file":"PakbonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/PakbonBuilderPage.tsx"],"names":[],"mappings":"AAiCA,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BAqMvF"}
1
+ {"version":3,"file":"PakbonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/PakbonBuilderPage.tsx"],"names":[],"mappings":"AAkCA,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA6MvF"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
- import { Link } from "@tanstack/react-router";
3
+ import { Link, useNavigate } from "@tanstack/react-router";
4
+ import { isStickerOntwerpSoort } from "../lib/stickerRoute.js";
4
5
  import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "@flowselections/core";
5
6
  import { AlertTriangle, ArrowLeft, CheckCircle2, Loader2, Printer, Save } from "lucide-react";
6
7
  import { PakbonSectiesPanel } from "./PakbonSectiesPanel.js";
@@ -35,6 +36,13 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
35
36
  if (layout)
36
37
  setConfig(leesPakbonConfig(layout.config));
37
38
  }, [layout?.id]);
39
+ // Stickers horen in de stickerontwerper (1.69.20); de inhoud blijft behouden.
40
+ const naarSticker = useNavigate();
41
+ useEffect(() => {
42
+ if (layout && isStickerOntwerpSoort(layout.documenttype)) {
43
+ void naarSticker({ to: "/layouts-printers/sticker/$layoutId", params: { layoutId: layout.id }, replace: true });
44
+ }
45
+ }, [layout?.id, layout?.documenttype]);
38
46
  const breedte = useMemo(() => (layout?.orientatie === "landscape" ? layout?.hoogte_mm : layout?.breedte_mm) ?? 210, [layout]);
39
47
  const hoogte = useMemo(() => (layout?.orientatie === "landscape" ? layout?.breedte_mm : layout?.hoogte_mm) ?? 297, [layout]);
40
48
  const marge = Number(layout?.marge_boven ?? 10);
@@ -1 +1 @@
1
- {"version":3,"file":"PrintersPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintersPage.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,YAAY,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BAsM3E"}
1
+ {"version":3,"file":"PrintersPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintersPage.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,YAAY,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BAuM3E"}
@@ -21,7 +21,7 @@ export function PrintersPage({ ingebed = false } = {}) {
21
21
  const { layouts } = useLayouts();
22
22
  const navigate = useNavigate();
23
23
  const { computers, loading: computersLaden, fout: computersFout, reload: herlaadComputers, } = useComputers();
24
- const { gevonden, zoek } = useNetwerkPrinters();
24
+ const { gevonden, zoek, geladen: lijstGeladen } = useNetwerkPrinters();
25
25
  const [computerToevoegen, setComputerToevoegen] = useState(false);
26
26
  const [zoekterm, setZoekterm] = useState("");
27
27
  const [status, setStatus] = useState("alle");
@@ -38,7 +38,8 @@ export function PrintersPage({ ingebed = false } = {}) {
38
38
  naam: c.naam,
39
39
  online: c.online,
40
40
  locatie: info?.locaties.join(" · ") || "Geen locatie",
41
- telling: info ?? { gevonden: c.aantalGevonden, ingesteld: 0, gekoppeld: 0, locaties: [] },
41
+ // Zonder PrintNode-lijst is "ingesteld" niet te tellen; dan alleen het gevonden aantal.
42
+ telling: info ?? { gevonden: lijstGeladen ? c.aantalGevonden : 0, ingesteld: 0, gekoppeld: 0, locaties: [] },
42
43
  };
43
44
  });
44
45
  const locaties = Array.from(new Set(alleRijen.map((r) => r.locatie))).filter((l) => l !== "Geen locatie");
@@ -1 +1 @@
1
- {"version":3,"file":"PrintplekDetailPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintplekDetailPage.tsx"],"names":[],"mappings":"AA0EA,wBAAgB,mBAAmB,gCA+uBlC"}
1
+ {"version":3,"file":"PrintplekDetailPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintplekDetailPage.tsx"],"names":[],"mappings":"AA2EA,wBAAgB,mBAAmB,gCA6uBlC"}
@@ -4,6 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
4
4
  // computers, printers (per computer) en welk document naar welke printer gaat.
5
5
  // Alles is hier direct bewerkbaar; de wizard is alleen voor een nieuwe plek.
6
6
  // ============================================================================
7
+ import { InstelOverzichtKaart } from "./InstelOverzichtKaart.js";
7
8
  import { useEffect, useMemo, useState } from "react";
8
9
  import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, toast, } from "@flowselections/core";
9
10
  import { Link, useNavigate, useParams } from "@tanstack/react-router";
@@ -234,14 +235,9 @@ export function PrintplekDetailPage() {
234
235
  if (!plek) {
235
236
  return (_jsxs("main", { className: "space-y-4 p-6", children: [_jsx(Button, { variant: "ghost", asChild: true, children: _jsxs(Link, { to: "/layouts-printers/printplekken", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Terug"] }) }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Deze printplek bestaat niet (meer)." })] }));
236
237
  }
237
- const PrinterRij = ({ p }) => (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-lg border p-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${isOnline(p) ? "bg-emerald-500" : "bg-muted-foreground"}` }), _jsx("span", { className: "font-medium", children: p.naam }), p.papierformaat ? _jsx(Badge, { variant: "secondary", children: p.papierformaat }) : null, !isOnline(p) ? _jsx("span", { className: "text-muted-foreground text-xs", children: "offline" }) : null] }), _jsxs("div", { className: "flex flex-wrap items-center gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: async () => {
238
- try {
239
- await drukTestpaginaAf(p.id, p.naam);
240
- toast.success("Testpagina verstuurd");
241
- }
242
- catch {
243
- toast.error("Testpagina versturen is niet gelukt.");
244
- }
238
+ const PrinterRij = ({ p }) => (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-lg border p-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${isOnline(p) ? "bg-emerald-500" : "bg-muted-foreground"}` }), _jsx("span", { className: "font-medium", children: p.naam }), p.papierformaat ? _jsx(Badge, { variant: "secondary", children: p.papierformaat }) : null, !isOnline(p) ? _jsx("span", { className: "text-muted-foreground text-xs", children: "offline" }) : null] }), _jsxs("div", { className: "flex flex-wrap items-center gap-1", children: [_jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
239
+ // De melding (gelukt of niet) komt uit drukTestpaginaAf zelf; nooit "verstuurd" zonder opdracht.
240
+ void drukTestpaginaAf(p.id, p.naam);
245
241
  }, children: "Testpagina" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => setVervangen({ id: p.id, naam: p.naam }), children: "Vervangen" }), andereplekken.length > 0 ? (_jsxs("select", { className: selectKlasse, value: "", "aria-label": `${p.naam} verplaatsen`, onChange: (e) => e.target.value && void verplaats(p, e.target.value), children: [_jsx("option", { value: "", children: "Verplaatsen\u2026" }), andereplekken.map((o) => (_jsxs("option", { value: o.id, children: ["naar ", o.naam] }, o.id)))] })) : null, _jsx(Button, { size: "sm", variant: "ghost", className: "text-destructive", onClick: () => void loskoppelen(p), children: "Verwijderen" })] })] }));
246
242
  const teVerwijderenPrinters = teVerwijderen
247
243
  ? eigenPrinters.filter((p) => computerVan(p) === teVerwijderen).map((p) => ({ id: p.id, naam: p.naam }))
@@ -262,7 +258,7 @@ export function PrintplekDetailPage() {
262
258
  }, children: _jsx(Check, { className: "h-4 w-4" }) }), _jsx(Button, { size: "icon", variant: "ghost", onClick: () => setNaamBewerken(false), children: _jsx(X, { className: "h-4 w-4" }) })] })) : (_jsx("h1", { className: "cursor-pointer text-xl font-semibold", onClick: () => {
263
259
  setNaam(plek.naam);
264
260
  setNaamBewerken(true);
265
- }, children: plek.naam })), _jsx("p", { className: "text-muted-foreground text-sm", children: plek.omschrijving ?? "Hier stel je alles in wat er op deze plek wordt afgedrukt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", onClick: () => setTestprintOpen(true), children: [_jsx(Printer, { className: "mr-2 h-4 w-4" }), " Testprint controleren"] }), _jsxs(Button, { variant: "ghost", className: "text-destructive", onClick: () => setVerwijderOpen(true), children: [_jsx(Trash2, { className: "mr-2 h-4 w-4" }), " Verwijderen"] })] })] }), _jsx(PrintplekVerwijderenDialog, { plek: verwijderOpen ? { id: plek.id, naam: plek.naam } : null, onOpenChange: setVerwijderOpen, onKlaar: () => void navigate({ to: "/layouts-printers/printplekken" }) }), _jsx(TestprintDialog, { open: testprintOpen, onOpenChange: setTestprintOpen, printplekId: plekId, printplekNaam: plek.naam }), uitgevallen.length > 0 && (_jsxs("div", { role: "alert", className: "rounded-lg border border-destructive bg-destructive/10 px-4 py-3 text-sm text-destructive", children: [_jsx("strong", { children: "Computer niet verbonden:" }), " ", uitgevallen.join(", "), ". Opdrachten voor deze plek worden pas geprint als de computer weer verbonden is, en verlopen anders."] })), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(Monitor, { className: "h-4 w-4" }), " Computers op deze plek"] }), _jsx(CardDescription, { children: "Het bolletje laat zien of de computer nu aan staat." })] }), vrijeComputers.length > 0 ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("select", { className: selectKlasse, value: computerToevoegen, onChange: (e) => setComputerToevoegen(e.target.value), "aria-label": "Computer kiezen", children: [_jsx("option", { value: "", children: "Computer kiezen\u2026" }), vrijeComputers.map((c) => (_jsx("option", { value: c.naam, children: c.naam }, c.id)))] }), _jsxs(Button, { size: "sm", disabled: !computerToevoegen, onClick: async () => {
261
+ }, children: plek.naam })), _jsx("p", { className: "text-muted-foreground text-sm", children: plek.omschrijving ?? "Hier stel je alles in wat er op deze plek wordt afgedrukt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", onClick: () => setTestprintOpen(true), children: [_jsx(Printer, { className: "mr-2 h-4 w-4" }), " Testprint controleren"] }), _jsxs(Button, { variant: "ghost", className: "text-destructive", onClick: () => setVerwijderOpen(true), children: [_jsx(Trash2, { className: "mr-2 h-4 w-4" }), " Verwijderen"] })] })] }), _jsx(PrintplekVerwijderenDialog, { plek: verwijderOpen ? { id: plek.id, naam: plek.naam } : null, onOpenChange: setVerwijderOpen, onKlaar: () => void navigate({ to: "/layouts-printers/printplekken" }) }), _jsx(TestprintDialog, { open: testprintOpen, onOpenChange: setTestprintOpen, printplekId: plekId, printplekNaam: plek.naam }), uitgevallen.length > 0 && (_jsxs("div", { role: "alert", className: "rounded-lg border border-destructive bg-destructive/10 px-4 py-3 text-sm text-destructive", children: [_jsx("strong", { children: "Computer niet verbonden:" }), " ", uitgevallen.join(", "), ". Opdrachten voor deze plek worden pas geprint als de computer weer verbonden is, en verlopen anders."] })), _jsx(InstelOverzichtKaart, { plekId: plekId }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(Monitor, { className: "h-4 w-4" }), " Computers op deze plek"] }), _jsx(CardDescription, { children: "Het bolletje laat zien of de computer nu aan staat." })] }), vrijeComputers.length > 0 ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("select", { className: selectKlasse, value: computerToevoegen, onChange: (e) => setComputerToevoegen(e.target.value), "aria-label": "Computer kiezen", children: [_jsx("option", { value: "", children: "Computer kiezen\u2026" }), vrijeComputers.map((c) => (_jsx("option", { value: c.naam, children: c.naam }, c.id)))] }), _jsxs(Button, { size: "sm", disabled: !computerToevoegen, onClick: async () => {
266
262
  try {
267
263
  await koppelComputerAanPrintplek(plekId, computerToevoegen, computers.find((k) => k.naam === computerToevoegen)?.id);
268
264
  setComputerToevoegen("");
@@ -0,0 +1,9 @@
1
+ import { type EtiketRol } from "../lib/etiketRollen.js";
2
+ import { type PrinterRij } from "../lib/werkplekken.js";
3
+ export declare function useEtiketRollen(): EtiketRol[];
4
+ export declare function RolKeuze({ printer, rollen, onGewijzigd }: {
5
+ printer: PrinterRij;
6
+ rollen: EtiketRol[];
7
+ onGewijzigd: () => void;
8
+ }): import("react").JSX.Element;
9
+ //# sourceMappingURL=RolKeuze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RolKeuze.d.ts","sourceRoot":"","sources":["../../src/components/RolKeuze.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAsD,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEzG,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAMvE,wBAAgB,eAAe,gBAiB9B;AAED,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,IAAI,CAAA;CAAE,+BA0G/H"}
@@ -0,0 +1,91 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/RolKeuze.tsx — per printer kiezen welke etiketrol erin zit
4
+ // (1.69.20). De keuzelijst komt uit print_etiketrollen (data, niet code), plus
5
+ // "Zelf invullen". Opslaan zet rol_* én geladen_etiket (dat leest de wachtrij).
6
+ // ============================================================================
7
+ import { useEffect, useState } from "react";
8
+ import { Button, Input, toast } from "@flowselections/core";
9
+ import { AlertTriangle } from "lucide-react";
10
+ import { supabase } from "../lib/supabaseClient.js";
11
+ import { leesbareFout } from "../lib/foutTekst.js";
12
+ import { INVOERRICHTINGEN, leesRollen, rolNaarGeladenEtiket } from "../lib/etiketRollen.js";
13
+ import { maatNl } from "../lib/etiketControle.js";
14
+ import { zetPrinterVelden } from "../lib/werkplekken.js";
15
+ const db = supabase;
16
+ const selectKlasse = "border-input bg-background rounded-md border px-2 py-1 text-sm";
17
+ const ZELF = "__zelf__";
18
+ export function useEtiketRollen() {
19
+ const [rollen, setRollen] = useState([]);
20
+ useEffect(() => {
21
+ let actief = true;
22
+ void db
23
+ .from("print_etiketrollen")
24
+ .select("*")
25
+ .eq("actief", true)
26
+ .order("volgorde")
27
+ .then(({ data }) => {
28
+ if (actief)
29
+ setRollen(leesRollen(data));
30
+ });
31
+ return () => {
32
+ actief = false;
33
+ };
34
+ }, []);
35
+ return rollen;
36
+ }
37
+ export function RolKeuze({ printer, rollen, onGewijzigd }) {
38
+ const huidigeRol = rollen.find((r) => r.id === printer.rol_id) ?? null;
39
+ const e = printer.geladen_etiket;
40
+ const [keuze, setKeuze] = useState(huidigeRol?.id ?? (e ? ZELF : ""));
41
+ const [breedte, setBreedte] = useState(e && !huidigeRol ? String(e.breedte_mm) : "");
42
+ const [hoogte, setHoogte] = useState(e && !huidigeRol ? String(e.hoogte_mm) : "");
43
+ const [richting, setRichting] = useState(printer.rol_invoerrichting ?? "korte_zijde");
44
+ const [marge, setMarge] = useState(printer.rol_marge_mm != null ? String(printer.rol_marge_mm) : "0");
45
+ const [doorlopend, setDoorlopend] = useState(printer.rol_doorlopend ?? huidigeRol?.doorlopend ?? false);
46
+ const [bezig, setBezig] = useState(false);
47
+ useEffect(() => {
48
+ setKeuze(huidigeRol?.id ?? (e ? ZELF : ""));
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
50
+ }, [huidigeRol?.id]);
51
+ const opslaan = async () => {
52
+ let maat = null;
53
+ let rolId = null;
54
+ if (keuze === ZELF) {
55
+ const b = Number(breedte.replace(",", "."));
56
+ const h = Number(hoogte.replace(",", "."));
57
+ if (!(b > 0) || !(h > 0)) {
58
+ toast.error("Vul breedte en hoogte in mm in.");
59
+ return;
60
+ }
61
+ maat = { naam: `${b} × ${h} mm`, breedte_mm: b, hoogte_mm: h };
62
+ }
63
+ else if (keuze) {
64
+ const r = rollen.find((x) => x.id === keuze);
65
+ if (!r)
66
+ return;
67
+ rolId = r.id;
68
+ maat = { naam: r.naam, breedte_mm: r.breedte_mm, hoogte_mm: r.hoogte_mm };
69
+ }
70
+ const m = Number(marge.replace(",", "."));
71
+ setBezig(true);
72
+ try {
73
+ await zetPrinterVelden(printer.id, {
74
+ rol_id: rolId,
75
+ rol_invoerrichting: maat ? richting : null,
76
+ rol_marge_mm: maat && m >= 0 ? m : null,
77
+ rol_doorlopend: maat ? doorlopend : null,
78
+ geladen_etiket: maat ? rolNaarGeladenEtiket(maat, printer.ondersteunde_formaten) : null,
79
+ });
80
+ toast.success(maat ? `Rol opgeslagen: ${maatNl(maat.breedte_mm, maat.hoogte_mm)}` : "Rol gewist: formaat onbekend");
81
+ onGewijzigd();
82
+ }
83
+ catch (err) {
84
+ toast.error(leesbareFout(err, "Opslaan mislukt"));
85
+ }
86
+ finally {
87
+ setBezig(false);
88
+ }
89
+ };
90
+ return (_jsxs("div", { className: "space-y-2 text-sm", id: `rol-${printer.id}`, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-muted-foreground", children: "Rol in de printer:" }), _jsxs("select", { className: selectKlasse, value: keuze, onChange: (ev) => setKeuze(ev.target.value), "aria-label": "Rol in de printer", children: [_jsx("option", { value: "", children: "\u2014 formaat onbekend \u2014" }), rollen.map((r) => (_jsxs("option", { value: r.id, children: [r.naam, " (", maatNl(r.breedte_mm, r.hoogte_mm), ")"] }, r.id))), _jsx("option", { value: ZELF, children: "Zelf invullen\u2026" })] }), keuze === ZELF ? (_jsxs(_Fragment, { children: [_jsx(Input, { className: "h-8 w-20", inputMode: "decimal", placeholder: "breedte", value: breedte, onChange: (ev) => setBreedte(ev.target.value), "aria-label": "Breedte in mm" }), _jsx("span", { children: "\u00D7" }), _jsx(Input, { className: "h-8 w-20", inputMode: "decimal", placeholder: "hoogte", value: hoogte, onChange: (ev) => setHoogte(ev.target.value), "aria-label": "Hoogte in mm" }), _jsx("span", { className: "text-muted-foreground", children: "mm" })] })) : null] }), keuze ? (_jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsxs("label", { className: "flex items-center gap-1", children: [_jsx("span", { className: "text-muted-foreground", children: "Invoer:" }), _jsx("select", { className: selectKlasse, value: richting, onChange: (ev) => setRichting(ev.target.value), children: INVOERRICHTINGEN.map((r) => (_jsx("option", { value: r.waarde, children: r.label }, r.waarde))) })] }), _jsxs("label", { className: "flex items-center gap-1", children: [_jsx("span", { className: "text-muted-foreground", children: "Marge:" }), _jsx(Input, { className: "h-8 w-16", inputMode: "decimal", value: marge, onChange: (ev) => setMarge(ev.target.value), "aria-label": "Marge in mm" }), _jsx("span", { className: "text-muted-foreground", children: "mm" })] }), _jsxs("label", { className: "flex items-center gap-1", children: [_jsx("input", { type: "checkbox", checked: doorlopend, onChange: (ev) => setDoorlopend(ev.target.checked) }), _jsx("span", { children: "Doorlopend (anders ponsband)" })] })] })) : (_jsxs("p", { className: "text-destructive flex items-center gap-1 text-xs", children: [_jsx(AlertTriangle, { className: "h-3 w-3" }), " Formaat onbekend: stel in welke rol erin zit. Er wordt niet aangenomen dat het A4 is."] })), _jsx(Button, { size: "sm", variant: "outline", disabled: bezig, onClick: () => void opslaan(), children: "Rol opslaan" })] }));
91
+ }
@@ -0,0 +1,4 @@
1
+ export declare function StickerOntwerpPage({ layoutId: layoutIdProp }?: {
2
+ layoutId?: string;
3
+ }): import("react").JSX.Element;
4
+ //# sourceMappingURL=StickerOntwerpPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StickerOntwerpPage.d.ts","sourceRoot":"","sources":["../../src/components/StickerOntwerpPage.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA6IxF"}