@flowselections/floriday-afhandeling-module 1.0.64 → 1.0.66

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 (33) hide show
  1. package/dist-lib/components/afhandeling/DagDetailDialog.d.ts +4 -0
  2. package/dist-lib/components/afhandeling/DagDetailDialog.d.ts.map +1 -1
  3. package/dist-lib/components/afhandeling/DagDetailDialog.js +26 -11
  4. package/dist-lib/components/afhandeling/LeveringenPage.d.ts.map +1 -1
  5. package/dist-lib/components/afhandeling/LeveringenPage.js +24 -2
  6. package/dist-lib/components/afhandeling/SignupMailMoments.js +7 -4
  7. package/dist-lib/components/afhandeling/VervoerderForm.d.ts.map +1 -1
  8. package/dist-lib/components/afhandeling/VervoerderForm.js +14 -7
  9. package/dist-lib/components/settings/AfhandelingSettingsCard.d.ts.map +1 -1
  10. package/dist-lib/components/settings/AfhandelingSettingsCard.js +1 -1
  11. package/dist-lib/hooks/useOrderPlanning.d.ts.map +1 -1
  12. package/dist-lib/hooks/useOrderPlanning.js +20 -5
  13. package/dist-lib/integrations/supabase/types.d.ts +249 -0
  14. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  15. package/dist-lib/lib/carrierPlanning.d.ts +4 -0
  16. package/dist-lib/lib/carrierPlanning.d.ts.map +1 -1
  17. package/dist-lib/lib/carrierPlanning.js +14 -8
  18. package/dist-lib/lib/carrierSignup.functions.d.ts +2 -0
  19. package/dist-lib/lib/carrierSignup.functions.d.ts.map +1 -1
  20. package/dist-lib/lib/carrierSignup.functions.js +2 -0
  21. package/dist-lib/lib/carriers.functions.d.ts.map +1 -1
  22. package/dist-lib/lib/carriers.functions.js +13 -6
  23. package/dist-lib/lib/pickWorkdays.d.ts +24 -0
  24. package/dist-lib/lib/pickWorkdays.d.ts.map +1 -0
  25. package/dist-lib/lib/pickWorkdays.js +30 -0
  26. package/dist-lib/lib/pickstationOrders.server.d.ts.map +1 -1
  27. package/dist-lib/lib/pickstationOrders.server.js +9 -3
  28. package/dist-lib/lib/planning.d.ts +19 -0
  29. package/dist-lib/lib/planning.d.ts.map +1 -1
  30. package/dist-lib/lib/planning.js +58 -11
  31. package/dist-lib/lib/signupMailText.d.ts.map +1 -1
  32. package/dist-lib/lib/signupMailText.js +2 -0
  33. package/package.json +1 -1
@@ -4,6 +4,10 @@ export interface DagDetailDialogProps {
4
4
  date: Date | null;
5
5
  planned: PlannedOrder[];
6
6
  onOpenChange: (open: boolean) => void;
7
+ /** Waar de dag op telt: leverdag (Planning en leveringen) of pickdag (Pick Agenda). */
8
+ basis?: "lever" | "pick";
9
+ /** Order (id) die uitgelicht wordt, bv. vanuit een link. */
10
+ highlightOrderId?: string | null;
7
11
  }
8
12
  export declare function DagDetailDialog(props: DagDetailDialogProps): import("react").JSX.Element | null;
9
13
  //# sourceMappingURL=DagDetailDialog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DagDetailDialog.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/DagDetailDialog.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AA6JjE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC;AAQD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,sCAG1D"}
1
+ {"version":3,"file":"DagDetailDialog.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/DagDetailDialog.tsx"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AA8JjE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAUD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,sCAG1D"}
@@ -9,6 +9,7 @@ import { ResponsiveDialogBody, ResponsiveDialogContent, ResponsiveDialogFooter,
9
9
  import { usePickAgenda } from "../../hooks/usePickAgenda";
10
10
  import { useOrderBuffers, useBufferMembers } from "../../hooks/useOrderBuffers";
11
11
  import { isSameDay } from "../../lib/pickDate";
12
+ import { isExcludedOrderStatus } from "../../lib/orderStatus";
12
13
  import { getOrderLines, getDayCartContents, getOrderCartIds, getPakbonCartInfo, } from "../../lib/cartAssignments.functions";
13
14
  import { printLayoutDocument, printPdfDocument, printFoutMelding } from "../../lib/printing";
14
15
  import { NuVersturenButton } from "./NuVersturenButton";
@@ -79,6 +80,7 @@ function StickerMeldingen({ orderId }) {
79
80
  return null;
80
81
  return (_jsx("ul", { className: "space-y-1", children: q.data.map((m, i) => (_jsxs("li", { className: "flex items-start gap-1 text-xs text-destructive", children: [_jsx(AlertTriangle, { className: "mt-0.5 h-3 w-3 shrink-0" }), _jsx("span", { children: m.melding })] }, (m.stickerId ?? "") + i))) }));
81
82
  }
83
+ const HighlightCtx = createContext(null);
82
84
  const NL_DATE = new Intl.DateTimeFormat("nl-NL", { dateStyle: "full" });
83
85
  function refKey(value) {
84
86
  return (value ?? "").trim().toUpperCase();
@@ -88,7 +90,7 @@ export function DagDetailDialog(props) {
88
90
  return null;
89
91
  return _jsx(DagDetailContent, { ...props, date: props.date });
90
92
  }
91
- function DagDetailContent({ open, date, planned, onOpenChange, }) {
93
+ function DagDetailContent({ open, date, planned, onOpenChange, basis = "pick", highlightOrderId, }) {
92
94
  const dayKey = toDayKey(date);
93
95
  const agenda = usePickAgenda(dayKey, dayKey);
94
96
  const row = agenda.byDate.get(dayKey);
@@ -102,16 +104,28 @@ function DagDetailContent({ open, date, planned, onOpenChange, }) {
102
104
  plannedByRef.set(k, p);
103
105
  }
104
106
  }
105
- const ordersOnDay = (row?.orders ?? []).map((o) => ({
106
- ref: o.orderRef,
107
- carts: o.carts,
108
- plants: o.plants,
109
- status: o.status,
110
- planned: plannedByRef.get(refKey(o.orderRef)) ?? null,
111
- }));
107
+ // Leverdag: dezelfde orders als de dagkaart in Planning en leveringen.
108
+ const ordersOnDay = basis === "lever"
109
+ ? planned
110
+ .filter((p) => p.planning?.deliveryDate && isSameDay(p.planning.deliveryDate, date))
111
+ .filter((p) => !/annul|cancel/i.test(p.order.status ?? "") && !isExcludedOrderStatus(p.order.status))
112
+ .map((p) => ({
113
+ ref: p.order.orderNumber || p.order.id,
114
+ carts: (p.planning?.pickAssignments ?? []).reduce((s, a) => s + a.cartCount, 0),
115
+ plants: p.order.plantCount ?? 0,
116
+ status: p.order.status ?? "",
117
+ planned: p,
118
+ }))
119
+ : (row?.orders ?? []).map((o) => ({
120
+ ref: o.orderRef,
121
+ carts: o.carts,
122
+ plants: o.plants,
123
+ status: o.status,
124
+ planned: plannedByRef.get(refKey(o.orderRef)) ?? null,
125
+ }));
112
126
  // Aanvullen met lokaal ingeplande orders die de Engine-rij (nog) niet noemt.
113
127
  const seen = new Set(ordersOnDay.map((o) => refKey(o.ref)));
114
- for (const p of planned) {
128
+ for (const p of basis === "lever" ? [] : planned) {
115
129
  const assigns = p.planning?.pickAssignments ?? [];
116
130
  const today = assigns.find((a) => isSameDay(a.date, date));
117
131
  if (!today)
@@ -181,7 +195,7 @@ function DagDetailContent({ open, date, planned, onOpenChange, }) {
181
195
  }
182
196
  // Tel karren op unieke kar-id (gedeelde bufferkar één keer); rijen zonder id tellen los.
183
197
  const uniekeKarren = new Set(cartRows.map((c) => c.cartId ?? `zonder-id:${c.key}`)).size;
184
- return (_jsx(ShipStateCtx.Provider, { value: shipState, children: _jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(ResponsiveDialogContent, { size: "xl", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsxs(DialogTitle, { children: ["Dagdetails \u2014 ", NL_DATE.format(date)] }), _jsxs(DialogDescription, { children: [ordersOnDay.length, " bestellingen \u00B7 ", uniekeKarren, " ", uniekeKarren === 1 ? "kar" : "karren", " \u00B7", " ", ordersOnDay.filter((o) => voortgang(o.status).done).length, " van ", ordersOnDay.length, " ", "bestellingen afgehandeld \u00B7 ", new Set(cartRows.filter((c) => voortgang(c.status).done).map((c) => c.cartId ?? `zonder-id:${c.key}`)).size, " van", " ", uniekeKarren, " karren afgehandeld"] })] }), _jsxs(ResponsiveDialogBody, { children: [_jsx(DayCapacityWarning, { date: date }), _jsx(BezettingCard, { date: date, cartsToday: uniekeKarren }), _jsx(SignupMailMoments, { from: dayKey, to: dayKey }), _jsxs(Tabs, { defaultValue: "bestellingen", children: [_jsxs(TabsList, { children: [_jsxs(TabsTrigger, { value: "bestellingen", children: ["Bestellingen (", ordersOnDay.length, ")"] }), _jsxs(TabsTrigger, { value: "karren", children: ["Karren (", uniekeKarren, ")"] })] }), _jsx(TabsContent, { value: "bestellingen", className: "mt-4", children: _jsx(BestellingenTab, { orders: ordersOnDay, isLoading: agenda.isLoading }) }), _jsx(TabsContent, { value: "karren", className: "mt-4", children: _jsx(KarrenTab, { carts: cartRows }) })] })] }), _jsx(ResponsiveDialogFooter, { children: _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Sluiten" }) })] }) }) }));
198
+ return (_jsx(HighlightCtx.Provider, { value: highlightOrderId ?? null, children: _jsx(ShipStateCtx.Provider, { value: shipState, children: _jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(ResponsiveDialogContent, { size: "xl", children: [_jsxs(ResponsiveDialogHeader, { children: [_jsxs(DialogTitle, { children: ["Dagdetails \u2014 ", NL_DATE.format(date), " (", basis === "lever" ? "leverdag" : "pickdag", ")"] }), _jsxs(DialogDescription, { children: [basis === "lever" ? "Bestellingen die op deze dag worden geleverd. " : "Bestellingen die op deze dag worden gepickt. ", ordersOnDay.length, " ", ordersOnDay.length === 1 ? "bestelling" : "bestellingen", " \u00B7 ", uniekeKarren, " ", uniekeKarren === 1 ? "kar" : "karren", " \u00B7", " ", ordersOnDay.filter((o) => voortgang(o.status).done).length, " van ", ordersOnDay.length, " ", ordersOnDay.length === 1 ? "bestelling" : "bestellingen", " afgehandeld \u00B7 ", new Set(cartRows.filter((c) => voortgang(c.status).done).map((c) => c.cartId ?? `zonder-id:${c.key}`)).size, " van", " ", uniekeKarren, " ", uniekeKarren === 1 ? "kar" : "karren", " afgehandeld"] })] }), _jsxs(ResponsiveDialogBody, { children: [_jsx(DayCapacityWarning, { date: date }), _jsx(BezettingCard, { date: date, cartsToday: uniekeKarren }), _jsx(SignupMailMoments, { from: dayKey, to: dayKey }), _jsxs(Tabs, { defaultValue: "bestellingen", children: [_jsxs(TabsList, { children: [_jsxs(TabsTrigger, { value: "bestellingen", children: ["Bestellingen (", ordersOnDay.length, ")"] }), _jsxs(TabsTrigger, { value: "karren", children: ["Karren (", uniekeKarren, ")"] })] }), _jsx(TabsContent, { value: "bestellingen", className: "mt-4", children: _jsx(BestellingenTab, { orders: ordersOnDay, isLoading: agenda.isLoading }) }), _jsx(TabsContent, { value: "karren", className: "mt-4", children: _jsx(KarrenTab, { carts: cartRows }) })] })] }), _jsx(ResponsiveDialogFooter, { children: _jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), children: "Sluiten" }) })] }) }) }) }));
185
199
  }
186
200
  function BezettingCard({ date, cartsToday }) {
187
201
  const queryClient = useQueryClient();
@@ -647,7 +661,8 @@ function OrderRow({ planned: p, cartsToday, engineStatus, }) {
647
661
  setPrinting(false);
648
662
  }
649
663
  };
650
- return (_jsxs("div", { className: "rounded-lg border bg-card", children: [_jsxs("div", { className: "flex flex-col gap-3 p-3", children: [_jsxs("button", { type: "button", onClick: () => setOpen((o) => !o), className: "-m-1 flex items-start gap-3 rounded-md p-1 text-left hover:bg-muted/50", children: [open ? (_jsx(ChevronDown, { className: "mt-1 h-4 w-4 shrink-0" })) : (_jsx(ChevronRight, { className: "mt-1 h-4 w-4 shrink-0" })), _jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-6 gap-y-1 text-sm", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "font-medium", children: p.order.orderNumber }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: p.order.customerName })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Type ", _jsx("span", { className: "text-foreground", children: p.order.deliveryType })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Leverdatum", " ", _jsx("span", { className: "text-foreground", children: p.order.deliveryDate
664
+ const highlighted = useContext(HighlightCtx) === p.order.id;
665
+ return (_jsxs("div", { className: `rounded-lg border bg-card ${highlighted ? "ring-2 ring-primary" : ""}`, ref: highlighted ? (el) => el?.scrollIntoView({ block: "center" }) : undefined, children: [_jsxs("div", { className: "flex flex-col gap-3 p-3", children: [_jsxs("button", { type: "button", onClick: () => setOpen((o) => !o), className: "-m-1 flex items-start gap-3 rounded-md p-1 text-left hover:bg-muted/50", children: [open ? (_jsx(ChevronDown, { className: "mt-1 h-4 w-4 shrink-0" })) : (_jsx(ChevronRight, { className: "mt-1 h-4 w-4 shrink-0" })), _jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-6 gap-y-1 text-sm", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "font-medium", children: p.order.orderNumber }), _jsx("div", { className: "truncate text-xs text-muted-foreground", children: p.order.customerName })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Type ", _jsx("span", { className: "text-foreground", children: p.order.deliveryType })] }), _jsxs("div", { className: "text-xs text-muted-foreground", children: ["Leverdatum", " ", _jsx("span", { className: "text-foreground", children: p.order.deliveryDate
651
666
  ? new Date(p.order.deliveryDate).toLocaleDateString("nl-NL")
652
667
  : "—" })] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", children: [cartsToday, " ", cartsToday === 1 ? "kar" : "karren", " vandaag"] }), _jsx(StatusBadge, { vg: vg })] }), _jsx(StickerMeldingen, { orderId: p.order.id })] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 border-t pt-3", children: [p.order.orderNumber && p.order.salesOrderId && !shipStateRow?.floridaySent ? _jsx(NuVersturenButton, { orderRef: p.order.orderNumber }) : null, p.order.salesOrderId ? _jsx(AutoSendStatus, { orderId: p.order.id, orderRef: p.order.orderNumber }) : null, _jsx(AfhandelenButton, { orderRef: p.order.orderNumber, done: vg.done }), _jsxs(Button, { size: "sm", variant: "outline", onClick: handlePrintAll, disabled: printing, title: "Alle documenten van deze bestelling afdrukken (pakbonnen per kar en de verzendbrief)", children: [_jsx(Printer, { className: "mr-1 h-3.5 w-3.5" }), printing ? "In de Printwachtrij…" : "Alle documenten afdrukken"] }), _jsxs(Button, { size: "sm", variant: "outline", onClick: (e) => {
653
668
  e.stopPropagation();
@@ -1 +1 @@
1
- {"version":3,"file":"LeveringenPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/LeveringenPage.tsx"],"names":[],"mappings":"AAOA,wBAAgB,cAAc,gCAqC7B"}
1
+ {"version":3,"file":"LeveringenPage.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/LeveringenPage.tsx"],"names":[],"mappings":"AAmBA,wBAAgB,cAAc,gCAmD7B"}
@@ -1,14 +1,36 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useMemo, useState } from "react";
2
+ import { useEffect, useMemo, useState } from "react";
3
3
  import { Button } from "@flowselections/core";
4
4
  import { WeekAgendaView } from "./WeekAgendaView";
5
5
  import { DagDetailDialog } from "./DagDetailDialog";
6
6
  import { useOrderPlanning } from "../../hooks/useOrderPlanning";
7
7
  import { agendaRange, currentWeekStart } from "../../lib/agendaRange";
8
+ import { startOfWeek } from "../../lib/pickDate";
9
+ /** Leest ?dag=JJJJ-MM-DD&order=<order_id> (link vanuit bv. Dashboards). */
10
+ function readLinkParams() {
11
+ const sp = new URLSearchParams(window.location.search);
12
+ const dag = sp.get("dag");
13
+ const order = sp.get("order");
14
+ const m = dag && /^(\d{4})-(\d{2})-(\d{2})$/.exec(dag);
15
+ const day = m ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : null;
16
+ const orderId = order && /^[0-9a-f-]{36}$/i.test(order) ? order : null;
17
+ return { day: day && !Number.isNaN(day.getTime()) ? day : null, orderId };
18
+ }
8
19
  export function LeveringenPage() {
9
20
  const [weekStart, setWeekStart] = useState(() => currentWeekStart());
10
21
  const range = useMemo(() => agendaRange(weekStart), [weekStart]);
11
22
  const { planned, nearestDeliveryDate, isLoading, error, warning, refetch } = useOrderPlanning(range);
12
23
  const [dayDetailDate, setDayDetailDate] = useState(null);
13
- return (_jsxs("main", { className: "p-6 space-y-6", children: [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: planned, mode: "delivery", isLoading: isLoading, onWeekChange: setWeekStart, onDayClick: setDayDetailDate, jumpToDate: nearestDeliveryDate })), _jsx(DagDetailDialog, { open: !!dayDetailDate, date: dayDetailDate, planned: planned, onOpenChange: (o) => !o && setDayDetailDate(null) })] }));
24
+ const [highlightOrderId, setHighlightOrderId] = useState(null);
25
+ const [linkDay, setLinkDay] = useState(null);
26
+ useEffect(() => {
27
+ const { day, orderId } = readLinkParams();
28
+ if (day) {
29
+ setLinkDay(new URLSearchParams(window.location.search).get("dag"));
30
+ setWeekStart(startOfWeek(day));
31
+ setDayDetailDate(day);
32
+ setHighlightOrderId(orderId);
33
+ }
34
+ }, []);
35
+ return (_jsxs("main", { className: "p-6 space-y-6", children: [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: planned, mode: "delivery", isLoading: isLoading, onWeekChange: setWeekStart, onDayClick: (d) => { setHighlightOrderId(null); setDayDetailDate(d); }, jumpToDate: linkDay ?? nearestDeliveryDate })), _jsx(DagDetailDialog, { open: !!dayDetailDate, date: dayDetailDate, planned: planned, basis: "lever", highlightOrderId: highlightOrderId, onOpenChange: (o) => !o && setDayDetailDate(null) })] }));
14
36
  }
@@ -29,15 +29,18 @@ export function SignupMailMoments({ from, to, compact }) {
29
29
  return null;
30
30
  return (_jsxs("div", { className: "space-y-2 rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm font-medium", children: [_jsx(Mail, { className: "h-4 w-4 text-primary" }), " Aanmeldmail vervoerders"] }), !ov.enabled ? _jsx("p", { className: "text-xs text-muted-foreground", children: "De aanmeldmail staat uit." }) : null, reason && ov.enabled ? _jsx("p", { className: "text-xs text-destructive", children: reason }) : null, unassigned > 0 ? (_jsxs("p", { className: "text-xs text-destructive", children: [unassigned, " ", unassigned === 1 ? "order heeft" : "orders hebben", " geen vervoerder. Stel een standaardvervoerder in bij Vervoerders."] })) : null, _jsx("ul", { className: "space-y-1", children: ov.groups.map((g) => (_jsx(MomentRow, { g: g, tz: tz, compact: compact, enabled: ov.enabled, onPreview: () => setPreview(g) }, `${g.carrier_id}-${g.pickup_date}-${g.pickup_moment_key}`))) }), preview ? _jsx(PreviewDialog, { g: preview, onClose: () => setPreview(null) }) : null] }));
31
31
  }
32
+ const kar = (n) => `${n} ${n === 1 ? "kar" : "karren"}`;
32
33
  function statusLine(g, tz, enabled) {
33
34
  const moment = compactMoment(g, tz);
34
35
  if (g.last) {
35
- const base = `Aanmeldmail verstuurd om ${fmtTime(g.last.sent_at, tz)} naar ${g.carrier_name} · ${g.last.cart_count} karren`;
36
- return g.last.fingerprint_match ? `${moment} — ${base}` : `${moment} — ${base} · wijziging volgt: nu ${g.cart_count} karren`;
36
+ if (g.last.fingerprint_match) {
37
+ return `${moment} — Al verstuurd om ${fmtTime(g.last.sent_at, tz)} naar ${g.carrier_name} · ${kar(g.last.cart_count)} — er is niets veranderd`;
38
+ }
39
+ return `${moment} — Aanmeldmail verstuurd om ${fmtTime(g.last.sent_at, tz)} naar ${g.carrier_name} · ${kar(g.last.cart_count)} · wijziging volgt: nu ${kar(g.cart_count)}`;
37
40
  }
38
41
  if (!enabled)
39
- return `${moment} — ${g.carrier_name} · ${g.cart_count} karren`;
40
- return `${moment} — Aanmeldmail volgt om ${fmtTime(g.send_at, tz)} naar ${g.carrier_name} · ${g.cart_count} karren`;
42
+ return `${moment} — ${g.carrier_name} · ${kar(g.cart_count)}`;
43
+ return `${moment} — Aanmeldmail volgt om ${fmtTime(g.send_at, tz)} naar ${g.carrier_name} · ${kar(g.cart_count)}`;
41
44
  }
42
45
  function compactMoment(g, tz) {
43
46
  return `Ophalen ${fmtDayTime(g.pickup_at, tz)}`;
@@ -1 +1 @@
1
- {"version":3,"file":"VervoerderForm.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/VervoerderForm.tsx"],"names":[],"mappings":"AA+CA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AA2PD,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,+BAyalD"}
1
+ {"version":3,"file":"VervoerderForm.d.ts","sourceRoot":"","sources":["../../../src/components/afhandeling/VervoerderForm.tsx"],"names":[],"mappings":"AA+CA,UAAU,KAAK;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAqQD,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,+BAiblD"}
@@ -18,7 +18,7 @@ const EMPTY = {
18
18
  address: "",
19
19
  notes: "",
20
20
  is_default: false,
21
- pickup_moments: [DEFAULT_PICKUP_MOMENT],
21
+ pickup_moments: [{ ...DEFAULT_PICKUP_MOMENT }],
22
22
  service_countries: [],
23
23
  service_provinces: [],
24
24
  service_cities: [],
@@ -45,8 +45,8 @@ function CountryPicker({ value, onChange, excluded, }) {
45
45
  setQuery("");
46
46
  }, className: "flex items-center justify-between w-full px-3 py-2 text-sm text-left hover:bg-muted", children: [_jsx("span", { children: c.name }), _jsx("span", { className: "text-xs text-muted-foreground", children: c.code })] }, c.code)))) })] })] }));
47
47
  }
48
- function PickupMomentRow({ label, days, time, maxDays, onDaysChange, onTimeChange, }) {
49
- return (_jsxs("div", { className: "grid grid-cols-[110px,1fr,1fr] items-center gap-3", children: [_jsx("div", { className: "text-sm font-medium", children: label }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: "Werkdagen v\u00F3\u00F3r levering" }), _jsx(IconInput, { icon: Calendar, type: "number", min: 0, max: maxDays, value: days, onChange: (e) => onDaysChange(Number(e.target.value) || 0) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: "Tijdstip" }), _jsx(IconInput, { icon: Clock, type: "time", value: time, onChange: (e) => onTimeChange(e.target.value) })] })] }));
48
+ function PickupMomentRow({ label, days, time, maxDays, onDaysChange, onTimeChange, showError, }) {
49
+ return (_jsxs("div", { className: "grid grid-cols-[110px,1fr,1fr] items-center gap-3", children: [_jsx("div", { className: "text-sm font-medium", children: label }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: "Werkdagen v\u00F3\u00F3r levering" }), _jsx(IconInput, { icon: Calendar, type: "number", min: 0, max: maxDays, value: days, onChange: (e) => onDaysChange(Number(e.target.value) || 0) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs text-muted-foreground", children: "Tijdstip" }), _jsx(IconInput, { icon: Clock, type: "time", value: time, required: true, "aria-invalid": showError && !time ? true : undefined, onChange: (e) => onTimeChange(e.target.value) }), showError && !time ? _jsx("p", { className: "text-xs text-destructive", children: "Vul een tijd in." }) : null] })] }));
50
50
  }
51
51
  // Normaliseer een ophaalmoment: aanmelden moet altijd vóór (of op) ophalen
52
52
  // liggen, ophalen vóór (of op) bezorgen. Werkdagen-waardes zijn afstanden tot
@@ -73,13 +73,13 @@ function normalizeMoment(next, prev) {
73
73
  }
74
74
  return m;
75
75
  }
76
- function PickupMomentEditor({ index, value, canDelete, onChange, onDelete, }) {
76
+ function PickupMomentEditor({ index, value, canDelete, onChange, onDelete, showErrors, }) {
77
77
  const update = (patch) => {
78
78
  const next = { ...value, ...patch };
79
79
  onChange(normalizeMoment(next, value));
80
80
  };
81
81
  const pickupInvalid = value.pickup_days > value.signup_days;
82
- return (_jsxs("div", { className: "rounded-md border bg-background p-4 space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "text-sm font-semibold", children: ["Ophaalmoment ", index + 1] }), canDelete ? (_jsxs("button", { type: "button", onClick: onDelete, className: "text-xs text-muted-foreground hover:text-destructive inline-flex items-center gap-1", "aria-label": "Ophaalmoment verwijderen", children: [_jsx(Trash2, { className: "w-3.5 h-3.5" }), "Verwijderen"] })) : null] }), _jsxs("div", { className: "space-y-3", children: [_jsx(PickupMomentRow, { label: "Aanmelden", days: value.signup_days, time: value.signup_time, onDaysChange: (n) => update({ signup_days: n }), onTimeChange: (v) => update({ signup_time: v }) }), _jsx(PickupMomentRow, { label: "Ophalen", days: value.pickup_days, time: value.pickup_time, maxDays: value.signup_days, onDaysChange: (n) => update({ pickup_days: Math.min(n, value.signup_days) }), onTimeChange: (v) => update({ pickup_time: v }) }), pickupInvalid ? (_jsx("p", { className: "text-xs text-destructive -mt-1 pl-[122px]", children: "Ophalen kan niet v\u00F3\u00F3r aanmelden plaatsvinden." })) : null, _jsx(PickupMomentRow, { label: "Bezorgen", days: value.delivery_days, time: value.delivery_time, maxDays: value.pickup_days, onDaysChange: (n) => update({ delivery_days: Math.min(n, value.pickup_days) }), onTimeChange: (v) => update({ delivery_time: v }) })] })] }));
82
+ return (_jsxs("div", { className: "rounded-md border bg-background p-4 space-y-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "text-sm font-semibold", children: ["Ophaalmoment ", index + 1] }), canDelete ? (_jsxs("button", { type: "button", onClick: onDelete, className: "text-xs text-muted-foreground hover:text-destructive inline-flex items-center gap-1", "aria-label": "Ophaalmoment verwijderen", children: [_jsx(Trash2, { className: "w-3.5 h-3.5" }), "Verwijderen"] })) : null] }), _jsxs("div", { className: "space-y-3", children: [_jsx(PickupMomentRow, { label: "Aanmelden", days: value.signup_days, time: value.signup_time, onDaysChange: (n) => update({ signup_days: n }), onTimeChange: (v) => update({ signup_time: v }), showError: showErrors }), _jsx(PickupMomentRow, { label: "Ophalen", days: value.pickup_days, time: value.pickup_time, maxDays: value.signup_days, onDaysChange: (n) => update({ pickup_days: Math.min(n, value.signup_days) }), onTimeChange: (v) => update({ pickup_time: v }), showError: showErrors }), pickupInvalid ? (_jsx("p", { className: "text-xs text-destructive -mt-1 pl-[122px]", children: "Ophalen kan niet v\u00F3\u00F3r aanmelden plaatsvinden." })) : null, _jsx(PickupMomentRow, { label: "Bezorgen", days: value.delivery_days, time: value.delivery_time, maxDays: value.pickup_days, onDaysChange: (n) => update({ delivery_days: Math.min(n, value.pickup_days) }), onTimeChange: (v) => update({ delivery_time: v }), showError: showErrors })] })] }));
83
83
  }
84
84
  export function VervoerderForm({ carrierId }) {
85
85
  const isEdit = !!carrierId;
@@ -89,6 +89,7 @@ export function VervoerderForm({ carrierId }) {
89
89
  const saveCarrier = useServerFn(upsertCarrier);
90
90
  const [form, setForm] = useState(EMPTY);
91
91
  const [rates, setRates] = useState([]);
92
+ const [showTimeErrors, setShowTimeErrors] = useState(false);
92
93
  const [pendingCountry, setPendingCountry] = useState("");
93
94
  const [pendingPrice, setPendingPrice] = useState("");
94
95
  const { data, isLoading } = useQuery({
@@ -110,7 +111,7 @@ export function VervoerderForm({ carrierId }) {
110
111
  is_default: c.is_default ?? false,
111
112
  pickup_moments: c.pickup_moments && c.pickup_moments.length > 0
112
113
  ? c.pickup_moments
113
- : [DEFAULT_PICKUP_MOMENT],
114
+ : [{ ...DEFAULT_PICKUP_MOMENT }],
114
115
  service_countries: c.service_countries ?? [],
115
116
  service_provinces: c.service_provinces ?? [],
116
117
  service_cities: c.service_cities ?? [],
@@ -173,6 +174,12 @@ export function VervoerderForm({ carrierId }) {
173
174
  toast.error("Bedrijfsnaam is verplicht");
174
175
  return;
175
176
  }
177
+ // Tijden zijn verplicht: er wordt nooit stil een tijd ingevuld.
178
+ if (form.pickup_moments.some((m) => !m.signup_time || !m.pickup_time || !m.delivery_time)) {
179
+ setShowTimeErrors(true);
180
+ toast.error("Vul bij elk ophaalmoment alle tijden in.");
181
+ return;
182
+ }
176
183
  mutation.mutate();
177
184
  };
178
185
  if (isEdit && isLoading) {
@@ -180,7 +187,7 @@ export function VervoerderForm({ carrierId }) {
180
187
  }
181
188
  return (_jsxs("main", { className: "p-6 space-y-6 max-w-4xl", children: [_jsx(Button, { asChild: true, variant: "ghost", size: "sm", children: _jsxs(Link, { to: "/afhandeling/vervoerders", children: [_jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }), "Terug naar vervoerders"] }) }), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx(FieldIcon, { icon: Truck }), _jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold", children: isEdit ? "Vervoerder bewerken" : "Vervoerder aanmaken" }), _jsx("p", { className: "text-sm text-muted-foreground", children: isEdit
182
189
  ? "Wijzig de gegevens van de vervoerder."
183
- : "Voeg een nieuwe vervoerder toe en stel verzendtarieven in." })] })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base", children: "Algemene gegevens" }) }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { children: ["Bedrijfsnaam ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(IconInput, { icon: Truck, value: form.name, onChange: (e) => setForm({ ...form, name: e.target.value }), placeholder: "Bijv. DHL Freight", required: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Contactpersoon" }), _jsx(IconInput, { icon: User, value: form.contact_person ?? "", onChange: (e) => setForm({ ...form, contact_person: e.target.value }) })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "E-mail" }), _jsx(IconInput, { icon: Mail, type: "email", value: form.email ?? "", onChange: (e) => setForm({ ...form, email: e.target.value }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Telefoonnummer" }), _jsx(IconInput, { icon: Phone, value: form.phone ?? "", onChange: (e) => setForm({ ...form, phone: e.target.value }) })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Adres" }), _jsx(IconInput, { icon: MapPin, value: form.address ?? "", onChange: (e) => setForm({ ...form, address: e.target.value }), placeholder: "Straat, postcode, plaats" })] }), _jsxs("div", { className: "rounded-md border bg-muted/30 p-4 space-y-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: "Ophaalmomenten (transportplanning)" }), _jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: ["De bezorgdag is ", _jsx("strong", { children: "dag 0" }), ". Per ophaalmoment stel je in op hoeveel werkdagen v\u00F3\u00F3r bezorging \u00E9n op welk tijdstip elke stap plaatsvindt. Bij een nieuwe order kiest het systeem automatisch het eerstvolgende moment waarvan de aanmelddeadline nog niet is verstreken."] })] }), _jsx("div", { className: "space-y-3", children: form.pickup_moments.map((moment, idx) => (_jsx(PickupMomentEditor, { index: idx, value: moment, canDelete: form.pickup_moments.length > 1, onChange: (next) => {
190
+ : "Voeg een nieuwe vervoerder toe en stel verzendtarieven in." })] })] }), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base", children: "Algemene gegevens" }) }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs(Label, { children: ["Bedrijfsnaam ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(IconInput, { icon: Truck, value: form.name, onChange: (e) => setForm({ ...form, name: e.target.value }), placeholder: "Bijv. DHL Freight", required: true })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Contactpersoon" }), _jsx(IconInput, { icon: User, value: form.contact_person ?? "", onChange: (e) => setForm({ ...form, contact_person: e.target.value }) })] }), _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "E-mail" }), _jsx(IconInput, { icon: Mail, type: "email", value: form.email ?? "", onChange: (e) => setForm({ ...form, email: e.target.value }) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Telefoonnummer" }), _jsx(IconInput, { icon: Phone, value: form.phone ?? "", onChange: (e) => setForm({ ...form, phone: e.target.value }) })] })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Adres" }), _jsx(IconInput, { icon: MapPin, value: form.address ?? "", onChange: (e) => setForm({ ...form, address: e.target.value }), placeholder: "Straat, postcode, plaats" })] }), _jsxs("div", { className: "rounded-md border bg-muted/30 p-4 space-y-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium", children: "Ophaalmomenten (transportplanning)" }), _jsxs("p", { className: "text-xs text-muted-foreground mt-1", children: ["De bezorgdag is ", _jsx("strong", { children: "dag 0" }), ". Per ophaalmoment stel je in op hoeveel werkdagen v\u00F3\u00F3r bezorging \u00E9n op welk tijdstip elke stap plaatsvindt. Bij een nieuwe order kiest het systeem automatisch het eerstvolgende moment waarvan de aanmelddeadline nog niet is verstreken."] })] }), _jsx("div", { className: "space-y-3", children: form.pickup_moments.map((moment, idx) => (_jsx(PickupMomentEditor, { showErrors: showTimeErrors, index: idx, value: moment, canDelete: form.pickup_moments.length > 1, onChange: (next) => {
184
191
  const copy = [...form.pickup_moments];
185
192
  copy[idx] = next;
186
193
  setForm({ ...form, pickup_moments: copy });
@@ -1 +1 @@
1
- {"version":3,"file":"AfhandelingSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/AfhandelingSettingsCard.tsx"],"names":[],"mappings":"AAuBA,wBAAgB,uBAAuB,gCAyJtC"}
1
+ {"version":3,"file":"AfhandelingSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/components/settings/AfhandelingSettingsCard.tsx"],"names":[],"mappings":"AAuBA,wBAAgB,uBAAuB,gCAiKtC"}
@@ -79,7 +79,7 @@ export function AfhandelingSettingsCard() {
79
79
  toast.error(e instanceof Error ? e.message : "Opslaan mislukt");
80
80
  },
81
81
  });
82
- return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CalendarClock, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { children: "Afhandeling \u2014 Planning" })] }), _jsx(CardDescription, { children: "De pickplanning (pickdagen, picktijd en verdeling over de week) wordt volledig bepaald door de planning. Hieronder staan alleen de instellingen van deze module zelf." })] }), _jsxs(CardContent, { className: "space-y-5", children: [_jsxs("div", { className: "rounded-md border p-4 space-y-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "h-4 w-4 text-primary" }), _jsx(Label, { htmlFor: "mailEnabled", className: "font-semibold", children: "Aanmeldmail vervoerders" })] }), _jsx("p", { className: "text-xs text-muted-foreground max-w-prose", children: "Verstuurt automatisch een mail met de te verwachten karren naar de vervoerder v\u00F3\u00F3r de aanmelddeadline van het ophaalmoment. E\u00E9n mail per ophaaldag/-moment per vervoerder." })] }), _jsx(Switch, { id: "mailEnabled", checked: mailEnabled, onCheckedChange: setMailEnabled })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "mailLead", children: "Minuten v\u00F3\u00F3r aanmelddeadline versturen" }), _jsx(Input, { id: "mailLead", type: "number", min: 0, max: 1440, value: mailLead, disabled: !mailEnabled, onChange: (e) => setMailLead(Math.max(0, Math.min(1440, Math.floor(Number(e.target.value)) || 0))) })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "mailPurpose", children: "E-mail-doeleinde (purpose)" }), _jsx(Input, { id: "mailPurpose", value: mailPurpose, disabled: !mailEnabled, onChange: (e) => setMailPurpose(e.target.value) }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Koppel dit doeleinde in de module ", _jsx("strong", { children: "E-mailkoppeling" }), " aan een actief send-adres. Standaard: ", _jsx("code", { children: "afhandeling_carrier_signup" }), "."] })] })] }), _jsx(SignupStatusBlock, { status: cron.data ?? null, loading: cron.isLoading, failed: cron.isError }), _jsxs("div", { className: "rounded-md bg-muted/50 p-3 text-xs text-muted-foreground", children: [_jsx("strong", { children: "Ophaaltijd" }), " en ", _jsx("strong", { children: "Aanmeldtijd" }), " stel je per vervoerder in (werkdagen v\u00F3\u00F3r bezorgdag). De vervoerder die als ", _jsx("strong", { children: "standaard" }), " is gemarkeerd, wordt gebruikt voor orders zonder eigen vervoerder."] }), _jsx(Button, { onClick: () => mutation.mutate(), disabled: mutation.isPending, children: mutation.isPending ? "Opslaan…" : "Opslaan" })] })] }));
82
+ return (_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(CalendarClock, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { children: "Afhandeling \u2014 Planning" })] }), _jsx(CardDescription, { children: "De pickplanning (pickdagen, picktijd en verdeling over de week) wordt volledig bepaald door de planning. Hieronder staan alleen de instellingen van deze module zelf." })] }), _jsxs(CardContent, { className: "space-y-5", children: [_jsxs("div", { className: "rounded-md border p-4 space-y-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "h-4 w-4 text-primary" }), _jsx(Label, { htmlFor: "mailEnabled", className: "font-semibold", children: "Aanmeldmail vervoerders" })] }), _jsx("p", { className: "text-xs text-muted-foreground max-w-prose", children: "Verstuurt automatisch een mail met de te verwachten karren naar de vervoerder v\u00F3\u00F3r de aanmelddeadline van het ophaalmoment. E\u00E9n mail per ophaaldag/-moment per vervoerder." })] }), _jsx(Switch, { id: "mailEnabled", checked: mailEnabled, onCheckedChange: setMailEnabled })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { htmlFor: "mailLead", children: "Minuten v\u00F3\u00F3r aanmelddeadline versturen" }), _jsx(Input, { id: "mailLead", type: "number", min: 0, max: 1440, value: mailLead, disabled: !mailEnabled, onChange: (e) => setMailLead(Math.max(0, Math.min(1440, Math.floor(Number(e.target.value)) || 0))) })] }), _jsx("div", { className: "space-y-1 text-sm", children: _jsxs("div", { children: [_jsx("strong", { children: "Verzendadres:" }), " ", cron.data?.senderEmail ? cron.data.senderEmail : _jsx("span", { className: "text-muted-foreground", children: "nog geen verbonden adres" }), " ", _jsx("span", { className: "text-xs text-muted-foreground", children: "(instellen bij E-mailkoppeling)" })] }) }), _jsxs("details", { className: "text-xs text-muted-foreground", children: [_jsx("summary", { className: "cursor-pointer", children: "Details voor beheer" }), _jsxs("div", { className: "mt-2 space-y-2", children: [_jsx(Label, { htmlFor: "mailPurpose", children: "Doeleinde in E-mailkoppeling" }), _jsx(Input, { id: "mailPurpose", value: mailPurpose, disabled: !mailEnabled, onChange: (e) => setMailPurpose(e.target.value) }), _jsxs("p", { children: ["Standaard: ", _jsx("code", { children: "afhandeling_carrier_signup" }), "."] })] })] })] }), _jsx(SignupStatusBlock, { status: cron.data ?? null, loading: cron.isLoading, failed: cron.isError }), _jsxs("div", { className: "rounded-md bg-muted/50 p-3 text-xs text-muted-foreground", children: [_jsx("strong", { children: "Ophaaltijd" }), " en ", _jsx("strong", { children: "Aanmeldtijd" }), " stel je per vervoerder in (werkdagen v\u00F3\u00F3r bezorgdag). De vervoerder die als ", _jsx("strong", { children: "standaard" }), " is gemarkeerd, wordt gebruikt voor orders zonder eigen vervoerder."] }), _jsx(Button, { onClick: () => mutation.mutate(), disabled: mutation.isPending, children: mutation.isPending ? "Opslaan…" : "Opslaan" })] })] }));
83
83
  }
84
84
  function SignupStatusBlock({ status, loading, failed, }) {
85
85
  if (loading)
@@ -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;AAK/D,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAYtG;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,iBAAiB,GACjB,gBAAgB,GAChB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAC;IACxB,iDAAiD;IACjD,KAAK,EAAE,aAAa,CAAC;IACrB,uEAAuE;IACvE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,wEAAwE;IACxE,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,wDAAwD;IACxD,iBAAiB,EAAE,YAAY,EAAE,CAAC;IAClC,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAGD,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,uBAAuB,GAAG,sBAAsB,CAmTxF"}
1
+ {"version":3,"file":"useOrderPlanning.d.ts","sourceRoot":"","sources":["../../src/hooks/useOrderPlanning.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAK/D,OAAO,EAEL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAwC,KAAK,UAAU,EAAE,MAAM,+BAA+B,CAAC;AActG;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GACrB,SAAS,GACT,iBAAiB,GACjB,gBAAgB,GAChB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,aAAa,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,cAAc,EAAE,OAAO,CAAC;IACxB,iDAAiD;IACjD,KAAK,EAAE,aAAa,CAAC;IACrB,uEAAuE;IACvE,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,6EAA6E;IAC7E,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,wEAAwE;IACxE,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,wDAAwD;IACxD,iBAAiB,EAAE,YAAY,EAAE,CAAC;IAClC,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAGD,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,uBAAuB,GAAG,sBAAsB,CAkUxF"}
@@ -5,12 +5,14 @@ import { getFloridayOrders } from "../lib/floriday.functions";
5
5
  import { listCarriers } from "../lib/carriers.functions";
6
6
  import { safeServerCall } from "../lib/serverFnError";
7
7
  import { normalizePickupMoments, sanitizeWeekdays, selectCarrierForTarget } from "../lib/carrierPlanning";
8
- import { calculateOrderPlanning, DEFAULT_PICKUP_MOMENT, } from "../lib/planning";
8
+ import { calculateOrderPlanning, } from "../lib/planning";
9
9
  import { useEngineTasks } from "./useEngineTasks";
10
10
  import { useCartIndex } from "./useCartIndex";
11
11
  import { emitEngineEvent, listComposeTaskRefs } from "../lib/logisticsEngine/engine";
12
12
  import { orderRefsFor } from "../lib/orderRefs";
13
13
  import { isOpenOrderStatus } from "../lib/orderStatus";
14
+ import { loadPickWorkdays } from "../lib/pickWorkdays";
15
+ import { supabase as moduleSupabase } from "../integrations/supabase/moduleClient";
14
16
  import { emitQueueStatus, markInFlight, markResult, resetEmitQueue, selectEmitBatch, } from "../lib/logisticsEngine/emitQueue";
15
17
  export function useOrderPlanning(range) {
16
18
  const from = range?.from ?? null;
@@ -57,6 +59,15 @@ export function useOrderPlanning(range) {
57
59
  refetchIntervalInBackground: false,
58
60
  refetchOnWindowFocus: true,
59
61
  });
62
+ // Werkdagen komen uitsluitend uit de Werktijden; zonder die kalender plannen we niet.
63
+ const workdaysQuery = useQuery({
64
+ queryKey: ["afhandeling", "pick-workdays"],
65
+ queryFn: () => loadPickWorkdays(moduleSupabase),
66
+ retry: 1,
67
+ staleTime: 5 * 60000,
68
+ refetchInterval: 10 * 60000,
69
+ refetchIntervalInBackground: false,
70
+ });
60
71
  const carriersQuery = useQuery({
61
72
  queryKey: ["carriers"],
62
73
  queryFn: () => safeServerCall(() => fetchCarriers(), { carriers: [] }, "listCarriers"),
@@ -122,7 +133,7 @@ export function useOrderPlanning(range) {
122
133
  });
123
134
  const moments = carrier
124
135
  ? normalizePickupMoments(carrier.pickup_moments)
125
- : [DEFAULT_PICKUP_MOMENT];
136
+ : [];
126
137
  // Transport-/leverdata blijven uit de vervoerdersagenda komen; het
127
138
  // pickmoment en de karindeling komen uitsluitend uit de Engine-taak.
128
139
  const base = calculateOrderPlanning(order.deliveryDate, {
@@ -188,7 +199,8 @@ export function useOrderPlanning(range) {
188
199
  };
189
200
  return { order, planning, engineTask: task, awaitingEngine: false, state: "planned", hasComposeTask: true };
190
201
  });
191
- }, [orderList, carriersQuery.data, composeByRef, pickByRef, composeExists, cartsForOrder]);
202
+ // workdaysQuery.data: herberekenen zodra de werkdagkalender (opnieuw) geladen is.
203
+ }, [orderList, carriersQuery.data, composeByRef, pickByRef, composeExists, cartsForOrder, workdaysQuery.data]);
192
204
  // Alleen echt open orders mogen bij de Logistics Engine worden aangemeld;
193
205
  // afgehandelde orders blijven wel zichtbaar maar krijgen geen melding meer.
194
206
  const openPlanned = useMemo(() => planned.filter((p) => isOpenOrderStatus(p.order.status)), [planned]);
@@ -285,12 +297,15 @@ export function useOrderPlanning(range) {
285
297
  tasksWithoutStart: openPlanned.filter((p) => p.state === "task_without_start"),
286
298
  signalError,
287
299
  lastEngineRun,
288
- isLoading: ordersQuery.isLoading || carriersQuery.isLoading || tasksLoading,
300
+ isLoading: ordersQuery.isLoading || carriersQuery.isLoading || tasksLoading || workdaysQuery.isLoading,
289
301
  error: ordersQuery.data?.orders?.length ? undefined : ordersQuery.data?.error,
290
- warning: ordersQuery.data?.orders?.length ? ordersQuery.data?.error : undefined,
302
+ warning: workdaysQuery.isError || (workdaysQuery.data && !workdaysQuery.data.available) || workdaysQuery.data?.count === 0
303
+ ? "De werkdagen uit Werktijden zijn niet beschikbaar. Ophaal- en aanmelddagen worden pas getoond als de werkdagen zijn ingesteld."
304
+ : ordersQuery.data?.orders?.length ? ordersQuery.data?.error : undefined,
291
305
  refetch: () => {
292
306
  void ordersQuery.refetch();
293
307
  void carriersQuery.refetch();
308
+ void workdaysQuery.refetch();
294
309
  refetchTasks();
295
310
  },
296
311
  };