@burdenoff/microfe-movethewheels 2026.920.1 → 2026.920.3

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.
@@ -0,0 +1,260 @@
1
+ import { Plus as e } from "../node_modules/lucide-react/dist/esm/icons/plus.js";
2
+ import { RefreshCw as t } from "../node_modules/lucide-react/dist/esm/icons/refresh-cw.js";
3
+ import { UserPlus as n } from "../node_modules/lucide-react/dist/esm/icons/user-plus.js";
4
+ import { Button as r, Dialog as i, DialogContent as a, DialogDescription as o, DialogFooter as s, DialogHeader as c, DialogTitle as l, Input as u, Label as d, Select as f, SelectContent as p, SelectItem as m, SelectTrigger as h, SelectValue as g } from "./ui.js";
5
+ import { FormError as _ } from "./FormError.js";
6
+ import { useState as v } from "react";
7
+ import { jsx as y, jsxs as b } from "react/jsx-runtime";
8
+ //#region src/movethewheels/components/CustomerPicker.tsx
9
+ var x = {
10
+ name: "",
11
+ type: "b2c",
12
+ email: "",
13
+ phone: "",
14
+ company: ""
15
+ };
16
+ function S(e, t) {
17
+ return !t || e.some((e) => e.id === t.id) ? e : [t, ...e];
18
+ }
19
+ function C({ customers: C, value: w, onValueChange: T, onCreated: E, createCustomer: D, isLoading: O, error: k, onRetry: A, onOpenCustomers: j, selectedCustomer: M, disabled: N = !1 }) {
20
+ let [P, F] = v(!1), [I, L] = v(x), [R, z] = v(!1), [B, V] = v(null), H = S(C, M), U = () => {
21
+ V(null), L(x), F(!0);
22
+ }, W = () => {
23
+ R || F(!1);
24
+ };
25
+ return /* @__PURE__ */ b("div", {
26
+ className: "space-y-2",
27
+ children: [
28
+ /* @__PURE__ */ b("div", {
29
+ className: "flex items-center justify-between gap-2",
30
+ children: [/* @__PURE__ */ y(d, {
31
+ htmlFor: "customer",
32
+ children: "Customer"
33
+ }), /* @__PURE__ */ b(r, {
34
+ type: "button",
35
+ variant: "ghost",
36
+ size: "sm",
37
+ onClick: U,
38
+ disabled: N || O,
39
+ children: [/* @__PURE__ */ y(e, {
40
+ size: 14,
41
+ className: "mr-1"
42
+ }), "Add customer"]
43
+ })]
44
+ }),
45
+ /* @__PURE__ */ b("div", {
46
+ className: "flex flex-col gap-2 sm:flex-row sm:items-start",
47
+ children: [/* @__PURE__ */ b(f, {
48
+ value: w,
49
+ onValueChange: T,
50
+ disabled: N || O || !!k,
51
+ children: [/* @__PURE__ */ y(h, {
52
+ id: "customer",
53
+ className: "flex-1",
54
+ children: /* @__PURE__ */ y(g, { placeholder: O ? "Loading customers..." : "Select customer" })
55
+ }), /* @__PURE__ */ y(p, { children: H.map((e) => /* @__PURE__ */ b(m, {
56
+ value: e.id,
57
+ children: [
58
+ e.name,
59
+ " ",
60
+ e.email ? `(${e.email})` : ""
61
+ ]
62
+ }, e.id)) })]
63
+ }), k && /* @__PURE__ */ b(r, {
64
+ type: "button",
65
+ variant: "outline",
66
+ size: "sm",
67
+ onClick: A,
68
+ children: [/* @__PURE__ */ y(t, {
69
+ size: 14,
70
+ className: "mr-1"
71
+ }), "Retry"]
72
+ })]
73
+ }),
74
+ k ? /* @__PURE__ */ b("div", {
75
+ className: "flex flex-wrap items-center gap-2",
76
+ children: [/* @__PURE__ */ y("p", {
77
+ role: "alert",
78
+ className: "text-sm text-status-error-text",
79
+ children: "Customers could not be loaded. Retry or add a customer to continue."
80
+ }), j && /* @__PURE__ */ y(r, {
81
+ type: "button",
82
+ variant: "outline",
83
+ size: "sm",
84
+ onClick: j,
85
+ children: "Open customer page"
86
+ })]
87
+ }) : !O && H.length === 0 ? /* @__PURE__ */ b("div", {
88
+ className: "rounded-lg border border-border-seam bg-bg-sunken/40 p-3",
89
+ children: [/* @__PURE__ */ b("div", {
90
+ className: "flex items-start gap-2",
91
+ children: [/* @__PURE__ */ y(n, {
92
+ size: 16,
93
+ className: "mt-0.5 shrink-0 text-text-secondary"
94
+ }), /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
95
+ className: "text-sm font-medium text-text-primary",
96
+ children: "Add a customer to continue"
97
+ }), /* @__PURE__ */ y("p", {
98
+ className: "text-sm text-text-secondary",
99
+ children: "The customer will be selected automatically and your order details will stay here."
100
+ })] })]
101
+ }), /* @__PURE__ */ b(r, {
102
+ type: "button",
103
+ size: "sm",
104
+ className: "mt-3",
105
+ onClick: U,
106
+ disabled: N,
107
+ children: [/* @__PURE__ */ y(e, {
108
+ size: 14,
109
+ className: "mr-1.5"
110
+ }), "Create customer"]
111
+ })]
112
+ }) : null,
113
+ /* @__PURE__ */ y(i, {
114
+ open: P,
115
+ onOpenChange: (e) => e ? F(!0) : W(),
116
+ children: /* @__PURE__ */ b(a, { children: [/* @__PURE__ */ b(c, { children: [/* @__PURE__ */ y(l, { children: "Create customer" }), /* @__PURE__ */ y(o, { children: "Add the customer without leaving this order. They will be selected automatically." })] }), /* @__PURE__ */ b("form", {
117
+ onSubmit: async (e) => {
118
+ e.preventDefault(), e.stopPropagation();
119
+ let t = I.name.trim();
120
+ if (!t) {
121
+ V("Customer name is required.");
122
+ return;
123
+ }
124
+ z(!0), V(null);
125
+ try {
126
+ E(await D({
127
+ name: t,
128
+ type: I.type,
129
+ email: I.email.trim() || void 0,
130
+ phone: I.phone.trim() || void 0,
131
+ company: I.company.trim() || void 0
132
+ })), F(!1), L(x);
133
+ } catch (e) {
134
+ V(e instanceof Error ? e.message : "Could not create the customer. Please try again.");
135
+ } finally {
136
+ z(!1);
137
+ }
138
+ },
139
+ className: "space-y-4",
140
+ children: [
141
+ /* @__PURE__ */ y(_, { message: B }),
142
+ /* @__PURE__ */ b("div", {
143
+ className: "space-y-2",
144
+ children: [/* @__PURE__ */ y(d, {
145
+ htmlFor: "quick-customer-name",
146
+ children: "Name"
147
+ }), /* @__PURE__ */ y(u, {
148
+ id: "quick-customer-name",
149
+ value: I.name,
150
+ onChange: (e) => L((t) => ({
151
+ ...t,
152
+ name: e.target.value
153
+ })),
154
+ placeholder: "Acme Corp or Jane Doe",
155
+ autoFocus: !0,
156
+ required: !0
157
+ })]
158
+ }),
159
+ /* @__PURE__ */ b("div", {
160
+ className: "space-y-2",
161
+ children: [/* @__PURE__ */ y(d, {
162
+ htmlFor: "quick-customer-type",
163
+ children: "Customer type"
164
+ }), /* @__PURE__ */ b(f, {
165
+ value: I.type,
166
+ onValueChange: (e) => L((t) => ({
167
+ ...t,
168
+ type: e
169
+ })),
170
+ children: [/* @__PURE__ */ y(h, {
171
+ id: "quick-customer-type",
172
+ children: /* @__PURE__ */ y(g, {})
173
+ }), /* @__PURE__ */ b(p, { children: [/* @__PURE__ */ y(m, {
174
+ value: "b2c",
175
+ children: "B2C (Individual)"
176
+ }), /* @__PURE__ */ y(m, {
177
+ value: "b2b",
178
+ children: "B2B (Business)"
179
+ })] })]
180
+ })]
181
+ }),
182
+ /* @__PURE__ */ b("div", {
183
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
184
+ children: [/* @__PURE__ */ b("div", {
185
+ className: "space-y-2",
186
+ children: [/* @__PURE__ */ y(d, {
187
+ htmlFor: "quick-customer-email",
188
+ children: "Email"
189
+ }), /* @__PURE__ */ y(u, {
190
+ id: "quick-customer-email",
191
+ type: "email",
192
+ value: I.email,
193
+ onChange: (e) => L((t) => ({
194
+ ...t,
195
+ email: e.target.value
196
+ })),
197
+ placeholder: "customer@example.com"
198
+ })]
199
+ }), /* @__PURE__ */ b("div", {
200
+ className: "space-y-2",
201
+ children: [/* @__PURE__ */ y(d, {
202
+ htmlFor: "quick-customer-phone",
203
+ children: "Phone"
204
+ }), /* @__PURE__ */ y(u, {
205
+ id: "quick-customer-phone",
206
+ value: I.phone,
207
+ onChange: (e) => L((t) => ({
208
+ ...t,
209
+ phone: e.target.value
210
+ })),
211
+ placeholder: "+1-555-0100"
212
+ })]
213
+ })]
214
+ }),
215
+ /* @__PURE__ */ b("div", {
216
+ className: "space-y-2",
217
+ children: [/* @__PURE__ */ y(d, {
218
+ htmlFor: "quick-customer-company",
219
+ children: "Company"
220
+ }), /* @__PURE__ */ y(u, {
221
+ id: "quick-customer-company",
222
+ value: I.company,
223
+ onChange: (e) => L((t) => ({
224
+ ...t,
225
+ company: e.target.value
226
+ })),
227
+ placeholder: "Company name (optional)"
228
+ })]
229
+ }),
230
+ /* @__PURE__ */ b(s, { children: [
231
+ j && /* @__PURE__ */ y(r, {
232
+ type: "button",
233
+ variant: "outline",
234
+ onClick: () => {
235
+ W(), j();
236
+ },
237
+ disabled: R,
238
+ children: "Use customer page"
239
+ }),
240
+ /* @__PURE__ */ y(r, {
241
+ type: "button",
242
+ variant: "outline",
243
+ onClick: W,
244
+ disabled: R,
245
+ children: "Cancel"
246
+ }),
247
+ /* @__PURE__ */ b(r, {
248
+ type: "submit",
249
+ disabled: R,
250
+ children: [/* @__PURE__ */ y(e, { size: 16 }), R ? "Creating..." : "Create and select"]
251
+ })
252
+ ] })
253
+ ]
254
+ })] })
255
+ })
256
+ ]
257
+ });
258
+ }
259
+ //#endregion
260
+ export { C as CustomerPicker };
@@ -1,142 +1,195 @@
1
1
  import { TriangleAlert as e } from "../node_modules/lucide-react/dist/esm/icons/triangle-alert.js";
2
- import { Card as t, CardContent as n, CardHeader as r, CardTitle as i, Table as a, TableBody as o, TableCell as s, TableHead as c, TableHeader as l, TableRow as u } from "./ui.js";
3
- import { StatusBadge as d } from "./StatusBadge.js";
4
- import { formatCurrency as f } from "../utils/formatters.js";
5
- import { Fragment as p, jsx as m, jsxs as h } from "react/jsx-runtime";
2
+ import { Truck as t } from "../node_modules/lucide-react/dist/esm/icons/truck.js";
3
+ import { Card as n, CardContent as r, CardHeader as i, CardTitle as a, Table as o, TableBody as s, TableCell as c, TableHead as l, TableHeader as u, TableRow as d } from "./ui.js";
4
+ import { StatusBadge as f } from "./StatusBadge.js";
5
+ import { formatCurrency as p } from "../utils/formatters.js";
6
+ import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
6
7
  //#region src/movethewheels/components/ShippingQuoteResults.tsx
7
- var g = {
8
+ var _ = {
8
9
  bg: "bg-status-success-bg-subtle",
9
10
  text: "text-status-success-text"
10
- }, _ = {
11
+ }, v = {
11
12
  bg: "bg-status-info-bg-subtle",
12
13
  text: "text-status-info-text"
13
14
  };
14
- function v(e, t) {
15
+ function y(e, t) {
15
16
  if (e.estimatedDeliveryDays === null) return e.estimatedDeliveryDate ?? "—";
16
17
  let n = e.estimatedDeliveryDays === 1 ? t("movethewheels.shipping.results.day", "day") : t("movethewheels.shipping.results.days", "days"), r = `${e.estimatedDeliveryDays} ${n}`;
17
18
  return e.estimatedDeliveryDate ? `${r} · ${e.estimatedDeliveryDate}` : r;
18
19
  }
19
- function y(e, t) {
20
+ function b(e, t) {
20
21
  return e.mode === "AIR" ? t("movethewheels.shipping.results.air", "Air") : e.mode === "SURFACE" ? t("movethewheels.shipping.results.surface", "Surface") : "—";
21
22
  }
22
- function b({ quote: e, t }) {
23
- return /* @__PURE__ */ h(p, { children: [
24
- e.isCheapest && /* @__PURE__ */ m(d, {
23
+ function x({ quote: e, t }) {
24
+ return /* @__PURE__ */ g(m, { children: [
25
+ e.isCheapest && /* @__PURE__ */ h(f, {
25
26
  status: t("movethewheels.shipping.results.cheapest", "Cheapest"),
26
- customColors: g,
27
+ customColors: _,
27
28
  size: "sm",
28
29
  showDot: !1
29
30
  }),
30
- e.isFastest && /* @__PURE__ */ m(d, {
31
+ e.isFastest && /* @__PURE__ */ h(f, {
31
32
  status: t("movethewheels.shipping.results.fastest", "Fastest"),
32
- customColors: _,
33
+ customColors: v,
33
34
  size: "sm",
34
35
  showDot: !1
35
36
  }),
36
- e.isRecommended && /* @__PURE__ */ m(d, {
37
+ e.isRecommended && /* @__PURE__ */ h(f, {
37
38
  status: t("movethewheels.shipping.results.recommended", "Recommended"),
38
- customColors: _,
39
+ customColors: v,
39
40
  size: "sm",
40
41
  showDot: !1
41
42
  })
42
43
  ] });
43
44
  }
44
- function x({ result: d, t: g }) {
45
- let _ = d.providers.filter((e) => !e.ok);
46
- return /* @__PURE__ */ h("div", {
47
- className: "space-y-4",
48
- children: [_.map((t) => /* @__PURE__ */ h("div", {
49
- role: "alert",
50
- className: "flex items-start gap-2 rounded-lg border border-status-warning-border bg-status-warning-bg-subtle px-4 py-3 text-sm text-status-warning-text",
51
- children: [/* @__PURE__ */ m(e, {
45
+ function S({ estimate: e, t: o }) {
46
+ let s = e.savingsVsCheapestCourier;
47
+ return /* @__PURE__ */ g(n, { children: [/* @__PURE__ */ h(i, { children: /* @__PURE__ */ g(a, {
48
+ className: "flex items-center gap-2",
49
+ children: [
50
+ /* @__PURE__ */ h(t, {
52
51
  size: 18,
53
- className: "mt-0.5 shrink-0",
54
52
  "aria-hidden": "true"
55
- }), /* @__PURE__ */ m("span", { children: t.errorMessage })]
56
- }, t.provider)), /* @__PURE__ */ h(t, { children: [/* @__PURE__ */ h(r, { children: [/* @__PURE__ */ h(i, { children: [
57
- g("movethewheels.shipping.results.title", "Courier options"),
58
- " (",
59
- d.quotes.length,
60
- ")"
61
- ] }), /* @__PURE__ */ h("p", {
62
- className: "text-sm text-text-secondary",
63
- children: [
64
- g("movethewheels.shipping.results.chargeableWeight", "Charged on"),
65
- " ",
66
- d.chargeableWeightKg,
67
- " kg"
68
- ]
69
- })] }), /* @__PURE__ */ m(n, {
70
- className: "p-0",
71
- children: d.quotes.length === 0 ? /* @__PURE__ */ m("p", {
72
- className: "px-6 pb-6 text-sm text-text-secondary",
73
- children: _.length > 0 ? g("movethewheels.shipping.results.allFailed", "No rates could be fetched — see the message above.") : g("movethewheels.shipping.results.noServiceable", "No courier serves this pincode pair.")
74
- }) : /* @__PURE__ */ h(p, { children: [/* @__PURE__ */ m("ul", {
75
- className: "divide-y md:hidden",
76
- "aria-label": g("movethewheels.shipping.results.title", "Courier options"),
77
- children: d.quotes.map((e) => /* @__PURE__ */ h("li", {
78
- className: "space-y-2 px-4 py-4",
79
- children: [
80
- /* @__PURE__ */ h("div", {
81
- className: "flex items-start justify-between gap-3",
82
- children: [/* @__PURE__ */ m("span", {
83
- className: "min-w-0 font-medium",
84
- children: e.courierName
85
- }), /* @__PURE__ */ m("span", {
86
- className: "shrink-0 text-lg font-semibold",
87
- children: f(e.price, e.currency)
88
- })]
89
- }),
90
- /* @__PURE__ */ m("div", {
53
+ }),
54
+ o("movethewheels.shipping.ownFleet.title", "Your own vehicle"),
55
+ /* @__PURE__ */ h(f, {
56
+ status: o("movethewheels.shipping.ownFleet.estimate", "Your estimate"),
57
+ customColors: v,
58
+ size: "sm",
59
+ showDot: !1
60
+ })
61
+ ]
62
+ }) }), /* @__PURE__ */ g(r, {
63
+ className: "space-y-2",
64
+ children: [
65
+ /* @__PURE__ */ h("p", {
66
+ className: "text-2xl font-semibold",
67
+ children: p(e.cost, e.currency)
68
+ }),
69
+ /* @__PURE__ */ g("p", {
70
+ className: "text-sm text-text-secondary",
71
+ children: [
72
+ e.distanceKm,
73
+ " km × ",
74
+ p(e.costPerKm, e.currency),
75
+ "/km",
76
+ e.fixedCost > 0 && ` + ${p(e.fixedCost, e.currency)}`
77
+ ]
78
+ }),
79
+ s !== null && /* @__PURE__ */ h("p", {
80
+ className: `text-sm font-medium ${e.isCheaperThanCouriers ? "text-status-success-text" : "text-status-warning-text"}`,
81
+ children: e.isCheaperThanCouriers ? `${o("movethewheels.shipping.ownFleet.cheaper", "Your own vehicle is cheaper than the cheapest courier by")} ${p(s, e.currency)}` : s === 0 ? o("movethewheels.shipping.ownFleet.same", "Same cost as the cheapest courier") : `${o("movethewheels.shipping.ownFleet.dearer", "The cheapest courier is cheaper by")} ${p(-s, e.currency)}`
82
+ }),
83
+ /* @__PURE__ */ h("p", {
84
+ className: "text-xs text-text-secondary",
85
+ children: o("movethewheels.shipping.ownFleet.note", "Based only on the distance and cost per km you entered — not a quote.")
86
+ })
87
+ ]
88
+ })] });
89
+ }
90
+ function C({ result: t, t: f }) {
91
+ let _ = t.providers.filter((e) => !e.ok);
92
+ return /* @__PURE__ */ g("div", {
93
+ className: "space-y-4",
94
+ children: [
95
+ _.map((t) => /* @__PURE__ */ g("div", {
96
+ role: "alert",
97
+ className: "flex items-start gap-2 rounded-lg border border-status-warning-border bg-status-warning-bg-subtle px-4 py-3 text-sm text-status-warning-text",
98
+ children: [/* @__PURE__ */ h(e, {
99
+ size: 18,
100
+ className: "mt-0.5 shrink-0",
101
+ "aria-hidden": "true"
102
+ }), /* @__PURE__ */ h("span", { children: t.errorMessage })]
103
+ }, t.provider)),
104
+ t.ownFleet && /* @__PURE__ */ h(S, {
105
+ estimate: t.ownFleet,
106
+ t: f
107
+ }),
108
+ /* @__PURE__ */ g(n, { children: [/* @__PURE__ */ g(i, { children: [/* @__PURE__ */ g(a, { children: [
109
+ f("movethewheels.shipping.results.title", "Courier options"),
110
+ " (",
111
+ t.quotes.length,
112
+ ")"
113
+ ] }), /* @__PURE__ */ g("p", {
114
+ className: "text-sm text-text-secondary",
115
+ children: [
116
+ f("movethewheels.shipping.results.chargeableWeight", "Charged on"),
117
+ " ",
118
+ t.chargeableWeightKg,
119
+ " kg"
120
+ ]
121
+ })] }), /* @__PURE__ */ h(r, {
122
+ className: "p-0",
123
+ children: t.quotes.length === 0 ? /* @__PURE__ */ h("p", {
124
+ className: "px-6 pb-6 text-sm text-text-secondary",
125
+ children: _.length > 0 ? f("movethewheels.shipping.results.allFailed", "No rates could be fetched — see the message above.") : f("movethewheels.shipping.results.noServiceable", "No courier serves this pincode pair.")
126
+ }) : /* @__PURE__ */ g(m, { children: [/* @__PURE__ */ h("ul", {
127
+ className: "divide-y md:hidden",
128
+ "aria-label": f("movethewheels.shipping.results.title", "Courier options"),
129
+ children: t.quotes.map((e) => /* @__PURE__ */ g("li", {
130
+ className: "space-y-2 px-4 py-4",
131
+ children: [
132
+ /* @__PURE__ */ g("div", {
133
+ className: "flex items-start justify-between gap-3",
134
+ children: [/* @__PURE__ */ h("span", {
135
+ className: "min-w-0 font-medium",
136
+ children: e.courierName
137
+ }), /* @__PURE__ */ h("span", {
138
+ className: "shrink-0 text-lg font-semibold",
139
+ children: p(e.price, e.currency)
140
+ })]
141
+ }),
142
+ /* @__PURE__ */ h("div", {
143
+ className: "flex flex-wrap items-center gap-2",
144
+ children: /* @__PURE__ */ h(x, {
145
+ quote: e,
146
+ t: f
147
+ })
148
+ }),
149
+ /* @__PURE__ */ h("p", {
150
+ className: "text-sm text-text-secondary",
151
+ children: [
152
+ b(e, f),
153
+ y(e, f),
154
+ e.rating === null ? null : `${e.rating.toFixed(1)} ★`
155
+ ].filter((e) => e !== "—" && e !== null).join(" · ")
156
+ })
157
+ ]
158
+ }, `${e.provider}:${e.courierId}`))
159
+ }), /* @__PURE__ */ h("div", {
160
+ className: "hidden md:block",
161
+ children: /* @__PURE__ */ g(o, { children: [/* @__PURE__ */ h(u, { children: /* @__PURE__ */ g(d, { children: [
162
+ /* @__PURE__ */ h(l, { children: f("movethewheels.shipping.results.courier", "Courier") }),
163
+ /* @__PURE__ */ h(l, { children: f("movethewheels.shipping.results.mode", "Mode") }),
164
+ /* @__PURE__ */ h(l, { children: f("movethewheels.shipping.results.transit", "Estimated delivery") }),
165
+ /* @__PURE__ */ h(l, { children: f("movethewheels.shipping.results.rating", "Rating") }),
166
+ /* @__PURE__ */ h(l, {
167
+ className: "text-right",
168
+ children: f("movethewheels.shipping.results.price", "Price")
169
+ })
170
+ ] }) }), /* @__PURE__ */ h(s, { children: t.quotes.map((e) => /* @__PURE__ */ g(d, { children: [
171
+ /* @__PURE__ */ h(c, { children: /* @__PURE__ */ g("div", {
91
172
  className: "flex flex-wrap items-center gap-2",
92
- children: /* @__PURE__ */ m(b, {
173
+ children: [/* @__PURE__ */ h("span", {
174
+ className: "font-medium",
175
+ children: e.courierName
176
+ }), /* @__PURE__ */ h(x, {
93
177
  quote: e,
94
- t: g
95
- })
96
- }),
97
- /* @__PURE__ */ m("p", {
98
- className: "text-sm text-text-secondary",
99
- children: [
100
- y(e, g),
101
- v(e, g),
102
- e.rating === null ? null : `${e.rating.toFixed(1)} ★`
103
- ].filter((e) => e !== "—" && e !== null).join(" · ")
178
+ t: f
179
+ })]
180
+ }) }),
181
+ /* @__PURE__ */ h(c, { children: b(e, f) }),
182
+ /* @__PURE__ */ h(c, { children: y(e, f) }),
183
+ /* @__PURE__ */ h(c, { children: e.rating === null ? "—" : e.rating.toFixed(1) }),
184
+ /* @__PURE__ */ h(c, {
185
+ className: "text-right font-medium",
186
+ children: p(e.price, e.currency)
104
187
  })
105
- ]
106
- }, `${e.provider}:${e.courierId}`))
107
- }), /* @__PURE__ */ m("div", {
108
- className: "hidden md:block",
109
- children: /* @__PURE__ */ h(a, { children: [/* @__PURE__ */ m(l, { children: /* @__PURE__ */ h(u, { children: [
110
- /* @__PURE__ */ m(c, { children: g("movethewheels.shipping.results.courier", "Courier") }),
111
- /* @__PURE__ */ m(c, { children: g("movethewheels.shipping.results.mode", "Mode") }),
112
- /* @__PURE__ */ m(c, { children: g("movethewheels.shipping.results.transit", "Estimated delivery") }),
113
- /* @__PURE__ */ m(c, { children: g("movethewheels.shipping.results.rating", "Rating") }),
114
- /* @__PURE__ */ m(c, {
115
- className: "text-right",
116
- children: g("movethewheels.shipping.results.price", "Price")
117
- })
118
- ] }) }), /* @__PURE__ */ m(o, { children: d.quotes.map((e) => /* @__PURE__ */ h(u, { children: [
119
- /* @__PURE__ */ m(s, { children: /* @__PURE__ */ h("div", {
120
- className: "flex flex-wrap items-center gap-2",
121
- children: [/* @__PURE__ */ m("span", {
122
- className: "font-medium",
123
- children: e.courierName
124
- }), /* @__PURE__ */ m(b, {
125
- quote: e,
126
- t: g
127
- })]
128
- }) }),
129
- /* @__PURE__ */ m(s, { children: y(e, g) }),
130
- /* @__PURE__ */ m(s, { children: v(e, g) }),
131
- /* @__PURE__ */ m(s, { children: e.rating === null ? "—" : e.rating.toFixed(1) }),
132
- /* @__PURE__ */ m(s, {
133
- className: "text-right font-medium",
134
- children: f(e.price, e.currency)
135
- })
136
- ] }, `${e.provider}:${e.courierId}`)) })] })
188
+ ] }, `${e.provider}:${e.courierId}`)) })] })
189
+ })] })
137
190
  })] })
138
- })] })]
191
+ ]
139
192
  });
140
193
  }
141
194
  //#endregion
142
- export { x as ShippingQuoteResults };
195
+ export { C as ShippingQuoteResults };
@@ -2,7 +2,7 @@ import { useMoveTheWheels as e } from "../providers/MoveTheWheelsProvider.js";
2
2
  import { executeGraphQL as t } from "../utils/graphqlClient.js";
3
3
  import { useCallback as n, useMemo as r } from "react";
4
4
  //#region src/movethewheels/hooks/useShippingCarriers.ts
5
- var i = "\n query ShippingQuotes($input: ShippingQuoteInput!) {\n shippingQuotes(input: $input) {\n chargeableWeightKg\n quotes {\n provider\n courierId\n courierName\n price\n currency\n estimatedDeliveryDays\n estimatedDeliveryDate\n rating\n mode\n isRecommended\n isCheapest\n isFastest\n }\n providers {\n provider\n ok\n quoteCount\n errorMessage\n }\n }\n }\n";
5
+ var i = "\n query ShippingQuotes($input: ShippingQuoteInput!) {\n shippingQuotes(input: $input) {\n chargeableWeightKg\n ownFleet {\n distanceKm\n costPerKm\n fixedCost\n cost\n currency\n savingsVsCheapestCourier\n isCheaperThanCouriers\n }\n quotes {\n provider\n courierId\n courierName\n price\n currency\n estimatedDeliveryDays\n estimatedDeliveryDate\n rating\n mode\n isRecommended\n isCheapest\n isFastest\n }\n providers {\n provider\n ok\n quoteCount\n errorMessage\n }\n }\n }\n";
6
6
  function a() {
7
7
  let { apiGatewayUrl: t, authToken: n, workspaceToken: i, workspaceId: a, tenantId: o, currentUser: s } = e();
8
8
  return r(() => ({
@@ -0,0 +1,17 @@
1
+ import { Customer } from '../types';
2
+
3
+ interface CustomerPickerProps {
4
+ customers: Customer[];
5
+ value: string;
6
+ onValueChange: (value: string) => void;
7
+ onCreated: (customer: Customer) => void;
8
+ createCustomer: (customer: Partial<Customer>) => Promise<Customer>;
9
+ isLoading: boolean;
10
+ error: Error | null;
11
+ onRetry: () => void;
12
+ onOpenCustomers?: () => void;
13
+ selectedCustomer?: Customer | null;
14
+ disabled?: boolean;
15
+ }
16
+ export declare function CustomerPicker({ customers, value, onValueChange, onCreated, createCustomer, isLoading, error, onRetry, onOpenCustomers, selectedCustomer, disabled, }: CustomerPickerProps): import("react").JSX.Element;
17
+ export {};
@@ -5,6 +5,21 @@
5
5
  */
6
6
  export type CarrierProvider = 'SHIPROCKET';
7
7
  export type CarrierServiceMode = 'SURFACE' | 'AIR';
8
+ export interface OwnFleetInput {
9
+ distanceKm: number;
10
+ costPerKm: number;
11
+ fixedCost?: number;
12
+ }
13
+ export interface OwnFleetEstimate {
14
+ distanceKm: number;
15
+ costPerKm: number;
16
+ fixedCost: number;
17
+ cost: number;
18
+ currency: string;
19
+ /** Cheapest courier price minus this estimate; positive = your own vehicle is cheaper. */
20
+ savingsVsCheapestCourier: number | null;
21
+ isCheaperThanCouriers: boolean;
22
+ }
8
23
  export interface ShippingQuoteInput {
9
24
  pickupPostcode: string;
10
25
  deliveryPostcode: string;
@@ -13,6 +28,7 @@ export interface ShippingQuoteInput {
13
28
  widthCm?: number;
14
29
  heightCm?: number;
15
30
  cod?: boolean;
31
+ ownFleet?: OwnFleetInput;
16
32
  }
17
33
  export interface ShippingQuote {
18
34
  provider: CarrierProvider;
@@ -36,6 +52,7 @@ export interface CarrierOutcome {
36
52
  }
37
53
  export interface ShippingQuoteResult {
38
54
  chargeableWeightKg: number;
55
+ ownFleet: OwnFleetEstimate | null;
39
56
  quotes: ShippingQuote[];
40
57
  providers: CarrierOutcome[];
41
58
  }
@@ -21,3 +21,17 @@ export declare function buildUrl(base: string, params?: Record<string, string |
21
21
  * Parse query parameters from a URL.
22
22
  */
23
23
  export declare function parseQueryParams(search: string): Record<string, string>;
24
+ /**
25
+ * Return only an internal order destination for customer create-and-return flows.
26
+ * Query strings are intentionally discarded so callers cannot smuggle a second
27
+ * return target or an open redirect through the customer form.
28
+ */
29
+ export declare function getSafeCustomerReturnPath(value: string | null | undefined): string | null;
30
+ /**
31
+ * Build an order route with a customer preselected after a customer is created.
32
+ */
33
+ export declare function buildOrderCustomerPath(orderPath: string, customerId: string): string;
34
+ /**
35
+ * Build the local customer creation route while preserving a safe order return path.
36
+ */
37
+ export declare function buildCustomerCreatePath(orderPath: string): string;