@flowselections/mailbox-orders 1.0.65 → 1.0.67

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.
@@ -1 +1 @@
1
- {"version":3,"file":"MailboxProposalsPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProposalsPage.tsx"],"names":[],"mappings":"AA8HA,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AA2CD,wBAAgB,oBAAoB,gCAsgBnC"}
1
+ {"version":3,"file":"MailboxProposalsPage.d.ts","sourceRoot":"","sources":["../../src/components/MailboxProposalsPage.tsx"],"names":[],"mappings":"AA+HA,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AA2CD,wBAAgB,oBAAoB,gCAsgBnC"}
@@ -10,6 +10,7 @@ import { normalizeUnitKind, toPlants, describeConversion, lineTotal, UNIT_KIND_L
10
10
  import { enabledLoadCarriers, normalizeAllowedLoadCarriers, EMPTY_LOAD_CARRIERS } from "../lib/load-carriers.js";
11
11
  import { listTemplateFields, listPlantTypesForPicker, listSuppliersForPicker, } from "../lib/mailbox-template.functions.js";
12
12
  import { SearchableSelect } from "./SearchableSelect.js";
13
+ import { carrierHint, decideCarrier } from "../lib/carrier-autofill.js";
13
14
  import { AI_AUTH_PATH } from "./MailboxStatusLine.js";
14
15
  import { listProposalsPage } from "../lib/mailbox-list.functions.js";
15
16
  import { MailboxPageFrame, browserTz } from "./MailboxPageFrame.js";
@@ -621,19 +622,24 @@ function ProposalEditor({ proposal, template, customers, products, allowBackorde
621
622
  setVal("delivery_location", primary[0].id);
622
623
  // eslint-disable-next-line react-hooks/exhaustive-deps
623
624
  }, [deliveryLocationVal, deliveryLocations.length, customerVal]);
624
- // Auto-vul vervoerder zodra een nieuwe locatie wordt gekozen (één keer per wissel).
625
- const lastLocRef = useRef(deliveryLocationVal);
625
+ // Auto-vul vervoerder: ook bij een locatie die al vaststaat bij openen.
626
+ // Ref pas bijwerken als de locatie echt in de geladen lijst staat.
627
+ const lastLocRef = useRef(null);
626
628
  useEffect(() => {
627
- if (deliveryLocationVal !== lastLocRef.current) {
628
- lastLocRef.current = deliveryLocationVal;
629
- const loc = deliveryLocations.find((l) => l.id === deliveryLocationVal);
630
- if (loc?.carrier_id)
631
- setVal("carrier", loc.carrier_id);
632
- else if (deliveryLocationVal === null)
633
- setVal("carrier", null);
634
- }
629
+ const d = decideCarrier({
630
+ locationId: deliveryLocationVal,
631
+ prevLocationId: lastLocRef.current,
632
+ locations: deliveryLocations,
633
+ carriers,
634
+ currentCarrier: carrierVal,
635
+ });
636
+ if (d.commitLocation !== undefined)
637
+ lastLocRef.current = d.commitLocation;
638
+ if (d.action === "set" && d.carrierId !== carrierVal)
639
+ setVal("carrier", d.carrierId);
635
640
  // eslint-disable-next-line react-hooks/exhaustive-deps
636
- }, [deliveryLocationVal, deliveryLocations.length]);
641
+ }, [deliveryLocationVal, deliveryLocations.length, carriers.length, carrierVal]);
642
+ const carrierHintKind = carrierHint(selectedLocation, carriers, carrierVal);
637
643
  const selectedCarrier = carriers.find((c) => c.id === carrierVal) ?? null;
638
644
  const pickupLocationVal = values["pickup_location"];
639
645
  // ─── Ladingdragers uit de Rule Engine (nooit cachen) ──────────────────────
@@ -941,7 +947,7 @@ function ProposalEditor({ proposal, template, customers, products, allowBackorde
941
947
  : "Kies vervoerder...", clearLabel: "\u2014 Geen \u2014", disabled: !deliveryLocationVal, options: carriers.map((c) => ({
942
948
  value: c.id,
943
949
  label: c.name + (c.is_default ? " (standaard)" : ""),
944
- })), onChange: (v) => setVal("carrier", v) }), selectedLocation?.carrier_id && carrierVal !== selectedLocation.carrier_id && (_jsx("div", { className: "text-xs text-muted-foreground", children: "Wijkt af van standaard vervoerder van deze locatie \u2014 geldt alleen voor deze bestelling." }))] }), _jsxs("div", { className: "space-y-1", children: [_jsxs(Label, { className: "flex items-center gap-2", children: ["Bezorgdatum ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(Input, { type: "date", value: deliveryVal ?? "", onChange: (e) => setVal("delivery_date", e.target.value || null) }), _jsx(ConfBadge, { meta: metaFor("delivery_date"), thresholds: thresholds }), !carrierVal || !deliveryLocationVal ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "Kies een afleverlocatie en vervoerder; daarna controleren we of deze datum haalbaar is." })) : !deliveryVal ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "De mail noemt geen datum. Kies zelf een datum." })) : previewLoading ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "Haalbaarheid controleren\u2026" })) : previewError ? (_jsxs("div", { className: "text-xs text-destructive", children: ["De haalbaarheid kon niet worden gecontroleerd: ", previewError] })) : dateFeasible ? (_jsxs("div", { className: "rounded-md border border-primary/30 bg-primary/10 px-3 py-2 text-xs text-primary", children: [fmtDate(deliveryVal), " is haalbaar.", preview?.chosen?.departureAt ? ` Ophaalmoment: ${fmtDateTime(preview.chosen.departureAt)}` : "", preview?.chosen?.signupDeadline ? ` (aanmelden tot ${fmtDateTime(preview.chosen.signupDeadline)}).` : "."] })) : (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs space-y-2", children: [_jsxs("div", { className: "text-destructive", children: [fmtDate(deliveryVal), " is niet haalbaar", preview?.reason ? `: ${preview.reason}` : "."] }), preview?.firstFeasibleDeliveryDate && preview.firstFeasibleDeliveryDate !== deliveryVal && (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => setVal("delivery_date", preview.firstFeasibleDeliveryDate), children: ["Gebruik ", fmtDate(preview.firstFeasibleDeliveryDate)] })), preview?.ok === true && previewKind === "late_signup" && (_jsx(LateSignupChoice, { open: lateOpen, setOpen: setLateOpen, reason: lateReason, setReason: setLateReason }))] }))] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Referentie klant" }), _jsx(Input, { value: typeof values["reference"] === "string" ? values["reference"] : "", placeholder: "Bijv. ordernummer van de klant", onChange: (e) => setVal("reference", e.target.value) }), _jsx(ConfBadge, { meta: metaFor("reference"), thresholds: thresholds })] }), otherFields.map(renderField)] }));
950
+ })), onChange: (v) => setVal("carrier", v) }), carrierHintKind === "location" && (_jsx("div", { className: "text-xs text-muted-foreground", children: "Standaard vervoerder van deze locatie" })), carrierHintKind === "default" && (_jsx("div", { className: "text-xs text-muted-foreground", children: "Algemene standaard vervoerder \u2014 controleer of dit klopt" })), selectedLocation?.carrier_id && carrierVal !== selectedLocation.carrier_id && (_jsx("div", { className: "text-xs text-muted-foreground", children: "Wijkt af van standaard vervoerder van deze locatie \u2014 geldt alleen voor deze bestelling." }))] }), _jsxs("div", { className: "space-y-1", children: [_jsxs(Label, { className: "flex items-center gap-2", children: ["Bezorgdatum ", _jsx("span", { className: "text-destructive", children: "*" })] }), _jsx(Input, { type: "date", value: deliveryVal ?? "", onChange: (e) => setVal("delivery_date", e.target.value || null) }), _jsx(ConfBadge, { meta: metaFor("delivery_date"), thresholds: thresholds }), !carrierVal || !deliveryLocationVal ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "Kies een afleverlocatie en vervoerder; daarna controleren we of deze datum haalbaar is." })) : !deliveryVal ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "De mail noemt geen datum. Kies zelf een datum." })) : previewLoading ? (_jsx("div", { className: "text-xs text-muted-foreground", children: "Haalbaarheid controleren\u2026" })) : previewError ? (_jsxs("div", { className: "text-xs text-destructive", children: ["De haalbaarheid kon niet worden gecontroleerd: ", previewError] })) : dateFeasible ? (_jsxs("div", { className: "rounded-md border border-primary/30 bg-primary/10 px-3 py-2 text-xs text-primary", children: [fmtDate(deliveryVal), " is haalbaar.", preview?.chosen?.departureAt ? ` Ophaalmoment: ${fmtDateTime(preview.chosen.departureAt)}` : "", preview?.chosen?.signupDeadline ? ` (aanmelden tot ${fmtDateTime(preview.chosen.signupDeadline)}).` : "."] })) : (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-xs space-y-2", children: [_jsxs("div", { className: "text-destructive", children: [fmtDate(deliveryVal), " is niet haalbaar", preview?.reason ? `: ${preview.reason}` : "."] }), preview?.firstFeasibleDeliveryDate && preview.firstFeasibleDeliveryDate !== deliveryVal && (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => setVal("delivery_date", preview.firstFeasibleDeliveryDate), children: ["Gebruik ", fmtDate(preview.firstFeasibleDeliveryDate)] })), preview?.ok === true && previewKind === "late_signup" && (_jsx(LateSignupChoice, { open: lateOpen, setOpen: setLateOpen, reason: lateReason, setReason: setLateReason }))] }))] }), _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { children: "Referentie klant" }), _jsx(Input, { value: typeof values["reference"] === "string" ? values["reference"] : "", placeholder: "Bijv. ordernummer van de klant", onChange: (e) => setVal("reference", e.target.value) }), _jsx(ConfBadge, { meta: metaFor("reference"), thresholds: thresholds })] }), otherFields.map(renderField)] }));
945
951
  })(), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { children: "Bestelregels" }), _jsxs("div", { className: "grid grid-cols-12 gap-2 text-xs text-muted-foreground px-1", children: [_jsx("div", { className: "col-span-4", children: "Product" }), _jsx("div", { className: "col-span-3", children: "Belading" }), _jsx("div", { className: "col-span-2", children: "Fusten" }), _jsx("div", { className: "col-span-2", children: "Prijs per stuk" }), _jsx("div", { className: "col-span-1 text-center", children: stickerAvailable ? "Sticker" : "" })] }), lines.map((line, idx) => {
946
952
  const product = line.product_id ? products.find((p) => p.id === line.product_id) : null;
947
953
  const stdBelading = defaultBelading(product);
@@ -0,0 +1,29 @@
1
+ export interface CarrierLocation {
2
+ id: string;
3
+ carrier_id?: string | null;
4
+ }
5
+ export interface CarrierOption {
6
+ id: string;
7
+ is_default?: boolean | null;
8
+ }
9
+ export type CarrierSource = "location" | "default" | null;
10
+ export interface CarrierDecision {
11
+ /** wait = niets doen en ref niet bijwerken; keep = niets wijzigen; set = carrierId invullen (null = leegmaken). */
12
+ action: "wait" | "keep" | "set";
13
+ carrierId: string | null;
14
+ source: CarrierSource;
15
+ /** Nieuwe waarde voor de "vorige locatie"-ref, of undefined als die niet mag wijzigen. */
16
+ commitLocation: string | null | undefined;
17
+ }
18
+ /** Alleen een standaard als precies één vervoerder is_default = true heeft. */
19
+ export declare function uniqueDefaultCarrier(carriers: CarrierOption[]): string | null;
20
+ export declare function decideCarrier(input: {
21
+ locationId: string | null;
22
+ prevLocationId: string | null;
23
+ locations: CarrierLocation[];
24
+ carriers: CarrierOption[];
25
+ currentCarrier: string | null;
26
+ }): CarrierDecision;
27
+ /** Grijze hulptekst onder het veld. */
28
+ export declare function carrierHint(location: CarrierLocation | null, carriers: CarrierOption[], carrierId: string | null): "location" | "default" | "differs" | null;
29
+ //# sourceMappingURL=carrier-autofill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carrier-autofill.d.ts","sourceRoot":"","sources":["../../src/lib/carrier-autofill.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,SAAS,GAAG,IAAI,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B,mHAAmH;IACnH,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IAChC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,0FAA0F;IAC1F,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC3C;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,GAAG,IAAI,CAG7E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GAAG,eAAe,CA0BlB;AAED,uCAAuC;AACvC,wBAAgB,WAAW,CACzB,QAAQ,EAAE,eAAe,GAAG,IAAI,EAChC,QAAQ,EAAE,aAAa,EAAE,EACzB,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI,CAI3C"}
@@ -0,0 +1,40 @@
1
+ // Bepaalt of het veld "Vervoerder" automatisch ingevuld moet worden op basis
2
+ // van de gekozen afleverlocatie. Pure functie: geen React, geen servercode.
3
+ /** Alleen een standaard als precies één vervoerder is_default = true heeft. */
4
+ export function uniqueDefaultCarrier(carriers) {
5
+ const defs = carriers.filter((c) => c.is_default === true);
6
+ return defs.length === 1 ? defs[0].id : null;
7
+ }
8
+ export function decideCarrier(input) {
9
+ const { locationId, prevLocationId, locations, carriers, currentCarrier } = input;
10
+ if (!locationId) {
11
+ if (!prevLocationId)
12
+ return { action: "wait", carrierId: null, source: null, commitLocation: undefined };
13
+ return { action: "set", carrierId: null, source: null, commitLocation: null };
14
+ }
15
+ const loc = locations.find((l) => l.id === locationId);
16
+ if (!loc)
17
+ return { action: "wait", carrierId: null, source: null, commitLocation: undefined };
18
+ const own = loc.carrier_id || null;
19
+ if (!own && carriers.length === 0) {
20
+ return { action: "wait", carrierId: null, source: null, commitLocation: undefined };
21
+ }
22
+ const def = own ? null : uniqueDefaultCarrier(carriers);
23
+ const target = own ?? def;
24
+ const source = own ? "location" : def ? "default" : null;
25
+ const changed = prevLocationId !== null && prevLocationId !== locationId;
26
+ if (changed)
27
+ return { action: "set", carrierId: target, source, commitLocation: locationId };
28
+ // Zelfde locatie of eerste keer na openen: alleen invullen als het veld leeg is.
29
+ if (!currentCarrier && target)
30
+ return { action: "set", carrierId: target, source, commitLocation: locationId };
31
+ return { action: "keep", carrierId: currentCarrier, source: null, commitLocation: locationId };
32
+ }
33
+ /** Grijze hulptekst onder het veld. */
34
+ export function carrierHint(location, carriers, carrierId) {
35
+ if (!location || !carrierId)
36
+ return null;
37
+ if (location.carrier_id)
38
+ return carrierId === location.carrier_id ? "location" : "differs";
39
+ return carrierId === uniqueDefaultCarrier(carriers) ? "default" : null;
40
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowselections/mailbox-orders",
3
- "version": "1.0.65",
3
+ "version": "1.0.67",
4
4
  "private": false,
5
5
  "sideEffects": false,
6
6
  "type": "module",