@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
package/README.md
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
# logistiek Engine
|
|
2
|
-
|
|
3
|
-
blank project start
|
|
4
|
-
|
|
5
|
-
This project was built with [Lovable](https://lovable.dev).
|
|
6
|
-
|
|
7
|
-
## Build with Lovable
|
|
8
|
-
|
|
9
|
-
Continue developing this project in the [Lovable editor](https://lovable.dev/projects/316ec9c5-0f01-408a-b7ec-3d4dccf9b65d).
|
|
10
|
-
|
|
11
|
-
- **Ship faster**: describe what you want to build and Lovable handles the code.
|
|
12
|
-
- **Stay in sync**: every change made in Lovable is committed straight to this repository.
|
|
13
|
-
- **Full ownership**: this code is yours. Push to `main` on GitHub and your changes sync back into Lovable, ready for your next prompt.
|
|
14
|
-
|
|
15
|
-
## Development
|
|
16
|
-
|
|
17
|
-
Prefer working locally? You need Node.js and npm — [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
|
|
18
|
-
|
|
19
|
-
```sh
|
|
20
|
-
git clone <this-repository-url>
|
|
21
|
-
cd <repository-name>
|
|
22
|
-
npm i
|
|
23
|
-
npm run dev
|
|
24
|
-
```
|
|
1
|
+
# logistiek Engine
|
|
2
|
+
|
|
3
|
+
blank project start
|
|
4
|
+
|
|
5
|
+
This project was built with [Lovable](https://lovable.dev).
|
|
6
|
+
|
|
7
|
+
## Build with Lovable
|
|
8
|
+
|
|
9
|
+
Continue developing this project in the [Lovable editor](https://lovable.dev/projects/316ec9c5-0f01-408a-b7ec-3d4dccf9b65d).
|
|
10
|
+
|
|
11
|
+
- **Ship faster**: describe what you want to build and Lovable handles the code.
|
|
12
|
+
- **Stay in sync**: every change made in Lovable is committed straight to this repository.
|
|
13
|
+
- **Full ownership**: this code is yours. Push to `main` on GitHub and your changes sync back into Lovable, ready for your next prompt.
|
|
14
|
+
|
|
15
|
+
## Development
|
|
16
|
+
|
|
17
|
+
Prefer working locally? You need Node.js and npm — [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating).
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
git clone <this-repository-url>
|
|
21
|
+
cd <repository-name>
|
|
22
|
+
npm i
|
|
23
|
+
npm run dev
|
|
24
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AfrondWachtrijCard.d.ts","sourceRoot":"","sources":["../../src/components/AfrondWachtrijCard.tsx"],"names":[],"mappings":"AAgBA,wBAAgB,kBAAkB,gCAqFjC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/AfrondWachtrijCard.tsx — zichtbaarheid op de afronding
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Toont wat er na de eindcontrole nog moet worden afgerond, met waarschuwing
|
|
6
|
+
// wanneer iets te lang wacht. Alleen lezen, behalve de knoppen.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
import { AlertTriangle, CheckCircle2, RefreshCw } from "lucide-react";
|
|
9
|
+
import { useAfrondWachtrij } from "../hooks/useAfrondWachtrij";
|
|
10
|
+
function duur(seconden) {
|
|
11
|
+
if (seconden < 60)
|
|
12
|
+
return `${seconden} sec`;
|
|
13
|
+
if (seconden < 3600)
|
|
14
|
+
return `${Math.round(seconden / 60)} min`;
|
|
15
|
+
return `${Math.round(seconden / 360) / 10} uur`;
|
|
16
|
+
}
|
|
17
|
+
export function AfrondWachtrijCard() {
|
|
18
|
+
const { stand, regels, laden, fout, herlaad, opnieuw, naloop } = useAfrondWachtrij();
|
|
19
|
+
const traag = stand.oudsteWachttijdSeconden > 300;
|
|
20
|
+
const alarm = traag || stand.mislukt > 0;
|
|
21
|
+
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: "Afronding na controle" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Orders waarvan de karren zijn afgemeld en die nog moeten worden afgerond." })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { type: "button", onClick: () => void naloop(), className: "rounded-md border px-3 py-1.5 text-sm hover:bg-accent", children: "Naloop uitvoeren" }), _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, _jsxs("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-4", children: [_jsx(Cijfer, { label: "Wachtend", waarde: stand.wachtend }), _jsx(Cijfer, { label: "Bezig", waarde: stand.bezig }), _jsx(Cijfer, { label: "Mislukt", waarde: stand.mislukt, nadruk: stand.mislukt > 0 }), _jsx(Cijfer, { label: "Oudste wacht", tekst: duur(stand.oudsteWachttijdSeconden), nadruk: traag })] }), !laden && !alarm && stand.wachtend === 0 && stand.bezig === 0 ? (_jsxs("p", { className: "mt-3 flex items-center gap-2 text-sm text-muted-foreground", children: [_jsx(CheckCircle2, { className: "h-4 w-4" }), " Alles is afgerond."] })) : null, alarm ? (_jsxs("p", { className: "mt-3 flex items-start gap-2 text-sm text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0" }), stand.mislukt > 0
|
|
22
|
+
? "Er zijn orders die niet konden worden afgerond. Bekijk de reden hieronder en probeer opnieuw."
|
|
23
|
+
: "Er wacht een order langer dan vijf minuten. Controleer of de achtergrondtaak draait."] })) : null, regels.length > 0 ? (_jsx("ul", { className: "mt-4 space-y-2", children: regels.map((r) => (_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: r.orderId }), _jsxs("span", { className: "text-muted-foreground", children: [r.status, " \u00B7 poging ", r.pogingen, r.maxPogingen ? `/${r.maxPogingen}` : ""] })] }), r.reden ? _jsx("p", { className: "text-muted-foreground", children: r.reden }) : null, r.fout ? _jsx("p", { className: "mt-1 text-destructive", children: r.fout }) : null, r.status === "failed" ? (_jsx("button", { type: "button", onClick: () => void opnieuw(r.orderId), className: "mt-2 rounded-md border px-2 py-1 text-xs hover:bg-accent", children: "Opnieuw proberen" })) : null] }, r.orderId))) })) : null] }));
|
|
24
|
+
}
|
|
25
|
+
function Cijfer({ label, waarde, tekst, nadruk, }) {
|
|
26
|
+
return (_jsxs("div", { className: "rounded-md border p-3", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: label }), _jsx("p", { className: `text-lg font-semibold ${nadruk ? "text-destructive" : ""}`, children: tekst ?? waarde ?? 0 })] }));
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BeladingsafwijkingenCard.d.ts","sourceRoot":"","sources":["../../src/components/BeladingsafwijkingenCard.tsx"],"names":[],"mappings":"AA0FA,wBAAgB,wBAAwB,gCA8EvC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// src/components/BeladingsafwijkingenCard.tsx — belading naast de Floriday-stand
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Toont per gevonden afwijking welk product of welke order het betreft, wat wij
|
|
6
|
+
// hebben opgeslagen, wat Floriday nu zegt en sinds wanneer het verschil bestaat.
|
|
7
|
+
// Wat veilig kon worden bijgewerkt is al automatisch rechtgezet; de rest staat
|
|
8
|
+
// hier als "beoordelen".
|
|
9
|
+
// GEEN <Header /> hier — die levert de shell.
|
|
10
|
+
// ============================================================================
|
|
11
|
+
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, } from "@flowselections/core";
|
|
12
|
+
import { Boxes, Check, RefreshCw } from "lucide-react";
|
|
13
|
+
import { useBeladingsafwijkingen, } from "../hooks/useBeladingsafwijkingen";
|
|
14
|
+
function beladingTekst(b) {
|
|
15
|
+
const deel = [
|
|
16
|
+
b.piecesPerPackage == null ? "?" : String(b.piecesPerPackage),
|
|
17
|
+
b.packagesPerLayer == null ? "?" : String(b.packagesPerLayer),
|
|
18
|
+
b.layersPerLoadCarrier == null ? "?" : String(b.layersPerLoadCarrier),
|
|
19
|
+
];
|
|
20
|
+
const basis = `${deel[0]} per fust · ${deel[1]} fusten per laag · ${deel[2]} lagen per kar`;
|
|
21
|
+
return b.loadCarrier ? `${basis} (${b.loadCarrier.toLowerCase().replace(/_/g, " ")})` : basis;
|
|
22
|
+
}
|
|
23
|
+
function sindsTekst(sinds) {
|
|
24
|
+
if (!sinds)
|
|
25
|
+
return "onbekend";
|
|
26
|
+
const ms = Date.now() - new Date(sinds).getTime();
|
|
27
|
+
const minuten = Math.max(0, Math.round(ms / 60000));
|
|
28
|
+
if (minuten < 60)
|
|
29
|
+
return `${minuten} min`;
|
|
30
|
+
const uren = Math.round(minuten / 60);
|
|
31
|
+
if (uren < 48)
|
|
32
|
+
return `${uren} uur`;
|
|
33
|
+
return `${Math.round(uren / 24)} dagen`;
|
|
34
|
+
}
|
|
35
|
+
function Regel({ a, onAfsluiten, }) {
|
|
36
|
+
return (_jsxs("div", { className: "space-y-2 rounded-lg border p-3", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(Badge, { variant: a.beoordelen ? "destructive" : "secondary", children: a.beoordelen ? "Beoordelen" : "Wordt bijgewerkt" }), _jsxs("span", { className: "text-sm font-medium", children: [a.soort === "product" ? "Product" : "Order", " ", a.orderNummer ?? a.productNaam ?? "onbekend"] }), a.orderNummer && a.productNaam ? (_jsx("span", { className: "text-muted-foreground text-xs", children: a.productNaam })) : null, _jsxs("span", { className: "text-muted-foreground ml-auto text-xs", children: ["sinds ", sindsTekst(a.sinds)] })] }), _jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [_jsxs("div", { className: "rounded-md border p-2", children: [_jsx("div", { className: "text-muted-foreground text-xs", children: "Bij ons opgeslagen" }), _jsx("div", { className: "text-sm tabular-nums", children: beladingTekst(a.lokaal) })] }), _jsxs("div", { className: "rounded-md border p-2", children: [_jsx("div", { className: "text-muted-foreground text-xs", children: "Floriday nu" }), _jsx("div", { className: "text-sm tabular-nums", children: beladingTekst(a.floriday) })] })] }), a.reden ? _jsx("p", { className: "text-muted-foreground text-xs", children: a.reden }) : null, a.beoordelen ? (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => onAfsluiten(a.id), children: [_jsx(Check, { className: "mr-2 h-4 w-4" }), "Beoordeeld, afsluiten"] })) : null] }));
|
|
37
|
+
}
|
|
38
|
+
export function BeladingsafwijkingenCard() {
|
|
39
|
+
const { stand, afwijkingen, laden, bezig, fout, nuControleren, afsluiten } = useBeladingsafwijkingen();
|
|
40
|
+
const lijst = Array.isArray(afwijkingen) ? afwijkingen : [];
|
|
41
|
+
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(Boxes, { className: "h-5 w-5 text-primary" }), "Beladingsafwijkingen"] }), _jsx(CardDescription, { children: "Elk uur vergelijken we de opgeslagen belading met de laatste Floriday-gegevens. Wat veilig kan, wordt vanzelf bijgewerkt; de rest wacht op uw beoordeling." })] }), _jsx(Button, { variant: "outline", size: "sm", onClick: () => void nuControleren(), disabled: bezig || laden, children: _jsx(RefreshCw, { className: `h-4 w-4 ${bezig ? "animate-spin" : ""}` }) })] }), _jsxs(CardContent, { className: "space-y-4", children: [fout ? _jsx("p", { className: "text-destructive text-sm", children: fout }) : null, laden && lijst.length === 0 ? (_jsx(Skeleton, { className: "h-24 w-full" })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: [_jsxs("div", { className: "rounded-lg border p-3", children: [_jsx("div", { className: "text-muted-foreground text-xs", children: "Openstaand" }), _jsx("div", { className: "text-2xl font-semibold tabular-nums", children: stand.openTotaal })] }), _jsxs("div", { className: "rounded-lg border p-3", children: [_jsx("div", { className: "text-muted-foreground text-xs", children: "Mens moet kijken" }), _jsx("div", { className: "text-2xl font-semibold tabular-nums", children: stand.beoordelen })] }), _jsxs("div", { className: "rounded-lg border p-3", children: [_jsx("div", { className: "text-muted-foreground text-xs", children: "Betrokken orders" }), _jsx("div", { className: "text-2xl font-semibold tabular-nums", children: stand.orders })] }), _jsxs("div", { className: "rounded-lg border p-3", children: [_jsx("div", { className: "text-muted-foreground text-xs", children: "Productgegevens" }), _jsx("div", { className: "text-2xl font-semibold tabular-nums", children: stand.producten })] })] }), lijst.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Geen verschillen gevonden. Onze belading komt overeen met Floriday." })) : (_jsx("div", { className: "space-y-3", children: lijst.map((a) => (_jsx(Regel, { a: a, onAfsluiten: (id) => void afsluiten(id) }, a.id))) })), _jsxs("p", { className: "text-muted-foreground text-xs", children: ["Laatste meting: ", stand.laatstGemeten ? sindsTekst(stand.laatstGemeten) + " geleden" : "nog niet", stand.laatstHersteld
|
|
42
|
+
? ` · laatst automatisch bijgewerkt ${sindsTekst(stand.laatstHersteld)} geleden`
|
|
43
|
+
: "", ". Regels die handmatig zijn vastgezet worden nooit automatisch gewijzigd."] })] }))] })] }));
|
|
44
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "@xyflow/react/dist/style.css";
|
|
2
2
|
import { type FlowTree } from "../lib/flowTree";
|
|
3
3
|
import type { RouteMarker } from "../lib/flowRoute";
|
|
4
|
+
import type { StopReden } from "../lib/stopReden";
|
|
4
5
|
import type { NodeTraceGroep } from "../lib/nodeTrace";
|
|
5
6
|
import type { RuleEngineSettings } from "../lib/ruleEngineSchema";
|
|
6
7
|
export type { RouteMarker };
|
|
@@ -11,6 +12,8 @@ interface Props {
|
|
|
11
12
|
settings: RuleEngineSettings;
|
|
12
13
|
/** Markeringen per knoop-id (vastgelopen / bezig / klaar) van een gekozen orderversie. */
|
|
13
14
|
markers?: Map<string, RouteMarker>;
|
|
15
|
+
/** Vakjes die vastlopen, met de reden erbij. Wordt als foutmelding getoond. */
|
|
16
|
+
problemen?: Map<string, StopReden>;
|
|
14
17
|
/** Wat de Engine per vakje voor de gekozen order heeft vastgelegd. */
|
|
15
18
|
nodeTrace?: Map<string, NodeTraceGroep> | null;
|
|
16
19
|
/** Tekst boven de kaart als een orderroute getoond wordt. */
|
|
@@ -23,6 +26,9 @@ interface Props {
|
|
|
23
26
|
onClearRoute?: () => void;
|
|
24
27
|
onSelectStep: (stepId: string) => void;
|
|
25
28
|
onChangeChoice: (storeId: string, fieldKey: string, value: unknown) => void;
|
|
29
|
+
/** Aangeklikt samenkomstpunt (ruitje) om te beheren. */
|
|
30
|
+
mergeId?: string | null;
|
|
31
|
+
onSelectMerge?: (mergeId: string | null) => void;
|
|
26
32
|
}
|
|
27
33
|
export declare function FlowCanvas(props: Props): import("react").JSX.Element;
|
|
28
34
|
//# sourceMappingURL=FlowCanvas.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlowCanvas.d.ts","sourceRoot":"","sources":["../../src/components/FlowCanvas.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FlowCanvas.d.ts","sourceRoot":"","sources":["../../src/components/FlowCanvas.tsx"],"names":[],"mappings":"AAiDA,OAAO,8BAA8B,CAAC;AAEtC,OAAO,EAA6B,KAAK,QAAQ,EAAiB,MAAM,iBAAiB,CAAC;AAC1F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAOlE,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B,UAAU,KAAK;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,kFAAkF;IAClF,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,0FAA0F;IAC1F,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACnC,+EAA+E;IAC/E,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnC,sEAAsE;IACtE,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI,CAAC;IAC/C,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5E,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAClD;AAymCD,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,+BAMtC"}
|
|
@@ -11,7 +11,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
|
11
11
|
import { BaseEdge, Background, BackgroundVariant, EdgeLabelRenderer, Handle, MiniMap, Position, ReactFlow, ReactFlowProvider, getSmoothStepPath, useReactFlow, } from "@xyflow/react";
|
|
12
12
|
import dagre from "@dagrejs/dagre";
|
|
13
13
|
import { Button } from "@flowselections/core";
|
|
14
|
-
import { AlertTriangle, ArrowDownUp, ArrowLeftRight, CheckCircle2, ChevronDown, ChevronRight, Clock, Maximize2, Minimize2, Expand, ListChecks, Pencil, Settings2, Minus, Plus, X, } from "lucide-react";
|
|
14
|
+
import { AlertTriangle, ArrowDownUp, ArrowLeftRight, CheckCircle2, ChevronDown, ChevronRight, ChevronUp, Clock, Maximize2, Minimize2, Expand, ListChecks, Pencil, Settings2, Minus, Plus, X, } from "lucide-react";
|
|
15
15
|
import "@xyflow/react/dist/style.css";
|
|
16
16
|
import { fieldsFor } from "../lib/flowTree";
|
|
17
17
|
import { RuleFieldInput } from "./rule-engine/RuleFieldInput";
|
|
@@ -32,7 +32,7 @@ const NODE_STATE_CLASS = {
|
|
|
32
32
|
disabled: "border-dashed border-border bg-muted text-muted-foreground",
|
|
33
33
|
};
|
|
34
34
|
// ── Lay-out ─────────────────────────────────────────────────────────────────
|
|
35
|
-
function layout(tree, collapsed, richting) {
|
|
35
|
+
function layout(tree, collapsed, richting, markers) {
|
|
36
36
|
const nodes = Array.isArray(tree?.nodes) ? tree.nodes : [];
|
|
37
37
|
const edges = Array.isArray(tree?.edges) ? tree.edges : [];
|
|
38
38
|
const verborgen = (ancestors) => ancestors.some((a) => collapsed.has(a));
|
|
@@ -65,8 +65,9 @@ function layout(tree, collapsed, richting) {
|
|
|
65
65
|
marginy: 40,
|
|
66
66
|
});
|
|
67
67
|
g.setDefaultEdgeLabel(() => ({}));
|
|
68
|
+
const effectieveHoogte = (n) => n.h + (markers?.get(n.id)?.eindpunt ? 112 : 0);
|
|
68
69
|
for (const n of zichtbaar)
|
|
69
|
-
g.setNode(n.id, { width: n.w, height: n
|
|
70
|
+
g.setNode(n.id, { width: n.w, height: effectieveHoogte(n) });
|
|
70
71
|
const alle = [...zichtbareEdges, ...extra];
|
|
71
72
|
for (const e of alle) {
|
|
72
73
|
// Verwijspijlen tellen niet mee voor de rangorde (anders trekt dagre stappen scheef).
|
|
@@ -79,7 +80,7 @@ function layout(tree, collapsed, richting) {
|
|
|
79
80
|
for (const n of zichtbaar) {
|
|
80
81
|
const p = g.node(n.id);
|
|
81
82
|
if (p)
|
|
82
|
-
posities.set(n.id, { x: p.x - n.w / 2, y: p.y - n
|
|
83
|
+
posities.set(n.id, { x: p.x - n.w / 2, y: p.y - effectieveHoogte(n) / 2 });
|
|
83
84
|
}
|
|
84
85
|
return { zichtbaar, edges: alle, posities };
|
|
85
86
|
}
|
|
@@ -134,6 +135,9 @@ function SourceNode({ data }) {
|
|
|
134
135
|
* Klikken opent het paneel met alle vastgelegde stappen van dat vakje.
|
|
135
136
|
*/
|
|
136
137
|
function Markering({ marker, onClick }) {
|
|
138
|
+
// Standaard klein: het vakje eronder blijft leesbaar. Met het pijltje klap
|
|
139
|
+
// je de volledige uitleg open.
|
|
140
|
+
const [open, setOpen] = useState(false);
|
|
137
141
|
if (!marker)
|
|
138
142
|
return null;
|
|
139
143
|
const kleur = marker.kind === "stuck"
|
|
@@ -149,10 +153,47 @@ function Markering({ marker, onClick }) {
|
|
|
149
153
|
marker.count && marker.count > 1 ? `${marker.count} gebeurtenissen` : null,
|
|
150
154
|
marker.attempts && marker.attempts > 1 ? `poging ${marker.attempts}` : null,
|
|
151
155
|
].filter(Boolean);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
const kop = `${marker.kind === "stuck" ? "Vastgelopen: " : "Beslissing: "}${marker.beslissing ?? marker.text}`;
|
|
157
|
+
if (marker.eindpunt && marker.stop) {
|
|
158
|
+
const stopKop = marker.stop.soort === "mislukt"
|
|
159
|
+
? "Flow vastgelopen"
|
|
160
|
+
: marker.stop.soort === "klaar"
|
|
161
|
+
? "Flow afgerond"
|
|
162
|
+
: marker.stop.soort === "nietvastgelegd"
|
|
163
|
+
? "Flow stopt hier"
|
|
164
|
+
: "Flow wacht hier";
|
|
165
|
+
const stand = marker.feiten?.length
|
|
166
|
+
? marker.feiten.slice(0, 2).join(" · ")
|
|
167
|
+
: marker.beslissing ?? marker.text;
|
|
168
|
+
return (_jsx("div", { className: `nodrag nopan absolute left-0 top-full z-30 mt-1 w-full rounded-md border px-2.5 py-2 text-left text-[10px] leading-tight shadow-lg ${kleur}`, children: _jsxs("button", { type: "button", className: `block w-full text-left ${onClick ? "cursor-pointer hover:brightness-110" : "cursor-default"}`, title: onClick ? "Klik voor alle vastgelegde details" : marker.stop.reden, onClick: (e) => {
|
|
169
|
+
e.stopPropagation();
|
|
170
|
+
onClick?.();
|
|
171
|
+
}, children: [_jsxs("span", { className: "flex items-center gap-1 font-semibold", children: [_jsx(Icoon, { className: "h-3 w-3 shrink-0" }), stopKop] }), _jsxs("span", { className: "mt-1 line-clamp-2 block font-normal", children: [_jsx("span", { className: "font-semibold", children: "Waarom: " }), marker.stop.reden] }), _jsxs("span", { className: "mt-0.5 line-clamp-1 block font-normal opacity-95", children: [_jsx("span", { className: "font-semibold", children: "Stand: " }), stand] }), _jsxs("span", { className: "mt-0.5 line-clamp-2 block font-normal opacity-95", children: [_jsx("span", { className: "font-semibold", children: "Wat moet er gebeuren: " }), marker.stop.volgendeStap ?? "Geen vervolgactie nodig."] })] }) }));
|
|
172
|
+
}
|
|
173
|
+
return (_jsxs("div", { className: `nodrag nopan absolute -bottom-6 left-3 right-3 z-20 flex items-start gap-1 rounded-md border px-2 py-1 text-left text-[10px] font-medium leading-tight shadow ${kleur}`, children: [_jsx(Icoon, { className: "mt-0.5 h-3 w-3 shrink-0" }), _jsxs("button", { type: "button", className: `min-w-0 flex-1 text-left ${onClick ? "cursor-pointer hover:brightness-110" : "cursor-default"}`, title: onClick ? "Klik voor alles wat hier is vastgelegd" : marker.text, onClick: (e) => {
|
|
174
|
+
e.stopPropagation();
|
|
175
|
+
onClick?.();
|
|
176
|
+
}, children: [_jsx("span", { className: open ? "line-clamp-2 block" : "block truncate", children: kop }), open ? (_jsxs(_Fragment, { children: [marker.waarom ? (_jsxs("span", { className: "line-clamp-2 block font-normal opacity-95", children: ["Waarom: ", marker.waarom] })) : null, feiten.length > 0 && (_jsx("span", { className: "line-clamp-2 block font-normal opacity-90", children: feiten.join(" · ") })), details.length > 0 && _jsx("span", { className: "block opacity-90", children: details.join(" · ") }), marker.verouderd && (_jsx("span", { className: "block font-normal opacity-90", children: "Instelling is sindsdien gewijzigd" }))] })) : null] }), _jsx("button", { type: "button", className: "mt-0.5 shrink-0 rounded p-0.5 hover:bg-black/20", title: open ? "Uitleg inklappen" : "Uitleg openklappen", "aria-label": open ? "Uitleg inklappen" : "Uitleg openklappen", "aria-expanded": open, onClick: (e) => {
|
|
177
|
+
e.stopPropagation();
|
|
178
|
+
setOpen((v) => !v);
|
|
179
|
+
}, children: open ? _jsx(ChevronUp, { className: "h-3 w-3" }) : _jsx(ChevronDown, { className: "h-3 w-3" }) })] }));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Rood blokje boven een vakje: dit vakje loopt vast, en dit is de reden.
|
|
183
|
+
* Standaard compact, zodat het vakje eronder leesbaar blijft.
|
|
184
|
+
*/
|
|
185
|
+
function Probleem({ probleem }) {
|
|
186
|
+
const [open, setOpen] = useState(false);
|
|
187
|
+
if (!probleem)
|
|
188
|
+
return null;
|
|
189
|
+
const kleur = probleem.soort === "mislukt"
|
|
190
|
+
? "border-destructive bg-destructive text-destructive-foreground"
|
|
191
|
+
: "border-amber-500 bg-amber-500 text-white";
|
|
192
|
+
const feiten = Array.isArray(probleem.feiten) ? probleem.feiten : [];
|
|
193
|
+
return (_jsxs("div", { className: `nodrag nopan absolute -top-7 left-3 right-3 z-20 flex items-start gap-1 rounded-md border px-2 py-1 text-left text-[10px] font-medium leading-tight shadow ${kleur}`, children: [_jsx(AlertTriangle, { className: "mt-0.5 h-3 w-3 shrink-0" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("span", { className: open ? "block" : "block truncate", children: probleem.titel }), open ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "block font-normal opacity-95", children: probleem.reden }), feiten.length > 0 && (_jsx("span", { className: "block font-normal opacity-90", children: feiten.join(" · ") })), probleem.volgendeStap ? (_jsxs("span", { className: "block font-normal opacity-90", children: ["Wat moet er gebeuren: ", probleem.volgendeStap] })) : null] })) : (_jsx("span", { className: "block truncate font-normal opacity-95", children: probleem.reden }))] }), _jsx("button", { type: "button", className: "mt-0.5 shrink-0 rounded p-0.5 hover:bg-black/20", title: open ? "Foutmelding inklappen" : "Foutmelding openklappen", "aria-label": open ? "Foutmelding inklappen" : "Foutmelding openklappen", "aria-expanded": open, onClick: (e) => {
|
|
194
|
+
e.stopPropagation();
|
|
195
|
+
setOpen((v) => !v);
|
|
196
|
+
}, children: open ? _jsx(ChevronUp, { className: "h-3 w-3" }) : _jsx(ChevronDown, { className: "h-3 w-3" }) })] }));
|
|
156
197
|
}
|
|
157
198
|
function StepNode({ data }) {
|
|
158
199
|
const { node, richting, geselecteerd, marker, traceActief } = data;
|
|
@@ -170,14 +211,18 @@ function StepNode({ data }) {
|
|
|
170
211
|
data.onTrace(node.id);
|
|
171
212
|
else if (node.stepId)
|
|
172
213
|
data.onSelectStep(node.stepId);
|
|
173
|
-
}, children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-[15px] font-semibold text-foreground", children: node.label }), _jsx("p", { className: "line-clamp-2 text-[11px] leading-snug text-muted-foreground", children: node.sublabel })] }), _jsx(TaakTeken, { soort: "taak", actief: !inactief }), _jsx(VraagTeken, { onClick: () => data.onHelp({ titel: node.label, regels: node.help }) }), _jsx(Markering, { marker: marker, onClick: data.onTrace ? () => data.onTrace?.(node.id) : undefined }), handles(richting)] }));
|
|
214
|
+
}, children: [_jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "text-[15px] font-semibold text-foreground", children: node.label }), _jsx("p", { className: "line-clamp-2 text-[11px] leading-snug text-muted-foreground", children: node.sublabel })] }), _jsx(TaakTeken, { soort: "taak", actief: !inactief }), _jsx(VraagTeken, { onClick: () => data.onHelp({ titel: node.label, regels: node.help }) }), _jsx(Markering, { marker: marker, onClick: data.onTrace ? () => data.onTrace?.(node.id) : undefined }), _jsx(Probleem, { probleem: data.probleem }), handles(richting)] }));
|
|
174
215
|
}
|
|
175
216
|
function SettingNode({ data }) {
|
|
176
217
|
const { node, richting, bewerken } = data;
|
|
177
|
-
return (_jsxs("div", { className: `relative flex cursor-pointer items-start justify-between gap-2 rounded-lg border px-3 py-2 ${NODE_STATE_CLASS[node.state]}${routeClass(node)} ${
|
|
218
|
+
return (_jsxs("div", { className: `relative flex cursor-pointer items-start justify-between gap-2 rounded-lg border px-3 py-2 ${NODE_STATE_CLASS[node.state]}${routeClass(node)} ${data.probleem?.soort === "mislukt"
|
|
219
|
+
? "border-destructive ring-2 ring-destructive/50"
|
|
220
|
+
: data.probleem
|
|
221
|
+
? "border-amber-500 ring-2 ring-amber-400/50"
|
|
222
|
+
: ""} ${bewerken ? "ring-2 ring-primary" : ""}`, style: { width: node.w, height: node.h }, onClick: () => node.stepId && data.onSelectStep(node.stepId), onDoubleClick: (e) => {
|
|
178
223
|
e.stopPropagation();
|
|
179
224
|
data.onBewerk(bewerken ? null : node.id);
|
|
180
|
-
}, title: "Klik voor het zijpaneel \u00B7 dubbelklik om hier aan te passen", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "truncate text-[11px] font-semibold leading-tight text-foreground", children: node.label }), Array.isArray(node.lines) && node.lines.length ? (_jsxs("ul", { className: "mt-1 space-y-0.5", children: [node.lines.slice(0, 6).map((l) => (_jsx("li", { className: "truncate text-[10px] leading-[16px] text-muted-foreground", children: l }, l))), node.lines.length > 6 && (_jsxs("li", { className: "text-[10px] text-muted-foreground", children: ["+", node.lines.length - 6, " meer\u2026"] }))] })) : (_jsx("p", { className: "truncate text-[11px] text-muted-foreground", children: node.sublabel }))] }), _jsx(TaakTeken, { soort: "regel", actief: node.state === "active" }), _jsx(VraagTeken, { onClick: () => data.onHelp({ titel: node.label, regels: node.help }) }), _jsx(BewerkHint, {}), bewerken && _jsx(VeldBewerker, { data: data }), handles(richting)] }));
|
|
225
|
+
}, title: "Klik voor het zijpaneel \u00B7 dubbelklik om hier aan te passen", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "truncate text-[11px] font-semibold leading-tight text-foreground", children: node.label }), Array.isArray(node.lines) && node.lines.length ? (_jsxs("ul", { className: "mt-1 space-y-0.5", children: [node.lines.slice(0, 6).map((l) => (_jsx("li", { className: "truncate text-[10px] leading-[16px] text-muted-foreground", children: l }, l))), node.lines.length > 6 && (_jsxs("li", { className: "text-[10px] text-muted-foreground", children: ["+", node.lines.length - 6, " meer\u2026"] }))] })) : (_jsx("p", { className: "truncate text-[11px] text-muted-foreground", children: node.sublabel }))] }), _jsx(TaakTeken, { soort: "regel", actief: node.state === "active" }), _jsx(VraagTeken, { onClick: () => data.onHelp({ titel: node.label, regels: node.help }) }), _jsx(BewerkHint, {}), _jsx(Probleem, { probleem: data.probleem }), bewerken && _jsx(VeldBewerker, { data: data }), handles(richting)] }));
|
|
181
226
|
}
|
|
182
227
|
function DecisionNode({ data }) {
|
|
183
228
|
const { node, richting, ingeklapt, bewerken } = data;
|
|
@@ -196,11 +241,20 @@ function DecisionNode({ data }) {
|
|
|
196
241
|
const waarde = node.isBoolean ? raw === "true" : raw;
|
|
197
242
|
if (node.storeId && node.fieldKey)
|
|
198
243
|
data.onChangeChoice(node.storeId, node.fieldKey, waarde);
|
|
199
|
-
}, children: options.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) }), bewerken && _jsx(VeldBewerker, { data: data }), handles(richting)] }));
|
|
244
|
+
}, children: options.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) }), _jsx(Probleem, { probleem: data.probleem }), bewerken && _jsx(VeldBewerker, { data: data }), handles(richting)] }));
|
|
200
245
|
}
|
|
201
246
|
function MergeNode({ data }) {
|
|
202
|
-
const { node, richting } = data;
|
|
203
|
-
|
|
247
|
+
const { node, richting, geselecteerd, onMerge } = data;
|
|
248
|
+
const wacht = node.wacht;
|
|
249
|
+
return (_jsxs("div", { className: "relative", style: { width: node.w, height: node.h }, children: [_jsx("div", { role: onMerge ? "button" : undefined, tabIndex: onMerge ? 0 : undefined, "aria-label": onMerge ? "Samenkomst beheren" : undefined, onClick: onMerge ? () => onMerge(node.id) : undefined, className: `h-full w-full rotate-45 border-2 ${onMerge ? "cursor-pointer" : ""} ${geselecteerd
|
|
250
|
+
? "border-primary bg-primary ring-2 ring-primary/40"
|
|
251
|
+
: wacht
|
|
252
|
+
? "border-amber-500 bg-amber-200"
|
|
253
|
+
: node.state === "active"
|
|
254
|
+
? "border-primary bg-primary/20"
|
|
255
|
+
: "border-muted-foreground/50 bg-background"}`, title: wacht
|
|
256
|
+
? `Samenkomst — de flow gaat verder zodra ${wacht.label} klaar is`
|
|
257
|
+
: "Samenkomst — klik om dit ruitje te beheren", children: handles(richting) }), wacht && (_jsx("span", { className: "pointer-events-none absolute left-1/2 top-full mt-1 -translate-x-1/2 whitespace-nowrap rounded border border-amber-500/50 bg-background px-1 text-[10px] font-medium text-amber-700", children: wacht.wanneer === "alle" ? "alle lijnen" : `alleen: ${wacht.label}` }))] }));
|
|
204
258
|
}
|
|
205
259
|
function OptionNode({ data }) {
|
|
206
260
|
const { node, richting } = data;
|
|
@@ -249,7 +303,7 @@ function StateEdge(props) {
|
|
|
249
303
|
}
|
|
250
304
|
const EDGE_TYPES = { state: StateEdge };
|
|
251
305
|
// ── Canvas ──────────────────────────────────────────────────────────────────
|
|
252
|
-
function Binnen({ tree, selectedStepId, settings, markers, nodeTrace, routeLabel, routeSummary, traceNodeId, onTraceNode, onClearRoute, onSelectStep, onChangeChoice, }) {
|
|
306
|
+
function Binnen({ tree, selectedStepId, settings, markers, problemen, nodeTrace, routeLabel, routeSummary, traceNodeId, onTraceNode, onClearRoute, onSelectStep, onChangeChoice, mergeId, onSelectMerge, }) {
|
|
253
307
|
const [debug, setDebug] = useState(false);
|
|
254
308
|
const [bewerktId, setBewerktId] = useState(null);
|
|
255
309
|
const [uitleg, setUitleg] = useState(null);
|
|
@@ -329,7 +383,7 @@ function Binnen({ tree, selectedStepId, settings, markers, nodeTrace, routeLabel
|
|
|
329
383
|
return next;
|
|
330
384
|
});
|
|
331
385
|
}, []);
|
|
332
|
-
const { zichtbaar, edges, posities } = useMemo(() => layout(tree, collapsed, richting), [tree, collapsed, richting]);
|
|
386
|
+
const { zichtbaar, edges, posities } = useMemo(() => layout(tree, collapsed, richting, markers), [tree, collapsed, richting, markers]);
|
|
333
387
|
const rfNodes = useMemo(() => zichtbaar.map((node) => ({
|
|
334
388
|
id: node.id,
|
|
335
389
|
type: node.kind,
|
|
@@ -344,10 +398,13 @@ function Binnen({ tree, selectedStepId, settings, markers, nodeTrace, routeLabel
|
|
|
344
398
|
data: {
|
|
345
399
|
node,
|
|
346
400
|
richting,
|
|
347
|
-
geselecteerd:
|
|
401
|
+
geselecteerd: node.kind === "merge"
|
|
402
|
+
? node.id === mergeId
|
|
403
|
+
: !!node.stepId && node.kind === "step" && node.stepId === selectedStepId,
|
|
348
404
|
ingeklapt: collapsed.has(node.id),
|
|
349
405
|
bewerken: bewerktId === node.id,
|
|
350
406
|
marker: markers?.get(node.id),
|
|
407
|
+
probleem: problemen?.get(node.id),
|
|
351
408
|
traceActief: traceNodeId === node.id,
|
|
352
409
|
settings,
|
|
353
410
|
onSelectStep,
|
|
@@ -356,15 +413,19 @@ function Binnen({ tree, selectedStepId, settings, markers, nodeTrace, routeLabel
|
|
|
356
413
|
onToggleCollapse: toggleCollapse,
|
|
357
414
|
onBewerk: setBewerktId,
|
|
358
415
|
onTrace: onTraceNode ? (id) => onTraceNode(id) : undefined,
|
|
416
|
+
onMerge: onSelectMerge,
|
|
359
417
|
},
|
|
360
418
|
})), [
|
|
361
419
|
zichtbaar,
|
|
362
420
|
posities,
|
|
363
421
|
richting,
|
|
364
422
|
selectedStepId,
|
|
423
|
+
mergeId,
|
|
424
|
+
onSelectMerge,
|
|
365
425
|
collapsed,
|
|
366
426
|
bewerktId,
|
|
367
427
|
markers,
|
|
428
|
+
problemen,
|
|
368
429
|
traceNodeId,
|
|
369
430
|
onTraceNode,
|
|
370
431
|
settings,
|
|
@@ -422,7 +483,7 @@ function Binnen({ tree, selectedStepId, settings, markers, nodeTrace, routeLabel
|
|
|
422
483
|
if (!d)
|
|
423
484
|
return "transparent";
|
|
424
485
|
return d.state === "active" ? "hsl(var(--primary))" : "hsl(var(--muted-foreground) / 0.4)";
|
|
425
|
-
} })] })] }), traceGroep && (_jsx(NodeTracePanel, { groep: traceGroep, orderLabel: routeLabel ?? null, debug: debug, onDebug: setDebug, onClose: () => onTraceNode?.(null) })), uitleg && (_jsxs("div", { className: "absolute bottom-12 left-3 z-20 w-[22rem] max-w-[85%] rounded-xl border border-border bg-background p-4 shadow-lg", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("p", { className: "text-sm font-semibold", children: uitleg.titel }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Uitleg sluiten", onClick: () => setUitleg(null), children: _jsx(X, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "mt-2 space-y-2", children: uitleg.regels.map((regel, i) => (_jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: regel }, i))) })] })), _jsx("p", { className: "border-t border-border px-3 py-2 text-xs text-muted-foreground", children: "Slepen om te verschuiven \u00B7 scrollen verschuift, linkermuisknop ingedrukt houden en scrollen zoomt in en uit \u00B7 dubbelklik op een vakje of keuzelijst om de instellingen daar meteen aan te passen (Escape sluit) \u00B7 klik een stap of instelling om alle regels in het zijpaneel te openen" })] }));
|
|
486
|
+
} })] })] }), traceGroep && (_jsx(NodeTracePanel, { groep: traceGroep, stop: problemen?.get(traceGroep.nodeId) ?? markers?.get(traceGroep.nodeId)?.stop ?? null, orderLabel: routeLabel ?? null, debug: debug, onDebug: setDebug, onClose: () => onTraceNode?.(null) })), uitleg && (_jsxs("div", { className: "absolute bottom-12 left-3 z-20 w-[22rem] max-w-[85%] rounded-xl border border-border bg-background p-4 shadow-lg", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("p", { className: "text-sm font-semibold", children: uitleg.titel }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Uitleg sluiten", onClick: () => setUitleg(null), children: _jsx(X, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "mt-2 space-y-2", children: uitleg.regels.map((regel, i) => (_jsx("p", { className: "text-xs leading-relaxed text-muted-foreground", children: regel }, i))) })] })), _jsx("p", { className: "border-t border-border px-3 py-2 text-xs text-muted-foreground", children: "Slepen om te verschuiven \u00B7 scrollen verschuift, linkermuisknop ingedrukt houden en scrollen zoomt in en uit \u00B7 dubbelklik op een vakje of keuzelijst om de instellingen daar meteen aan te passen (Escape sluit) \u00B7 klik een stap of instelling om alle regels in het zijpaneel te openen" })] }));
|
|
426
487
|
}
|
|
427
488
|
export function FlowCanvas(props) {
|
|
428
489
|
return (_jsx(ReactFlowProvider, { children: _jsx(Binnen, { ...props }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlowOrders.d.ts","sourceRoot":"","sources":["../../src/components/FlowOrders.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FlowOrders.d.ts","sourceRoot":"","sources":["../../src/components/FlowOrders.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAA2B,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG9F,UAAU,KAAK;IACb,mEAAmE;IACnE,OAAO,EAAE,CACP,KAAK,EAAE,UAAU,GAAG,IAAI,EACxB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,MAAM,EAAE,WAAW,GAAG,IAAI,KACvB,IAAI,CAAC;CACX;AAoCD,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,+BA6Q5C"}
|
|
@@ -9,7 +9,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
// ============================================================================
|
|
10
10
|
import { useEffect, useMemo, useState } from "react";
|
|
11
11
|
import { Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Skeleton, } from "@flowselections/core";
|
|
12
|
-
import { AlertTriangle, CheckCircle2, ChevronDown, ChevronRight, Clock, RefreshCw, Search, X } from "lucide-react";
|
|
12
|
+
import { AlertTriangle, CheckCircle2, ChevronDown, ChevronRight, Clock, RefreshCw, RotateCcw, Search, X } from "lucide-react";
|
|
13
|
+
import { toast } from "sonner";
|
|
14
|
+
import { supabase } from "../integrations/supabase/moduleClient.js";
|
|
13
15
|
import { useAlleOrders, useOrderVersies, useVersieEvents } from "../hooks/useOrderVersies";
|
|
14
16
|
import { bepaalRoute, redenTekst } from "../lib/flowRoute";
|
|
15
17
|
import { Gebeurtenis } from "./OrderLogboek";
|
|
@@ -58,24 +60,33 @@ export function FlowOrders({ onRoute }) {
|
|
|
58
60
|
const [zoek, setZoek] = useState("");
|
|
59
61
|
const [zoekActief, setZoekActief] = useState("");
|
|
60
62
|
const [filter, setFilter] = useState("");
|
|
63
|
+
const [sortering, setSortering] = useState("nieuw");
|
|
61
64
|
const [orderRef, setOrderRef] = useState(null);
|
|
62
65
|
const [versieId, setVersieId] = useState(null);
|
|
66
|
+
const [herbezig, setHerbezig] = useState(false);
|
|
63
67
|
useEffect(() => {
|
|
64
68
|
const t = setTimeout(() => setZoekActief(zoek.trim()), 300);
|
|
65
69
|
return () => clearTimeout(t);
|
|
66
70
|
}, [zoek]);
|
|
67
71
|
const { rows, loading, error, refresh } = useAlleOrders(zoekActief);
|
|
68
72
|
const veiligeRows = Array.isArray(rows) ? rows : [];
|
|
69
|
-
const gefilterd = useMemo(() =>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
const gefilterd = useMemo(() => {
|
|
74
|
+
const lijst = veiligeRows.filter((r) => {
|
|
75
|
+
if (!filter)
|
|
76
|
+
return true;
|
|
77
|
+
const st = orderStand(r);
|
|
78
|
+
if (filter === "fout")
|
|
79
|
+
return st.kleur === "destructive";
|
|
80
|
+
if (filter === "bezig")
|
|
81
|
+
return st.kleur === "secondary";
|
|
82
|
+
return st.kleur === "default" || st.kleur === "outline";
|
|
83
|
+
});
|
|
84
|
+
const stempel = (r) => {
|
|
85
|
+
const t = Date.parse(String(r.createdAt ?? r.lastAt ?? ""));
|
|
86
|
+
return Number.isFinite(t) ? t : 0;
|
|
87
|
+
};
|
|
88
|
+
return [...lijst].sort((a, b) => (sortering === "nieuw" ? stempel(b) - stempel(a) : stempel(a) - stempel(b)));
|
|
89
|
+
}, [veiligeRows, filter, sortering]);
|
|
79
90
|
const versies = useOrderVersies(orderRef);
|
|
80
91
|
const veiligeVersies = Array.isArray(versies.versions) ? versies.versions : [];
|
|
81
92
|
const gekozen = veiligeVersies.find((v) => v.id === versieId) ?? null;
|
|
@@ -98,18 +109,53 @@ export function FlowOrders({ onRoute }) {
|
|
|
98
109
|
setVersieId(null);
|
|
99
110
|
setOrderRef((v) => (v === nr ? null : nr));
|
|
100
111
|
};
|
|
112
|
+
// Eén order helemaal opnieuw vanaf "Order komt binnen" door de flow laten lopen.
|
|
113
|
+
const opnieuwDoorFlow = async (nr) => {
|
|
114
|
+
setHerbezig(true);
|
|
115
|
+
try {
|
|
116
|
+
const { data, error: rpcError } = await supabase.rpc("logistics_replan_order_journey", {
|
|
117
|
+
p_order_ref: nr,
|
|
118
|
+
});
|
|
119
|
+
if (rpcError)
|
|
120
|
+
throw new Error(rpcError.message);
|
|
121
|
+
const r = (data ?? {});
|
|
122
|
+
if (r?.gevonden === false) {
|
|
123
|
+
toast.error(`Order ${nr} is niet gevonden.`);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
toast.success(`${nr} begint opnieuw vanaf "Order komt binnen"`, {
|
|
127
|
+
description: `Oude route gewist (${r?.oudeStappenGewist ?? 0} stappen, ${r?.oudeBerekeningenGewist ?? 0} eerdere berekeningen). ${r?.karrenVerwijderd ?? 0} karren opnieuw te berekenen.`,
|
|
128
|
+
});
|
|
129
|
+
setVersieId(null);
|
|
130
|
+
onRoute(null, null, null, null);
|
|
131
|
+
try {
|
|
132
|
+
await supabase.rpc("logistics_trace_progress_order", { p_order_ref: nr });
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
/* meekijken mag nooit blokkeren */
|
|
136
|
+
}
|
|
137
|
+
await refresh();
|
|
138
|
+
await versies.refresh();
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
toast.error("Opnieuw berekenen is niet gelukt", { description: e?.message ? String(e.message) : undefined });
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
setHerbezig(false);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
101
147
|
return (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: "Orders in het systeem" }), _jsx(CardDescription, { children: "Klik een order voor alle herberekeningen; klik een versie om de gelopen route blauw op de kaart te zien en precies te lezen waar hij is vastgelopen." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: () => void refresh(), disabled: loading, children: [_jsx(RefreshCw, { className: `mr-1 h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` }), "Vernieuwen"] })] }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-2", children: [_jsxs("div", { className: "relative w-full max-w-xs", children: [_jsx(Search, { className: "pointer-events-none absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" }), _jsx(Input, { className: "pl-8", placeholder: "Zoek op ordernummer of klant", value: zoek, onChange: (e) => setZoek(e.target.value) })] }), [
|
|
102
148
|
["", "Alles"],
|
|
103
149
|
["fout", "Vastgelopen"],
|
|
104
150
|
["bezig", "Bezig / wachtend"],
|
|
105
151
|
["klaar", "Overig"],
|
|
106
|
-
].map(([w, l]) => (_jsx(Button, { size: "sm", variant: filter === w ? "default" : "outline", onClick: () => setFilter(w), children: l }, w))), _jsxs("span", { className: "ml-auto text-xs text-muted-foreground", children: [gefilterd.length, " orders"] })] })] }), _jsxs(CardContent, { className: "space-y-3", children: [error && _jsx("p", { className: "text-sm text-destructive", children: error }), loading && veiligeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : gefilterd.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen orders gevonden." })) : (_jsx("div", { className: "max-h-[420px] overflow-y-auto rounded-md border border-border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "sticky top-0 bg-muted/60 text-xs text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Order" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Klant" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Bron" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Levering" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Stand" }), _jsx("th", { className: "px-2 py-1.5 text-right font-medium", children: "Versies" }), _jsx("th", { className: "px-2 py-1.5 text-right font-medium", children: "Fouten" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Laatste activiteit" })] }) }), _jsx("tbody", { children: gefilterd.map((r) => {
|
|
152
|
+
].map(([w, l]) => (_jsx(Button, { size: "sm", variant: filter === w ? "default" : "outline", onClick: () => setFilter(w), children: l }, w))), _jsx(Button, { size: "sm", variant: "outline", onClick: () => setSortering((s) => (s === "nieuw" ? "oud" : "nieuw")), children: sortering === "nieuw" ? "Nieuwste eerst" : "Oudste eerst" }), _jsxs("span", { className: "ml-auto text-xs text-muted-foreground", children: [gefilterd.length, " orders"] })] })] }), _jsxs(CardContent, { className: "space-y-3", children: [error && (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2 rounded-md border border-destructive/30 bg-destructive/5 px-3 py-2", children: [_jsx("p", { className: "text-sm text-destructive", children: error }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void refresh(), disabled: loading, children: [_jsx(RefreshCw, { className: `mr-1 h-3.5 w-3.5 ${loading ? "animate-spin" : ""}` }), "Opnieuw proberen"] })] })), loading && veiligeRows.length === 0 ? (_jsxs("div", { className: "space-y-2", children: [_jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" }), _jsx(Skeleton, { className: "h-10 w-full" })] })) : gefilterd.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen orders gevonden." })) : (_jsx("div", { className: "max-h-[420px] overflow-y-auto rounded-md border border-border", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "sticky top-0 bg-muted/60 text-xs text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Order" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Klant" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Bron" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Levering" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Stand" }), _jsx("th", { className: "px-2 py-1.5 text-right font-medium", children: "Versies" }), _jsx("th", { className: "px-2 py-1.5 text-right font-medium", children: "Fouten" }), _jsx("th", { className: "px-2 py-1.5 text-left font-medium", children: "Laatste activiteit" })] }) }), _jsx("tbody", { children: gefilterd.map((r) => {
|
|
107
153
|
const st = orderStand(r);
|
|
108
154
|
const actief = r.orderNumber === orderRef;
|
|
109
155
|
return (_jsxs("tr", { className: `cursor-pointer border-t border-border hover:bg-muted/40 ${actief ? "bg-primary/10" : ""}`, onClick: () => kies(r.orderNumber), children: [_jsx("td", { className: "px-2 py-1.5 font-medium", children: _jsxs("span", { className: "inline-flex items-center gap-1", children: [actief ? _jsx(ChevronDown, { className: "h-3.5 w-3.5" }) : _jsx(ChevronRight, { className: "h-3.5 w-3.5" }), r.orderNumber] }) }), _jsx("td", { className: "max-w-[180px] truncate px-2 py-1.5", children: r.customerName ?? "—" }), _jsx("td", { className: "px-2 py-1.5", children: r.orderSource === "floriday" ? "Floriday" : r.orderSource ? "Eigen verkoop" : "—" }), _jsx("td", { className: "px-2 py-1.5", children: r.deliveryDate ?? "—" }), _jsxs("td", { className: "px-2 py-1.5", children: [_jsx(Badge, { variant: st.kleur, children: st.label }), r.reasonCode && st.kleur === "destructive" && (_jsx("span", { className: "ml-1 text-xs text-muted-foreground", children: redenTekst(r.reasonCode) }))] }), _jsx("td", { className: "px-2 py-1.5 text-right tabular-nums", children: r.versions }), _jsx("td", { className: `px-2 py-1.5 text-right tabular-nums ${r.errors > 0 ? "text-destructive" : ""}`, children: r.errors }), _jsx("td", { className: "px-2 py-1.5 text-xs text-muted-foreground", children: tijd(r.lastAt ?? r.createdAt) })] }, r.orderNumber));
|
|
110
156
|
}) })] }) })), orderRef && (_jsxs("div", { className: "space-y-3 rounded-md border border-primary/40 bg-primary/5 p-3", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [_jsxs("div", { children: [_jsx("p", { className: "font-semibold", children: orderRef }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [versies.order?.customerName ?? "", versies.order?.status ? ` · status: ${versies.order.status}` : "", versies.carts && versies.carts.total > 0
|
|
111
157
|
? ` · karren: ${versies.carts.total} (${versies.carts.printed} geprint, ${versies.carts.controlled} gecontroleerd)`
|
|
112
|
-
: "", versies.order?.planLockedAt ? " · indeling bevroren" : ""] })] }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Order sluiten", onClick: () => kies(orderRef), children: _jsx(X, { className: "h-4 w-4" }) })] }), versies.error && _jsx("p", { className: "text-sm text-destructive", children: versies.error }), versies.loading ? (_jsx(Skeleton, { className: "h-16 w-full" })) : veiligeVersies.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen herberekening vastgelegd voor deze order. De kaart toont waar de order nu staat." })) : (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("p", { className: "text-xs font-medium text-muted-foreground", children: [veiligeVersies.length, " herberekening", veiligeVersies.length === 1 ? "" : "en", " \u2014 nieuwste bovenaan"] }), veiligeVersies.map((v) => (_jsx(VersieRij, { versie: v, laatste: v.id === laatsteId, gekozen: (gekozen?.id ?? (versieId ? null : laatsteId)) === v.id, onKies: () => setVersieId((cur) => (cur === v.id ? null : v.id)) }, v.id)))] })), (gekozen ?? (versieId ? null : veiligeVersies[0])) && (_jsx(VersieDetail, { orderRef: orderRef, versie: (gekozen ?? veiligeVersies[0]), route: bepaalRoute(gekozen ?? veiligeVersies[0], versies.order, versies.carts, (gekozen ?? veiligeVersies[0])?.id === laatsteId) }))] }))] })] }));
|
|
158
|
+
: "", versies.order?.planLockedAt ? " · indeling bevroren" : ""] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { size: "sm", onClick: () => void opnieuwDoorFlow(orderRef), disabled: herbezig, children: [_jsx(RotateCcw, { className: "mr-1 h-4 w-4" }), herbezig ? "Bezig…" : "Opnieuw door de flowchart"] }), _jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Order sluiten", onClick: () => kies(orderRef), children: _jsx(X, { className: "h-4 w-4" }) })] })] }), versies.error && _jsx("p", { className: "text-sm text-destructive", children: versies.error }), versies.loading ? (_jsx(Skeleton, { className: "h-16 w-full" })) : veiligeVersies.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen herberekening vastgelegd voor deze order. De kaart toont waar de order nu staat." })) : (_jsxs("div", { className: "space-y-1.5", children: [_jsxs("p", { className: "text-xs font-medium text-muted-foreground", children: [veiligeVersies.length, " herberekening", veiligeVersies.length === 1 ? "" : "en", " \u2014 nieuwste bovenaan"] }), veiligeVersies.map((v) => (_jsx(VersieRij, { versie: v, laatste: v.id === laatsteId, gekozen: (gekozen?.id ?? (versieId ? null : laatsteId)) === v.id, onKies: () => setVersieId((cur) => (cur === v.id ? null : v.id)) }, v.id)))] })), (gekozen ?? (versieId ? null : veiligeVersies[0])) && (_jsx(VersieDetail, { orderRef: orderRef, versie: (gekozen ?? veiligeVersies[0]), route: bepaalRoute(gekozen ?? veiligeVersies[0], versies.order, versies.carts, (gekozen ?? veiligeVersies[0])?.id === laatsteId) }))] }))] })] }));
|
|
113
159
|
}
|
|
114
160
|
function VersieRij({ versie, laatste, gekozen, onKies, }) {
|
|
115
161
|
const st = VERSIE_STATUS[(versie.status ?? "pending").toLowerCase()] ?? { label: versie.status ?? "—", kleur: "outline" };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlowPage.d.ts","sourceRoot":"","sources":["../../src/components/FlowPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FlowPage.d.ts","sourceRoot":"","sources":["../../src/components/FlowPage.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,QAAQ,gCAitBvB"}
|