@flowselections/layout-maker 1.62.2 → 1.63.2

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 (52) hide show
  1. package/dist-lib/components/AfdrukKnop.js +64 -64
  2. package/dist-lib/components/BevestigDialog.d.ts +9 -0
  3. package/dist-lib/components/BevestigDialog.d.ts.map +1 -0
  4. package/dist-lib/components/BevestigDialog.js +24 -0
  5. package/dist-lib/components/LogosPage.d.ts.map +1 -1
  6. package/dist-lib/components/LogosPage.js +27 -5
  7. package/dist-lib/components/NetwerkPrintersDialog.js +79 -79
  8. package/dist-lib/components/PrintenInstellenWizard.js +1 -1
  9. package/dist-lib/components/PrinterSetupWizard.d.ts.map +1 -1
  10. package/dist-lib/components/PrinterSetupWizard.js +3 -1
  11. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  12. package/dist-lib/components/PrintplekDetailPage.js +42 -4
  13. package/dist-lib/components/TestprintDialog.d.ts.map +1 -1
  14. package/dist-lib/components/TestprintDialog.js +15 -1
  15. package/dist-lib/components/WerkplekConfiguratiePage.js +2 -2
  16. package/dist-lib/components/WerkplekkenTab.d.ts.map +1 -1
  17. package/dist-lib/components/WerkplekkenTab.js +13 -6
  18. package/dist-lib/integrations/supabase/client.server.js +1 -1
  19. package/dist-lib/integrations/supabase/types.d.ts +125 -0
  20. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  21. package/dist-lib/lib/afbeeldingMaat.d.ts +10 -0
  22. package/dist-lib/lib/afbeeldingMaat.d.ts.map +1 -0
  23. package/dist-lib/lib/afbeeldingMaat.js +39 -0
  24. package/dist-lib/lib/etiketControle.d.ts +9 -1
  25. package/dist-lib/lib/etiketControle.d.ts.map +1 -1
  26. package/dist-lib/lib/etiketControle.js +21 -4
  27. package/dist-lib/lib/htmlNaarPdf.server.d.ts +4 -0
  28. package/dist-lib/lib/htmlNaarPdf.server.d.ts.map +1 -1
  29. package/dist-lib/lib/htmlNaarPdf.server.js +5 -1
  30. package/dist-lib/lib/htmlPdf.server.d.ts +6 -0
  31. package/dist-lib/lib/htmlPdf.server.d.ts.map +1 -1
  32. package/dist-lib/lib/htmlPdf.server.js +46 -10
  33. package/dist-lib/lib/logoLibrary.d.ts +25 -0
  34. package/dist-lib/lib/logoLibrary.d.ts.map +1 -1
  35. package/dist-lib/lib/logoLibrary.js +73 -1
  36. package/dist-lib/lib/opmaakLimiet.d.ts +8 -0
  37. package/dist-lib/lib/opmaakLimiet.d.ts.map +1 -0
  38. package/dist-lib/lib/opmaakLimiet.js +25 -0
  39. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  40. package/dist-lib/lib/printQueue.server.js +81 -20
  41. package/dist-lib/lib/printService.functions.js +2 -2
  42. package/dist-lib/lib/printplekken.d.ts +17 -1
  43. package/dist-lib/lib/printplekken.d.ts.map +1 -1
  44. package/dist-lib/lib/printplekken.js +42 -3
  45. package/dist-lib/lib/profielHtml.js +1 -1
  46. package/dist-lib/lib/shellPoort.d.ts +1 -1
  47. package/dist-lib/lib/shellPoort.js +1 -1
  48. package/dist-lib/lib/stickerFormaat.d.ts +21 -0
  49. package/dist-lib/lib/stickerFormaat.d.ts.map +1 -0
  50. package/dist-lib/lib/stickerFormaat.js +39 -0
  51. package/dist-lib/lib/testprint.js +1 -1
  52. package/package.json +1 -1
@@ -1,64 +1,64 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // ============================================================================
3
- // src/components/AfdrukKnop.tsx — afdrukken met automatisch ingesteld
4
- // papierformaat, stand en de bedoelde printer. Waar mogelijk gaat het
5
- // document direct naar de printer; anders opent het printvenster.
6
- // ============================================================================
7
- import { useState } from "react";
8
- import { Button, toast } from "@flowselections/core";
9
- import { Loader2, Printer } from "lucide-react";
10
- import { drukAf } from "../lib/browserPrint.js";
11
- import { printDirect } from "../lib/directPrint.js";
12
- /**
13
- * @deprecated Verouderd — deze knop gebruikt het browser-printvenster als
14
- * terugval. Gebruik `printHtml()` / `printPdf()` uit `printApi` zodat alles
15
- * via PrintNode loopt.
16
- */
17
- export function AfdrukKnop({ documenttype, formaatCode, orientatie, getHtml, css, documentnaam, label = "Afdrukken", layoutId, kopieen, }) {
18
- const [bezig, setBezig] = useState(false);
19
- const afdrukken = async () => {
20
- setBezig(true);
21
- try {
22
- const html = getHtml();
23
- const direct = await printDirect({
24
- documenttype,
25
- formaatCode,
26
- orientatie,
27
- html,
28
- css,
29
- documentnaam,
30
- layoutId: layoutId ?? null,
31
- kopieen,
32
- });
33
- if (direct.gelukt) {
34
- toast.success(direct.printernaam
35
- ? `Verstuurd naar ${direct.printernaam}`
36
- : "Het document is naar de printer verstuurd");
37
- return;
38
- }
39
- if (direct.reden)
40
- toast.error(direct.reden);
41
- const { printer } = await drukAf({
42
- documenttype,
43
- formaatCode,
44
- orientatie,
45
- html,
46
- css,
47
- documentnaam,
48
- });
49
- if (printer) {
50
- toast.info(`Kies in het printvenster: ${printer.systeemnaam ?? printer.naam}`);
51
- }
52
- else {
53
- toast.info("Er is nog geen vaste printer ingesteld voor dit document.");
54
- }
55
- }
56
- catch {
57
- toast.error("Afdrukken mislukt");
58
- }
59
- finally {
60
- setBezig(false);
61
- }
62
- };
63
- return (_jsxs(Button, { variant: "outline", disabled: bezig, onClick: () => void afdrukken(), children: [bezig ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(Printer, { className: "mr-2 h-4 w-4" }), label] }));
64
- }
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/AfdrukKnop.tsx — afdrukken met automatisch ingesteld
4
+ // papierformaat, stand en de bedoelde printer. Waar mogelijk gaat het
5
+ // document direct naar de printer; anders opent het printvenster.
6
+ // ============================================================================
7
+ import { useState } from "react";
8
+ import { Button, toast } from "@flowselections/core";
9
+ import { Loader2, Printer } from "lucide-react";
10
+ import { drukAf } from "../lib/browserPrint.js";
11
+ import { printDirect } from "../lib/directPrint.js";
12
+ /**
13
+ * @deprecated Verouderd — deze knop gebruikt het browser-printvenster als
14
+ * terugval. Gebruik `printHtml()` / `printPdf()` uit `printApi` zodat alles
15
+ * via PrintNode loopt.
16
+ */
17
+ export function AfdrukKnop({ documenttype, formaatCode, orientatie, getHtml, css, documentnaam, label = "Afdrukken", layoutId, kopieen, }) {
18
+ const [bezig, setBezig] = useState(false);
19
+ const afdrukken = async () => {
20
+ setBezig(true);
21
+ try {
22
+ const html = getHtml();
23
+ const direct = await printDirect({
24
+ documenttype,
25
+ formaatCode,
26
+ orientatie,
27
+ html,
28
+ css,
29
+ documentnaam,
30
+ layoutId: layoutId ?? null,
31
+ kopieen,
32
+ });
33
+ if (direct.gelukt) {
34
+ toast.success(direct.printernaam
35
+ ? `Verstuurd naar ${direct.printernaam}`
36
+ : "Het document is naar de printer verstuurd");
37
+ return;
38
+ }
39
+ if (direct.reden)
40
+ toast.error(direct.reden);
41
+ const { printer } = await drukAf({
42
+ documenttype,
43
+ formaatCode,
44
+ orientatie,
45
+ html,
46
+ css,
47
+ documentnaam,
48
+ });
49
+ if (printer) {
50
+ toast.info(`Kies in het printvenster: ${printer.systeemnaam ?? printer.naam}`);
51
+ }
52
+ else {
53
+ toast.info("Er is nog geen vaste printer ingesteld voor dit document.");
54
+ }
55
+ }
56
+ catch {
57
+ toast.error("Afdrukken mislukt");
58
+ }
59
+ finally {
60
+ setBezig(false);
61
+ }
62
+ };
63
+ return (_jsxs(Button, { variant: "outline", disabled: bezig, onClick: () => void afdrukken(), children: [bezig ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : _jsx(Printer, { className: "mr-2 h-4 w-4" }), label] }));
64
+ }
@@ -0,0 +1,9 @@
1
+ import { type ReactNode } from "react";
2
+ export interface BevestigVraag {
3
+ titel: string;
4
+ tekst?: ReactNode;
5
+ knop?: string;
6
+ gevaarlijk?: boolean;
7
+ }
8
+ export declare function useBevestig(): [ReactNode, (v: BevestigVraag) => Promise<boolean>];
9
+ //# sourceMappingURL=BevestigDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BevestigDialog.d.ts","sourceRoot":"","sources":["../../src/components/BevestigDialog.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAUtE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,WAAW,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAwCjF"}
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/BevestigDialog.tsx — eigen bevestigvenster in plaats van het
4
+ // standaard browservenster (dat in sommige omgevingen stil wordt geblokkeerd).
5
+ // Gebruik: const [venster, bevestig] = useBevestig(); if (!(await bevestig({...}))) return;
6
+ // ============================================================================
7
+ import { useCallback, useRef, useState } from "react";
8
+ import { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@flowselections/core";
9
+ export function useBevestig() {
10
+ const [vraag, setVraag] = useState(null);
11
+ const antwoord = useRef(null);
12
+ const sluit = (ja) => {
13
+ antwoord.current?.(ja);
14
+ antwoord.current = null;
15
+ setVraag(null);
16
+ };
17
+ const bevestig = useCallback((v) => new Promise((resolve) => {
18
+ antwoord.current?.(false);
19
+ antwoord.current = resolve;
20
+ setVraag(v);
21
+ }), []);
22
+ const venster = (_jsx(Dialog, { open: !!vraag, onOpenChange: (open) => !open && sluit(false), children: _jsxs(DialogContent, { className: "sm:max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: vraag?.titel }), vraag?.tekst ? _jsx(DialogDescription, { asChild: true, children: _jsx("div", { children: vraag.tekst }) }) : null] }), _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { variant: "outline", onClick: () => sluit(false), children: "Annuleren" }), _jsx(Button, { variant: vraag?.gevaarlijk ? "destructive" : "default", onClick: () => sluit(true), children: vraag?.knop ?? "Doorgaan" })] })] }) }));
23
+ return [venster, bevestig];
24
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"LogosPage.d.ts","sourceRoot":"","sources":["../../src/components/LogosPage.tsx"],"names":[],"mappings":"AAkCA,OAAO,EAaL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,SAAc,EAAE,EAAE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BAY9F;AASD,wBAAgB,SAAS,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BA8LxE"}
1
+ {"version":3,"file":"LogosPage.d.ts","sourceRoot":"","sources":["../../src/components/LogosPage.tsx"],"names":[],"mappings":"AAkCA,OAAO,EAcL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAE5B,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,SAAc,EAAE,EAAE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BAY9F;AASD,wBAAgB,SAAS,CAAC,EAAE,OAAe,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,+BAwNxE"}
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useState } from "react";
3
3
  import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Textarea, toast, } from "@flowselections/core";
4
- import { Download, ImagePlus, Pencil, RefreshCw, Trash2, Upload } from "lucide-react";
4
+ import { Download, ImagePlus, Pencil, RefreshCw, Trash2, Undo2, Upload } from "lucide-react";
5
5
  import { useAutoRefresh } from "../lib/useAutoRefresh.js";
6
- import { LOGO_CATEGORIEEN, TOEGESTANE_LOGO_TYPES, downloadLogo, formatteerBytes, logoCategorieLabel, maakLogo, useLogoOpslag, useLogos, vervangLogoBestand, verwijderLogo, werkLogoBij, } from "../lib/logoLibrary.js";
6
+ import { LOGO_CATEGORIEEN, TOEGESTANE_LOGO_TYPES, downloadLogo, formatteerBytes, logoCategorieLabel, maakLogo, useLogoOpslag, useLogos, verkleinLogoVoorUpload, zetOrigineelTerug, vervangLogoBestand, verwijderLogo, werkLogoBij, } from "../lib/logoLibrary.js";
7
7
  export function LogoThumbnail({ logo, className = "" }) {
8
8
  return (_jsx("div", { className: `flex h-12 w-16 items-center justify-center overflow-hidden rounded border bg-[repeating-conic-gradient(#e5e7eb_0%_25%,#fff_0%_50%)] bg-[length:10px_10px] ${className}`, children: logo.viewUrl ? (_jsx("img", { src: logo.viewUrl, alt: logo.naam, className: "max-h-full max-w-full object-contain" })) : (_jsx(ImagePlus, { className: "h-4 w-4 text-muted-foreground" })) }));
9
9
  }
@@ -22,14 +22,30 @@ export function LogosPage({ ingebed = false } = {}) {
22
22
  }, [logos, zoek, categorie]);
23
23
  const vervang = async (logo, file) => {
24
24
  try {
25
- await vervangLogoBestand(logo, file);
25
+ const v = await verkleinLogoVoorUpload(file);
26
+ await vervangLogoBestand(logo, v.bestand);
26
27
  toast.success("Logo vervangen — alle layouts zijn bijgewerkt");
28
+ if (v.verkleind && v.van && v.naar) {
29
+ toast.info("Logo verkleind voor snel printen", {
30
+ description: `${v.van.breedte} × ${v.van.hoogte} → ${v.naar.breedte} × ${v.naar.hoogte} pixels`,
31
+ });
32
+ }
27
33
  await reload();
28
34
  }
29
35
  catch (e) {
30
36
  toast.error(e instanceof Error ? e.message : "Vervangen mislukt");
31
37
  }
32
38
  };
39
+ const terugzetten = async (logo) => {
40
+ try {
41
+ await zetOrigineelTerug(logo);
42
+ toast.success("Origineel logo teruggezet");
43
+ await reload();
44
+ }
45
+ catch (e) {
46
+ toast.error(e instanceof Error ? e.message : "Terugzetten mislukt");
47
+ }
48
+ };
33
49
  const wis = async (logo) => {
34
50
  if (!window.confirm(`Logo "${logo.naam}" verwijderen?`))
35
51
  return;
@@ -48,7 +64,7 @@ export function LogosPage({ ingebed = false } = {}) {
48
64
  if (f)
49
65
  void vervang(l, f);
50
66
  e.target.value = "";
51
- } }), _jsx("span", { className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md hover:bg-accent", children: _jsx(RefreshCw, { className: "h-4 w-4" }) })] }), _jsx(Button, { variant: "ghost", size: "icon", title: "Downloaden", onClick: () => void downloadLogo(l), children: _jsx(Download, { className: "h-4 w-4" }) }), _jsx(Button, { variant: "ghost", size: "icon", title: "Verwijderen", onClick: () => void wis(l), children: _jsx(Trash2, { className: "h-4 w-4" }) })] }) })] }, l.id)))] })] }) })] })] }), _jsx(LogoUploadDialog, { open: uploadOpen, onOpenChange: setUploadOpen, onKlaar: reload }), _jsx(LogoBewerkDialog, { logo: bewerk, onOpenChange: () => setBewerk(null), onKlaar: reload })] }));
67
+ } }), _jsx("span", { className: "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-md hover:bg-accent", children: _jsx(RefreshCw, { className: "h-4 w-4" }) })] }), _jsx(Button, { variant: "ghost", size: "icon", title: "Downloaden", onClick: () => void downloadLogo(l), children: _jsx(Download, { className: "h-4 w-4" }) }), l.origineel_pad && (_jsx(Button, { variant: "ghost", size: "icon", title: "Origineel terugzetten", onClick: () => void terugzetten(l), children: _jsx(Undo2, { className: "h-4 w-4" }) })), _jsx(Button, { variant: "ghost", size: "icon", title: "Verwijderen", onClick: () => void wis(l), children: _jsx(Trash2, { className: "h-4 w-4" }) })] }) })] }, l.id)))] })] }) })] })] }), _jsx(LogoUploadDialog, { open: uploadOpen, onOpenChange: setUploadOpen, onKlaar: reload }), _jsx(LogoBewerkDialog, { logo: bewerk, onOpenChange: () => setBewerk(null), onKlaar: reload })] }));
52
68
  }
53
69
  function LogoUploadDialog({ open, onOpenChange, onKlaar, }) {
54
70
  const [bestanden, setBestanden] = useState([]);
@@ -75,13 +91,19 @@ function LogoUploadDialog({ open, onOpenChange, onKlaar, }) {
75
91
  ? form.naam.trim() || file.name.replace(/\.[^.]+$/, "")
76
92
  : `${form.naam.trim() ? `${form.naam.trim()} — ` : ""}${file.name.replace(/\.[^.]+$/, "")}`;
77
93
  try {
94
+ const v = await verkleinLogoVoorUpload(file);
78
95
  await maakLogo({
79
- file,
96
+ file: v.bestand,
80
97
  naam,
81
98
  omschrijving: form.omschrijving,
82
99
  categorie: form.categorie,
83
100
  is_standaard: form.is_standaard && i === 0,
84
101
  });
102
+ if (v.verkleind && v.van && v.naar) {
103
+ toast.info("Logo verkleind voor snel printen", {
104
+ description: `${v.van.breedte} × ${v.van.hoogte} → ${v.naar.breedte} × ${v.naar.hoogte} pixels`,
105
+ });
106
+ }
85
107
  gelukt += 1;
86
108
  }
87
109
  catch (e) {
@@ -1,79 +1,79 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // ============================================================================
3
- // src/components/NetwerkPrintersDialog.tsx — printers uit het netwerk zoeken,
4
- // toevoegen of koppelen aan een bestaande printer.
5
- // ============================================================================
6
- import { useCallback, useEffect, useState } from "react";
7
- import { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, toast, } from "@flowselections/core";
8
- import { Loader2, Printer, RefreshCw } from "lucide-react";
9
- import { supabase } from "../lib/supabaseClient.js";
10
- import { netwerkPrinters } from "../lib/printService.functions.js";
11
- export function NetwerkPrintersDialog({ open, onOpenChange, huidigePrinterId, huidigePrinterNaam, onKlaar, }) {
12
- const [bezig, setBezig] = useState(false);
13
- const [fout, setFout] = useState(null);
14
- const [lijst, setLijst] = useState([]);
15
- const zoeken = useCallback(async () => {
16
- setBezig(true);
17
- setFout(null);
18
- try {
19
- const res = await netwerkPrinters({ data: undefined });
20
- if (!res.ok) {
21
- setFout(res.fout);
22
- setLijst([]);
23
- }
24
- else {
25
- setLijst(Array.isArray(res.printers) ? res.printers : []);
26
- }
27
- }
28
- catch {
29
- setFout("Er kon niet in het netwerk worden gezocht. Probeer het zo opnieuw.");
30
- }
31
- finally {
32
- setBezig(false);
33
- }
34
- }, []);
35
- useEffect(() => {
36
- if (open)
37
- void zoeken();
38
- }, [open, zoeken]);
39
- const toevoegen = async (p) => {
40
- try {
41
- const { error } = await supabase.from("printers").insert({
42
- naam: p.naam,
43
- systeemnaam: p.naam,
44
- locatie: p.computer,
45
- omschrijving: p.omschrijving,
46
- online: p.online,
47
- actief: true,
48
- extern_printer_id: p.id,
49
- });
50
- if (error)
51
- throw error;
52
- toast.success(`${p.naam} is toegevoegd`);
53
- onKlaar?.();
54
- onOpenChange(false);
55
- }
56
- catch {
57
- toast.error("Toevoegen mislukt");
58
- }
59
- };
60
- const koppelen = async (p) => {
61
- if (!huidigePrinterId)
62
- return;
63
- try {
64
- const { error } = await supabase
65
- .from("printers")
66
- .update({ extern_printer_id: p.id, systeemnaam: p.naam, locatie: p.computer })
67
- .eq("id", huidigePrinterId);
68
- if (error)
69
- throw error;
70
- toast.success("Printer gekoppeld");
71
- onKlaar?.();
72
- onOpenChange(false);
73
- }
74
- catch {
75
- toast.error("Koppelen mislukt");
76
- }
77
- };
78
- return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Printers in het netwerk" }), _jsx(DialogDescription, { children: "Kies een printer om toe te voegen. Staat een printer er niet bij? Zet dan de computer aan waar de printer op is aangesloten." })] }), _jsxs("div", { className: "space-y-2", children: [bezig && (_jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Zoeken\u2026"] })), !bezig && fout && _jsx("p", { className: "text-destructive text-sm", children: fout }), !bezig && !fout && lijst.length === 0 && (_jsx("p", { className: "text-muted-foreground text-sm", children: "Er zijn geen printers gevonden." })), lijst.map((p) => (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border p-3", 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 }), _jsxs("p", { className: "text-muted-foreground truncate text-xs", children: [p.computer || "Onbekende computer", " \u00B7 ", p.online ? "online" : "offline"] })] }), huidigePrinterId && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => void koppelen(p), children: ["Koppelen aan ", huidigePrinterNaam ?? "printer"] })), _jsx(Button, { size: "sm", onClick: () => void toevoegen(p), children: "Toevoegen" })] }, p.id)))] }), _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { variant: "ghost", onClick: () => void zoeken(), disabled: bezig, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), " Opnieuw zoeken"] }) })] }) }));
79
- }
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/NetwerkPrintersDialog.tsx — printers uit het netwerk zoeken,
4
+ // toevoegen of koppelen aan een bestaande printer.
5
+ // ============================================================================
6
+ import { useCallback, useEffect, useState } from "react";
7
+ import { Button, Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, toast, } from "@flowselections/core";
8
+ import { Loader2, Printer, RefreshCw } from "lucide-react";
9
+ import { supabase } from "../lib/supabaseClient.js";
10
+ import { netwerkPrinters } from "../lib/printService.functions.js";
11
+ export function NetwerkPrintersDialog({ open, onOpenChange, huidigePrinterId, huidigePrinterNaam, onKlaar, }) {
12
+ const [bezig, setBezig] = useState(false);
13
+ const [fout, setFout] = useState(null);
14
+ const [lijst, setLijst] = useState([]);
15
+ const zoeken = useCallback(async () => {
16
+ setBezig(true);
17
+ setFout(null);
18
+ try {
19
+ const res = await netwerkPrinters({ data: undefined });
20
+ if (!res.ok) {
21
+ setFout(res.fout);
22
+ setLijst([]);
23
+ }
24
+ else {
25
+ setLijst(Array.isArray(res.printers) ? res.printers : []);
26
+ }
27
+ }
28
+ catch {
29
+ setFout("Er kon niet in het netwerk worden gezocht. Probeer het zo opnieuw.");
30
+ }
31
+ finally {
32
+ setBezig(false);
33
+ }
34
+ }, []);
35
+ useEffect(() => {
36
+ if (open)
37
+ void zoeken();
38
+ }, [open, zoeken]);
39
+ const toevoegen = async (p) => {
40
+ try {
41
+ const { error } = await supabase.from("printers").insert({
42
+ naam: p.naam,
43
+ systeemnaam: p.naam,
44
+ locatie: p.computer,
45
+ omschrijving: p.omschrijving,
46
+ online: p.online,
47
+ actief: true,
48
+ extern_printer_id: p.id,
49
+ });
50
+ if (error)
51
+ throw error;
52
+ toast.success(`${p.naam} is toegevoegd`);
53
+ onKlaar?.();
54
+ onOpenChange(false);
55
+ }
56
+ catch {
57
+ toast.error("Toevoegen mislukt");
58
+ }
59
+ };
60
+ const koppelen = async (p) => {
61
+ if (!huidigePrinterId)
62
+ return;
63
+ try {
64
+ const { error } = await supabase
65
+ .from("printers")
66
+ .update({ extern_printer_id: p.id, systeemnaam: p.naam, locatie: p.computer })
67
+ .eq("id", huidigePrinterId);
68
+ if (error)
69
+ throw error;
70
+ toast.success("Printer gekoppeld");
71
+ onKlaar?.();
72
+ onOpenChange(false);
73
+ }
74
+ catch {
75
+ toast.error("Koppelen mislukt");
76
+ }
77
+ };
78
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-w-lg", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Printers in het netwerk" }), _jsx(DialogDescription, { children: "Kies een printer om toe te voegen. Staat een printer er niet bij? Zet dan de computer aan waar de printer op is aangesloten." })] }), _jsxs("div", { className: "space-y-2", children: [bezig && (_jsxs("p", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Zoeken\u2026"] })), !bezig && fout && _jsx("p", { className: "text-destructive text-sm", children: fout }), !bezig && !fout && lijst.length === 0 && (_jsx("p", { className: "text-muted-foreground text-sm", children: "Er zijn geen printers gevonden." })), lijst.map((p) => (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border p-3", 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 }), _jsxs("p", { className: "text-muted-foreground truncate text-xs", children: [p.computer || "Onbekende computer", " \u00B7 ", p.online ? "online" : "offline"] })] }), huidigePrinterId && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => void koppelen(p), children: ["Koppelen aan ", huidigePrinterNaam ?? "printer"] })), _jsx(Button, { size: "sm", onClick: () => void toevoegen(p), children: "Toevoegen" })] }, p.id)))] }), _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { variant: "ghost", onClick: () => void zoeken(), disabled: bezig, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), " Opnieuw zoeken"] }) })] }) }));
79
+ }
@@ -60,7 +60,7 @@ export function PrintenInstellenWizard({ open, onOpenChange, onKlaar, }) {
60
60
  Tijdstip: new Date().toLocaleString("nl-NL"),
61
61
  }),
62
62
  printerId,
63
- payload: { is_testprint: true },
63
+ payload: { is_testprint: true, is_test: true },
64
64
  });
65
65
  volgJobStatus(jobId, (j) => setStatus((s) => ({ ...s, [printerId]: j.foutmelding ? `mislukt: ${j.foutmelding}` : j.status })));
66
66
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PrinterSetupWizard.d.ts","sourceRoot":"","sources":["../../src/components/PrinterSetupWizard.tsx"],"names":[],"mappings":"AAoDA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAwCD,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,cAAc,EACd,iBAAsB,EACtB,eAAoB,EACpB,QAAQ,EACR,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CACjC,+BAodA"}
1
+ {"version":3,"file":"PrinterSetupWizard.d.ts","sourceRoot":"","sources":["../../src/components/PrinterSetupWizard.tsx"],"names":[],"mappings":"AAoDA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAwCD,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,cAAc,EACd,iBAAsB,EACtB,eAAoB,EACpB,QAAQ,EACR,WAAW,GACZ,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;CACjC,+BAsdA"}
@@ -240,6 +240,8 @@ export function PrinterSetupWizard({ open, onOpenChange, onKlaar, computerFilter
240
240
  }) })), !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: "Omschrijving (optioneel)" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "Waar staat deze printer? Bijvoorbeeld: magazijn achter." }), _jsx(Input, { value: locatie, placeholder: "Bijvoorbeeld: magazijn achter", 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))) }))] }), formaatOpties.length > 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Standaardformaat van deze printer" }), _jsxs("p", { className: "text-muted-foreground text-xs", children: ["Deze printer kan: ", formaatOpties.map((o) => o.label.split(" (")[0]).join(", "), "."] }), formaatOpties.length === 1 ? (_jsx("p", { className: "text-sm", children: formaatOpties[0].label })) : (_jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: formaatOpties.map((o) => (_jsxs("button", { type: "button", onClick: () => setFormaatCode(o.code), className: `hover:bg-accent rounded-lg border p-3 text-left transition ${formaatCode === o.code ? "border-primary bg-accent" : ""}`, children: [o.breedte <= 120 && o.hoogte <= 220 ? (_jsx(Tag, { className: "text-muted-foreground mb-1 h-4 w-4" })) : (_jsx(FileText, { className: "text-muted-foreground mb-1 h-4 w-4" })), _jsx("p", { className: "text-sm font-medium", children: o.label.split(" (")[0] }), _jsxs("p", { className: "text-muted-foreground text-xs", children: [o.breedte, " \u00D7 ", o.hoogte, " mm"] })] }, o.code))) }))] })) : (_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Wat gaat deze printer afdrukken?" }), _jsx("p", { className: "text-muted-foreground text-xs", children: "De formaten van deze printer konden niet worden opgehaald." }), _jsx("div", { className: "grid grid-cols-2 gap-3", children: [
241
241
  { code: "papier", label: "Papier (A4)", sub: "Gewone documenten", Icon: FileText },
242
242
  { code: "etiket", label: "Etiketten", sub: "Stickers en labels", Icon: Tag },
243
- ].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 || gekozen?.computer || "Geen omschrijving" })] })] })] })), 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" && (testMelding || "De testpagina is afgedrukt."), testStatus === "fout" &&
243
+ ].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 || gekozen?.computer || "Geen omschrijving" })] })] })] })), 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" }), _jsx("p", { className: "text-muted-foreground text-sm", children: printPlekId
244
+ ? `${naam} ${locatie ? `bij ${locatie} ` : ""}hoort nu bij deze printplek. Kies onder Documentroutering welke documenten hierheen gaan.`
245
+ : `${naam} is opgeslagen, maar hoort nog bij geen printplek. Er wordt pas afgedrukt als je hem aan een printplek koppelt.` })] }), testStatus !== "leeg" && (_jsxs("p", { className: "text-muted-foreground text-sm", children: [testStatus === "bezig" && "Onderweg naar de printer…", testStatus === "gelukt" && (testMelding || "De testpagina is afgedrukt."), testStatus === "fout" &&
244
246
  `De testpagina kon niet worden afgedrukt.${testMelding ? ` ${testMelding}` : ""}`] })), _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, {})] }))] }) }));
245
247
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PrintplekDetailPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintplekDetailPage.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,mBAAmB,gCAqqBlC"}
1
+ {"version":3,"file":"PrintplekDetailPage.d.ts","sourceRoot":"","sources":["../../src/components/PrintplekDetailPage.tsx"],"names":[],"mappings":"AAwEA,wBAAgB,mBAAmB,gCA4uBlC"}
@@ -8,8 +8,9 @@ import { useEffect, useMemo, useState } from "react";
8
8
  import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, toast, } from "@flowselections/core";
9
9
  import { Link, useNavigate, useParams } from "@tanstack/react-router";
10
10
  import { PrintplekVerwijderenDialog } from "./PrintplekVerwijderenDialog.js";
11
+ import { useBevestig } from "./BevestigDialog.js";
11
12
  import { AlertTriangle, ArrowLeft, Check, Link2, Monitor, Plus, Printer, Trash2, X, } from "lucide-react";
12
- import { bewerkPrintplek, koppelComputerAanPrintplek, koppelPrinterLosVanPrintplek, ontkoppelBron, usePrintplekken, verplaatsPrinterNaarPrintplek, wijsPrinterToeAanPrintplek, zetPrintplekPrinter, } from "../lib/printplekken.js";
13
+ import { bewerkPrintplek, koppelComputerAanPrintplek, koppelPrinterLosVanPrintplek, ontkoppelBron, printerHerstelUitvoeren, printerHerstelVoorstel, printerVerwijzingen, usePrintplekken, verplaatsPrinterNaarPrintplek, wijsPrinterToeAanPrintplek, zetPrintplekPrinter, } from "../lib/printplekken.js";
13
14
  import { PrinterVervangenDialog } from "./PrinterVervangenDialog.js";
14
15
  import { ComputerVerwijderenDialog } from "./ComputerVerwijderenDialog.js";
15
16
  import { usePrinters } from "../lib/useDocumentData.js";
@@ -105,6 +106,27 @@ export function PrintplekDetailPage() {
105
106
  .filter((t) => t.print_plek_id === plekId)
106
107
  .map((t) => t.printer_id));
107
108
  const eigenPrinters = printers.filter((p) => toegewezenIds.has(p.id));
109
+ const eigenPrinterSleutel = eigenPrinters.map((p) => p.id).join(",");
110
+ const [venster, bevestig] = useBevestig();
111
+ // Dezelfde printer opnieuw toegevoegd? Dan de leeggemaakte regels aanbieden.
112
+ const [herstel, setHerstel] = useState([]);
113
+ useEffect(() => {
114
+ let weg = false;
115
+ void (async () => {
116
+ const uit = [];
117
+ for (const p of eigenPrinters) {
118
+ const aantal = await printerHerstelVoorstel(plekId, p.id).catch(() => 0);
119
+ if (aantal > 0)
120
+ uit.push({ id: p.id, naam: p.naam, aantal });
121
+ }
122
+ if (!weg)
123
+ setHerstel(uit);
124
+ })();
125
+ return () => {
126
+ weg = true;
127
+ };
128
+ // eslint-disable-next-line react-hooks/exhaustive-deps
129
+ }, [plekId, eigenPrinterSleutel, regels.length]);
108
130
  const nietToegewezen = printers.filter((p) => !toegewezenIds.has(p.id));
109
131
  const eigenNamen = new Set(eigenComputers.map((c) => c.computer_naam));
110
132
  const printersPerComputer = eigenComputers.map((c) => ({
@@ -178,8 +200,15 @@ export function PrintplekDetailPage() {
178
200
  }
179
201
  };
180
202
  const loskoppelen = async (p) => {
181
- const n = regels.filter((r) => r.print_plek_id === plekId && r.printer_id === p.id).length;
182
- if (n > 0 && !window.confirm(`${n} regel(s) wijzen naar ${p.naam}. Die worden leeg en gemarkeerd. Doorgaan?`))
203
+ const v = await printerVerwijzingen(plekId, p.id).catch(() => null);
204
+ const n = v?.printplek_regels ?? regels.filter((r) => r.print_plek_id === plekId && r.printer_id === p.id).length;
205
+ const ja = await bevestig({
206
+ titel: `${p.naam} van deze plek verwijderen?`,
207
+ knop: "Verwijderen",
208
+ gevaarlijk: true,
209
+ tekst: (_jsxs("div", { className: "space-y-2 text-sm", children: [n > 0 ? _jsxs("p", { children: [n, " regel(s) van deze plek wijzen naar deze printer. Die worden leeg en vallen terug op de bedrijfsstandaard."] }) : _jsx("p", { children: "Er wijzen geen regels van deze plek naar deze printer." }), v && v.werkplek_regels.length > 0 ? (_jsxs("div", { children: [_jsx("p", { children: "Ook deze uitzonderingen worden leeg:" }), _jsx("ul", { className: "list-disc pl-5", children: v.werkplek_regels.map((w, i) => (_jsxs("li", { children: [w.werkplek, " \u2192 ", documentTypeLabel(w.documenttype)] }, i))) })] })) : null, v && v.werkplekken.length > 0 ? (_jsxs("div", { children: [_jsx("p", { children: "Deze werkplekken gebruiken de printer nog en blijven ernaar wijzen tot je ze aanpast:" }), _jsx("ul", { className: "list-disc pl-5", children: v.werkplekken.map((w, i) => (_jsxs("li", { children: [w.naam, " (", w.rol, "-printer)"] }, i))) })] })) : null, _jsx("p", { children: "Voeg je dezelfde printer later opnieuw toe, dan bieden we aan de regels terug te zetten." })] })),
210
+ });
211
+ if (!ja)
183
212
  return;
184
213
  try {
185
214
  await koppelPrinterLosVanPrintplek(plekId, p.id);
@@ -215,7 +244,16 @@ export function PrintplekDetailPage() {
215
244
  const teVerwijderenPrinters = teVerwijderen
216
245
  ? eigenPrinters.filter((p) => computerVan(p) === teVerwijderen).map((p) => ({ id: p.id, naam: p.naam }))
217
246
  : [];
218
- return (_jsxs("main", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, className: "-ml-2", children: _jsxs(Link, { to: "/layouts-printers/printplekken", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Alle printplekken"] }) }), naamBewerken ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: naam, onChange: (e) => setNaam(e.target.value), className: "w-64" }), _jsx(Button, { size: "icon", onClick: async () => {
247
+ return (_jsxs("main", { className: "space-y-6 p-6", children: [venster, herstel.map((h) => (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-lg border p-3 text-sm", children: [_jsxs("span", { children: ["Zet de ", h.aantal, " regels terug naar ", h.naam, "?"] }), _jsx(Button, { size: "sm", onClick: async () => {
248
+ try {
249
+ const n = await printerHerstelUitvoeren(plekId, h.id);
250
+ toast.success(`${n} regel(s) teruggezet naar ${h.naam}`);
251
+ await vernieuw();
252
+ }
253
+ catch (e) {
254
+ toast.error(leesbareFout(e, "Terugzetten mislukt"));
255
+ }
256
+ }, children: "Terugzetten" })] }, h.id))), _jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Button, { variant: "ghost", size: "sm", asChild: true, className: "-ml-2", children: _jsxs(Link, { to: "/layouts-printers/printplekken", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), " Alle printplekken"] }) }), naamBewerken ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: naam, onChange: (e) => setNaam(e.target.value), className: "w-64" }), _jsx(Button, { size: "icon", onClick: async () => {
219
257
  await bewerkPrintplek(plek.id, { naam: naam.trim() });
220
258
  setNaamBewerken(false);
221
259
  await reload(true);
@@ -1 +1 @@
1
- {"version":3,"file":"TestprintDialog.d.ts","sourceRoot":"","sources":["../../src/components/TestprintDialog.tsx"],"names":[],"mappings":"AAsCA,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,aAAa,EACb,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,+BAwKA"}
1
+ {"version":3,"file":"TestprintDialog.d.ts","sourceRoot":"","sources":["../../src/components/TestprintDialog.tsx"],"names":[],"mappings":"AA0DA,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,aAAa,EACb,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,+BA2KA"}
@@ -9,6 +9,20 @@ import { Badge, Button, Dialog, DialogContent, DialogDescription, DialogHeader,
9
9
  import { AlertTriangle, Check, Loader2, Printer, X } from "lucide-react";
10
10
  import { volgJobStatus } from "../lib/printApi.js";
11
11
  import { bepaalTestOverzicht, verstuurTestprint, } from "../lib/testprint.js";
12
+ import { supabase } from "../lib/supabaseClient.js";
13
+ import { GeladenEtiketKeuze } from "./WerkplekkenTab.js";
14
+ function EtiketWijzigen({ printerId }) {
15
+ const [open, setOpen] = useState(false);
16
+ const [printer, setPrinter] = useState(null);
17
+ const laad = useCallback(async () => {
18
+ const { data } = await supabase.from("printers").select("*").eq("id", printerId).maybeSingle();
19
+ setPrinter(data ?? null);
20
+ }, [printerId]);
21
+ if (!open) {
22
+ return (_jsx(Button, { size: "sm", variant: "link", className: "h-auto p-0 text-xs", onClick: () => { setOpen(true); void laad(); }, children: "Geladen etiket wijzigen" }));
23
+ }
24
+ return printer ? _jsx("div", { className: "mt-2", children: _jsx(GeladenEtiketKeuze, { printer: printer, onGewijzigd: () => void laad() }) }) : null;
25
+ }
12
26
  const STATUS_LABEL = {
13
27
  wachtend: "In de wachtrij",
14
28
  bezig: "Naar de printer",
@@ -85,7 +99,7 @@ export function TestprintDialog({ open, onOpenChange, printplekId, printplekNaam
85
99
  const ontbreekt = regels.filter((r) => !r.printerId);
86
100
  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: "Testprint controleren" }), _jsxs(DialogDescription, { children: ["Elke testprint volgt precies dezelfde weg als een echt document", printplekNaam ? ` vanaf ${printplekNaam}` : werkplek ? ` vanaf ${werkplek}` : "", ". Op het vel staat welke documentsoort, plek en printer bedoeld waren."] })] }), _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("p", { className: "text-muted-foreground text-sm", children: [ingesteld.length, " documentsoort", ingesteld.length === 1 ? "" : "en", " ingesteld", ontbreekt.length ? `, ${ontbreekt.length} zonder printer` : "", "."] }), _jsxs(Button, { size: "sm", disabled: laden || alles || !ingesteld.length, onClick: () => void testAlles(), children: [alles ? (_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" })) : (_jsx(Printer, { className: "mr-2 h-4 w-4" })), "Alles testen"] })] }), laden ? (_jsxs("div", { className: "text-muted-foreground flex items-center gap-2 py-8 text-sm", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), " Instellingen ophalen\u2026"] })) : (_jsx("div", { className: "space-y-2", children: [...ingesteld, ...ontbreekt].map((r) => {
87
101
  const st = statussen[r.documenttype];
88
- return (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-lg border p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-medium", children: r.label }), r.printerId ? (_jsxs("div", { className: "text-muted-foreground text-xs", children: ["Gaat naar ", _jsx("span", { className: "font-medium", children: r.printerNaam })] })) : (_jsxs("div", { className: "text-muted-foreground flex items-center gap-1 text-xs", children: [_jsx(AlertTriangle, { className: "h-3 w-3" }), " ", r.reden] })), st?.fout ? (_jsx("div", { className: "text-destructive mt-1 text-xs", children: st.fout })) : null] }), _jsxs("div", { className: "flex items-center gap-2", children: [st?.status ? (_jsxs(Badge, { variant: st.status === "voltooid"
102
+ return (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-lg border p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-medium", children: r.label }), r.printerId ? (_jsxs("div", { className: "text-muted-foreground text-xs", children: ["Gaat naar ", _jsx("span", { className: "font-medium", children: r.printerNaam })] })) : (_jsxs("div", { className: "text-muted-foreground flex items-center gap-1 text-xs", children: [_jsx(AlertTriangle, { className: "h-3 w-3" }), " ", r.reden] })), st?.fout ? (_jsx("div", { className: "text-destructive mt-1 text-xs", children: st.fout })) : null, r.printerId && st?.status === "mislukt" && /^(FORMAAT_PAST_NIET|GEEN_GELADEN_ETIKET)|past niet|geen etiket/i.test(st.fout ?? "") ? (_jsx(EtiketWijzigen, { printerId: r.printerId })) : null] }), _jsxs("div", { className: "flex items-center gap-2", children: [st?.status ? (_jsxs(Badge, { variant: st.status === "voltooid"
89
103
  ? "default"
90
104
  : st.status === "mislukt" || st.status === "geannuleerd"
91
105
  ? "destructive"
@@ -61,7 +61,7 @@ export function WerkplekConfiguratiePage() {
61
61
  setGekoppeld(new Set());
62
62
  return;
63
63
  }
64
- const id = await printplekVoorComputer(werkplekNaam);
64
+ const id = await printplekVoorComputer(werkplekNaam, computer?.id ?? null);
65
65
  setPlekId(id);
66
66
  if (!id) {
67
67
  setGekoppeld(new Set());
@@ -73,7 +73,7 @@ export function WerkplekConfiguratiePage() {
73
73
  .eq("print_plek_id", id);
74
74
  const lijst = Array.isArray(data) ? data : [];
75
75
  setGekoppeld(new Set(lijst.map((r) => r.printer_id)));
76
- }, [werkplekNaam]);
76
+ }, [werkplekNaam, computer?.id]);
77
77
  useEffect(() => {
78
78
  void laadKoppeling();
79
79
  }, [laadKoppeling, printers]);
@@ -1 +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,+BAyE5G;AAqPD,wBAAgB,cAAc,gCA4E7B"}
1
+ {"version":3,"file":"WerkplekkenTab.d.ts","sourceRoot":"","sources":["../../src/components/WerkplekkenTab.tsx"],"names":[],"mappings":"AAcA,OAAO,EAUL,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAO5B,wBAAgB,kBAAkB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,WAAW,EAAE,MAAM,IAAI,CAAA;CAAE,+BAyE5G;AA0PD,wBAAgB,cAAc,gCA4E7B"}