@flowselections/layout-maker 1.3.3 → 1.6.5

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 (112) hide show
  1. package/README.md +24 -24
  2. package/dist-lib/components/AfdrukKnop.d.ts +3 -1
  3. package/dist-lib/components/AfdrukKnop.d.ts.map +1 -1
  4. package/dist-lib/components/AfdrukKnop.js +24 -3
  5. package/dist-lib/components/ComputersLijst.d.ts +23 -0
  6. package/dist-lib/components/ComputersLijst.d.ts.map +1 -0
  7. package/dist-lib/components/ComputersLijst.js +75 -0
  8. package/dist-lib/components/LayoutsPage.d.ts.map +1 -1
  9. package/dist-lib/components/LayoutsPage.js +2 -0
  10. package/dist-lib/components/LogosPage.d.ts.map +1 -1
  11. package/dist-lib/components/LogosPage.js +2 -0
  12. package/dist-lib/components/NetwerkPrintersDialog.d.ts +8 -0
  13. package/dist-lib/components/NetwerkPrintersDialog.d.ts.map +1 -0
  14. package/dist-lib/components/NetwerkPrintersDialog.js +79 -0
  15. package/dist-lib/components/PrintProgrammaUitleg.d.ts +5 -0
  16. package/dist-lib/components/PrintProgrammaUitleg.d.ts.map +1 -0
  17. package/dist-lib/components/PrintProgrammaUitleg.js +19 -0
  18. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  19. package/dist-lib/components/PrintQueuePage.js +37 -3
  20. package/dist-lib/components/PrinterKaart.d.ts +17 -0
  21. package/dist-lib/components/PrinterKaart.d.ts.map +1 -0
  22. package/dist-lib/components/PrinterKaart.js +14 -0
  23. package/dist-lib/components/PrinterSetupWizard.d.ts +11 -1
  24. package/dist-lib/components/PrinterSetupWizard.d.ts.map +1 -1
  25. package/dist-lib/components/PrinterSetupWizard.js +134 -64
  26. package/dist-lib/components/PrinterStatsKaarten.d.ts +11 -0
  27. package/dist-lib/components/PrinterStatsKaarten.d.ts.map +1 -0
  28. package/dist-lib/components/PrinterStatsKaarten.js +8 -0
  29. package/dist-lib/components/PrintersPage.d.ts.map +1 -1
  30. package/dist-lib/components/PrintersPage.js +120 -49
  31. package/dist-lib/components/WerkplekConfiguratiePage.d.ts +2 -0
  32. package/dist-lib/components/WerkplekConfiguratiePage.d.ts.map +1 -0
  33. package/dist-lib/components/WerkplekConfiguratiePage.js +101 -0
  34. package/dist-lib/components/WerkplekkenTabel.d.ts +14 -0
  35. package/dist-lib/components/WerkplekkenTabel.d.ts.map +1 -0
  36. package/dist-lib/components/WerkplekkenTabel.js +16 -0
  37. package/dist-lib/index.d.ts +11 -0
  38. package/dist-lib/index.d.ts.map +1 -1
  39. package/dist-lib/index.js +11 -0
  40. package/dist-lib/integrations/supabase/auth-middleware.d.ts +925 -34
  41. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  42. package/dist-lib/integrations/supabase/client.server.d.ts +925 -34
  43. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  44. package/dist-lib/integrations/supabase/types.d.ts +920 -29
  45. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  46. package/dist-lib/integrations/supabase/types.js +12 -1
  47. package/dist-lib/lib/aiLayout.functions.d.ts +925 -34
  48. package/dist-lib/lib/aiLayout.functions.d.ts.map +1 -1
  49. package/dist-lib/lib/aiLayout.server.js +9 -9
  50. package/dist-lib/lib/browserPrint.d.ts +1 -0
  51. package/dist-lib/lib/browserPrint.d.ts.map +1 -1
  52. package/dist-lib/lib/browserPrint.js +6 -6
  53. package/dist-lib/lib/centralAuth.server.d.ts +13 -0
  54. package/dist-lib/lib/centralAuth.server.d.ts.map +1 -0
  55. package/dist-lib/lib/centralAuth.server.js +60 -0
  56. package/dist-lib/lib/directPrint.d.ts +26 -0
  57. package/dist-lib/lib/directPrint.d.ts.map +1 -0
  58. package/dist-lib/lib/directPrint.js +65 -0
  59. package/dist-lib/lib/documentPdf.d.ts +11 -0
  60. package/dist-lib/lib/documentPdf.d.ts.map +1 -0
  61. package/dist-lib/lib/documentPdf.js +62 -0
  62. package/dist-lib/lib/htmlNaarPdf.server.d.ts +14 -0
  63. package/dist-lib/lib/htmlNaarPdf.server.d.ts.map +1 -0
  64. package/dist-lib/lib/htmlNaarPdf.server.js +34 -0
  65. package/dist-lib/lib/htmlPdf.server.d.ts +29 -0
  66. package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -0
  67. package/dist-lib/lib/htmlPdf.server.js +1009 -0
  68. package/dist-lib/lib/layoutPreview.d.ts +1 -1
  69. package/dist-lib/lib/layoutPreview.d.ts.map +1 -1
  70. package/dist-lib/lib/layoutPreview.js +9 -9
  71. package/dist-lib/lib/logoLibrary.d.ts +1 -1
  72. package/dist-lib/lib/logoLibrary.js +5 -3
  73. package/dist-lib/lib/orderData.server.d.ts +15 -0
  74. package/dist-lib/lib/orderData.server.d.ts.map +1 -0
  75. package/dist-lib/lib/orderData.server.js +194 -0
  76. package/dist-lib/lib/pakbonBuilder.d.ts.map +1 -1
  77. package/dist-lib/lib/pakbonBuilder.js +22 -2
  78. package/dist-lib/lib/pakbonHtml.js +50 -50
  79. package/dist-lib/lib/printQueue.server.d.ts +31 -0
  80. package/dist-lib/lib/printQueue.server.d.ts.map +1 -0
  81. package/dist-lib/lib/printQueue.server.js +435 -0
  82. package/dist-lib/lib/printService.functions.d.ts +103742 -0
  83. package/dist-lib/lib/printService.functions.d.ts.map +1 -0
  84. package/dist-lib/lib/printService.functions.js +94 -0
  85. package/dist-lib/lib/printService.server.d.ts +31 -0
  86. package/dist-lib/lib/printService.server.d.ts.map +1 -0
  87. package/dist-lib/lib/printService.server.js +110 -0
  88. package/dist-lib/lib/productiebonHtml.d.ts +18 -0
  89. package/dist-lib/lib/productiebonHtml.d.ts.map +1 -0
  90. package/dist-lib/lib/productiebonHtml.js +166 -0
  91. package/dist-lib/lib/profielHtml.d.ts +14 -0
  92. package/dist-lib/lib/profielHtml.d.ts.map +1 -0
  93. package/dist-lib/lib/profielHtml.js +256 -0
  94. package/dist-lib/lib/runnerRegistry.server.d.ts +10 -0
  95. package/dist-lib/lib/runnerRegistry.server.d.ts.map +1 -0
  96. package/dist-lib/lib/runnerRegistry.server.js +79 -0
  97. package/dist-lib/lib/supabaseAdmin.server.d.ts +6 -0
  98. package/dist-lib/lib/supabaseAdmin.server.d.ts.map +1 -0
  99. package/dist-lib/lib/supabaseAdmin.server.js +43 -0
  100. package/dist-lib/lib/testpagina.d.ts +2 -0
  101. package/dist-lib/lib/testpagina.d.ts.map +1 -0
  102. package/dist-lib/lib/testpagina.js +31 -0
  103. package/dist-lib/lib/useAutoRefresh.d.ts +8 -0
  104. package/dist-lib/lib/useAutoRefresh.d.ts.map +1 -0
  105. package/dist-lib/lib/useAutoRefresh.js +44 -0
  106. package/dist-lib/lib/useDocumentData.d.ts +4 -3
  107. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  108. package/dist-lib/lib/useDocumentData.js +10 -7
  109. package/dist-lib/lib/useNetwerkPrinters.d.ts +12 -0
  110. package/dist-lib/lib/useNetwerkPrinters.d.ts.map +1 -0
  111. package/dist-lib/lib/useNetwerkPrinters.js +26 -0
  112. package/package.json +11 -3
@@ -1,16 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // ============================================================================
3
- // src/components/PrinterSetupWizard.tsx — eenvoudige setupwizard voor printers
3
+ // src/components/PrinterSetupWizard.tsx — printer toevoegen in drie stappen:
4
+ // kiezen uit het netwerk, naam en locatie geven, testpagina afdrukken.
4
5
  // ============================================================================
5
- import { useEffect, useState } from "react";
6
+ import { useCallback, useEffect, useMemo, useState } from "react";
6
7
  import { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, Input, Label, toast, } from "@flowselections/core";
7
- import { Check, CheckCircle2, FileText, Tag } from "lucide-react";
8
+ import { Check, CheckCircle2, FileText, Loader2, Printer, RefreshCw, Search, Tag, } from "lucide-react";
8
9
  import { supabase } from "../lib/supabaseClient";
9
- import { DOCUMENT_PROFIELEN } from "../lib/documentProfiles";
10
- import { zetFormaatPrinter } from "../lib/formaatPrinters";
11
10
  import { drukAf } from "../lib/browserPrint";
12
- const STAPPEN = ["Printer", "Documenten", "Klaar"];
13
- /** Vertaalt een simpele keuze naar de technische printerinstellingen. */
11
+ import { printDirect } from "../lib/directPrint";
12
+ import { netwerkPrinters } from "../lib/printService.functions";
13
+ import { PrintProgrammaUitleg, WerktHetNiet } from "./PrintProgrammaUitleg";
14
+ const STAPPEN = ["Printer kiezen", "Naam en locatie", "Klaar"];
14
15
  function instellingenVoor(gebruik) {
15
16
  return gebruik === "etiket"
16
17
  ? { soort: "labelprinter", papierformaat: "label" }
@@ -21,42 +22,109 @@ function Stappenbalk({ stap }) {
21
22
  ? "bg-primary text-primary-foreground"
22
23
  : i === stap
23
24
  ? "border-primary text-primary border-2"
24
- : "bg-muted text-muted-foreground"}`, children: i < stap ? _jsx(Check, { className: "h-4 w-4" }) : i + 1 }), _jsx("span", { className: `text-sm ${i === stap ? "text-foreground font-medium" : "text-muted-foreground"}`, children: s }), i < STAPPEN.length - 1 && _jsx("div", { className: "bg-border h-px flex-1" })] }, s))) }));
25
+ : "bg-muted text-muted-foreground"}`, children: i < stap ? _jsx(Check, { className: "h-4 w-4" }) : i + 1 }), _jsx("span", { className: `hidden text-sm sm:inline ${i === stap ? "text-foreground font-medium" : "text-muted-foreground"}`, children: s }), i < STAPPEN.length - 1 && _jsx("div", { className: "bg-border h-px flex-1" })] }, s))) }));
25
26
  }
26
- export function PrinterSetupWizard({ open, onOpenChange, onKlaar, }) {
27
+ export function PrinterSetupWizard({ open, onOpenChange, onKlaar, computerFilter, bekendeExterneIds = [], bekendeLocaties = [], bewerken, }) {
27
28
  const [stap, setStap] = useState(0);
28
29
  const [bezig, setBezig] = useState(false);
29
- const [printernaam, setPrinternaam] = useState("");
30
- const [systeemnaam, setSysteemnaam] = useState("");
30
+ const [zoekt, setZoekt] = useState(false);
31
+ const [fout, setFout] = useState(null);
32
+ const [lijst, setLijst] = useState([]);
33
+ const [zoekterm, setZoekterm] = useState("");
34
+ const [uitlegOpen, setUitlegOpen] = useState(false);
35
+ const [gekozen, setGekozen] = useState(null);
36
+ const [naam, setNaam] = useState("");
37
+ const [locatie, setLocatie] = useState("");
31
38
  const [gebruik, setGebruik] = useState("papier");
32
39
  const [printerId, setPrinterId] = useState(null);
33
- const [keuzes, setKeuzes] = useState({});
34
- const resetAlles = () => {
35
- setStap(0);
36
- setPrinternaam("");
37
- setSysteemnaam("");
38
- setGebruik("papier");
39
- setPrinterId(null);
40
- setKeuzes({});
41
- };
40
+ const zoeken = useCallback(async () => {
41
+ setZoekt(true);
42
+ setFout(null);
43
+ try {
44
+ const res = await netwerkPrinters({ data: undefined });
45
+ if (!res.ok) {
46
+ setFout(res.fout);
47
+ setLijst([]);
48
+ }
49
+ else {
50
+ setLijst(Array.isArray(res.printers) ? res.printers : []);
51
+ }
52
+ }
53
+ catch {
54
+ setFout("Er kon niet in het netwerk worden gezocht. Probeer het zo opnieuw.");
55
+ setLijst([]);
56
+ }
57
+ finally {
58
+ setZoekt(false);
59
+ }
60
+ }, []);
42
61
  useEffect(() => {
43
- if (!open)
44
- resetAlles();
45
- }, [open]);
46
- const printerOpslaan = async () => {
47
- const naam = printernaam.trim() || systeemnaam.trim();
48
- if (!naam) {
62
+ if (!open) {
63
+ setStap(0);
64
+ setGekozen(null);
65
+ setNaam("");
66
+ setLocatie("");
67
+ setGebruik("papier");
68
+ setPrinterId(null);
69
+ setZoekterm("");
70
+ setUitlegOpen(false);
71
+ return;
72
+ }
73
+ if (bewerken) {
74
+ setStap(1);
75
+ setPrinterId(bewerken.id);
76
+ setNaam(bewerken.naam);
77
+ setLocatie(bewerken.locatie ?? "");
78
+ setGebruik(bewerken.papierformaat === "label" ? "etiket" : "papier");
79
+ return;
80
+ }
81
+ void zoeken();
82
+ }, [open, bewerken, zoeken]);
83
+ const zichtbaar = useMemo(() => {
84
+ const term = zoekterm.trim().toLowerCase();
85
+ return lijst
86
+ .filter((p) => (computerFilter ? p.computer === computerFilter : true))
87
+ .filter((p) => (term ? `${p.naam} ${p.computer}`.toLowerCase().includes(term) : true));
88
+ }, [lijst, zoekterm, computerFilter]);
89
+ const kiesPrinter = (p) => {
90
+ setGekozen(p);
91
+ setNaam(p.naam);
92
+ setLocatie(p.computer ?? "");
93
+ setStap(1);
94
+ };
95
+ const opslaan = async () => {
96
+ const eindnaam = naam.trim() || gekozen?.naam || "";
97
+ if (!eindnaam) {
49
98
  toast.error("Geef de printer een naam");
50
99
  return;
51
100
  }
52
101
  setBezig(true);
53
102
  try {
103
+ if (bewerken) {
104
+ const { error } = await supabase
105
+ .from("printers")
106
+ .update({
107
+ naam: eindnaam,
108
+ locatie: locatie.trim() || null,
109
+ ...instellingenVoor(gebruik),
110
+ })
111
+ .eq("id", bewerken.id);
112
+ if (error)
113
+ throw error;
114
+ toast.success("Printer bijgewerkt");
115
+ onKlaar?.();
116
+ onOpenChange(false);
117
+ return;
118
+ }
54
119
  const { data, error } = await supabase
55
120
  .from("printers")
56
121
  .insert({
57
- naam,
122
+ naam: eindnaam,
58
123
  actief: true,
59
- systeemnaam: systeemnaam.trim() || naam,
124
+ online: gekozen?.online ?? false,
125
+ systeemnaam: gekozen?.naam ?? eindnaam,
126
+ locatie: locatie.trim() || null,
127
+ extern_printer_id: gekozen?.id ?? null,
60
128
  ...instellingenVoor(gebruik),
61
129
  })
62
130
  .select("id")
@@ -64,7 +132,7 @@ export function PrinterSetupWizard({ open, onOpenChange, onKlaar, }) {
64
132
  if (error)
65
133
  throw error;
66
134
  setPrinterId(data?.id ?? null);
67
- setStap(1);
135
+ setStap(2);
68
136
  onKlaar?.();
69
137
  }
70
138
  catch {
@@ -74,46 +142,48 @@ export function PrinterSetupWizard({ open, onOpenChange, onKlaar, }) {
74
142
  setBezig(false);
75
143
  }
76
144
  };
77
- const koppelingenOpslaan = async () => {
78
- if (!printerId)
79
- return;
80
- setBezig(true);
145
+ const [testStatus, setTestStatus] = useState("leeg");
146
+ const testpagina = async () => {
147
+ setTestStatus("bezig");
148
+ const html = `<div style="padding:20mm;font-size:14pt"><h1 style="font-size:20pt">Testpagina</h1>
149
+ <p>Deze pagina hoort uit: <strong>${naam}</strong></p></div>`;
150
+ const opdracht = {
151
+ documenttype: "pakbon",
152
+ formaatCode: gebruik === "etiket" ? "label" : "A4",
153
+ orientatie: "portrait",
154
+ documentnaam: "Testpagina",
155
+ html,
156
+ printerId: printerId ?? undefined,
157
+ };
81
158
  try {
82
- for (const [documenttype, formaatCode] of Object.entries(keuzes)) {
83
- await zetFormaatPrinter(documenttype, formaatCode, printerId);
159
+ const direct = await printDirect(opdracht);
160
+ if (direct.gelukt) {
161
+ setTestStatus("gelukt");
162
+ return;
84
163
  }
85
- setStap(2);
164
+ await drukAf(opdracht);
165
+ setTestStatus("gelukt");
86
166
  }
87
167
  catch {
88
- toast.error("Opslaan van de documentkeuzes mislukt");
89
- }
90
- finally {
91
- setBezig(false);
168
+ setTestStatus("fout");
92
169
  }
93
170
  };
94
- const testpaginaAfdrukken = async () => {
95
- const naam = printernaam || systeemnaam;
96
- await drukAf({
97
- documenttype: "pakbon",
98
- formaatCode: gebruik === "etiket" ? "label" : "A4",
99
- orientatie: "portrait",
100
- documentnaam: "Testpagina",
101
- html: `<div style="padding:20mm;font-size:14pt"><h1 style="font-size:20pt">Testpagina</h1>
102
- <p>Deze pagina hoort uit: <strong>${naam}</strong></p></div>`,
103
- });
171
+ const opnieuw = () => {
172
+ setStap(0);
173
+ setGekozen(null);
174
+ setNaam("");
175
+ setLocatie("");
176
+ setPrinterId(null);
177
+ setTestStatus("leeg");
178
+ void zoeken();
104
179
  };
105
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-h-[85vh] overflow-y-auto sm:max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Printer instellen" }), _jsx(DialogDescription, { children: "Twee korte stappen, daarna staat alles goed." })] }), _jsx(Stappenbalk, { stap: stap }), stap === 0 && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Naam van de printer" }), _jsx(Input, { value: printernaam, placeholder: "Bijvoorbeeld: printer magazijn", onChange: (e) => setPrinternaam(e.target.value) }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Gebruik dezelfde naam als in het printvenster van deze computer, dan weet u meteen welke u moet kiezen." })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Wat gaat deze printer afdrukken?" }), _jsx("div", { className: "grid grid-cols-2 gap-3", children: [
106
- { code: "papier", label: "Papier", sub: "Gewone A4-documenten", Icon: FileText },
107
- { code: "etiket", label: "Etiketten", sub: "Stickers en labels", Icon: Tag },
108
- ].map((o) => (_jsxs("button", { type: "button", onClick: () => setGebruik(o.code), className: `hover:bg-accent rounded-lg border p-4 text-left transition ${gebruik === o.code ? "border-primary bg-accent" : ""}`, children: [_jsx(o.Icon, { className: "text-muted-foreground mb-2 h-5 w-5" }), _jsx("p", { className: "text-sm font-medium", children: o.label }), _jsx("p", { className: "text-muted-foreground text-xs", children: o.sub })] }, o.code))) })] }), _jsx("div", { className: "flex justify-end", children: _jsx(Button, { disabled: bezig, onClick: () => void printerOpslaan(), children: "Opslaan en verder" }) })] })), stap === 1 && (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium", children: "Wat drukt deze printer af?" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Kies per soort document het formaat. Daarna staan papierformaat en stand bij het afdrukken automatisch goed." })] }), _jsx("div", { className: "space-y-3", children: DOCUMENT_PROFIELEN.map((profiel) => {
109
- const gekozen = keuzes[profiel.id];
110
- return (_jsxs("div", { className: "rounded-lg border p-3", children: [_jsx("p", { className: "text-sm font-medium", children: profiel.label }), _jsx("div", { className: "mt-2 flex flex-wrap gap-2", children: profiel.formaten.map((f) => (_jsx("button", { type: "button", onClick: () => setKeuzes((k) => {
111
- const n = { ...k };
112
- if (n[profiel.id] === f.code)
113
- delete n[profiel.id];
114
- else
115
- n[profiel.id] = f.code;
116
- return n;
117
- }), className: `hover:bg-accent rounded-md border px-3 py-1.5 text-xs transition ${gekozen === f.code ? "border-primary bg-accent" : ""}`, children: f.label }, f.code))) })] }, profiel.id));
118
- }) }), _jsxs("div", { className: "flex justify-between", children: [_jsx(Button, { variant: "ghost", onClick: () => setStap(2), children: "Overslaan" }), _jsx(Button, { disabled: bezig, onClick: () => void koppelingenOpslaan(), children: "Opslaan en verder" })] })] })), stap === 2 && (_jsxs("div", { className: "space-y-4 text-center", children: [_jsx(CheckCircle2, { className: "text-primary mx-auto h-10 w-10" }), _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "De printer is klaar voor gebruik" }), _jsxs("p", { className: "text-muted-foreground text-sm", children: [printernaam || systeemnaam, " staat klaar. Papierformaat en stand worden voortaan automatisch ingesteld bij het afdrukken."] })] }), _jsxs("div", { className: "flex flex-wrap justify-center gap-2", children: [_jsx(Button, { variant: "outline", onClick: () => void testpaginaAfdrukken(), children: "Testpagina afdrukken" }), _jsx(Button, { variant: "ghost", onClick: resetAlles, children: "Nog een printer instellen" }), _jsx(Button, { onClick: () => onOpenChange(false), children: "Klaar" })] })] }))] }) }));
180
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-h-[85vh] overflow-y-auto sm:max-w-xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: bewerken ? "Naam en locatie wijzigen" : "Printer toevoegen" }), _jsx(DialogDescription, { children: bewerken
181
+ ? "Pas de naam, de locatie en het soort papier aan."
182
+ : "Kies uw printer, geef hem een herkenbare naam en druk een testpagina af." })] }), !bewerken && _jsx(Stappenbalk, { stap: stap }), stap === 0 && (_jsxs("div", { className: "space-y-4", children: [lijst.length > 6 && (_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground absolute top-2.5 left-3 h-4 w-4" }), _jsx(Input, { className: "pl-9", value: zoekterm, placeholder: "Zoek op printer of computer", onChange: (e) => setZoekterm(e.target.value) })] })), zoekt && (_jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Printers zoeken\u2026"] })), !zoekt && fout && _jsx("p", { className: "text-destructive text-sm", children: fout }), !zoekt && zichtbaar.length > 0 && (_jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: zichtbaar.map((p) => {
183
+ const al = bekendeExterneIds.includes(p.id);
184
+ return (_jsx("button", { type: "button", disabled: al, onClick: () => kiesPrinter(p), className: `rounded-xl border p-4 text-left transition ${al ? "opacity-60" : "hover:border-primary/50 hover:bg-accent/40"}`, children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(Printer, { className: "text-muted-foreground mt-0.5 h-5 w-5 shrink-0" }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "truncate text-sm font-medium", children: p.naam }), _jsx("p", { className: "text-muted-foreground truncate text-xs", children: p.computer }), _jsxs("span", { className: "mt-2 flex items-center gap-1.5 text-xs", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${p.online ? "bg-primary" : "bg-muted-foreground/40"}` }), al ? "Al toegevoegd" : p.online ? "Beschikbaar" : "Niet aan"] })] })] }) }, p.id));
185
+ }) })), !zoekt && zichtbaar.length === 0 && _jsx(PrintProgrammaUitleg, {}), !zoekt && zichtbaar.length > 0 && (_jsxs("div", { className: "space-y-3", children: [_jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground text-sm underline", onClick: () => setUitlegOpen((v) => !v), children: "Ik zie mijn printer niet" }), uitlegOpen && _jsx(PrintProgrammaUitleg, { compact: true })] })), _jsx("div", { className: "flex justify-between", children: _jsxs(Button, { variant: "ghost", onClick: () => void zoeken(), disabled: zoekt, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), " Opnieuw zoeken"] }) })] })), stap === 1 && (_jsxs("div", { className: "grid gap-5 sm:grid-cols-[1fr_200px]", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Weergavenaam" }), _jsx(Input, { value: naam, placeholder: "Bijvoorbeeld: pakbonprinter voorin", onChange: (e) => setNaam(e.target.value) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Locatie" }), _jsx(Input, { value: locatie, placeholder: "Bijvoorbeeld: magazijn", onChange: (e) => setLocatie(e.target.value) }), bekendeLocaties.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 pt-1", children: bekendeLocaties.slice(0, 6).map((l) => (_jsx("button", { type: "button", onClick: () => setLocatie(l), className: "hover:bg-accent rounded-full border px-3 py-1 text-xs", children: l }, l))) }))] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Wat gaat deze printer afdrukken?" }), _jsx("div", { className: "grid grid-cols-2 gap-3", children: [
186
+ { code: "papier", label: "Papier (A4)", sub: "Gewone documenten", Icon: FileText },
187
+ { code: "etiket", label: "Etiketten", sub: "Stickers en labels", Icon: Tag },
188
+ ].map((o) => (_jsxs("button", { type: "button", onClick: () => setGebruik(o.code), className: `hover:bg-accent rounded-lg border p-4 text-left transition ${gebruik === o.code ? "border-primary bg-accent" : ""}`, children: [_jsx(o.Icon, { className: "text-muted-foreground mb-2 h-5 w-5" }), _jsx("p", { className: "text-sm font-medium", children: o.label }), _jsx("p", { className: "text-muted-foreground text-xs", children: o.sub })] }, o.code))) })] }), _jsxs("div", { className: "flex justify-between", children: [!bewerken ? (_jsx(Button, { variant: "ghost", onClick: () => setStap(0), children: "Terug" })) : (_jsx("span", {})), _jsx(Button, { disabled: bezig, onClick: () => void opslaan(), children: bewerken ? "Opslaan" : "Opslaan en verder" })] })] }), _jsxs("div", { className: "hidden sm:block", children: [_jsx("p", { className: "text-muted-foreground mb-2 text-xs", children: "Zo komt hij in de lijst:" }), _jsxs("div", { className: "bg-card rounded-xl border p-3", children: [_jsx(Printer, { className: "text-muted-foreground mb-2 h-4 w-4" }), _jsx("p", { className: "truncate text-sm font-medium", children: naam || "Naam van de printer" }), _jsx("p", { className: "text-muted-foreground truncate text-xs", children: locatie || "Geen locatie" })] })] })] })), stap === 2 && (_jsxs("div", { className: "space-y-4 text-center", children: [_jsx(CheckCircle2, { className: "text-primary mx-auto h-10 w-10" }), _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "De printer is klaar voor gebruik" }), _jsxs("p", { className: "text-muted-foreground text-sm", children: [naam, " ", locatie ? `bij ${locatie}` : "", " drukt voortaan automatisch af."] })] }), testStatus !== "leeg" && (_jsxs("p", { className: "text-muted-foreground text-sm", children: [testStatus === "bezig" && "Onderweg naar de printer…", testStatus === "gelukt" && "De testpagina is verstuurd.", testStatus === "fout" && "De testpagina kon niet worden afgedrukt."] })), _jsxs("div", { className: "flex flex-wrap justify-center gap-2", children: [_jsx(Button, { variant: "outline", onClick: () => void testpagina(), children: "Testpagina afdrukken" }), _jsx(Button, { variant: "ghost", onClick: opnieuw, children: "Nog een printer toevoegen" }), _jsx(Button, { onClick: () => onOpenChange(false), children: "Klaar" })] }), _jsx(WerktHetNiet, {})] }))] }) }));
119
189
  }
@@ -0,0 +1,11 @@
1
+ import type { LucideIcon } from "lucide-react";
2
+ export interface StatKaart {
3
+ label: string;
4
+ waarde: string;
5
+ toelichting: string;
6
+ icon: LucideIcon;
7
+ }
8
+ export declare function PrinterStatsKaarten({ kaarten }: {
9
+ kaarten: StatKaart[];
10
+ }): import("react").JSX.Element;
11
+ //# sourceMappingURL=PrinterStatsKaarten.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrinterStatsKaarten.d.ts","sourceRoot":"","sources":["../../src/components/PrinterStatsKaarten.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,SAAS,EAAE,CAAA;CAAE,+BAmBxE"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/PrinterStatsKaarten.tsx — vier kerncijfers bovenaan de pagina
4
+ // ============================================================================
5
+ import { Card, CardContent } from "@flowselections/core";
6
+ export function PrinterStatsKaarten({ kaarten }) {
7
+ return (_jsx("div", { className: "grid gap-4 sm:grid-cols-2 xl:grid-cols-4", children: kaarten.map((k) => (_jsx(Card, { children: _jsxs(CardContent, { className: "flex items-center gap-4 py-5", children: [_jsx("div", { className: "bg-muted rounded-lg p-3", children: _jsx(k.icon, { className: "text-muted-foreground h-5 w-5" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-muted-foreground truncate text-sm", children: k.label }), _jsx("p", { className: "text-2xl font-semibold leading-tight", children: k.waarde }), _jsx("p", { className: "text-muted-foreground truncate text-xs", children: k.toelichting })] })] }) }, k.label))) }));
8
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"PrintersPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintersPage.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,YAAY,gCAoK3B"}
1
+ {"version":3,"file":"PrintersPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintersPage.tsx"],"names":[],"mappings":"AAyBA,wBAAgB,YAAY,gCA6O3B"}
@@ -1,60 +1,131 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/PrintersPage.tsx — overzicht van werkplekken (computers) met
4
+ // hun printers, status en snelkoppelingen naar het configuratiescherm.
5
+ // ============================================================================
2
6
  import { useMemo, useState } from "react";
3
- import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Checkbox, toast, } from "@flowselections/core";
7
+ import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@flowselections/core";
4
8
  import { Link } from "@tanstack/react-router";
5
- import { ListChecks, Plus, Printer, Trash2 } from "lucide-react";
6
- import { toggleKoppeling, useLayouts, usePrinters, verwijderPrinter } from "../lib/useDocumentData";
7
- import { drukAf } from "../lib/browserPrint";
9
+ import { CheckCircle2, FileText, ListChecks, Monitor, Plus, Printer, Search } from "lucide-react";
10
+ import { bijgewerktTekst, useAutoRefresh } from "../lib/useAutoRefresh";
11
+ import { useLayouts, usePrinters } from "../lib/useDocumentData";
12
+ import { useNetwerkPrinters } from "../lib/useNetwerkPrinters";
8
13
  import { PrinterSetupWizard } from "./PrinterSetupWizard";
14
+ import { ComputersLijst, useComputers } from "./ComputersLijst";
15
+ import { PrinterStatsKaarten } from "./PrinterStatsKaarten";
16
+ import { WerkplekkenTabel } from "./WerkplekkenTabel";
9
17
  export function PrintersPage() {
10
- const { printers, koppelingen, loading, reload } = usePrinters();
18
+ const { printers, koppelingen, reload } = usePrinters();
11
19
  const { layouts } = useLayouts();
20
+ const { computers, loading: computersLaden, fout: computersFout, reload: herlaadComputers, } = useComputers();
21
+ const { gevonden, zoek } = useNetwerkPrinters();
12
22
  const [wizard, setWizard] = useState(false);
13
- const [gekozenPrinter, setGekozenPrinter] = useState(null);
14
- const gekoppeld = useMemo(() => {
23
+ const [computerToevoegen, setComputerToevoegen] = useState(false);
24
+ const [computerFilter, setComputerFilter] = useState(null);
25
+ const [bewerken] = useState(null);
26
+ const [zoekterm, setZoekterm] = useState("");
27
+ const [status, setStatus] = useState("alle");
28
+ const [locatie, setLocatie] = useState("alle");
29
+ const bijgewerkt = useAutoRefresh(async () => {
30
+ await Promise.all([reload(true), herlaadComputers(true), zoek()]);
31
+ }, 10000, wizard || computerToevoegen);
32
+ const gekoppeldePrinters = useMemo(() => new Set(koppelingen.map((k) => k.printer_id)), [koppelingen]);
33
+ const printersPerComputer = useMemo(() => {
34
+ const externNaarComputer = new Map(gevonden.map((g) => [g.id, g.computer]));
15
35
  const map = new Map();
16
- for (const k of koppelingen) {
17
- if (!map.has(k.printer_id))
18
- map.set(k.printer_id, new Set());
19
- map.get(k.printer_id).add(k.layout_id);
36
+ for (const p of printers) {
37
+ const extern = p.extern_printer_id ?? null;
38
+ const naam = extern ? externNaarComputer.get(extern) : undefined;
39
+ if (!naam)
40
+ continue;
41
+ const rij = map.get(naam) ?? { totaal: 0, gekoppeld: 0, locaties: [] };
42
+ rij.totaal += 1;
43
+ if (gekoppeldePrinters.has(p.id))
44
+ rij.gekoppeld += 1;
45
+ if (p.locatie && !rij.locaties.includes(p.locatie))
46
+ rij.locaties.push(p.locatie);
47
+ map.set(naam, rij);
20
48
  }
21
49
  return map;
22
- }, [koppelingen]);
23
- const actievePrinter = printers.find((p) => p.id === gekozenPrinter) ?? null;
24
- const testpagina = async (naam) => {
25
- try {
26
- await drukAf({
27
- documenttype: "pakbon",
28
- formaatCode: "A4",
29
- orientatie: "portrait",
30
- documentnaam: "Testpagina",
31
- html: `<div style="padding:20mm;font-size:14pt"><h1 style="font-size:20pt">Testpagina</h1>
32
- <p>Deze pagina hoort uit: <strong>${naam}</strong></p></div>`,
33
- });
34
- }
35
- catch {
36
- toast.error("De testpagina kon niet worden geopend");
37
- }
38
- };
39
- 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: "Printers" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Stel een printer in en kies wat erop wordt afgedrukt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", asChild: true, children: _jsxs(Link, { to: "/layouts-printers/wachtrij", children: [_jsx(ListChecks, { className: "mr-2 h-4 w-4" }), " Printwachtrij"] }) }), _jsxs(Button, { onClick: () => setWizard(true), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Printer instellen"] })] })] }), _jsxs("div", { className: "grid gap-6 lg:grid-cols-[1fr_340px]", children: [_jsxs("div", { className: "space-y-3", children: [loading && _jsx("p", { className: "text-muted-foreground text-sm", children: "Laden\u2026" }), !loading && printers.length === 0 && (_jsx(Card, { children: _jsxs(CardContent, { className: "py-12 text-center", children: [_jsx(Printer, { className: "text-muted-foreground mx-auto mb-3 h-8 w-8" }), _jsx("p", { className: "text-sm font-medium", children: "Nog geen printers" }), _jsx("p", { className: "text-muted-foreground mb-4 text-sm", children: "In drie korte stappen is uw printer klaar voor gebruik." }), _jsx(Button, { onClick: () => setWizard(true), children: "Printer instellen" })] }) })), printers.map((p) => (_jsxs("button", { type: "button", onClick: () => setGekozenPrinter(p.id), className: `hover:bg-accent/50 flex w-full items-center gap-3 rounded-lg border p-4 text-left transition ${p.id === gekozenPrinter ? "border-primary bg-accent/40" : ""}`, children: [_jsx(Printer, { className: "text-muted-foreground h-5 w-5" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "truncate text-sm font-medium", children: p.naam }), _jsx("p", { className: "text-muted-foreground text-xs", children: p.locatie ? `Bij ${p.locatie}` : "Geen computer gekozen" })] }), _jsx("span", { className: `h-2.5 w-2.5 rounded-full ${p.actief ? "bg-primary" : "bg-muted-foreground/40"}` }), _jsx(Button, { variant: "ghost", size: "sm", onClick: (e) => {
40
- e.stopPropagation();
41
- void testpagina(p.naam);
42
- }, children: "Testpagina" }), _jsx(Button, { variant: "ghost", size: "sm", title: "Verwijderen", onClick: async (e) => {
43
- e.stopPropagation();
44
- try {
45
- await verwijderPrinter(p.id);
46
- toast.success("Printer verwijderd");
47
- void reload();
48
- }
49
- catch {
50
- toast.error("Verwijderen mislukt");
51
- }
52
- }, children: _jsx(Trash2, { className: "h-4 w-4" }) })] }, p.id)))] }), _jsx("div", { className: "space-y-6", children: _jsxs(Card, { className: "h-fit", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Wat wordt hier afgedrukt?" }), _jsx(CardDescription, { children: actievePrinter ? actievePrinter.naam : "Kies eerst een printer" })] }), _jsxs(CardContent, { className: "space-y-3", children: [!actievePrinter && (_jsx("p", { className: "text-muted-foreground text-sm", children: "Nog geen printer gekozen." })), actievePrinter &&
53
- layouts.map((l) => {
54
- const aan = gekoppeld.get(actievePrinter.id)?.has(l.id) ?? false;
55
- return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Checkbox, { checked: aan, onCheckedChange: async (v) => {
56
- await toggleKoppeling(l.id, actievePrinter.id, !!v);
57
- void reload();
58
- } }), _jsxs("div", { className: "min-w-0", children: [_jsx("span", { className: "block truncate text-sm", children: l.naam }), _jsx("span", { className: "text-muted-foreground text-xs", children: l.papierformaat })] })] }, l.id));
59
- }), actievePrinter && layouts.length === 0 && (_jsx("p", { className: "text-muted-foreground text-sm", children: "Er zijn nog geen ontwerpen." }))] })] }) })] }), _jsx(PrinterSetupWizard, { open: wizard, onOpenChange: setWizard, onKlaar: () => void reload() })] }));
50
+ }, [printers, gevonden, gekoppeldePrinters]);
51
+ const alleRijen = computers.map((c) => {
52
+ const info = printersPerComputer.get(c.naam);
53
+ return {
54
+ id: c.id,
55
+ naam: c.naam,
56
+ online: c.online,
57
+ locatie: info?.locaties.join(" · ") || "Geen locatie",
58
+ aantalPrinters: info?.totaal ?? c.aantalPrinters,
59
+ aantalGekoppeld: info?.gekoppeld ?? 0,
60
+ };
61
+ });
62
+ const locaties = Array.from(new Set(alleRijen.map((r) => r.locatie))).filter((l) => l !== "Geen locatie");
63
+ const rijen = alleRijen.filter((r) => {
64
+ const term = zoekterm.trim().toLowerCase();
65
+ if (term && !r.naam.toLowerCase().includes(term) && !r.locatie.toLowerCase().includes(term))
66
+ return false;
67
+ if (status === "aan" && !r.online)
68
+ return false;
69
+ if (status === "uit" && r.online)
70
+ return false;
71
+ if (locatie !== "alle" && r.locatie !== locatie)
72
+ return false;
73
+ return true;
74
+ });
75
+ const computersOnline = computers.filter((c) => c.online).length;
76
+ const bekendeExterneIds = printers
77
+ .map((p) => p.extern_printer_id ?? null)
78
+ .filter((e) => !!e);
79
+ const bekendeLocaties = Array.from(new Set(printers.map((p) => p.locatie).filter((l) => !!l)));
80
+ 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: "Printers" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Beheer per werkplek welke computer is aangemeld en welke printers worden gebruikt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", asChild: true, children: _jsxs(Link, { to: "/layouts-printers/wachtrij", children: [_jsx(ListChecks, { className: "mr-2 h-4 w-4" }), " Printwachtrij"] }) }), _jsxs(Button, { onClick: () => setComputerToevoegen(true), children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Computer toevoegen"] })] })] }), _jsx(PrinterStatsKaarten, { kaarten: [
81
+ {
82
+ label: "Werkplekken",
83
+ waarde: String(computers.length),
84
+ toelichting: "Aangemelde computers",
85
+ icon: Monitor,
86
+ },
87
+ {
88
+ label: "Totaal printers",
89
+ waarde: String(printers.length),
90
+ toelichting: "Ingestelde printers",
91
+ icon: Printer,
92
+ },
93
+ {
94
+ label: "Documenten",
95
+ waarde: String(layouts.length),
96
+ toelichting: "Beschikbare ontwerpen",
97
+ icon: FileText,
98
+ },
99
+ {
100
+ label: "Status",
101
+ waarde: `${computersOnline} / ${computers.length}`,
102
+ toelichting: "Werkplekken aan",
103
+ icon: CheckCircle2,
104
+ },
105
+ ] }), _jsxs("div", { className: "flex flex-wrap items-center gap-3 rounded-xl border p-3", children: [_jsxs("div", { className: "relative min-w-[220px] flex-1", children: [_jsx(Search, { className: "text-muted-foreground absolute top-2.5 left-3 h-4 w-4" }), _jsx(Input, { className: "pl-9", placeholder: "Zoek werkplek of locatie\u2026", value: zoekterm, onChange: (e) => setZoekterm(e.target.value) })] }), _jsxs(Select, { value: status, onValueChange: setStatus, children: [_jsx(SelectTrigger, { className: "w-[170px]", children: _jsx(SelectValue, { placeholder: "Status" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Status: alle" }), _jsx(SelectItem, { value: "aan", children: "Alleen aan" }), _jsx(SelectItem, { value: "uit", children: "Alleen uit" })] })] }), _jsxs(Select, { value: locatie, onValueChange: setLocatie, children: [_jsx(SelectTrigger, { className: "w-[190px]", children: _jsx(SelectValue, { placeholder: "Locatie" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "alle", children: "Locatie: alle" }), locaties.map((l) => (_jsx(SelectItem, { value: l, children: l }, l)))] })] }), _jsx("span", { className: "text-muted-foreground ml-auto text-xs", children: bijgewerktTekst(bijgewerkt) })] }), rijen.length > 0 ? (_jsx(WerkplekkenTabel, { rijen: rijen, onPrinterToevoegen: (computer) => {
106
+ setComputerFilter(computer);
107
+ setWizard(true);
108
+ }, onVernieuw: () => {
109
+ void herlaadComputers();
110
+ void zoek();
111
+ } })) : (_jsx(ComputersLijst, { computers: computers, loading: computersLaden, fout: computersFout, onVernieuw: () => {
112
+ void herlaadComputers();
113
+ void zoek();
114
+ }, onPrintersToevoegen: (computer) => {
115
+ setComputerFilter(computer);
116
+ setWizard(true);
117
+ }, toevoegenOpen: false, onToevoegenOpenChange: setComputerToevoegen })), _jsx(ComputersLijst, { computers: computers, loading: false, fout: null, onVernieuw: () => {
118
+ void herlaadComputers();
119
+ void zoek();
120
+ }, onPrintersToevoegen: (computer) => {
121
+ setComputerFilter(computer);
122
+ setWizard(true);
123
+ }, toevoegenOpen: computerToevoegen, onToevoegenOpenChange: setComputerToevoegen, alleenDialog: true }), _jsx(PrinterSetupWizard, { open: wizard, onOpenChange: (v) => {
124
+ setWizard(v);
125
+ if (!v)
126
+ setComputerFilter(null);
127
+ }, computerFilter: computerFilter, bekendeExterneIds: bekendeExterneIds, bekendeLocaties: bekendeLocaties, bewerken: bewerken, onKlaar: () => {
128
+ void reload();
129
+ void zoek();
130
+ } })] }));
60
131
  }
@@ -0,0 +1,2 @@
1
+ export declare function WerkplekConfiguratiePage(): import("react").JSX.Element;
2
+ //# sourceMappingURL=WerkplekConfiguratiePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WerkplekConfiguratiePage.d.ts","sourceRoot":"","sources":["../../src/components/WerkplekConfiguratiePage.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,wBAAwB,gCA6QvC"}
@@ -0,0 +1,101 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/WerkplekConfiguratiePage.tsx — één computer configureren:
4
+ // printers op deze computer en welke ontwerpen er worden afgedrukt.
5
+ // ============================================================================
6
+ import { useMemo, useState } from "react";
7
+ import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Checkbox, Input, toast, } from "@flowselections/core";
8
+ import { Link, useParams } from "@tanstack/react-router";
9
+ import { ChevronRight, Monitor, Plus, Printer, Search } from "lucide-react";
10
+ import { bijgewerktTekst, useAutoRefresh } from "../lib/useAutoRefresh";
11
+ import { toggleKoppeling, useLayouts, usePrinters, verwijderPrinter } from "../lib/useDocumentData";
12
+ import { useNetwerkPrinters } from "../lib/useNetwerkPrinters";
13
+ import { drukTestpaginaAf } from "../lib/testpagina";
14
+ import { useComputers } from "./ComputersLijst";
15
+ import { PrinterKaart } from "./PrinterKaart";
16
+ import { PrinterSetupWizard } from "./PrinterSetupWizard";
17
+ export function WerkplekConfiguratiePage() {
18
+ const params = useParams({ strict: false });
19
+ const computerId = params.computerId ?? "";
20
+ const { printers, koppelingen, reload } = usePrinters();
21
+ const { layouts } = useLayouts();
22
+ const { computers, reload: herlaadComputers } = useComputers();
23
+ const { gevonden, zoek } = useNetwerkPrinters();
24
+ const [wizard, setWizard] = useState(false);
25
+ const [bewerken, setBewerken] = useState(null);
26
+ const [gekozenPrinter, setGekozenPrinter] = useState(null);
27
+ const [zoekComputer, setZoekComputer] = useState("");
28
+ const [layoutZoek, setLayoutZoek] = useState("");
29
+ const bijgewerkt = useAutoRefresh(async () => {
30
+ await Promise.all([reload(true), herlaadComputers(true), zoek()]);
31
+ }, 10000, wizard);
32
+ const computer = computers.find((c) => c.id === computerId) ?? null;
33
+ const beschikbaarheid = useMemo(() => {
34
+ const map = new Map();
35
+ for (const g of gevonden)
36
+ map.set(g.id, g);
37
+ return map;
38
+ }, [gevonden]);
39
+ const gekoppeld = useMemo(() => {
40
+ const map = new Map();
41
+ for (const k of koppelingen) {
42
+ if (!map.has(k.printer_id))
43
+ map.set(k.printer_id, new Set());
44
+ map.get(k.printer_id).add(k.layout_id);
45
+ }
46
+ return map;
47
+ }, [koppelingen]);
48
+ const rijen = printers
49
+ .map((p) => {
50
+ const extern = p.extern_printer_id ?? null;
51
+ const net = extern ? beschikbaarheid.get(extern) : undefined;
52
+ return { printer: p, extern, computer: net?.computer ?? null, online: !!net?.online };
53
+ })
54
+ .filter((r) => (computer ? r.computer === computer.naam : false));
55
+ const actievePrinter = printers.find((p) => p.id === gekozenPrinter) ?? null;
56
+ const zichtbareComputers = computers.filter((c) => zoekComputer.trim() ? c.naam.toLowerCase().includes(zoekComputer.trim().toLowerCase()) : true);
57
+ const zichtbareLayouts = layouts.filter((l) => layoutZoek.trim() ? l.naam.toLowerCase().includes(layoutZoek.trim().toLowerCase()) : true);
58
+ const bekendeExterneIds = printers
59
+ .map((p) => p.extern_printer_id ?? null)
60
+ .filter((e) => !!e);
61
+ const bekendeLocaties = Array.from(new Set(printers.map((p) => p.locatie).filter((l) => !!l)));
62
+ return (_jsxs("main", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "text-muted-foreground flex items-center gap-1 text-sm", children: [_jsx(Link, { to: "/layouts-printers/printers", className: "hover:text-foreground", children: "Printers" }), _jsx(ChevronRight, { className: "h-3.5 w-3.5" }), _jsx("span", { className: "text-foreground", children: computer?.naam ?? "Werkplek" })] }), _jsxs("div", { className: "flex flex-wrap items-end justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold", children: "Werkplek configureren" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Kies welke printers op deze computer welke ontwerpen afdrukken." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-muted-foreground text-xs", children: bijgewerktTekst(bijgewerkt) }), _jsxs(Button, { onClick: () => {
63
+ setBewerken(null);
64
+ setWizard(true);
65
+ }, children: [_jsx(Plus, { className: "mr-2 h-4 w-4" }), " Printer toevoegen"] })] })] }), _jsxs("div", { className: "grid gap-6 lg:grid-cols-[300px_1fr]", children: [_jsxs(Card, { className: "h-fit", children: [_jsx(CardHeader, { className: "pb-3", children: _jsx(CardTitle, { className: "text-base", children: "Werkplekken" }) }), _jsxs(CardContent, { className: "space-y-2", children: [_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground absolute top-2.5 left-3 h-4 w-4" }), _jsx(Input, { className: "pl-9", placeholder: "Zoek werkplek", value: zoekComputer, onChange: (e) => setZoekComputer(e.target.value) })] }), zichtbareComputers.map((c) => (_jsxs(Link, { to: "/layouts-printers/printers/$computerId", params: { computerId: c.id }, className: `flex items-center gap-3 rounded-lg border p-3 text-sm transition ${c.id === computerId ? "border-primary ring-primary/20 ring-2" : "hover:bg-muted/50"}`, children: [_jsx("span", { className: `h-2 w-2 shrink-0 rounded-full ${c.online ? "bg-primary" : "bg-muted-foreground/40"}` }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate font-medium", children: c.naam }), _jsxs("span", { className: "text-muted-foreground block text-xs", children: [c.aantalPrinters, " ", c.aantalPrinters === 1 ? "printer" : "printers"] })] }), _jsx(ChevronRight, { className: "text-muted-foreground h-4 w-4" })] }, c.id))), zichtbareComputers.length === 0 && (_jsx("p", { className: "text-muted-foreground text-sm", children: "Geen werkplekken gevonden." }))] })] }), _jsxs("div", { className: "space-y-6", children: [_jsx(Card, { children: _jsxs(CardHeader, { className: "pb-3", children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(Monitor, { className: "h-4 w-4" }), " ", computer?.naam ?? "Onbekende werkplek"] }), _jsx(CardDescription, { children: computer
66
+ ? `${computer.online ? "Aan" : "Uit"} · ${rijen.length} ${rijen.length === 1 ? "printer" : "printers"}`
67
+ : "Deze computer is niet gevonden. Staat hij aan?" })] }) }), _jsxs("div", { className: "grid gap-6 xl:grid-cols-[1fr_340px]", children: [_jsxs("div", { className: "space-y-3", children: [rijen.length === 0 && (_jsx(Card, { children: _jsxs(CardContent, { className: "space-y-4 py-10 text-center", children: [_jsx(Printer, { className: "text-muted-foreground mx-auto h-8 w-8" }), _jsx("p", { className: "text-sm font-medium", children: "Nog geen printers op deze werkplek" }), _jsx(Button, { onClick: () => {
68
+ setBewerken(null);
69
+ setWizard(true);
70
+ }, children: "Printer toevoegen" })] }) })), rijen.map(({ printer, online }) => (_jsx(PrinterKaart, { printer: printer, computer: computer?.naam ?? null, beschikbaar: online, gekozen: printer.id === gekozenPrinter, onKies: () => setGekozenPrinter(printer.id), onTest: () => void drukTestpaginaAf(printer.id, printer.naam), onBewerk: () => {
71
+ setBewerken({
72
+ id: printer.id,
73
+ naam: printer.naam,
74
+ locatie: printer.locatie,
75
+ papierformaat: printer.papierformaat,
76
+ });
77
+ setWizard(true);
78
+ }, onVerwijder: async () => {
79
+ try {
80
+ await verwijderPrinter(printer.id);
81
+ toast.success("Printer verwijderd");
82
+ void reload();
83
+ }
84
+ catch {
85
+ toast.error("Verwijderen mislukt");
86
+ }
87
+ } }, printer.id)))] }), actievePrinter && (_jsxs(Card, { className: "h-fit", children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Wat wordt hier afgedrukt?" }), _jsx(CardDescription, { children: actievePrinter.naam })] }), _jsxs(CardContent, { className: "space-y-3", children: [layouts.length > 8 && (_jsxs("div", { className: "relative", children: [_jsx(Search, { className: "text-muted-foreground absolute top-2.5 left-3 h-4 w-4" }), _jsx(Input, { className: "pl-9", value: layoutZoek, placeholder: "Zoek een ontwerp", onChange: (e) => setLayoutZoek(e.target.value) })] })), zichtbareLayouts.map((l) => {
88
+ const aan = gekoppeld.get(actievePrinter.id)?.has(l.id) ?? false;
89
+ return (_jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Checkbox, { checked: aan, onCheckedChange: async (v) => {
90
+ await toggleKoppeling(l.id, actievePrinter.id, !!v);
91
+ void reload();
92
+ } }), _jsxs("div", { className: "min-w-0", children: [_jsx("span", { className: "block truncate text-sm", children: l.naam }), _jsx("span", { className: "text-muted-foreground text-xs", children: l.papierformaat })] })] }, l.id));
93
+ }), zichtbareLayouts.length === 0 && (_jsx("p", { className: "text-muted-foreground text-sm", children: "Er zijn nog geen ontwerpen." }))] })] }))] })] })] }), _jsx(PrinterSetupWizard, { open: wizard, onOpenChange: (v) => {
94
+ setWizard(v);
95
+ if (!v)
96
+ setBewerken(null);
97
+ }, computerFilter: computer?.naam ?? null, bekendeExterneIds: bekendeExterneIds, bekendeLocaties: bekendeLocaties, bewerken: bewerken, onKlaar: () => {
98
+ void reload();
99
+ void zoek();
100
+ } })] }));
101
+ }