@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.
Files changed (168) hide show
  1. package/README.md +24 -24
  2. package/dist-lib/components/AfrondWachtrijCard.d.ts +2 -0
  3. package/dist-lib/components/AfrondWachtrijCard.d.ts.map +1 -0
  4. package/dist-lib/components/AfrondWachtrijCard.js +27 -0
  5. package/dist-lib/components/BeladingsafwijkingenCard.d.ts +2 -0
  6. package/dist-lib/components/BeladingsafwijkingenCard.d.ts.map +1 -0
  7. package/dist-lib/components/BeladingsafwijkingenCard.js +44 -0
  8. package/dist-lib/components/FlowCanvas.d.ts +6 -0
  9. package/dist-lib/components/FlowCanvas.d.ts.map +1 -1
  10. package/dist-lib/components/FlowCanvas.js +79 -18
  11. package/dist-lib/components/FlowOrders.d.ts.map +1 -1
  12. package/dist-lib/components/FlowOrders.js +59 -13
  13. package/dist-lib/components/FlowPage.d.ts.map +1 -1
  14. package/dist-lib/components/FlowPage.js +175 -6
  15. package/dist-lib/components/GeblokkeerdeOrdersCard.d.ts.map +1 -1
  16. package/dist-lib/components/GeblokkeerdeOrdersCard.js +21 -2
  17. package/dist-lib/components/KardekkingCard.d.ts +2 -0
  18. package/dist-lib/components/KardekkingCard.d.ts.map +1 -0
  19. package/dist-lib/components/KardekkingCard.js +29 -0
  20. package/dist-lib/components/LogistiekEnginePage.d.ts.map +1 -1
  21. package/dist-lib/components/LogistiekEnginePage.js +7 -1
  22. package/dist-lib/components/LogistiekEngineQueuePage.d.ts.map +1 -1
  23. package/dist-lib/components/LogistiekEngineQueuePage.js +4 -2
  24. package/dist-lib/components/NodeTracePanel.d.ts +4 -1
  25. package/dist-lib/components/NodeTracePanel.d.ts.map +1 -1
  26. package/dist-lib/components/NodeTracePanel.js +8 -2
  27. package/dist-lib/components/OrderStopBanner.d.ts +9 -2
  28. package/dist-lib/components/OrderStopBanner.d.ts.map +1 -1
  29. package/dist-lib/components/OrderStopBanner.js +27 -13
  30. package/dist-lib/components/OrderTraceDetails.d.ts.map +1 -1
  31. package/dist-lib/components/OrderTraceDetails.js +2 -1
  32. package/dist-lib/components/PlanWachtrijPage.d.ts +2 -0
  33. package/dist-lib/components/PlanWachtrijPage.d.ts.map +1 -0
  34. package/dist-lib/components/PlanWachtrijPage.js +99 -0
  35. package/dist-lib/components/PlannerDiffCard.d.ts +2 -0
  36. package/dist-lib/components/PlannerDiffCard.d.ts.map +1 -0
  37. package/dist-lib/components/PlannerDiffCard.js +25 -0
  38. package/dist-lib/components/RegiePage.d.ts.map +1 -1
  39. package/dist-lib/components/RegiePage.js +21 -13
  40. package/dist-lib/components/TaakGezondheidCard.d.ts +2 -0
  41. package/dist-lib/components/TaakGezondheidCard.d.ts.map +1 -0
  42. package/dist-lib/components/TaakGezondheidCard.js +31 -0
  43. package/dist-lib/hooks/useAfrondWachtrij.d.ts +28 -0
  44. package/dist-lib/hooks/useAfrondWachtrij.d.ts.map +1 -0
  45. package/dist-lib/hooks/useAfrondWachtrij.js +88 -0
  46. package/dist-lib/hooks/useBeladingsafwijkingen.d.ts +39 -0
  47. package/dist-lib/hooks/useBeladingsafwijkingen.d.ts.map +1 -0
  48. package/dist-lib/hooks/useBeladingsafwijkingen.js +119 -0
  49. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts +7 -0
  50. package/dist-lib/hooks/useGeblokkeerdeOrders.d.ts.map +1 -1
  51. package/dist-lib/hooks/useGeblokkeerdeOrders.js +28 -2
  52. package/dist-lib/hooks/useLogisticsTrace.js +1 -1
  53. package/dist-lib/hooks/useOrderTrace.js +1 -1
  54. package/dist-lib/hooks/useOrderVersies.d.ts.map +1 -1
  55. package/dist-lib/hooks/useOrderVersies.js +17 -3
  56. package/dist-lib/hooks/usePlanWachtrij.d.ts +33 -0
  57. package/dist-lib/hooks/usePlanWachtrij.d.ts.map +1 -0
  58. package/dist-lib/hooks/usePlanWachtrij.js +104 -0
  59. package/dist-lib/hooks/useRecalcJob.js +1 -1
  60. package/dist-lib/hooks/useShippingNoteDiagnose.d.ts +20 -0
  61. package/dist-lib/hooks/useShippingNoteDiagnose.d.ts.map +1 -0
  62. package/dist-lib/hooks/useShippingNoteDiagnose.js +52 -0
  63. package/dist-lib/hooks/useTaakGezondheid.d.ts +16 -0
  64. package/dist-lib/hooks/useTaakGezondheid.d.ts.map +1 -0
  65. package/dist-lib/hooks/useTaakGezondheid.js +43 -0
  66. package/dist-lib/hooks/useWerktijden.js +1 -1
  67. package/dist-lib/hooks/useWerkwijzeStatus.js +1 -1
  68. package/dist-lib/index.d.ts +10 -0
  69. package/dist-lib/index.d.ts.map +1 -1
  70. package/dist-lib/index.js +10 -0
  71. package/dist-lib/integrations/supabase/auth-middleware.d.ts +3147 -159
  72. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  73. package/dist-lib/integrations/supabase/client.server.d.ts +3147 -159
  74. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  75. package/dist-lib/integrations/supabase/client.server.js +1 -1
  76. package/dist-lib/integrations/supabase/moduleClient.d.ts +3147 -159
  77. package/dist-lib/integrations/supabase/moduleClient.d.ts.map +1 -1
  78. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts +1 -1
  79. package/dist-lib/integrations/supabase/previewAuthStorage.d.ts.map +1 -1
  80. package/dist-lib/integrations/supabase/previewAuthStorage.js +8 -1
  81. package/dist-lib/integrations/supabase/types.d.ts +3183 -161
  82. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  83. package/dist-lib/lib/attachAuthToken.js +1 -1
  84. package/dist-lib/lib/bufferDecision.test.d.ts +2 -0
  85. package/dist-lib/lib/bufferDecision.test.d.ts.map +1 -0
  86. package/dist-lib/lib/bufferDecision.test.js +104 -0
  87. package/dist-lib/lib/cartCoverage.functions.d.ts +30820 -0
  88. package/dist-lib/lib/cartCoverage.functions.d.ts.map +1 -0
  89. package/dist-lib/lib/cartCoverage.functions.js +20 -0
  90. package/dist-lib/lib/floridayDocuments.functions.d.ts +8979 -15
  91. package/dist-lib/lib/floridayDocuments.functions.d.ts.map +1 -1
  92. package/dist-lib/lib/floridayDocuments.functions.js +5 -5
  93. package/dist-lib/lib/floridayPush.functions.d.ts +3147 -159
  94. package/dist-lib/lib/floridayPush.functions.d.ts.map +1 -1
  95. package/dist-lib/lib/floridayPush.functions.js +3 -3
  96. package/dist-lib/lib/flowJourney.d.ts +40 -0
  97. package/dist-lib/lib/flowJourney.d.ts.map +1 -0
  98. package/dist-lib/lib/flowJourney.js +156 -0
  99. package/dist-lib/lib/flowNodes.d.ts +3 -0
  100. package/dist-lib/lib/flowNodes.d.ts.map +1 -1
  101. package/dist-lib/lib/flowNodes.js +6 -0
  102. package/dist-lib/lib/flowRoute.d.ts +11 -1
  103. package/dist-lib/lib/flowRoute.d.ts.map +1 -1
  104. package/dist-lib/lib/flowRoute.js +343 -40
  105. package/dist-lib/lib/flowTree.d.ts +86 -1
  106. package/dist-lib/lib/flowTree.d.ts.map +1 -1
  107. package/dist-lib/lib/flowTree.js +391 -2
  108. package/dist-lib/lib/foutTekst.d.ts +4 -0
  109. package/dist-lib/lib/foutTekst.d.ts.map +1 -0
  110. package/dist-lib/lib/foutTekst.js +43 -0
  111. package/dist-lib/lib/handlers/logistics-tick.server.d.ts +2 -0
  112. package/dist-lib/lib/handlers/logistics-tick.server.d.ts.map +1 -1
  113. package/dist-lib/lib/handlers/logistics-tick.server.js +56 -0
  114. package/dist-lib/lib/handlers/logistics-tick.test.d.ts +2 -0
  115. package/dist-lib/lib/handlers/logistics-tick.test.d.ts.map +1 -0
  116. package/dist-lib/lib/handlers/logistics-tick.test.js +63 -0
  117. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts +14965 -25
  118. package/dist-lib/lib/loadCarrierPlanning.functions.d.ts.map +1 -1
  119. package/dist-lib/lib/loadCarrierPlanning.functions.js +7 -7
  120. package/dist-lib/lib/loadCarrierPlanning.server.d.ts +24 -12
  121. package/dist-lib/lib/loadCarrierPlanning.server.d.ts.map +1 -1
  122. package/dist-lib/lib/loadCarrierPlanning.server.js +490 -211
  123. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts +5986 -10
  124. package/dist-lib/lib/logisticsRecalcJob.functions.d.ts.map +1 -1
  125. package/dist-lib/lib/logisticsRecalcJob.functions.js +4 -4
  126. package/dist-lib/lib/logisticsRecalcJob.server.d.ts.map +1 -1
  127. package/dist-lib/lib/logisticsRecalcJob.server.js +17 -2
  128. package/dist-lib/lib/logisticsRecalculate.functions.d.ts +3147 -159
  129. package/dist-lib/lib/logisticsRecalculate.functions.d.ts.map +1 -1
  130. package/dist-lib/lib/logisticsRecalculate.functions.js +2 -2
  131. package/dist-lib/lib/modulePrompts.d.ts.map +1 -1
  132. package/dist-lib/lib/modulePrompts.js +3436 -3325
  133. package/dist-lib/lib/nodeTrace.d.ts +4 -0
  134. package/dist-lib/lib/nodeTrace.d.ts.map +1 -1
  135. package/dist-lib/lib/nodeTrace.js +6 -15
  136. package/dist-lib/lib/planQueue.server.d.ts.map +1 -1
  137. package/dist-lib/lib/planQueue.server.js +24 -3
  138. package/dist-lib/lib/plannerDiff.d.ts +37 -0
  139. package/dist-lib/lib/plannerDiff.d.ts.map +1 -0
  140. package/dist-lib/lib/plannerDiff.functions.d.ts +30821 -0
  141. package/dist-lib/lib/plannerDiff.functions.d.ts.map +1 -0
  142. package/dist-lib/lib/plannerDiff.functions.js +21 -0
  143. package/dist-lib/lib/plannerDiff.js +74 -0
  144. package/dist-lib/lib/plannerDiff.server.d.ts +5 -0
  145. package/dist-lib/lib/plannerDiff.server.d.ts.map +1 -0
  146. package/dist-lib/lib/plannerDiff.server.js +60 -0
  147. package/dist-lib/lib/plannerDiff.test.d.ts +2 -0
  148. package/dist-lib/lib/plannerDiff.test.d.ts.map +1 -0
  149. package/dist-lib/lib/plannerDiff.test.js +41 -0
  150. package/dist-lib/lib/resolveBuffer.test.d.ts +2 -0
  151. package/dist-lib/lib/resolveBuffer.test.d.ts.map +1 -0
  152. package/dist-lib/lib/resolveBuffer.test.js +38 -0
  153. package/dist-lib/lib/ruleEngineSchema.d.ts.map +1 -1
  154. package/dist-lib/lib/ruleEngineSchema.js +52 -0
  155. package/dist-lib/lib/stopReden.d.ts +43 -0
  156. package/dist-lib/lib/stopReden.d.ts.map +1 -0
  157. package/dist-lib/lib/stopReden.js +197 -0
  158. package/dist-lib/lib/taskCounts.d.ts +2 -0
  159. package/dist-lib/lib/taskCounts.d.ts.map +1 -0
  160. package/dist-lib/lib/taskCounts.js +15 -0
  161. package/dist-lib/lib/taskCounts.test.d.ts +2 -0
  162. package/dist-lib/lib/taskCounts.test.d.ts.map +1 -0
  163. package/dist-lib/lib/taskCounts.test.js +12 -0
  164. package/dist-lib/lib/trace.server.d.ts.map +1 -1
  165. package/dist-lib/lib/trace.server.js +3 -0
  166. package/dist-lib/lib/vakUitleg.d.ts.map +1 -1
  167. package/dist-lib/lib/vakUitleg.js +2 -1
  168. 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,2 @@
1
+ export declare function AfrondWachtrijCard(): import("react").JSX.Element;
2
+ //# sourceMappingURL=AfrondWachtrijCard.d.ts.map
@@ -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,2 @@
1
+ export declare function BeladingsafwijkingenCard(): import("react").JSX.Element;
2
+ //# sourceMappingURL=BeladingsafwijkingenCard.d.ts.map
@@ -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":"AAgDA,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,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,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;CAC7E;AA87BD,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,+BAMtC"}
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.h });
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.h / 2 });
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
- return (_jsxs("button", { type: "button", 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} ${onClick ? "cursor-pointer hover:brightness-110" : "cursor-default"}`, title: onClick ? "Klik voor alles wat hier is vastgelegd" : marker.text, onClick: (e) => {
153
- e.stopPropagation();
154
- onClick?.();
155
- }, children: [_jsx(Icoon, { className: "mt-0.5 h-3 w-3 shrink-0" }), _jsxs("span", { className: "min-w-0", children: [_jsxs("span", { className: "line-clamp-2 block", children: [marker.kind === "stuck" ? "Vastgelopen: " : "Beslissing: ", marker.beslissing ?? marker.text] }), 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(" · ") })] })] }));
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)} ${bewerken ? "ring-2 ring-primary" : ""}`, style: { width: node.w, height: node.h }, onClick: () => node.stepId && data.onSelectStep(node.stepId), onDoubleClick: (e) => {
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
- return (_jsx("div", { className: `rotate-45 border-2 ${node.state === "active" ? "border-primary bg-primary/20" : "border-muted-foreground/50 bg-background"}`, style: { width: node.w, height: node.h }, title: "Samenkomst (BPMN-gateway)", children: handles(richting) }));
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: !!node.stepId && node.kind === "step" && node.stepId === selectedStepId,
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":"AAwBA,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,+BAgN5C"}
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(() => veiligeRows.filter((r) => {
70
- if (!filter)
71
- return true;
72
- const st = orderStand(r);
73
- if (filter === "fout")
74
- return st.kleur === "destructive";
75
- if (filter === "bezig")
76
- return st.kleur === "secondary";
77
- return st.kleur === "default" || st.kleur === "outline";
78
- }), [veiligeRows, filter]);
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":"AAuDA,wBAAgB,QAAQ,gCAqVvB"}
1
+ {"version":3,"file":"FlowPage.d.ts","sourceRoot":"","sources":["../../src/components/FlowPage.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,QAAQ,gCAitBvB"}