@flowselections/logistiek-engine 1.0.28 → 1.0.29

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 (34) hide show
  1. package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts +2 -0
  2. package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -0
  3. package/dist-lib/components/GeblokkeerdeOrdersCard.js +44 -0
  4. package/dist-lib/components/RegiePage.d.ts.map +1 -1
  5. package/dist-lib/components/RegiePage.js +2 -1
  6. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +28 -0
  7. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -0
  8. package/dist-lib/hooks/useGeblokkeerdeOrders.js +94 -0
  9. package/dist-lib/index.d.ts +1 -0
  10. package/dist-lib/index.d.ts.map +1 -1
  11. package/dist-lib/index.js +1 -0
  12. package/dist-lib/integrations/supabase/auth-middleware.d.ts +52 -0
  13. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  14. package/dist-lib/integrations/supabase/client.server.d.ts +52 -0
  15. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  16. package/dist-lib/integrations/supabase/moduleClient.d.ts +52 -0
  17. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  18. package/dist-lib/integrations/supabase/types.d.ts +52 -0
  19. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  20. package/dist-lib/lib/floridayDocuments.functions.d.ts +156 -0
  21. package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
  22. package/dist-lib/lib/floridayPush.functions.d.ts +52 -0
  23. package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
  24. package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
  25. package/dist-lib/lib/handlers/logistics-tick.server.js +7 -0
  26. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +260 -0
  27. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
  28. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  29. package/dist-lib/lib/loadCarrierPlanning.server.js +23 -3
  30. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +104 -0
  31. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
  32. package/dist-lib/lib/logisticsRecalculate.functions.d.ts +52 -0
  33. package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
  34. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ export declare function GeblokkeerdeOrdersCard(): import("react").JSX.Element;
2
+ //# sourceMappingURL=GeblokkeerdeOrdersCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GeblokkeerdeOrdersCard.d.ts","sourceRoot":"","sources":["../../src/components/GeblokkeerdeOrdersCard.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,sBAAsB,gCAsIrC"}
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ // ============================================================================
3
+ // src/components/GeblokkeerdeOrdersCard.tsx — orders die vastlopen
4
+ // ============================================================================
5
+ // Een blokkade is een zichtbare eindtoestand: de order blijft staan tot er
6
+ // iets aan de order verandert of iemand hier op opnieuw proberen klikt.
7
+ // Alles komt uit de Engine-functies; hier wordt niets zelf berekend.
8
+ // GEEN <Header /> hier — die levert de shell.
9
+ // ============================================================================
10
+ import { useMemo, useState } from "react";
11
+ import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, } from "@flowselections/core";
12
+ import { AlertTriangle, RefreshCw, RotateCcw } from "lucide-react";
13
+ import { useGeblokkeerdeOrders, redenLabel } from "../hooks/useGeblokkeerdeOrders";
14
+ function datum(waarde) {
15
+ if (!waarde)
16
+ return "—";
17
+ const d = new Date(waarde);
18
+ return Number.isNaN(d.getTime()) ? "—" : d.toLocaleDateString("nl-NL");
19
+ }
20
+ export function GeblokkeerdeOrdersCard() {
21
+ const { rows, overzicht, loading, error, busy, refresh, retry } = useGeblokkeerdeOrders();
22
+ const [filter, setFilter] = useState("");
23
+ const [melding, setMelding] = useState(null);
24
+ const safeRows = Array.isArray(rows) ? rows : [];
25
+ const codes = useMemo(() => {
26
+ const set = new Map();
27
+ for (const r of safeRows)
28
+ set.set(r.reasonCode, (set.get(r.reasonCode) ?? 0) + 1);
29
+ return Array.from(set.entries()).sort((a, b) => b[1] - a[1]);
30
+ }, [safeRows]);
31
+ const zichtbaar = filter ? safeRows.filter((r) => r.reasonCode === filter) : safeRows;
32
+ const opnieuw = async (ids) => {
33
+ try {
34
+ const n = await retry(ids);
35
+ setMelding(n === 0
36
+ ? "Er is niets opnieuw aangeboden."
37
+ : `${n} order(s) opnieuw aangeboden. Ze verdwijnen zodra de verwerking ze heeft opgepakt.`);
38
+ }
39
+ catch (e) {
40
+ setMelding(e?.message ? String(e.message) : "Opnieuw proberen is niet gelukt.");
41
+ }
42
+ };
43
+ 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 }))] }), _jsx(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw([r.orderId]), children: "Opnieuw" })] }, r.queueId))) })] }))] })] }));
44
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"RegiePage.d.ts","sourceRoot":"","sources":["../../src/components/RegiePage.tsx"],"names":[],"mappings":"AA4EA,wBAAgB,SAAS,gCAiYxB"}
1
+ {"version":3,"file":"RegiePage.d.ts","sourceRoot":"","sources":["../../src/components/RegiePage.tsx"],"names":[],"mappings":"AA6EA,wBAAgB,SAAS,gCAmYxB"}
@@ -19,6 +19,7 @@ import { FloridayPushCard } from "./FloridayPushCard";
19
19
  import { PrintjobsCard } from "./PrintjobsCard";
20
20
  import { ConsistentieCard } from "./ConsistentieCard";
21
21
  import { KarplanStatusCard } from "./KarplanStatusCard";
22
+ import { GeblokkeerdeOrdersCard } from "./GeblokkeerdeOrdersCard";
22
23
  import { AfmetingenBronnenCard } from "./AfmetingenBronnenCard";
23
24
  import { LOGISTICS_MODULES, TASK_LABEL, TASK_STATUS_LABEL, } from "../lib/logisticsTasks";
24
25
  function tijd(value) {
@@ -76,7 +77,7 @@ export function RegiePage() {
76
77
  }
77
78
  return counts;
78
79
  }, [safeTaken]);
79
- 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(ConsistentieCard, {}), _jsx(KarplanStatusCard, {}), _jsx(AfmetingenBronnenCard, {}), _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))) }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Taken per order" }), _jsx(CardDescription, { children: "Elke order krijgt bij binnenkomst meteen de volledige keten aan taken toegewezen." }), _jsxs("div", { className: "pt-2", children: [_jsx(Label, { htmlFor: "regie-filter", className: "sr-only", children: "Zoeken" }), _jsx(Input, { id: "regie-filter", placeholder: "Zoek op ordernummer, taaktype of module\u2026", value: filter, onChange: (e) => setFilter(e.target.value), className: "max-w-sm" })] })] }), _jsx(CardContent, { className: "space-y-6", children: loading ? (_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" })] })) : perOrder.length === 0 ? (_jsxs("p", { className: "text-muted-foreground py-8 text-center text-sm", children: ["Nog geen taken. Zodra een module een melding wegschrijft in", " ", _jsx("code", { className: "bg-muted rounded px-1", children: "logistics_events" }), " maakt de database de keten meteen aan."] })) : (perOrder.map(([orderRef, orderTaken]) => {
80
+ 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(ConsistentieCard, {}), _jsx(KarplanStatusCard, {}), _jsx(GeblokkeerdeOrdersCard, {}), _jsx(AfmetingenBronnenCard, {}), _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))) }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Taken per order" }), _jsx(CardDescription, { children: "Elke order krijgt bij binnenkomst meteen de volledige keten aan taken toegewezen." }), _jsxs("div", { className: "pt-2", children: [_jsx(Label, { htmlFor: "regie-filter", className: "sr-only", children: "Zoeken" }), _jsx(Input, { id: "regie-filter", placeholder: "Zoek op ordernummer, taaktype of module\u2026", value: filter, onChange: (e) => setFilter(e.target.value), className: "max-w-sm" })] })] }), _jsx(CardContent, { className: "space-y-6", children: loading ? (_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" })] })) : perOrder.length === 0 ? (_jsxs("p", { className: "text-muted-foreground py-8 text-center text-sm", children: ["Nog geen taken. Zodra een module een melding wegschrijft in", " ", _jsx("code", { className: "bg-muted rounded px-1", children: "logistics_events" }), " maakt de database de keten meteen aan."] })) : (perOrder.map(([orderRef, orderTaken]) => {
80
81
  const spoed = orderTaken.some((t) => (t.priority ?? 0) > 0);
81
82
  const actief = orderTaken.some((t) => t.status !== "cancelled" && t.status !== "done" && t.status !== "superseded");
82
83
  return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("h2", { className: "flex items-center gap-2 font-medium", children: ["Order ", orderRef, _jsxs("span", { className: "text-muted-foreground text-xs font-normal", children: [orderTaken.length, " taken"] }), spoed && (_jsx(Badge, { variant: "destructive", className: "text-[10px]", children: "spoed" }))] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => void zetPrioriteit(orderRef, spoed ? 0 : 100), children: [_jsx(ArrowUpCircle, { className: "mr-1 h-4 w-4" }), spoed ? "Normaal" : "Spoed"] }), actief && (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => void annuleerOrder(orderRef), children: [_jsx(Ban, { className: "mr-1 h-4 w-4" }), "Annuleren"] })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void verwijderOrder(orderRef), children: _jsx(Trash2, { className: "h-4 w-4" }) })] })] }), _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-12", children: "#" }), _jsx(TableHead, { children: "Taak" }), _jsx(TableHead, { children: "Module" }), _jsx(TableHead, { children: "Start" }), _jsx(TableHead, { children: "Gereed" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { className: "text-right", children: "Actie" })] }) }), _jsx(TableBody, { children: orderTaken.map((t) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "text-muted-foreground", children: t.sequence + 1 }), _jsxs(TableCell, { className: "font-medium", children: [TASK_LABEL[t.task_type] ?? t.task_type, t.shadow && (_jsx(Badge, { variant: "outline", className: "ml-2 text-[10px]", children: "schaduw" }))] }), _jsx(TableCell, { className: "text-sm", children: LOGISTICS_MODULES[t.owner_module] ?? t.owner_module }), _jsxs(TableCell, { className: "text-sm", children: [tijd(t.planned_start), t.payload?.["pickWindowShifted"] === true && (_jsx(Badge, { variant: "outline", className: "ml-2 text-[10px]", title: "Het berekende moment lag in het verleden; deze taak is naar nu verschoven.", children: "te laat aangemeld" }))] }), _jsx(TableCell, { className: "text-sm", children: tijd(t.planned_end) }), _jsxs(TableCell, { children: [_jsx(Badge, { variant: statusVariant(t.status), children: TASK_STATUS_LABEL[t.status] ?? t.status }), t.claimed_by && (t.status === "claimed" || t.status === "in_progress") && (_jsxs("span", { className: "text-muted-foreground ml-2 text-xs", children: ["door ", t.claimed_by] })), t.error && _jsx("span", { className: "text-destructive ml-2 text-xs", children: t.error })] }), _jsxs(TableCell, { className: "space-x-1 text-right", children: [t.status === "planned" && (_jsx(Button, { variant: "outline", size: "sm", onClick: () => void claimTaak(t.id), children: "Claimen" })), (t.status === "claimed" || t.status === "in_progress") && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "outline", size: "sm", onClick: () => void rondTaakAf(t.id), children: "Afronden" }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void meldTaakMislukt(t.id, "Handmatig gemeld vanuit regieoverzicht"), children: "Mislukt" })] }))] })] }, t.id))) })] })] }, orderRef));
@@ -0,0 +1,28 @@
1
+ export interface GeblokkeerdeOrder {
2
+ queueId: string;
3
+ orderId: string;
4
+ orderRef: string;
5
+ deliveryDate: string | null;
6
+ reason: string | null;
7
+ reasonCode: string;
8
+ attempts: number;
9
+ blockedSince: string | null;
10
+ }
11
+ export interface BlokkadeOverzicht {
12
+ blocked: number;
13
+ pending: number;
14
+ lastTickAt: string | null;
15
+ tickStale: boolean;
16
+ }
17
+ export declare const REDEN_LABEL: Record<string, string>;
18
+ export declare function redenLabel(code: string | null | undefined): string;
19
+ export declare function useGeblokkeerdeOrders(): {
20
+ rows: GeblokkeerdeOrder[];
21
+ overzicht: BlokkadeOverzicht | null;
22
+ loading: boolean;
23
+ error: string | null;
24
+ busy: boolean;
25
+ refresh: () => Promise<void>;
26
+ retry: (orderIds: string[]) => Promise<number>;
27
+ };
28
+ //# sourceMappingURL=useGeblokkeerdeOrders.d.ts.map
@@ -0,0 +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,CAY9C,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,UAGzD;AAED,wBAAgB,qBAAqB;;;;;;;sBAqDhB,MAAM,EAAE;EAmB5B"}
@@ -0,0 +1,94 @@
1
+ // ============================================================================
2
+ // src/hooks/useGeblokkeerdeOrders.ts — geblokkeerde orders ophalen en opnieuw
3
+ // aanbieden. De Engine is de enige bron: alles komt uit de database-functies
4
+ // logistics_blocked_orders / logistics_blocked_overview / logistics_plan_retry.
5
+ // ============================================================================
6
+ import { useCallback, useEffect, useState } from "react";
7
+ import { supabase } from "../integrations/supabase/moduleClient";
8
+ export const REDEN_LABEL = {
9
+ belading_onbekend: "Belading onbekend",
10
+ belading_onvolledig: "Belading onvolledig",
11
+ beladingsprofiel_ontbreekt: "Beladingsprofiel ontbreekt",
12
+ afmetingen_onbekend: "Afmetingen onbekend",
13
+ afmetingen_plan_ongeldig: "Afmetingenplan ongeldig",
14
+ kargrens_overschreden: "Te veel karren",
15
+ geen_karren: "Geen karren berekend",
16
+ verificatie_mislukt: "Controle mislukt",
17
+ bufferdekking_onvolledig: "Buffer niet volledig gedekt",
18
+ karindeling_geblokkeerd: "Karindeling geblokkeerd",
19
+ other: "Overige reden",
20
+ };
21
+ export function redenLabel(code) {
22
+ if (!code)
23
+ return REDEN_LABEL.other;
24
+ return REDEN_LABEL[code] ?? code;
25
+ }
26
+ export function useGeblokkeerdeOrders() {
27
+ const [rows, setRows] = useState([]);
28
+ const [overzicht, setOverzicht] = useState(null);
29
+ const [loading, setLoading] = useState(true);
30
+ const [error, setError] = useState(null);
31
+ const [busy, setBusy] = useState(false);
32
+ const load = useCallback(async () => {
33
+ setLoading(true);
34
+ setError(null);
35
+ try {
36
+ const [list, summary] = await Promise.all([
37
+ supabase.rpc("logistics_blocked_orders"),
38
+ supabase.rpc("logistics_blocked_overview"),
39
+ ]);
40
+ if (list.error)
41
+ throw new Error(list.error.message);
42
+ if (summary.error)
43
+ throw new Error(summary.error.message);
44
+ const safe = Array.isArray(list.data) ? list.data : [];
45
+ setRows(safe.map((r) => ({
46
+ queueId: String(r.queue_id),
47
+ orderId: String(r.order_id),
48
+ orderRef: String(r.order_ref ?? r.order_id),
49
+ deliveryDate: r.delivery_date ?? null,
50
+ reason: r.reason ?? null,
51
+ reasonCode: String(r.reason_code ?? "other"),
52
+ attempts: Number(r.attempts ?? 0),
53
+ blockedSince: r.blocked_since ?? null,
54
+ })));
55
+ const o = (summary.data ?? {});
56
+ setOverzicht({
57
+ blocked: Number(o.blocked ?? 0),
58
+ pending: Number(o.pending ?? 0),
59
+ lastTickAt: o.lastTickAt ?? null,
60
+ tickStale: Boolean(o.tickStale ?? true),
61
+ });
62
+ }
63
+ catch (e) {
64
+ setError(e?.message ? String(e.message) : "Kon de geblokkeerde orders niet ophalen.");
65
+ }
66
+ finally {
67
+ setLoading(false);
68
+ }
69
+ }, []);
70
+ useEffect(() => {
71
+ void load();
72
+ const timer = setInterval(() => void load(), 30000);
73
+ return () => clearInterval(timer);
74
+ }, [load]);
75
+ const retry = useCallback(async (orderIds) => {
76
+ const ids = Array.isArray(orderIds) ? orderIds.filter(Boolean) : [];
77
+ if (ids.length === 0)
78
+ return 0;
79
+ setBusy(true);
80
+ try {
81
+ const { data, error: rpcError } = await supabase.rpc("logistics_plan_retry", {
82
+ p_order_ids: ids,
83
+ });
84
+ if (rpcError)
85
+ throw new Error(rpcError.message);
86
+ await load();
87
+ return Number(data ?? 0);
88
+ }
89
+ finally {
90
+ setBusy(false);
91
+ }
92
+ }, [load]);
93
+ return { rows, overzicht, loading, error, busy, refresh: load, retry };
94
+ }
@@ -11,6 +11,7 @@ export { FloridayPushCard } from './components/FloridayPushCard';
11
11
  export { PrintjobsCard } from './components/PrintjobsCard';
12
12
  export { ConsistentieCard } from './components/ConsistentieCard';
13
13
  export { KarplanStatusCard } from './components/KarplanStatusCard';
14
+ export { GeblokkeerdeOrdersCard } from './components/GeblokkeerdeOrdersCard';
14
15
  export { AfmetingenBronnenCard } from './components/AfmetingenBronnenCard';
15
16
  export * from './hooks/usePrintjobs';
16
17
  export * from './components/VertragingMeldingenCard';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,cAAc,sBAAsB,CAAC;AAErC,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAGrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AAChG,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qCAAqC,CAAC;AAMpD,eAAO,MAAM,qBAAqB,EAAE,UAcnC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,cAAc,kBAAkB,CAAC;AACjC,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,cAAc,sBAAsB,CAAC;AAErC,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAGrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AAChG,cAAc,iCAAiC,CAAC;AAChD,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qCAAqC,CAAC;AAMpD,eAAO,MAAM,qBAAqB,EAAE,UAcnC,CAAC"}
package/dist-lib/index.js CHANGED
@@ -14,6 +14,7 @@ export { FloridayPushCard } from './components/FloridayPushCard';
14
14
  export { PrintjobsCard } from './components/PrintjobsCard';
15
15
  export { ConsistentieCard } from './components/ConsistentieCard';
16
16
  export { KarplanStatusCard } from './components/KarplanStatusCard';
17
+ export { GeblokkeerdeOrdersCard } from './components/GeblokkeerdeOrdersCard';
17
18
  export { AfmetingenBronnenCard } from './components/AfmetingenBronnenCard';
18
19
  export * from './hooks/usePrintjobs';
19
20
  export * from './components/VertragingMeldingenCard';
@@ -10236,6 +10236,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
10236
10236
  next_attempt_at: string;
10237
10237
  order_id: string;
10238
10238
  reason: string;
10239
+ reason_code: string | null;
10239
10240
  status: string;
10240
10241
  updated_at: string;
10241
10242
  };
@@ -10248,6 +10249,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
10248
10249
  next_attempt_at?: string;
10249
10250
  order_id: string;
10250
10251
  reason?: string;
10252
+ reason_code?: string | null;
10251
10253
  status?: string;
10252
10254
  updated_at?: string;
10253
10255
  };
@@ -10260,6 +10262,7 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
10260
10262
  next_attempt_at?: string;
10261
10263
  order_id?: string;
10262
10264
  reason?: string;
10265
+ reason_code?: string | null;
10263
10266
  status?: string;
10264
10267
  updated_at?: string;
10265
10268
  };
@@ -10964,6 +10967,21 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
10964
10967
  referencedColumns: ["id"];
10965
10968
  }];
10966
10969
  };
10970
+ logistics_tick_heartbeat: {
10971
+ Row: {
10972
+ id: boolean;
10973
+ last_tick_at: string;
10974
+ };
10975
+ Insert: {
10976
+ id?: boolean;
10977
+ last_tick_at?: string;
10978
+ };
10979
+ Update: {
10980
+ id?: boolean;
10981
+ last_tick_at?: string;
10982
+ };
10983
+ Relationships: [];
10984
+ };
10967
10985
  logistics_variables: {
10968
10986
  Row: {
10969
10987
  created_at: string;
@@ -22846,6 +22864,30 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
22846
22864
  };
22847
22865
  Returns: import("./types").Json;
22848
22866
  };
22867
+ logistics_block_reason_code: {
22868
+ Args: {
22869
+ p_details?: import("./types").Json;
22870
+ p_reason: string;
22871
+ };
22872
+ Returns: string;
22873
+ };
22874
+ logistics_blocked_orders: {
22875
+ Args: never;
22876
+ Returns: {
22877
+ attempts: number;
22878
+ blocked_since: string;
22879
+ delivery_date: string;
22880
+ order_id: string;
22881
+ order_ref: string;
22882
+ queue_id: string;
22883
+ reason: string;
22884
+ reason_code: string;
22885
+ }[];
22886
+ };
22887
+ logistics_blocked_overview: {
22888
+ Args: never;
22889
+ Returns: import("./types").Json;
22890
+ };
22849
22891
  logistics_buffer_criteria: {
22850
22892
  Args: {
22851
22893
  p_settings: import("./types").Json;
@@ -23715,6 +23757,12 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
23715
23757
  Args: never;
23716
23758
  Returns: number;
23717
23759
  };
23760
+ logistics_plan_retry: {
23761
+ Args: {
23762
+ p_order_ids: string[];
23763
+ };
23764
+ Returns: number;
23765
+ };
23718
23766
  logistics_plan_setting: {
23719
23767
  Args: {
23720
23768
  p_default: number;
@@ -23950,6 +23998,10 @@ export declare const requireSupabaseAuth: import("@tanstack/start-client-core").
23950
23998
  };
23951
23999
  Returns: number;
23952
24000
  };
24001
+ logistics_tick_ping: {
24002
+ Args: never;
24003
+ Returns: string;
24004
+ };
23953
24005
  logistics_upsert_task: {
23954
24006
  Args: {
23955
24007
  p_buffer_ref: string;