@flowselections/layout-maker 1.13.2 → 1.20.0

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/AfdrukKnop.d.ts +5 -0
  2. package/dist-lib/components/AfdrukKnop.d.ts.map +1 -1
  3. package/dist-lib/components/AfdrukKnop.js +5 -0
  4. package/dist-lib/components/DocumentRouteringPage.d.ts +3 -1
  5. package/dist-lib/components/DocumentRouteringPage.d.ts.map +1 -1
  6. package/dist-lib/components/DocumentRouteringPage.js +66 -64
  7. package/dist-lib/components/DocumentenPage.d.ts +4 -0
  8. package/dist-lib/components/DocumentenPage.d.ts.map +1 -0
  9. package/dist-lib/components/DocumentenPage.js +16 -0
  10. package/dist-lib/components/LayoutsPage.d.ts +3 -1
  11. package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
  12. package/dist-lib/components/LayoutsPage.js +3 -2
  13. package/dist-lib/components/LayoutsPrintersTabPage.d.ts +2 -0
  14. package/dist-lib/components/LayoutsPrintersTabPage.d.ts.map +1 -0
  15. package/dist-lib/components/LayoutsPrintersTabPage.js +32 -0
  16. package/dist-lib/components/LogosPage.d.ts +3 -1
  17. package/dist-lib/components/LogosPage.d.ts.map +1 -1
  18. package/dist-lib/components/LogosPage.js +3 -2
  19. package/dist-lib/components/ModuleTabs.d.ts +19 -0
  20. package/dist-lib/components/ModuleTabs.d.ts.map +1 -0
  21. package/dist-lib/components/ModuleTabs.js +17 -0
  22. package/dist-lib/components/PakbonBuilderPage.d.ts.map +1 -1
  23. package/dist-lib/components/PakbonBuilderPage.js +30 -4
  24. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  25. package/dist-lib/components/PrintQueuePage.js +15 -2
  26. package/dist-lib/components/PrintenPage.d.ts +4 -0
  27. package/dist-lib/components/PrintenPage.d.ts.map +1 -0
  28. package/dist-lib/components/PrintenPage.js +21 -0
  29. package/dist-lib/components/PrinterSetupWizard.js +3 -3
  30. package/dist-lib/components/PrintersPage.d.ts +3 -1
  31. package/dist-lib/components/PrintersPage.d.ts.map +1 -1
  32. package/dist-lib/components/PrintersPage.js +20 -38
  33. package/dist-lib/components/PrintersRedirectPage.d.ts +2 -0
  34. package/dist-lib/components/PrintersRedirectPage.d.ts.map +1 -0
  35. package/dist-lib/components/PrintersRedirectPage.js +14 -0
  36. package/dist-lib/components/PrintplekDetailPage.d.ts +2 -0
  37. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -0
  38. package/dist-lib/components/PrintplekDetailPage.js +93 -0
  39. package/dist-lib/components/PrintplekWizard.d.ts +8 -0
  40. package/dist-lib/components/PrintplekWizard.d.ts.map +1 -0
  41. package/dist-lib/components/PrintplekWizard.js +194 -0
  42. package/dist-lib/components/PrintplekkenPage.d.ts +4 -0
  43. package/dist-lib/components/PrintplekkenPage.d.ts.map +1 -0
  44. package/dist-lib/components/PrintplekkenPage.js +110 -0
  45. package/dist-lib/index.d.ts +15 -1
  46. package/dist-lib/index.d.ts.map +1 -1
  47. package/dist-lib/index.js +16 -7
  48. package/dist-lib/integrations/supabase/auth-middleware.d.ts +371 -0
  49. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  50. package/dist-lib/integrations/supabase/client.server.d.ts +371 -0
  51. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  52. package/dist-lib/integrations/supabase/types.d.ts +378 -0
  53. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  54. package/dist-lib/lib/aiLayout.functions.d.ts +371 -0
  55. package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
  56. package/dist-lib/lib/browserPrint.d.ts +4 -0
  57. package/dist-lib/lib/browserPrint.d.ts.map +1 -1
  58. package/dist-lib/lib/browserPrint.js +4 -0
  59. package/dist-lib/lib/pakbonHtml.d.ts +5 -2
  60. package/dist-lib/lib/pakbonHtml.d.ts.map +1 -1
  61. package/dist-lib/lib/pakbonHtml.js +5 -2
  62. package/dist-lib/lib/printApi.d.ts +23 -7
  63. package/dist-lib/lib/printApi.d.ts.map +1 -1
  64. package/dist-lib/lib/printApi.js +51 -15
  65. package/dist-lib/lib/printQueue.d.ts +28 -0
  66. package/dist-lib/lib/printQueue.d.ts.map +1 -0
  67. package/dist-lib/lib/printQueue.js +70 -0
  68. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  69. package/dist-lib/lib/printQueue.server.js +141 -18
  70. package/dist-lib/lib/printService.functions.d.ts +1484 -0
  71. package/dist-lib/lib/printService.functions.d.ts.map +1 -1
  72. package/dist-lib/lib/printplekWizard.d.ts +57 -0
  73. package/dist-lib/lib/printplekWizard.d.ts.map +1 -0
  74. package/dist-lib/lib/printplekWizard.js +87 -0
  75. package/dist-lib/lib/printplekken.d.ts +90 -0
  76. package/dist-lib/lib/printplekken.d.ts.map +1 -0
  77. package/dist-lib/lib/printplekken.js +244 -0
  78. package/dist-lib/lib/testpagina.d.ts.map +1 -1
  79. package/dist-lib/lib/testpagina.js +5 -5
  80. package/dist-lib/lib/useDocumentData.d.ts +6 -0
  81. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  82. package/dist-lib/lib/useDocumentData.js +31 -0
  83. package/package.json +14 -14
@@ -11,5 +11,10 @@ export interface AfdrukKnopProps {
11
11
  layoutId?: string | null;
12
12
  kopieen?: number;
13
13
  }
14
+ /**
15
+ * @deprecated Verouderd — deze knop gebruikt het browser-printvenster als
16
+ * terugval. Gebruik `printHtml()` / `printPdf()` uit `printApi` zodat alles
17
+ * via PrintNode loopt.
18
+ */
14
19
  export declare function AfdrukKnop({ documenttype, formaatCode, orientatie, getHtml, css, documentnaam, label, layoutId, kopieen, }: AfdrukKnopProps): import("react").JSX.Element;
15
20
  //# sourceMappingURL=AfdrukKnop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AfdrukKnop.d.ts","sourceRoot":"","sources":["../../src/components/AfdrukKnop.tsx"],"names":[],"mappings":"AASA,OAAO,EAAU,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAG9D,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,uEAAuE;IACvE,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,UAAU,CAAC,EACzB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,OAAO,EACP,GAAG,EACH,YAAY,EACZ,KAAmB,EACnB,QAAQ,EACR,OAAO,GACR,EAAE,eAAe,+BAwDjB"}
1
+ {"version":3,"file":"AfdrukKnop.d.ts","sourceRoot":"","sources":["../../src/components/AfdrukKnop.tsx"],"names":[],"mappings":"AASA,OAAO,EAAU,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAG9D,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,uEAAuE;IACvE,OAAO,EAAE,MAAM,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,OAAO,EACP,GAAG,EACH,YAAY,EACZ,KAAmB,EACnB,QAAQ,EACR,OAAO,GACR,EAAE,eAAe,+BAwDjB"}
@@ -9,6 +9,11 @@ import { Button, toast } from "@flowselections/core";
9
9
  import { Loader2, Printer } from "lucide-react";
10
10
  import { drukAf } from "../lib/browserPrint.js";
11
11
  import { printDirect } from "../lib/directPrint.js";
12
+ /**
13
+ * @deprecated Verouderd — deze knop gebruikt het browser-printvenster als
14
+ * terugval. Gebruik `printHtml()` / `printPdf()` uit `printApi` zodat alles
15
+ * via PrintNode loopt.
16
+ */
12
17
  export function AfdrukKnop({ documenttype, formaatCode, orientatie, getHtml, css, documentnaam, label = "Afdrukken", layoutId, kopieen, }) {
13
18
  const [bezig, setBezig] = useState(false);
14
19
  const afdrukken = async () => {
@@ -1,2 +1,4 @@
1
- export declare function DocumentRouteringPage(): import("react").JSX.Element;
1
+ export declare function DocumentRouteringPage({ ingebed }?: {
2
+ ingebed?: boolean;
3
+ }): import("react").JSX.Element;
2
4
  //# sourceMappingURL=DocumentRouteringPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DocumentRouteringPage.d.ts","sourceRoot":"","sources":["../../src/components/DocumentRouteringPage.tsx"],"names":[],"mappings":"AA2CA,wBAAgB,qBAAqB,gCAiTpC"}
1
+ {"version":3,"file":"DocumentRouteringPage.d.ts","sourceRoot":"","sources":["../../src/components/DocumentRouteringPage.tsx"],"names":[],"mappings":"AAsCA,wBAAgB,qBAAqB,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BAmVpF"}
@@ -1,38 +1,41 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  // ============================================================================
3
3
  // src/components/DocumentRouteringPage.tsx — overzicht: welke documentsoort
4
- // gaat via welke werkplek naar welke printer.
4
+ // gaat standaard naar welke printer, en welk document daarvoor wordt gebruikt.
5
+ // Afwijkingen per plek staan bij de printplek zelf.
5
6
  // ============================================================================
6
7
  import { useMemo, useState } from "react";
7
- import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "@flowselections/core";
8
- import { Link } from "@tanstack/react-router";
9
- import { AlertTriangle, Monitor, Plus, Printer, Trash2 } from "lucide-react";
8
+ import { Badge, Card, CardContent, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, toast, } from "@flowselections/core";
9
+ import { AlertTriangle, ChevronDown, ChevronRight } from "lucide-react";
10
10
  import { DOCUMENT_TYPES, documentTypeLabel, isFloridayLayout } from "../lib/documentTypes.js";
11
11
  import { documentProfiel } from "../lib/documentProfiles.js";
12
12
  import { usePrinters } from "../lib/useDocumentData.js";
13
13
  import { useAlleFormaatPrinters, zetFormaatPrinter } from "../lib/formaatPrinters.js";
14
- import { BRONNEN, HERKOMSTEN, useBronregels, zetBronregel, } from "../lib/documentBron.js";
14
+ import { BRONNEN, HERKOMSTEN, useBronregels, zetBronregel } from "../lib/documentBron.js";
15
15
  import { useLayouts } from "../lib/useDocumentData.js";
16
- import { useWerkplekPrinters, verwijderWerkplekPrinter, zetWerkplekPrinter, } from "../lib/documentRoutering.js";
17
- import { useComputers } from "./ComputersLijst.js";
18
16
  const GEEN = "geen";
19
- export function DocumentRouteringPage() {
17
+ /**
18
+ * Documentsoorten die de Logistiek Engine naar de wachtrij stuurt. Die kiest
19
+ * zelf geen printer meer, dus zonder standaardregel blijft zo'n opdracht
20
+ * liggen. Daarom staan ze altijd bovenaan met een waarschuwing.
21
+ */
22
+ const ENGINE_TYPES = ["pakbon", "sticker", "transportdocument", "productiebon"];
23
+ export function DocumentRouteringPage({ ingebed = false } = {}) {
20
24
  const { printers } = usePrinters();
21
- const { computers } = useComputers();
22
25
  const { koppelingen: standaard, reload: herlaadStandaard } = useAlleFormaatPrinters();
23
- const { koppelingen: werkplekken, reload: herlaadWerkplekken } = useWerkplekPrinters();
24
26
  const { regels, reload: herlaadRegels } = useBronregels();
25
27
  const { layouts } = useLayouts();
26
28
  const [zoek, setZoek] = useState("");
27
- const [nieuw, setNieuw] = useState(null);
28
- const [nieuweWerkplek, setNieuweWerkplek] = useState("");
29
- const [nieuwePrinter, setNieuwePrinter] = useState(GEEN);
29
+ const [gekozen, setGekozen] = useState("pakbon");
30
+ const [toonRest, setToonRest] = useState(false);
31
+ const [toonUitleg, setToonUitleg] = useState(false);
32
+ const [toonGeavanceerd, setToonGeavanceerd] = useState(false);
30
33
  const printerNaam = (id) => printers.find((p) => p.id === id)?.naam ?? "Onbekende printer";
31
34
  const standaardFormaat = (type) => documentProfiel(type).formaten[0]?.code ?? "A4";
35
+ const actieveLayouts = (type) => layouts.filter((l) => l.documenttype === type && l.actief);
32
36
  /** Formaat zoals de gebruiker het ziet: dat van de actieve layouts zelf. */
33
37
  const weergaveFormaat = (type) => {
34
- const eigen = Array.from(new Set(layouts
35
- .filter((l) => l.documenttype === type && l.actief)
38
+ const eigen = Array.from(new Set(actieveLayouts(type)
36
39
  .map((l) => l.papierformaat)
37
40
  .filter((f) => !!f)));
38
41
  if (eigen.length === 1)
@@ -43,11 +46,26 @@ export function DocumentRouteringPage() {
43
46
  };
44
47
  const standaardVoor = (type) => standaard.find((k) => k.documenttype === type && k.formaat_code === standaardFormaat(type))
45
48
  ?.printer_id ?? null;
46
- const werkplekkenVoor = (type) => werkplekken.filter((w) => w.documenttype === type);
47
- const rijen = useMemo(() => {
48
- const term = zoek.trim().toLowerCase();
49
- return DOCUMENT_TYPES.filter((d) => (term ? d.label.toLowerCase().includes(term) : true));
50
- }, [zoek]);
49
+ const bronVan = (type, herkomst) => regels.find((r) => r.documenttype === type && r.herkomst === herkomst);
50
+ /** In gebruik = er is een actieve layout of er is iets ingesteld. */
51
+ const inGebruik = (type) => actieveLayouts(type).length > 0 ||
52
+ !!standaardVoor(type) ||
53
+ regels.some((r) => r.documenttype === type && r.bron !== "auto");
54
+ const term = zoek.trim().toLowerCase();
55
+ const gefilterd = useMemo(() => DOCUMENT_TYPES.filter((d) => (term ? d.label.toLowerCase().includes(term) : true)), [term]);
56
+ const engine = gefilterd.filter((d) => ENGINE_TYPES.includes(d.value));
57
+ const overig = gefilterd.filter((d) => !ENGINE_TYPES.includes(d.value));
58
+ const actief = overig.filter((d) => inGebruik(d.value));
59
+ const rest = overig.filter((d) => !inGebruik(d.value));
60
+ const aantalIngesteld = DOCUMENT_TYPES.filter((d) => !!standaardVoor(d.value)).length;
61
+ const huidig = gekozen;
62
+ const std = standaardVoor(huidig);
63
+ const bronSamenvatting = HERKOMSTEN.map((h) => {
64
+ const r = bronVan(huidig, h.value);
65
+ if (!r || r.bron === "auto")
66
+ return null;
67
+ return `${h.label}: ${BRONNEN.find((b) => b.value === r.bron)?.label ?? r.bron}`;
68
+ }).filter((s) => !!s);
51
69
  const kiesStandaard = async (type, printerId) => {
52
70
  try {
53
71
  await zetFormaatPrinter(type, standaardFormaat(type), printerId === GEEN ? null : printerId);
@@ -58,24 +76,6 @@ export function DocumentRouteringPage() {
58
76
  toast.error("Opslaan mislukt");
59
77
  }
60
78
  };
61
- const voegWerkplekToe = async (type) => {
62
- if (!nieuweWerkplek.trim()) {
63
- toast.error("Kies eerst een werkplek");
64
- return;
65
- }
66
- try {
67
- await zetWerkplekPrinter(type, nieuweWerkplek, nieuwePrinter === GEEN ? null : nieuwePrinter, standaardFormaat(type));
68
- await herlaadWerkplekken();
69
- setNieuw(null);
70
- setNieuweWerkplek("");
71
- setNieuwePrinter(GEEN);
72
- toast.success("Werkplek gekoppeld");
73
- }
74
- catch {
75
- toast.error("Opslaan mislukt");
76
- }
77
- };
78
- const bronVan = (type, herkomst) => regels.find((r) => r.documenttype === type && r.herkomst === herkomst);
79
79
  const kiesBron = async (type, herkomst, bron, layoutId) => {
80
80
  try {
81
81
  await zetBronregel(type, herkomst, bron, layoutId ?? null);
@@ -86,30 +86,32 @@ export function DocumentRouteringPage() {
86
86
  toast.error("Opslaan mislukt");
87
87
  }
88
88
  };
89
- const verwijder = async (id) => {
90
- try {
91
- await verwijderWerkplekPrinter(id);
92
- await herlaadWerkplekken();
93
- toast.success("Uitzondering verwijderd");
94
- }
95
- catch {
96
- toast.error("Verwijderen mislukt");
97
- }
89
+ const kies = (type) => {
90
+ setGekozen(type);
91
+ setToonGeavanceerd(false);
92
+ };
93
+ const LijstItem = ({ type, label }) => {
94
+ const printerId = standaardVoor(type);
95
+ const gekozenItem = huidig === type;
96
+ const engineType = ENGINE_TYPES.includes(type);
97
+ const geenLayout = actieveLayouts(type).length === 0;
98
+ const waarschuw = engineType
99
+ ? !printerId || geenLayout
100
+ : !printerId && actieveLayouts(type).length > 0;
101
+ const melding = !printerId
102
+ ? "Geen standaardprinter"
103
+ : geenLayout && engineType
104
+ ? "Geen actieve layout"
105
+ : printerNaam(printerId);
106
+ return (_jsxs("button", { type: "button", onClick: () => kies(type), className: `w-full rounded-md px-3 py-2 text-left transition-colors ${gekozenItem ? "bg-primary/10 text-primary" : "hover:bg-muted"}`, children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: label }), waarschuw && _jsx(AlertTriangle, { className: "text-destructive h-3.5 w-3.5 shrink-0" })] }), _jsx("span", { className: `block truncate text-xs ${waarschuw ? "text-destructive" : "text-muted-foreground"}`, children: melding })] }));
98
107
  };
99
- 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: "Documentroutering" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Bepaal per documentsoort welke printer wordt gebruikt, en welke printer geldt op een specifieke werkplek." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { className: "w-56", placeholder: "Zoek documentsoort", value: zoek, onChange: (e) => setZoek(e.target.value) }), _jsx(Button, { variant: "outline", asChild: true, children: _jsxs(Link, { to: "/layouts-printers/printers", children: [_jsx(Printer, { className: "mr-2 h-4 w-4" }), " Printers"] }) })] })] }), _jsx(Card, { children: _jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Keuzevolgorde" }), _jsx(CardDescription, { children: "1. printer die de module meestuurt \u00B7 2. uitzondering voor de werkplek \u00B7 3. printer gekoppeld aan het ontwerp \u00B7 4. standaardprinter hieronder \u00B7 5. is er maar \u00E9\u00E9n actieve printer, dan die \u00B7 6. anders blijft de opdracht wachten in de printwachtrij." })] }) }), _jsx("div", { className: "space-y-3", children: rijen.map((d) => {
100
- const uitzonderingen = werkplekkenVoor(d.value);
101
- const std = standaardVoor(d.value);
102
- const zonderPrinter = !std && uitzonderingen.length === 0;
103
- return (_jsxs(Card, { children: [_jsxs(CardContent, { className: "grid gap-4 py-4 lg:grid-cols-[220px_260px_1fr]", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "font-medium", children: documentTypeLabel(d.value) }), _jsx("p", { className: "text-muted-foreground text-xs", children: weergaveFormaat(d.value) }), zonderPrinter && (_jsxs("p", { className: "text-destructive mt-1 flex items-center gap-1 text-xs", children: [_jsx(AlertTriangle, { className: "h-3.5 w-3.5" }), " Geen printer ingesteld"] }))] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-xs uppercase", children: "Standaardprinter" }), _jsxs(Select, { value: std ?? GEEN, onValueChange: (v) => void kiesStandaard(d.value, v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Geen printer" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: GEEN, children: "Geen printer" }), printers.map((p) => (_jsx(SelectItem, { value: p.id, children: p.naam }, p.id)))] })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-muted-foreground text-xs uppercase", children: "Per werkplek" }), uitzonderingen.map((w) => (_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(Monitor, { className: "text-muted-foreground h-4 w-4 shrink-0" }), _jsxs("span", { className: "min-w-0 flex-1 truncate", children: [w.werkplek, " \u2192 ", printerNaam(w.printer_id)] }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void verwijder(w.id), children: _jsx(Trash2, { className: "h-4 w-4" }) })] }, w.id))), nieuw === d.value ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Select, { value: nieuweWerkplek, onValueChange: setNieuweWerkplek, children: [_jsx(SelectTrigger, { className: "w-48", children: _jsx(SelectValue, { placeholder: "Kies werkplek" }) }), _jsx(SelectContent, { children: computers.map((c) => (_jsx(SelectItem, { value: c.naam, children: c.naam }, c.id))) })] }), _jsxs(Select, { value: nieuwePrinter, onValueChange: setNieuwePrinter, children: [_jsx(SelectTrigger, { className: "w-48", children: _jsx(SelectValue, { placeholder: "Kies printer" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: GEEN, children: "Geen printer" }), printers.map((p) => (_jsx(SelectItem, { value: p.id, children: p.naam }, p.id)))] })] }), _jsx(Button, { size: "sm", onClick: () => void voegWerkplekToe(d.value), children: "Opslaan" }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => setNieuw(null), children: "Annuleren" })] })) : (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
104
- setNieuw(d.value);
105
- setNieuweWerkplek("");
106
- setNieuwePrinter(GEEN);
107
- }, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Werkplek toevoegen"] }))] })] }), _jsxs(CardContent, { className: "border-t pt-4", children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs uppercase", children: "Bron per herkomst" }), _jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: HERKOMSTEN.map((h) => {
108
- const regel = bronVan(d.value, h.value);
109
- const huidig = regel?.bron ?? "auto";
110
- return (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "w-32 shrink-0 text-sm", children: h.label }), _jsxs(Select, { value: huidig, onValueChange: (v) => void kiesBron(d.value, h.value, v, regel?.layout_id ?? null), children: [_jsx(SelectTrigger, { className: "w-52", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: BRONNEN.map((b) => (_jsx(SelectItem, { value: b.value, children: b.label }, b.value))) })] }), huidig === "eigen_layout" && (_jsxs(Select, { value: regel?.layout_id ?? GEEN, onValueChange: (v) => void kiesBron(d.value, h.value, "eigen_layout", v === GEEN ? null : v), children: [_jsx(SelectTrigger, { className: "w-52", children: _jsx(SelectValue, { placeholder: "Standaardontwerp" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: GEEN, children: "Standaardontwerp" }), layouts
111
- .filter((l) => l.documenttype === d.value)
112
- .map((l) => (_jsxs(SelectItem, { value: l.id, children: [l.naam, isFloridayLayout(l) ? " (uit Floriday)" : ""] }, l.id)))] })] }))] }, h.value));
113
- }) })] })] }, d.value));
114
- }) })] }));
108
+ const Wrapper = ingebed ? "div" : "main";
109
+ return (_jsxs(Wrapper, { className: ingebed ? "space-y-5" : "space-y-5 p-6", children: [_jsxs("header", { className: "flex flex-wrap items-end justify-between gap-4", children: [_jsxs("p", { className: "text-muted-foreground text-sm", children: [aantalIngesteld, " van ", DOCUMENT_TYPES.length, " documentsoorten hebben een standaardprinter. Deze geldt als er geen printplek is meegegeven."] }), _jsx(Input, { className: "w-full sm:w-56", placeholder: "Zoek documentsoort", value: zoek, onChange: (e) => setZoek(e.target.value) })] }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setToonUitleg((v) => !v), className: "text-muted-foreground hover:text-foreground flex items-center gap-1 text-sm", children: [toonUitleg ? (_jsx(ChevronDown, { className: "h-4 w-4" })) : (_jsx(ChevronRight, { className: "h-4 w-4" })), "Hoe wordt de printer gekozen?"] }), toonUitleg && (_jsx(Card, { className: "mt-2", children: _jsx(CardContent, { className: "text-muted-foreground py-3 text-sm", children: "1. de printer die op de opdracht zelf staat \u00B7 2. de documentregel van de printplek (bijv. het pickstation) \u00B7 3. de printer die aan het ontwerp hangt \u00B7 4. de standaardprinter hieronder \u00B7 anders blijft de opdracht liggen met een melding welke instelling ontbreekt." }) }))] }), _jsxs("div", { className: "grid gap-4 lg:grid-cols-[280px_minmax(0,1fr)]", children: [_jsx(Card, { className: "min-w-0 self-start lg:sticky lg:top-4", children: _jsxs(CardContent, { className: "space-y-1 py-3", children: [engine.length > 0 && (_jsxs(_Fragment, { children: [_jsx("p", { className: "text-muted-foreground px-3 pb-1 text-xs uppercase", children: "Logistiek (pickstations)" }), engine.map((d) => (_jsx(LijstItem, { type: d.value, label: d.label }, d.value))), _jsx(Separator, { className: "my-2" })] })), _jsx("p", { className: "text-muted-foreground px-3 pb-1 text-xs uppercase", children: "In gebruik" }), actief.length === 0 && (_jsx("p", { className: "text-muted-foreground px-3 pb-2 text-sm", children: "Nog niets in gebruik." })), actief.map((d) => (_jsx(LijstItem, { type: d.value, label: d.label }, d.value))), rest.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Separator, { className: "my-2" }), _jsxs("button", { type: "button", onClick: () => setToonRest((v) => !v), className: "text-muted-foreground hover:text-foreground flex w-full items-center gap-1 px-3 py-1 text-xs uppercase", children: [toonRest ? (_jsx(ChevronDown, { className: "h-3.5 w-3.5" })) : (_jsx(ChevronRight, { className: "h-3.5 w-3.5" })), "Nog niet ingesteld (", rest.length, ")"] }), toonRest &&
110
+ rest.map((d) => _jsx(LijstItem, { type: d.value, label: d.label }, d.value))] }))] }) }), _jsx(Card, { className: "min-w-0", children: _jsxs(CardContent, { className: "space-y-6 py-5", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("h2", { className: "text-lg font-semibold", children: documentTypeLabel(huidig) }), _jsx(Badge, { variant: "secondary", children: weergaveFormaat(huidig) }), actieveLayouts(huidig).length > 0 && (_jsxs(Badge, { variant: "outline", children: [actieveLayouts(huidig).length, " actief ontwerp", actieveLayouts(huidig).length === 1 ? "" : "en"] }))] }), !std && (_jsxs("p", { className: "text-destructive mt-1 flex items-center gap-1 text-sm", children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), " Nog geen printer gekozen \u2014 opdrachten blijven wachten in de printwachtrij."] }))] }), _jsxs("div", { className: "max-w-md space-y-1.5", children: [_jsx("p", { className: "text-sm font-medium", children: "Standaardprinter (bedrijfsbreed)" }), _jsxs(Select, { value: std ?? GEEN, onValueChange: (v) => void kiesStandaard(huidig, v), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Geen printer" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: GEEN, children: "Geen printer" }), printers.map((p) => (_jsx(SelectItem, { value: p.id, children: p.naam }, p.id)))] })] }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Wordt gebruikt als de opdracht geen printplek meegeeft. Per printplek stel je een afwijkende printer in met de printplek-wizard." })] }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setToonGeavanceerd((v) => !v), className: "text-muted-foreground hover:text-foreground flex items-center gap-1 text-sm", children: [toonGeavanceerd || bronSamenvatting.length > 0 ? (_jsx(ChevronDown, { className: "h-4 w-4" })) : (_jsx(ChevronRight, { className: "h-4 w-4" })), "Geavanceerd: welk document wordt gebruikt", bronSamenvatting.length > 0 ? ` · ${bronSamenvatting.join(" · ")}` : ""] }), (toonGeavanceerd || bronSamenvatting.length > 0) && (_jsxs("div", { className: "mt-3 space-y-3", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: "Kies of het meegestuurde document van Floriday wordt afgedrukt of een eigen ontwerp uit deze module." }), HERKOMSTEN.map((h) => {
111
+ const regel = bronVan(huidig, h.value);
112
+ const bron = regel?.bron ?? "auto";
113
+ return (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "w-32 shrink-0 text-sm", children: h.label }), _jsxs(Select, { value: bron, onValueChange: (v) => void kiesBron(huidig, h.value, v, regel?.layout_id ?? null), children: [_jsx(SelectTrigger, { className: "w-52", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: BRONNEN.map((b) => (_jsx(SelectItem, { value: b.value, children: b.label }, b.value))) })] }), bron === "eigen_layout" && (_jsxs(Select, { value: regel?.layout_id ?? GEEN, onValueChange: (v) => void kiesBron(huidig, h.value, "eigen_layout", v === GEEN ? null : v), children: [_jsx(SelectTrigger, { className: "w-52", children: _jsx(SelectValue, { placeholder: "Standaardontwerp" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: GEEN, children: "Standaardontwerp" }), layouts
114
+ .filter((l) => l.documenttype === huidig)
115
+ .map((l) => (_jsxs(SelectItem, { value: l.id, children: [l.naam, isFloridayLayout(l) ? " (uit Floriday)" : ""] }, l.id)))] })] }))] }, h.value));
116
+ })] }))] })] }) })] })] }));
115
117
  }
@@ -0,0 +1,4 @@
1
+ export declare function DocumentenPage({ tab }: {
2
+ tab?: "layouts" | "logos";
3
+ }): import("react").JSX.Element;
4
+ //# sourceMappingURL=DocumentenPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DocumentenPage.d.ts","sourceRoot":"","sources":["../../src/components/DocumentenPage.tsx"],"names":[],"mappings":"AAeA,wBAAgB,cAAc,CAAC,EAAE,GAAe,EAAE,EAAE;IAAE,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;CAAE,+BAUhF"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/DocumentenPage.tsx — één menu-item "Documenten" met tabbladen
4
+ // voor de documentontwerpen en de logobibliotheek.
5
+ // ============================================================================
6
+ import { FileText, Image } from "lucide-react";
7
+ import { ModuleTabs } from "./ModuleTabs.js";
8
+ import { LayoutsPage } from "./LayoutsPage.js";
9
+ import { LogosPage } from "./LogosPage.js";
10
+ const TABS = [
11
+ { label: "Documenten", href: "/layouts-printers", icon: FileText },
12
+ { label: "Logo's", href: "/layouts-printers/logos", icon: Image },
13
+ ];
14
+ export function DocumentenPage({ tab = "layouts" }) {
15
+ return (_jsx(ModuleTabs, { titel: "Documenten", omschrijving: "Ontwerp pakbonnen, facturen, stickers en beheer de logo's die daarop staan.", tabs: TABS, children: tab === "logos" ? _jsx(LogosPage, { ingebed: true }) : _jsx(LayoutsPage, { ingebed: true }) }));
16
+ }
@@ -1,2 +1,4 @@
1
- export declare function LayoutsPage(): import("react").JSX.Element;
1
+ export declare function LayoutsPage({ ingebed }?: {
2
+ ingebed?: boolean;
3
+ }): import("react").JSX.Element;
2
4
  //# sourceMappingURL=LayoutsPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LayoutsPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPage.tsx"],"names":[],"mappings":"AAgEA,wBAAgB,WAAW,gCA4kB1B"}
1
+ {"version":3,"file":"LayoutsPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPage.tsx"],"names":[],"mappings":"AAgEA,wBAAgB,WAAW,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BA+kB1E"}
@@ -13,7 +13,7 @@ function klantOntwerpLayout(l) {
13
13
  const cfg = (l.config ?? {});
14
14
  return Boolean(cfg?.klantlayout?.gebruik_klantlayout);
15
15
  }
16
- export function LayoutsPage() {
16
+ export function LayoutsPage({ ingebed = false } = {}) {
17
17
  const { layouts, loading, reload } = useLayouts();
18
18
  useAutoRefresh(() => reload(true), 30000);
19
19
  const navigate = useNavigate();
@@ -144,7 +144,8 @@ export function LayoutsPage() {
144
144
  setBezig(false);
145
145
  }
146
146
  };
147
- return (_jsxs("main", { className: "p-6 space-y-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: "Documentlayouts" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Ontwerp pakbonnen, facturen, etiketten en alle andere documenten." })] }), _jsx("div", { className: "flex gap-2", children: _jsxs(Button, { onClick: () => setWizardOpen(true), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Nieuwe layout"] }) })] }), _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" }), _jsx(TableHead, { children: "Versie" }), _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 }))] }), _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"] }), _jsxs(TableCell, { children: ["v", l.huidige_versie] }), _jsx(TableCell, { children: _jsx(Switch, { checked: l.actief, onCheckedChange: async (v) => {
147
+ const Wrapper = ingebed ? "div" : "main";
148
+ return (_jsxs(Wrapper, { className: ingebed ? "space-y-6" : "p-6 space-y-6", children: [_jsxs("div", { className: "flex flex-wrap items-end justify-between gap-4", children: [!ingebed && (_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold", children: "Documentlayouts" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Ontwerp pakbonnen, facturen, etiketten en alle andere documenten." })] })), _jsx("div", { className: "ml-auto flex gap-2", children: _jsxs(Button, { onClick: () => setWizardOpen(true), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Nieuwe layout"] }) })] }), _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" }), _jsx(TableHead, { children: "Actief" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsxs(TableBody, { children: [gefilterd.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 5, 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 }))] }), _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, { children: _jsx(Switch, { checked: l.actief, onCheckedChange: async (v) => {
148
149
  await updateLayout(l.id, { actief: v });
149
150
  void reload();
150
151
  } }) }), _jsx(TableCell, { className: "text-right", children: _jsxs("div", { className: "flex justify-end gap-1", children: [isFloridayLayout(l) ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "Niet aanpasbaar \u2014 komt uit Floriday" })) : klantOntwerpLayout(l) ? (_jsx(Badge, { variant: "outline", children: "Ontwerp van klant" })) : (_jsxs(Button, { variant: "ghost", size: "sm", onClick: () => navigate(l.documenttype === "productiebon"
@@ -0,0 +1,2 @@
1
+ export declare function LayoutsPrintersTabPage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=LayoutsPrintersTabPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LayoutsPrintersTabPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPrintersTabPage.tsx"],"names":[],"mappings":"AAeA,wBAAgB,sBAAsB,gCAmBrC"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/LayoutsPrintersTabPage.tsx — één pagina die de tabblad-URL's
4
+ // van de module bedient (/layouts-printers/logos, /routering, /printers).
5
+ // ============================================================================
6
+ import { useEffect } from "react";
7
+ import { useNavigate, useRouterState } from "@tanstack/react-router";
8
+ import { DocumentenPage } from "./DocumentenPage.js";
9
+ import { PrintenPage } from "./PrintenPage.js";
10
+ function huidigTab(pathname) {
11
+ const delen = pathname.split("/").filter(Boolean);
12
+ return delen[delen.length - 1] ?? "";
13
+ }
14
+ export function LayoutsPrintersTabPage() {
15
+ const navigate = useNavigate();
16
+ const pathname = useRouterState({ select: (s) => s.location.pathname });
17
+ const tab = huidigTab(pathname);
18
+ const stuurDoor = tab === "printers"
19
+ ? "/layouts-printers/printplekken"
20
+ : tab === "logos" || tab === "routering"
21
+ ? null
22
+ : "/layouts-printers";
23
+ useEffect(() => {
24
+ if (stuurDoor)
25
+ void navigate({ to: stuurDoor, replace: true });
26
+ }, [stuurDoor, navigate]);
27
+ if (tab === "logos")
28
+ return _jsx(DocumentenPage, { tab: "logos" });
29
+ if (tab === "routering")
30
+ return _jsx(PrintenPage, { tab: "routering" });
31
+ return _jsx("p", { className: "text-muted-foreground p-6 text-sm", children: "Doorsturen\u2026" });
32
+ }
@@ -3,5 +3,7 @@ export declare function LogoThumbnail({ logo, className }: {
3
3
  logo: LogoModel;
4
4
  className?: string;
5
5
  }): import("react").JSX.Element;
6
- export declare function LogosPage(): import("react").JSX.Element;
6
+ export declare function LogosPage({ ingebed }?: {
7
+ ingebed?: boolean;
8
+ }): import("react").JSX.Element;
7
9
  //# sourceMappingURL=LogosPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LogosPage.d.ts","sourceRoot":"","sources":["../../src/components/LogosPage.tsx"],"names":[],"mappings":"AAkCA,OAAO,EAaL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,SAAc,EAAE,EAAE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BAY9F;AASD,wBAAgB,SAAS,gCA4LxB"}
1
+ {"version":3,"file":"LogosPage.d.ts","sourceRoot":"","sources":["../../src/components/LogosPage.tsx"],"names":[],"mappings":"AAkCA,OAAO,EAaL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,SAAc,EAAE,EAAE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BAY9F;AASD,wBAAgB,SAAS,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BA8LxE"}
@@ -7,7 +7,7 @@ import { LOGO_CATEGORIEEN, TOEGESTANE_LOGO_TYPES, downloadLogo, formatteerBytes,
7
7
  export function LogoThumbnail({ logo, className = "" }) {
8
8
  return (_jsx("div", { className: `flex h-12 w-16 items-center justify-center overflow-hidden rounded border bg-[repeating-conic-gradient(#e5e7eb_0%_25%,#fff_0%_50%)] bg-[length:10px_10px] ${className}`, children: logo.viewUrl ? (_jsx("img", { src: logo.viewUrl, alt: logo.naam, className: "max-h-full max-w-full object-contain" })) : (_jsx(ImagePlus, { className: "h-4 w-4 text-muted-foreground" })) }));
9
9
  }
10
- export function LogosPage() {
10
+ export function LogosPage({ ingebed = false } = {}) {
11
11
  const { logos, loading, reload } = useLogos();
12
12
  const { opslagFout, controleer } = useLogoOpslag();
13
13
  const [zoek, setZoek] = useState("");
@@ -42,7 +42,8 @@ export function LogosPage() {
42
42
  toast.error("Verwijderen mislukt");
43
43
  }
44
44
  };
45
- return (_jsxs("main", { className: "flex-1 space-y-6 p-6", children: [opslagFout ? (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-md border border-destructive/40 bg-destructive/10 p-4 text-sm text-destructive", children: [_jsx("span", { children: opslagFout }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => void controleer(), children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), " Opnieuw controleren"] })] })) : null, _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex-row flex-wrap items-end justify-between gap-3 space-y-0", children: [_jsxs("div", { children: [_jsx(CardTitle, { children: "Logo Bibliotheek" }), _jsx(CardDescription, { children: "Centraal beheer van alle bedrijfslogo's. Layouts verwijzen naar deze bibliotheek, dus een vervangen logo werkt direct door in elke layout." })] }), _jsxs(Button, { onClick: () => setUploadOpen(true), disabled: !!opslagFout, title: opslagFout ?? undefined, children: [_jsx(Upload, { className: "mr-2 h-4 w-4" }), " Logo's uploaden"] })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap gap-3", children: [_jsx(Input, { placeholder: "Zoek op naam of omschrijving\u2026", value: zoek, onChange: (e) => setZoek(e.target.value), className: "max-w-xs" }), _jsxs(Select, { value: categorie, onValueChange: setCategorie, children: [_jsx(SelectTrigger, { className: "w-52", children: _jsx(SelectValue, { placeholder: "Categorie" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle categorie\u00EBn" }), LOGO_CATEGORIEEN.map((c) => (_jsx(SelectItem, { value: c.value, children: c.label }, c.value)))] })] })] }), _jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Voorbeeld" }), _jsx(TableHead, { children: "Naam" }), _jsx(TableHead, { children: "Omschrijving" }), _jsx(TableHead, { children: "Categorie" }), _jsx(TableHead, { children: "Formaat" }), _jsx(TableHead, { children: "Resolutie" }), _jsx(TableHead, { children: "Transparant" }), _jsx(TableHead, { children: "Toegevoegd" }), _jsx(TableHead, { children: "Gewijzigd" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsxs(TableBody, { children: [loading && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 10, children: "Laden\u2026" }) })), !loading && zichtbaar.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 10, className: "text-muted-foreground", children: "Nog geen logo's gevonden." }) })), zichtbaar.map((l) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(LogoThumbnail, { logo: l }) }), _jsxs(TableCell, { className: "font-medium", children: [l.naam, l.is_standaard && (_jsx(Badge, { variant: "secondary", className: "ml-2", children: "Standaard" }))] }), _jsx(TableCell, { className: "max-w-56 truncate text-muted-foreground", children: l.omschrijving }), _jsx(TableCell, { children: logoCategorieLabel(l.categorie) }), _jsx(TableCell, { className: "uppercase", children: l.bestandstype }), _jsxs(TableCell, { children: [l.breedte && l.hoogte ? `${l.breedte} × ${l.hoogte} px` : "—", _jsx("div", { className: "text-xs text-muted-foreground", children: formatteerBytes(l.bestandsgrootte) })] }), _jsx(TableCell, { children: l.transparant ? "Ja" : "Nee" }), _jsx(TableCell, { children: new Date(l.created_at).toLocaleDateString("nl-NL") }), _jsx(TableCell, { children: new Date(l.updated_at).toLocaleDateString("nl-NL") }), _jsx(TableCell, { children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsx(Button, { variant: "ghost", size: "icon", title: "Bewerken", onClick: () => setBewerk(l), children: _jsx(Pencil, { className: "h-4 w-4" }) }), _jsxs("label", { title: "Vervangen", children: [_jsx("input", { type: "file", className: "hidden", accept: TOEGESTANE_LOGO_TYPES.join(","), onChange: (e) => {
45
+ const Wrapper = ingebed ? "div" : "main";
46
+ return (_jsxs(Wrapper, { className: ingebed ? "space-y-6" : "flex-1 space-y-6 p-6", children: [opslagFout ? (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-md border border-destructive/40 bg-destructive/10 p-4 text-sm text-destructive", children: [_jsx("span", { children: opslagFout }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => void controleer(), children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), " Opnieuw controleren"] })] })) : null, _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex-row flex-wrap items-end justify-between gap-3 space-y-0", children: [_jsxs("div", { children: [_jsx(CardTitle, { children: "Logo Bibliotheek" }), _jsx(CardDescription, { children: "Centraal beheer van alle bedrijfslogo's. Layouts verwijzen naar deze bibliotheek, dus een vervangen logo werkt direct door in elke layout." })] }), _jsxs(Button, { onClick: () => setUploadOpen(true), disabled: !!opslagFout, title: opslagFout ?? undefined, children: [_jsx(Upload, { className: "mr-2 h-4 w-4" }), " Logo's uploaden"] })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap gap-3", children: [_jsx(Input, { placeholder: "Zoek op naam of omschrijving\u2026", value: zoek, onChange: (e) => setZoek(e.target.value), className: "max-w-xs" }), _jsxs(Select, { value: categorie, onValueChange: setCategorie, children: [_jsx(SelectTrigger, { className: "w-52", children: _jsx(SelectValue, { placeholder: "Categorie" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Alle categorie\u00EBn" }), LOGO_CATEGORIEEN.map((c) => (_jsx(SelectItem, { value: c.value, children: c.label }, c.value)))] })] })] }), _jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Voorbeeld" }), _jsx(TableHead, { children: "Naam" }), _jsx(TableHead, { children: "Omschrijving" }), _jsx(TableHead, { children: "Categorie" }), _jsx(TableHead, { children: "Formaat" }), _jsx(TableHead, { children: "Resolutie" }), _jsx(TableHead, { children: "Transparant" }), _jsx(TableHead, { children: "Toegevoegd" }), _jsx(TableHead, { children: "Gewijzigd" }), _jsx(TableHead, { className: "text-right", children: "Acties" })] }) }), _jsxs(TableBody, { children: [loading && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 10, children: "Laden\u2026" }) })), !loading && zichtbaar.length === 0 && (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 10, className: "text-muted-foreground", children: "Nog geen logo's gevonden." }) })), zichtbaar.map((l) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: _jsx(LogoThumbnail, { logo: l }) }), _jsxs(TableCell, { className: "font-medium", children: [l.naam, l.is_standaard && (_jsx(Badge, { variant: "secondary", className: "ml-2", children: "Standaard" }))] }), _jsx(TableCell, { className: "max-w-56 truncate text-muted-foreground", children: l.omschrijving }), _jsx(TableCell, { children: logoCategorieLabel(l.categorie) }), _jsx(TableCell, { className: "uppercase", children: l.bestandstype }), _jsxs(TableCell, { children: [l.breedte && l.hoogte ? `${l.breedte} × ${l.hoogte} px` : "—", _jsx("div", { className: "text-xs text-muted-foreground", children: formatteerBytes(l.bestandsgrootte) })] }), _jsx(TableCell, { children: l.transparant ? "Ja" : "Nee" }), _jsx(TableCell, { children: new Date(l.created_at).toLocaleDateString("nl-NL") }), _jsx(TableCell, { children: new Date(l.updated_at).toLocaleDateString("nl-NL") }), _jsx(TableCell, { children: _jsxs("div", { className: "flex justify-end gap-1", children: [_jsx(Button, { variant: "ghost", size: "icon", title: "Bewerken", onClick: () => setBewerk(l), children: _jsx(Pencil, { className: "h-4 w-4" }) }), _jsxs("label", { title: "Vervangen", children: [_jsx("input", { type: "file", className: "hidden", accept: TOEGESTANE_LOGO_TYPES.join(","), onChange: (e) => {
46
47
  const f = e.target.files?.[0];
47
48
  if (f)
48
49
  void vervang(l, f);
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ import type { LucideIcon } from "lucide-react";
3
+ export interface ModuleTab {
4
+ label: string;
5
+ href: string;
6
+ icon?: LucideIcon;
7
+ /** Extra paden die dit tabblad actief maken (bijv. detailpagina's). */
8
+ ook?: string[];
9
+ }
10
+ interface Props {
11
+ titel: string;
12
+ omschrijving?: string;
13
+ tabs: ModuleTab[];
14
+ acties?: ReactNode;
15
+ children: ReactNode;
16
+ }
17
+ export declare function ModuleTabs({ titel, omschrijving, tabs, acties, children }: Props): import("react").JSX.Element;
18
+ export {};
19
+ //# sourceMappingURL=ModuleTabs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModuleTabs.d.ts","sourceRoot":"","sources":["../../src/components/ModuleTabs.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,KAAK,+BA2ChF"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Link, useRouterState } from "@tanstack/react-router";
3
+ export function ModuleTabs({ titel, omschrijving, tabs, acties, children }) {
4
+ const pad = useRouterState({ select: (s) => s.location.pathname });
5
+ const veilig = Array.isArray(tabs) ? tabs : [];
6
+ const isActief = (t) => {
7
+ const paden = [t.href, ...(Array.isArray(t.ook) ? t.ook : [])];
8
+ return paden.some((p) => pad === p || pad.startsWith(`${p}/`));
9
+ };
10
+ return (_jsxs("main", { className: "space-y-5 p-6", children: [_jsxs("header", { className: "flex flex-wrap items-end justify-between gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h1", { className: "truncate text-xl font-semibold", children: titel }), omschrijving && _jsx("p", { className: "text-muted-foreground text-sm", children: omschrijving })] }), acties && _jsx("div", { className: "flex flex-wrap items-center gap-2", children: acties })] }), _jsx("nav", { className: "bg-muted/50 inline-flex flex-wrap gap-1 rounded-lg p-1", children: veilig.map((t) => {
11
+ const actief = isActief(t);
12
+ const Icon = t.icon;
13
+ return (_jsxs(Link, { to: t.href, className: `flex items-center gap-2 rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${actief
14
+ ? "bg-background text-foreground shadow-sm"
15
+ : "text-muted-foreground hover:text-foreground"}`, children: [Icon && _jsx(Icon, { className: "h-4 w-4" }), t.label] }, t.href));
16
+ }) }), _jsx("div", { children: children })] }));
17
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"PakbonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/PakbonBuilderPage.tsx"],"names":[],"mappings":"AAwBA,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA0IvF"}
1
+ {"version":3,"file":"PakbonBuilderPage.d.ts","sourceRoot":"","sources":["../../src/components/PakbonBuilderPage.tsx"],"names":[],"mappings":"AAyBA,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,+BA0KvF"}
@@ -7,7 +7,8 @@ import { PakbonSectiesPanel } from "./PakbonSectiesPanel.js";
7
7
  import { PakbonPreview } from "./PakbonPreview.js";
8
8
  import { FormaatOrientatieBar } from "./FormaatOrientatieBar.js";
9
9
  import { leesPakbonConfig } from "../lib/pakbonBuilder.js";
10
- import { printPakbon, voorbeeldPakbonOrder } from "../lib/pakbonHtml.js";
10
+ import { renderPakbonDocument, voorbeeldPakbonOrder } from "../lib/pakbonHtml.js";
11
+ import { printHtml, printerVoorDocumenttype, volgJobStatus } from "../lib/printApi.js";
11
12
  import { haalPrintLogos } from "../lib/logoLibrary.js";
12
13
  import { updateLayout, useLayoutDetail } from "../lib/useDocumentData.js";
13
14
  import { useLayoutIdParam } from "../lib/useLayoutIdParam.js";
@@ -44,16 +45,41 @@ export function PakbonBuilderPage({ layoutId: layoutIdProp } = {}) {
44
45
  return;
45
46
  setPrinten(true);
46
47
  try {
48
+ const printerId = await printerVoorDocumenttype("pakbon", layout?.papierformaat ?? undefined);
49
+ if (!printerId) {
50
+ toast.error("Nog geen printer gekoppeld aan Pakbon — stel dit in bij Layouts & printers > Routering.");
51
+ return;
52
+ }
47
53
  const logos = await haalPrintLogos();
48
- printPakbon(config, voorbeeldPakbonOrder(), {
54
+ const html = renderPakbonDocument(config, voorbeeldPakbonOrder(), {
49
55
  logos,
50
56
  breedteMm: breedte,
51
57
  hoogteMm: hoogte,
52
58
  titel: layout?.naam ?? "Pakbon",
53
59
  });
60
+ const { jobId } = await printHtml({
61
+ documenttype: "pakbon",
62
+ documentnaam: `Voorbeeld ${layout?.naam ?? "pakbon"}`,
63
+ html,
64
+ printerId,
65
+ payload: { voorbeeld: true, layout_id: layout?.id ?? layoutId },
66
+ isHerprint: true,
67
+ });
68
+ toast.success("Voorbeeld naar de printer verstuurd");
69
+ const stop = volgJobStatus(jobId, (s) => {
70
+ if (s.status === "klaar") {
71
+ toast.success("Voorbeeld afgedrukt");
72
+ stop();
73
+ }
74
+ else if (s.status === "mislukt") {
75
+ toast.error(s.foutmelding ?? "Voorbeeld printen mislukt");
76
+ stop();
77
+ }
78
+ });
79
+ window.setTimeout(() => stop(), 120000);
54
80
  }
55
- catch {
56
- toast.error("Voorbeeld printen mislukt");
81
+ catch (e) {
82
+ toast.error(e instanceof Error ? e.message : "Voorbeeld printen mislukt");
57
83
  }
58
84
  finally {
59
85
  setPrinten(false);
@@ -1 +1 @@
1
- {"version":3,"file":"PrintQueuePage.d.ts","sourceRoot":"","sources":["../../src/components/PrintQueuePage.tsx"],"names":[],"mappings":"AAuDA,wBAAgB,cAAc,gCAqN7B"}
1
+ {"version":3,"file":"PrintQueuePage.d.ts","sourceRoot":"","sources":["../../src/components/PrintQueuePage.tsx"],"names":[],"mappings":"AA+DA,wBAAgB,cAAc,gCAsP7B"}
@@ -4,10 +4,11 @@ import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitl
4
4
  import { RotateCcw, Search, XCircle } from "lucide-react";
5
5
  import { bijgewerktTekst, useAutoRefresh } from "../lib/useAutoRefresh.js";
6
6
  import { PrintStatusBanner } from "./PrintStatusBanner.js";
7
- import { maakPrintJob, updateJobStatus, useLayouts, usePrinters, usePrintJobs } from "../lib/useDocumentData.js";
7
+ import { maakPrintJob, updateJobStatus, useLayouts, usePrinters, usePrintJobs, usePrintPlekNamen, } from "../lib/useDocumentData.js";
8
8
  import { printStatus } from "../lib/printService.functions.js";
9
9
  import { vraagWachtrijRonde } from "../lib/queueTickClient.js";
10
10
  import { documentTypeLabel } from "../lib/documentTypes.js";
11
+ import { jobPlekLabel } from "../lib/printQueue.js";
11
12
  const STATUS_VARIANT = {
12
13
  wachtend: "outline",
13
14
  bezig: "secondary",
@@ -35,15 +36,27 @@ export function PrintQueuePage() {
35
36
  const { layouts } = useLayouts();
36
37
  const [zoek, setZoek] = useState("");
37
38
  const [status, setStatus] = useState("alle");
39
+ const [plekFilter, setPlekFilter] = useState("alle");
38
40
  const [tickFout, setTickFout] = useState(null);
41
+ const plekNamen = usePrintPlekNamen();
39
42
  const printerNaam = useMemo(() => new Map(printers.map((p) => [p.id, p.naam])), [printers]);
40
43
  const layoutNaam = useMemo(() => new Map(layouts.map((l) => [l.id, l.naam])), [layouts]);
44
+ /** Herkomstlabel per opdracht: printplek, anders pickstation of werkplek. */
45
+ const plekPerJob = useMemo(() => {
46
+ const m = new Map();
47
+ for (const j of jobs)
48
+ m.set(j.id, jobPlekLabel(j, plekNamen));
49
+ return m;
50
+ }, [jobs, plekNamen]);
51
+ const plekOpties = useMemo(() => Array.from(new Set(Array.from(plekPerJob.values()).filter(Boolean))).sort(), [plekPerJob]);
41
52
  const gefilterd = jobs.filter((j) => {
42
53
  const q = zoek.trim().toLowerCase();
43
54
  if (q && !`${j.documentnaam ?? ""} ${j.gebruiker_naam ?? ""}`.toLowerCase().includes(q))
44
55
  return false;
45
56
  if (status !== "alle" && j.status !== status)
46
57
  return false;
58
+ if (plekFilter !== "alle" && (plekPerJob.get(j.id) || "—") !== plekFilter)
59
+ return false;
47
60
  return true;
48
61
  });
49
62
  const tellingen = useMemo(() => {
@@ -83,7 +96,7 @@ export function PrintQueuePage() {
83
96
  await reload(true);
84
97
  };
85
98
  const bijgewerkt = useAutoRefresh(ronde, lopende ? 5000 : 20000);
86
- 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(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Document" }), _jsx(TableHead, { children: "Layout" }), _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: 6, 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: j.layout_id ? layoutNaam.get(j.layout_id) ?? "—" : "—" }), _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 () => {
99
+ 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" }), _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) || "—" }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: j.layout_id ? layoutNaam.get(j.layout_id) ?? "—" : "—" }), _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 () => {
87
100
  if (!j.layout_id)
88
101
  return;
89
102
  try {
@@ -0,0 +1,4 @@
1
+ export declare function PrintenPage({ tab, }: {
2
+ tab?: "printplekken" | "routering";
3
+ }): import("react").JSX.Element;
4
+ //# sourceMappingURL=PrintenPage.d.ts.map