@flowselections/floriday-afhandeling-module 1.0.25 → 1.0.27

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 (123) hide show
  1. package/dist-lib/components/afhandeling/CapacityWarning.d.ts +10 -0
  2. package/dist-lib/components/afhandeling/CapacityWarning.d.ts.map +1 -0
  3. package/dist-lib/components/afhandeling/CapacityWarning.js +12 -0
  4. package/dist-lib/components/afhandeling/ControlePage.d.ts.map +1 -1
  5. package/dist-lib/components/afhandeling/ControlePage.js +7 -2
  6. package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
  7. package/dist-lib/components/afhandeling/DagDetailDialog.js +158 -62
  8. package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
  9. package/dist-lib/components/afhandeling/LeveringenPage.js +2 -10
  10. package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -1
  11. package/dist-lib/components/afhandeling/PickAgendaView.js +4 -11
  12. package/dist-lib/components/afhandeling/VervoerdersPage.d.ts.map +1 -1
  13. package/dist-lib/components/afhandeling/VervoerdersPage.js +2 -5
  14. package/dist-lib/components/afhandeling/VerzetOrderDialog.d.ts +14 -0
  15. package/dist-lib/components/afhandeling/VerzetOrderDialog.d.ts.map +1 -0
  16. package/dist-lib/components/afhandeling/VerzetOrderDialog.js +203 -0
  17. package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
  18. package/dist-lib/components/afhandeling/WeekAgendaView.js +7 -3
  19. package/dist-lib/components/pickstation/PickstationPage.d.ts.map +1 -1
  20. package/dist-lib/components/pickstation/PickstationPage.js +1 -0
  21. package/dist-lib/components/settings/VervoerdersSettingsCard.d.ts.map +1 -1
  22. package/dist-lib/components/settings/VervoerdersSettingsCard.js +2 -5
  23. package/dist-lib/hooks/useCapacityCheck.d.ts +10 -0
  24. package/dist-lib/hooks/useCapacityCheck.d.ts.map +1 -0
  25. package/dist-lib/hooks/useCapacityCheck.js +22 -0
  26. package/dist-lib/hooks/useEngineTasks.d.ts +14 -0
  27. package/dist-lib/hooks/useEngineTasks.d.ts.map +1 -0
  28. package/dist-lib/hooks/useEngineTasks.js +49 -0
  29. package/dist-lib/hooks/useOrderPlanning.d.ts +8 -2
  30. package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
  31. package/dist-lib/hooks/useOrderPlanning.js +95 -93
  32. package/dist-lib/index.d.ts +0 -3
  33. package/dist-lib/index.d.ts.map +1 -1
  34. package/dist-lib/index.js +1 -5
  35. package/dist-lib/integrations/supabase/auth-middleware.d.ts +9010 -5433
  36. package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
  37. package/dist-lib/integrations/supabase/client.d.ts +9010 -5433
  38. package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
  39. package/dist-lib/integrations/supabase/client.server.d.ts +9010 -5433
  40. package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
  41. package/dist-lib/integrations/supabase/types.d.ts +9184 -5544
  42. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  43. package/dist-lib/lib/afhandelingSettings.functions.d.ts +7186 -32
  44. package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
  45. package/dist-lib/lib/carriers.functions.d.ts +17965 -80
  46. package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
  47. package/dist-lib/lib/cartAssignments.functions.d.ts +17965 -80
  48. package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
  49. package/dist-lib/lib/cartControl.functions.d.ts +35962 -170
  50. package/dist-lib/lib/cartControl.functions.d.ts.map +1 -1
  51. package/dist-lib/lib/cartControl.functions.js +103 -13
  52. package/dist-lib/lib/floriday.functions.d.ts +9010 -5433
  53. package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
  54. package/dist-lib/lib/logisticsEngine/capacity.d.ts +19 -0
  55. package/dist-lib/lib/logisticsEngine/capacity.d.ts.map +1 -0
  56. package/dist-lib/lib/logisticsEngine/capacity.js +91 -0
  57. package/dist-lib/lib/logisticsEngine/engine.d.ts +99 -0
  58. package/dist-lib/lib/logisticsEngine/engine.d.ts.map +1 -0
  59. package/dist-lib/lib/logisticsEngine/engine.js +102 -0
  60. package/dist-lib/lib/logisticsEngine/reschedule.d.ts +65 -0
  61. package/dist-lib/lib/logisticsEngine/reschedule.d.ts.map +1 -0
  62. package/dist-lib/lib/logisticsEngine/reschedule.js +86 -0
  63. package/dist-lib/lib/logisticsEngine/staffPlanning.d.ts +37 -0
  64. package/dist-lib/lib/logisticsEngine/staffPlanning.d.ts.map +1 -0
  65. package/dist-lib/lib/logisticsEngine/staffPlanning.js +100 -0
  66. package/dist-lib/lib/serverFnError.d.ts +10 -0
  67. package/dist-lib/lib/serverFnError.d.ts.map +1 -0
  68. package/dist-lib/lib/serverFnError.js +29 -0
  69. package/dist-lib/lib/serverRoutes/index.d.ts +0 -1
  70. package/dist-lib/lib/serverRoutes/index.d.ts.map +1 -1
  71. package/dist-lib/lib/serverRoutes/index.js +0 -1
  72. package/dist-lib/lib/timezone.d.ts +27 -0
  73. package/dist-lib/lib/timezone.d.ts.map +1 -0
  74. package/dist-lib/lib/timezone.js +68 -0
  75. package/package.json +6 -21
  76. package/dist-lib/components/engine/CapaciteitsmaatregelenPage.d.ts +0 -2
  77. package/dist-lib/components/engine/CapaciteitsmaatregelenPage.d.ts.map +0 -1
  78. package/dist-lib/components/engine/CapaciteitsmaatregelenPage.js +0 -40
  79. package/dist-lib/components/engine/CapaciteitsmonitorPage.d.ts +0 -2
  80. package/dist-lib/components/engine/CapaciteitsmonitorPage.d.ts.map +0 -1
  81. package/dist-lib/components/engine/CapaciteitsmonitorPage.js +0 -49
  82. package/dist-lib/components/engine/FormulesPage.d.ts +0 -2
  83. package/dist-lib/components/engine/FormulesPage.d.ts.map +0 -1
  84. package/dist-lib/components/engine/FormulesPage.js +0 -252
  85. package/dist-lib/components/engine/PlaceholderPage.d.ts +0 -6
  86. package/dist-lib/components/engine/PlaceholderPage.d.ts.map +0 -1
  87. package/dist-lib/components/engine/PlaceholderPage.js +0 -6
  88. package/dist-lib/components/engine/StrategieenPage.d.ts +0 -2
  89. package/dist-lib/components/engine/StrategieenPage.d.ts.map +0 -1
  90. package/dist-lib/components/engine/StrategieenPage.js +0 -80
  91. package/dist-lib/lib/logisticsEngine/capacity.functions.d.ts +0 -64978
  92. package/dist-lib/lib/logisticsEngine/capacity.functions.d.ts.map +0 -1
  93. package/dist-lib/lib/logisticsEngine/capacity.functions.js +0 -90
  94. package/dist-lib/lib/logisticsEngine/config.d.ts +0 -140
  95. package/dist-lib/lib/logisticsEngine/config.d.ts.map +0 -1
  96. package/dist-lib/lib/logisticsEngine/config.js +0 -488
  97. package/dist-lib/lib/logisticsEngine/enginePickTime.d.ts +0 -29
  98. package/dist-lib/lib/logisticsEngine/enginePickTime.d.ts.map +0 -1
  99. package/dist-lib/lib/logisticsEngine/enginePickTime.js +0 -136
  100. package/dist-lib/lib/logisticsEngine/evaluate.functions.d.ts +0 -16278
  101. package/dist-lib/lib/logisticsEngine/evaluate.functions.d.ts.map +0 -1
  102. package/dist-lib/lib/logisticsEngine/evaluate.functions.js +0 -104
  103. package/dist-lib/lib/logisticsEngine/expression.d.ts +0 -21
  104. package/dist-lib/lib/logisticsEngine/expression.d.ts.map +0 -1
  105. package/dist-lib/lib/logisticsEngine/expression.js +0 -263
  106. package/dist-lib/lib/logisticsEngine/formulas.functions.d.ts +0 -32512
  107. package/dist-lib/lib/logisticsEngine/formulas.functions.d.ts.map +0 -1
  108. package/dist-lib/lib/logisticsEngine/formulas.functions.js +0 -58
  109. package/dist-lib/lib/logisticsEngine/safetyLayer.d.ts +0 -83
  110. package/dist-lib/lib/logisticsEngine/safetyLayer.d.ts.map +0 -1
  111. package/dist-lib/lib/logisticsEngine/safetyLayer.js +0 -182
  112. package/dist-lib/lib/logisticsEngine/strategies.functions.d.ts +0 -129961
  113. package/dist-lib/lib/logisticsEngine/strategies.functions.d.ts.map +0 -1
  114. package/dist-lib/lib/logisticsEngine/strategies.functions.js +0 -176
  115. package/dist-lib/lib/logisticsEngine/variables.d.ts +0 -29
  116. package/dist-lib/lib/logisticsEngine/variables.d.ts.map +0 -1
  117. package/dist-lib/lib/logisticsEngine/variables.js +0 -144
  118. package/dist-lib/lib/logisticsEngine/wizard.functions.d.ts +0 -64976
  119. package/dist-lib/lib/logisticsEngine/wizard.functions.d.ts.map +0 -1
  120. package/dist-lib/lib/logisticsEngine/wizard.functions.js +0 -175
  121. package/dist-lib/lib/serverRoutes/logisticsTick.handler.d.ts +0 -3
  122. package/dist-lib/lib/serverRoutes/logisticsTick.handler.d.ts.map +0 -1
  123. package/dist-lib/lib/serverRoutes/logisticsTick.handler.js +0 -42
@@ -0,0 +1,203 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useState } from "react";
3
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
4
+ import { useServerFn } from "@tanstack/react-start";
5
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Dialog, DialogTitle, DialogDescription, Input, Label, Textarea, toast, } from "@flowselections/core";
6
+ import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter, ResponsiveDialogHeader, } from "../../components/ui/responsive-dialog";
7
+ import { applyReschedule, listRescheduleHistory, previewReschedule, getPickMoments, setPickDay, } from "../../lib/logisticsEngine/reschedule";
8
+ import { ENGINE_TASKS_KEY } from "../../hooks/useEngineTasks";
9
+ import { listCarriers } from "../../lib/carriers.functions";
10
+ import { normalizePickupMoments, selectCarrierForTarget } from "../../lib/carrierPlanning";
11
+ import { safeServerCall } from "../../lib/serverFnError";
12
+ import { amsterdamDay, formatAmsterdam } from "../../lib/timezone";
13
+ function fmtDateTime(v) {
14
+ if (!v)
15
+ return "—";
16
+ return formatAmsterdam(v, { dateStyle: "full", timeStyle: "short" }) || v;
17
+ }
18
+ function toDayInput(v) {
19
+ if (!v)
20
+ return "";
21
+ return amsterdamDay(v);
22
+ }
23
+ function fmtDate(v) {
24
+ if (!v)
25
+ return "—";
26
+ return formatAmsterdam(v, { dateStyle: "short" }) || v;
27
+ }
28
+ export function VerzetOrderDialog({ open, orderRef, carrierTarget, onOpenChange }) {
29
+ const qc = useQueryClient();
30
+ const fetchCarriers = useServerFn(listCarriers);
31
+ const [pickupDate, setPickupDate] = useState("");
32
+ const [pickupFrom, setPickupFrom] = useState("");
33
+ const [pickupTo, setPickupTo] = useState("");
34
+ const [confirmOpen, setConfirmOpen] = useState(false);
35
+ const [reason, setReason] = useState("");
36
+ const [preview, setPreview] = useState(null);
37
+ const [loadingPreview, setLoadingPreview] = useState(false);
38
+ const [saving, setSaving] = useState(false);
39
+ const [history, setHistory] = useState([]);
40
+ const [pickMoments, setPickMoments] = useState([]);
41
+ const [pickDay, setPickDayValue] = useState("");
42
+ const carriersQuery = useQuery({
43
+ queryKey: ["carriers"],
44
+ enabled: open,
45
+ queryFn: () => safeServerCall(() => fetchCarriers(), { carriers: [] }, "listCarriers"),
46
+ retry: false,
47
+ });
48
+ const carrier = useMemo(() => {
49
+ const carriers = carriersQuery.data?.carriers ?? [];
50
+ if (carriers.length === 0)
51
+ return null;
52
+ return selectCarrierForTarget(carriers, {
53
+ carrierId: carrierTarget?.carrierId ?? null,
54
+ country: carrierTarget?.country ?? null,
55
+ province: carrierTarget?.province ?? null,
56
+ city: carrierTarget?.city ?? null,
57
+ });
58
+ }, [carriersQuery.data, carrierTarget?.carrierId, carrierTarget?.country, carrierTarget?.province, carrierTarget?.city]);
59
+ const carrierMoments = useMemo(() => (carrier ? normalizePickupMoments(carrier.pickup_moments) : []), [carrier]);
60
+ // Voorvertoning live opvragen bij elke wijziging in het formulier.
61
+ useEffect(() => {
62
+ if (!open)
63
+ return;
64
+ let cancelled = false;
65
+ setLoadingPreview(true);
66
+ const timer = setTimeout(async () => {
67
+ const res = await previewReschedule({
68
+ orderRef,
69
+ pickupDate: pickupDate || null,
70
+ pickupFrom: pickupFrom || null,
71
+ pickupTo: pickupTo || null,
72
+ });
73
+ if (cancelled)
74
+ return;
75
+ setPreview(res);
76
+ setLoadingPreview(false);
77
+ }, 250);
78
+ return () => {
79
+ cancelled = true;
80
+ clearTimeout(timer);
81
+ };
82
+ }, [open, orderRef, pickupDate, pickupFrom, pickupTo]);
83
+ useEffect(() => {
84
+ if (!open)
85
+ return;
86
+ void listRescheduleHistory(orderRef).then(setHistory);
87
+ void getPickMoments(orderRef).then((m) => {
88
+ setPickMoments(m);
89
+ setPickDayValue(toDayInput(m[0]?.plannedStart));
90
+ });
91
+ }, [open, orderRef]);
92
+ // Aanmeldmoment voorvullen met de huidige waarden, zodat het zichtbaar én wijzigbaar is.
93
+ useEffect(() => {
94
+ if (!open || !preview?.current)
95
+ return;
96
+ setPickupDate((v) => v || (preview.current.pickupDate ?? "").slice(0, 10));
97
+ setPickupFrom((v) => v || (preview.current.pickupFrom ?? "").slice(0, 5));
98
+ setPickupTo((v) => v || (preview.current.pickupTo ?? "").slice(0, 5));
99
+ }, [open, preview?.current?.pickupDate, preview?.current?.pickupFrom, preview?.current?.pickupTo]);
100
+ const currentPickDay = toDayInput(pickMoments[0]?.plannedStart);
101
+ const pickDayChanged = !!pickDay && pickDay !== currentPickDay;
102
+ const transportChanged = (!!pickupDate && pickupDate !== (preview?.current?.pickupDate ?? "").slice(0, 10)) ||
103
+ (!!pickupFrom && pickupFrom !== (preview?.current?.pickupFrom ?? "").slice(0, 5)) ||
104
+ (!!pickupTo && pickupTo !== (preview?.current?.pickupTo ?? "").slice(0, 5));
105
+ const direction = preview?.direction;
106
+ const needsCustomerChoice = direction === "later" && preview?.customerNoticeRequired !== false;
107
+ const blocked = !preview || preview.ok === false;
108
+ const summary = useMemo(() => {
109
+ if (!preview || preview.ok === false)
110
+ return null;
111
+ const shift = Math.abs(preview.dayShift ?? 0);
112
+ if (direction === "earlier") {
113
+ return `Order wordt ${shift} dag(en) eerder opgehaald. Het aflevermoment blijft ${fmtDate(preview.current?.deliveryDate)}.`;
114
+ }
115
+ if (direction === "later") {
116
+ return `Order wordt ${shift} dag(en) later. Nieuwe leverdatum: ${fmtDate(preview.next?.deliveryDate)}.`;
117
+ }
118
+ if (preview.timeChanged) {
119
+ return `Nieuwe ophaaltijd: ${preview.next?.pickupFrom ?? "—"} – ${preview.next?.pickupTo ?? "—"}.`;
120
+ }
121
+ return "Nog geen wijziging ingevuld.";
122
+ }, [preview, direction]);
123
+ const submit = async (notifyCustomer) => {
124
+ if (saving)
125
+ return;
126
+ setConfirmOpen(false);
127
+ setSaving(true);
128
+ try {
129
+ // Alleen de pickdag gewijzigd? Dan niets naar de Engine sturen: die zou
130
+ // "geen wijziging" terugmelden en de pickdag zou nooit worden opgeslagen.
131
+ if (!transportChanged) {
132
+ const res = await setPickDay(orderRef, pickDay);
133
+ if (!res.ok) {
134
+ toast.error(res.error ?? "Pickdag verzetten mislukt");
135
+ return;
136
+ }
137
+ await Promise.all([
138
+ qc.invalidateQueries({ queryKey: ENGINE_TASKS_KEY }),
139
+ qc.invalidateQueries({ queryKey: ["floriday", "orders"] }),
140
+ ]);
141
+ toast.success(`Pickdag verzet naar ${fmtDate(pickDay)} (${res.updated} pick-taak/taken).`);
142
+ onOpenChange(false);
143
+ return;
144
+ }
145
+ const result = await applyReschedule({
146
+ orderRef,
147
+ pickupDate: pickupDate || null,
148
+ pickupFrom: pickupFrom || null,
149
+ pickupTo: pickupTo || null,
150
+ notifyCustomer,
151
+ reason: reason.trim() || undefined,
152
+ });
153
+ if (result.ok === false || !result.applied) {
154
+ toast.error(result.error ?? "Verzetten mislukt");
155
+ return;
156
+ }
157
+ if (pickDayChanged) {
158
+ const res = await setPickDay(orderRef, pickDay);
159
+ if (!res.ok)
160
+ toast.error(res.error ?? "Pickdag verzetten mislukt");
161
+ }
162
+ // Taken opnieuw laden — de Engine heeft alles al herpland.
163
+ await Promise.all([
164
+ qc.invalidateQueries({ queryKey: ENGINE_TASKS_KEY }),
165
+ qc.invalidateQueries({ queryKey: ["floriday", "orders"] }),
166
+ ]);
167
+ if (notifyCustomer && !result.customerNotified) {
168
+ toast.error(`Verzet gelukt, maar de klantmail is niet verstuurd${result.customerNotifyError ? `: ${result.customerNotifyError}` : "."}`);
169
+ }
170
+ toast.success(`Verzet naar ${fmtDate(result.next?.pickupDate ?? result.current?.pickupDate)} ` +
171
+ `(${result.next?.pickupFrom ?? "—"}–${result.next?.pickupTo ?? "—"}), ` +
172
+ `leverdatum ${fmtDate(result.next?.deliveryDate)}. ` +
173
+ (result.customerNotified
174
+ ? "De Logistiek Engine heeft de klant per e-mail geïnformeerd."
175
+ : "Klant is niet geïnformeerd."));
176
+ onOpenChange(false);
177
+ }
178
+ finally {
179
+ setSaving(false);
180
+ }
181
+ };
182
+ const handleVerzetten = () => {
183
+ if (saving)
184
+ return;
185
+ if (!pickDayChanged && !transportChanged)
186
+ return;
187
+ if (transportChanged && blocked)
188
+ return;
189
+ // Alleen bij een latere leverdatum vragen we of de klant geïnformeerd moet worden.
190
+ if (needsCustomerChoice) {
191
+ setConfirmOpen(true);
192
+ return;
193
+ }
194
+ void submit(false);
195
+ };
196
+ return (_jsxs(Dialog, { open: open, onOpenChange: onOpenChange, children: [_jsxs(ResponsiveDialogContent, { size: "lg", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsxs(DialogTitle, { children: ["Order verzetten \u2014 ", orderRef] }), _jsx(DialogDescription, { children: "De Logistics Engine bepaalt de gevolgen; deze module past niets zelf aan." })] }), _jsxs(ResponsiveDialogBody, { className: "space-y-4", children: [_jsxs("div", { className: "rounded-md border p-3 space-y-2", children: [_jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Pickmoment (dag waarop de order gemaakt wordt)" }), pickMoments.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Nog geen pickmoment van de Engine." })) : (_jsxs(_Fragment, { children: [_jsxs("p", { className: "text-sm", children: ["Nu ingepland: ", fmtDateTime(pickMoments[0]?.plannedStart)] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Nieuwe pickdag" }), _jsx(Input, { type: "date", value: pickDay, onChange: (e) => setPickDayValue(e.target.value), className: "sm:w-56" })] }), pickDayChanged && (_jsxs("p", { className: "text-xs text-muted-foreground", children: [pickMoments.length, " pick-taak(en) worden naar deze dag verzet; het tijdstip blijft gelijk."] }))] }))] }), _jsxs("div", { className: "rounded-md border p-3 space-y-2", children: [_jsxs("p", { className: "text-xs font-medium text-muted-foreground", children: ["Vervoerder", carrier ? `: ${carrier.name}` : ""] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Vervoersdatum" }), _jsx(Input, { type: "date", value: pickupDate, onChange: (e) => setPickupDate(e.target.value), className: "sm:w-56" })] }), carrierMoments.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen vervoerder gekoppeld \u2014 aanmeldtijden zijn niet bekend." })) : (_jsxs(_Fragment, { children: [_jsxs("p", { className: "text-sm", children: ["Huidige aanmeldtijd: ", pickupFrom || "—", pickupTo && pickupTo !== pickupFrom ? `–${pickupTo}` : ""] }), _jsx("div", { className: "flex flex-wrap gap-2", children: carrierMoments.map((m, i) => {
197
+ const active = pickupFrom === m.signup_time;
198
+ return (_jsxs(Button, { type: "button", size: "sm", variant: active ? "default" : "outline", onClick: () => {
199
+ setPickupFrom(m.signup_time);
200
+ setPickupTo(m.signup_time);
201
+ }, children: [m.signup_time, _jsxs("span", { className: "ml-1 text-xs opacity-70", children: ["(", m.signup_days, " wd vooraf \u00B7 ophalen ", m.pickup_time, ")"] })] }, `${m.signup_time}-${i}`));
202
+ }) }), _jsx("p", { className: "text-xs text-muted-foreground", children: "Kies een aanmeldtijd van deze vervoerder." })] }))] }), preview?.current && (_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Huidig aanmeldmoment: ", fmtDate(preview.current.pickupDate), " ", preview.current.pickupFrom ?? "—", "\u2013", preview.current.pickupTo ?? "—", " \u00B7 leverdatum ", fmtDate(preview.current.deliveryDate)] })), loadingPreview && _jsx("p", { className: "text-sm text-muted-foreground", children: "Voorvertoning ophalen\u2026" }), preview && preview.ok === false && (_jsx("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive", children: preview.error ?? "De Engine kan deze wijziging niet verwerken." })), preview && preview.ok !== false && (_jsxs("div", { className: "rounded-md border bg-muted/40 p-3 text-sm space-y-2", children: [_jsx("p", { children: summary }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [preview.affectedTasks ?? 0, " taken worden opnieuw ingepland."] }), preview.planLocked && (_jsx(Badge, { variant: "outline", children: "Planning is vergrendeld door de Engine" }))] })), needsCustomerChoice && (_jsxs("div", { className: "space-y-1 rounded-md border p-3", children: [_jsx(Label, { children: "Reden voor de klantmelding (optioneel)" }), _jsx(Textarea, { value: reason, onChange: (e) => setReason(e.target.value), maxLength: 500, placeholder: "Bijv. Aanvoer bloemen vertraagd" })] })), history.length > 0 && (_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Verzetgeschiedenis" }), _jsx("ul", { className: "space-y-1 text-xs text-muted-foreground", children: history.map((h) => (_jsxs("li", { children: [new Date(h.created_at).toLocaleString("nl-NL"), " \u2014", " ", String(h.direction ?? ""), " ", String(h.reason ?? "")] }, h.id))) })] }))] }), _jsxs(ResponsiveDialogFooter, { children: [_jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Annuleren" }), _jsx(Button, { onClick: handleVerzetten, disabled: saving || loadingPreview || (!pickDayChanged && (!transportChanged || blocked)), children: saving ? "Opslaan…" : "Verzetten" })] })] }), _jsx(AlertDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Klant informeren?" }), _jsx(AlertDialogDescription, { children: "De leverdatum is gewijzigd naar een latere datum. Wilt u de klant hierover informeren?" })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { onClick: () => void submit(false), children: "Nee" }), _jsx(AlertDialogAction, { onClick: () => void submit(true), children: "Ja" })] })] }) })] }));
203
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAOjE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAEnF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA8DD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,UAAU,EACV,KAAK,EACL,gBAAgB,GACjB,EAAE,mBAAmB,+BA8JrB"}
1
+ {"version":3,"file":"WeekAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/WeekAgendaView.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAUjE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAEnF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA8DD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,UAAU,EACV,KAAK,EACL,gBAAgB,GACjB,EAAE,mBAAmB,+BAiKrB"}
@@ -4,6 +4,9 @@ import { Button, Badge, toast } from "@flowselections/core";
4
4
  import { ChevronLeft, ChevronRight, Package, Truck, Sprout, Clock, CheckCircle2, Scale, Printer } from "lucide-react";
5
5
  import { isSameDay, startOfWeek, addDays } from "../../lib/pickDate";
6
6
  import { printDeliveryNote, printDeliveryNotesMerged, } from "../../lib/deliveryNotePrint";
7
+ import { useCapacityCheck } from "../../hooks/useCapacityCheck";
8
+ import { CapacityWarning } from "./CapacityWarning";
9
+ import { toDayKey } from "../../lib/logisticsEngine/capacity";
7
10
  const WEEKDAY_LABELS = ["MAANDAG", "DINSDAG", "WOENSDAG", "DONDERDAG", "VRIJDAG", "ZATERDAG", "ZONDAG"];
8
11
  const MONTHS_NL_SHORT = ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"];
9
12
  function isOrderReady(o) {
@@ -142,6 +145,7 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayCl
142
145
  const totaalStuks = days.reduce((s, d) => s + d.planten, 0);
143
146
  return { leveringen, verzendklaar, voorbereiding, totaalStuks };
144
147
  }, [days]);
148
+ const capacity = useCapacityCheck(toDayKey(weekStart), toDayKey(weekEnd));
145
149
  const headerLabel = `Week ${weekNumber} - ${weekStart.getDate()} ${MONTHS_NL_SHORT[weekStart.getMonth()]}. t/m ${weekEnd.getDate()} ${MONTHS_NL_SHORT[weekEnd.getMonth()]}. ${weekEnd.getFullYear()}`;
146
150
  const goPrev = () => setCursor((c) => addDays(c, -7));
147
151
  const goNext = () => setCursor((c) => addDays(c, 7));
@@ -150,13 +154,13 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayCl
150
154
  d.setHours(0, 0, 0, 0);
151
155
  setCursor(startOfWeek(d));
152
156
  };
153
- return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h2", { className: "text-xl font-semibold tracking-tight", children: title ?? headerLabel }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: goPrev, children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), " Vorige week"] }), _jsx(Button, { variant: "outline", size: "sm", onClick: goToday, children: "Deze week" }), _jsxs(Button, { variant: "outline", size: "sm", onClick: goNext, children: ["Volgende week ", _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4", children: [_jsx(SummaryCard, { label: MODE_LABELS[mode].summary, value: totals.leveringen, tone: "default" }), _jsx(SummaryCard, { label: "Verzendklaar", value: totals.verzendklaar, tone: "success" }), _jsx(SummaryCard, { label: "In voorbereiding", value: totals.voorbereiding, tone: "muted" }), _jsx(SummaryCard, { label: "Totaal stuks", value: totals.totaalStuks, tone: "default" })] }), _jsx("div", { className: "space-y-2", children: isLoading ? (_jsx("div", { className: "rounded-lg border bg-card p-10 text-center text-sm text-muted-foreground", children: "Laden\u2026" })) : (days.map((day) => (_jsx(DayRow, { day: day, onOrderClick: onOrderClick, onDayClick: onDayClick, showPrintButtons: showPrintButtons }, day.date.toISOString())))) })] }));
157
+ return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("h2", { className: "text-xl font-semibold tracking-tight", children: title ?? headerLabel }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: goPrev, children: [_jsx(ChevronLeft, { className: "mr-1 h-4 w-4" }), " Vorige week"] }), _jsx(Button, { variant: "outline", size: "sm", onClick: goToday, children: "Deze week" }), _jsxs(Button, { variant: "outline", size: "sm", onClick: goNext, children: ["Volgende week ", _jsx(ChevronRight, { className: "ml-1 h-4 w-4" })] })] })] }), _jsxs("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4", children: [_jsx(SummaryCard, { label: MODE_LABELS[mode].summary, value: totals.leveringen, tone: "default" }), _jsx(SummaryCard, { label: "Verzendklaar", value: totals.verzendklaar, tone: "success" }), _jsx(SummaryCard, { label: "In voorbereiding", value: totals.voorbereiding, tone: "muted" }), _jsx(SummaryCard, { label: "Totaal stuks", value: totals.totaalStuks, tone: "default" })] }), _jsx("div", { className: "max-h-[520px] space-y-2 overflow-y-auto rounded-lg border bg-muted/20 p-2", children: isLoading ? (_jsx("div", { className: "rounded-lg border bg-card p-10 text-center text-sm text-muted-foreground", children: "Laden\u2026" })) : (days.map((day) => (_jsx(DayRow, { day: day, onOrderClick: onOrderClick, onDayClick: onDayClick, showPrintButtons: showPrintButtons, capacity: mode === "delivery" ? undefined : capacity.byDate.get(toDayKey(day.date)) }, day.date.toISOString())))) })] }));
154
158
  }
155
159
  function SummaryCard({ label, value, tone, }) {
156
160
  const valueClass = tone === "success" ? "text-green-600" : "text-foreground";
157
161
  return (_jsxs("div", { className: "rounded-lg border bg-card p-4", children: [_jsx("div", { className: `text-3xl font-bold ${valueClass}`, children: value }), _jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: label })] }));
158
162
  }
159
- function DayRow({ day, onOrderClick, onDayClick, showPrintButtons, }) {
163
+ function DayRow({ day, onOrderClick, onDayClick, showPrintButtons, capacity, }) {
160
164
  const weekdayIdx = (day.date.getDay() + 6) % 7;
161
165
  const today = new Date();
162
166
  today.setHours(0, 0, 0, 0);
@@ -200,7 +204,7 @@ function DayRow({ day, onOrderClick, onDayClick, showPrintButtons, }) {
200
204
  setPrintingOrderId(null);
201
205
  }
202
206
  };
203
- return (_jsx("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""}`, children: _jsxs("div", { className: "flex flex-wrap items-center gap-6 px-4 py-4 sm:px-6", children: [_jsxs("div", { className: "w-20 shrink-0", children: [_jsx("div", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: WEEKDAY_LABELS[weekdayIdx] }), _jsx("div", { className: "mt-1 text-3xl font-bold leading-none", children: day.date.getDate() }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [MONTHS_NL_SHORT[day.date.getMonth()], "."] })] }), _jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-6", children: [_jsx(Stat, { icon: _jsx(Package, { className: "h-4 w-4 text-slate-500" }), bg: "bg-slate-100", value: day.bestellingen, label: "bestellingen" }), _jsx(Stat, { icon: _jsx(Truck, { className: "h-4 w-4 text-amber-600" }), bg: "bg-amber-100", value: day.karren, label: "karren" }), _jsx(Stat, { icon: _jsx(Sprout, { className: "h-4 w-4 text-green-600" }), bg: "bg-green-100", value: day.planten, label: "planten" })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [day.movedEarlierOrderIds.size > 0 && (_jsxs(Badge, { className: "bg-purple-500/10 text-purple-700 hover:bg-purple-500/10", variant: "secondary", title: "Aantal orders dat vervroegd is ingepland door Pickverdeling.", children: [_jsx(Scale, { className: "mr-1 h-3.5 w-3.5" }), day.movedEarlierOrderIds.size, " vervroegd"] })), day.verzendklaar > 0 && (_jsxs(Badge, { className: "bg-green-500/15 text-green-700 hover:bg-green-500/15", variant: "secondary", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), day.verzendklaar, " verzendklaar"] })), day.voorbereiding > 0 && (_jsxs(Badge, { className: "bg-blue-500/10 text-blue-700 hover:bg-blue-500/10", variant: "secondary", children: [_jsx(Clock, { className: "mr-1 h-3.5 w-3.5" }), day.voorbereiding, " in voorbereiding"] })), showPrintButtons && printableItems.length > 0 && (_jsxs(Button, { size: "sm", variant: "outline", onClick: handlePrintDay, disabled: printingDay, children: [_jsx(Printer, { className: "mr-1 h-4 w-4" }), printingDay ? "Printen…" : `Print afleverbrieven (${printableItems.length})`] })), onDayClick && day.bestellingen > 0 && (_jsx(Button, { size: "sm", variant: "outline", onClick: () => onDayClick(day.date), children: "Dagdetails" }))] })] }) }));
207
+ return (_jsxs("div", { className: `rounded-lg border bg-card ${isToday ? "ring-1 ring-primary" : ""}`, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-6 px-4 py-4 sm:px-6", children: [_jsxs("div", { className: "w-20 shrink-0", children: [_jsx("div", { className: "text-xs font-medium tracking-wider text-muted-foreground", children: WEEKDAY_LABELS[weekdayIdx] }), _jsx("div", { className: "mt-1 text-3xl font-bold leading-none", children: day.date.getDate() }), _jsxs("div", { className: "text-sm text-muted-foreground", children: [MONTHS_NL_SHORT[day.date.getMonth()], "."] })] }), _jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-6", children: [_jsx(Stat, { icon: _jsx(Package, { className: "h-4 w-4 text-slate-500" }), bg: "bg-slate-100", value: day.bestellingen, label: "bestellingen" }), _jsx(Stat, { icon: _jsx(Truck, { className: "h-4 w-4 text-amber-600" }), bg: "bg-amber-100", value: day.karren, label: "karren" }), _jsx(Stat, { icon: _jsx(Sprout, { className: "h-4 w-4 text-green-600" }), bg: "bg-green-100", value: day.planten, label: "planten" })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [day.movedEarlierOrderIds.size > 0 && (_jsxs(Badge, { className: "bg-purple-500/10 text-purple-700 hover:bg-purple-500/10", variant: "secondary", title: "Aantal orders dat vervroegd is ingepland door Pickverdeling.", children: [_jsx(Scale, { className: "mr-1 h-3.5 w-3.5" }), day.movedEarlierOrderIds.size, " vervroegd"] })), day.verzendklaar > 0 && (_jsxs(Badge, { className: "bg-green-500/15 text-green-700 hover:bg-green-500/15", variant: "secondary", children: [_jsx(CheckCircle2, { className: "mr-1 h-3.5 w-3.5" }), day.verzendklaar, " verzendklaar"] })), day.voorbereiding > 0 && (_jsxs(Badge, { className: "bg-blue-500/10 text-blue-700 hover:bg-blue-500/10", variant: "secondary", children: [_jsx(Clock, { className: "mr-1 h-3.5 w-3.5" }), day.voorbereiding, " in voorbereiding"] })), showPrintButtons && printableItems.length > 0 && (_jsxs(Button, { size: "sm", variant: "outline", onClick: handlePrintDay, disabled: printingDay, children: [_jsx(Printer, { className: "mr-1 h-4 w-4" }), printingDay ? "Printen…" : `Print afleverbrieven (${printableItems.length})`] })), onDayClick && day.bestellingen > 0 && (_jsx(Button, { size: "sm", variant: "outline", onClick: () => onDayClick(day.date), children: "Dagdetails" }))] })] }), _jsx(CapacityWarning, { day: capacity, className: "mx-4 mb-4 sm:mx-6" })] }));
204
208
  }
205
209
  function Stat({ icon, bg, value, label, }) {
206
210
  return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: `grid h-8 w-8 place-items-center rounded-full ${bg}`, children: icon }), _jsxs("div", { children: [_jsx("div", { className: "text-lg font-bold leading-none", children: value }), _jsx("div", { className: "text-xs text-muted-foreground", children: label })] })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"PickstationPage.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/PickstationPage.tsx"],"names":[],"mappings":"AA2EA,wBAAgB,eAAe,gCA4Z9B"}
1
+ {"version":3,"file":"PickstationPage.d.ts","sourceRoot":"","sources":["../../../src/components/pickstation/PickstationPage.tsx"],"names":[],"mappings":"AA2EA,wBAAgB,eAAe,gCA6Z9B"}
@@ -264,6 +264,7 @@ export function PickstationPage() {
264
264
  orderSource: o.orderSource,
265
265
  cartIndex: o.cartIndex - 1,
266
266
  orderNumber: o.orderNumber,
267
+ orderNumbers: [o.orderNumber].filter(Boolean),
267
268
  customerName: o.customerName,
268
269
  carrierName: o.carrierName,
269
270
  deliveryDate: o.deliveryDate,
@@ -1 +1 @@
1
- {"version":3,"file":"VervoerdersSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/VervoerdersSettingsCard.tsx"],"names":[],"mappings":"AAcA,wBAAgB,uBAAuB,gCAwDtC"}
1
+ {"version":3,"file":"VervoerdersSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/VervoerdersSettingsCard.tsx"],"names":[],"mappings":"AAeA,wBAAgB,uBAAuB,gCAoDtC"}
@@ -4,6 +4,7 @@ import { Building2, Truck, ArrowRight } from "lucide-react";
4
4
  import { Link } from "@tanstack/react-router";
5
5
  import { useServerFn } from "@tanstack/react-start";
6
6
  import { useQuery } from "@tanstack/react-query";
7
+ import { toServerFnError } from "../../lib/serverFnError";
7
8
  import { listCarriers } from "../../lib/carriers.functions";
8
9
  export function VervoerdersSettingsCard() {
9
10
  const fetchList = useServerFn(listCarriers);
@@ -14,11 +15,7 @@ export function VervoerdersSettingsCard() {
14
15
  return await fetchList();
15
16
  }
16
17
  catch (e) {
17
- if (e instanceof Response) {
18
- const text = await e.text().catch(() => e.statusText);
19
- throw new Error(`${e.status}: ${text}`);
20
- }
21
- throw e;
18
+ throw await toServerFnError(e);
22
19
  }
23
20
  },
24
21
  });
@@ -0,0 +1,10 @@
1
+ import { type CapacityDay } from "../lib/logisticsEngine/capacity";
2
+ /**
3
+ * Capaciteitscontrole van de Logistics Engine voor een periode.
4
+ * Wordt opnieuw opgehaald bij elke periodewissel (from/to zitten in de queryKey).
5
+ */
6
+ export declare function useCapacityCheck(from: string | null, to: string | null): {
7
+ byDate: Map<string, CapacityDay>;
8
+ isLoading: boolean;
9
+ };
10
+ //# sourceMappingURL=useCapacityCheck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCapacityCheck.d.ts","sourceRoot":"","sources":["../../src/hooks/useCapacityCheck.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAEpF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;;;EAgBtE"}
@@ -0,0 +1,22 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import { getCapacityDays } from "../lib/logisticsEngine/capacity";
3
+ /**
4
+ * Capaciteitscontrole van de Logistics Engine voor een periode.
5
+ * Wordt opnieuw opgehaald bij elke periodewissel (from/to zitten in de queryKey).
6
+ */
7
+ export function useCapacityCheck(from, to) {
8
+ const query = useQuery({
9
+ queryKey: ["logistics-capacity-day-check", from, to],
10
+ queryFn: () => getCapacityDays(from, to),
11
+ enabled: !!from && !!to,
12
+ staleTime: 60000,
13
+ retry: false,
14
+ refetchInterval: 60000,
15
+ refetchIntervalInBackground: false,
16
+ refetchOnWindowFocus: true,
17
+ });
18
+ const byDate = new Map();
19
+ for (const d of query.data ?? [])
20
+ byDate.set(d.date, d);
21
+ return { byDate, isLoading: query.isLoading };
22
+ }
@@ -0,0 +1,14 @@
1
+ import { type EngineTask } from "../lib/logisticsEngine/engine";
2
+ export declare const ENGINE_TASKS_KEY: string[];
3
+ export declare function useEngineTasks(options?: {
4
+ taskTypes?: string[];
5
+ statuses?: string[];
6
+ }): {
7
+ tasks: EngineTask[];
8
+ isLoading: boolean;
9
+ error: string | undefined;
10
+ refetch: () => undefined;
11
+ };
12
+ /** Taken per order_ref, gesorteerd op sequence. */
13
+ export declare function groupTasksByOrder(tasks: EngineTask[]): Map<string, EngineTask[]>;
14
+ //# sourceMappingURL=useEngineTasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEngineTasks.d.ts","sourceRoot":"","sources":["../../src/hooks/useEngineTasks.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEjF,eAAO,MAAM,gBAAgB,UAAsB,CAAC;AAIpD,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;;;;;EAsCrF;AAED,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAShF"}
@@ -0,0 +1,49 @@
1
+ import { useEffect, useMemo } from "react";
2
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
3
+ import { supabase } from "../integrations/supabase/client";
4
+ import { listEngineTasks } from "../lib/logisticsEngine/engine";
5
+ export const ENGINE_TASKS_KEY = ["engine", "tasks"];
6
+ const OPEN_STATUSES = ["planned", "ready", "in_progress"];
7
+ export function useEngineTasks(options) {
8
+ const qc = useQueryClient();
9
+ const taskTypes = options?.taskTypes;
10
+ const statuses = options?.statuses ?? OPEN_STATUSES;
11
+ const query = useQuery({
12
+ queryKey: [...ENGINE_TASKS_KEY, taskTypes ?? "all", statuses],
13
+ queryFn: () => listEngineTasks({ taskTypes, statuses }),
14
+ retry: false,
15
+ refetchInterval: 60000,
16
+ refetchIntervalInBackground: false,
17
+ refetchOnWindowFocus: true,
18
+ });
19
+ useEffect(() => {
20
+ const channel = supabase
21
+ .channel("engine-tasks")
22
+ .on("postgres_changes", { event: "*", schema: "public", table: "logistics_tasks" }, () => {
23
+ void qc.invalidateQueries({ queryKey: ENGINE_TASKS_KEY });
24
+ })
25
+ .subscribe();
26
+ return () => {
27
+ void supabase.removeChannel(channel);
28
+ };
29
+ }, [qc]);
30
+ const tasks = useMemo(() => query.data ?? [], [query.data]);
31
+ return {
32
+ tasks,
33
+ isLoading: query.isLoading,
34
+ error: query.error instanceof Error ? query.error.message : undefined,
35
+ refetch: () => void query.refetch(),
36
+ };
37
+ }
38
+ /** Taken per order_ref, gesorteerd op sequence. */
39
+ export function groupTasksByOrder(tasks) {
40
+ const map = new Map();
41
+ for (const t of tasks) {
42
+ const list = map.get(t.order_ref) ?? [];
43
+ list.push(t);
44
+ map.set(t.order_ref, list);
45
+ }
46
+ for (const list of map.values())
47
+ list.sort((a, b) => a.sequence - b.sequence);
48
+ return map;
49
+ }
@@ -1,13 +1,19 @@
1
1
  import type { FloridayOrder } from "../lib/floriday.functions";
2
- import { type CartOverride } from "../lib/cartAssignments.functions";
3
2
  import { type OrderPlanning } from "../lib/planning";
3
+ import { type EngineTask } from "../lib/logisticsEngine/engine";
4
4
  export interface PlannedOrder {
5
5
  order: FloridayOrder;
6
+ /** Planning volgens de Logistics Engine. Null zolang er geen taak is. */
6
7
  planning: OrderPlanning | null;
8
+ /** De leidende load.compose-taak uit de Engine (indien aanwezig). */
9
+ engineTask: EngineTask | null;
10
+ /** True zolang de Engine nog geen load.compose-taak heeft geleverd. */
11
+ awaitingEngine: boolean;
7
12
  }
8
13
  export interface UseOrderPlanningResult {
9
14
  planned: PlannedOrder[];
10
- overrides: CartOverride[];
15
+ /** Orders die op een Engine-taak wachten en dus niet zijn ingedeeld. */
16
+ awaiting: PlannedOrder[];
11
17
  isLoading: boolean;
12
18
  error?: string;
13
19
  warning?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"useOrderPlanning.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrderPlanning.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAI/D,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAIxF,OAAO,EAKL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,gBAAgB,IAAI,sBAAsB,CA+KzD"}
1
+ {"version":3,"file":"useOrderPlanning.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrderPlanning.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAM/D,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAmB,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAEjF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,yEAAyE;IACzE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,uEAAuE;IACvE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,wEAAwE;IACxE,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAMD,wBAAgB,gBAAgB,IAAI,sBAAsB,CA6LzD"}