@flowselections/logistiek-engine 1.0.34 → 1.0.89
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.
- package/dist-lib/components/AfrondWachtrijCard.d.ts +2 -0
- package/dist-lib/components/AfrondWachtrijCard.d.ts.map +1 -0
- package/dist-lib/components/AfrondWachtrijCard.js +27 -0
- package/dist-lib/components/BeladingsafwijkingenCard.d.ts +2 -0
- package/dist-lib/components/BeladingsafwijkingenCard.d.ts.map +1 -0
- package/dist-lib/components/BeladingsafwijkingenCard.js +44 -0
- package/dist-lib/components/FlowCanvas.d.ts +34 -0
- package/dist-lib/components/FlowCanvas.d.ts.map +1 -0
- package/dist-lib/components/FlowCanvas.js +490 -0
- package/dist-lib/components/FlowOrders.d.ts +8 -0
- package/dist-lib/components/FlowOrders.d.ts.map +1 -0
- package/dist-lib/components/FlowOrders.js +171 -0
- package/dist-lib/components/FlowPage.d.ts +2 -0
- package/dist-lib/components/FlowPage.d.ts.map +1 -0
- package/dist-lib/components/FlowPage.js +310 -0
- package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
- package/dist-lib/components/GeblokkeerdeOrdersCard.js +21 -2
- package/dist-lib/components/InklapbaarVenster.d.ts +9 -0
- package/dist-lib/components/InklapbaarVenster.d.ts.map +1 -0
- package/dist-lib/components/InklapbaarVenster.js +10 -0
- package/dist-lib/components/KardekkingCard.d.ts +2 -0
- package/dist-lib/components/KardekkingCard.d.ts.map +1 -0
- package/dist-lib/components/KardekkingCard.js +29 -0
- package/dist-lib/components/LogistiekEnginePage.d.ts.map +1 -1
- package/dist-lib/components/LogistiekEnginePage.js +15 -3
- package/dist-lib/components/LogistiekEngineQueuePage.d.ts +2 -0
- package/dist-lib/components/LogistiekEngineQueuePage.d.ts.map +1 -0
- package/dist-lib/components/LogistiekEngineQueuePage.js +13 -0
- package/dist-lib/components/NodeTracePanel.d.ts +14 -0
- package/dist-lib/components/NodeTracePanel.d.ts.map +1 -0
- package/dist-lib/components/NodeTracePanel.js +46 -0
- package/dist-lib/components/OrderJourneyBar.d.ts +9 -0
- package/dist-lib/components/OrderJourneyBar.d.ts.map +1 -0
- package/dist-lib/components/OrderJourneyBar.js +26 -0
- package/dist-lib/components/OrderLogboek.d.ts +10 -0
- package/dist-lib/components/OrderLogboek.d.ts.map +1 -0
- package/dist-lib/components/OrderLogboek.js +92 -0
- package/dist-lib/components/OrderStopBanner.d.ts +12 -0
- package/dist-lib/components/OrderStopBanner.d.ts.map +1 -0
- package/dist-lib/components/OrderStopBanner.js +36 -0
- package/dist-lib/components/OrderTraceDetails.d.ts +22 -0
- package/dist-lib/components/OrderTraceDetails.d.ts.map +1 -0
- package/dist-lib/components/OrderTraceDetails.js +88 -0
- package/dist-lib/components/PlanWachtrijPage.d.ts +2 -0
- package/dist-lib/components/PlanWachtrijPage.d.ts.map +1 -0
- package/dist-lib/components/PlanWachtrijPage.js +99 -0
- package/dist-lib/components/PlannerDiffCard.d.ts +2 -0
- package/dist-lib/components/PlannerDiffCard.d.ts.map +1 -0
- package/dist-lib/components/PlannerDiffCard.js +25 -0
- package/dist-lib/components/RegiePage.d.ts.map +1 -1
- package/dist-lib/components/RegiePage.js +28 -78
- package/dist-lib/components/TaakGezondheidCard.d.ts +2 -0
- package/dist-lib/components/TaakGezondheidCard.d.ts.map +1 -0
- package/dist-lib/components/TaakGezondheidCard.js +31 -0
- package/dist-lib/components/WerktijdenCard.d.ts +2 -0
- package/dist-lib/components/WerktijdenCard.d.ts.map +1 -0
- package/dist-lib/components/WerktijdenCard.js +37 -0
- package/dist-lib/components/WerkwijzeHerindelingCard.d.ts.map +1 -1
- package/dist-lib/components/WerkwijzeHerindelingCard.js +100 -6
- package/dist-lib/hooks/useAfrondWachtrij.d.ts +28 -0
- package/dist-lib/hooks/useAfrondWachtrij.d.ts.map +1 -0
- package/dist-lib/hooks/useAfrondWachtrij.js +88 -0
- package/dist-lib/hooks/useBeladingsafwijkingen.d.ts +39 -0
- package/dist-lib/hooks/useBeladingsafwijkingen.d.ts.map +1 -0
- package/dist-lib/hooks/useBeladingsafwijkingen.js +119 -0
- package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +7 -0
- package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
- package/dist-lib/hooks/useGeblokkeerdeOrders.js +28 -2
- package/dist-lib/hooks/useLogisticsTrace.d.ts +78 -0
- package/dist-lib/hooks/useLogisticsTrace.d.ts.map +1 -0
- package/dist-lib/hooks/useLogisticsTrace.js +152 -0
- package/dist-lib/hooks/useOrderNodeTrace.d.ts +11 -0
- package/dist-lib/hooks/useOrderNodeTrace.d.ts.map +1 -0
- package/dist-lib/hooks/useOrderNodeTrace.js +26 -0
- package/dist-lib/hooks/useOrderTrace.d.ts +74 -0
- package/dist-lib/hooks/useOrderTrace.d.ts.map +1 -0
- package/dist-lib/hooks/useOrderTrace.js +134 -0
- package/dist-lib/hooks/useOrderVersies.d.ts +47 -0
- package/dist-lib/hooks/useOrderVersies.d.ts.map +1 -0
- package/dist-lib/hooks/useOrderVersies.js +194 -0
- package/dist-lib/hooks/usePlanWachtrij.d.ts +33 -0
- package/dist-lib/hooks/usePlanWachtrij.d.ts.map +1 -0
- package/dist-lib/hooks/usePlanWachtrij.js +104 -0
- package/dist-lib/hooks/useRecalcJob.js +1 -1
- package/dist-lib/hooks/useRuleEngine.d.ts +1 -0
- package/dist-lib/hooks/useRuleEngine.d.ts.map +1 -1
- package/dist-lib/hooks/useRuleEngine.js +1 -0
- package/dist-lib/hooks/useShippingNoteDiagnose.d.ts +20 -0
- package/dist-lib/hooks/useShippingNoteDiagnose.d.ts.map +1 -0
- package/dist-lib/hooks/useShippingNoteDiagnose.js +52 -0
- package/dist-lib/hooks/useShippingNoteStatus.d.ts +29 -0
- package/dist-lib/hooks/useShippingNoteStatus.d.ts.map +1 -0
- package/dist-lib/hooks/useShippingNoteStatus.js +107 -0
- package/dist-lib/hooks/useTaakGezondheid.d.ts +16 -0
- package/dist-lib/hooks/useTaakGezondheid.d.ts.map +1 -0
- package/dist-lib/hooks/useTaakGezondheid.js +43 -0
- package/dist-lib/hooks/useWerktijden.d.ts +33 -0
- package/dist-lib/hooks/useWerktijden.d.ts.map +1 -0
- package/dist-lib/hooks/useWerktijden.js +88 -0
- package/dist-lib/hooks/useWerkwijzeStatus.d.ts +12 -1
- package/dist-lib/hooks/useWerkwijzeStatus.d.ts.map +1 -1
- package/dist-lib/hooks/useWerkwijzeStatus.js +61 -5
- package/dist-lib/index.d.ts +23 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +23 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +4993 -459
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +4993 -459
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.js +1 -1
- package/dist-lib/integrations/supabase/moduleClient.d.ts +4993 -459
- package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/previewAuthStorage.js +8 -1
- package/dist-lib/integrations/supabase/types.d.ts +5022 -432
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/attachAuthToken.js +1 -1
- package/dist-lib/lib/bufferDecision.test.d.ts +2 -0
- package/dist-lib/lib/bufferDecision.test.d.ts.map +1 -0
- package/dist-lib/lib/bufferDecision.test.js +104 -0
- package/dist-lib/lib/cartCoverage.functions.d.ts +30820 -0
- package/dist-lib/lib/cartCoverage.functions.d.ts.map +1 -0
- package/dist-lib/lib/cartCoverage.functions.js +20 -0
- package/dist-lib/lib/cartPlanRequests.server.d.ts +1 -1
- package/dist-lib/lib/cartPlanRequests.server.d.ts.map +1 -1
- package/dist-lib/lib/cartPlanRequests.server.js +49 -8
- package/dist-lib/lib/floridayDocuments.functions.d.ts +13623 -21
- package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.functions.js +5 -5
- package/dist-lib/lib/floridayDocuments.server.d.ts +14 -0
- package/dist-lib/lib/floridayDocuments.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.server.js +58 -0
- package/dist-lib/lib/floridayGuard.server.d.ts +1 -1
- package/dist-lib/lib/floridayGuard.server.d.ts.map +1 -1
- package/dist-lib/lib/floridayGuard.server.js +6 -3
- package/dist-lib/lib/floridayPush.functions.d.ts +4993 -459
- package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.functions.js +3 -3
- package/dist-lib/lib/flowGraph.d.ts +43 -0
- package/dist-lib/lib/flowGraph.d.ts.map +1 -0
- package/dist-lib/lib/flowGraph.js +153 -0
- package/dist-lib/lib/flowJourney.d.ts +40 -0
- package/dist-lib/lib/flowJourney.d.ts.map +1 -0
- package/dist-lib/lib/flowJourney.js +156 -0
- package/dist-lib/lib/flowNodes.d.ts +26 -0
- package/dist-lib/lib/flowNodes.d.ts.map +1 -0
- package/dist-lib/lib/flowNodes.js +64 -0
- package/dist-lib/lib/flowRoute.d.ts +117 -0
- package/dist-lib/lib/flowRoute.d.ts.map +1 -0
- package/dist-lib/lib/flowRoute.js +583 -0
- package/dist-lib/lib/flowTree.d.ts +149 -0
- package/dist-lib/lib/flowTree.d.ts.map +1 -0
- package/dist-lib/lib/flowTree.js +908 -0
- package/dist-lib/lib/foutTekst.d.ts +4 -0
- package/dist-lib/lib/foutTekst.d.ts.map +1 -0
- package/dist-lib/lib/foutTekst.js +43 -0
- package/dist-lib/lib/handlers/index.d.ts +1 -0
- package/dist-lib/lib/handlers/index.d.ts.map +1 -1
- package/dist-lib/lib/handlers/index.js +1 -0
- package/dist-lib/lib/handlers/logistics-shipping-note-now.server.d.ts +3 -0
- package/dist-lib/lib/handlers/logistics-shipping-note-now.server.d.ts.map +1 -0
- package/dist-lib/lib/handlers/logistics-shipping-note-now.server.js +100 -0
- package/dist-lib/lib/handlers/logistics-tick.server.d.ts +2 -0
- package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
- package/dist-lib/lib/handlers/logistics-tick.server.js +153 -2
- package/dist-lib/lib/handlers/logistics-tick.test.d.ts +2 -0
- package/dist-lib/lib/handlers/logistics-tick.test.d.ts.map +1 -0
- package/dist-lib/lib/handlers/logistics-tick.test.js +63 -0
- package/dist-lib/lib/loadCarrierPlanner.d.ts +2 -0
- package/dist-lib/lib/loadCarrierPlanner.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanner.js +18 -0
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +22705 -35
- package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.functions.js +7 -7
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts +33 -12
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +534 -228
- package/dist-lib/lib/logisticsPlanner.d.ts.map +1 -1
- package/dist-lib/lib/logisticsPlanner.js +14 -2
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +9082 -14
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.functions.js +4 -4
- package/dist-lib/lib/logisticsRecalcJob.server.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalcJob.server.js +17 -2
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts +4993 -459
- package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
- package/dist-lib/lib/logisticsRecalculate.functions.js +2 -2
- package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
- package/dist-lib/lib/modulePrompts.js +893 -0
- package/dist-lib/lib/nodeTrace.d.ts +65 -0
- package/dist-lib/lib/nodeTrace.d.ts.map +1 -0
- package/dist-lib/lib/nodeTrace.js +182 -0
- package/dist-lib/lib/pickQueueCleanup.server.d.ts +14 -0
- package/dist-lib/lib/pickQueueCleanup.server.d.ts.map +1 -0
- package/dist-lib/lib/pickQueueCleanup.server.js +80 -0
- package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/planQueue.server.js +164 -3
- package/dist-lib/lib/plannerDiff.d.ts +37 -0
- package/dist-lib/lib/plannerDiff.d.ts.map +1 -0
- package/dist-lib/lib/plannerDiff.functions.d.ts +30821 -0
- package/dist-lib/lib/plannerDiff.functions.d.ts.map +1 -0
- package/dist-lib/lib/plannerDiff.functions.js +21 -0
- package/dist-lib/lib/plannerDiff.js +74 -0
- package/dist-lib/lib/plannerDiff.server.d.ts +5 -0
- package/dist-lib/lib/plannerDiff.server.d.ts.map +1 -0
- package/dist-lib/lib/plannerDiff.server.js +60 -0
- package/dist-lib/lib/plannerDiff.test.d.ts +2 -0
- package/dist-lib/lib/plannerDiff.test.d.ts.map +1 -0
- package/dist-lib/lib/plannerDiff.test.js +41 -0
- package/dist-lib/lib/resolveBuffer.test.d.ts +2 -0
- package/dist-lib/lib/resolveBuffer.test.d.ts.map +1 -0
- package/dist-lib/lib/resolveBuffer.test.js +38 -0
- package/dist-lib/lib/ruleEngineImpact.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineImpact.js +11 -4
- package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineSchema.js +102 -6
- package/dist-lib/lib/ruleEngineWizard.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineWizard.js +3 -1
- package/dist-lib/lib/shippingNoteQueue.server.d.ts +18 -0
- package/dist-lib/lib/shippingNoteQueue.server.d.ts.map +1 -0
- package/dist-lib/lib/shippingNoteQueue.server.js +304 -0
- package/dist-lib/lib/stopReden.d.ts +43 -0
- package/dist-lib/lib/stopReden.d.ts.map +1 -0
- package/dist-lib/lib/stopReden.js +197 -0
- package/dist-lib/lib/taskCounts.d.ts +2 -0
- package/dist-lib/lib/taskCounts.d.ts.map +1 -0
- package/dist-lib/lib/taskCounts.js +15 -0
- package/dist-lib/lib/taskCounts.test.d.ts +2 -0
- package/dist-lib/lib/taskCounts.test.d.ts.map +1 -0
- package/dist-lib/lib/taskCounts.test.js +12 -0
- package/dist-lib/lib/trace.server.d.ts +75 -0
- package/dist-lib/lib/trace.server.d.ts.map +1 -0
- package/dist-lib/lib/trace.server.js +78 -0
- package/dist-lib/lib/vakUitleg.d.ts +19 -0
- package/dist-lib/lib/vakUitleg.d.ts.map +1 -0
- package/dist-lib/lib/vakUitleg.js +133 -0
- package/package.json +158 -131
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts +0 -2
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.d.ts.map +0 -1
- package/dist-lib/components/rule-engine/FloridayConnectionBanner.js +0 -41
- package/dist-lib/integrations/supabase/client.d.ts +0 -20293
- package/dist-lib/integrations/supabase/client.d.ts.map +0 -1
- package/dist-lib/integrations/supabase/client.js +0 -13
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/PlanWachtrijPage.tsx — de planwachtrij bekijken en resetten
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Laat zien welke orders wachten op een karrenindeling, hoe vaak het is
|
|
6
|
+
// geprobeerd en wat er precies misging (in gewone taal). Met knoppen om de
|
|
7
|
+
// wachtrij opnieuw te starten. GEEN <Header /> hier — die levert de shell.
|
|
8
|
+
// ============================================================================
|
|
9
|
+
import { useMemo, useState } from "react";
|
|
10
|
+
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@flowselections/core";
|
|
11
|
+
import { AlertTriangle, RefreshCw, RotateCcw } from "lucide-react";
|
|
12
|
+
import { toast } from "sonner";
|
|
13
|
+
import { usePlanWachtrij } from "../hooks/usePlanWachtrij";
|
|
14
|
+
import { foutTekst } from "../lib/foutTekst";
|
|
15
|
+
const STAND_KLEUR = {
|
|
16
|
+
wacht: "bg-amber-500/15 text-amber-700 dark:text-amber-300",
|
|
17
|
+
bezig: "bg-sky-500/15 text-sky-700 dark:text-sky-300",
|
|
18
|
+
"blijft hangen": "bg-orange-500/20 text-orange-700 dark:text-orange-300",
|
|
19
|
+
klaar: "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300",
|
|
20
|
+
mislukt: "bg-destructive/15 text-destructive",
|
|
21
|
+
geblokkeerd: "bg-destructive/15 text-destructive",
|
|
22
|
+
};
|
|
23
|
+
const FILTERS = [
|
|
24
|
+
{ id: "alles", label: "Alles" },
|
|
25
|
+
{ id: "open", label: "Open" },
|
|
26
|
+
{ id: "mislukt", label: "Mislukt of geblokkeerd" },
|
|
27
|
+
{ id: "blijft hangen", label: "Blijft hangen" },
|
|
28
|
+
{ id: "klaar", label: "Klaar" },
|
|
29
|
+
];
|
|
30
|
+
function tijd(v) {
|
|
31
|
+
if (!v)
|
|
32
|
+
return "—";
|
|
33
|
+
const d = new Date(v);
|
|
34
|
+
return Number.isNaN(d.getTime()) ? "—" : d.toLocaleString("nl-NL");
|
|
35
|
+
}
|
|
36
|
+
function klok(v) {
|
|
37
|
+
if (!v)
|
|
38
|
+
return "—";
|
|
39
|
+
const d = new Date(v);
|
|
40
|
+
return Number.isNaN(d.getTime()) ? "—" : d.toLocaleTimeString("nl-NL", { hour: "2-digit", minute: "2-digit" });
|
|
41
|
+
}
|
|
42
|
+
function past(regel, filter, zoek) {
|
|
43
|
+
const z = zoek.trim().toLowerCase();
|
|
44
|
+
if (z && !`${regel.orderNumber ?? ""} ${regel.klant ?? ""}`.toLowerCase().includes(z))
|
|
45
|
+
return false;
|
|
46
|
+
if (filter === "alles")
|
|
47
|
+
return true;
|
|
48
|
+
if (filter === "open")
|
|
49
|
+
return regel.stand === "wacht" || regel.stand === "bezig";
|
|
50
|
+
if (filter === "mislukt")
|
|
51
|
+
return regel.stand === "mislukt" || regel.stand === "geblokkeerd";
|
|
52
|
+
return regel.stand === filter;
|
|
53
|
+
}
|
|
54
|
+
export function PlanWachtrijPage() {
|
|
55
|
+
const { regels, loading, busy, error, refresh, reset, opnieuw } = usePlanWachtrij();
|
|
56
|
+
const [filter, setFilter] = useState("alles");
|
|
57
|
+
const [zoek, setZoek] = useState("");
|
|
58
|
+
const [nieuwsteEerst, setNieuwsteEerst] = useState(true);
|
|
59
|
+
const veilig = Array.isArray(regels) ? regels : [];
|
|
60
|
+
const zichtbaar = useMemo(() => {
|
|
61
|
+
const lijst = veilig.filter((r) => past(r, filter, zoek));
|
|
62
|
+
const stempel = (r) => {
|
|
63
|
+
// Volgorde volgt de order zelf: wanneer de bestelling is binnengekomen.
|
|
64
|
+
const d = new Date(r.orderGemaaktOp ?? r.aangemeldOp ?? r.bijgewerktOp ?? 0).getTime();
|
|
65
|
+
return Number.isNaN(d) ? 0 : d;
|
|
66
|
+
};
|
|
67
|
+
return [...lijst].sort((a, b) => (nieuwsteEerst ? stempel(b) - stempel(a) : stempel(a) - stempel(b)));
|
|
68
|
+
}, [veilig, filter, zoek, nieuwsteEerst]);
|
|
69
|
+
const tellingen = useMemo(() => {
|
|
70
|
+
const t = {};
|
|
71
|
+
for (const r of veilig)
|
|
72
|
+
t[r.stand] = (t[r.stand] ?? 0) + 1;
|
|
73
|
+
return t;
|
|
74
|
+
}, [veilig]);
|
|
75
|
+
async function doeReset(keuze, vraag) {
|
|
76
|
+
if (!window.confirm(vraag))
|
|
77
|
+
return;
|
|
78
|
+
try {
|
|
79
|
+
const n = await reset(keuze);
|
|
80
|
+
toast.success(`${n} order(s) opnieuw aangemeld voor indeling.`);
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
toast.error(e?.message ? String(e.message) : "Opnieuw starten is niet gelukt.");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
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))) })] }))] })] }) }));
|
|
99
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlannerDiffCard.d.ts","sourceRoot":"","sources":["../../src/components/PlannerDiffCard.tsx"],"names":[],"mappings":"AAWA,wBAAgB,eAAe,gCA0D9B"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
4
|
+
import { Badge, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@flowselections/core";
|
|
5
|
+
import { getPlannerDiffOverview } from "../lib/plannerDiff.functions";
|
|
6
|
+
const MODUS = {
|
|
7
|
+
off: "Uit (wissen en opnieuw opbouwen)",
|
|
8
|
+
dry_run: "Proef (oude aanpak leidend, vergelijking ernaast)",
|
|
9
|
+
apply: "Actief (alleen verschillen aanpassen)",
|
|
10
|
+
};
|
|
11
|
+
export function PlannerDiffCard() {
|
|
12
|
+
const fetchOverview = useServerFn(getPlannerDiffOverview);
|
|
13
|
+
const { data, isLoading, error } = useQuery({ queryKey: ["planner-diff"], queryFn: () => fetchOverview() });
|
|
14
|
+
if (isLoading)
|
|
15
|
+
return _jsx(Skeleton, { className: "h-24 w-full" });
|
|
16
|
+
if (error || !data)
|
|
17
|
+
return _jsx("p", { className: "text-sm text-destructive", children: "Kon de vergelijking niet ophalen." });
|
|
18
|
+
const afwijkingen = Array.isArray(data.afwijkingen) ? data.afwijkingen : [];
|
|
19
|
+
return (_jsxs("div", { className: "space-y-3", children: [_jsxs("p", { className: "text-sm", children: ["Modus: ", _jsx("span", { className: "font-medium", children: MODUS[data.modus] ?? MODUS["off"] })] }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Badge, { variant: "secondary", children: ["Buffers vergeleken: ", data.totaal] }), _jsxs(Badge, { variant: "secondary", children: ["Identiek: ", data.identiek] }), _jsxs(Badge, { variant: data.afwijkend > 0 ? "destructive" : "secondary", children: ["Afwijkend: ", data.afwijkend] }), data.mislukt > 0 && _jsxs(Badge, { variant: "destructive", children: ["Mislukt: ", data.mislukt] }), data.overgeslagen > 0 && _jsxs(Badge, { variant: "outline", children: ["Overgeslagen (indeling geblokkeerd): ", data.overgeslagen] })] }), afwijkingen.length > 0 && (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Order" }), _jsx(TableHead, { children: "Karren oud \u2192 nieuw" }), _jsx(TableHead, { children: "Verschil" }), _jsx(TableHead, { children: "Moment" })] }) }), _jsx(TableBody, { children: afwijkingen.map((r) => {
|
|
20
|
+
const diffs = Array.isArray(r.differences) ? r.differences : [];
|
|
21
|
+
return (_jsxs(TableRow, { children: [_jsx(TableCell, { children: r.order_ref ?? "—" }), _jsxs(TableCell, { children: [r.carts_before ?? "?", " \u2192 ", r.carts_after ?? "?"] }), _jsxs(TableCell, { className: "max-w-md text-xs", children: [diffs.slice(0, 3).map((d, i) => (_jsx("div", { children: d?.fout
|
|
22
|
+
? `Fout: ${d.fout}`
|
|
23
|
+
: `Kar ${d?.cartNumber ?? "?"}: ${d?.before ?? "leeg"} → ${d?.after ?? "leeg"}` }, i))), diffs.length > 3 && _jsxs("div", { children: ["\u2026 en ", diffs.length - 3, " meer"] })] }), _jsx(TableCell, { className: "text-xs", children: new Date(r.created_at).toLocaleString("nl-NL") })] }, r.id));
|
|
24
|
+
}) })] }))] }));
|
|
25
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RegiePage.d.ts","sourceRoot":"","sources":["../../src/components/RegiePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RegiePage.d.ts","sourceRoot":"","sources":["../../src/components/RegiePage.tsx"],"names":[],"mappings":"AA+BA,wBAAgB,SAAS,gCA0FxB"}
|
|
@@ -1,88 +1,38 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// ============================================================================
|
|
3
3
|
// src/components/RegiePage.tsx — Regieoverzicht van de Logistics Engine
|
|
4
4
|
// ============================================================================
|
|
5
|
-
// Toont
|
|
6
|
-
//
|
|
5
|
+
// Toont hoeveel taken er per module openstaan en daaronder alle binnengekomen
|
|
6
|
+
// orders met het volledige logboek per order.
|
|
7
7
|
// GEEN <Header /> hier — die levert de shell.
|
|
8
8
|
// ============================================================================
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { useCallback, useEffect, useState } from "react";
|
|
10
|
+
import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, supabase, } from "@flowselections/core";
|
|
11
|
+
import { RefreshCw, Workflow } from "lucide-react";
|
|
12
12
|
import { Link } from "@tanstack/react-router";
|
|
13
|
-
import { useLogistiekTaken } from "../hooks/useLogistiekTaken";
|
|
14
|
-
import { BeladingIndelingCard } from "./BeladingIndelingCard";
|
|
15
|
-
import { VoorraadMeldingenCard } from "./VoorraadMeldingenCard";
|
|
16
|
-
import { VertragingMeldingenCard } from "./VertragingMeldingenCard";
|
|
17
|
-
import { CapaciteitMeldingenCard } from "./CapaciteitMeldingenCard";
|
|
18
|
-
import { FloridayPushCard } from "./FloridayPushCard";
|
|
19
|
-
import { PrintjobsCard } from "./PrintjobsCard";
|
|
20
13
|
import { ConsistentieCard } from "./ConsistentieCard";
|
|
21
14
|
import { KarplanStatusCard } from "./KarplanStatusCard";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (Number.isNaN(d.getTime()))
|
|
30
|
-
return "—";
|
|
31
|
-
return d.toLocaleString("nl-NL", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" });
|
|
32
|
-
}
|
|
33
|
-
function statusVariant(status) {
|
|
34
|
-
if (status === "done")
|
|
35
|
-
return "default";
|
|
36
|
-
if (status === "failed" || status === "cancelled")
|
|
37
|
-
return "destructive";
|
|
38
|
-
if (status === "in_progress" || status === "claimed")
|
|
39
|
-
return "secondary";
|
|
40
|
-
return "outline";
|
|
41
|
-
}
|
|
42
|
-
const WAARSCHUWING_LABEL = {
|
|
43
|
-
pick_start_in_past: "Pickstart lag in het verleden",
|
|
44
|
-
pick_window_too_short: "Pickvenster te kort",
|
|
45
|
-
pickup_in_past: "Ophaalmoment verstreken",
|
|
46
|
-
buffer_close_in_past: "Buffer sloot al",
|
|
47
|
-
rule_version_not_found: "Regelversie niet gevonden",
|
|
48
|
-
no_rule_config: "Geen regelset gekoppeld",
|
|
49
|
-
};
|
|
15
|
+
import { KardekkingCard } from "./KardekkingCard";
|
|
16
|
+
import { PlannerDiffCard } from "./PlannerDiffCard";
|
|
17
|
+
import { BeladingsafwijkingenCard } from "./BeladingsafwijkingenCard";
|
|
18
|
+
import { OrderLogboek } from "./OrderLogboek";
|
|
19
|
+
import { InklapbaarVenster } from "./InklapbaarVenster";
|
|
20
|
+
import { tellOpenTaken } from "../lib/taskCounts";
|
|
21
|
+
import { LOGISTICS_MODULES } from "../lib/logisticsTasks";
|
|
50
22
|
export function RegiePage() {
|
|
51
|
-
|
|
52
|
-
const [
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
for (const t of gefilterd) {
|
|
67
|
-
const list = map.get(t.order_ref) ?? [];
|
|
68
|
-
list.push(t);
|
|
69
|
-
map.set(t.order_ref, list);
|
|
70
|
-
}
|
|
71
|
-
return Array.from(map.entries());
|
|
72
|
-
}, [gefilterd]);
|
|
73
|
-
const perModule = useMemo(() => {
|
|
74
|
-
const counts = {};
|
|
75
|
-
for (const t of safeTaken) {
|
|
76
|
-
counts[t.owner_module] = (counts[t.owner_module] ?? 0) + 1;
|
|
77
|
-
}
|
|
78
|
-
return counts;
|
|
79
|
-
}, [safeTaken]);
|
|
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]) => {
|
|
81
|
-
const spoed = orderTaken.some((t) => (t.priority ?? 0) > 0);
|
|
82
|
-
const actief = orderTaken.some((t) => t.status !== "cancelled" && t.status !== "done" && t.status !== "superseded");
|
|
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));
|
|
84
|
-
})) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Planrondes" }), _jsx(CardDescription, { children: "Elke keer dat de Engine (her)plande, met welke regelversie." })] }), _jsx(CardContent, { children: safeRuns.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Nog geen planrondes." })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Moment" }), _jsx(TableHead, { children: "Order" }), _jsx(TableHead, { children: "Aanleiding" }), _jsx(TableHead, { children: "Bron" }), _jsx(TableHead, { children: "Regelversie" }), _jsx(TableHead, { children: "Taken" }), _jsx(TableHead, { children: "Signalen" })] }) }), _jsx(TableBody, { children: safeRuns.map((r) => {
|
|
85
|
-
const warnings = Array.isArray(r.warnings) ? r.warnings : [];
|
|
86
|
-
return (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "text-sm", children: tijd(r.created_at) }), _jsx(TableCell, { className: "font-medium", children: r.order_ref }), _jsx(TableCell, { className: "text-sm", children: r.trigger }), _jsx(TableCell, { className: "text-sm", children: r.source_module ?? "—" }), _jsxs(TableCell, { className: "text-sm", children: [r.rule_version ?? "—", r.settings_hash ? (_jsx("span", { className: "text-muted-foreground ml-1 font-mono text-xs", children: r.settings_hash.slice(0, 6) })) : null] }), _jsxs(TableCell, { className: "text-sm", children: [r.tasks_created, " nieuw / ", r.tasks_revised, " herzien"] }), _jsx(TableCell, { className: "text-sm", children: warnings.length === 0 ? (_jsx("span", { className: "text-muted-foreground", children: "\u2014" })) : (_jsx("div", { className: "flex flex-wrap gap-1", children: warnings.map((w, i) => (_jsx(Badge, { variant: "outline", children: WAARSCHUWING_LABEL[String(w.code)] ?? String(w.code) }, i))) })) })] }, r.id));
|
|
87
|
-
}) })] })) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Binnengekomen orders" }), _jsx(CardDescription, { children: "Elke binnengekomen order wordt automatisch omgezet naar de bijbehorende werkzaamheden." })] }), _jsx(CardContent, { children: safeMeldingen.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Nog geen meldingen ontvangen." })) : (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Moment" }), _jsx(TableHead, { children: "Onderdeel" }), _jsx(TableHead, { children: "Soort" }), _jsx(TableHead, { children: "Order" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { className: "w-24" })] }) }), _jsx(TableBody, { children: safeMeldingen.map((m) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "text-sm", children: tijd(m.created_at) }), _jsx(TableCell, { className: "text-sm", children: LOGISTICS_MODULES[m.source_module] ?? m.source_module }), _jsx(TableCell, { className: "text-sm", children: m.event_type }), _jsx(TableCell, { className: "font-medium", children: m.order_ref }), _jsxs(TableCell, { children: [_jsx(Badge, { variant: m.status === "failed" ? "destructive" : m.status === "processed" ? "default" : "outline", children: m.status === "processed" ? "Verwerkt" : m.status === "failed" ? "Mislukt" : "Wachtend" }), m.error && _jsx("p", { className: "text-destructive mt-1 text-xs", children: m.error })] }), _jsx(TableCell, { className: "text-right", children: m.status !== "processed" && (_jsxs(Button, { variant: "ghost", size: "sm", onClick: () => void herverwerkMelding(m.id), children: [_jsx(RotateCcw, { className: "mr-1 h-4 w-4" }), "Opnieuw"] })) })] }, m.id))) })] })) })] }), _jsx(FloridayPushCard, {}), _jsx(PrintjobsCard, {}), _jsx(VoorraadMeldingenCard, {}), _jsx(VertragingMeldingenCard, {}), _jsx(CapaciteitMeldingenCard, {}), _jsx(BeladingIndelingCard, {})] }));
|
|
23
|
+
// Alleen open en geplande taken, geteld in de database (geen 500-grens, geen geannuleerde).
|
|
24
|
+
const [perModule, setPerModule] = useState({});
|
|
25
|
+
const [loading, setLoading] = useState(true);
|
|
26
|
+
const [telFout, setTelFout] = useState(null);
|
|
27
|
+
const laden = useCallback(async () => {
|
|
28
|
+
setLoading(true);
|
|
29
|
+
const { data, error } = await supabase.rpc("logistics_task_open_counts");
|
|
30
|
+
setTelFout(error ? error.message : null);
|
|
31
|
+
setPerModule(error ? {} : tellOpenTaken(data));
|
|
32
|
+
setLoading(false);
|
|
33
|
+
}, []);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
void laden();
|
|
36
|
+
}, [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))) })] })] }));
|
|
88
38
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TaakGezondheidCard.d.ts","sourceRoot":"","sources":["../../src/components/TaakGezondheidCard.tsx"],"names":[],"mappings":"AAoBA,wBAAgB,kBAAkB,gCA6DjC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/TaakGezondheidCard.tsx — draaien de achtergrondtaken nog?
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Toont per achtergrondtaak van de engine wanneer hij voor het laatst draaide
|
|
6
|
+
// en of hij mislukt. Alleen lezen.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
import { AlertTriangle, CheckCircle2, RefreshCw } from "lucide-react";
|
|
9
|
+
import { useTaakGezondheid } from "../hooks/useTaakGezondheid";
|
|
10
|
+
function geleden(tijd) {
|
|
11
|
+
if (!tijd)
|
|
12
|
+
return "nooit gedraaid";
|
|
13
|
+
const ms = Date.now() - new Date(tijd).getTime();
|
|
14
|
+
if (!Number.isFinite(ms))
|
|
15
|
+
return "onbekend";
|
|
16
|
+
const min = Math.round(ms / 60000);
|
|
17
|
+
if (min < 1)
|
|
18
|
+
return "zojuist";
|
|
19
|
+
if (min < 60)
|
|
20
|
+
return `${min} min geleden`;
|
|
21
|
+
return `${Math.round(min / 6) / 10} uur geleden`;
|
|
22
|
+
}
|
|
23
|
+
export function TaakGezondheidCard() {
|
|
24
|
+
const { taken, laden, fout, herlaad } = useTaakGezondheid();
|
|
25
|
+
const veilig = Array.isArray(taken) ? taken : [];
|
|
26
|
+
const problemen = veilig.filter((t) => !t.actief || t.mislukt24u > 0 || t.laatsteStatus === "failed");
|
|
27
|
+
return (_jsxs("div", { className: "rounded-lg border bg-card p-4 text-card-foreground", children: [_jsxs("div", { className: "mb-3 flex items-center justify-between gap-2", children: [_jsxs("div", { children: [_jsx("h3", { className: "font-semibold", children: "Achtergrondtaken" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Indelen, taken uitvoeren, afronden en opruimen draaien automatisch." })] }), _jsx("button", { type: "button", onClick: () => void herlaad(), className: "rounded-md border px-3 py-1.5 text-sm hover:bg-accent", "aria-label": "Vernieuwen", children: _jsx(RefreshCw, { className: "h-4 w-4" }) })] }), fout ? _jsx("p", { className: "mb-3 text-sm text-destructive", children: fout }) : null, !laden && problemen.length === 0 && veilig.length > 0 ? (_jsxs("p", { className: "mb-3 flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), " Alle taken draaien zonder fouten."] })) : null, _jsx("ul", { className: "space-y-2", children: veilig.map((t) => {
|
|
28
|
+
const slecht = !t.actief || t.mislukt24u > 0 || t.laatsteStatus === "failed";
|
|
29
|
+
return (_jsxs("li", { className: "rounded-md border p-3 text-sm", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "font-medium", children: t.naam }), _jsx("span", { className: slecht ? "text-destructive" : "text-muted-foreground", children: geleden(t.laatsteStart) })] }), _jsxs("p", { className: "text-muted-foreground", children: [t.actief ? "actief" : "uitgezet", " \u00B7 ", t.schema, t.mislukt24u > 0 ? ` · ${t.mislukt24u} keer mislukt in 24 uur` : ""] }), slecht && t.laatsteBericht ? (_jsxs("p", { className: "mt-1 flex items-start gap-2 text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), t.laatsteBericht] })) : null] }, t.naam));
|
|
30
|
+
}) })] }));
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WerktijdenCard.d.ts","sourceRoot":"","sources":["../../src/components/WerktijdenCard.tsx"],"names":[],"mappings":"AA0BA,wBAAgB,cAAc,gCAwN7B"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/WerktijdenCard.tsx — openingstijden voor het terugrekenen
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// De Engine rekent de benodigde picktijd terug in werkuren. Deze kaart toont en
|
|
6
|
+
// beheert de vensters per weekdag, afwijkende dagen en de tijdzone. Ontbreken
|
|
7
|
+
// die gegevens, dan rekent de Engine niets uit — er wordt niets geraden.
|
|
8
|
+
// GEEN <Header /> hier — die levert de shell.
|
|
9
|
+
// ============================================================================
|
|
10
|
+
import { useState } from "react";
|
|
11
|
+
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Skeleton, } from "@flowselections/core";
|
|
12
|
+
import { Clock, Plus, RefreshCw, Trash2 } from "lucide-react";
|
|
13
|
+
import { useWerktijden } from "../hooks/useWerktijden";
|
|
14
|
+
const DAGEN = ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"];
|
|
15
|
+
export function WerktijdenCard() {
|
|
16
|
+
const { status, loading, error, refresh, zetTijdzone, voegVensterToe, verwijderVenster, voegUitzonderingToe, verwijderUitzondering, } = useWerktijden();
|
|
17
|
+
const [tz, setTz] = useState("");
|
|
18
|
+
const [dag, setDag] = useState("1");
|
|
19
|
+
const [van, setVan] = useState("07:00");
|
|
20
|
+
const [tot, setTot] = useState("17:00");
|
|
21
|
+
const [datum, setDatum] = useState("");
|
|
22
|
+
const [melding, setMelding] = useState(null);
|
|
23
|
+
const vensters = status?.windows ?? [];
|
|
24
|
+
const uitzonderingen = status?.exceptions ?? [];
|
|
25
|
+
const doe = async (fn, ok) => {
|
|
26
|
+
try {
|
|
27
|
+
await fn();
|
|
28
|
+
setMelding(ok);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
setMelding(e?.message ? String(e.message) : "Opslaan is niet gelukt.");
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
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(Clock, { className: "h-4 w-4" }), "Werktijden voor het picken"] }), _jsx(CardDescription, { children: "De starttijd van een pickopdracht wordt teruggerekend in werkuren, niet in klokuren. Alleen tijd binnen deze vensters telt mee." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => void refresh(), disabled: loading, children: [_jsx(RefreshCw, { className: "h-4 w-4" }), "Verversen"] })] }), _jsx(CardContent, { className: "space-y-4", children: loading ? (_jsx(Skeleton, { className: "h-24 w-full" })) : error ? (_jsx("p", { className: "text-sm text-destructive", children: error })) : (_jsxs(_Fragment, { children: [!status?.usable ? (_jsx("p", { className: "text-sm text-destructive", children: "Er zijn nog geen werktijden ingesteld. Zolang die ontbreken, bepaalt de Engine geen starttijd voor het picken en komt er niets vrij op het pickscherm." })) : null, _jsx("div", { className: "flex flex-wrap items-end gap-2", children: _jsxs("div", { children: [_jsx("p", { className: "text-xs text-muted-foreground", children: "Tijdzone van de vestiging" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: tz || status?.timezone || "", placeholder: "bijv. Europe/Amsterdam", onChange: (e) => setTz(e.target.value), className: "w-56" }), _jsx(Button, { size: "sm", onClick: () => void doe(() => zetTijdzone((tz || status?.timezone || "").trim()), "Tijdzone opgeslagen."), children: "Opslaan" })] })] }) }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: "Openingstijden per dag" }), vensters.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen openingstijden ingesteld." })) : (_jsx("ul", { className: "space-y-1", children: vensters.map((v) => (_jsxs("li", { className: "flex items-center gap-2 text-sm", children: [_jsx(Badge, { variant: "outline", children: DAGEN[v.weekday] ?? v.weekday }), _jsxs("span", { children: [String(v.opens).slice(0, 5), " \u2013 ", String(v.closes).slice(0, 5)] }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void doe(() => verwijderVenster(v.id), "Venster verwijderd."), children: _jsx(Trash2, { className: "h-4 w-4" }) })] }, v.id))) })), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("select", { value: dag, onChange: (e) => setDag(e.target.value), className: "h-9 rounded-md border bg-background px-2 text-sm", children: DAGEN.map((d, i) => (_jsx("option", { value: String(i), children: d }, d))) }), _jsx(Input, { type: "time", value: van, onChange: (e) => setVan(e.target.value), className: "w-32" }), _jsx(Input, { type: "time", value: tot, onChange: (e) => setTot(e.target.value), className: "w-32" }), _jsxs(Button, { size: "sm", onClick: () => void doe(() => voegVensterToe(Number(dag), van, tot), "Openingstijd toegevoegd."), children: [_jsx(Plus, { className: "h-4 w-4" }), "Toevoegen"] })] }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Meerdere vensters op \u00E9\u00E9n dag mag; zo blijft bijvoorbeeld een pauze buiten de picktijd. Een dag zonder venster is een niet-werkdag." })] }), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: "Afwijkende dagen" }), uitzonderingen.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen afwijkende dagen ingesteld." })) : (_jsx("ul", { className: "space-y-1", children: uitzonderingen.map((u) => (_jsxs("li", { className: "flex items-center gap-2 text-sm", children: [_jsx(Badge, { variant: "outline", children: u.day }), _jsx("span", { children: u.closed
|
|
35
|
+
? "gesloten"
|
|
36
|
+
: `${String(u.opens ?? "").slice(0, 5)} – ${String(u.closes ?? "").slice(0, 5)}` }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void doe(() => verwijderUitzondering(u.id), "Afwijkende dag verwijderd."), children: _jsx(Trash2, { className: "h-4 w-4" }) })] }, u.id))) })), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Input, { type: "date", value: datum, onChange: (e) => setDatum(e.target.value), className: "w-44" }), _jsx(Button, { variant: "outline", size: "sm", disabled: !datum, onClick: () => void doe(() => voegUitzonderingToe(datum, true, null, null, null), "Dag als gesloten gezet."), children: "Gesloten" }), _jsxs(Button, { size: "sm", disabled: !datum, onClick: () => void doe(() => voegUitzonderingToe(datum, false, van, tot, null), "Afwijkende openingstijd toegevoegd."), children: ["Afwijkend ", van, "\u2013", tot] })] }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Een afwijkende dag gaat altijd boven de vaste weekinstelling." })] }), melding ? _jsx("p", { className: "text-sm", children: melding }) : null] })) })] }));
|
|
37
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WerkwijzeHerindelingCard.d.ts","sourceRoot":"","sources":["../../src/components/WerkwijzeHerindelingCard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"WerkwijzeHerindelingCard.d.ts","sourceRoot":"","sources":["../../src/components/WerkwijzeHerindelingCard.tsx"],"names":[],"mappings":"AAoCA,wBAAgB,wBAAwB,gCA+RvC"}
|
|
@@ -7,30 +7,124 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
7
7
|
// Engine-functies; hier wordt niets zelf berekend.
|
|
8
8
|
// GEEN <Header /> hier — die levert de shell.
|
|
9
9
|
// ============================================================================
|
|
10
|
-
import { useState } from "react";
|
|
11
|
-
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, } from "@flowselections/core";
|
|
12
|
-
import { RefreshCw, RotateCcw, Ruler, Boxes } from "lucide-react";
|
|
10
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, } from "@flowselections/core";
|
|
12
|
+
import { RefreshCw, RotateCcw, Ruler, Boxes, AlertTriangle } from "lucide-react";
|
|
13
13
|
import { useWerkwijzeStatus } from "../hooks/useWerkwijzeStatus";
|
|
14
14
|
const METHODE_LABEL = {
|
|
15
15
|
belading: "Indelen op basis van belading",
|
|
16
16
|
afmetingen: "Indelen op basis van afmetingen",
|
|
17
17
|
};
|
|
18
18
|
export function WerkwijzeHerindelingCard() {
|
|
19
|
-
const { status, loading, busy, error, refresh, herindelen } = useWerkwijzeStatus();
|
|
19
|
+
const { status, loading, busy, error, refresh, refreshQuiet, herindelen, alsnogAllesHerindelen, pakbonnenGereedmaken, } = useWerkwijzeStatus();
|
|
20
20
|
const [melding, setMelding] = useState(null);
|
|
21
|
+
const [totaal, setTotaal] = useState(0);
|
|
22
|
+
const [bevestigOpen, setBevestigOpen] = useState(false);
|
|
23
|
+
const [pakbonnen, setPakbonnen] = useState(null);
|
|
24
|
+
const [pakbonBezig, setPakbonBezig] = useState(false);
|
|
25
|
+
const quietRef = useRef(refreshQuiet);
|
|
26
|
+
quietRef.current = refreshQuiet;
|
|
27
|
+
const pakbonRef = useRef(pakbonnenGereedmaken);
|
|
28
|
+
pakbonRef.current = pakbonnenGereedmaken;
|
|
29
|
+
const draaitRef = useRef(false);
|
|
21
30
|
const wachtrij = status?.wachtrij ?? {};
|
|
22
31
|
const pending = Number(wachtrij["pending"] ?? 0);
|
|
32
|
+
const running = Number(wachtrij["running"] ?? 0);
|
|
23
33
|
const blocked = Number(wachtrij["geblokkeerd"] ?? 0);
|
|
34
|
+
const openWerk = pending + running;
|
|
35
|
+
const bezigMetIndelen = totaal > 0 && openWerk > 0;
|
|
36
|
+
const gereed = totaal > 0 ? Math.max(0, Math.min(totaal, totaal - openWerk)) : 0;
|
|
37
|
+
const percentage = totaal > 0 ? Math.round((gereed / totaal) * 100) : 0;
|
|
38
|
+
const pakbonPercentage = pakbonnen && pakbonnen.totaal > 0
|
|
39
|
+
? Math.round((pakbonnen.gereed / pakbonnen.totaal) * 100)
|
|
40
|
+
: 0;
|
|
41
|
+
// Pakbongegevens klaarzetten; herhaald aanroepen is veilig en idempotent.
|
|
42
|
+
const pakbonRonde = useCallback(async () => {
|
|
43
|
+
if (draaitRef.current)
|
|
44
|
+
return;
|
|
45
|
+
draaitRef.current = true;
|
|
46
|
+
setPakbonBezig(true);
|
|
47
|
+
try {
|
|
48
|
+
setPakbonnen(await pakbonRef.current());
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Een mislukte ronde blokkeert de herindeling niet; volgende ronde probeert opnieuw.
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
draaitRef.current = false;
|
|
55
|
+
setPakbonBezig(false);
|
|
56
|
+
}
|
|
57
|
+
}, []);
|
|
58
|
+
// Zolang er nog orders in de wachtrij staan, de stand stil bijwerken en
|
|
59
|
+
// ondertussen de pakbonnen van die orders alvast printklaar maken.
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const nogPakbonnenOpen = (pakbonnen?.open ?? 0) > 0;
|
|
62
|
+
if (!bezigMetIndelen && !nogPakbonnenOpen)
|
|
63
|
+
return;
|
|
64
|
+
const t = setInterval(() => {
|
|
65
|
+
void quietRef.current();
|
|
66
|
+
void pakbonRonde();
|
|
67
|
+
}, 3000);
|
|
68
|
+
return () => clearInterval(t);
|
|
69
|
+
}, [bezigMetIndelen, pakbonnen?.open, pakbonRonde]);
|
|
70
|
+
// De balk verdwijnt vanzelf zodra alles klaar is, zodat hij nooit blijft staan.
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (totaal === 0)
|
|
73
|
+
return;
|
|
74
|
+
const nogPakbonnenOpen = (pakbonnen?.open ?? 0) > 0;
|
|
75
|
+
if (bezigMetIndelen || nogPakbonnenOpen)
|
|
76
|
+
return;
|
|
77
|
+
const t = setTimeout(() => {
|
|
78
|
+
setTotaal(0);
|
|
79
|
+
setPakbonnen(null);
|
|
80
|
+
setMelding(null);
|
|
81
|
+
}, 6000);
|
|
82
|
+
return () => clearTimeout(t);
|
|
83
|
+
}, [totaal, bezigMetIndelen, pakbonnen?.open]);
|
|
84
|
+
// Harde bovengrens: duurt het te lang, dan stopt de balk met een leesbare melding.
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (totaal === 0)
|
|
87
|
+
return;
|
|
88
|
+
const t = setTimeout(() => {
|
|
89
|
+
setTotaal(0);
|
|
90
|
+
setPakbonnen(null);
|
|
91
|
+
setMelding("Het opnieuw indelen duurt langer dan verwacht. De achtergrondverwerking loopt door; klik op Verversen voor de actuele stand.");
|
|
92
|
+
}, 5 * 60 * 1000);
|
|
93
|
+
return () => clearTimeout(t);
|
|
94
|
+
}, [totaal]);
|
|
24
95
|
const opnieuw = async () => {
|
|
25
96
|
try {
|
|
26
97
|
const n = await herindelen();
|
|
98
|
+
setTotaal(n);
|
|
27
99
|
setMelding(n === 0
|
|
28
100
|
? "Er stonden geen orders open om opnieuw in te delen."
|
|
29
|
-
: `${n} order(s) opnieuw aangemeld. De indeling
|
|
101
|
+
: `${n} order(s) opnieuw aangemeld. De indeling en de pakbonnen worden op de achtergrond klaargezet.`);
|
|
102
|
+
void pakbonRonde();
|
|
30
103
|
}
|
|
31
104
|
catch (e) {
|
|
105
|
+
setTotaal(0);
|
|
32
106
|
setMelding(e?.message ? String(e.message) : "Opnieuw indelen is niet gelukt.");
|
|
33
107
|
}
|
|
34
108
|
};
|
|
35
|
-
|
|
109
|
+
// Noodknop: alles opnieuw indelen, ook orders die al gepickt of geprint zijn.
|
|
110
|
+
const allesOpnieuwInclusiefGepickt = async () => {
|
|
111
|
+
setBevestigOpen(false);
|
|
112
|
+
try {
|
|
113
|
+
const r = await alsnogAllesHerindelen();
|
|
114
|
+
setTotaal(r.aangemeld);
|
|
115
|
+
setMelding(r.aangemeld === 0
|
|
116
|
+
? "Er stonden geen orders open om opnieuw in te delen."
|
|
117
|
+
: `${r.aangemeld} order(s) lopen de flow opnieuw af, vanaf "Order komt binnen". ${r.karrenVerwijderd} kar(ren) en ${r.pakbonnenVervallen} oude pakbon(nen) zijn vervallen; overal worden nieuwe pakbonnen met nieuwe barcodes klaargezet.`);
|
|
118
|
+
void pakbonRonde();
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
setTotaal(0);
|
|
122
|
+
setMelding(e?.message ? String(e.message) : "Volledig opnieuw indelen is niet gelukt.");
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
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: [status?.methode === "afmetingen" ? (_jsx(Ruler, { className: "h-4 w-4" })) : (_jsx(Boxes, { className: "h-4 w-4" })), "Werkwijze en herindeling"] }), _jsx(CardDescription, { children: "Zo worden karren op dit moment samengesteld. Verandert de methode, dan worden alle openstaande orders automatisch opnieuw ingedeeld." })] }), _jsxs("div", { className: "flex flex-wrap justify-end gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: () => void refresh(), disabled: loading, children: [_jsx(RefreshCw, { className: "h-4 w-4" }), "Verversen"] }), _jsxs(Button, { size: "sm", onClick: () => void opnieuw(), disabled: busy, children: [_jsx(RotateCcw, { className: "h-4 w-4" }), "Alles opnieuw indelen"] }), _jsxs(Button, { size: "sm", variant: "destructive", onClick: () => setBevestigOpen(true), disabled: busy, children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), "Alle orders opnieuw indelen, ook gepickte orders"] })] })] }), _jsx(CardContent, { className: "space-y-3", children: loading ? (_jsx(Skeleton, { className: "h-16 w-full" })) : error ? (_jsx("p", { className: "text-sm text-destructive", children: error })) : status ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Badge, { children: METHODE_LABEL[status.methode] ?? status.methode }), status.actieveWerkwijze ? (_jsxs("span", { className: "text-sm text-muted-foreground", children: ["volgens werkwijze \u201C", status.actieveWerkwijze, "\u201D"] })) : (_jsx("span", { className: "text-sm text-muted-foreground", children: "Er staat geen werkwijze aan; er wordt op belading ingedeeld." }))] }), _jsxs("div", { className: "grid gap-3 sm:grid-cols-3", children: [_jsxs("div", { className: "rounded-md border p-3", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: "Karren volgens deze methode" }), _jsx("p", { className: "text-lg font-semibold", children: status.karrenVolgensMethode })] }), _jsxs("div", { className: "rounded-md border p-3", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: "Karren van een oudere methode" }), _jsx("p", { className: "text-lg font-semibold", children: status.karrenOudeMethode })] }), _jsxs("div", { className: "rounded-md border p-3", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: "Wacht op indelen" }), _jsx("p", { className: "text-lg font-semibold", children: openWerk }), running > 0 ? (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["waarvan ", running, " nu bezig"] })) : null, blocked > 0 ? (_jsxs("p", { className: "text-xs text-destructive", children: [blocked, " geblokkeerd"] })) : null] })] }), status.karrenOudeMethode > 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Deze karren zijn nog met een eerdere methode berekend. Ze worden vervangen zodra de order opnieuw is ingedeeld; al geprinte of gecontroleerde karren blijven staan." })) : null, melding ? _jsx("p", { className: "text-sm", children: melding }) : null, totaal > 0 ? (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "h-2 w-full overflow-hidden rounded-full bg-muted", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": percentage, "aria-label": "Voortgang opnieuw indelen", children: _jsx("div", { className: "h-full rounded-full bg-primary transition-all duration-500", style: { width: `${percentage}%` } }) }), _jsx("p", { className: "text-xs text-muted-foreground", children: bezigMetIndelen
|
|
126
|
+
? `${gereed} van ${totaal} order(s) ingedeeld — ${percentage}%`
|
|
127
|
+
: `Klaar: ${totaal} order(s) opnieuw ingedeeld.` })] })) : null, pakbonnen && pakbonnen.totaal > 0 ? (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "h-2 w-full overflow-hidden rounded-full bg-muted", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": pakbonPercentage, "aria-label": "Voortgang pakbonnen klaarzetten", children: _jsx("div", { className: "h-full rounded-full bg-primary/70 transition-all duration-500", style: { width: `${pakbonPercentage}%` } }) }), _jsx("p", { className: "text-xs text-muted-foreground", children: pakbonnen.open > 0 || pakbonBezig
|
|
128
|
+
? `Pakbonnen klaarzetten: ${pakbonnen.gereed} van ${pakbonnen.totaal} printklaar — ${pakbonPercentage}%`
|
|
129
|
+
: `Alle ${pakbonnen.totaal} pakbon(nen) staan printklaar.` })] })) : null] })) : null }), _jsx(AlertDialog, { open: bevestigOpen, onOpenChange: setBevestigOpen, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Weet je het zeker?" }), _jsx(AlertDialogDescription, { children: "Alle openstaande orders worden opnieuw ingedeeld, ook orders die al gepickt of geprint zijn. Alle oude pakbonnen en barcodes vervallen en er worden overal nieuwe aangemaakt. Reeds geprinte pakbonnen kunnen daarna niet meer worden gescand. Dit kan niet ongedaan worden gemaakt." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Annuleren" }), _jsx(AlertDialogAction, { onClick: () => void allesOpnieuwInclusiefGepickt(), children: "Ja, alles opnieuw indelen" })] })] }) })] }));
|
|
36
130
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface AfrondStand {
|
|
2
|
+
wachtend: number;
|
|
3
|
+
bezig: number;
|
|
4
|
+
mislukt: number;
|
|
5
|
+
oudsteWachttijdSeconden: number;
|
|
6
|
+
laatsteFout: string | null;
|
|
7
|
+
laatstAfgerond: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface AfrondRegel {
|
|
10
|
+
orderId: string;
|
|
11
|
+
status: string;
|
|
12
|
+
pogingen: number;
|
|
13
|
+
maxPogingen: number;
|
|
14
|
+
reden: string | null;
|
|
15
|
+
fout: string | null;
|
|
16
|
+
aangemeldOp: string | null;
|
|
17
|
+
volgendePoging: string | null;
|
|
18
|
+
}
|
|
19
|
+
export declare function useAfrondWachtrij(intervalMs?: number): {
|
|
20
|
+
stand: AfrondStand;
|
|
21
|
+
regels: AfrondRegel[];
|
|
22
|
+
laden: boolean;
|
|
23
|
+
fout: string | null;
|
|
24
|
+
herlaad: () => Promise<void>;
|
|
25
|
+
opnieuw: (orderId: string) => Promise<boolean>;
|
|
26
|
+
naloop: () => Promise<boolean>;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=useAfrondWachtrij.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAfrondWachtrij.d.ts","sourceRoot":"","sources":["../../src/hooks/useAfrondWachtrij.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,uBAAuB,EAAE,MAAM,CAAC;IAChC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAWD,wBAAgB,iBAAiB,CAAC,UAAU,SAAQ;;;;;;uBA4DhC,MAAM;;EAuBzB"}
|