@flowselections/logistiek-engine 1.0.90 → 1.0.98

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 (53) hide show
  1. package/dist-lib/components/FlowOrders.js +1 -1
  2. package/dist-lib/components/MisluktVerzendbrievenCard.d.ts +2 -0
  3. package/dist-lib/components/MisluktVerzendbrievenCard.d.ts.map +1 -0
  4. package/dist-lib/components/MisluktVerzendbrievenCard.js +50 -0
  5. package/dist-lib/components/RegiePage.d.ts.map +1 -1
  6. package/dist-lib/components/RegiePage.js +2 -1
  7. package/dist-lib/components/RuleEnginePage.d.ts.map +1 -1
  8. package/dist-lib/components/RuleEnginePage.js +3 -1
  9. package/dist-lib/hooks/useShippingNoteStatus.d.ts +2 -0
  10. package/dist-lib/hooks/useShippingNoteStatus.d.ts.map +1 -1
  11. package/dist-lib/hooks/useShippingNoteStatus.js +13 -1
  12. package/dist-lib/hooks/useShippingNoteStatus.test.d.ts +2 -0
  13. package/dist-lib/hooks/useShippingNoteStatus.test.d.ts.map +1 -0
  14. package/dist-lib/hooks/useShippingNoteStatus.test.js +20 -0
  15. package/dist-lib/integrations/supabase/auth-middleware.d.ts +415 -0
  16. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  17. package/dist-lib/integrations/supabase/client.server.d.ts +415 -0
  18. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  19. package/dist-lib/integrations/supabase/moduleClient.d.ts +415 -0
  20. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  21. package/dist-lib/integrations/supabase/types.d.ts +423 -0
  22. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  23. package/dist-lib/lib/cartCoverage.functions.d.ts +415 -0
  24. package/dist-lib/lib/cartCoverage.functions.d.ts.map +1 -1
  25. package/dist-lib/lib/controlScan.server.d.ts +2 -0
  26. package/dist-lib/lib/controlScan.server.d.ts.map +1 -1
  27. package/dist-lib/lib/controlScan.server.js +59 -53
  28. package/dist-lib/lib/floridayDocuments.functions.d.ts +1245 -0
  29. package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
  30. package/dist-lib/lib/floridayPush.functions.d.ts +415 -0
  31. package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
  32. package/dist-lib/lib/layoutPrint.server.d.ts +27 -0
  33. package/dist-lib/lib/layoutPrint.server.d.ts.map +1 -0
  34. package/dist-lib/lib/layoutPrint.server.js +48 -0
  35. package/dist-lib/lib/layoutPrint.test.d.ts +2 -0
  36. package/dist-lib/lib/layoutPrint.test.d.ts.map +1 -0
  37. package/dist-lib/lib/layoutPrint.test.js +47 -0
  38. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +2075 -0
  39. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
  40. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  41. package/dist-lib/lib/loadCarrierPlanning.server.js +52 -8
  42. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +830 -0
  43. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
  44. package/dist-lib/lib/logisticsRecalculate.functions.d.ts +415 -0
  45. package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
  46. package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
  47. package/dist-lib/lib/modulePrompts.js +54 -0
  48. package/dist-lib/lib/plannerDiff.functions.d.ts +415 -0
  49. package/dist-lib/lib/plannerDiff.functions.d.ts.map +1 -1
  50. package/dist-lib/lib/ruleEngineSchema.js +2 -2
  51. package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -1
  52. package/dist-lib/lib/shippingNoteQueue.server.js +40 -49
  53. package/package.json +1 -1
@@ -149,7 +149,7 @@ export function FlowOrders({ onRoute }) {
149
149
  ["fout", "Vastgelopen"],
150
150
  ["bezig", "Bezig / wachtend"],
151
151
  ["klaar", "Overig"],
152
- ].map(([w, l]) => (_jsx(Button, { size: "sm", variant: filter === w ? "default" : "outline", onClick: () => setFilter(w), children: l }, w))), _jsx(Button, { size: "sm", variant: "outline", onClick: () => setSortering((s) => (s === "nieuw" ? "oud" : "nieuw")), children: sortering === "nieuw" ? "Nieuwste eerst" : "Oudste eerst" }), _jsxs("span", { className: "ml-auto text-xs text-muted-foreground", children: [gefilterd.length, " orders"] })] })] }), _jsxs(CardContent, { className: "space-y-3", children: [error && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2", children: [_jsx("p", { className: "text-sm text-destructive", children: error }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void refresh(), disabled: loading, children: [_jsx(RefreshCw, { className: `mr-1 h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` }), "Opnieuw proberen"] })] })), loading && veiligeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : gefilterd.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen orders gevonden." })) : (_jsx("div", { className: "max-h-[420px] overflow-y-auto rounded-md border border-border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "sticky top-0 bg-muted/60 text-xs text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Order" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Klant" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Bron" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Levering" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Stand" }), _jsx("th", { className: "px-2 py-1.5 text-right font-medium", children: "Versies" }), _jsx("th", { className: "px-2 py-1.5 text-right font-medium", children: "Fouten" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Laatste activiteit" })] }) }), _jsx("tbody", { children: gefilterd.map((r) => {
152
+ ].map(([w, l]) => (_jsx(Button, { size: "sm", variant: filter === w ? "default" : "outline", onClick: () => setFilter(w), children: l }, w))), _jsx(Button, { size: "sm", variant: "outline", onClick: () => setSortering((s) => (s === "nieuw" ? "oud" : "nieuw")), children: sortering === "nieuw" ? "Nieuwste eerst" : "Oudste eerst" }), _jsxs("span", { className: "ml-auto text-xs text-muted-foreground", children: [gefilterd.length, " orders"] })] })] }), _jsxs(CardContent, { className: "space-y-3", children: [error && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2", children: [_jsx("p", { className: "text-sm text-destructive", children: error }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void refresh(), disabled: loading, children: [_jsx(RefreshCw, { className: `mr-1 h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` }), "Opnieuw proberen"] })] })), loading && veiligeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : gefilterd.length === 0 ? (error ? null : _jsx("p", { className: "text-sm text-muted-foreground", children: "Geen orders gevonden." })) : (_jsx("div", { className: "max-h-[420px] overflow-y-auto rounded-md border border-border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "sticky top-0 bg-muted/60 text-xs text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Order" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Klant" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Bron" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Levering" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Stand" }), _jsx("th", { className: "px-2 py-1.5 text-right font-medium", children: "Versies" }), _jsx("th", { className: "px-2 py-1.5 text-right font-medium", children: "Fouten" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Laatste activiteit" })] }) }), _jsx("tbody", { children: gefilterd.map((r) => {
153
153
  const st = orderStand(r);
154
154
  const actief = r.orderNumber === orderRef;
155
155
  return (_jsxs("tr", { className: `cursor-pointer border-t border-border hover:bg-muted/40 ${actief ? "bg-primary/10" : ""}`, onClick: () => kies(r.orderNumber), children: [_jsx("td", { className: "px-2 py-1.5 font-medium", children: _jsxs("span", { className: "inline-flex items-center gap-1", children: [actief ? _jsx(ChevronDown, { className: "h-3.5 w-3.5" }) : _jsx(ChevronRight, { className: "h-3.5 w-3.5" }), r.orderNumber] }) }), _jsx("td", { className: "max-w-[180px] truncate px-2 py-1.5", children: r.customerName ?? "—" }), _jsx("td", { className: "px-2 py-1.5", children: r.orderSource === "floriday" ? "Floriday" : r.orderSource ? "Eigen verkoop" : "—" }), _jsx("td", { className: "px-2 py-1.5", children: r.deliveryDate ?? "—" }), _jsxs("td", { className: "px-2 py-1.5", children: [_jsx(Badge, { variant: st.kleur, children: st.label }), r.reasonCode && st.kleur === "destructive" && (_jsx("span", { className: "ml-1 text-xs text-muted-foreground", children: redenTekst(r.reasonCode) }))] }), _jsx("td", { className: "px-2 py-1.5 text-right tabular-nums", children: r.versions }), _jsx("td", { className: `px-2 py-1.5 text-right tabular-nums ${r.errors > 0 ? "text-destructive" : ""}`, children: r.errors }), _jsx("td", { className: "px-2 py-1.5 text-xs text-muted-foreground", children: tijd(r.lastAt ?? r.createdAt) })] }, r.orderNumber));
@@ -0,0 +1,2 @@
1
+ export declare function MisluktVerzendbrievenCard(): import("react").JSX.Element;
2
+ //# sourceMappingURL=MisluktVerzendbrievenCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MisluktVerzendbrievenCard.d.ts","sourceRoot":"","sources":["../../src/components/MisluktVerzendbrievenCard.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,yBAAyB,gCAqExC"}
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/MisluktVerzendbrievenCard.tsx — mislukte Floriday-verzendbrieven
4
+ // bij een pakbon, met per regel "Opnieuw proberen". Opnieuw scannen is niet nodig.
5
+ // ============================================================================
6
+ import { useCallback, useEffect, useState } from "react";
7
+ import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle } from "@flowselections/core";
8
+ import { RefreshCw } from "lucide-react";
9
+ import { toast } from "sonner";
10
+ import { supabase } from "../integrations/supabase/moduleClient.js";
11
+ export function MisluktVerzendbrievenCard() {
12
+ const [regels, setRegels] = useState([]);
13
+ const [fout, setFout] = useState(null);
14
+ const [bezig, setBezig] = useState(null);
15
+ const laad = useCallback(async () => {
16
+ const { data, error } = await supabase
17
+ .from("logistics_slip_shipping_note")
18
+ .select("id, order_number, error, error_code, updated_at")
19
+ .eq("status", "mislukt")
20
+ .order("updated_at", { ascending: false })
21
+ .limit(25);
22
+ if (error) {
23
+ setFout(error.message);
24
+ return;
25
+ }
26
+ setFout(null);
27
+ setRegels(Array.isArray(data) ? data : []);
28
+ }, []);
29
+ useEffect(() => {
30
+ void laad();
31
+ }, [laad]);
32
+ const opnieuw = async (id) => {
33
+ setBezig(id);
34
+ try {
35
+ const { data, error } = await supabase.rpc("logistics_slip_note_retry", { _id: id });
36
+ const res = (data ?? {});
37
+ if (error || !res.ok) {
38
+ toast.error(error?.message ?? res.error ?? "Opnieuw proberen is niet gelukt.");
39
+ }
40
+ else {
41
+ toast.success("De verzendbrief wordt opnieuw aangevraagd.");
42
+ }
43
+ await laad();
44
+ }
45
+ finally {
46
+ setBezig(null);
47
+ }
48
+ };
49
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Mislukte verzendbrieven" }), _jsx(CardDescription, { children: "Floriday-verzendbrieven bij een pakbon die niet geprint konden worden. Los de oorzaak op en druk op \"Opnieuw proberen\"; de kar hoeft niet opnieuw gescand te worden." })] }), _jsxs(CardContent, { className: "space-y-2", children: [fout && _jsx("p", { className: "text-sm text-destructive", children: fout }), !fout && regels.length === 0 && (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen mislukte verzendbrieven." })), regels.map((r) => (_jsxs("div", { className: "flex items-start justify-between gap-3 border-b border-border py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-sm font-medium", children: r.order_number ?? "Onbekende order" }), _jsx("p", { className: "text-xs text-muted-foreground break-words", children: r.error ?? r.error_code ?? "Onbekende fout" })] }), _jsxs(Button, { size: "sm", variant: "outline", disabled: bezig === r.id, onClick: () => void opnieuw(r.id), children: [_jsx(RefreshCw, { className: "mr-1 h-3 w-3" }), "Opnieuw proberen"] })] }, r.id)))] })] }));
50
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"RegiePage.d.ts","sourceRoot":"","sources":["../../src/components/RegiePage.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,SAAS,gCA0FxB"}
1
+ {"version":3,"file":"RegiePage.d.ts","sourceRoot":"","sources":["../../src/components/RegiePage.tsx"],"names":[],"mappings":"AAgCA,wBAAgB,SAAS,gCA2FxB"}
@@ -13,6 +13,7 @@ import { Link } from "@tanstack/react-router";
13
13
  import { ConsistentieCard } from "./ConsistentieCard";
14
14
  import { KarplanStatusCard } from "./KarplanStatusCard";
15
15
  import { KardekkingCard } from "./KardekkingCard";
16
+ import { MisluktVerzendbrievenCard } from "./MisluktVerzendbrievenCard";
16
17
  import { PlannerDiffCard } from "./PlannerDiffCard";
17
18
  import { BeladingsafwijkingenCard } from "./BeladingsafwijkingenCard";
18
19
  import { OrderLogboek } from "./OrderLogboek";
@@ -34,5 +35,5 @@ export function RegiePage() {
34
35
  useEffect(() => {
35
36
  void laden();
36
37
  }, [laden]);
37
- return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs("h1", { className: "flex items-center gap-2 text-2xl font-semibold tracking-tight", children: [_jsx(Workflow, { className: "h-6 w-6 text-primary" }), "Overzicht & meldingen"] }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Wat er vandaag klaarstaat en waar aandacht voor nodig is." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/logistiek-engine", children: "Terug naar overzicht" }) }), _jsxs(Button, { variant: "outline", onClick: () => void laden(), disabled: loading, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Vernieuwen"] })] })] }), _jsx(InklapbaarVenster, { titel: "Binnengekomen orders", omschrijving: "Klik een order open voor elke stap, beslissing, foutmelding en elk document.", standaardOpen: true, children: _jsx(OrderLogboek, { titel: "Binnengekomen orders" }) }), _jsx(InklapbaarVenster, { titel: "Consistentie", omschrijving: "Controle of alle modules hetzelfde tonen.", children: _jsx(ConsistentieCard, {}) }), _jsx(InklapbaarVenster, { titel: "Beladingsafwijkingen", omschrijving: "Verschillen tussen onze belading en de laatste Floriday-gegevens.", children: _jsx(BeladingsafwijkingenCard, {}) }), _jsx(InklapbaarVenster, { titel: "Karplanstatus", omschrijving: "Stand van de karrenindeling.", children: _jsx(KarplanStatusCard, {}) }), _jsx(InklapbaarVenster, { titel: "Kardekking", omschrijving: "Staat elke bestelregel correct op een kar?", children: _jsx(KardekkingCard, {}) }), _jsx(InklapbaarVenster, { titel: "Vergelijkende planner", omschrijving: "Proefvergelijking: blijft de karindeling gelijk?", children: _jsx(PlannerDiffCard, {}) }), _jsxs(InklapbaarVenster, { titel: "Taken per module", omschrijving: "Openstaande en geplande taken.", children: [telFout && _jsxs("p", { className: "mb-2 text-sm text-destructive", children: ["Telling niet beschikbaar: ", telFout] }), _jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: Object.keys(LOGISTICS_MODULES).map((key) => (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsx(CardDescription, { children: LOGISTICS_MODULES[key] }), _jsx(CardTitle, { className: "text-2xl", children: perModule[key] ?? 0 })] }), _jsx(CardContent, { className: "text-muted-foreground text-xs", children: "openstaande en geplande taken" })] }, key))) })] })] }));
38
+ return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs("h1", { className: "flex items-center gap-2 text-2xl font-semibold tracking-tight", children: [_jsx(Workflow, { className: "h-6 w-6 text-primary" }), "Overzicht & meldingen"] }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Wat er vandaag klaarstaat en waar aandacht voor nodig is." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", asChild: true, children: _jsx(Link, { to: "/logistiek-engine", children: "Terug naar overzicht" }) }), _jsxs(Button, { variant: "outline", onClick: () => void laden(), disabled: loading, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Vernieuwen"] })] })] }), _jsx(InklapbaarVenster, { titel: "Binnengekomen orders", omschrijving: "Klik een order open voor elke stap, beslissing, foutmelding en elk document.", standaardOpen: true, children: _jsx(OrderLogboek, { titel: "Binnengekomen orders" }) }), _jsx(InklapbaarVenster, { titel: "Consistentie", omschrijving: "Controle of alle modules hetzelfde tonen.", children: _jsx(ConsistentieCard, {}) }), _jsx(InklapbaarVenster, { titel: "Beladingsafwijkingen", omschrijving: "Verschillen tussen onze belading en de laatste Floriday-gegevens.", children: _jsx(BeladingsafwijkingenCard, {}) }), _jsx(InklapbaarVenster, { titel: "Karplanstatus", omschrijving: "Stand van de karrenindeling.", children: _jsx(KarplanStatusCard, {}) }), _jsxs(InklapbaarVenster, { titel: "Kardekking", omschrijving: "Staat elke bestelregel correct op een kar?", children: [_jsx(KardekkingCard, {}), _jsx(MisluktVerzendbrievenCard, {})] }), _jsx(InklapbaarVenster, { titel: "Vergelijkende planner", omschrijving: "Proefvergelijking: blijft de karindeling gelijk?", children: _jsx(PlannerDiffCard, {}) }), _jsxs(InklapbaarVenster, { titel: "Taken per module", omschrijving: "Openstaande en geplande taken.", children: [telFout && _jsxs("p", { className: "mb-2 text-sm text-destructive", children: ["Telling niet beschikbaar: ", telFout] }), _jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: Object.keys(LOGISTICS_MODULES).map((key) => (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsx(CardDescription, { children: LOGISTICS_MODULES[key] }), _jsx(CardTitle, { className: "text-2xl", children: perModule[key] ?? 0 })] }), _jsx(CardContent, { className: "text-muted-foreground text-xs", children: "openstaande en geplande taken" })] }, key))) })] })] }));
38
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"RuleEnginePage.d.ts","sourceRoot":"","sources":["../../src/components/RuleEnginePage.tsx"],"names":[],"mappings":"AAmEA,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAQD,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EAAE,cAAqB,EACjC,YAAY,EAAE,gBAAuB,GACtC,GAAE,mBAAwB,+BA2b1B"}
1
+ {"version":3,"file":"RuleEnginePage.d.ts","sourceRoot":"","sources":["../../src/components/RuleEnginePage.tsx"],"names":[],"mappings":"AAmEA,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAQD,wBAAgB,cAAc,CAAC,EAC7B,UAAU,EAAE,cAAqB,EACjC,YAAY,EAAE,gBAAuB,GACtC,GAAE,mBAAwB,+BA+b1B"}
@@ -121,7 +121,9 @@ export function RuleEnginePage({ strategyId: strategyIdProp = null, strategyName
121
121
  ? "Bezig…"
122
122
  : "Opslaan & opnieuw berekenen"] })] })] }), error && (_jsx("p", { className: "rounded-md border border-destructive/50 bg-destructive/5 px-3 py-2 text-sm text-destructive", children: "De gegevens konden niet worden geladen. Probeer het opnieuw." })), showJobLine && (_jsxs("div", { className: `rounded-md border px-3 py-2 text-sm ${job?.status === "error" ? "border-destructive/50 bg-destructive/5 text-destructive" : "border-border"}`, children: [_jsx("span", { children: running
123
123
  ? `${phaseLabel(job?.phase)} — ${job?.processed ?? 0} verwerkt`
124
- : "De laatste berekening is niet volledig gelukt." }), 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
124
+ : `De laatste volledige herberekening${job?.finished_at
125
+ ? ` (${new Date(job.finished_at).toLocaleString("nl-NL", { dateStyle: "medium", timeStyle: "short" })})`
126
+ : ""} 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
125
127
  ? "lg:grid-cols-[220px_minmax(0,1fr)_320px]"
126
128
  : "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
127
129
  ? "border-primary bg-primary/5"
@@ -9,6 +9,8 @@ export interface ShippingNoteStatus {
9
9
  cartId: string | null;
10
10
  orderNumber: string | null;
11
11
  }
12
+ /** Zet een nog wachtende status om naar een expliciete fout na de pollimiet. */
13
+ export declare function timedOutStatus(current: ShippingNoteStatus, maxPollMs: number): ShippingNoteStatus;
12
14
  /**
13
15
  * Zet de verzendbriefverwerking direct aan het werk zodra de pakbon naar het
14
16
  * pickstation is gestuurd, zodat niet op de volgende ronde hoeft te worden
@@ -1 +1 @@
1
- {"version":3,"file":"useShippingNoteStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/useShippingNoteStatus.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,sBAAsB,GAC9B,kBAAkB,GAClB,mBAAmB,GACnB,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AA+BD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAe3D;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO;;;;EAqD1E"}
1
+ {"version":3,"file":"useShippingNoteStatus.d.ts","sourceRoot":"","sources":["../../src/hooks/useShippingNoteStatus.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,sBAAsB,GAC9B,kBAAkB,GAClB,mBAAmB,GACnB,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAID,gFAAgF;AAChF,wBAAgB,cAAc,CAC5B,OAAO,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,GAChB,kBAAkB,CAOpB;AA6BD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAe3D;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO;;;;EAyD1E"}
@@ -5,6 +5,15 @@
5
5
  import { useCallback, useEffect, useState } from "react";
6
6
  import { supabase } from "@flowselections/core";
7
7
  const WAITING = new Set(["klaar_voor_print", "wacht_op_floriday"]);
8
+ /** Zet een nog wachtende status om naar een expliciete fout na de pollimiet. */
9
+ export function timedOutStatus(current, maxPollMs) {
10
+ const minuten = Math.round(maxPollMs / 60000);
11
+ return {
12
+ ...current,
13
+ status: "mislukt",
14
+ message: `Verzendbriefstatus kon niet worden bepaald na ${minuten} minuten. Controleer de printwachtrij.`,
15
+ };
16
+ }
8
17
  function safeStatus(value) {
9
18
  if (!value || typeof value !== "object")
10
19
  return null;
@@ -98,8 +107,11 @@ export function useShippingNoteStatus(slipJobId, cartId, options = {}) {
98
107
  useEffect(() => {
99
108
  if (!data || !WAITING.has(data.status) || startedAt === null)
100
109
  return;
101
- if (Date.now() - startedAt >= maxPollMs)
110
+ if (Date.now() - startedAt >= maxPollMs) {
111
+ // Nooit stil stoppen: zonder eindstatus na de limiet expliciet een fout tonen.
112
+ setData(timedOutStatus(data, maxPollMs));
102
113
  return;
114
+ }
103
115
  const timer = window.setTimeout(() => void reload(), pollMs);
104
116
  return () => window.clearTimeout(timer);
105
117
  }, [data, maxPollMs, pollMs, reload, startedAt]);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=useShippingNoteStatus.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useShippingNoteStatus.test.d.ts","sourceRoot":"","sources":["../../src/hooks/useShippingNoteStatus.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { timedOutStatus } from "./useShippingNoteStatus";
3
+ describe("timedOutStatus", () => {
4
+ it("maakt van een wachtende status na de limiet een expliciete fout", () => {
5
+ const wachtend = {
6
+ status: "klaar_voor_print",
7
+ message: "Verzendbrief wordt klaargezet.",
8
+ attempts: 0,
9
+ nextAttemptAt: null,
10
+ slipJobId: "s",
11
+ shippingNoteJobId: null,
12
+ cartId: "c",
13
+ orderNumber: "HO-1",
14
+ };
15
+ const uit = timedOutStatus(wachtend, 15 * 60000);
16
+ expect(uit.status).toBe("mislukt");
17
+ expect(uit.message).toContain("15 minuten");
18
+ expect(uit.slipJobId).toBe("s");
19
+ });
20
+ });