@flowselections/layout-maker 1.55.1 → 1.57.1

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 (65) hide show
  1. package/dist-lib/components/LayoutVerwijzingenKaart.d.ts +4 -0
  2. package/dist-lib/components/LayoutVerwijzingenKaart.d.ts.map +1 -0
  3. package/dist-lib/components/LayoutVerwijzingenKaart.js +59 -0
  4. package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
  5. package/dist-lib/components/LayoutsPage.js +4 -13
  6. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  7. package/dist-lib/components/PrintQueuePage.js +16 -1
  8. package/dist-lib/components/PrintenInstellenWizard.d.ts +6 -0
  9. package/dist-lib/components/PrintenInstellenWizard.d.ts.map +1 -0
  10. package/dist-lib/components/PrintenInstellenWizard.js +89 -0
  11. package/dist-lib/components/PrintenPage.d.ts +3 -1
  12. package/dist-lib/components/PrintenPage.d.ts.map +1 -1
  13. package/dist-lib/components/PrintenPage.js +4 -2
  14. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  15. package/dist-lib/components/PrintplekDetailPage.js +2 -0
  16. package/dist-lib/components/TestprintDialog.js +2 -2
  17. package/dist-lib/components/WerkplekOmzettingStap.d.ts +10 -0
  18. package/dist-lib/components/WerkplekOmzettingStap.d.ts.map +1 -0
  19. package/dist-lib/components/WerkplekOmzettingStap.js +46 -0
  20. package/dist-lib/components/WerkplekVraag.d.ts +4 -0
  21. package/dist-lib/components/WerkplekVraag.d.ts.map +1 -0
  22. package/dist-lib/components/WerkplekVraag.js +26 -0
  23. package/dist-lib/components/WerkplekkenTab.d.ts +7 -0
  24. package/dist-lib/components/WerkplekkenTab.d.ts.map +1 -0
  25. package/dist-lib/components/WerkplekkenTab.js +143 -0
  26. package/dist-lib/index.d.ts +15 -0
  27. package/dist-lib/index.d.ts.map +1 -1
  28. package/dist-lib/index.js +12 -0
  29. package/dist-lib/integrations/supabase/types.d.ts +415 -0
  30. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  31. package/dist-lib/lib/beheerder.d.ts +2 -0
  32. package/dist-lib/lib/beheerder.d.ts.map +1 -0
  33. package/dist-lib/lib/beheerder.js +18 -0
  34. package/dist-lib/lib/etiketControle.d.ts +36 -0
  35. package/dist-lib/lib/etiketControle.d.ts.map +1 -0
  36. package/dist-lib/lib/etiketControle.js +89 -0
  37. package/dist-lib/lib/layoutVerwijzingen.d.ts +50 -0
  38. package/dist-lib/lib/layoutVerwijzingen.d.ts.map +1 -0
  39. package/dist-lib/lib/layoutVerwijzingen.js +101 -0
  40. package/dist-lib/lib/papierFormaten.d.ts +3 -3
  41. package/dist-lib/lib/papierFormaten.d.ts.map +1 -1
  42. package/dist-lib/lib/papierFormaten.js +6 -6
  43. package/dist-lib/lib/printQueue.server.d.ts +6 -0
  44. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  45. package/dist-lib/lib/printQueue.server.js +149 -23
  46. package/dist-lib/lib/printRoutering.d.ts +14 -1
  47. package/dist-lib/lib/printRoutering.d.ts.map +1 -1
  48. package/dist-lib/lib/printRoutering.js +6 -0
  49. package/dist-lib/lib/printnodeStatusTekst.d.ts +2 -0
  50. package/dist-lib/lib/printnodeStatusTekst.d.ts.map +1 -0
  51. package/dist-lib/lib/printnodeStatusTekst.js +13 -0
  52. package/dist-lib/lib/productiebonHtml.js +1 -1
  53. package/dist-lib/lib/testprint.d.ts +6 -0
  54. package/dist-lib/lib/testprint.d.ts.map +1 -1
  55. package/dist-lib/lib/testprint.js +11 -7
  56. package/dist-lib/lib/waaromPrinter.d.ts +7 -0
  57. package/dist-lib/lib/waaromPrinter.d.ts.map +1 -0
  58. package/dist-lib/lib/waaromPrinter.js +35 -0
  59. package/dist-lib/lib/werkplekOmzetting.d.ts +22 -0
  60. package/dist-lib/lib/werkplekOmzetting.d.ts.map +1 -0
  61. package/dist-lib/lib/werkplekOmzetting.js +42 -0
  62. package/dist-lib/lib/werkplekken.d.ts +73 -0
  63. package/dist-lib/lib/werkplekken.d.ts.map +1 -0
  64. package/dist-lib/lib/werkplekken.js +156 -0
  65. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ export declare function LayoutVerwijzingenKaart({ onGewijzigd }: {
2
+ onGewijzigd?: () => void;
3
+ }): import("react").JSX.Element | null;
4
+ //# sourceMappingURL=LayoutVerwijzingenKaart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LayoutVerwijzingenKaart.d.ts","sourceRoot":"","sources":["../../src/components/LayoutVerwijzingenKaart.tsx"],"names":[],"mappings":"AAwBA,wBAAgB,uBAAuB,CAAC,EAAE,WAAW,EAAE,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,sCAqFpF"}
@@ -0,0 +1,59 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/LayoutVerwijzingenKaart.tsx — per documentsoort met meerdere
4
+ // actieve layouts of verschillende verwijzingen: welke instellingen naar welke
5
+ // layout wijzen en hoe vaak hij de laatste 30 dagen is gebruikt. De beheerder
6
+ // kiest zelf een standaard; instellingen van andere modules worden nooit
7
+ // gewijzigd, alleen getoond met een link.
8
+ // ============================================================================
9
+ import { useState } from "react";
10
+ import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, toast } from "@flowselections/core";
11
+ import { AlertTriangle, ExternalLink } from "lucide-react";
12
+ import { documentTypeLabel } from "../lib/documentTypes.js";
13
+ import { maakStandaardLayout } from "../lib/useDocumentData.js";
14
+ import { leesbareFout } from "../lib/foutTekst.js";
15
+ import { useIsBeheerder } from "../lib/beheerder.js";
16
+ import { BRON_LABEL, isEigenVerwijzing, plekVanVerwijzing, useLayoutVerwijzingen, zetVerwijzingOm, } from "../lib/layoutVerwijzingen.js";
17
+ export function LayoutVerwijzingenKaart({ onGewijzigd }) {
18
+ const { overzicht, fout, reload } = useLayoutVerwijzingen();
19
+ const beheerder = useIsBeheerder() === true;
20
+ const [bezig, setBezig] = useState(null);
21
+ const safe = Array.isArray(overzicht) ? overzicht : [];
22
+ if (fout)
23
+ return _jsxs("p", { className: "text-destructive text-sm", children: ["Overzicht van verwijzingen laden mislukt: ", fout] });
24
+ if (!safe.length)
25
+ return null;
26
+ const klaar = () => { void reload(); onGewijzigd?.(); };
27
+ return (_jsxs(Card, { className: "border-destructive/50", children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(AlertTriangle, { className: "text-destructive h-4 w-4" }), " Meerdere layouts voor dezelfde documentsoort"] }), _jsx(CardDescription, { children: "Per layout zie je welke instellingen hem gebruiken en hoe vaak hij de laatste 30 dagen is geprint. Kies zelf \u00E9\u00E9n standaard. Instellingen van andere modules pas je aan in die module." })] }), _jsx(CardContent, { className: "space-y-3", children: safe.map((s) => (_jsxs("div", { className: "space-y-2 rounded-lg border p-2 text-sm", "data-soort": s.documenttype, children: [_jsx("div", { className: "font-medium", children: documentTypeLabel(s.documenttype) }), s.layouts.map((l) => {
28
+ const standaard = s.layouts.find((x) => x.is_standaard && x.actief && x.bron === l.bron && x.id !== l.id);
29
+ return (_jsxs("div", { className: "rounded border p-2", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: l.naam }), _jsx(Badge, { variant: "outline", children: l.bron === "floriday" ? "Floriday" : "eigen" }), l.is_standaard ? _jsx(Badge, { children: "standaard" }) : null, !l.actief ? _jsx(Badge, { variant: "secondary", children: "niet actief" }) : null, _jsxs("span", { className: "text-muted-foreground text-xs", children: ["30 dagen: ", l.totaal30, "\u00D7", Object.entries(l.gebruik).map(([b, n]) => ` · ${BRON_LABEL[b] ?? b} ${n}×`).join("")] }), l.actief && !l.is_standaard ? (_jsx(Button, { size: "sm", variant: "outline", className: "ml-auto", disabled: !beheerder || bezig === l.id, title: beheerder ? undefined : "Alleen beheerders kunnen dit wijzigen", onClick: async () => {
30
+ setBezig(l.id);
31
+ try {
32
+ await maakStandaardLayout(l.id);
33
+ toast.success(`${l.naam} is nu de standaard`);
34
+ klaar();
35
+ }
36
+ catch (e) {
37
+ toast.error(leesbareFout(e, "Standaard maken mislukt"));
38
+ }
39
+ finally {
40
+ setBezig(null);
41
+ }
42
+ }, children: "Maak standaard" })) : null] }), l.verwijzingen.length ? (_jsx("ul", { className: "mt-1 space-y-1", children: l.verwijzingen.map((v) => (_jsx(VerwijzingRegel, { v: v, naarStandaard: isEigenVerwijzing(v) && standaard ? standaard : null, beheerder: beheerder, onKlaar: klaar }, `${v.tabel}-${v.rij_id}-${v.pad.join(".")}`))) })) : (_jsx("p", { className: "text-muted-foreground mt-1 text-xs", children: "Geen instelling verwijst naar deze layout." }))] }, l.id));
43
+ })] }, s.documenttype))) })] }));
44
+ }
45
+ function VerwijzingRegel({ v, naarStandaard, beheerder, onKlaar, }) {
46
+ const plek = plekVanVerwijzing(v);
47
+ return (_jsxs("li", { className: "flex flex-wrap items-center gap-2 text-xs", children: [_jsxs("span", { children: [plek.module, " \u203A ", plek.scherm, v.rij_naam ? ` (${v.rij_naam}${v.rij_actief === false ? ", niet actief" : ""})` : v.rij_actief === false ? " (niet actief)" : ""] }), !isEigenVerwijzing(v) && plek.link ? (_jsxs("a", { href: plek.link, className: "text-primary inline-flex items-center gap-1 underline", children: ["Openen ", _jsx(ExternalLink, { className: "h-3 w-3" })] })) : null, naarStandaard ? (_jsxs(Button, { size: "sm", variant: "ghost", disabled: !beheerder, title: beheerder ? undefined : "Alleen beheerders kunnen dit wijzigen", onClick: async () => {
48
+ if (!window.confirm(`Deze regel laten wijzen naar "${naarStandaard.naam}"?`))
49
+ return;
50
+ try {
51
+ await zetVerwijzingOm(v, naarStandaard.id);
52
+ toast.success("Verwijzing omgezet");
53
+ onKlaar();
54
+ }
55
+ catch (e) {
56
+ toast.error(leesbareFout(e, "Omzetten mislukt"));
57
+ }
58
+ }, children: ["Naar standaard \"", naarStandaard.naam, "\""] })) : null] }));
59
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"LayoutsPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPage.tsx"],"names":[],"mappings":"AA2EA,wBAAgB,WAAW,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BAkpB1E"}
1
+ {"version":3,"file":"LayoutsPage.d.ts","sourceRoot":"","sources":["../../src/components/LayoutsPage.tsx"],"names":[],"mappings":"AA4EA,wBAAgB,WAAW,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BAomB1E"}
@@ -3,8 +3,9 @@ import { useMemo, useState } from "react";
3
3
  import { useAutoRefresh } from "../lib/useAutoRefresh.js";
4
4
  import { Link, useNavigate } from "@tanstack/react-router";
5
5
  import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Textarea, toast, } from "@flowselections/core";
6
- import { AlertTriangle, Copy, FileText, Pencil, Plus, Search, Settings2, Trash2 } from "lucide-react";
7
- import { layoutConflicten, maakStandaardLayout } from "../lib/useDocumentData.js";
6
+ import { Copy, FileText, Pencil, Plus, Search, Settings2, Trash2 } from "lucide-react";
7
+ import { LayoutVerwijzingenKaart } from "./LayoutVerwijzingenKaart.js";
8
+ import { maakStandaardLayout } from "../lib/useDocumentData.js";
8
9
  import { dupliceerLayout, maakLayout, updateLayout, useLayouts, verwijderLayout, } from "../lib/useDocumentData.js";
9
10
  import { LayoutPrinterSelect } from "./LayoutPrinterSelect.js";
10
11
  import { DOCUMENT_TYPES, FLORIDAY_LAYOUT_TOELICHTING, PAPIERFORMATEN, documentTypeLabel, isFloridayLayout, } from "../lib/documentTypes.js";
@@ -25,7 +26,6 @@ function klantOntwerpLayout(l) {
25
26
  }
26
27
  export function LayoutsPage({ ingebed = false } = {}) {
27
28
  const { layouts, loading, reload } = useLayouts();
28
- const conflicten = useMemo(() => layoutConflicten(layouts), [layouts]);
29
29
  useAutoRefresh(() => {
30
30
  void reload(true);
31
31
  }, 30000);
@@ -156,16 +156,7 @@ export function LayoutsPage({ ingebed = false } = {}) {
156
156
  }
157
157
  };
158
158
  const Wrapper = ingebed ? "div" : "main";
159
- 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"] }) })] }), conflicten.length > 0 && (_jsxs(Card, { className: "border-destructive/50", children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), " Meerdere actieve layouts"] }), _jsx(CardDescription, { children: "Bij het printen wint per documentsoort \u00E9\u00E9n layout. De andere worden alleen gebruikt als een module ze expliciet kiest." })] }), _jsx(CardContent, { className: "space-y-2", children: conflicten.map((c) => (_jsxs("div", { className: "rounded-lg border p-2 text-sm", "data-conflict": c.documenttype, children: [_jsxs("div", { className: "font-medium", children: [documentTypeLabel(c.documenttype), " (", c.bron === "floriday" ? "Floriday" : "eigen", ") \u2014 ", c.actief.length, " actief"] }), _jsxs("div", { className: "text-muted-foreground text-xs", children: ["Wint bij printen: ", _jsx("span", { className: "font-medium text-foreground", children: c.winnaar.naam }), c.heeftStandaard ? " (standaard)" : " — geen standaard, de laatst bewerkte wint"] }), _jsx("div", { className: "mt-1 flex flex-wrap gap-2", children: c.actief.filter((l) => l.id !== c.winnaar.id || !c.heeftStandaard).map((l) => (_jsxs(Button, { size: "sm", variant: "outline", onClick: async () => {
160
- try {
161
- await maakStandaardLayout(l.id);
162
- toast.success(`${l.naam} is nu de standaard`);
163
- }
164
- catch {
165
- toast.error("Standaard maken mislukt");
166
- }
167
- void reload();
168
- }, children: ["Maak \"", l.naam, "\" standaard"] }, l.id))) })] }, `${c.documenttype}-${c.bron}`))) })] })), _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 }))] }), _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) => {
159
+ 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"] }) })] }), _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 }))] }), _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) => {
169
160
  await updateLayout(l.id, { actief: v });
170
161
  void reload();
171
162
  } }), !l.is_standaard && (_jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"PrintQueuePage.d.ts","sourceRoot":"","sources":["../../src/components/PrintQueuePage.tsx"],"names":[],"mappings":"AAoFA,wBAAgB,cAAc,gCA+X7B"}
1
+ {"version":3,"file":"PrintQueuePage.d.ts","sourceRoot":"","sources":["../../src/components/PrintQueuePage.tsx"],"names":[],"mappings":"AAoFA,wBAAgB,cAAc,gCAqZ7B"}
@@ -193,7 +193,22 @@ export function PrintQueuePage() {
193
193
  return null;
194
194
  const s = scanLabel(scan, j.gestart_op ?? j.created_at);
195
195
  return s === "gescand" ? (_jsx(Badge, { variant: "default", className: "ml-2", children: "Gescand" })) : (_jsx(Badge, { variant: "secondary", className: "ml-2", children: "Kar eerder gescand" }));
196
- })(), j.printnode_bericht && j.status === "mislukt" && (_jsx("span", { className: "block text-xs text-destructive", children: j.printnode_bericht }))] }), _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: [opnieuwActie(j) && (_jsxs(Button, { variant: "ghost", size: "sm", onClick: async () => {
196
+ })(), j.printnode_bericht && j.status === "mislukt" && (_jsx("span", { className: "block text-xs text-destructive", children: j.printnode_bericht }))] }), _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: [_jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
197
+ const { data } = await supabase
198
+ .from("print_job_logs")
199
+ .select("gebeurtenis, detail, created_at")
200
+ .eq("job_id", j.id)
201
+ .in("gebeurtenis", ["waarom", "etiket", "route"])
202
+ .order("created_at", { ascending: true });
203
+ const regels = (Array.isArray(data) ? data : []).map((r) => r.detail).filter(Boolean);
204
+ toast.message("Waarom deze printer?", {
205
+ description: regels.length
206
+ ? regels.join("\n")
207
+ : j.status === "mislukt"
208
+ ? (j.foutmelding ?? "Er is niets geprint.")
209
+ : "Nog niet bepaald: de opdracht is nog niet verwerkt.",
210
+ });
211
+ }, children: "Waarom?" }), opnieuwActie(j) && (_jsxs(Button, { variant: "ghost", size: "sm", onClick: async () => {
197
212
  const pr = j.printer_id ? printerById.get(j.printer_id) : null;
198
213
  if (pr && !pr.online) {
199
214
  const door = window.confirm(`Printer "${pr.naam}" (of de computer) is nu offline. De opdracht blijft wachten tot hij weer aan staat, en verloopt anders. Toch versturen?`);
@@ -0,0 +1,6 @@
1
+ export declare function PrintenInstellenWizard({ open, onOpenChange, onKlaar, }: {
2
+ open: boolean;
3
+ onOpenChange: (v: boolean) => void;
4
+ onKlaar?: () => void;
5
+ }): import("react").JSX.Element;
6
+ //# sourceMappingURL=PrintenInstellenWizard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrintenInstellenWizard.d.ts","sourceRoot":"","sources":["../../src/components/PrintenInstellenWizard.tsx"],"names":[],"mappings":"AAsBA,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,YAAY,EACZ,OAAO,GACR,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,+BA0JA"}
@@ -0,0 +1,89 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/PrintenInstellenWizard.tsx — "Printen instellen" voor een
4
+ // nieuwe klant: computers zoeken, per werkplek de A4-printer en labelprinter
5
+ // (met geladen etiket) kiezen, een testpagina per printer, klaar.
6
+ // ============================================================================
7
+ import { useEffect, useState } from "react";
8
+ import { Badge, Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, Input, toast } from "@flowselections/core";
9
+ import { Check, Loader2, RefreshCw } from "lucide-react";
10
+ import { useComputers } from "./ComputersLijst.js";
11
+ import { GeladenEtiketKeuze } from "./WerkplekkenTab.js";
12
+ import { printHtml, volgJobStatus } from "../lib/printApi.js";
13
+ import { leesbareFout } from "../lib/foutTekst.js";
14
+ import { testHtml } from "../lib/testprint.js";
15
+ import { printTitelVoorStatus } from "../lib/printnodeStatusTekst.js";
16
+ import { printerTitel, slaWerkplekOp, usePrinterLijst } from "../lib/werkplekken.js";
17
+ import { haalOmzettingVoorstel } from "../lib/werkplekOmzetting.js";
18
+ import { useIsBeheerder } from "../lib/beheerder.js";
19
+ import { WerkplekOmzettingStap } from "./WerkplekOmzettingStap.js";
20
+ const selectKlasse = "border-input bg-background rounded-md border px-2 py-1 text-sm";
21
+ export function PrintenInstellenWizard({ open, onOpenChange, onKlaar, }) {
22
+ const [stap, setStap] = useState(1);
23
+ const { computers, loading, reload } = useComputers();
24
+ const { printers, reload: reloadPrinters } = usePrinterLijst();
25
+ const [naam, setNaam] = useState("Kantoor");
26
+ const [a4, setA4] = useState(null);
27
+ const [label, setLabel] = useState(null);
28
+ const [status, setStatus] = useState({});
29
+ const bruikbaar = printers.filter((p) => !p.verborgen && !p.is_virtueel && p.actief !== false);
30
+ const labelPrinter = printers.find((p) => p.id === label) ?? null;
31
+ const beheerder = useIsBeheerder() === true;
32
+ const [voorstel, setVoorstel] = useState(null);
33
+ // Bestaande Shell: begin met het voorstel uit de huidige instellingen.
34
+ // Lege Shell: geen voorstel, de wizard begint gewoon bij stap 1.
35
+ useEffect(() => {
36
+ if (!open)
37
+ return;
38
+ let weg = false;
39
+ haalOmzettingVoorstel()
40
+ .then((v) => { if (!weg) {
41
+ setVoorstel(v);
42
+ if (v.length)
43
+ setStap(0);
44
+ } })
45
+ .catch(() => { if (!weg)
46
+ setVoorstel([]); });
47
+ return () => { weg = true; };
48
+ }, [open]);
49
+ const test = async (printerId, soort) => {
50
+ setStatus((s) => ({ ...s, [printerId]: "wachtend" }));
51
+ try {
52
+ const p = printers.find((x) => x.id === printerId);
53
+ const { jobId } = await printHtml({
54
+ documenttype: soort,
55
+ documentnaam: `Testpagina ${printerTitel(p)}`,
56
+ html: testHtml({
57
+ Documentsoort: soort === "sticker" ? "Testetiket" : "Testpagina A4",
58
+ Werkplek: naam,
59
+ Printer: printerTitel(p),
60
+ Tijdstip: new Date().toLocaleString("nl-NL"),
61
+ }),
62
+ printerId,
63
+ payload: { is_testprint: true },
64
+ });
65
+ volgJobStatus(jobId, (j) => setStatus((s) => ({ ...s, [printerId]: j.foutmelding ? `mislukt: ${j.foutmelding}` : j.status })));
66
+ }
67
+ catch (e) {
68
+ setStatus((s) => ({ ...s, [printerId]: `mislukt: ${leesbareFout(e, "versturen mislukt")}` }));
69
+ }
70
+ };
71
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-h-[85vh] max-w-2xl overflow-y-auto", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: stap === 0 ? "Printen instellen — voorstel uit huidige instellingen" : `Printen instellen — stap ${stap} van 4` }), _jsx(DialogDescription, { children: "In een paar minuten weet je zeker waar het papier uitkomt." })] }), stap === 0 && voorstel?.length ? (_jsx(WerkplekOmzettingStap, { voorstel: voorstel, printers: printers, beheerder: beheerder, onOverslaan: () => setStap(1), onKlaar: () => { void reloadPrinters(); onKlaar?.(); setNaam(voorstel[0]?.naam ?? naam); setStap(3); } })) : null, stap === 1 ? (_jsxs("div", { className: "space-y-2 text-sm", children: [_jsx("p", { children: "Op deze computers draait het printprogramma:" }), computers.map((c) => (_jsxs("div", { className: "flex items-center gap-2 rounded border p-2", children: [_jsx("span", { className: "font-medium", children: c.naam }), _jsx(Badge, { variant: c.online ? "secondary" : "destructive", children: c.online ? "online" : "offline" }), _jsxs("span", { className: "text-muted-foreground text-xs", children: [c.aantalGevonden, " printers"] })] }, c.id))), !loading && !computers.length ? _jsx("p", { className: "text-muted-foreground", children: "Nog geen computers gevonden. Installeer het printprogramma op de computer met de printers." }) : null, _jsxs(Button, { size: "sm", variant: "outline", onClick: () => { void reload(); void reloadPrinters(); }, children: [loading ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), " Opnieuw zoeken"] })] })) : null, stap === 2 ? (_jsxs("div", { className: "grid gap-2 text-sm sm:grid-cols-[9rem_1fr]", children: [_jsx("span", { children: "Naam werkplek" }), _jsx(Input, { value: naam, onChange: (e) => setNaam(e.target.value) }), _jsx("span", { children: "A4-printer" }), _jsxs("select", { className: selectKlasse, value: a4 ?? "", onChange: (e) => setA4(e.target.value || null), children: [_jsx("option", { value: "", children: "\u2014 geen \u2014" }), bruikbaar.map((p) => _jsxs("option", { value: p.id, children: [printerTitel(p), p.locatie ? ` · ${p.locatie}` : ""] }, p.id))] }), _jsx("span", { children: "Labelprinter" }), _jsxs("select", { className: selectKlasse, value: label ?? "", onChange: (e) => setLabel(e.target.value || null), children: [_jsx("option", { value: "", children: "\u2014 geen \u2014" }), bruikbaar.map((p) => _jsxs("option", { value: p.id, children: [printerTitel(p), p.locatie ? ` · ${p.locatie}` : ""] }, p.id))] }), labelPrinter ? (_jsx("div", { className: "sm:col-span-2", children: _jsx(GeladenEtiketKeuze, { printer: labelPrinter, onGewijzigd: () => void reloadPrinters() }) })) : null] })) : null, stap === 3 ? (_jsx("div", { className: "space-y-2 text-sm", children: [a4 ? { id: a4, soort: "vrij" } : null, label ? { id: label, soort: "sticker" } : null]
72
+ .filter(Boolean)
73
+ .map((r) => {
74
+ const p = printers.find((x) => x.id === r.id);
75
+ const st = status[r.id];
76
+ return (_jsxs("div", { className: "flex flex-wrap items-center gap-2 rounded border p-2", children: [_jsx("span", { className: "font-medium", children: printerTitel(p) }), st ? _jsx(Badge, { variant: st.startsWith("mislukt") ? "destructive" : "secondary", children: printTitelVoorStatus(st) }) : null, _jsx(Button, { size: "sm", variant: "outline", className: "ml-auto", onClick: () => void test(r.id, r.soort), children: r.soort === "sticker" ? "Testetiket" : "Testpagina" })] }, r.id));
77
+ }) })) : null, stap === 4 ? (_jsxs("p", { className: "flex items-center gap-2 text-sm", children: [_jsx(Check, { className: "h-4 w-4" }), " Werkplek ", naam, " is klaar. Documenten kiezen nu automatisch de A4-printer of de labelprinter op hun papierformaat."] })) : null, stap > 0 ? _jsxs("div", { className: "flex justify-between pt-2", children: [_jsx(Button, { variant: "ghost", disabled: stap === 1 && !voorstel?.length, onClick: () => setStap((s) => s - 1), children: "Terug" }), stap < 4 ? (_jsx(Button, { disabled: stap === 2 && (!naam.trim() || (!a4 && !label)), onClick: async () => {
78
+ if (stap === 2) {
79
+ try {
80
+ await slaWerkplekOp({ naam, a4_printer_id: a4, label_printer_id: label });
81
+ }
82
+ catch (e) {
83
+ toast.error(leesbareFout(e, "Werkplek opslaan mislukt"));
84
+ return;
85
+ }
86
+ }
87
+ setStap((s) => s + 1);
88
+ }, children: "Volgende" })) : (_jsx(Button, { onClick: () => { onKlaar?.(); onOpenChange(false); setStap(1); }, children: "Klaar" }))] }) : null] }) }));
89
+ }
@@ -1,4 +1,6 @@
1
+ type Tab = "printplekken" | "werkplekken" | "routering";
1
2
  export declare function PrintenPage({ tab, }: {
2
- tab?: "printplekken" | "routering";
3
+ tab?: Tab;
3
4
  }): import("react").JSX.Element;
5
+ export {};
4
6
  //# sourceMappingURL=PrintenPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PrintenPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintenPage.tsx"],"names":[],"mappings":"AAqBA,wBAAgB,WAAW,CAAC,EAC1B,GAAoB,GACrB,EAAE;IACD,GAAG,CAAC,EAAE,cAAc,GAAG,WAAW,CAAC;CACpC,+BAuBA"}
1
+ {"version":3,"file":"PrintenPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintenPage.tsx"],"names":[],"mappings":"AAaA,KAAK,GAAG,GAAG,cAAc,GAAG,aAAa,GAAG,WAAW,CAAC;AAYxD,wBAAgB,WAAW,CAAC,EAC1B,GAAoB,GACrB,EAAE;IACD,GAAG,CAAC,EAAE,GAAG,CAAC;CACX,+BAyBA"}
@@ -4,20 +4,22 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
4
4
  // printplekken (plekken, computers en printers samen) en standaardregels.
5
5
  // ============================================================================
6
6
  import { useState } from "react";
7
- import { MapPin, Route as RouteIcon } from "lucide-react";
7
+ import { Laptop, MapPin, Route as RouteIcon } from "lucide-react";
8
8
  import { ModuleTabs } from "./ModuleTabs.js";
9
9
  import { PrintplekkenPage } from "./PrintplekkenPage.js";
10
10
  import { DocumentRouteringPage } from "./DocumentRouteringPage.js";
11
11
  import { LivePrintstatusRegel } from "./LivePrintstatusRegel.js";
12
+ import { WerkplekkenTab } from "./WerkplekkenTab.js";
12
13
  const TABS = [
13
14
  {
14
15
  id: "printplekken",
15
16
  label: "Printplekken",
16
17
  icon: MapPin,
17
18
  },
19
+ { id: "werkplekken", label: "Werkplekken", icon: Laptop },
18
20
  { id: "routering", label: "Standaardregels", icon: RouteIcon },
19
21
  ];
20
22
  export function PrintenPage({ tab = "printplekken", }) {
21
23
  const [actiefTab, setActiefTab] = useState(tab);
22
- return (_jsx(_Fragment, { children: _jsxs(ModuleTabs, { titel: "Printen", omschrijving: "Stel per plek in het bedrijf in welke computers, printers en documenten daar horen.", tabs: TABS, actiefTab: actiefTab, onTabWijzig: (nieuwTab) => setActiefTab(nieuwTab === "routering" ? "routering" : "printplekken"), children: [_jsx(LivePrintstatusRegel, {}), actiefTab === "routering" ? (_jsx(DocumentRouteringPage, { ingebed: true })) : (_jsx(PrintplekkenPage, { ingebed: true }))] }) }));
24
+ return (_jsx(_Fragment, { children: _jsxs(ModuleTabs, { titel: "Printen", omschrijving: "Stel per plek in het bedrijf in welke computers, printers en documenten daar horen.", tabs: TABS, actiefTab: actiefTab, onTabWijzig: (nieuwTab) => setActiefTab(nieuwTab === "routering" || nieuwTab === "werkplekken" ? nieuwTab : "printplekken"), children: [_jsx(LivePrintstatusRegel, {}), actiefTab === "werkplekken" ? (_jsx(WerkplekkenTab, {})) : actiefTab === "routering" ? (_jsx(DocumentRouteringPage, { ingebed: true })) : (_jsx(PrintplekkenPage, { ingebed: true }))] }) }));
23
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PrintplekDetailPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintplekDetailPage.tsx"],"names":[],"mappings":"AA+DA,wBAAgB,mBAAmB,gCAooBlC"}
1
+ {"version":3,"file":"PrintplekDetailPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintplekDetailPage.tsx"],"names":[],"mappings":"AAiEA,wBAAgB,mBAAmB,gCAooBlC"}
@@ -22,6 +22,8 @@ import { leesbareFout } from "../lib/foutTekst.js";
22
22
  import { supabase } from "../lib/supabaseClient.js";
23
23
  import { useRouteringOverzicht } from "../lib/printRoutering.js";
24
24
  const BRON_LABEL = {
25
+ werkplek_formaat: "Werkplek (papierformaat)",
26
+ werkplek_afwijking: "Werkplek (afwijking)",
25
27
  printplek: "Printplek-eigen",
26
28
  werkplek: "Werkplek-uitzondering",
27
29
  layout: "Standaardprinter (layout)",
@@ -11,8 +11,8 @@ import { volgJobStatus } from "../lib/printApi.js";
11
11
  import { bepaalTestOverzicht, verstuurTestprint, } from "../lib/testprint.js";
12
12
  const STATUS_LABEL = {
13
13
  wachtend: "In de wachtrij",
14
- bezig: "Wordt afgedrukt",
15
- voltooid: "Afgedrukt",
14
+ bezig: "Naar de printer",
15
+ voltooid: "Bij printer afgeleverd",
16
16
  mislukt: "Mislukt",
17
17
  geannuleerd: "Geannuleerd",
18
18
  };
@@ -0,0 +1,10 @@
1
+ import { type PrinterRij } from "../lib/werkplekken.js";
2
+ import { type WerkplekVoorstel } from "../lib/werkplekOmzetting.js";
3
+ export declare function WerkplekOmzettingStap({ voorstel: begin, printers, beheerder, onKlaar, onOverslaan, }: {
4
+ voorstel: WerkplekVoorstel[];
5
+ printers: PrinterRij[];
6
+ beheerder: boolean;
7
+ onKlaar: () => void;
8
+ onOverslaan: () => void;
9
+ }): import("react").JSX.Element;
10
+ //# sourceMappingURL=WerkplekOmzettingStap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WerkplekOmzettingStap.d.ts","sourceRoot":"","sources":["../../src/components/WerkplekOmzettingStap.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAA+B,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAW9F,wBAAgB,qBAAqB,CAAC,EACpC,QAAQ,EAAE,KAAK,EACf,QAAQ,EACR,SAAS,EACT,OAAO,EACP,WAAW,GACZ,EAAE;IACD,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,IAAI,CAAC;CACzB,+BAuFA"}
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Eerste stap van "Printen instellen" in een Shell die al printplekken of
3
+ // standaardregels heeft: per werkplek de printer van nu en die van na de
4
+ // omzetting, met de bron en de verschillen gemarkeerd.
5
+ import { useState } from "react";
6
+ import { Badge, Button, Input, toast } from "@flowselections/core";
7
+ import { documentTypeLabel } from "../lib/documentTypes.js";
8
+ import { leesbareFout } from "../lib/foutTekst.js";
9
+ import { printerTitel } from "../lib/werkplekken.js";
10
+ import { herbereken, pasOmzettingToe } from "../lib/werkplekOmzetting.js";
11
+ const selectKlasse = "border-input bg-background rounded-md border px-2 py-1 text-sm";
12
+ const BRON = {
13
+ printplek: "printplek",
14
+ werkplek: "computer-uitzondering",
15
+ layout: "layout-koppeling",
16
+ standaard: "standaardregel",
17
+ geen: "geen regel",
18
+ };
19
+ export function WerkplekOmzettingStap({ voorstel: begin, printers, beheerder, onKlaar, onOverslaan, }) {
20
+ const [voorstel, setVoorstel] = useState(begin);
21
+ const [bezig, setBezig] = useState(false);
22
+ const titel = (id) => (id ? printerTitel(printers.find((p) => p.id === id)) : "—");
23
+ const bruikbaar = printers.filter((p) => !p.verborgen && !p.is_virtueel && p.actief !== false);
24
+ const wijzig = (i, patch) => setVoorstel((v) => v.map((w, j) => (j === i ? herbereken({ ...w, ...patch }) : w)));
25
+ const nieuw = voorstel.filter((w) => !w.bestaat);
26
+ return (_jsxs("div", { className: "space-y-3 text-sm", children: [_jsx("p", { children: "Op basis van de huidige instellingen stelt de module deze werkplekken voor. Controleer per documentsoort de printer van nu en die van na de omzetting. Er wordt pas iets aangemaakt als je bevestigt." }), voorstel.map((w, i) => {
27
+ const etiket = printers.find((p) => p.id === w.label_printer_id)?.geladen_etiket;
28
+ const verschillen = w.soorten.filter((s) => s.verschil).length;
29
+ return (_jsxs("div", { className: "space-y-2 rounded border p-2", "data-werkplek-voorstel": w.print_plek_id ?? "kantoor", children: [_jsxs("div", { className: "grid gap-2 sm:grid-cols-[8rem_1fr]", children: [_jsx("span", { children: "Naam" }), _jsx(Input, { value: w.naam, disabled: w.bestaat || !beheerder, onChange: (e) => wijzig(i, { naam: e.target.value }) }), _jsx("span", { children: "A4-printer" }), _jsxs("select", { className: selectKlasse, disabled: w.bestaat || !beheerder, value: w.a4_printer_id ?? "", onChange: (e) => wijzig(i, { a4_printer_id: e.target.value || null }), children: [_jsx("option", { value: "", children: "\u2014 geen \u2014" }), bruikbaar.map((p) => _jsx("option", { value: p.id, children: printerTitel(p) }, p.id))] }), _jsx("span", { children: "Labelprinter" }), _jsxs("select", { className: selectKlasse, disabled: w.bestaat || !beheerder, value: w.label_printer_id ?? "", onChange: (e) => wijzig(i, { label_printer_id: e.target.value || null }), children: [_jsx("option", { value: "", children: "\u2014 geen \u2014" }), bruikbaar.map((p) => _jsx("option", { value: p.id, children: printerTitel(p) }, p.id))] }), _jsx("span", { children: "Geladen etiket" }), _jsx("span", { className: etiket ? "" : "text-destructive", children: etiket ? JSON.stringify(etiket) : "nog niet ingesteld — stel het in bij Werkplekken" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [w.print_plek_id ? _jsx(Badge, { variant: "outline", children: "gekoppeld aan printplek" }) : _jsx(Badge, { variant: "outline", children: "op basis van standaardregels" }), w.bestaat ? _jsx(Badge, { variant: "secondary", children: "bestaat al \u2014 wordt overgeslagen" }) : null, _jsxs(Badge, { variant: verschillen ? "destructive" : "secondary", children: [verschillen, " verschillen"] })] }), _jsxs("table", { className: "w-full text-xs", children: [_jsx("thead", { children: _jsxs("tr", { className: "text-muted-foreground text-left", children: [_jsx("th", { className: "py-0.5", children: "Documentsoort" }), _jsx("th", { children: "Nu" }), _jsx("th", { children: "Bron nu" }), _jsx("th", { children: "Na omzetting" })] }) }), _jsx("tbody", { children: w.soorten.map((s) => (_jsxs("tr", { className: s.verschil ? "bg-destructive/10 font-medium" : "", "data-verschil": s.verschil ? "ja" : "nee", children: [_jsx("td", { className: "py-0.5", children: documentTypeLabel(s.documenttype) }), _jsx("td", { children: titel(s.printer_id) }), _jsx("td", { children: BRON[s.bron ?? "geen"] ?? s.bron }), _jsxs("td", { children: [titel(s.na_printer_id), s.klasse === "label" ? " (label)" : " (A4)"] })] }, s.documenttype))) })] })] }, `${w.print_plek_id ?? "kantoor"}`));
30
+ }), !beheerder ? _jsx("p", { className: "text-muted-foreground", children: "Alleen beheerders kunnen dit wijzigen." }) : null, _jsxs("div", { className: "flex justify-between", children: [_jsx(Button, { variant: "ghost", onClick: onOverslaan, children: "Overslaan, zelf instellen" }), _jsx(Button, { disabled: !beheerder || bezig || !nieuw.length || nieuw.some((w) => !w.naam.trim() || (!w.a4_printer_id && !w.label_printer_id)), onClick: async () => {
31
+ if (!window.confirm(`${nieuw.length} werkplek(ken) aanmaken? De verschillen hierboven gaan dan gelden voor wie deze werkplek kiest.`))
32
+ return;
33
+ setBezig(true);
34
+ try {
35
+ await pasOmzettingToe(voorstel);
36
+ toast.success("Werkplekken aangemaakt");
37
+ onKlaar();
38
+ }
39
+ catch (e) {
40
+ toast.error(leesbareFout(e, "Aanmaken mislukt"));
41
+ }
42
+ finally {
43
+ setBezig(false);
44
+ }
45
+ }, children: "Bevestigen en aanmaken" })] })] }));
46
+ }
@@ -0,0 +1,4 @@
1
+ export declare function WerkplekVraag({ altijdTonen }: {
2
+ altijdTonen?: boolean;
3
+ }): import("react").JSX.Element;
4
+ //# sourceMappingURL=WerkplekVraag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WerkplekVraag.d.ts","sourceRoot":"","sources":["../../src/components/WerkplekVraag.tsx"],"names":[],"mappings":"AAWA,wBAAgB,aAAa,CAAC,EAAE,WAAmB,EAAE,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,+BAuC/E"}
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/WerkplekVraag.tsx — vraagt een ingelogde gebruiker één keer
4
+ // op welke werkplek hij werkt (Afhandeling, Facturen…) en onthoudt dat.
5
+ // Pickstations en scanners gebruiken dit niet: die hangen aan hun printplek.
6
+ // ============================================================================
7
+ import { useState } from "react";
8
+ import { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, toast } from "@flowselections/core";
9
+ import { leesbareFout } from "../lib/foutTekst.js";
10
+ import { useMijnWerkplek, useWerkplekken } from "../lib/werkplekken.js";
11
+ export function WerkplekVraag({ altijdTonen = false }) {
12
+ const { werkplekId, laden, kies } = useMijnWerkplek();
13
+ const { werkplekken } = useWerkplekken();
14
+ const [keuze, setKeuze] = useState("");
15
+ const [dicht, setDicht] = useState(false);
16
+ const open = !dicht && !laden && werkplekken.length > 0 && (altijdTonen || !werkplekId);
17
+ return (_jsx(Dialog, { open: open, onOpenChange: (v) => !v && setDicht(true), children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Op welke werkplek werk je?" }), _jsx(DialogDescription, { children: "Dit vragen we \u00E9\u00E9n keer. Je documenten komen dan uit de printers van die werkplek." })] }), _jsxs("select", { className: "border-input bg-background rounded-md border px-2 py-2 text-sm", value: keuze || werkplekId || "", onChange: (e) => setKeuze(e.target.value), children: [_jsx("option", { value: "", children: "\u2014 kies een werkplek \u2014" }), werkplekken.filter((w) => w.actief).map((w) => (_jsx("option", { value: w.id, children: w.naam }, w.id)))] }), _jsx(Button, { disabled: !keuze, onClick: async () => {
18
+ try {
19
+ await kies(keuze);
20
+ setDicht(true);
21
+ }
22
+ catch (e) {
23
+ toast.error(leesbareFout(e, "Opslaan mislukt"));
24
+ }
25
+ }, children: "Onthouden" })] }) }));
26
+ }
@@ -0,0 +1,7 @@
1
+ import { type PrinterRij } from "../lib/werkplekken.js";
2
+ export declare function GeladenEtiketKeuze({ printer, onGewijzigd }: {
3
+ printer: PrinterRij;
4
+ onGewijzigd: () => void;
5
+ }): import("react").JSX.Element;
6
+ export declare function WerkplekkenTab(): import("react").JSX.Element;
7
+ //# sourceMappingURL=WerkplekkenTab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WerkplekkenTab.d.ts","sourceRoot":"","sources":["../../src/components/WerkplekkenTab.tsx"],"names":[],"mappings":"AAcA,OAAO,EAUL,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAM5B,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,IAAI,CAAA;CAAE,+BAmC5G;AAqPD,wBAAgB,cAAc,gCA4E7B"}