@flowselections/logistiek-engine 1.0.140 → 1.0.151

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 (70) hide show
  1. package/dist-lib/components/AutomatischVersturenCard.d.ts +2 -0
  2. package/dist-lib/components/AutomatischVersturenCard.d.ts.map +1 -0
  3. package/dist-lib/components/AutomatischVersturenCard.js +22 -0
  4. package/dist-lib/components/BeheerPage.d.ts.map +1 -1
  5. package/dist-lib/components/BeheerPage.js +3 -1
  6. package/dist-lib/components/GearchiveerdeOrdersCard.d.ts +2 -0
  7. package/dist-lib/components/GearchiveerdeOrdersCard.d.ts.map +1 -0
  8. package/dist-lib/components/GearchiveerdeOrdersCard.js +32 -0
  9. package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
  10. package/dist-lib/components/GeblokkeerdeOrdersCard.js +1 -1
  11. package/dist-lib/components/OudeOrderregelsCard.d.ts +2 -0
  12. package/dist-lib/components/OudeOrderregelsCard.d.ts.map +1 -0
  13. package/dist-lib/components/OudeOrderregelsCard.js +28 -0
  14. package/dist-lib/components/PlanWachtrijPage.d.ts.map +1 -1
  15. package/dist-lib/components/PlanWachtrijPage.js +20 -13
  16. package/dist-lib/components/RuleEnginePage.d.ts.map +1 -1
  17. package/dist-lib/components/RuleEnginePage.js +24 -3
  18. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +20 -0
  19. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
  20. package/dist-lib/hooks/useGeblokkeerdeOrders.js +57 -0
  21. package/dist-lib/index.d.ts +1 -0
  22. package/dist-lib/index.d.ts.map +1 -1
  23. package/dist-lib/index.js +1 -0
  24. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
  25. package/dist-lib/integrations/supabase/previewAuthStorage.js +22 -4
  26. package/dist-lib/integrations/supabase/types.d.ts +914 -2
  27. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  28. package/dist-lib/integrations/supabase/types.js +1 -0
  29. package/dist-lib/lib/autoSend.d.ts +21 -0
  30. package/dist-lib/lib/autoSend.d.ts.map +1 -0
  31. package/dist-lib/lib/autoSend.functions.d.ts +10 -0
  32. package/dist-lib/lib/autoSend.functions.d.ts.map +1 -0
  33. package/dist-lib/lib/autoSend.functions.js +18 -0
  34. package/dist-lib/lib/autoSend.js +69 -0
  35. package/dist-lib/lib/autoSend.server.d.ts +13 -0
  36. package/dist-lib/lib/autoSend.server.d.ts.map +1 -0
  37. package/dist-lib/lib/autoSend.server.js +75 -0
  38. package/dist-lib/lib/briefTransport.server.d.ts +17 -0
  39. package/dist-lib/lib/briefTransport.server.d.ts.map +1 -0
  40. package/dist-lib/lib/briefTransport.server.js +41 -0
  41. package/dist-lib/lib/centralSecrets.server.d.ts +13 -0
  42. package/dist-lib/lib/centralSecrets.server.d.ts.map +1 -0
  43. package/dist-lib/lib/centralSecrets.server.js +82 -0
  44. package/dist-lib/lib/controlScan.server.d.ts.map +1 -1
  45. package/dist-lib/lib/controlScan.server.js +8 -0
  46. package/dist-lib/lib/handlers/logistics-tick.server.js +31 -0
  47. package/dist-lib/lib/layoutPrint.server.d.ts +2 -0
  48. package/dist-lib/lib/layoutPrint.server.d.ts.map +1 -1
  49. package/dist-lib/lib/layoutPrint.server.js +1 -1
  50. package/dist-lib/lib/logisticsTasks.d.ts +1 -0
  51. package/dist-lib/lib/logisticsTasks.d.ts.map +1 -1
  52. package/dist-lib/lib/logisticsTasks.js +2 -1
  53. package/dist-lib/lib/modulePrompts.d.ts +1 -0
  54. package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
  55. package/dist-lib/lib/modulePrompts.js +420 -1
  56. package/dist-lib/lib/moduleVersion.d.ts +1 -1
  57. package/dist-lib/lib/moduleVersion.js +1 -1
  58. package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
  59. package/dist-lib/lib/planQueue.server.js +13 -0
  60. package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
  61. package/dist-lib/lib/ruleEngineSchema.js +25 -0
  62. package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -1
  63. package/dist-lib/lib/shippingNoteQueue.server.js +3 -0
  64. package/dist-lib/lib/stickerQueue.server.d.ts +15 -0
  65. package/dist-lib/lib/stickerQueue.server.d.ts.map +1 -0
  66. package/dist-lib/lib/stickerQueue.server.js +349 -0
  67. package/dist-lib/lib/stickerRules.d.ts +38 -0
  68. package/dist-lib/lib/stickerRules.d.ts.map +1 -0
  69. package/dist-lib/lib/stickerRules.js +111 -0
  70. package/package.json +5 -5
@@ -0,0 +1,2 @@
1
+ export declare function AutomatischVersturenCard(): import("react").JSX.Element;
2
+ //# sourceMappingURL=AutomatischVersturenCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AutomatischVersturenCard.d.ts","sourceRoot":"","sources":["../../src/components/AutomatischVersturenCard.tsx"],"names":[],"mappings":"AAMA,wBAAgB,wBAAwB,gCA0CvC"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // src/components/AutomatischVersturenCard.tsx — toont alleen óf de sleutel op te halen is en het Shell-adres aanwezig is.
3
+ import { useEffect, useState } from "react";
4
+ import { useServerFn } from "@tanstack/react-start";
5
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@flowselections/core";
6
+ import { getAutoSendConfig } from "../lib/autoSend.functions.js";
7
+ export function AutomatischVersturenCard() {
8
+ const lees = useServerFn(getAutoSendConfig);
9
+ const [stand, setStand] = useState(null);
10
+ const [fout, setFout] = useState(null);
11
+ useEffect(() => {
12
+ let actief = true;
13
+ lees()
14
+ .then((r) => actief && setStand(r && typeof r === "object" ? r : null))
15
+ .catch((e) => actief && setFout(String(e?.message ?? e)));
16
+ return () => {
17
+ actief = false;
18
+ };
19
+ }, [lees]);
20
+ const jaNee = (v) => (v ? "ja" : "nee");
21
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Automatisch versturen" }), _jsx(CardDescription, { children: "Alleen voor Floriday-orders, als \"Automatisch versturen\" in de werkwijze aan staat. Is de sleutel niet op te halen of ontbreekt het Shell-adres, dan wordt er niets verstuurd." })] }), _jsx(CardContent, { className: "space-y-1 text-sm", children: fout ? (_jsxs("p", { className: "text-destructive", children: ["Stand onbekend: ", fout] })) : !stand ? (_jsx("p", { className: "text-muted-foreground", children: "Bezig met controleren\u2026" })) : (_jsxs(_Fragment, { children: [_jsxs("p", { children: ["Sleutel op te halen: ", jaNee(stand.sleutelOpTeHalen), !stand.sleutelOpTeHalen && stand.sleutelReden ? ` (${stand.sleutelReden})` : ""] }), _jsxs("p", { children: ["Shell-adres aanwezig: ", jaNee(stand.adresAanwezig)] })] })) })] }));
22
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"BeheerPage.d.ts","sourceRoot":"","sources":["../../src/components/BeheerPage.tsx"],"names":[],"mappings":"AAmJA,wBAAgB,UAAU,gCAQzB"}
1
+ {"version":3,"file":"BeheerPage.d.ts","sourceRoot":"","sources":["../../src/components/BeheerPage.tsx"],"names":[],"mappings":"AAqJA,wBAAgB,UAAU,gCAUzB"}
@@ -11,6 +11,8 @@ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent,
11
11
  import { RotateCcw } from "lucide-react";
12
12
  import { supabase } from "../integrations/supabase/moduleClient.js";
13
13
  import { RolPoort } from "./RolPoort";
14
+ import { OudeOrderregelsCard } from "./OudeOrderregelsCard";
15
+ import { AutomatischVersturenCard } from "./AutomatischVersturenCard";
14
16
  import { ENGINE_TOEGANG } from "../hooks/useEngineRollen";
15
17
  function HerindelenBeheer() {
16
18
  const [datum, setDatum] = useState("");
@@ -69,5 +71,5 @@ function HerindelenBeheer() {
69
71
  : `${voor?.geprintOfGepickt ?? 0} order(s) die al geprint of gepickt zijn, blijven ongemoeid.` })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Annuleren" }), _jsxs(AlertDialogAction, { onClick: () => void voerUit(), disabled: (voor?.aantal ?? 0) === 0, children: ["Ja, ", voor?.aantal ?? 0, " order(s) opnieuw indelen"] })] })] }) })] }));
70
72
  }
71
73
  export function BeheerPage() {
72
- return (_jsx(RolPoort, { rollen: ENGINE_TOEGANG.beheer, children: _jsx("div", { className: "space-y-6 p-6", children: _jsx(HerindelenBeheer, {}) }) }));
74
+ return (_jsx(RolPoort, { rollen: ENGINE_TOEGANG.beheer, children: _jsxs("div", { className: "space-y-6 p-6", children: [_jsx(HerindelenBeheer, {}), _jsx(OudeOrderregelsCard, {}), _jsx(AutomatischVersturenCard, {})] }) }));
73
75
  }
@@ -0,0 +1,2 @@
1
+ export declare function GearchiveerdeOrdersCard(): import("react").JSX.Element;
2
+ //# sourceMappingURL=GearchiveerdeOrdersCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GearchiveerdeOrdersCard.d.ts","sourceRoot":"","sources":["../../src/components/GearchiveerdeOrdersCard.tsx"],"names":[],"mappings":"AA2BA,wBAAgB,uBAAuB,gCAyEtC"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/GearchiveerdeOrdersCard.tsx — "Niet geleverd en gearchiveerd"
4
+ // ============================================================================
5
+ // Archiveren is een status, geen verwijdering. "Opnieuw aanbieden" zet de
6
+ // order op id terug in de wachtrij. GEEN <Header /> — die levert de shell.
7
+ // ============================================================================
8
+ import { useState } from "react";
9
+ import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, } from "@flowselections/core";
10
+ import { Archive, RefreshCw, RotateCcw } from "lucide-react";
11
+ import { redenLabel, useGearchiveerdeOrders } from "../hooks/useGeblokkeerdeOrders";
12
+ function datum(waarde) {
13
+ if (!waarde)
14
+ return "—";
15
+ const d = new Date(waarde);
16
+ return Number.isNaN(d.getTime()) ? "—" : d.toLocaleDateString("nl-NL");
17
+ }
18
+ export function GearchiveerdeOrdersCard() {
19
+ const { rows, loading, error, busy, refresh, opnieuwAanbieden } = useGearchiveerdeOrders();
20
+ const [melding, setMelding] = useState(null);
21
+ const safeRows = Array.isArray(rows) ? rows : [];
22
+ const aanbieden = async (ids) => {
23
+ try {
24
+ const n = await opnieuwAanbieden(ids);
25
+ setMelding(n === 0 ? "Er is niets opnieuw aangeboden." : `${n} order(s) opnieuw aangeboden.`);
26
+ }
27
+ catch (e) {
28
+ setMelding(e?.message ? String(e.message) : "Opnieuw aanbieden is niet gelukt.");
29
+ }
30
+ };
31
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Archive, { className: "h-4 w-4 text-muted-foreground" }), "Niet geleverd en gearchiveerd"] }), _jsx(CardDescription, { children: "Geblokkeerde orders waarvan de leverdatum meer dan 2 dagen voorbij is. Er is niets verwijderd; met Opnieuw aanbieden gaan ze terug in de wachtrij." })] }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void refresh(), disabled: loading, children: _jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }) })] }), _jsxs(CardContent, { className: "space-y-3", children: [error && _jsx("p", { className: "text-sm text-destructive", children: error }), melding && _jsx("p", { className: "text-sm text-muted-foreground", children: melding }), loading && safeRows.length === 0 ? (_jsx(Skeleton, { className: "h-12 w-full" })) : safeRows.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen gearchiveerde orders." })) : (_jsx("div", { className: "divide-y rounded-md border", children: safeRows.map((r) => (_jsxs("div", { className: "flex items-start justify-between gap-4 p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: r.orderRef }), _jsx(Badge, { variant: "secondary", children: redenLabel(r.reasonCode) }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Leverdatum ", datum(r.deliveryDate), " \u00B7 gearchiveerd ", datum(r.archivedAt), " \u00B7", " ", r.attempts, " poging(en)"] })] }), (r.lastError || r.reason) && (_jsxs("p", { className: "mt-1 line-clamp-2 text-sm text-muted-foreground", children: ["Laatste fout: ", r.lastError ?? r.reason] }))] }), _jsxs(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void aanbieden([r.orderId]), children: [_jsx(RotateCcw, { className: "mr-2 h-4 w-4" }), "Opnieuw aanbieden"] })] }, r.queueId))) }))] })] }));
32
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"GeblokkeerdeOrdersCard.d.ts","sourceRoot":"","sources":["../../src/components/GeblokkeerdeOrdersCard.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,sBAAsB,gCA6KrC"}
1
+ {"version":3,"file":"GeblokkeerdeOrdersCard.d.ts","sourceRoot":"","sources":["../../src/components/GeblokkeerdeOrdersCard.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,sBAAsB,gCA8KrC"}
@@ -59,5 +59,5 @@ export function GeblokkeerdeOrdersCard() {
59
59
  setMelding(e?.message ? String(e.message) : "Opruimen is niet gelukt.");
60
60
  }
61
61
  };
62
- return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), "Vastgelopen orders"] }), _jsx(CardDescription, { children: "Deze orders krijgen geen karrenindeling tot er iets aan de order verandert of je ze hier opnieuw aanbiedt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [zichtbaar.length > 0 && (_jsxs(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw(zichtbaar.map((r) => r.orderId)), children: [_jsx(RotateCcw, { className: "mr-2 h-4 w-4" }), "Alles opnieuw proberen"] })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void refresh(), disabled: loading, children: _jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }) })] })] }), _jsxs(CardContent, { className: "space-y-4", children: [overzicht?.tickStale && (_jsx("p", { className: "rounded-md bg-muted p-3 text-sm text-muted-foreground", children: "De verwerking op de achtergrond heeft zich langer dan tien minuten niet gemeld. Opnieuw proberen zet de order wel klaar, maar hij wordt pas opgepakt zodra de verwerking weer draait." })), error && _jsx("p", { className: "text-sm text-destructive", children: error }), melding && _jsx("p", { className: "text-sm text-muted-foreground", children: melding }), loading && safeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-6 w-full" }), _jsx(Skeleton, { className: "h-6 w-full" })] })) : safeRows.length === 0 ? (_jsxs("p", { className: "text-sm text-muted-foreground", children: ["Geen vastgelopen orders. Alles is ingedeeld of staat nog in de wachtrij", overzicht ? ` (${overzicht.pending} wachtend)` : "", "."] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Badge, { variant: filter === "" ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(""), children: ["Alles (", safeRows.length, ")"] }), codes.map(([code, aantal]) => (_jsxs(Badge, { variant: filter === code ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(code), children: [redenLabel(code), " (", aantal, ")"] }, code)))] }), _jsx("div", { className: "divide-y rounded-md border", children: zichtbaar.map((r) => (_jsxs("div", { className: "flex items-start justify-between gap-4 p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: r.orderRef }), _jsx(Badge, { variant: "secondary", children: redenLabel(r.reasonCode) }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Leverdatum ", datum(r.deliveryDate), " \u00B7 sinds ", datum(r.blockedSince)] })] }), r.reason && (_jsx("p", { className: "mt-1 line-clamp-2 text-sm text-muted-foreground", children: r.reason }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [r.reasonCode === "dubbele_regels" && (_jsx(Button, { variant: "secondary", size: "sm", disabled: busy, onClick: () => void opruimen(r.orderId, r.orderRef), children: "Dubbele regels opruimen" })), _jsx(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw([r.orderId]), children: "Opnieuw" })] })] }, r.queueId))) })] }))] })] }));
62
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), "Vastgelopen orders"] }), _jsx(CardDescription, { children: "Deze orders krijgen geen karrenindeling tot er iets aan de order verandert of je ze hier opnieuw aanbiedt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [zichtbaar.length > 0 && (_jsxs(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw(zichtbaar.map((r) => r.orderId)), children: [_jsx(RotateCcw, { className: "mr-2 h-4 w-4" }), "Alles opnieuw proberen"] })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void refresh(), disabled: loading, children: _jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }) })] })] }), _jsxs(CardContent, { className: "space-y-4", children: [overzicht?.tickStale && (_jsx("p", { className: "rounded-md bg-muted p-3 text-sm text-muted-foreground", children: "De verwerking op de achtergrond heeft zich langer dan tien minuten niet gemeld. Opnieuw proberen zet de order wel klaar, maar hij wordt pas opgepakt zodra de verwerking weer draait." })), error && _jsx("p", { className: "text-sm text-destructive", children: error }), melding && _jsx("p", { className: "text-sm text-muted-foreground", children: melding }), loading && safeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-6 w-full" }), _jsx(Skeleton, { className: "h-6 w-full" })] })) : safeRows.length === 0 ? (_jsxs("p", { className: "text-sm text-muted-foreground", children: ["Geen vastgelopen orders. Alles is ingedeeld of staat nog in de wachtrij", overzicht ? ` (${overzicht.pending} wachtend)` : "", "."] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Badge, { variant: filter === "" ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(""), children: ["Alles (", safeRows.length, ")"] }), codes.map(([code, aantal]) => (_jsxs(Badge, { variant: filter === code ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(code), children: [redenLabel(code), " (", aantal, ")"] }, code)))] }), _jsx("div", { className: "divide-y rounded-md border", children: zichtbaar.map((r) => (_jsxs("div", { className: "flex items-start justify-between gap-4 p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: r.orderRef }), _jsx(Badge, { variant: "secondary", children: redenLabel(r.reasonCode) }), _jsx(Badge, { variant: "outline", children: "Wacht op actie" }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Leverdatum ", datum(r.deliveryDate), " \u00B7 sinds ", datum(r.blockedSince)] })] }), r.reason && (_jsx("p", { className: "mt-1 line-clamp-2 text-sm text-muted-foreground", children: r.reason }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [r.reasonCode === "dubbele_regels" && (_jsx(Button, { variant: "secondary", size: "sm", disabled: busy, onClick: () => void opruimen(r.orderId, r.orderRef), children: "Dubbele regels opruimen" })), _jsx(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw([r.orderId]), children: "Opnieuw" })] })] }, r.queueId))) })] }))] })] }));
63
63
  }
@@ -0,0 +1,2 @@
1
+ export declare function OudeOrderregelsCard(): import("react").JSX.Element;
2
+ //# sourceMappingURL=OudeOrderregelsCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OudeOrderregelsCard.d.ts","sourceRoot":"","sources":["../../src/components/OudeOrderregelsCard.tsx"],"names":[],"mappings":"AAeA,wBAAgB,mBAAmB,gCAiDlC"}
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // src/components/OudeOrderregelsCard.tsx — orders met een oude pakbon-orderregel
3
+ // (bron: logistics_pakbon_oude_orderregels, alleen lezen).
4
+ import { useEffect, useState } from "react";
5
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@flowselections/core";
6
+ import { supabase } from "../integrations/supabase/moduleClient.js";
7
+ export function OudeOrderregelsCard() {
8
+ const [rijen, setRijen] = useState([]);
9
+ const [fout, setFout] = useState(null);
10
+ useEffect(() => {
11
+ let actief = true;
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ supabase.rpc("logistics_pakbon_oude_orderregels").then(({ data, error }) => {
14
+ if (!actief)
15
+ return;
16
+ if (error)
17
+ setFout(error.message);
18
+ else
19
+ setRijen(Array.isArray(data) ? data : []);
20
+ });
21
+ return () => {
22
+ actief = false;
23
+ };
24
+ }, []);
25
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Oude pakbon-orderregels" }), _jsx(CardDescription, { children: "Orders die geen pakbon per kar krijgen omdat er al een oude orderregel bestaat. Er wordt niets aangepast zonder akkoord." })] }), _jsx(CardContent, { children: fout ? (_jsxs("p", { className: "text-sm text-destructive", children: ["Kon het overzicht niet laden: ", fout] })) : rijen.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen orders met een oude orderregel." })) : (_jsx("ul", { className: "space-y-2 text-sm", children: rijen.map((r) => (_jsxs("li", { children: [_jsx("span", { className: "font-medium", children: r.orderNumber }), ": ", r.melding, r.oudeRegel ? ` (${r.oudeRegel})` : "", Array.isArray(r.bufferOrders) && r.bufferOrders.length > 1
26
+ ? ` — buffer: ${r.bufferOrders.join(", ")}`
27
+ : ""] }, `${r.orderId}-${r.oudeRegel ?? ""}`))) })) })] }));
28
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"PlanWachtrijPage.d.ts","sourceRoot":"","sources":["../../src/components/PlanWachtrijPage.tsx"],"names":[],"mappings":"AAsEA,wBAAgB,gBAAgB,gCA0N/B"}
1
+ {"version":3,"file":"PlanWachtrijPage.d.ts","sourceRoot":"","sources":["../../src/components/PlanWachtrijPage.tsx"],"names":[],"mappings":"AAuEA,wBAAgB,gBAAgB,gCAmO/B"}
@@ -12,6 +12,7 @@ import { AlertTriangle, RefreshCw, RotateCcw } from "lucide-react";
12
12
  import { toast } from "sonner";
13
13
  import { usePlanWachtrij } from "../hooks/usePlanWachtrij";
14
14
  import { foutTekst } from "../lib/foutTekst";
15
+ import { GearchiveerdeOrdersCard } from "./GearchiveerdeOrdersCard";
15
16
  const STAND_KLEUR = {
16
17
  wacht: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
17
18
  bezig: "bg-sky-500/15 text-sky-700 dark:text-sky-300",
@@ -83,17 +84,23 @@ export function PlanWachtrijPage() {
83
84
  toast.error(e?.message ? String(e.message) : "Opnieuw starten is niet gelukt.");
84
85
  }
85
86
  }
86
- return (_jsx("div", { className: "space-y-4 p-4", children: _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Wachtrij \u2014 orders die op een karrenindeling wachten" }), _jsx(CardDescription, { children: "Per order zie je de stand, hoe vaak het is geprobeerd en wat er misging. Je kunt de wachtrij opnieuw starten: de Engine kijkt dan opnieuw wat er in de order zit en maakt de karrenindeling opnieuw. Al geprinte, gescande of gecontroleerde karren blijven altijd staan." })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [FILTERS.map((f) => (_jsxs(Button, { size: "sm", variant: filter === f.id ? "default" : "outline", onClick: () => setFilter(f.id), children: [f.label, f.id !== "alles" && f.id !== "open" ? (_jsx("span", { className: "ml-1 text-xs opacity-70", children: f.id === "mislukt"
87
- ? (tellingen["mislukt"] ?? 0) + (tellingen["geblokkeerd"] ?? 0)
88
- : tellingen[f.id] ?? 0 })) : null] }, f.id))), _jsx(Input, { value: zoek, onChange: (e) => setZoek(e.target.value), placeholder: "Zoek op ordernummer of klant", className: "h-9 w-64" }), _jsxs("div", { className: "ml-auto flex flex-wrap gap-2", children: [_jsx(Button, { size: "sm", variant: "outline", onClick: () => setNieuwsteEerst((v) => !v), children: nieuwsteEerst ? "Nieuwste eerst" : "Oudste eerst" }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void refresh(), disabled: busy, children: [_jsx(RefreshCw, { className: "mr-1 h-4 w-4" }), " Verversen"] }), _jsx(Button, { size: "sm", variant: "outline", disabled: busy, onClick: () => void doeReset("stuck", "Regels die al langer dan een kwartier 'bezig' blijven terugzetten op wachtend?"), children: "Blijft hangen losmaken" }), _jsxs(Button, { size: "sm", disabled: busy, onClick: () => void doeReset("failed", "Alle mislukte en geblokkeerde orders opnieuw aanmelden? De Engine bekijkt ze opnieuw en maakt de karrenindeling opnieuw."), children: [_jsx(RotateCcw, { className: "mr-1 h-4 w-4" }), " Wachtrij resetten"] }), _jsx(Button, { size: "sm", variant: "destructive", disabled: busy, onClick: () => void doeReset("all", "De hele wachtrij opnieuw starten, dus ook orders die al klaar waren? Dit kan even duren."), children: "Alles opnieuw" })] })] }), error ? (_jsxs("p", { className: "flex items-center gap-2 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), " ", error] })) : null, loading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-8 w-full" }), _jsx(Skeleton, { className: "h-8 w-full" }), _jsx(Skeleton, { className: "h-8 w-full" })] })) : zichtbaar.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen regels in de wachtrij voor deze keuze." })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Order" }), _jsx(TableHead, { children: "Stand" }), _jsx(TableHead, { children: "Voortgang" }), _jsx(TableHead, { children: "Pogingen" }), _jsx(TableHead, { children: "Volgende poging" }), _jsx(TableHead, { children: "Aangemeld omdat" }), _jsx(TableHead, { children: "Wat ging er mis" }), _jsx(TableHead, { children: "Bijgewerkt" }), _jsx(TableHead, {})] }) }), _jsx(TableBody, { children: zichtbaar.map((r) => (_jsxs(TableRow, { children: [_jsxs(TableCell, { children: [_jsx("div", { className: "font-medium", children: r.orderNumber ?? "—" }), _jsx("div", { className: "text-xs text-muted-foreground", children: r.klant ?? "" })] }), _jsx(TableCell, { children: _jsx(Badge, { className: STAND_KLEUR[r.stand] ?? "", children: r.stand }) }), _jsx(TableCell, { className: "w-40", children: r.voortgang === null ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" })) : (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "h-2 w-28 overflow-hidden rounded-full bg-muted", children: _jsx("div", { className: "h-full rounded-full bg-primary transition-all", style: { width: `${Math.min(100, Math.max(0, r.voortgang))}%` } }) }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [r.voortgang, "% van de orderregels ingedeeld"] })] })) }), _jsxs(TableCell, { className: "text-sm", children: [r.pogingen, " van ", r.maxPogingen || "—"] }), _jsx(TableCell, { className: "text-sm", children: klok(r.volgendePoging) }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: r.reden ?? "—" }), _jsxs(TableCell, { className: "max-w-md text-sm", children: [r.foutTekst ?? foutTekst(r.foutRuw) ?? "—", r.foutRuw && (r.foutTekst ?? foutTekst(r.foutRuw)) !== r.foutRuw ? (_jsxs("details", { className: "mt-1", children: [_jsx("summary", { className: "cursor-pointer text-xs text-muted-foreground", children: "Technische details" }), _jsx("p", { className: "mt-1 break-words text-xs text-muted-foreground", children: r.foutRuw })] })) : null] }), _jsx(TableCell, { className: "text-xs text-muted-foreground", children: tijd(r.bijgewerktOp) }), _jsx(TableCell, { className: "text-right", children: _jsx(Button, { size: "sm", variant: "outline", disabled: busy || !r.orderId, onClick: async () => {
89
- if (!r.orderId)
90
- return;
91
- try {
92
- await opnieuw(r.orderId);
93
- toast.success(`${r.orderNumber ?? "Order"} opnieuw aangemeld.`);
94
- }
95
- catch (e) {
96
- toast.error(e?.message ? String(e.message) : "Opnieuw proberen is niet gelukt.");
97
- }
98
- }, children: "Opnieuw" }) })] }, r.id))) })] }))] })] }) }));
87
+ return (_jsxs("div", { className: "space-y-4 p-4", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Wachtrij \u2014 orders die op een karrenindeling wachten" }), _jsx(CardDescription, { children: "Per order zie je de stand, hoe vaak het is geprobeerd en wat er misging. Je kunt de wachtrij opnieuw starten: de Engine kijkt dan opnieuw wat er in de order zit en maakt de karrenindeling opnieuw. Al geprinte, gescande of gecontroleerde karren blijven altijd staan." })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [FILTERS.map((f) => (_jsxs(Button, { size: "sm", variant: filter === f.id ? "default" : "outline", onClick: () => setFilter(f.id), children: [f.label, f.id !== "alles" && f.id !== "open" ? (_jsx("span", { className: "ml-1 text-xs opacity-70", children: f.id === "mislukt"
88
+ ? (tellingen["mislukt"] ?? 0) + (tellingen["geblokkeerd"] ?? 0)
89
+ : tellingen[f.id] ?? 0 })) : null] }, f.id))), _jsx(Input, { value: zoek, onChange: (e) => setZoek(e.target.value), placeholder: "Zoek op ordernummer of klant", className: "h-9 w-64" }), _jsxs("div", { className: "ml-auto flex flex-wrap gap-2", children: [_jsx(Button, { size: "sm", variant: "outline", onClick: () => setNieuwsteEerst((v) => !v), children: nieuwsteEerst ? "Nieuwste eerst" : "Oudste eerst" }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void refresh(), disabled: busy, children: [_jsx(RefreshCw, { className: "mr-1 h-4 w-4" }), " Verversen"] }), _jsx(Button, { size: "sm", variant: "outline", disabled: busy, onClick: () => void doeReset("stuck", "Regels die al langer dan een kwartier 'bezig' blijven terugzetten op wachtend?"), children: "Blijft hangen losmaken" }), _jsxs(Button, { size: "sm", disabled: busy, onClick: () => void doeReset("failed", "Alle mislukte en geblokkeerde orders opnieuw aanmelden? De Engine bekijkt ze opnieuw en maakt de karrenindeling opnieuw."), children: [_jsx(RotateCcw, { className: "mr-1 h-4 w-4" }), " Wachtrij resetten"] }), _jsx(Button, { size: "sm", variant: "destructive", disabled: busy, onClick: () => void doeReset("all", "De hele wachtrij opnieuw starten, dus ook orders die al klaar waren? Dit kan even duren."), children: "Alles opnieuw" })] })] }), error ? (_jsxs("p", { className: "flex items-center gap-2 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), " ", error] })) : null, loading ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-8 w-full" }), _jsx(Skeleton, { className: "h-8 w-full" }), _jsx(Skeleton, { className: "h-8 w-full" })] })) : zichtbaar.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen regels in de wachtrij voor deze keuze." })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Order" }), _jsx(TableHead, { children: "Stand" }), _jsx(TableHead, { children: "Voortgang" }), _jsx(TableHead, { children: "Pogingen" }), _jsx(TableHead, { children: "Volgende poging" }), _jsx(TableHead, { children: "Aangemeld omdat" }), _jsx(TableHead, { children: "Wat ging er mis" }), _jsx(TableHead, { children: "Bijgewerkt" }), _jsx(TableHead, {})] }) }), _jsx(TableBody, { children: zichtbaar.map((r) => (_jsxs(TableRow, { children: [_jsxs(TableCell, { children: [_jsx("div", { className: "font-medium", children: r.orderNumber ?? "—" }), _jsx("div", { className: "text-xs text-muted-foreground", children: r.klant ?? "" })] }), _jsx(TableCell, { children: _jsx(Badge, { className: STAND_KLEUR[r.stand] ?? "", children: r.stand }) }), _jsx(TableCell, { className: "w-40", children: r.voortgang === null ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "\u2014" })) : (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "h-2 w-28 overflow-hidden rounded-full bg-muted", children: _jsx("div", { className: "h-full rounded-full bg-primary transition-all", style: { width: `${Math.min(100, Math.max(0, r.voortgang))}%` } }) }), _jsxs("span", { className: "text-xs text-muted-foreground", children: [r.voortgang, "% van de orderregels ingedeeld"] })] })) }), _jsx(TableCell, { className: "text-sm", children: ["geblokkeerd", "failed", "gearchiveerd", "opgelost"].includes(r.status)
90
+ ? `${r.pogingen} poging(en)`
91
+ : `${r.pogingen} van ${r.maxPogingen || "—"}` }), _jsx(TableCell, { className: "text-sm", children: ["geblokkeerd", "failed"].includes(r.status)
92
+ ? "Wacht op actie"
93
+ : ["gearchiveerd", "opgelost", "done"].includes(r.status)
94
+ ? "—"
95
+ : klok(r.volgendePoging) }), _jsx(TableCell, { className: "text-sm text-muted-foreground", children: r.reden ?? "—" }), _jsxs(TableCell, { className: "max-w-md text-sm", children: [r.foutTekst ?? foutTekst(r.foutRuw) ?? "—", r.foutRuw && (r.foutTekst ?? foutTekst(r.foutRuw)) !== r.foutRuw ? (_jsxs("details", { className: "mt-1", children: [_jsx("summary", { className: "cursor-pointer text-xs text-muted-foreground", children: "Technische details" }), _jsx("p", { className: "mt-1 break-words text-xs text-muted-foreground", children: r.foutRuw })] })) : null] }), _jsx(TableCell, { className: "text-xs text-muted-foreground", children: tijd(r.bijgewerktOp) }), _jsx(TableCell, { className: "text-right", children: _jsx(Button, { size: "sm", variant: "outline", disabled: busy || !r.orderId, onClick: async () => {
96
+ if (!r.orderId)
97
+ return;
98
+ try {
99
+ await opnieuw(r.orderId);
100
+ toast.success(`${r.orderNumber ?? "Order"} opnieuw aangemeld.`);
101
+ }
102
+ catch (e) {
103
+ toast.error(e?.message ? String(e.message) : "Opnieuw proberen is niet gelukt.");
104
+ }
105
+ }, children: "Opnieuw" }) })] }, r.id))) })] }))] })] }), _jsx(GearchiveerdeOrdersCard, {})] }));
99
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RuleEnginePage.d.ts","sourceRoot":"","sources":["../../src/components/RuleEnginePage.tsx"],"names":[],"mappings":"AAsEA,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AA4cD,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,+BAMxC"}
1
+ {"version":3,"file":"RuleEnginePage.d.ts","sourceRoot":"","sources":["../../src/components/RuleEnginePage.tsx"],"names":[],"mappings":"AAuEA,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAueD,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,GAAG,+BAMxC"}
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  // ============================================================================
3
3
  // src/components/RuleEnginePage.tsx — logistieke werkwijze instellen
4
4
  // ============================================================================
5
- import { useMemo, useState } from "react";
5
+ import { useEffect, useMemo, useState } from "react";
6
+ import { supabase } from "../integrations/supabase/moduleClient.js";
6
7
  import { useSearch } from "@tanstack/react-router";
7
8
  import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Input, Label, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Skeleton, } from "@flowselections/core";
8
9
  import { AlertTriangle, CheckCircle2, ChevronLeft, ChevronRight, MoreVertical, Plus, RefreshCw, Save, Trash2, } from "lucide-react";
@@ -116,7 +117,25 @@ function RuleEnginePageInhoud({ strategyId: strategyIdProp = null, strategyName:
116
117
  }
117
118
  return list;
118
119
  }, [job]);
119
- const showJobLine = Boolean(job) && (running || job?.status === "error" || jobProblems.length > 0);
120
+ // Een oude, mislukte volledige herberekening is niet meer de actuele stand:
121
+ // alleen een lopende of recente (laatste 24 uur) herberekening tonen. De
122
+ // minuutronde rekent daarna per order verder; de uitkomst daarvan staat hier.
123
+ const jobRecent = Boolean(job?.finished_at) &&
124
+ Date.now() - new Date(job?.finished_at ?? 0).getTime() < 24 * 60 * 60 * 1000;
125
+ const showJobLine = Boolean(job) && (running || (jobRecent && (job?.status === "error" || jobProblems.length > 0)));
126
+ const [laatsteRonde, setLaatsteRonde] = useState(null);
127
+ useEffect(() => {
128
+ let actief = true;
129
+ void (async () => {
130
+ const { data } = await supabase.rpc("logistics_blocked_overview");
131
+ if (!actief || !data)
132
+ return;
133
+ setLaatsteRonde({ at: data.lastTickAt ?? null, stale: Boolean(data.tickStale ?? true) });
134
+ })();
135
+ return () => {
136
+ actief = false;
137
+ };
138
+ }, [job?.status]);
120
139
  return (_jsxs("div", { className: "space-y-4 p-6", children: [_jsxs("header", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h1", { className: "text-xl font-semibold tracking-tight", children: strategyName ? `Werkwijze: ${strategyName}` : "Werkwijze instellen" }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => setCreateOpen(true), children: [_jsx(Plus, { className: "h-4 w-4" }), "Nieuw"] }), _jsxs(Button, { size: "sm", disabled: !activeConfig || saving || busy, onClick: handleSaveAndRecalculate, children: [busy ? _jsx(RefreshCw, { className: "h-4 w-4 animate-spin" }) : _jsx(Save, { className: "h-4 w-4" }), running
121
140
  ? `${phaseLabel(job?.phase)}… (${job?.processed ?? 0})`
122
141
  : busy
@@ -125,7 +144,9 @@ function RuleEnginePageInhoud({ strategyId: strategyIdProp = null, strategyName:
125
144
  ? `${phaseLabel(job?.phase)} — ${job?.processed ?? 0} verwerkt`
126
145
  : `De laatste volledige herberekening${job?.finished_at
127
146
  ? ` (${new Date(job.finished_at).toLocaleString("nl-NL", { dateStyle: "medium", timeStyle: "short" })})`
128
- : ""} is niet volledig gelukt. Deze meldingen horen bij die berekening; opnieuw berekenen ververst ze.` }), jobProblems.length > 0 && (_jsx("ul", { className: "mt-1 list-disc pl-5 text-xs", children: jobProblems.map((p, i) => (_jsx("li", { children: p }, i))) }))] })), !loading && activeConfig && !activeConfig.is_active && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-md border border-amber-500/60 bg-amber-500/5 px-3 py-2 text-sm", children: [_jsxs("span", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), "Deze werkwijze staat nog op ", _jsx("strong", { children: "concept" }), " en telt nog niet mee bij het inplannen."] }), _jsxs(Button, { size: "sm", onClick: () => activateConfig(activeConfig.id), children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), "Nu activeren"] })] })), loading || (strategyId && !activeConfig && !error) ? (_jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-64 w-full" })] })) : !activeConfig ? (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Nog geen werkwijze" }), _jsx(CardDescription, { children: "Maak een werkwijze aan om vast te leggen hoe jouw orders verwerkt worden." })] }), _jsx(CardContent, { children: _jsxs(Button, { onClick: () => setCreateOpen(true), children: [_jsx(Plus, { className: "h-4 w-4" }), "Werkwijze aanmaken"] }) })] })) : (_jsxs("div", { className: `grid gap-6 lg:h-[calc(100vh-13rem)] ${sideOpen
147
+ : ""} is niet volledig gelukt. Deze meldingen horen bij die berekening; opnieuw berekenen ververst ze.` }), jobProblems.length > 0 && (_jsx("ul", { className: "mt-1 list-disc pl-5 text-xs", children: jobProblems.map((p, i) => (_jsx("li", { children: p }, i))) }))] })), !showJobLine && laatsteRonde && (_jsx("p", { className: "rounded-md border border-border px-3 py-2 text-sm text-muted-foreground", children: laatsteRonde.at
148
+ ? `Laatste ronde: ${new Date(laatsteRonde.at).toLocaleString("nl-NL", { dateStyle: "medium", timeStyle: "short" })}${laatsteRonde.stale ? " — de ronde heeft zich langer dan tien minuten niet gemeld." : " — orders worden per ronde opnieuw ingedeeld."}`
149
+ : "De ronde heeft zich nog niet gemeld." })), !loading && activeConfig && !activeConfig.is_active && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3 rounded-md border border-amber-500/60 bg-amber-500/5 px-3 py-2 text-sm", children: [_jsxs("span", { className: "flex items-start gap-2", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-amber-600" }), "Deze werkwijze staat nog op ", _jsx("strong", { children: "concept" }), " en telt nog niet mee bij het inplannen."] }), _jsxs(Button, { size: "sm", onClick: () => activateConfig(activeConfig.id), children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), "Nu activeren"] })] })), loading || (strategyId && !activeConfig && !error) ? (_jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-64 w-full" })] })) : !activeConfig ? (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Nog geen werkwijze" }), _jsx(CardDescription, { children: "Maak een werkwijze aan om vast te leggen hoe jouw orders verwerkt worden." })] }), _jsx(CardContent, { children: _jsxs(Button, { onClick: () => setCreateOpen(true), children: [_jsx(Plus, { className: "h-4 w-4" }), "Werkwijze aanmaken"] }) })] })) : (_jsxs("div", { className: `grid gap-6 lg:h-[calc(100vh-13rem)] ${sideOpen
129
150
  ? "lg:grid-cols-[220px_minmax(0,1fr)_320px]"
130
151
  : "lg:grid-cols-[220px_minmax(0,1fr)_44px]"}`, children: [_jsx("nav", { className: "space-y-1 lg:overflow-y-auto lg:pr-1", children: WIZARD_STEPS.map((item, index) => (_jsxs("button", { type: "button", onClick: () => setStepIndex(index), className: `flex w-full items-center gap-3 rounded-lg border p-2.5 text-left transition-colors ${index === stepIndex
131
152
  ? "border-primary bg-primary/5"
@@ -32,4 +32,24 @@ export declare function useGeblokkeerdeOrders(): {
32
32
  meerTeDoen: boolean;
33
33
  }>;
34
34
  };
35
+ export interface GearchiveerdeOrder {
36
+ queueId: string;
37
+ orderId: string;
38
+ orderRef: string;
39
+ deliveryDate: string | null;
40
+ reason: string | null;
41
+ reasonCode: string;
42
+ lastError: string | null;
43
+ attempts: number;
44
+ archivedAt: string | null;
45
+ }
46
+ /** Lijst "Niet geleverd en gearchiveerd" en "Opnieuw aanbieden" (op order-id). */
47
+ export declare function useGearchiveerdeOrders(): {
48
+ rows: GearchiveerdeOrder[];
49
+ loading: boolean;
50
+ error: string | null;
51
+ busy: boolean;
52
+ refresh: () => Promise<void>;
53
+ opnieuwAanbieden: (orderIds: string[]) => Promise<number>;
54
+ };
35
55
  //# sourceMappingURL=useGeblokkeerdeOrders.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useGeblokkeerdeOrders.d.ts","sourceRoot":"","sources":["../../src/hooks/useGeblokkeerdeOrders.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAc9C,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,UAGzD;AAED,wBAAgB,qBAAqB;;;;;;;sBAqDhB,MAAM,EAAE;gCAwBT,MAAM;;;;;;;EAyBzB"}
1
+ {"version":3,"file":"useGeblokkeerdeOrders.d.ts","sourceRoot":"","sources":["../../src/hooks/useGeblokkeerdeOrders.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAe9C,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,UAGzD;AAED,wBAAgB,qBAAqB;;;;;;;sBAqDhB,MAAM,EAAE;gCAwBT,MAAM;;;;;;;EAyBzB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,kFAAkF;AAClF,wBAAgB,sBAAsB;;;;;;iCAsCjB,MAAM,EAAE;EAmB5B"}
@@ -17,6 +17,7 @@ export const REDEN_LABEL = {
17
17
  bufferdekking_onvolledig: "Buffer niet volledig gedekt",
18
18
  dubbele_regels: "Dubbele bestelregels",
19
19
  karindeling_geblokkeerd: "Karindeling geblokkeerd",
20
+ indeling_te_lang: "Indeling duurde te lang",
20
21
  other: "Overige reden",
21
22
  };
22
23
  export function redenLabel(code) {
@@ -118,3 +119,59 @@ export function useGeblokkeerdeOrders() {
118
119
  }, [load]);
119
120
  return { rows, overzicht, loading, error, busy, refresh: load, retry, dubbelenOpruimen };
120
121
  }
122
+ /** Lijst "Niet geleverd en gearchiveerd" en "Opnieuw aanbieden" (op order-id). */
123
+ export function useGearchiveerdeOrders() {
124
+ const [rows, setRows] = useState([]);
125
+ const [loading, setLoading] = useState(true);
126
+ const [error, setError] = useState(null);
127
+ const [busy, setBusy] = useState(false);
128
+ const load = useCallback(async () => {
129
+ setLoading(true);
130
+ setError(null);
131
+ try {
132
+ const { data, error: rpcError } = await supabase.rpc("logistics_archived_orders");
133
+ if (rpcError)
134
+ throw new Error(rpcError.message);
135
+ const safe = Array.isArray(data) ? data : [];
136
+ setRows(safe.map((r) => ({
137
+ queueId: String(r.queue_id),
138
+ orderId: String(r.order_id),
139
+ orderRef: String(r.order_ref ?? r.order_id),
140
+ deliveryDate: r.delivery_date ?? null,
141
+ reason: r.reason ?? null,
142
+ reasonCode: String(r.reason_code ?? "other"),
143
+ lastError: r.last_error ?? null,
144
+ attempts: Number(r.attempts ?? 0),
145
+ archivedAt: r.archived_at ?? null,
146
+ })));
147
+ }
148
+ catch (e) {
149
+ setError(e?.message ? String(e.message) : "Kon de gearchiveerde orders niet ophalen.");
150
+ }
151
+ finally {
152
+ setLoading(false);
153
+ }
154
+ }, []);
155
+ useEffect(() => {
156
+ void load();
157
+ }, [load]);
158
+ const opnieuwAanbieden = useCallback(async (orderIds) => {
159
+ const ids = Array.isArray(orderIds) ? orderIds.filter(Boolean) : [];
160
+ if (ids.length === 0)
161
+ return 0;
162
+ setBusy(true);
163
+ try {
164
+ const { data, error: rpcError } = await supabase.rpc("logistics_plan_unarchive", {
165
+ p_order_ids: ids,
166
+ });
167
+ if (rpcError)
168
+ throw new Error(rpcError.message);
169
+ await load();
170
+ return Number(data ?? 0);
171
+ }
172
+ finally {
173
+ setBusy(false);
174
+ }
175
+ }, [load]);
176
+ return { rows, loading, error, busy, refresh: load, opnieuwAanbieden };
177
+ }
@@ -14,6 +14,7 @@ export { BeladingsafwijkingenCard } from './components/BeladingsafwijkingenCard'
14
14
  export * from './hooks/useBeladingsafwijkingen';
15
15
  export { KarplanStatusCard } from './components/KarplanStatusCard';
16
16
  export { GeblokkeerdeOrdersCard } from './components/GeblokkeerdeOrdersCard';
17
+ export { GearchiveerdeOrdersCard } from './components/GearchiveerdeOrdersCard';
17
18
  export { AfmetingenBronnenCard } from './components/AfmetingenBronnenCard';
18
19
  export { WerkwijzeHerindelingCard } from './components/WerkwijzeHerindelingCard';
19
20
  export { WerktijdenCard } from './components/WerktijdenCard';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist-lib/index.js CHANGED
@@ -17,6 +17,7 @@ export { BeladingsafwijkingenCard } from './components/BeladingsafwijkingenCard'
17
17
  export * from './hooks/useBeladingsafwijkingen';
18
18
  export { KarplanStatusCard } from './components/KarplanStatusCard';
19
19
  export { GeblokkeerdeOrdersCard } from './components/GeblokkeerdeOrdersCard';
20
+ export { GearchiveerdeOrdersCard } from './components/GearchiveerdeOrdersCard';
20
21
  export { AfmetingenBronnenCard } from './components/AfmetingenBronnenCard';
21
22
  export { WerkwijzeHerindelingCard } from './components/WerkwijzeHerindelingCard';
22
23
  export { WerktijdenCard } from './components/WerktijdenCard';
@@ -1 +1 @@
1
- {"version":3,"file":"previewAuthStorage.d.ts","sourceRoot":"","sources":["../../../src/integrations/supabase/previewAuthStorage.ts"],"names":[],"mappings":"AAIA,wBAAgB,sBAAsB;mBA2Db,MAAM;mBAeZ,MAAM,SAAS,MAAM;sBASlB,MAAM;cAK3B"}
1
+ {"version":3,"file":"previewAuthStorage.d.ts","sourceRoot":"","sources":["../../../src/integrations/supabase/previewAuthStorage.ts"],"names":[],"mappings":"AAIA,wBAAgB,sBAAsB;mBA6Db,MAAM;mBAwBZ,MAAM,SAAS,MAAM;sBASlB,MAAM;cAM3B"}
@@ -61,21 +61,38 @@ export function brokeredPreviewStorage() {
61
61
  // The editor may not be listening yet at the first getItem, so retry once.
62
62
  let firstGet = true;
63
63
  const RETRY_DELAY = 250;
64
+ // Blocked third-party storage throws here; seeding must not break broker reads.
65
+ const readLocal = (key) => { try {
66
+ return localStorage.getItem(key);
67
+ }
68
+ catch {
69
+ return undefined;
70
+ } };
64
71
  return {
65
72
  getItem: async (key) => {
66
- let res = await request('lovable-preview-auth:get', key);
73
+ // Sent with GET and REMOVE so an editor that never cached this session can check or revoke it.
74
+ const local = readLocal(key);
75
+ let res = await request('lovable-preview-auth:get', key, local ?? undefined);
67
76
  if (!res && firstGet) {
68
77
  await new Promise((r) => setTimeout(r, RETRY_DELAY));
69
- res = await request('lovable-preview-auth:get', key);
78
+ res = await request('lovable-preview-auth:get', key, local ?? undefined);
70
79
  }
71
80
  firstGet = false;
72
81
  // '' is the logout tombstone: clear the local copy too so it can't resurrect if
73
82
  // the broker later goes silent. A null reply means never-synced -> keep local.
74
83
  if (res && res.ok && typeof res.value === 'string') {
75
84
  if (res.value === '') {
76
- localStorage.removeItem(key);
85
+ if (local !== undefined && readLocal(key) === local)
86
+ localStorage.removeItem(key);
77
87
  return null;
78
88
  }
89
+ // Seed this origin so a new tab, whose editor holds no session, stays signed in.
90
+ if (local === null && readLocal(key) === null) {
91
+ try {
92
+ localStorage.setItem(key, res.value);
93
+ }
94
+ catch { /* storage full: still return the editor's session */ }
95
+ }
79
96
  return res.value;
80
97
  }
81
98
  return localStorage.getItem(key);
@@ -92,8 +109,9 @@ export function brokeredPreviewStorage() {
92
109
  });
93
110
  },
94
111
  removeItem: (key) => {
112
+ const local = readLocal(key);
95
113
  localStorage.removeItem(key);
96
- return request('lovable-preview-auth:remove', key).then(() => undefined);
114
+ return request('lovable-preview-auth:remove', key, local ?? undefined).then(() => undefined);
97
115
  },
98
116
  };
99
117
  }