@flowselections/logistiek-engine 1.0.53 → 1.0.90
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/README.md +24 -24
- 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 +6 -0
- package/dist-lib/components/FlowCanvas.d.ts.map +1 -1
- package/dist-lib/components/FlowCanvas.js +79 -18
- package/dist-lib/components/FlowOrders.d.ts.map +1 -1
- package/dist-lib/components/FlowOrders.js +59 -13
- package/dist-lib/components/FlowPage.d.ts.map +1 -1
- package/dist-lib/components/FlowPage.js +175 -6
- package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
- package/dist-lib/components/GeblokkeerdeOrdersCard.js +21 -2
- 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 +7 -1
- package/dist-lib/components/LogistiekEngineQueuePage.d.ts.map +1 -1
- package/dist-lib/components/LogistiekEngineQueuePage.js +4 -2
- package/dist-lib/components/NodeTracePanel.d.ts +4 -1
- package/dist-lib/components/NodeTracePanel.d.ts.map +1 -1
- package/dist-lib/components/NodeTracePanel.js +8 -2
- package/dist-lib/components/OrderStopBanner.d.ts +9 -2
- package/dist-lib/components/OrderStopBanner.d.ts.map +1 -1
- package/dist-lib/components/OrderStopBanner.js +27 -13
- package/dist-lib/components/OrderTraceDetails.d.ts.map +1 -1
- package/dist-lib/components/OrderTraceDetails.js +2 -1
- 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 +21 -13
- 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/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.js +1 -1
- package/dist-lib/hooks/useOrderTrace.js +1 -1
- package/dist-lib/hooks/useOrderVersies.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderVersies.js +17 -3
- 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/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/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.js +1 -1
- package/dist-lib/hooks/useWerkwijzeStatus.js +1 -1
- package/dist-lib/index.d.ts +10 -0
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +10 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +3147 -159
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +3147 -159
- 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 +3147 -159
- 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 +3183 -161
- 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/floridayDocuments.functions.d.ts +8979 -15
- package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayDocuments.functions.js +5 -5
- package/dist-lib/lib/floridayPush.functions.d.ts +3147 -159
- package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
- package/dist-lib/lib/floridayPush.functions.js +3 -3
- 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 +3 -0
- package/dist-lib/lib/flowNodes.d.ts.map +1 -1
- package/dist-lib/lib/flowNodes.js +6 -0
- package/dist-lib/lib/flowRoute.d.ts +11 -1
- package/dist-lib/lib/flowRoute.d.ts.map +1 -1
- package/dist-lib/lib/flowRoute.js +343 -40
- package/dist-lib/lib/flowTree.d.ts +86 -1
- package/dist-lib/lib/flowTree.d.ts.map +1 -1
- package/dist-lib/lib/flowTree.js +391 -2
- 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/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 +56 -0
- 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/loadCarrierPlanning.functions.d.ts +14965 -25
- 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 +24 -12
- package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
- package/dist-lib/lib/loadCarrierPlanning.server.js +490 -211
- package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +5986 -10
- 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 +3147 -159
- 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 +3436 -3325
- package/dist-lib/lib/nodeTrace.d.ts +4 -0
- package/dist-lib/lib/nodeTrace.d.ts.map +1 -1
- package/dist-lib/lib/nodeTrace.js +6 -15
- package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
- package/dist-lib/lib/planQueue.server.js +24 -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/ruleEngineSchema.d.ts.map +1 -1
- package/dist-lib/lib/ruleEngineSchema.js +52 -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.map +1 -1
- package/dist-lib/lib/trace.server.js +3 -0
- package/dist-lib/lib/vakUitleg.d.ts.map +1 -1
- package/dist-lib/lib/vakUitleg.js +2 -1
- package/package.json +12 -9
|
@@ -7,18 +7,22 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
// je diezelfde instellingen aan; opslaan werkt door in de engine én in dit
|
|
8
8
|
// schema. GEEN <Header /> hier — die levert de shell.
|
|
9
9
|
// ============================================================================
|
|
10
|
-
import { useCallback, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
11
11
|
import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, toast, } from "@flowselections/core";
|
|
12
12
|
import { CheckCircle2, RefreshCw, Save, X } from "lucide-react";
|
|
13
13
|
import { fieldVisible, } from "../lib/ruleEngineSchema";
|
|
14
14
|
import { WIZARD_STEPS, groupSummary, isAdvancedField } from "../lib/ruleEngineWizard";
|
|
15
|
-
import { buildFlowTree } from "../lib/flowTree";
|
|
15
|
+
import { buildFlowTree, pasMergeOverridesToe, verbergEindnodeLijnen, verduidelijkVerzendbrief, mergeVoorwaarde, MERGE_MAX_WACHT_MINUTEN, } from "../lib/flowTree";
|
|
16
16
|
import { applyRoute } from "../lib/flowRoute";
|
|
17
|
+
import { ontbrekendeJourneyEvents } from "../lib/flowJourney";
|
|
17
18
|
import { FlowCanvas } from "./FlowCanvas";
|
|
18
19
|
import { FlowOrders } from "./FlowOrders";
|
|
19
20
|
import { OrderJourneyBar } from "./OrderJourneyBar";
|
|
20
21
|
import { OrderStopBanner } from "./OrderStopBanner";
|
|
21
22
|
import { useOrderNodeTrace } from "../hooks/useOrderNodeTrace";
|
|
23
|
+
import { useShippingNoteDiagnose } from "../hooks/useShippingNoteDiagnose";
|
|
24
|
+
import { stopReden, verzendbriefStop } from "../lib/stopReden";
|
|
25
|
+
import { useOrderTraceStand } from "../hooks/useOrderTrace";
|
|
22
26
|
import { useRuleEngine } from "../hooks/useRuleEngine";
|
|
23
27
|
import { useLogistiekStrategieen } from "../hooks/useLogistiekStrategieen";
|
|
24
28
|
import { useRecalcJob, phaseLabel } from "../hooks/useRecalcJob";
|
|
@@ -45,7 +49,25 @@ export function FlowPage() {
|
|
|
45
49
|
return match?.name ?? config.name.replace(/^Werkwijze\s+/i, "");
|
|
46
50
|
};
|
|
47
51
|
const settings = activeConfig?.settings ?? {};
|
|
48
|
-
|
|
52
|
+
// Handmatige keuzes op de samenkomstpunten (de ruitjes) horen bij de
|
|
53
|
+
// werkwijze, zodat de kaart voor iedereen hetzelfde blijft.
|
|
54
|
+
const mergeOverrides = useMemo(() => {
|
|
55
|
+
const raw = (settings?.["flow_weergave"]?.fields ?? {})["merges"];
|
|
56
|
+
return raw && typeof raw === "object" ? raw : {};
|
|
57
|
+
}, [settings]);
|
|
58
|
+
const ruweTree = useMemo(() => buildFlowTree(settings, mergeOverrides), [settings, mergeOverrides]);
|
|
59
|
+
const basisTree = useMemo(() => pasMergeOverridesToe(ruweTree, mergeOverrides), [ruweTree, mergeOverrides]);
|
|
60
|
+
const [mergeId, setMergeId] = useState(null);
|
|
61
|
+
const zetMergeOverride = (id, patch) => {
|
|
62
|
+
if (!activeConfig)
|
|
63
|
+
return;
|
|
64
|
+
const huidig = settings["flow_weergave"] ?? { fields: {}, conditions: [] };
|
|
65
|
+
const merges = { ...mergeOverrides, [id]: { ...(mergeOverrides[id] ?? {}), ...patch } };
|
|
66
|
+
patchSettings(activeConfig.id, {
|
|
67
|
+
...settings,
|
|
68
|
+
flow_weergave: { ...huidig, fields: { ...(huidig.fields ?? {}), merges } },
|
|
69
|
+
});
|
|
70
|
+
};
|
|
49
71
|
// Gekozen order/versie: de echte reis wordt als laag over de kaart gelegd.
|
|
50
72
|
const [orderRoute, setOrderRoute] = useState(null);
|
|
51
73
|
const [routeLabel, setRouteLabel] = useState(null);
|
|
@@ -65,8 +87,122 @@ export function FlowPage() {
|
|
|
65
87
|
}
|
|
66
88
|
}, []);
|
|
67
89
|
const { groepen, reis, loading: traceLoading } = useOrderNodeTrace(orderRef, versie);
|
|
68
|
-
const
|
|
69
|
-
|
|
90
|
+
const { stand: orderStand } = useOrderTraceStand(orderRef);
|
|
91
|
+
// Auditpunt 5: het openen van een order verandert nooit iets aan die order.
|
|
92
|
+
// De keuzevakjes die de Engine zelf niet vastlegt worden hier alléén afgeleid
|
|
93
|
+
// en getoond (herkenbaar als "automatisch afgeleid"). Het echte logboek wordt
|
|
94
|
+
// bijgewerkt door de Engine zelf: bij een herberekening en in elke planronde.
|
|
95
|
+
// Samenkomstpunten waar deze order wacht; daar loopt de route niet voorbij.
|
|
96
|
+
const wachtpuntenRef = useRef(new Set());
|
|
97
|
+
const [wachtpunten, setWachtpunten] = useState(() => new Set());
|
|
98
|
+
const alleGroepen = useMemo(() => {
|
|
99
|
+
if (!orderRef || traceLoading || groepen.size === 0)
|
|
100
|
+
return groepen;
|
|
101
|
+
const vastgelegd = new Set(groepen.keys());
|
|
102
|
+
const events = ontbrekendeJourneyEvents({
|
|
103
|
+
tree: basisTree,
|
|
104
|
+
orderRef,
|
|
105
|
+
orderSource: orderRoute?.source ?? null,
|
|
106
|
+
vastgelegd,
|
|
107
|
+
wachtpunten,
|
|
108
|
+
});
|
|
109
|
+
if (events.length === 0)
|
|
110
|
+
return groepen;
|
|
111
|
+
const samen = new Map(groepen);
|
|
112
|
+
for (const e of events) {
|
|
113
|
+
if (!e.nodeId || samen.has(e.nodeId))
|
|
114
|
+
continue;
|
|
115
|
+
samen.set(e.nodeId, {
|
|
116
|
+
nodeId: e.nodeId,
|
|
117
|
+
events: [],
|
|
118
|
+
aantal: 0,
|
|
119
|
+
eerste: null,
|
|
120
|
+
laatste: null,
|
|
121
|
+
duurMs: null,
|
|
122
|
+
status: "geslaagd",
|
|
123
|
+
pogingen: 0,
|
|
124
|
+
reden: e.reason ?? null,
|
|
125
|
+
errorClass: null,
|
|
126
|
+
volgendeStap: e.nextStep ?? null,
|
|
127
|
+
afgeleid: true,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return samen;
|
|
131
|
+
}, [groepen, traceLoading, orderRef, basisTree, orderRoute?.source, wachtpunten]);
|
|
132
|
+
const overlay = useMemo(() => applyRoute(basisTree, orderRoute, orderRef ? alleGroepen : null, orderStand), [basisTree, orderRoute, alleGroepen, orderRef, orderStand]);
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
// Wachtpunten komen uit de kaart en sturen de volgende afleiding aan.
|
|
135
|
+
const nieuw = overlay.wachtpunten;
|
|
136
|
+
const oud = wachtpuntenRef.current;
|
|
137
|
+
const gelijk = nieuw.size === oud.size && [...nieuw].every((id) => oud.has(id));
|
|
138
|
+
if (gelijk)
|
|
139
|
+
return;
|
|
140
|
+
wachtpuntenRef.current = nieuw;
|
|
141
|
+
setWachtpunten(new Set(nieuw));
|
|
142
|
+
}, [overlay]);
|
|
143
|
+
/** Het laatste vakje van de route, met de reden waarom het daar ophoudt. */
|
|
144
|
+
const eindpunt = useMemo(() => {
|
|
145
|
+
for (const [nodeId, m] of overlay.markers) {
|
|
146
|
+
if (m.eindpunt && m.stop)
|
|
147
|
+
return { nodeId, stop: m.stop };
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}, [overlay]);
|
|
151
|
+
// Zonder geselecteerde order: geen doorlopende lijnen onder een eindstation.
|
|
152
|
+
// Met een order: het verzendbriefvakje toont de tekst die bij die herkomst hoort.
|
|
153
|
+
const tree = useMemo(() => orderRoute
|
|
154
|
+
? verduidelijkVerzendbrief(overlay.tree, orderRoute.source)
|
|
155
|
+
: verbergEindnodeLijnen(overlay.tree), [overlay.tree, orderRoute]);
|
|
156
|
+
// Alleen-lezen: waarom wacht deze order nog op zijn verzendbrief?
|
|
157
|
+
const { diagnose: verzendbrief } = useShippingNoteDiagnose(orderRef);
|
|
158
|
+
const verzendbriefReden = useMemo(() => verzendbriefStop(verzendbrief), [verzendbrief]);
|
|
159
|
+
// Vakjes die vastlopen, met de reden erbij: die krijgen een foutmelding op de
|
|
160
|
+
// kaart en in het zijpaneel. Alleen weergave; er verandert niets aan de order.
|
|
161
|
+
const problemen = useMemo(() => {
|
|
162
|
+
const map = new Map();
|
|
163
|
+
if (!orderRef)
|
|
164
|
+
return map;
|
|
165
|
+
for (const [nodeId, groep] of alleGroepen) {
|
|
166
|
+
if (groep.status === "mislukt") {
|
|
167
|
+
map.set(nodeId, stopReden({ nodeId, groep, stand: orderStand }));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (verzendbriefReden) {
|
|
171
|
+
for (const n of tree.nodes) {
|
|
172
|
+
if (n.id.includes(":verzendbrief:") || n.id.endsWith(":verzendbrief")) {
|
|
173
|
+
map.set(n.id, verzendbriefReden);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return map;
|
|
178
|
+
}, [orderRef, alleGroepen, orderStand, verzendbriefReden, tree]);
|
|
179
|
+
// Gegevens voor het ruitje-paneel komen uit de kaart zonder overrides, zodat
|
|
180
|
+
// een weggehaald ruitje ook weer terug te zetten is.
|
|
181
|
+
const mergeNode = mergeId ? (ruweTree.nodes.find((n) => n.id === mergeId) ?? null) : null;
|
|
182
|
+
const mergeVast = !!mergeId && (mergeId.startsWith("samen:stap:") || mergeId === "__bron_merge");
|
|
183
|
+
const mergeWeg = !!mergeId && mergeOverrides[mergeId]?.verwijderd === true;
|
|
184
|
+
const naamVan = (id) => {
|
|
185
|
+
const n = ruweTree.nodes.find((x) => x.id === id);
|
|
186
|
+
if (!n)
|
|
187
|
+
return id;
|
|
188
|
+
if (n.label)
|
|
189
|
+
return n.label;
|
|
190
|
+
return n.kind === "merge" ? "samenkomst" : id;
|
|
191
|
+
};
|
|
192
|
+
const mergeLijnen = mergeId
|
|
193
|
+
? ruweTree.edges
|
|
194
|
+
.filter((e) => e.kind === "flow" && e.to === mergeId)
|
|
195
|
+
.map((e) => ({ id: e.id, naam: e.label ? `${naamVan(e.from)} — ${e.label}` : naamVan(e.from) }))
|
|
196
|
+
: [];
|
|
197
|
+
const mergeKeuze = mergeId ? mergeVoorwaarde(ruweTree, mergeId, mergeOverrides[mergeId]) : null;
|
|
198
|
+
// Altijd de opgeloste voorwaarde tonen: een opgeslagen "alle" die hier
|
|
199
|
+
// onmogelijk is, valt terug op "één" en wordt ook zo weergegeven.
|
|
200
|
+
const mergeWanneer = mergeKeuze?.wanneer ?? "een";
|
|
201
|
+
const mergeUitsluitend = mergeKeuze?.uitsluitend === true;
|
|
202
|
+
const alleOnmogelijkOpgeslagen = mergeUitsluitend && mergeOverrides[mergeId ?? ""]?.wanneer === "alle";
|
|
203
|
+
const weggehaaldeRuitjes = Object.entries(mergeOverrides)
|
|
204
|
+
.filter(([, k]) => k?.verwijderd)
|
|
205
|
+
.map(([id]) => id);
|
|
70
206
|
const step = WIZARD_STEPS.find((s) => s.id === openStep) ?? null;
|
|
71
207
|
const stepValues = step ? (settings?.[step.storeId]?.fields ?? {}) : {};
|
|
72
208
|
const stepConditions = step
|
|
@@ -129,7 +265,40 @@ export function FlowPage() {
|
|
|
129
265
|
}
|
|
130
266
|
};
|
|
131
267
|
const veiligeConfigs = Array.isArray(configs) ? configs : [];
|
|
132
|
-
return (_jsxs("div", { className: "space-y-4 p-6", children: [_jsxs("header", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold tracking-tight", children: "Flow van de Logistiek Engine" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Alle mogelijke routes door de engine in \u00E9\u00E9n kaart. De gekleurde route geldt nu; kies in een beslistegel iets anders en de actieve tak springt direct mee." })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [veiligeConfigs.length > 1 && (_jsxs(Select, { value: activeId ?? "", onValueChange: (v) => setActiveId(v), children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Kies een werkwijze" }) }), _jsx(SelectContent, { children: veiligeConfigs.map((c) => (_jsxs(SelectItem, { value: c.id, children: [werkwijzeNaam(c), c.is_active ? " (actief)" : ""] }, c.id))) })] })), _jsxs(Button, { variant: "outline", size: "sm", disabled: !activeConfig || saving || busy, onClick: () => void opslaan(false), children: [_jsx(Save, { className: "h-4 w-4" }), " Opslaan"] }), _jsxs(Button, { size: "sm", disabled: !activeConfig || saving || busy || starting || running, onClick: () => void opslaan(true), children: [busy || starting || running ? (_jsx(RefreshCw, { className: "h-4 w-4 animate-spin" })) : (_jsx(CheckCircle2, { className: "h-4 w-4" })), running ? `${phaseLabel(job?.phase)}…` : "Opslaan & opnieuw berekenen"] })] })] }), error && (_jsx("p", { className: "rounded-md border border-destructive/50 bg-destructive/5 px-3 py-2 text-sm text-destructive", children: "De werkwijze kon niet worden geladen. Probeer het opnieuw." })), loading ? (_jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-24 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" })] })) : !activeConfig ? (_jsx(Card, { children: _jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Nog geen werkwijze" }), _jsx(CardDescription, { children: "Maak eerst een werkwijze aan bij Werkwijze instellen; daarna verschijnt de flow hier vanzelf." })] }) })) : (_jsxs("div", { className: `grid gap-6 ${openStep ? "lg:grid-cols-[minmax(0,1fr)_420px]" : "lg:grid-cols-1"}`, children: [_jsxs("div", { className: "space-y-2", ref: kaartRef, children: [_jsxs("p", { className: "text-xs text-muted-foreground", children: ["werkwijze: ", werkwijzeNaam(activeConfig), activeConfig.is_active ? " (actief)" : " (concept)"] }), orderRef && _jsx(OrderStopBanner, { orderRef: orderRef,
|
|
268
|
+
return (_jsxs("div", { className: "space-y-4 p-6", children: [_jsxs("header", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-xl font-semibold tracking-tight", children: "Flow van de Logistiek Engine" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Alle mogelijke routes door de engine in \u00E9\u00E9n kaart. De gekleurde route geldt nu; kies in een beslistegel iets anders en de actieve tak springt direct mee." })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [veiligeConfigs.length > 1 && (_jsxs(Select, { value: activeId ?? "", onValueChange: (v) => setActiveId(v), children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Kies een werkwijze" }) }), _jsx(SelectContent, { children: veiligeConfigs.map((c) => (_jsxs(SelectItem, { value: c.id, children: [werkwijzeNaam(c), c.is_active ? " (actief)" : ""] }, c.id))) })] })), _jsxs(Button, { variant: "outline", size: "sm", disabled: !activeConfig || saving || busy, onClick: () => void opslaan(false), children: [_jsx(Save, { className: "h-4 w-4" }), " Opslaan"] }), _jsxs(Button, { size: "sm", disabled: !activeConfig || saving || busy || starting || running, onClick: () => void opslaan(true), children: [busy || starting || running ? (_jsx(RefreshCw, { className: "h-4 w-4 animate-spin" })) : (_jsx(CheckCircle2, { className: "h-4 w-4" })), running ? `${phaseLabel(job?.phase)}…` : "Opslaan & opnieuw berekenen"] })] })] }), error && (_jsx("p", { className: "rounded-md border border-destructive/50 bg-destructive/5 px-3 py-2 text-sm text-destructive", children: "De werkwijze kon niet worden geladen. Probeer het opnieuw." })), loading ? (_jsxs("div", { className: "space-y-3", children: [_jsx(Skeleton, { className: "h-24 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" })] })) : !activeConfig ? (_jsx(Card, { children: _jsxs(CardHeader, { children: [_jsx(CardTitle, { children: "Nog geen werkwijze" }), _jsx(CardDescription, { children: "Maak eerst een werkwijze aan bij Werkwijze instellen; daarna verschijnt de flow hier vanzelf." })] }) })) : (_jsxs("div", { className: `grid gap-6 ${openStep || mergeId ? "lg:grid-cols-[minmax(0,1fr)_420px]" : "lg:grid-cols-1"}`, children: [_jsxs("div", { className: "space-y-2", ref: kaartRef, children: [_jsxs("p", { className: "text-xs text-muted-foreground", children: ["werkwijze: ", werkwijzeNaam(activeConfig), activeConfig.is_active ? " (actief)" : " (concept)"] }), orderRef && (_jsx(OrderStopBanner, { orderRef: orderRef, stop: eindpunt?.stop ?? null, stopNode: eindpunt?.nodeId ?? null, onNode: setTraceNodeId })), verzendbriefReden && (_jsxs("div", { className: `rounded-md border px-3 py-2 text-sm ${verzendbriefReden.soort === "mislukt"
|
|
269
|
+
? "border-destructive/50 bg-destructive/5"
|
|
270
|
+
: "border-amber-500/40 bg-amber-500/5"}`, children: [_jsxs("p", { className: "font-medium", children: [verzendbriefReden.titel, ": ", verzendbriefReden.reden] }), verzendbriefReden.feiten.length > 0 && (_jsx("p", { className: "text-muted-foreground", children: verzendbriefReden.feiten.join(" · ") })), verzendbriefReden.volgendeStap && (_jsxs("p", { className: "text-muted-foreground", children: ["Wat moet er gebeuren: ", verzendbriefReden.volgendeStap] }))] })), _jsx(FlowCanvas, { tree: tree, selectedStepId: openStep, settings: settings, markers: overlay.markers, problemen: problemen, nodeTrace: orderRef ? alleGroepen : null, routeLabel: routeLabel, routeSummary: orderRoute?.summary ?? null, traceNodeId: traceNodeId, onTraceNode: setTraceNodeId, onClearRoute: () => onRoute(null, null, null, null), mergeId: mergeId, onSelectMerge: (id) => setMergeId((v) => (v === id ? null : id)), onSelectStep: (stepId) => setOpenStep((v) => (v === stepId ? null : stepId)), onChangeChoice: setFieldByStore }), orderRef && (_jsx(OrderJourneyBar, { reis: reis, actiefNodeId: traceNodeId, onKies: setTraceNodeId })), weggehaaldeRuitjes.length > 0 && (_jsxs("p", { className: "text-xs text-muted-foreground", children: [weggehaaldeRuitjes.length, " samenkomstpunt", weggehaaldeRuitjes.length === 1 ? "" : "en", " weggehaald.", " ", _jsx("button", { type: "button", className: "underline underline-offset-2", onClick: () => {
|
|
271
|
+
if (!activeConfig)
|
|
272
|
+
return;
|
|
273
|
+
const huidig = settings["flow_weergave"] ?? { fields: {}, conditions: [] };
|
|
274
|
+
const merges = {};
|
|
275
|
+
for (const [id, keuze] of Object.entries(mergeOverrides)) {
|
|
276
|
+
merges[id] = { ...keuze, verwijderd: false };
|
|
277
|
+
}
|
|
278
|
+
patchSettings(activeConfig.id, {
|
|
279
|
+
...settings,
|
|
280
|
+
flow_weergave: { ...huidig, fields: { ...(huidig.fields ?? {}), merges } },
|
|
281
|
+
});
|
|
282
|
+
}, children: "Allemaal terugzetten" })] })), orderRef && !traceLoading && reis.length === 0 && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Voor deze order zijn nog geen stappen per vakje vastgelegd; de kaart toont dan de afgeleide route." }))] }), mergeNode && (_jsx("aside", { className: "space-y-3 lg:sticky lg:top-4", children: _jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-3", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Samenkomstpunt" }), _jsx(CardDescription, { children: "Hier komen lijnen weer samen tot \u00E9\u00E9n route. Het punt zelf doet niets met een order." })] }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Paneel sluiten", onClick: () => setMergeId(null), children: _jsx(X, { className: "h-4 w-4" }) })] }) }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "space-y-2 rounded-md border border-border p-2", children: [_jsx("p", { className: "text-sm font-medium", children: "Wanneer mag de flow verder?" }), _jsxs(Select, { value: mergeWanneer, onValueChange: (v) => {
|
|
283
|
+
if (v === "alle" && mergeUitsluitend)
|
|
284
|
+
return;
|
|
285
|
+
zetMergeOverride(mergeNode.id, {
|
|
286
|
+
wanneer: v,
|
|
287
|
+
...(v === "specifiek" && !mergeOverrides[mergeNode.id]?.verplichteLijn
|
|
288
|
+
? { verplichteLijn: mergeLijnen[0]?.id }
|
|
289
|
+
: {}),
|
|
290
|
+
});
|
|
291
|
+
}, children: [_jsx(SelectTrigger, { className: "h-9 w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "een", children: "Zodra \u00E9\u00E9n flow klaar is" }), _jsx(SelectItem, { value: "alle", disabled: mergeUitsluitend, children: "Pas als alle flows klaar zijn" }), _jsx(SelectItem, { value: "specifiek", children: "Als een specifieke flow klaar is" })] })] }), mergeUitsluitend && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Deze lijnen sluiten elkaar uit: een order komt maar via \u00E9\u00E9n van ze binnen. Wachten op alle flows kan hier dus nooit \u2014 die keuze is niet beschikbaar." })), alleOnmogelijkOpgeslagen && (_jsx("p", { className: "text-xs text-amber-700", children: "\u201CPas als alle flows klaar zijn\u201D was hier opgeslagen, maar is onmogelijk. Er is terugezet op: zodra \u00E9\u00E9n flow klaar is." })), mergeWanneer === "specifiek" && (_jsxs(Select, { value: mergeOverrides[mergeNode.id]?.verplichteLijn ?? "", onValueChange: (v) => zetMergeOverride(mergeNode.id, { verplichteLijn: v }), children: [_jsx(SelectTrigger, { className: "h-9 w-full", children: _jsx(SelectValue, { placeholder: "Kies de verplichte flow" }) }), _jsx(SelectContent, { children: mergeLijnen.map((l) => (_jsx(SelectItem, { value: l.id, children: l.naam }, l.id))) })] })), mergeWanneer !== "een" && (_jsxs("label", { className: "flex items-center justify-between gap-2 text-xs text-muted-foreground", children: [_jsx("span", { children: "Ga na zoveel minuten toch verder" }), _jsx("input", { type: "number", min: 1, className: "h-8 w-20 rounded-md border border-border bg-background px-2 text-right text-xs", value: mergeOverrides[mergeNode.id]?.maxWachtMinuten ?? MERGE_MAX_WACHT_MINUTEN, onChange: (e) => zetMergeOverride(mergeNode.id, {
|
|
292
|
+
maxWachtMinuten: Math.max(1, Number(e.target.value) || MERGE_MAX_WACHT_MINUTEN),
|
|
293
|
+
}) })] })), mergeKeuze?.terugval && (_jsx("p", { className: "text-xs text-amber-700", children: "De gekozen flow bestaat niet meer of is uitgeschakeld; zolang dat zo is, gaat de flow verder zodra \u00E9\u00E9n flow klaar is." })), _jsx("p", { className: "text-xs text-muted-foreground", children: "Lijnen die nu uitgeschakeld zijn of op \u201CStopt hier\u201D staan, tellen niet mee. Zo blijft de flow nooit wachten op een tak die toch nooit loopt." })] }), _jsx(Button, { variant: "outline", size: "sm", disabled: mergeVast, onClick: () => zetMergeOverride(mergeNode.id, { verwijderd: !mergeWeg }), children: mergeWeg ? "Ruitje terugzetten" : "Ruitje weghalen" }), mergeVast && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Dit punt houdt de doorgaande route tussen de stappen heel en kan niet worden weggehaald." })), _jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-sm font-medium", children: "Binnenkomende lijnen" }), mergeLijnen.length === 0 && (_jsx("p", { className: "text-xs text-muted-foreground", children: "Er komt hier niets binnen." })), mergeLijnen.map((lijn) => {
|
|
294
|
+
const stand = mergeOverrides[mergeNode.id]?.lijnen?.[lijn.id] ?? "door";
|
|
295
|
+
return (_jsxs("div", { className: "flex items-center justify-between gap-2 rounded-md border border-border px-2 py-1.5", children: [_jsx("span", { className: "truncate text-xs", children: lijn.naam }), _jsxs(Select, { value: stand, onValueChange: (v) => zetMergeOverride(mergeNode.id, {
|
|
296
|
+
lijnen: {
|
|
297
|
+
...(mergeOverrides[mergeNode.id]?.lijnen ?? {}),
|
|
298
|
+
[lijn.id]: v,
|
|
299
|
+
},
|
|
300
|
+
}), children: [_jsx(SelectTrigger, { className: "h-8 w-36", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "door", children: "Gaat door" }), _jsx(SelectItem, { value: "stop", children: "Stopt hier" })] })] })] }, lijn.id));
|
|
301
|
+
}), _jsx("p", { className: "text-xs text-muted-foreground", children: "Staat een lijn op \u201CStopt hier\u201D, dan gaat een order die via die lijn binnenkomt niet verder; de route eindigt op dat punt." })] }), _jsx("div", { className: "flex flex-wrap gap-2 pt-1", children: _jsxs(Button, { variant: "outline", size: "sm", disabled: saving || busy, onClick: () => void opslaan(false), children: [_jsx(Save, { className: "h-4 w-4" }), " Opslaan"] }) })] })] }) })), step && (_jsx("aside", { className: "space-y-3 lg:sticky lg:top-4 lg:max-h-[calc(100vh-8rem)] lg:overflow-y-auto", children: _jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-3", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: step.label }), _jsx(CardDescription, { children: step.description })] }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Paneel sluiten", onClick: () => setOpenStep(null), children: _jsx(X, { className: "h-4 w-4" }) })] }) }), _jsxs(CardContent, { className: "space-y-3", children: [step.groups.map((group, groupIndex) => {
|
|
133
302
|
const visibleFields = group.fields.filter((field) => fieldVisible(field, stepValues, settings));
|
|
134
303
|
if (visibleFields.length === 0)
|
|
135
304
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GeblokkeerdeOrdersCard.d.ts","sourceRoot":"","sources":["../../src/components/GeblokkeerdeOrdersCard.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"GeblokkeerdeOrdersCard.d.ts","sourceRoot":"","sources":["../../src/components/GeblokkeerdeOrdersCard.tsx"],"names":[],"mappings":"AA6BA,wBAAgB,sBAAsB,gCA6KrC"}
|
|
@@ -18,7 +18,7 @@ function datum(waarde) {
|
|
|
18
18
|
return Number.isNaN(d.getTime()) ? "—" : d.toLocaleDateString("nl-NL");
|
|
19
19
|
}
|
|
20
20
|
export function GeblokkeerdeOrdersCard() {
|
|
21
|
-
const { rows, overzicht, loading, error, busy, refresh, retry } = useGeblokkeerdeOrders();
|
|
21
|
+
const { rows, overzicht, loading, error, busy, refresh, retry, dubbelenOpruimen } = useGeblokkeerdeOrders();
|
|
22
22
|
const [filter, setFilter] = useState("");
|
|
23
23
|
const [melding, setMelding] = useState(null);
|
|
24
24
|
const safeRows = Array.isArray(rows) ? rows : [];
|
|
@@ -40,5 +40,24 @@ export function GeblokkeerdeOrdersCard() {
|
|
|
40
40
|
setMelding(e?.message ? String(e.message) : "Opnieuw proberen is niet gelukt.");
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
|
-
|
|
43
|
+
const opruimen = async (orderId, orderRef) => {
|
|
44
|
+
try {
|
|
45
|
+
const r = await dubbelenOpruimen(orderId);
|
|
46
|
+
if (!r.ok) {
|
|
47
|
+
setMelding(r.reden === "bevroren"
|
|
48
|
+
? `${orderRef} is niet aangeraakt: er is al een pakbon geprint, gescand of gecontroleerd.`
|
|
49
|
+
: r.reden === "bezig"
|
|
50
|
+
? `${orderRef} wordt op dit moment al opgeruimd; probeer het zo opnieuw.`
|
|
51
|
+
: `Opruimen van ${orderRef} is niet gelukt.`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
setMelding(`${orderRef}: ${r.verwijderd} dubbele bestelregel(s) verwijderd, ${r.na} regel(s) over.` +
|
|
55
|
+
(r.meerTeDoen ? " Er staan er nog meer klaar; klik nogmaals." : "") +
|
|
56
|
+
" Klik daarna op Opnieuw om de order te laten indelen.");
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
setMelding(e?.message ? String(e.message) : "Opruimen is niet gelukt.");
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(AlertTriangle, { className: "h-4 w-4 text-destructive" }), "Vastgelopen orders"] }), _jsx(CardDescription, { children: "Deze orders krijgen geen karrenindeling tot er iets aan de order verandert of je ze hier opnieuw aanbiedt." })] }), _jsxs("div", { className: "flex items-center gap-2", children: [zichtbaar.length > 0 && (_jsxs(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw(zichtbaar.map((r) => r.orderId)), children: [_jsx(RotateCcw, { className: "mr-2 h-4 w-4" }), "Alles opnieuw proberen"] })), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => void refresh(), disabled: loading, children: _jsx(RefreshCw, { className: `h-4 w-4 ${loading ? "animate-spin" : ""}` }) })] })] }), _jsxs(CardContent, { className: "space-y-4", children: [overzicht?.tickStale && (_jsx("p", { className: "rounded-md bg-muted p-3 text-sm text-muted-foreground", children: "De verwerking op de achtergrond heeft zich langer dan tien minuten niet gemeld. Opnieuw proberen zet de order wel klaar, maar hij wordt pas opgepakt zodra de verwerking weer draait." })), error && _jsx("p", { className: "text-sm text-destructive", children: error }), melding && _jsx("p", { className: "text-sm text-muted-foreground", children: melding }), loading && safeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-6 w-full" }), _jsx(Skeleton, { className: "h-6 w-full" })] })) : safeRows.length === 0 ? (_jsxs("p", { className: "text-sm text-muted-foreground", children: ["Geen vastgelopen orders. Alles is ingedeeld of staat nog in de wachtrij", overzicht ? ` (${overzicht.pending} wachtend)` : "", "."] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsxs(Badge, { variant: filter === "" ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(""), children: ["Alles (", safeRows.length, ")"] }), codes.map(([code, aantal]) => (_jsxs(Badge, { variant: filter === code ? "default" : "outline", className: "cursor-pointer", onClick: () => setFilter(code), children: [redenLabel(code), " (", aantal, ")"] }, code)))] }), _jsx("div", { className: "divide-y rounded-md border", children: zichtbaar.map((r) => (_jsxs("div", { className: "flex items-start justify-between gap-4 p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: r.orderRef }), _jsx(Badge, { variant: "secondary", children: redenLabel(r.reasonCode) }), _jsxs("span", { className: "text-xs text-muted-foreground", children: ["Leverdatum ", datum(r.deliveryDate), " \u00B7 sinds ", datum(r.blockedSince)] })] }), r.reason && (_jsx("p", { className: "mt-1 line-clamp-2 text-sm text-muted-foreground", children: r.reason }))] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [r.reasonCode === "dubbele_regels" && (_jsx(Button, { variant: "secondary", size: "sm", disabled: busy, onClick: () => void opruimen(r.orderId, r.orderRef), children: "Dubbele regels opruimen" })), _jsx(Button, { variant: "outline", size: "sm", disabled: busy, onClick: () => void opnieuw([r.orderId]), children: "Opnieuw" })] })] }, r.queueId))) })] }))] })] }));
|
|
44
63
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KardekkingCard.d.ts","sourceRoot":"","sources":["../../src/components/KardekkingCard.tsx"],"names":[],"mappings":"AAkCA,wBAAgB,cAAc,gCA6C7B"}
|
|
@@ -0,0 +1,29 @@
|
|
|
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 { getCartCoverage } from "../lib/cartCoverage.functions";
|
|
6
|
+
const LABEL = {
|
|
7
|
+
gelijk: "Gelijk",
|
|
8
|
+
gelijk_afgerond: "Gelijk (afgerond op fust)",
|
|
9
|
+
verkeerde_karinhoud: "Op verkeerde kar",
|
|
10
|
+
geblokkeerd: "Geblokkeerd",
|
|
11
|
+
geen_kar: "Geen kar",
|
|
12
|
+
echt_verschil: "Echt verschil",
|
|
13
|
+
};
|
|
14
|
+
function Telling({ titel, data }) {
|
|
15
|
+
const keys = Object.keys(LABEL).filter((k) => (data[k] ?? 0) > 0);
|
|
16
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium", children: titel }), keys.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: "Geen regels." })) : (_jsx("div", { className: "flex flex-wrap gap-2", children: keys.map((k) => (_jsxs(Badge, { variant: k === "gelijk" || k === "gelijk_afgerond" ? "secondary" : "destructive", children: [LABEL[k], ": ", data[k]] }, k))) }))] }));
|
|
17
|
+
}
|
|
18
|
+
export function KardekkingCard() {
|
|
19
|
+
const fetchCoverage = useServerFn(getCartCoverage);
|
|
20
|
+
const { data, isLoading, error } = useQuery({ queryKey: ["kardekking"], queryFn: () => fetchCoverage() });
|
|
21
|
+
if (isLoading)
|
|
22
|
+
return _jsx(Skeleton, { className: "h-24 w-full" });
|
|
23
|
+
if (error || !data)
|
|
24
|
+
return _jsx("p", { className: "text-sm text-destructive", children: "Kon de controle niet ophalen." });
|
|
25
|
+
const lijst = Array.isArray(data.afwijkingen) ? data.afwijkingen : [];
|
|
26
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(Telling, { titel: "Lopende orders", data: data.lopend }), _jsx(Telling, { titel: "Afgehandelde orders", data: data.afgehandeld }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Regels met een dubbel product op dezelfde order: ", data.dubbeleRegels, " (opgelost via de Verkoop-module)."] }), lijst.length > 0 && (_jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Order" }), _jsx(TableHead, { children: "Uitkomst" }), _jsx(TableHead, { className: "text-right", children: "Besteld" }), _jsx(TableHead, { className: "text-right", children: "Op kar" }), _jsx(TableHead, { children: "Opmerking" })] }) }), _jsx(TableBody, { children: lijst.slice(0, 200).map((r, i) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: r.order }), _jsx(TableCell, { children: LABEL[r.klasse] ?? r.klasse }), _jsx(TableCell, { className: "text-right", children: r.besteld ?? "—" }), _jsx(TableCell, { className: "text-right", children: r.planten ?? "—" }), _jsx(TableCell, { className: "text-xs text-muted-foreground", children: [r.afgehandeld ? "afgehandeld" : null, r.dubbel ? "dubbele regel" : null, r.blokkade]
|
|
27
|
+
.filter(Boolean)
|
|
28
|
+
.join(" · ") })] }, `${r.order}-${i}`))) })] }))] }));
|
|
29
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogistiekEnginePage.d.ts","sourceRoot":"","sources":["../../src/components/LogistiekEnginePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LogistiekEnginePage.d.ts","sourceRoot":"","sources":["../../src/components/LogistiekEnginePage.tsx"],"names":[],"mappings":"AAuFA,wBAAgB,mBAAmB,gCAgPlC"}
|
|
@@ -7,7 +7,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
// ============================================================================
|
|
8
8
|
import { useState } from "react";
|
|
9
9
|
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Badge, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Skeleton, } from "@flowselections/core";
|
|
10
|
-
import { Container, GitBranch, Pencil, Plus, Puzzle, SlidersHorizontal, Trash2, Workflow } from "lucide-react";
|
|
10
|
+
import { Container, GitBranch, ListChecks, Pencil, Plus, Puzzle, SlidersHorizontal, Trash2, Workflow } from "lucide-react";
|
|
11
11
|
import { Link } from "@tanstack/react-router";
|
|
12
12
|
import { StrategieDialog } from "./StrategieDialog";
|
|
13
13
|
import { WerkwijzeHerindelingCard } from "./WerkwijzeHerindelingCard";
|
|
@@ -26,6 +26,12 @@ const SNELKOPPELINGEN = [
|
|
|
26
26
|
titel: "Flow",
|
|
27
27
|
uitleg: "Volg per order de reis door de flow en pas de werkwijze aan.",
|
|
28
28
|
},
|
|
29
|
+
{
|
|
30
|
+
to: "/logistiek-engine/wachtrij",
|
|
31
|
+
icon: ListChecks,
|
|
32
|
+
titel: "Wachtrij",
|
|
33
|
+
uitleg: "Orders die nog een karrenindeling moeten krijgen, opnieuw proberen of resetten.",
|
|
34
|
+
},
|
|
29
35
|
{
|
|
30
36
|
to: "/logistiek-engine/regie",
|
|
31
37
|
icon: Workflow,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogistiekEngineQueuePage.d.ts","sourceRoot":"","sources":["../../src/components/LogistiekEngineQueuePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LogistiekEngineQueuePage.d.ts","sourceRoot":"","sources":["../../src/components/LogistiekEngineQueuePage.tsx"],"names":[],"mappings":"AAWA,wBAAgB,wBAAwB,gCAYvC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// ============================================================================
|
|
3
3
|
// src/components/LogistiekEngineQueuePage.tsx — Queue: de volledige orderflow
|
|
4
4
|
// ============================================================================
|
|
@@ -6,6 +6,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
// GEEN <Header /> hier — die levert de shell.
|
|
7
7
|
// ============================================================================
|
|
8
8
|
import { OrderLogboek } from "./OrderLogboek";
|
|
9
|
+
import { AfrondWachtrijCard } from "./AfrondWachtrijCard";
|
|
10
|
+
import { TaakGezondheidCard } from "./TaakGezondheidCard";
|
|
9
11
|
export function LogistiekEngineQueuePage() {
|
|
10
|
-
return (
|
|
12
|
+
return (_jsxs("div", { className: "space-y-4 p-4", children: [_jsx(AfrondWachtrijCard, {}), _jsx(TaakGezondheidCard, {}), _jsx(OrderLogboek, { titel: "Queue \u2014 volledige orderflow", omschrijving: "Per order precies wat de Logistiek Engine heeft gedaan, waarom, en wat er is gewijzigd. Alleen echt vastgelegde stappen; er wordt niets aangevuld." })] }));
|
|
11
13
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { type NodeTraceGroep } from "../lib/nodeTrace";
|
|
2
|
+
import type { StopReden } from "../lib/stopReden";
|
|
2
3
|
interface Props {
|
|
3
4
|
groep: NodeTraceGroep;
|
|
5
|
+
/** Gevuld als de reis van de order bij dit vakje ophoudt. */
|
|
6
|
+
stop?: StopReden | null;
|
|
4
7
|
orderLabel: string | null;
|
|
5
8
|
debug: boolean;
|
|
6
9
|
onDebug: (aan: boolean) => void;
|
|
7
10
|
onClose: () => void;
|
|
8
11
|
}
|
|
9
|
-
export declare function NodeTracePanel({ groep, orderLabel, debug, onDebug, onClose }: Props): import("react").JSX.Element;
|
|
12
|
+
export declare function NodeTracePanel({ groep, stop, orderLabel, debug, onDebug, onClose }: Props): import("react").JSX.Element;
|
|
10
13
|
export {};
|
|
11
14
|
//# sourceMappingURL=NodeTracePanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeTracePanel.d.ts","sourceRoot":"","sources":["../../src/components/NodeTracePanel.tsx"],"names":[],"mappings":"AAcA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"NodeTracePanel.d.ts","sourceRoot":"","sources":["../../src/components/NodeTracePanel.tsx"],"names":[],"mappings":"AAcA,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAYlD,UAAU,KAAK;IACb,KAAK,EAAE,cAAc,CAAC;IACtB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AA+CD,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,IAAW,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,+BA0LhG"}
|
|
@@ -21,7 +21,7 @@ function Bundel({ item, debug }) {
|
|
|
21
21
|
const items = Array.isArray(item.events) ? item.events : [];
|
|
22
22
|
return (_jsxs("div", { className: "rounded-lg border bg-muted/30", children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), className: "flex w-full items-start gap-3 p-3 text-left", children: [open ? (_jsx(ChevronDown, { className: "mt-1 h-4 w-4 shrink-0" })) : (_jsx(ChevronRight, { className: "mt-1 h-4 w-4 shrink-0" })), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: item.label }), _jsxs(Badge, { variant: "outline", children: [item.aantal, "x"] })] }), _jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: ["Automatische gegevenswijziging \u00B7 laatste ", tijd(item.laatste)] })] })] }), open ? (_jsxs("div", { className: "space-y-2 border-t px-3 py-3", children: [items.slice(0, toon).map((e) => (_jsx(Stap, { e: e, debug: debug }, e.id))), items.length > toon ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => setToon((n) => n + 25), children: ["Toon meer (", items.length - toon, ")"] })) : null] })) : null] }));
|
|
23
23
|
}
|
|
24
|
-
export function NodeTracePanel({ groep, orderLabel, debug, onDebug, onClose }) {
|
|
24
|
+
export function NodeTracePanel({ groep, stop = null, orderLabel, debug, onDebug, onClose }) {
|
|
25
25
|
const events = Array.isArray(groep.events) ? groep.events : [];
|
|
26
26
|
const [toon, setToon] = useState(EERSTE_AANTAL);
|
|
27
27
|
const samenvatting = useMemo(() => samenvatVak(groep), [groep]);
|
|
@@ -31,7 +31,13 @@ export function NodeTracePanel({ groep, orderLabel, debug, onDebug, onClose }) {
|
|
|
31
31
|
const zichtbaar = debug ? ruw.slice(0, toon) : regels.slice(0, toon);
|
|
32
32
|
const totaal = debug ? ruw.length : regels.length;
|
|
33
33
|
const calc = samenvatting.berekening;
|
|
34
|
-
return (_jsxs("div", { className: "pointer-events-auto absolute right-3 top-16 bottom-16 z-30 flex w-[26rem] max-w-[90%] flex-col rounded-xl border border-border bg-background shadow-xl", children: [_jsxs("div", { className: "flex items-start justify-between gap-2 border-b border-border px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "truncate text-sm font-semibold", children: flowNodeLabel(groep.nodeId) }), _jsx("p", { className: "truncate text-xs text-muted-foreground", children: orderLabel ?? "Order" })] }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Sluiten", onClick: onClose, children: _jsx(X, { className: "h-4 w-4" }) })] }), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto", children: [_jsxs("div", { className:
|
|
34
|
+
return (_jsxs("div", { className: "pointer-events-auto absolute right-3 top-16 bottom-16 z-30 flex w-[26rem] max-w-[90%] flex-col rounded-xl border border-border bg-background shadow-xl", children: [_jsxs("div", { className: "flex items-start justify-between gap-2 border-b border-border px-3 py-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "truncate text-sm font-semibold", children: flowNodeLabel(groep.nodeId) }), _jsx("p", { className: "truncate text-xs text-muted-foreground", children: orderLabel ?? "Order" })] }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Sluiten", onClick: onClose, children: _jsx(X, { className: "h-4 w-4" }) })] }), _jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto", children: [stop ? (_jsxs("div", { className: `border-b px-3 py-3 ${stop.soort === "mislukt"
|
|
35
|
+
? "border-destructive/40 bg-destructive/5"
|
|
36
|
+
: stop.soort === "klaar"
|
|
37
|
+
? "border-border bg-primary/5"
|
|
38
|
+
: stop.soort === "nietvastgelegd"
|
|
39
|
+
? "border-border bg-muted/40"
|
|
40
|
+
: "border-amber-500/40 bg-amber-500/5"}`, children: [_jsx("p", { className: "text-sm font-semibold", children: stop.titel }), _jsx("p", { className: "mt-1 text-sm", children: stop.reden }), stop.feiten.length > 0 ? (_jsx("ul", { className: "mt-2 space-y-0.5 text-xs text-muted-foreground", children: stop.feiten.map((f) => (_jsx("li", { children: f }, f))) })) : null, stop.volgendeStap ? (_jsxs("p", { className: "mt-2 text-xs text-muted-foreground", children: ["Wat er moet gebeuren: ", stop.volgendeStap] })) : null, stop.verouderd ? (_jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Let op: een instelling is sindsdien gewijzigd, de route kan daardoor afwijken." })) : null] })) : null, _jsxs("div", { className: "space-y-2 border-b border-border px-3 py-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Badge, { className: STATUS_KLEUR[groep.status] ?? "", children: groep.status }), samenvatting.errorClass ? (_jsx(Badge, { variant: "outline", children: FOUTSOORT_LABEL[samenvatting.errorClass] ?? samenvatting.errorClass })) : null] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Veld, { label: "Beslissing", children: uitleg.beslissing }), _jsx(Veld, { label: "Waarom", children: uitleg.waarom }), uitleg.feiten.length > 0 ? (_jsx(Veld, { label: "Bepalend", children: _jsx("span", { className: "block", children: uitleg.feiten.map((f) => (_jsx("span", { className: "block", children: f }, f))) }) })) : null, _jsx(Veld, { label: "Regel", children: uitleg.regel ?? samenvatting.regel }), _jsx(Veld, { label: "Hierna", children: samenvatting.volgendeStap }), uitleg.afgeleid ? (_jsx("p", { className: "text-xs text-muted-foreground", children: "Afgeleid uit de registraties: de Engine legde hier nog geen besluit met reden vast." })) : null] }), calc ? (_jsxs("div", { className: "rounded-md border bg-muted/40 p-2", children: [_jsx("p", { className: "text-sm font-medium", children: "Berekening" }), _jsx(Veld, { label: "Instelling", children: calc.setting }), _jsx(Veld, { label: "Rekenstap", children: calc.formula }), _jsx(Veld, { label: "Uitkomst", children: calc.result }), _jsx(Veld, { label: "Conclusie", children: calc.conclusion })] })) : null, samenvatting.fout ? (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 p-2", children: [_jsx(Veld, { label: "Fout", children: samenvatting.fout }), _jsx(Veld, { label: "Uitleg", children: samenvatting.errorClass ? FOUTSOORT_UITLEG[samenvatting.errorClass] ?? null : null })] })) : null, _jsxs("div", { className: "space-y-1", children: [_jsx(Veld, { label: "Eerste", children: tijd(groep.eerste) }), _jsx(Veld, { label: "Laatste", children: tijd(groep.laatste) }), _jsx(Veld, { label: "Totale duur", children: groep.duurMs === null ? null : duur(groep.duurMs) }), _jsx(Veld, { label: "Pogingen", children: samenvatting.pogingen > 0 ? String(samenvatting.pogingen) : null }), _jsx(Veld, { label: "Volgende poging", children: samenvatting.volgendePoging ? tijd(samenvatting.volgendePoging) : null })] }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [samenvatting.aantalBeslissingen, " beslismoment", samenvatting.aantalBeslissingen === 1 ? "" : "en", " van de Engine", samenvatting.aantalAutomatisch > 0
|
|
35
41
|
? ` · ${samenvatting.aantalAutomatisch} automatische gegevenswijziging${samenvatting.aantalAutomatisch === 1 ? "" : "en"}`
|
|
36
42
|
: ""] })] }), _jsxs("div", { className: "flex items-center justify-between px-3 py-2", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Stappen in dit vakje" }), _jsx(Button, { size: "sm", variant: debug ? "default" : "outline", onClick: () => {
|
|
37
43
|
setToon(EERSTE_AANTAL);
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { type StopReden } from "../lib/stopReden";
|
|
2
|
+
interface Props {
|
|
2
3
|
orderRef: string;
|
|
4
|
+
/** De reden bij het laatste vakje van de route (uit de flowkaart). */
|
|
5
|
+
stop?: StopReden | null;
|
|
6
|
+
/** Het vakje waar de reis ophoudt. */
|
|
7
|
+
stopNode?: string | null;
|
|
3
8
|
onNode?: (nodeId: string) => void;
|
|
4
|
-
}
|
|
9
|
+
}
|
|
10
|
+
export declare function OrderStopBanner({ orderRef, stop, stopNode, onNode }: Props): import("react").JSX.Element | null;
|
|
11
|
+
export {};
|
|
5
12
|
//# sourceMappingURL=OrderStopBanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrderStopBanner.d.ts","sourceRoot":"","sources":["../../src/components/OrderStopBanner.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"OrderStopBanner.d.ts","sourceRoot":"","sources":["../../src/components/OrderStopBanner.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7D,UAAU,KAAK;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,IAAI,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAkBD,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,IAAW,EAAE,QAAe,EAAE,MAAM,EAAE,EAAE,KAAK,sCAqCxF"}
|
|
@@ -1,22 +1,36 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// ============================================================================
|
|
3
|
-
// src/components/OrderStopBanner.tsx — waar staat deze order stil?
|
|
3
|
+
// src/components/OrderStopBanner.tsx — waar staat deze order stil, en waarom?
|
|
4
4
|
// ============================================================================
|
|
5
|
-
// Boven de flowkaart: bij welk vakje de
|
|
6
|
-
//
|
|
5
|
+
// Boven de flowkaart: bij welk vakje de reis van de order ophoudt, waarom dat
|
|
6
|
+
// zo is, wat de bepalende gegevens zijn en wat er moet gebeuren. Alleen lezen.
|
|
7
7
|
// ============================================================================
|
|
8
|
-
import { AlertTriangle, Clock } from "lucide-react";
|
|
8
|
+
import { AlertTriangle, CheckCircle2, Clock } from "lucide-react";
|
|
9
9
|
import { useOrderTraceStand } from "../hooks/useOrderTrace";
|
|
10
10
|
import { flowNodeLabel } from "../lib/flowNodes";
|
|
11
|
-
import {
|
|
12
|
-
|
|
11
|
+
import { stopReden } from "../lib/stopReden";
|
|
12
|
+
import { Veld, sinds, tijd } from "./OrderTraceDetails";
|
|
13
|
+
const KLEUR = {
|
|
14
|
+
mislukt: "border-destructive/50 bg-destructive/5",
|
|
15
|
+
wachtrij: "border-amber-500/40 bg-amber-500/5",
|
|
16
|
+
handeling: "border-amber-500/40 bg-amber-500/5",
|
|
17
|
+
nietvastgelegd: "border-border bg-muted/40",
|
|
18
|
+
klaar: "border-primary/40 bg-primary/5",
|
|
19
|
+
};
|
|
20
|
+
const KOP = {
|
|
21
|
+
mislukt: "ORDER GESTOPT BIJ",
|
|
22
|
+
wachtrij: "ORDER WACHT BIJ",
|
|
23
|
+
handeling: "ORDER WACHT BIJ",
|
|
24
|
+
nietvastgelegd: "FLOW STOPT BIJ",
|
|
25
|
+
klaar: "FLOW EINDIGT BIJ",
|
|
26
|
+
};
|
|
27
|
+
export function OrderStopBanner({ orderRef, stop = null, stopNode = null, onNode }) {
|
|
13
28
|
const { stand } = useOrderTraceStand(orderRef);
|
|
14
|
-
|
|
29
|
+
// Komt de reden niet uit de kaart, dan leiden we hem af uit de stand.
|
|
30
|
+
const node = stopNode ?? stand?.stuckNode ?? stand?.lastNode ?? null;
|
|
31
|
+
const reden = stop ?? (node ? stopReden({ nodeId: node, stand: stand ?? null }) : null);
|
|
32
|
+
if (!reden)
|
|
15
33
|
return null;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
if (!gestopt && !wacht)
|
|
19
|
-
return null;
|
|
20
|
-
const node = stand.stuckNode ?? null;
|
|
21
|
-
return (_jsxs("div", { className: `rounded-lg border p-3 ${gestopt ? "border-destructive/50 bg-destructive/5" : "border-amber-500/40 bg-amber-500/5"}`, children: [_jsxs("p", { className: "flex items-center gap-2 text-sm font-semibold", children: [gestopt ? _jsx(AlertTriangle, { className: "h-4 w-4" }) : _jsx(Clock, { className: "h-4 w-4" }), gestopt ? "ORDER GESTOPT BIJ" : "ORDER WACHT BIJ", ":", " ", node ? flowNodeLabel(node) : stand.stuckStep ?? "onbekende stap", node && onNode ? (_jsx("button", { type: "button", className: "text-xs font-normal underline", onClick: () => onNode(node), children: "toon dit vakje" })) : null] }), _jsx(Veld, { label: "Reden", children: stand.stuckReason ?? stand.queueError }), _jsx(Veld, { label: "Soort", children: stand.errorClass ? FOUTSOORT_LABEL[stand.errorClass] ?? stand.errorClass : null }), _jsx(Veld, { label: "Geblokkeerd sinds", children: stand.blockedSince ? `${tijd(stand.blockedSince)} (${sinds(stand.blockedSince)})` : null }), _jsx(Veld, { label: "Automatische pogingen", children: stand.tries > 0 ? String(stand.tries) : null }), _jsx(Veld, { label: "Volgende poging", children: stand.nextAttemptAt ? tijd(stand.nextAttemptAt) : null }), _jsx(Veld, { label: "Wat moet er gebeuren", children: stand.nextStep }), _jsx(Veld, { label: "Wachtrij", children: stand.queueStatus })] }));
|
|
34
|
+
const Icoon = reden.soort === "mislukt" ? AlertTriangle : reden.soort === "klaar" ? CheckCircle2 : Clock;
|
|
35
|
+
return (_jsxs("div", { className: `rounded-lg border p-3 ${KLEUR[reden.soort]}`, children: [_jsxs("p", { className: "flex flex-wrap items-center gap-2 text-sm font-semibold", children: [_jsx(Icoon, { className: "h-4 w-4" }), KOP[reden.soort], ": ", node ? flowNodeLabel(node) : stand?.stuckStep ?? "onbekende stap", node && onNode ? (_jsx("button", { type: "button", className: "text-xs font-normal underline", onClick: () => onNode(node), children: "toon dit vakje" })) : null] }), _jsx("p", { className: "mt-1 text-sm", children: reden.reden }), reden.feiten.length > 0 ? (_jsx("ul", { className: "mt-2 space-y-0.5 text-xs text-muted-foreground", children: reden.feiten.map((f) => (_jsx("li", { children: f }, f))) })) : null, _jsx(Veld, { label: "Geblokkeerd sinds", children: stand?.blockedSince ? `${tijd(stand.blockedSince)} (${sinds(stand.blockedSince)})` : null }), _jsx(Veld, { label: "Wat moet er gebeuren", children: reden.volgendeStap }), _jsx(Veld, { label: "Wachtrij", children: stand?.queueStatus ?? null })] }));
|
|
22
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OrderTraceDetails.d.ts","sourceRoot":"","sources":["../../src/components/OrderTraceDetails.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"OrderTraceDetails.d.ts","sourceRoot":"","sources":["../../src/components/OrderTraceDetails.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAIhE,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMlD,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMnD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM/C,CAAC;AAEF,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAIzD;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAKzD;AAED,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAK1D;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAS1D;AAED,wBAAgB,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,sCAOnD;AAED,wBAAgB,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,sCAQrF;AAED,+EAA+E;AAC/E,wBAAgB,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE;IAAE,CAAC,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,+BAyJ3G"}
|
|
@@ -10,6 +10,7 @@ import { useState } from "react";
|
|
|
10
10
|
import { Badge } from "@flowselections/core";
|
|
11
11
|
import { AlertTriangle, ChevronDown, ChevronRight, Database, ExternalLink } from "lucide-react";
|
|
12
12
|
import { flowNodeLabel } from "../lib/flowNodes";
|
|
13
|
+
import { foutTekst } from "../lib/foutTekst";
|
|
13
14
|
export const FOUTSOORT_LABEL = {
|
|
14
15
|
technisch: "Technische fout",
|
|
15
16
|
ontbrekende_gegevens: "Ontbrekende gegevens",
|
|
@@ -83,5 +84,5 @@ export function Stap({ e, debug, open: standaardOpen }) {
|
|
|
83
84
|
const [open, setOpen] = useState(standaardOpen ?? e.status === "mislukt");
|
|
84
85
|
const calc = (e.calc ?? null);
|
|
85
86
|
const fout = e.status === "mislukt";
|
|
86
|
-
return (_jsxs("div", { className: `rounded-lg border ${fout ? "border-destructive/50 bg-destructive/5" : "bg-card"}`, children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), className: "flex w-full items-start gap-3 p-3 text-left", children: [open ? _jsx(ChevronDown, { className: "mt-1 h-4 w-4 shrink-0" }) : _jsx(ChevronRight, { className: "mt-1 h-4 w-4 shrink-0" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: e.step }), _jsx(Badge, { className: STATUS_KLEUR[e.status] ?? "", children: e.status }), e.errorClass ? _jsx(Badge, { variant: "outline", children: FOUTSOORT_LABEL[e.errorClass] ?? e.errorClass }) : null, e.nodeId ? _jsx(Badge, { variant: "outline", children: flowNodeLabel(e.nodeId) }) : null] }), _jsxs("div", { className: "mt-1 flex flex-wrap gap-x-4 text-xs text-muted-foreground", children: [_jsx("span", { children: tijd(e.createdAt) }), _jsxs("span", { children: ["Duur: ", duur(e.durationMs)] }), e.actor ? _jsxs("span", { children: ["Door: ", e.actor] }) : null, e.attempts > 0 ? _jsxs("span", { children: ["Poging ", e.attempts] }) : null] }), e.reason || e.decision ? (_jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: e.reason ?? e.decision })) : null] })] }), open ? (_jsxs("div", { className: "space-y-3 border-t px-3 py-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Veld, { label: "Beslissing", children: e.decision }), _jsx(Veld, { label: "Waarom", children: e.reason }), _jsx(Veld, { label: "Regel", children: e.rule }), _jsx(Veld, { label: "Volgende stap", children: e.nextStep }), _jsx(Veld, { label: "Volgende poging", children: e.nextAttemptAt ? tijd(e.nextAttemptAt) : null })] }), calc ? (_jsxs("div", { className: "rounded-md border bg-muted/40 p-3", children: [_jsx("p", { className: "text-sm font-medium", children: "Berekening" }), _jsx(Veld, { label: "Instelling", children: calc.setting }), _jsx(Veld, { label: "Rekenstap", children: calc.formula }), _jsx(Veld, { label: "Uitkomst", children: calc.result }), _jsx(Veld, { label: "Conclusie", children: calc.conclusion }), calc.values ? _jsx(Json, { waarde: calc.values }) : null] })) : null, fout ? (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 p-3", children: [_jsxs("p", { className: "flex items-center gap-2 text-sm font-medium text-destructive", children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), " Fout bij deze stap"] }), _jsx(Veld, { label: "Soort", children: e.errorClass ? FOUTSOORT_LABEL[e.errorClass] ?? e.errorClass : "Technische fout" }), _jsx(Veld, { label: "Uitleg", children: e.errorClass ? FOUTSOORT_UITLEG[e.errorClass] ?? null : null }), _jsx(Veld, { label: "Melding", children: e.error }), _jsx(Veld, { label: "Pogingen", children: e.attempts > 0 ? String(e.attempts) : null })] })) : null, e.dbTable ? (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("p", { className: "flex items-center gap-2 text-sm font-medium", children: [_jsx(Database, { className: "h-4 w-4" }), " Gegevens gewijzigd"] }), _jsx(Veld, { label: "Tabel", children: e.dbTable }), _jsx(Veld, { label: "Actie", children: e.dbAction }), e.dbOld ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-2 text-xs font-medium", children: "Voor" }), _jsx(Json, { waarde: e.dbOld })] })) : null, e.dbNew ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-2 text-xs font-medium", children: "Na" }), _jsx(Json, { waarde: e.dbNew })] })) : null] })) : null, e.externalSystem ? (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("p", { className: "flex items-center gap-2 text-sm font-medium", children: [_jsx(ExternalLink, { className: "h-4 w-4" }), " Extern systeem"] }), _jsx(Veld, { label: "Systeem", children: e.externalSystem }), _jsx(Veld, { label: "Actie", children: e.externalAction }), _jsx(Veld, { label: "Kenmerk", children: e.externalRef }), _jsx(Veld, { label: "Resultaat", children: e.externalStatus }), _jsx(Json, { waarde: e.externalResponse })] })) : null, e.reads ? (_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium", children: "Gelezen gegevens" }), _jsx(Json, { waarde: e.reads })] })) : null, e.values ? (_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium", children: "Gebruikte waarden" }), _jsx(Json, { waarde: e.values })] })) : null, debug ? (_jsxs("div", { className: "rounded-md border border-dashed p-3", children: [_jsx("p", { className: "text-sm font-medium", children: "Technische gegevens" }), _jsx(Veld, { label: "Trace ID", children: e.traceId }), _jsx(Veld, { label: "Gebeurtenis ID", children: e.id }), _jsx(Veld, { label: "Vakje", children: e.nodeId }), _jsx(Veld, { label: "Fase", children: e.phase }), _jsx(Veld, { label: "Kar", children: e.cartRef }), _jsx(Veld, { label: "Pakbon", children: e.slipRef }), _jsx(Veld, { label: "Regel in database", children: e.dbRecord }), _jsxs("div", { className: "mt-2 grid gap-2 md:grid-cols-2", children: [_jsxs("div", { children: [_jsx("p", { className: "text-xs font-medium", children: "Invoer" }), _jsx(Json, { waarde: e.input })] }), _jsxs("div", { children: [_jsx("p", { className: "text-xs font-medium", children: "Uitvoer" }), _jsx(Json, { waarde: e.output })] })] })] })) : null] })) : null] }));
|
|
87
|
+
return (_jsxs("div", { className: `rounded-lg border ${fout ? "border-destructive/50 bg-destructive/5" : "bg-card"}`, children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), className: "flex w-full items-start gap-3 p-3 text-left", children: [open ? _jsx(ChevronDown, { className: "mt-1 h-4 w-4 shrink-0" }) : _jsx(ChevronRight, { className: "mt-1 h-4 w-4 shrink-0" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "font-medium", children: e.step }), _jsx(Badge, { className: STATUS_KLEUR[e.status] ?? "", children: e.status }), e.errorClass ? _jsx(Badge, { variant: "outline", children: FOUTSOORT_LABEL[e.errorClass] ?? e.errorClass }) : null, e.nodeId ? _jsx(Badge, { variant: "outline", children: flowNodeLabel(e.nodeId) }) : null] }), _jsxs("div", { className: "mt-1 flex flex-wrap gap-x-4 text-xs text-muted-foreground", children: [_jsx("span", { children: tijd(e.createdAt) }), _jsxs("span", { children: ["Duur: ", duur(e.durationMs)] }), e.actor ? _jsxs("span", { children: ["Door: ", e.actor] }) : null, e.attempts > 0 ? _jsxs("span", { children: ["Poging ", e.attempts] }) : null] }), e.reason || e.decision ? (_jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: e.reason ?? e.decision })) : null] })] }), open ? (_jsxs("div", { className: "space-y-3 border-t px-3 py-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Veld, { label: "Beslissing", children: e.decision }), _jsx(Veld, { label: "Waarom", children: e.reason }), _jsx(Veld, { label: "Regel", children: e.rule }), _jsx(Veld, { label: "Volgende stap", children: e.nextStep }), _jsx(Veld, { label: "Volgende poging", children: e.nextAttemptAt ? tijd(e.nextAttemptAt) : null })] }), calc ? (_jsxs("div", { className: "rounded-md border bg-muted/40 p-3", children: [_jsx("p", { className: "text-sm font-medium", children: "Berekening" }), _jsx(Veld, { label: "Instelling", children: calc.setting }), _jsx(Veld, { label: "Rekenstap", children: calc.formula }), _jsx(Veld, { label: "Uitkomst", children: calc.result }), _jsx(Veld, { label: "Conclusie", children: calc.conclusion }), calc.values ? _jsx(Json, { waarde: calc.values }) : null] })) : null, fout ? (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 p-3", children: [_jsxs("p", { className: "flex items-center gap-2 text-sm font-medium text-destructive", children: [_jsx(AlertTriangle, { className: "h-4 w-4" }), " Fout bij deze stap"] }), _jsx(Veld, { label: "Soort", children: e.errorClass ? FOUTSOORT_LABEL[e.errorClass] ?? e.errorClass : "Technische fout" }), _jsx(Veld, { label: "Uitleg", children: e.errorClass ? FOUTSOORT_UITLEG[e.errorClass] ?? null : null }), _jsx(Veld, { label: "Melding", children: foutTekst(e.error) }), e.error && foutTekst(e.error) !== e.error ? (_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: e.error })] })) : null, _jsx(Veld, { label: "Pogingen", children: e.attempts > 0 ? String(e.attempts) : null })] })) : null, e.dbTable ? (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("p", { className: "flex items-center gap-2 text-sm font-medium", children: [_jsx(Database, { className: "h-4 w-4" }), " Gegevens gewijzigd"] }), _jsx(Veld, { label: "Tabel", children: e.dbTable }), _jsx(Veld, { label: "Actie", children: e.dbAction }), e.dbOld ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-2 text-xs font-medium", children: "Voor" }), _jsx(Json, { waarde: e.dbOld })] })) : null, e.dbNew ? (_jsxs(_Fragment, { children: [_jsx("p", { className: "mt-2 text-xs font-medium", children: "Na" }), _jsx(Json, { waarde: e.dbNew })] })) : null] })) : null, e.externalSystem ? (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("p", { className: "flex items-center gap-2 text-sm font-medium", children: [_jsx(ExternalLink, { className: "h-4 w-4" }), " Extern systeem"] }), _jsx(Veld, { label: "Systeem", children: e.externalSystem }), _jsx(Veld, { label: "Actie", children: e.externalAction }), _jsx(Veld, { label: "Kenmerk", children: e.externalRef }), _jsx(Veld, { label: "Resultaat", children: e.externalStatus }), _jsx(Json, { waarde: e.externalResponse })] })) : null, e.reads ? (_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium", children: "Gelezen gegevens" }), _jsx(Json, { waarde: e.reads })] })) : null, e.values ? (_jsxs("div", { children: [_jsx("p", { className: "text-sm font-medium", children: "Gebruikte waarden" }), _jsx(Json, { waarde: e.values })] })) : null, debug ? (_jsxs("div", { className: "rounded-md border border-dashed p-3", children: [_jsx("p", { className: "text-sm font-medium", children: "Technische gegevens" }), _jsx(Veld, { label: "Trace ID", children: e.traceId }), _jsx(Veld, { label: "Gebeurtenis ID", children: e.id }), _jsx(Veld, { label: "Vakje", children: e.nodeId }), _jsx(Veld, { label: "Fase", children: e.phase }), _jsx(Veld, { label: "Kar", children: e.cartRef }), _jsx(Veld, { label: "Pakbon", children: e.slipRef }), _jsx(Veld, { label: "Regel in database", children: e.dbRecord }), _jsxs("div", { className: "mt-2 grid gap-2 md:grid-cols-2", children: [_jsxs("div", { children: [_jsx("p", { className: "text-xs font-medium", children: "Invoer" }), _jsx(Json, { waarde: e.input })] }), _jsxs("div", { children: [_jsx("p", { className: "text-xs font-medium", children: "Uitvoer" }), _jsx(Json, { waarde: e.output })] })] })] })) : null] })) : null] }));
|
|
87
88
|
}
|