@flowselections/floriday-afhandeling-module 1.0.15 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/LeveringenPage.js +2 -2
- package/dist-lib/components/afhandeling/PickAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/PickAgendaView.js +2 -3
- package/dist-lib/components/afhandeling/WeekAgendaView.d.ts.map +1 -1
- package/dist-lib/components/afhandeling/WeekAgendaView.js +31 -17
- package/dist-lib/components/engine/CapaciteitsmaatregelenPage.d.ts +2 -0
- package/dist-lib/components/engine/CapaciteitsmaatregelenPage.d.ts.map +1 -0
- package/dist-lib/components/engine/CapaciteitsmaatregelenPage.js +40 -0
- package/dist-lib/components/engine/CapaciteitsmonitorPage.d.ts +2 -0
- package/dist-lib/components/engine/CapaciteitsmonitorPage.d.ts.map +1 -0
- package/dist-lib/components/engine/CapaciteitsmonitorPage.js +49 -0
- package/dist-lib/components/engine/FormulesPage.d.ts +2 -0
- package/dist-lib/components/engine/FormulesPage.d.ts.map +1 -0
- package/dist-lib/components/engine/FormulesPage.js +252 -0
- package/dist-lib/components/engine/PlaceholderPage.d.ts +6 -0
- package/dist-lib/components/engine/PlaceholderPage.d.ts.map +1 -0
- package/dist-lib/components/engine/PlaceholderPage.js +6 -0
- package/dist-lib/components/engine/StrategieenPage.d.ts +2 -0
- package/dist-lib/components/engine/StrategieenPage.d.ts.map +1 -0
- package/dist-lib/components/engine/StrategieenPage.js +80 -0
- package/dist-lib/components/pickstation/PickstationPage.d.ts.map +1 -1
- package/dist-lib/components/pickstation/PickstationPage.js +16 -4
- package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
- package/dist-lib/hooks/useOrderPlanning.js +37 -3
- package/dist-lib/index.d.ts.map +1 -1
- package/dist-lib/index.js +2 -1
- package/dist-lib/integrations/supabase/auth-middleware.d.ts +1496 -272
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts +1496 -272
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts +1496 -272
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/types.d.ts +1523 -266
- package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
- package/dist-lib/lib/afhandelingSettings.functions.d.ts +2944 -496
- package/dist-lib/lib/afhandelingSettings.functions.d.ts.map +1 -1
- package/dist-lib/lib/ai-gateway.server.d.ts +2 -0
- package/dist-lib/lib/ai-gateway.server.d.ts.map +1 -0
- package/dist-lib/lib/ai-gateway.server.js +11 -0
- package/dist-lib/lib/authGateway.server.d.ts +16 -0
- package/dist-lib/lib/authGateway.server.d.ts.map +1 -0
- package/dist-lib/lib/authGateway.server.js +200 -0
- package/dist-lib/lib/carriers.functions.d.ts +7100 -980
- package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartAssignments.functions.d.ts +7100 -980
- package/dist-lib/lib/cartAssignments.functions.d.ts.map +1 -1
- package/dist-lib/lib/cartControl.functions.d.ts +14630 -2390
- package/dist-lib/lib/cartControl.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.d.ts +1496 -272
- package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
- package/dist-lib/lib/floriday.functions.js +41 -8
- package/dist-lib/lib/logisticsEngine/capacity.functions.d.ts +50282 -0
- package/dist-lib/lib/logisticsEngine/capacity.functions.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/capacity.functions.js +90 -0
- package/dist-lib/lib/logisticsEngine/config.d.ts +140 -0
- package/dist-lib/lib/logisticsEngine/config.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/config.js +488 -0
- package/dist-lib/lib/logisticsEngine/enginePickTime.d.ts +29 -0
- package/dist-lib/lib/logisticsEngine/enginePickTime.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/enginePickTime.js +136 -0
- package/dist-lib/lib/logisticsEngine/evaluate.functions.d.ts +12604 -0
- package/dist-lib/lib/logisticsEngine/evaluate.functions.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/evaluate.functions.js +104 -0
- package/dist-lib/lib/logisticsEngine/expression.d.ts +21 -0
- package/dist-lib/lib/logisticsEngine/expression.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/expression.js +263 -0
- package/dist-lib/lib/logisticsEngine/formulas.functions.d.ts +25164 -0
- package/dist-lib/lib/logisticsEngine/formulas.functions.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/formulas.functions.js +58 -0
- package/dist-lib/lib/logisticsEngine/safetyLayer.d.ts +83 -0
- package/dist-lib/lib/logisticsEngine/safetyLayer.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/safetyLayer.js +182 -0
- package/dist-lib/lib/logisticsEngine/strategies.functions.d.ts +100569 -0
- package/dist-lib/lib/logisticsEngine/strategies.functions.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/strategies.functions.js +176 -0
- package/dist-lib/lib/logisticsEngine/variables.d.ts +29 -0
- package/dist-lib/lib/logisticsEngine/variables.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/variables.js +144 -0
- package/dist-lib/lib/logisticsEngine/wizard.functions.d.ts +50288 -0
- package/dist-lib/lib/logisticsEngine/wizard.functions.d.ts.map +1 -0
- package/dist-lib/lib/logisticsEngine/wizard.functions.js +175 -0
- package/dist-lib/lib/pickstationI18n.d.ts +2 -0
- package/dist-lib/lib/pickstationI18n.d.ts.map +1 -1
- package/dist-lib/lib/pickstationI18n.js +12 -0
- package/dist-lib/lib/pickstationOrders.server.d.ts +5 -0
- package/dist-lib/lib/pickstationOrders.server.d.ts.map +1 -1
- package/dist-lib/lib/pickstationOrders.server.js +29 -0
- package/dist-lib/lib/pickstationTypes.d.ts +4 -0
- package/dist-lib/lib/pickstationTypes.d.ts.map +1 -1
- package/package.json +24 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LeveringenPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/LeveringenPage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LeveringenPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/LeveringenPage.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,cAAc,gCA2F7B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useState } from "react";
|
|
3
3
|
import { useQueryClient } from "@tanstack/react-query";
|
|
4
|
-
import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
|
|
4
|
+
import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "@flowselections/core";
|
|
5
5
|
import { RefreshCw } from "lucide-react";
|
|
6
6
|
import { WeekAgendaView } from "./WeekAgendaView";
|
|
7
7
|
import { useOrderPlanning } from "../../hooks/useOrderPlanning";
|
|
@@ -33,5 +33,5 @@ export function LeveringenPage() {
|
|
|
33
33
|
return true;
|
|
34
34
|
});
|
|
35
35
|
}, [planned, customer, deliveryType, dateFrom, dateTo]);
|
|
36
|
-
return (
|
|
36
|
+
return (_jsxs("main", { className: "p-6 space-y-6", children: [_jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum vanaf" }), _jsx(Input, { type: "date", value: dateFrom, onChange: (e) => setDateFrom(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum t/m" }), _jsx(Input, { type: "date", value: dateTo, onChange: (e) => setDateTo(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Klant" }), _jsxs(Select, { value: customer, onValueChange: setCustomer, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle klanten" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle klanten" }), customers.map((c) => _jsx(SelectItem, { value: c, children: c }, c))] })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Type levering" }), _jsxs(Select, { value: deliveryType, onValueChange: setDeliveryType, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle types" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle types" }), deliveryTypes.map((t) => _jsx(SelectItem, { value: t, children: t }, t))] })] })] })] }), _jsx("div", { className: "flex items-end gap-2", children: _jsxs(Button, { variant: "outline", onClick: handleRecalc, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Herbereken planning"] }) })] }), warning && !error && (_jsxs("div", { className: "rounded-md border border-amber-300 bg-amber-50 p-4 text-sm text-amber-900", children: [warning, " De beschikbare orders blijven zichtbaar."] })), error ? (_jsxs("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive", children: [error, _jsx(Button, { size: "sm", variant: "outline", className: "ml-3", onClick: () => refetch(), children: "Opnieuw proberen" })] })) : (_jsx(WeekAgendaView, { planned: filtered, mode: "delivery", isLoading: isLoading, showPrintButtons: true }))] }));
|
|
37
37
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PickAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/PickAgendaView.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PickAgendaView.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/PickAgendaView.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAIlE,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,cAAc,CAAC,EAAE,YAAY,EAAE,EAAE,mBAAmB,+BAmGnE"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo, useState } from "react";
|
|
3
3
|
import { useQueryClient } from "@tanstack/react-query";
|
|
4
|
-
import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
|
|
4
|
+
import { Button, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, toast, } from "@flowselections/core";
|
|
5
5
|
import { RefreshCw } from "lucide-react";
|
|
6
|
-
import { toast } from "@flowselections/core";
|
|
7
6
|
import { WeekAgendaView } from "./WeekAgendaView";
|
|
8
7
|
import { DagDetailDialog } from "./DagDetailDialog";
|
|
9
8
|
import { useOrderPlanning } from "../../hooks/useOrderPlanning";
|
|
@@ -36,5 +35,5 @@ export function PickAgendaView({ onOrderClick }) {
|
|
|
36
35
|
return true;
|
|
37
36
|
});
|
|
38
37
|
}, [planned, customer, deliveryType, dateFrom, dateTo]);
|
|
39
|
-
return (_jsxs(
|
|
38
|
+
return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { className: "flex flex-wrap items-end justify-between gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum vanaf" }), _jsx(Input, { type: "date", value: dateFrom, onChange: (e) => setDateFrom(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Datum t/m" }), _jsx(Input, { type: "date", value: dateTo, onChange: (e) => setDateTo(e.target.value), className: "w-40" })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Klant" }), _jsxs(Select, { value: customer, onValueChange: setCustomer, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle klanten" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle klanten" }), customers.map((c) => _jsx(SelectItem, { value: c, children: c }, c))] })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { className: "text-xs text-muted-foreground", children: "Type levering" }), _jsxs(Select, { value: deliveryType, onValueChange: setDeliveryType, children: [_jsx(SelectTrigger, { className: "w-56", children: _jsx(SelectValue, { placeholder: "Alle types" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: "Alle types" }), deliveryTypes.map((t) => _jsx(SelectItem, { value: t, children: t }, t))] })] })] })] }), _jsx("div", { className: "flex items-end gap-2", children: _jsxs(Button, { variant: "outline", onClick: handleRecalc, children: [_jsx(RefreshCw, { className: "mr-2 h-4 w-4" }), "Herbereken planning"] }) })] }), warning && !error && (_jsxs("div", { className: "rounded-md border border-amber-300 bg-amber-50 p-4 text-sm text-amber-900", children: [warning, " De beschikbare orders blijven zichtbaar."] })), error ? (_jsxs("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-4 text-sm text-destructive", children: [error, _jsx(Button, { size: "sm", variant: "outline", className: "ml-3", onClick: () => refetch(), children: "Opnieuw proberen" })] })) : (_jsx(WeekAgendaView, { planned: filtered, mode: "pick", isLoading: isLoading, onOrderClick: onOrderClick, onDayClick: setDayDetailDate })), _jsx(DagDetailDialog, { open: !!dayDetailDate, date: dayDetailDate, planned: filtered, onOpenChange: (o) => !o && setDayDetailDate(null) })] }));
|
|
40
39
|
}
|
|
@@ -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,+
|
|
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,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState } from "react";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
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";
|
|
@@ -44,6 +44,35 @@ export function WeekAgendaView({ planned, mode, isLoading, onOrderClick, onDayCl
|
|
|
44
44
|
d.setHours(0, 0, 0, 0);
|
|
45
45
|
return startOfWeek(d);
|
|
46
46
|
});
|
|
47
|
+
// Als er in de huidige week niks staat maar er zijn wél orders in de
|
|
48
|
+
// toekomst, spring dan éénmalig naar de eerstvolgende week met data zodat
|
|
49
|
+
// gebruikers hun orders direct zien in plaats van een lege week.
|
|
50
|
+
const autoJumpedRef = useRef(false);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (autoJumpedRef.current)
|
|
53
|
+
return;
|
|
54
|
+
if (!planned.length)
|
|
55
|
+
return;
|
|
56
|
+
const today = new Date();
|
|
57
|
+
today.setHours(0, 0, 0, 0);
|
|
58
|
+
const currentWeekStart = startOfWeek(today);
|
|
59
|
+
const currentWeekEnd = addDays(currentWeekStart, 6);
|
|
60
|
+
const dates = planned
|
|
61
|
+
.map((p) => dateForPlanned(p, mode))
|
|
62
|
+
.filter((d) => !!d);
|
|
63
|
+
const hasCurrent = dates.some((d) => d >= currentWeekStart && d <= new Date(currentWeekEnd.getTime() + 86399999));
|
|
64
|
+
if (hasCurrent) {
|
|
65
|
+
autoJumpedRef.current = true;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const future = dates
|
|
69
|
+
.filter((d) => d > currentWeekEnd)
|
|
70
|
+
.sort((a, b) => a.getTime() - b.getTime());
|
|
71
|
+
if (future.length > 0) {
|
|
72
|
+
setCursor(startOfWeek(future[0]));
|
|
73
|
+
autoJumpedRef.current = true;
|
|
74
|
+
}
|
|
75
|
+
}, [planned, mode]);
|
|
47
76
|
const weekStart = useMemo(() => startOfWeek(cursor), [cursor]);
|
|
48
77
|
const weekEnd = useMemo(() => addDays(weekStart, 6), [weekStart]);
|
|
49
78
|
const weekNumber = useMemo(() => getISOWeek(weekStart), [weekStart]);
|
|
@@ -171,22 +200,7 @@ function DayRow({ day, onOrderClick, onDayClick, showPrintButtons, }) {
|
|
|
171
200
|
setPrintingOrderId(null);
|
|
172
201
|
}
|
|
173
202
|
};
|
|
174
|
-
return (
|
|
175
|
-
const moved = e.movedEarlier;
|
|
176
|
-
const split = e.splitPart;
|
|
177
|
-
const canPrint = showPrintButtons && e.order.source === "floriday" && !!e.order.salesOrderId;
|
|
178
|
-
return (_jsxs("div", { className: `flex items-center gap-1 rounded border px-2 py-1 text-xs ${moved || split ? "border-purple-300 bg-purple-50" : ""}`, children: [_jsxs("button", { type: "button", onClick: () => onOrderClick?.(e.order), disabled: !onOrderClick, title: [
|
|
179
|
-
split
|
|
180
|
-
? `Deel ${split.index}/${split.total} — ${e.cartCount} karren deze dag (verdeeld picken).`
|
|
181
|
-
: moved
|
|
182
|
-
? "Deze order is eerder ingepland vanwege Pickverdeling."
|
|
183
|
-
: null,
|
|
184
|
-
e.carrierName ? `Vervoerder: ${e.carrierName}` : null,
|
|
185
|
-
e.reason ? `Planning: ${e.reason}` : null,
|
|
186
|
-
]
|
|
187
|
-
.filter(Boolean)
|
|
188
|
-
.join("\n") || undefined, className: `flex items-center gap-1 ${onOrderClick ? "hover:underline" : "cursor-default"}`, children: [(moved || split) && _jsx(Scale, { className: "h-3 w-3 text-purple-600" }), _jsx("span", { className: "font-medium", children: e.order.orderNumber }), _jsxs("span", { className: "ml-1 text-muted-foreground", children: ["\u00B7 ", e.order.customerName] }), _jsxs("span", { className: "ml-1 text-purple-700", children: ["\u00B7 ", e.cartCount, " karren", split ? ` (deel ${split.index}/${split.total})` : ""] })] }), canPrint && (_jsx("button", { type: "button", onClick: () => handlePrintOrder(e.order), disabled: printingOrderId === e.order.id, title: "Afleverbrief printen", className: "ml-1 rounded p-0.5 hover:bg-muted disabled:opacity-50", children: _jsx(Printer, { className: "h-3.5 w-3.5" }) }))] }, `${e.order.id}-${idx}`));
|
|
189
|
-
}) }) }))] }));
|
|
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" }))] })] }) }));
|
|
190
204
|
}
|
|
191
205
|
function Stat({ icon, bg, value, label, }) {
|
|
192
206
|
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 })] })] }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CapaciteitsmaatregelenPage.d.ts","sourceRoot":"","sources":["../../../src/components/engine/CapaciteitsmaatregelenPage.tsx"],"names":[],"mappings":"AAiBA,wBAAgB,0BAA0B,gCAyIzC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { useMutation, useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
|
|
4
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
+
import { Card, CardContent, CardHeader, CardTitle, CardDescription, Button, Input, Label, Switch, Separator, toast, } from "@flowselections/core";
|
|
6
|
+
import { ChevronDown, ChevronUp, Save, ShieldCheck } from "lucide-react";
|
|
7
|
+
import { DEFAULT_CAPACITY_SETTINGS, MEASURE_LABELS, MEASURE_UNITS, } from "../../lib/logisticsEngine/safetyLayer";
|
|
8
|
+
import { getCapacitySettings, saveCapacitySettings } from "../../lib/logisticsEngine/capacity.functions";
|
|
9
|
+
export function CapaciteitsmaatregelenPage() {
|
|
10
|
+
const getFn = useServerFn(getCapacitySettings);
|
|
11
|
+
const saveFn = useServerFn(saveCapacitySettings);
|
|
12
|
+
const qc = useQueryClient();
|
|
13
|
+
const { data } = useSuspenseQuery({
|
|
14
|
+
queryKey: ["capacity-settings"],
|
|
15
|
+
queryFn: () => getFn(),
|
|
16
|
+
});
|
|
17
|
+
const [settings, setSettings] = useState(data.settings ?? DEFAULT_CAPACITY_SETTINGS);
|
|
18
|
+
useEffect(() => { setSettings(data.settings ?? DEFAULT_CAPACITY_SETTINGS); }, [data.settings]);
|
|
19
|
+
const save = useMutation({
|
|
20
|
+
mutationFn: () => saveFn({ data: { settings } }),
|
|
21
|
+
onSuccess: () => {
|
|
22
|
+
toast.success("Instellingen opgeslagen");
|
|
23
|
+
qc.invalidateQueries({ queryKey: ["capacity-settings"] });
|
|
24
|
+
},
|
|
25
|
+
onError: (e) => toast.error(e instanceof Error ? e.message : "Opslaan mislukt"),
|
|
26
|
+
});
|
|
27
|
+
const move = (idx, dir) => {
|
|
28
|
+
const next = [...settings.measures];
|
|
29
|
+
const j = idx + dir;
|
|
30
|
+
if (j < 0 || j >= next.length)
|
|
31
|
+
return;
|
|
32
|
+
[next[idx], next[j]] = [next[j], next[idx]];
|
|
33
|
+
setSettings({ ...settings, measures: next });
|
|
34
|
+
};
|
|
35
|
+
const patch = (idx, p) => {
|
|
36
|
+
const next = settings.measures.map((m, i) => (i === idx ? { ...m, ...p } : m));
|
|
37
|
+
setSettings({ ...settings, measures: next });
|
|
38
|
+
};
|
|
39
|
+
return (_jsxs("main", { className: "p-6 space-y-6 max-w-4xl", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsxs("h1", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(ShieldCheck, { className: "w-6 h-6" }), " Capaciteitsmaatregelen"] }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Bepaal welke maatregelen de engine mag inzetten wanneer de planning niet meer haalbaar is, en in welke volgorde." })] }), _jsxs(Button, { onClick: () => save.mutate(), disabled: save.isPending, children: [_jsx(Save, { className: "w-4 h-4 mr-2" }), " Opslaan"] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: "Drempels en modus" }), _jsx(CardDescription, { children: "Wanneer wordt de planning oranje of rood en mag de engine zelf ingrijpen?" })] }), _jsxs(CardContent, { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Oranje drempel (min reserve)" }), _jsx(Input, { type: "number", value: settings.amberThresholdMinutes, onChange: (e) => setSettings({ ...settings, amberThresholdMinutes: Number(e.target.value) || 0 }) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Rood drempel (min reserve)" }), _jsx(Input, { type: "number", value: settings.redThresholdMinutes, onChange: (e) => setSettings({ ...settings, redThresholdMinutes: Number(e.target.value) || 0 }) })] }), _jsxs("div", { className: "flex items-center justify-between rounded-md border p-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: "Automatisch toepassen" }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Voer maatregelen automatisch uit zodra ze nodig zijn." })] }), _jsx(Switch, { checked: settings.autoApply, onCheckedChange: (v) => setSettings({ ...settings, autoApply: Boolean(v), warningOnly: v ? false : settings.warningOnly }) })] }), _jsxs("div", { className: "flex items-center justify-between rounded-md border p-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: "Nooit automatisch ingrijpen" }), _jsx("div", { className: "text-xs text-muted-foreground", children: "Alleen waarschuwingen tonen, geen maatregelen voorstellen." })] }), _jsx(Switch, { checked: settings.warningOnly, onCheckedChange: (v) => setSettings({ ...settings, warningOnly: Boolean(v), autoApply: v ? false : settings.autoApply }) })] })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { className: "text-base", children: "Maatregelen op volgorde" }), _jsx(CardDescription, { children: "De engine probeert maatregelen van boven naar beneden totdat het tekort is opgelost." })] }), _jsx(CardContent, { className: "space-y-3", children: settings.measures.map((m, idx) => (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("div", { className: "flex flex-col", children: [_jsx("button", { className: "p-1 text-muted-foreground hover:text-foreground disabled:opacity-30", disabled: idx === 0, onClick: () => move(idx, -1), "aria-label": "Omhoog", children: _jsx(ChevronUp, { className: "w-4 h-4" }) }), _jsx("button", { className: "p-1 text-muted-foreground hover:text-foreground disabled:opacity-30", disabled: idx === settings.measures.length - 1, onClick: () => move(idx, 1), "aria-label": "Omlaag", children: _jsx(ChevronDown, { className: "w-4 h-4" }) })] }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsxs("div", { className: "font-medium", children: [idx + 1, ". ", MEASURE_LABELS[m.kind]] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Prioriteit ", idx + 1] })] }), _jsx(Switch, { checked: m.enabled, onCheckedChange: (v) => patch(idx, { enabled: Boolean(v) }) })] }), m.enabled && (_jsxs("div", { className: "mt-3 grid gap-3 sm:grid-cols-2", children: [_jsxs("div", { children: [_jsxs(Label, { children: ["Maximum (", MEASURE_UNITS[m.kind], ")"] }), _jsx(Input, { type: "number", value: m.max, onChange: (e) => patch(idx, { max: Number(e.target.value) || 0 }) })] }), m.kind === "extra-pickers" && (_jsxs("div", { children: [_jsx(Label, { children: "Karren/uur per picker" }), _jsx(Input, { type: "number", value: m.perUnit ?? 10, onChange: (e) => patch(idx, { perUnit: Number(e.target.value) || 0 }) })] }))] }))] })] }), idx < settings.measures.length - 1 && _jsx(Separator, { className: "mt-3" })] }, m.kind))) })] })] }));
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CapaciteitsmonitorPage.d.ts","sourceRoot":"","sources":["../../../src/components/engine/CapaciteitsmonitorPage.tsx"],"names":[],"mappings":"AAuBA,wBAAgB,sBAAsB,gCAiLrC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { useQuery } from "@tanstack/react-query";
|
|
4
|
+
import { useServerFn } from "@tanstack/react-start";
|
|
5
|
+
import { Card, CardContent, CardHeader, CardTitle, CardDescription, Input, Label, Badge, Separator, } from "@flowselections/core";
|
|
6
|
+
import { Activity, AlertTriangle, CheckCircle2, PlayCircle, TimerReset } from "lucide-react";
|
|
7
|
+
import { DEFAULT_CAPACITY_SETTINGS, evaluateCapacity, } from "../../lib/logisticsEngine/safetyLayer";
|
|
8
|
+
import { getCapacitySettings, listCapacityEvents } from "../../lib/logisticsEngine/capacity.functions";
|
|
9
|
+
function statusMeta(s) {
|
|
10
|
+
if (s === "green")
|
|
11
|
+
return { color: "bg-emerald-500", label: "Groen — planning haalbaar", icon: CheckCircle2 };
|
|
12
|
+
if (s === "amber")
|
|
13
|
+
return { color: "bg-amber-500", label: "Oranje — planning wordt kritisch", icon: AlertTriangle };
|
|
14
|
+
return { color: "bg-red-500", label: "Rood — planning niet meer haalbaar", icon: AlertTriangle };
|
|
15
|
+
}
|
|
16
|
+
export function CapaciteitsmonitorPage() {
|
|
17
|
+
const getSettingsFn = useServerFn(getCapacitySettings);
|
|
18
|
+
const listEventsFn = useServerFn(listCapacityEvents);
|
|
19
|
+
const settingsQ = useQuery({ queryKey: ["capacity-settings"], queryFn: () => getSettingsFn() });
|
|
20
|
+
const eventsQ = useQuery({ queryKey: ["capacity-events"], queryFn: () => listEventsFn(), refetchInterval: 30000 });
|
|
21
|
+
const settings = settingsQ.data?.settings ?? DEFAULT_CAPACITY_SETTINGS;
|
|
22
|
+
const [input, setInput] = useState({
|
|
23
|
+
remainingWorkHours: 4,
|
|
24
|
+
cartsPerHour: 10,
|
|
25
|
+
pickers: 1,
|
|
26
|
+
requiredCarts: 40,
|
|
27
|
+
remainingBreakMinutes: 30,
|
|
28
|
+
earlierStartRoom: 1,
|
|
29
|
+
});
|
|
30
|
+
const [extraSim, setExtraSim] = useState(10);
|
|
31
|
+
const evalNow = useMemo(() => evaluateCapacity(input, settings), [input, settings]);
|
|
32
|
+
const evalSim = useMemo(() => evaluateCapacity({ ...input, requiredCarts: input.requiredCarts + extraSim }, settings), [input, extraSim, settings]);
|
|
33
|
+
const meta = statusMeta(evalNow.status);
|
|
34
|
+
const Icon = meta.icon;
|
|
35
|
+
return (_jsxs("main", { className: "p-6 space-y-6 max-w-6xl", children: [_jsxs("div", { children: [_jsxs("h1", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(Activity, { className: "w-6 h-6" }), " Capaciteitsmonitor"] }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Live gezondheid van de logistieke planning. Simuleer extra orders en bekijk welke maatregelen ingezet zouden worden." })] }), _jsxs("div", { className: "grid gap-4 lg:grid-cols-3", children: [_jsxs(Card, { className: "lg:col-span-2", children: [_jsx(CardHeader, { className: "pb-2", children: _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("span", { className: `inline-flex h-8 w-8 items-center justify-center rounded-full ${meta.color}`, children: _jsx(Icon, { className: "w-4 h-4 text-white" }) }), _jsxs("div", { children: [_jsx(CardTitle, { className: "text-base", children: meta.label }), _jsx(CardDescription, { children: evalNow.reason })] })] }) }), _jsxs(CardContent, { className: "grid gap-4 sm:grid-cols-4", children: [_jsx(Stat, { label: "Beschikbaar", value: `${evalNow.availableCarts} karren` }), _jsx(Stat, { label: "Benodigd", value: `${evalNow.requiredCarts} karren` }), _jsx(Stat, { label: "Reserve", value: `${evalNow.reserveMinutes} min` }), _jsx(Stat, { label: "Verwachte eindtijd", value: `+${evalNow.expectedFinishMinutes} min` })] }), _jsxs(CardContent, { children: [_jsx("div", { className: "text-sm font-medium mb-2", children: "Actievoorstellen" }), evalNow.measures.length === 0 ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "Geen maatregelen nodig \u2014 planning past binnen de capaciteit." })) : (_jsx("ul", { className: "space-y-2", children: evalNow.measures.map((m, i) => (_jsxs("li", { className: "flex items-center justify-between rounded-md border p-2 text-sm", children: [_jsxs("div", { children: [_jsxs("div", { className: "font-medium", children: ["\u2714 ", m.label] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [m.amount, " ", m.unit, m.addsCarts > 0 ? ` → +${m.addsCarts} karren capaciteit` : ""] })] }), _jsxs(Badge, { variant: "secondary", children: ["stap ", i + 1] })] }, i))) })), evalNow.stillShortAfterMeasures > 0 && (_jsxs("div", { className: "mt-2 text-xs text-red-600", children: ["Zelfs met alle maatregelen blijft er een tekort van ", evalNow.stillShortAfterMeasures, " karren."] }))] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsxs(CardTitle, { className: "text-base flex items-center gap-2", children: [_jsx(TimerReset, { className: "w-4 h-4" }), " Huidige situatie"] }), _jsx(CardDescription, { children: "Pas aan om de monitor door te rekenen." })] }), _jsx(CardContent, { className: "space-y-2", children: [
|
|
36
|
+
["remainingWorkHours", "Resterende werkuren"],
|
|
37
|
+
["cartsPerHour", "Karren/uur (per picker)"],
|
|
38
|
+
["pickers", "Aantal pickers"],
|
|
39
|
+
["requiredCarts", "Benodigde karren"],
|
|
40
|
+
["remainingBreakMinutes", "Resterende pauze (min)"],
|
|
41
|
+
["earlierStartRoom", "Ruimte om eerder te starten (uur)"],
|
|
42
|
+
].map(([key, label]) => (_jsxs("div", { className: "grid grid-cols-2 items-center gap-2", children: [_jsx(Label, { className: "text-xs", children: label }), _jsx(Input, { type: "number", value: input[key], onChange: (e) => setInput({ ...input, [key]: Number(e.target.value) || 0 }) })] }, key))) })] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsxs(CardTitle, { className: "text-base flex items-center gap-2", children: [_jsx(PlayCircle, { className: "w-4 h-4" }), " Simulatie"] }), _jsx(CardDescription, { children: "Test wat er gebeurt bij een plotselinge extra order." })] }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "flex items-end gap-3", children: [_jsxs("div", { className: "w-40", children: [_jsx(Label, { className: "text-xs", children: "Extra karren" }), _jsx(Input, { type: "number", value: extraSim, onChange: (e) => setExtraSim(Number(e.target.value) || 0) })] }), _jsxs("div", { className: "text-sm", children: [_jsx("span", { className: "font-medium", children: "Resultaat: " }), _jsx(Badge, { variant: evalSim.status === "green" ? "secondary" : "destructive", children: evalSim.status === "green" ? "Haalbaar" : evalSim.status === "amber" ? "Kritisch" : "Niet haalbaar" })] })] }), _jsx("div", { className: "text-sm text-muted-foreground", children: evalSim.reason }), evalSim.measures.length > 0 && (_jsx("ul", { className: "text-sm list-disc list-inside", children: evalSim.measures.map((m, i) => (_jsxs("li", { children: [m.label, " \u2014 ", m.amount, " ", m.unit, m.addsCarts > 0 ? ` (+${m.addsCarts} karren)` : ""] }, i))) }))] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-2", children: [_jsx(CardTitle, { className: "text-base", children: "Auditlog" }), _jsx(CardDescription, { children: "Laatste 50 capaciteitsberekeningen." })] }), _jsx(CardContent, { children: eventsQ.isLoading ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "Laden\u2026" })) : (eventsQ.data?.events ?? []).length === 0 ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "Nog geen evaluaties gelogd." })) : (_jsx("ul", { className: "divide-y", children: (eventsQ.data?.events ?? []).map((ev) => {
|
|
43
|
+
const m = statusMeta(ev.status);
|
|
44
|
+
return (_jsxs("li", { className: "py-2 flex items-center gap-3 text-sm", children: [_jsx("span", { className: `h-2 w-2 rounded-full ${m.color}` }), _jsx("span", { className: "w-40 text-muted-foreground text-xs", children: new Date(ev.created_at).toLocaleString("nl-NL") }), _jsxs("span", { className: "flex-1", children: ["Benodigd ", ev.required_carts, ", beschikbaar ", ev.available_carts, ", reserve ", ev.reserve_minutes, " min", ev.shortage_carts > 0 ? ` — tekort ${ev.shortage_carts}` : ""] }), _jsx(Badge, { variant: "outline", children: ev.outcome })] }, ev.id));
|
|
45
|
+
}) })) })] }), _jsx(Separator, {}), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Instellingen aanpassen? Ga naar ", _jsx("a", { className: "underline", href: "/afhandeling/engine/capaciteit", children: "Capaciteitsmaatregelen" }), "."] })] }));
|
|
46
|
+
}
|
|
47
|
+
function Stat({ label, value }) {
|
|
48
|
+
return (_jsxs("div", { className: "rounded-md border p-3", children: [_jsx("div", { className: "text-xs text-muted-foreground", children: label }), _jsx("div", { className: "text-lg font-semibold", children: value })] }));
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormulesPage.d.ts","sourceRoot":"","sources":["../../../src/components/engine/FormulesPage.tsx"],"names":[],"mappings":"AA8DA,wBAAgB,YAAY,gCA2L3B"}
|