@burdenoff/microfe-movethewheels 2026.929.1 → 2026.929.2
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.
|
@@ -8,35 +8,33 @@ import { MapPin as ee } from "../node_modules/lucide-react/dist/esm/icons/map-pi
|
|
|
8
8
|
import { Navigation as o } from "../node_modules/lucide-react/dist/esm/icons/navigation.js";
|
|
9
9
|
import { Plus as s } from "../node_modules/lucide-react/dist/esm/icons/plus.js";
|
|
10
10
|
import { Save as c } from "../node_modules/lucide-react/dist/esm/icons/save.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { joinPath as p } from "../utils/navigation.js";
|
|
11
|
+
import { SquarePen as l } from "../node_modules/lucide-react/dist/esm/icons/square-pen.js";
|
|
12
|
+
import { Trash2 as u } from "../node_modules/lucide-react/dist/esm/icons/trash-2.js";
|
|
13
|
+
import { Zap as d } from "../node_modules/lucide-react/dist/esm/icons/zap.js";
|
|
14
|
+
import { joinPath as f } from "../utils/navigation.js";
|
|
16
15
|
import { useMoveTheWheels as te } from "../providers/MoveTheWheelsProvider.js";
|
|
17
|
-
import { useRoute as
|
|
18
|
-
import { useDriver as
|
|
19
|
-
import { Badge as
|
|
20
|
-
import { ErrorState as
|
|
21
|
-
import { RouteMap as
|
|
16
|
+
import { useRoute as ne, useRoutes as re } from "../hooks/useRoutes.js";
|
|
17
|
+
import { useDriver as p, useDrivers as ie, useVehicle as ae, useVehicles as m } from "../hooks/useFleet.js";
|
|
18
|
+
import { Badge as h, Button as g, Card as _, CardContent as v, CardHeader as y, CardTitle as b, Input as x, Label as S, Select as C, SelectContent as w, SelectItem as T, SelectTrigger as E, SelectValue as D } from "../components/ui.js";
|
|
19
|
+
import { ErrorState as oe, LoadingState as se, PageLayout as O } from "../components/PageLayout.js";
|
|
20
|
+
import { RouteMap as k } from "../components/maps/RouteMap.js";
|
|
22
21
|
import "../components/maps/index.js";
|
|
23
|
-
import { ROUTE_STATUS_COLORS as
|
|
24
|
-
import { StatusBadge as
|
|
25
|
-
import { FormError as
|
|
26
|
-
import { Notice as
|
|
27
|
-
import { formatAddress as
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import { firstRealLatLng as le } from "../utils/mapMarkers.js";
|
|
22
|
+
import { ROUTE_STATUS_COLORS as A } from "../constants/index.js";
|
|
23
|
+
import { StatusBadge as j } from "../components/StatusBadge.js";
|
|
24
|
+
import { FormError as M } from "../components/FormError.js";
|
|
25
|
+
import { Notice as N, useNotice as ce } from "../components/Notice.js";
|
|
26
|
+
import { formatAddress as P, formatCurrency as le, formatDate as F } from "../utils/formatters.js";
|
|
27
|
+
import { EntityCombobox as I } from "../components/EntityCombobox.js";
|
|
28
|
+
import { firstRealLatLng as L } from "../utils/mapMarkers.js";
|
|
31
29
|
import { useAssignmentSuggestions as ue } from "../hooks/useFleetIntelligence.js";
|
|
32
|
-
import { AssignmentSuggestions as
|
|
33
|
-
import { useEffect as
|
|
34
|
-
import { useLocation as
|
|
35
|
-
import { Fragment as
|
|
36
|
-
import { useI18n as
|
|
37
|
-
import { EmphasisPanel as
|
|
30
|
+
import { AssignmentSuggestions as de } from "../components/AssignmentSuggestions.js";
|
|
31
|
+
import { useEffect as R, useState as z } from "react";
|
|
32
|
+
import { useLocation as B, useParams as V } from "react-router";
|
|
33
|
+
import { Fragment as H, jsx as U, jsxs as W } from "react/jsx-runtime";
|
|
34
|
+
import { useI18n as fe } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
35
|
+
import { EmphasisPanel as pe, NextSteps as me, PagePurpose as he, ResponsiveDialog as ge, ResponsiveDialogContent as _e, ResponsiveDialogDescription as G, ResponsiveDialogFooter as K, ResponsiveDialogHeader as ve, ResponsiveDialogTitle as q } from "@burdenoff/fe-libs/ui";
|
|
38
36
|
//#region src/movethewheels/pages/RouteDetailsPage.tsx
|
|
39
|
-
var
|
|
37
|
+
var J = [
|
|
40
38
|
{
|
|
41
39
|
value: "planned",
|
|
42
40
|
label: "Planned"
|
|
@@ -54,8 +52,8 @@ var ve = [
|
|
|
54
52
|
label: "Cancelled"
|
|
55
53
|
}
|
|
56
54
|
];
|
|
57
|
-
function
|
|
58
|
-
let { basePath: i, navigate: a } = te(), { createRoute: ee, updateRoute:
|
|
55
|
+
function Y({ editId: r }) {
|
|
56
|
+
let { basePath: i, navigate: a } = te(), { createRoute: ee, updateRoute: l } = re(), { route: d } = ne(r), [h, oe] = z(""), [se, k] = z(""), A = !!r, [j, N] = z({
|
|
59
57
|
name: "",
|
|
60
58
|
status: "planned",
|
|
61
59
|
vehicleId: "",
|
|
@@ -64,46 +62,46 @@ function Z({ editId: r }) {
|
|
|
64
62
|
address: "",
|
|
65
63
|
type: "delivery"
|
|
66
64
|
}]
|
|
67
|
-
}), { vehicles:
|
|
65
|
+
}), { vehicles: ce, isLoading: le, hasMore: F, totalVehicles: L } = m({
|
|
68
66
|
limit: 20,
|
|
69
|
-
search:
|
|
70
|
-
driverId:
|
|
71
|
-
}), { drivers:
|
|
67
|
+
search: h || void 0,
|
|
68
|
+
driverId: j.driverId || void 0
|
|
69
|
+
}), { drivers: ue, isLoading: de, hasMore: B, totalDrivers: V } = ie({
|
|
72
70
|
limit: 20,
|
|
73
|
-
search:
|
|
74
|
-
vehicleId:
|
|
75
|
-
}), { vehicle:
|
|
76
|
-
|
|
77
|
-
!r || !
|
|
78
|
-
name:
|
|
79
|
-
status:
|
|
80
|
-
vehicleId:
|
|
81
|
-
driverId:
|
|
82
|
-
stops:
|
|
83
|
-
address:
|
|
71
|
+
search: se || void 0,
|
|
72
|
+
vehicleId: j.vehicleId || void 0
|
|
73
|
+
}), { vehicle: fe, isLoading: me } = ae(j.vehicleId || void 0), { driver: ge, isLoading: _e } = p(j.driverId || void 0), [G, K] = z(!1), [ve, q] = z(null);
|
|
74
|
+
R(() => {
|
|
75
|
+
!r || !d || N({
|
|
76
|
+
name: d.name || "",
|
|
77
|
+
status: d.status,
|
|
78
|
+
vehicleId: d.vehicleId || "",
|
|
79
|
+
driverId: d.driverId || "",
|
|
80
|
+
stops: d.stops.length > 0 ? d.stops.map((e) => ({
|
|
81
|
+
address: P(e.address) || e.address.street || "",
|
|
84
82
|
type: e.type
|
|
85
83
|
})) : [{
|
|
86
84
|
address: "",
|
|
87
85
|
type: "delivery"
|
|
88
86
|
}]
|
|
89
87
|
});
|
|
90
|
-
}, [r,
|
|
91
|
-
let
|
|
88
|
+
}, [r, d]);
|
|
89
|
+
let Y = () => a?.(f(i, "routes")), X = () => N((e) => ({
|
|
92
90
|
...e,
|
|
93
91
|
stops: [...e.stops, {
|
|
94
92
|
address: "",
|
|
95
93
|
type: "delivery"
|
|
96
94
|
}]
|
|
97
|
-
})),
|
|
95
|
+
})), ye = (e) => N((t) => ({
|
|
98
96
|
...t,
|
|
99
97
|
stops: t.stops.filter((t, n) => n !== e)
|
|
100
|
-
})),
|
|
98
|
+
})), Z = (e, t, n) => N((r) => ({
|
|
101
99
|
...r,
|
|
102
100
|
stops: r.stops.map((r, i) => i === e ? {
|
|
103
101
|
...r,
|
|
104
102
|
[t]: n
|
|
105
103
|
} : r)
|
|
106
|
-
})),
|
|
104
|
+
})), Q = (e, t) => N((n) => {
|
|
107
105
|
let r = e + t;
|
|
108
106
|
if (r < 0 || r >= n.stops.length) return n;
|
|
109
107
|
let i = [...n.stops];
|
|
@@ -111,17 +109,17 @@ function Z({ editId: r }) {
|
|
|
111
109
|
...n,
|
|
112
110
|
stops: i
|
|
113
111
|
};
|
|
114
|
-
}),
|
|
115
|
-
if (e.preventDefault(), !
|
|
116
|
-
|
|
112
|
+
}), $ = async (e) => {
|
|
113
|
+
if (e.preventDefault(), !j.name.trim()) {
|
|
114
|
+
q("Route name is required.");
|
|
117
115
|
return;
|
|
118
116
|
}
|
|
119
|
-
let t =
|
|
117
|
+
let t = j.stops.filter((e) => e.address.trim());
|
|
120
118
|
if (t.length === 0) {
|
|
121
|
-
|
|
119
|
+
q("Add at least one stop with an address.");
|
|
122
120
|
return;
|
|
123
121
|
}
|
|
124
|
-
|
|
122
|
+
K(!0), q(null);
|
|
125
123
|
try {
|
|
126
124
|
let e = t.map((e, t) => ({
|
|
127
125
|
id: `stop-${t + 1}`,
|
|
@@ -139,273 +137,255 @@ function Z({ editId: r }) {
|
|
|
139
137
|
duration: 0,
|
|
140
138
|
status: "pending"
|
|
141
139
|
}));
|
|
142
|
-
if (
|
|
143
|
-
let t = await
|
|
144
|
-
name:
|
|
145
|
-
status:
|
|
146
|
-
vehicleId:
|
|
147
|
-
driverId:
|
|
140
|
+
if (A) {
|
|
141
|
+
let t = await l(r, {
|
|
142
|
+
name: j.name.trim(),
|
|
143
|
+
status: j.status,
|
|
144
|
+
vehicleId: j.vehicleId || void 0,
|
|
145
|
+
driverId: j.driverId || void 0,
|
|
148
146
|
stops: e
|
|
149
147
|
});
|
|
150
|
-
a?.(
|
|
148
|
+
a?.(f(i, `routes/${t.id}`));
|
|
151
149
|
return;
|
|
152
150
|
}
|
|
153
151
|
let n = await ee({
|
|
154
|
-
name:
|
|
155
|
-
status:
|
|
156
|
-
vehicleId:
|
|
157
|
-
driverId:
|
|
152
|
+
name: j.name.trim(),
|
|
153
|
+
status: j.status,
|
|
154
|
+
vehicleId: j.vehicleId || void 0,
|
|
155
|
+
driverId: j.driverId || void 0,
|
|
158
156
|
stops: e
|
|
159
157
|
});
|
|
160
|
-
a?.(
|
|
158
|
+
a?.(f(i, `routes/${n.id}`));
|
|
161
159
|
} catch (e) {
|
|
162
|
-
console.error("Failed to create route:", e),
|
|
160
|
+
console.error("Failed to create route:", e), q(e instanceof Error ? e.message : "Failed to create route. Please try again."), K(!1);
|
|
163
161
|
}
|
|
164
162
|
};
|
|
165
|
-
return /* @__PURE__ */
|
|
166
|
-
title:
|
|
163
|
+
return /* @__PURE__ */ W(O, {
|
|
164
|
+
title: A ? "Edit Route" : "Create Route",
|
|
167
165
|
subtitle: "Plan a new delivery route",
|
|
168
|
-
icon: /* @__PURE__ */
|
|
169
|
-
headerActions: /* @__PURE__ */
|
|
166
|
+
icon: /* @__PURE__ */ U(o, { size: 24 }),
|
|
167
|
+
headerActions: /* @__PURE__ */ W("div", {
|
|
170
168
|
className: "flex gap-2",
|
|
171
|
-
children: [/* @__PURE__ */
|
|
169
|
+
children: [/* @__PURE__ */ W(g, {
|
|
172
170
|
variant: "outline",
|
|
173
|
-
onClick:
|
|
174
|
-
disabled:
|
|
175
|
-
children: [/* @__PURE__ */
|
|
176
|
-
}), /* @__PURE__ */
|
|
177
|
-
onClick:
|
|
178
|
-
disabled:
|
|
171
|
+
onClick: Y,
|
|
172
|
+
disabled: G,
|
|
173
|
+
children: [/* @__PURE__ */ U(t, { size: 16 }), " Cancel"]
|
|
174
|
+
}), /* @__PURE__ */ W(g, {
|
|
175
|
+
onClick: $,
|
|
176
|
+
disabled: G,
|
|
179
177
|
children: [
|
|
180
|
-
/* @__PURE__ */
|
|
178
|
+
/* @__PURE__ */ U(c, { size: 16 }),
|
|
181
179
|
" ",
|
|
182
|
-
|
|
180
|
+
A ? G ? "Saving..." : "Save Changes" : G ? "Saving..." : "Create Route"
|
|
183
181
|
]
|
|
184
182
|
})]
|
|
185
183
|
}),
|
|
186
|
-
children: [/* @__PURE__ */
|
|
187
|
-
icon: /* @__PURE__ */
|
|
184
|
+
children: [/* @__PURE__ */ U(he, {
|
|
185
|
+
icon: /* @__PURE__ */ U(o, { size: 18 }),
|
|
188
186
|
children: "Plan a new delivery route — name it, list the stops to visit, and optionally assign a vehicle and driver. Once created you can optimize it to sequence the stops into the shortest run."
|
|
189
|
-
}), /* @__PURE__ */
|
|
190
|
-
onSubmit:
|
|
187
|
+
}), /* @__PURE__ */ W("form", {
|
|
188
|
+
onSubmit: $,
|
|
191
189
|
className: "max-w-3xl space-y-6",
|
|
192
190
|
children: [
|
|
193
|
-
/* @__PURE__ */
|
|
194
|
-
/* @__PURE__ */
|
|
191
|
+
/* @__PURE__ */ U(M, { message: ve }),
|
|
192
|
+
/* @__PURE__ */ W(pe, { children: [/* @__PURE__ */ U("h2", {
|
|
195
193
|
className: "text-base font-semibold text-text-primary mb-4",
|
|
196
194
|
children: "Route Details"
|
|
197
|
-
}), /* @__PURE__ */
|
|
195
|
+
}), /* @__PURE__ */ W("div", {
|
|
198
196
|
className: "space-y-4",
|
|
199
|
-
children: [
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
children: "*"
|
|
209
|
-
})]
|
|
210
|
-
}), /* @__PURE__ */ G(w, {
|
|
211
|
-
id: "name",
|
|
212
|
-
value: N.name,
|
|
213
|
-
onChange: (e) => P((t) => ({
|
|
214
|
-
...t,
|
|
215
|
-
name: e.target.value
|
|
216
|
-
})),
|
|
217
|
-
placeholder: "Downtown morning run",
|
|
218
|
-
required: !0
|
|
219
|
-
})]
|
|
220
|
-
}), /* @__PURE__ */ K("div", {
|
|
221
|
-
className: "space-y-2",
|
|
222
|
-
children: [/* @__PURE__ */ G(T, {
|
|
223
|
-
htmlFor: "status",
|
|
224
|
-
children: "Status"
|
|
225
|
-
}), /* @__PURE__ */ K(E, {
|
|
226
|
-
value: N.status,
|
|
227
|
-
onValueChange: (e) => P((t) => ({
|
|
228
|
-
...t,
|
|
229
|
-
status: e
|
|
230
|
-
})),
|
|
231
|
-
children: [/* @__PURE__ */ G(k, {
|
|
232
|
-
id: "status",
|
|
233
|
-
children: /* @__PURE__ */ G(A, {})
|
|
234
|
-
}), /* @__PURE__ */ G(D, { children: ve.map((e) => /* @__PURE__ */ G(O, {
|
|
235
|
-
value: e.value,
|
|
236
|
-
children: e.label
|
|
237
|
-
}, e.value)) })]
|
|
197
|
+
children: [/* @__PURE__ */ W("div", {
|
|
198
|
+
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
199
|
+
children: [/* @__PURE__ */ W("div", {
|
|
200
|
+
className: "space-y-2",
|
|
201
|
+
children: [/* @__PURE__ */ W(S, {
|
|
202
|
+
htmlFor: "name",
|
|
203
|
+
children: ["Route Name ", /* @__PURE__ */ U("span", {
|
|
204
|
+
className: "text-status-error-text",
|
|
205
|
+
children: "*"
|
|
238
206
|
})]
|
|
207
|
+
}), /* @__PURE__ */ U(x, {
|
|
208
|
+
id: "name",
|
|
209
|
+
value: j.name,
|
|
210
|
+
onChange: (e) => N((t) => ({
|
|
211
|
+
...t,
|
|
212
|
+
name: e.target.value
|
|
213
|
+
})),
|
|
214
|
+
placeholder: "Downtown morning run",
|
|
215
|
+
required: !0
|
|
239
216
|
})]
|
|
240
|
-
}),
|
|
241
|
-
/* @__PURE__ */ K("div", {
|
|
217
|
+
}), /* @__PURE__ */ W("div", {
|
|
242
218
|
className: "space-y-2",
|
|
243
|
-
children: [
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
className: "text-xs text-text-secondary",
|
|
260
|
-
children: "Narrows both pickers below as you type — up to 20 matches at a time."
|
|
261
|
-
})
|
|
262
|
-
]
|
|
263
|
-
}),
|
|
264
|
-
/* @__PURE__ */ K("div", {
|
|
265
|
-
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
266
|
-
children: [/* @__PURE__ */ K("div", {
|
|
267
|
-
className: "space-y-2",
|
|
268
|
-
children: [/* @__PURE__ */ G(T, {
|
|
269
|
-
htmlFor: "vehicle",
|
|
270
|
-
children: "Vehicle (optional)"
|
|
271
|
-
}), /* @__PURE__ */ G(z, {
|
|
272
|
-
id: "vehicle",
|
|
273
|
-
value: N.vehicleId,
|
|
274
|
-
onChange: (e) => P((t) => ({
|
|
275
|
-
...t,
|
|
276
|
-
vehicleId: e
|
|
277
|
-
})),
|
|
278
|
-
options: oe,
|
|
279
|
-
loading: se,
|
|
280
|
-
getId: (e) => e.id,
|
|
281
|
-
getLabel: (e) => `${e.vehicleNumber} (${e.type})`,
|
|
282
|
-
renderOption: (e) => /* @__PURE__ */ K(W, { children: [
|
|
283
|
-
e.vehicleNumber,
|
|
284
|
-
" (",
|
|
285
|
-
e.type,
|
|
286
|
-
")"
|
|
287
|
-
] }),
|
|
288
|
-
selectedOption: le,
|
|
289
|
-
selectedLoading: ue,
|
|
290
|
-
required: !0,
|
|
291
|
-
placeholder: "Assign later",
|
|
292
|
-
emptyText: "No available vehicles."
|
|
293
|
-
})]
|
|
294
|
-
}), /* @__PURE__ */ K("div", {
|
|
295
|
-
className: "space-y-2",
|
|
296
|
-
children: [/* @__PURE__ */ G(T, {
|
|
297
|
-
htmlFor: "driver",
|
|
298
|
-
children: "Driver (optional)"
|
|
299
|
-
}), /* @__PURE__ */ G(z, {
|
|
300
|
-
id: "driver",
|
|
301
|
-
value: N.driverId,
|
|
302
|
-
onChange: (e) => P((t) => ({
|
|
303
|
-
...t,
|
|
304
|
-
driverId: e
|
|
305
|
-
})),
|
|
306
|
-
options: ce,
|
|
307
|
-
loading: L,
|
|
308
|
-
getId: (e) => e.id,
|
|
309
|
-
getLabel: (e) => `${e.fullName} (${e.employeeId})`,
|
|
310
|
-
renderOption: (e) => /* @__PURE__ */ K(W, { children: [
|
|
311
|
-
e.fullName,
|
|
312
|
-
" (",
|
|
313
|
-
e.employeeId,
|
|
314
|
-
")"
|
|
315
|
-
] }),
|
|
316
|
-
selectedOption: B,
|
|
317
|
-
selectedLoading: de,
|
|
318
|
-
required: !0,
|
|
319
|
-
placeholder: "Assign later",
|
|
320
|
-
emptyText: "No available drivers."
|
|
321
|
-
})]
|
|
219
|
+
children: [/* @__PURE__ */ U(S, {
|
|
220
|
+
htmlFor: "status",
|
|
221
|
+
children: "Status"
|
|
222
|
+
}), /* @__PURE__ */ W(C, {
|
|
223
|
+
value: j.status,
|
|
224
|
+
onValueChange: (e) => N((t) => ({
|
|
225
|
+
...t,
|
|
226
|
+
status: e
|
|
227
|
+
})),
|
|
228
|
+
children: [/* @__PURE__ */ U(E, {
|
|
229
|
+
id: "status",
|
|
230
|
+
children: /* @__PURE__ */ U(D, {})
|
|
231
|
+
}), /* @__PURE__ */ U(w, { children: J.map((e) => /* @__PURE__ */ U(T, {
|
|
232
|
+
value: e.value,
|
|
233
|
+
children: e.label
|
|
234
|
+
}, e.value)) })]
|
|
322
235
|
})]
|
|
323
|
-
})
|
|
324
|
-
|
|
236
|
+
})]
|
|
237
|
+
}), /* @__PURE__ */ W("div", {
|
|
238
|
+
className: "grid grid-cols-1 md:grid-cols-2 gap-4",
|
|
239
|
+
children: [/* @__PURE__ */ W("div", {
|
|
240
|
+
className: "space-y-2",
|
|
241
|
+
children: [/* @__PURE__ */ U(S, {
|
|
242
|
+
htmlFor: "vehicle",
|
|
243
|
+
children: "Vehicle (optional)"
|
|
244
|
+
}), /* @__PURE__ */ U(I, {
|
|
245
|
+
id: "vehicle",
|
|
246
|
+
value: j.vehicleId,
|
|
247
|
+
onChange: (e) => N((t) => ({
|
|
248
|
+
...t,
|
|
249
|
+
vehicleId: e
|
|
250
|
+
})),
|
|
251
|
+
options: ce,
|
|
252
|
+
loading: le,
|
|
253
|
+
getId: (e) => e.id,
|
|
254
|
+
getLabel: (e) => `${e.vehicleNumber} (${e.type})`,
|
|
255
|
+
renderOption: (e) => /* @__PURE__ */ W(H, { children: [
|
|
256
|
+
e.vehicleNumber,
|
|
257
|
+
" (",
|
|
258
|
+
e.type,
|
|
259
|
+
")"
|
|
260
|
+
] }),
|
|
261
|
+
selectedOption: fe,
|
|
262
|
+
selectedLoading: me,
|
|
263
|
+
onSearchChange: oe,
|
|
264
|
+
searchPlaceholder: "Search vehicle number or type…",
|
|
265
|
+
hasMore: F,
|
|
266
|
+
totalCount: L,
|
|
267
|
+
required: !0,
|
|
268
|
+
placeholder: "Assign later",
|
|
269
|
+
emptyText: "No available vehicles."
|
|
270
|
+
})]
|
|
271
|
+
}), /* @__PURE__ */ W("div", {
|
|
272
|
+
className: "space-y-2",
|
|
273
|
+
children: [/* @__PURE__ */ U(S, {
|
|
274
|
+
htmlFor: "driver",
|
|
275
|
+
children: "Driver (optional)"
|
|
276
|
+
}), /* @__PURE__ */ U(I, {
|
|
277
|
+
id: "driver",
|
|
278
|
+
value: j.driverId,
|
|
279
|
+
onChange: (e) => N((t) => ({
|
|
280
|
+
...t,
|
|
281
|
+
driverId: e
|
|
282
|
+
})),
|
|
283
|
+
options: ue,
|
|
284
|
+
loading: de,
|
|
285
|
+
getId: (e) => e.id,
|
|
286
|
+
getLabel: (e) => `${e.fullName} (${e.employeeId})`,
|
|
287
|
+
renderOption: (e) => /* @__PURE__ */ W(H, { children: [
|
|
288
|
+
e.fullName,
|
|
289
|
+
" (",
|
|
290
|
+
e.employeeId,
|
|
291
|
+
")"
|
|
292
|
+
] }),
|
|
293
|
+
selectedOption: ge,
|
|
294
|
+
selectedLoading: _e,
|
|
295
|
+
onSearchChange: k,
|
|
296
|
+
searchPlaceholder: "Search driver name or employee ID…",
|
|
297
|
+
hasMore: B,
|
|
298
|
+
totalCount: V,
|
|
299
|
+
required: !0,
|
|
300
|
+
placeholder: "Assign later",
|
|
301
|
+
emptyText: "No available drivers."
|
|
302
|
+
})]
|
|
303
|
+
})]
|
|
304
|
+
})]
|
|
325
305
|
})] }),
|
|
326
|
-
/* @__PURE__ */
|
|
306
|
+
/* @__PURE__ */ W(_, { children: [/* @__PURE__ */ W(y, {
|
|
327
307
|
className: "flex flex-row items-center justify-between",
|
|
328
|
-
children: [/* @__PURE__ */
|
|
308
|
+
children: [/* @__PURE__ */ W(b, { children: ["Stops ", /* @__PURE__ */ U("span", {
|
|
329
309
|
className: "text-status-error-text",
|
|
330
310
|
children: "*"
|
|
331
|
-
})] }), /* @__PURE__ */
|
|
311
|
+
})] }), /* @__PURE__ */ W(g, {
|
|
332
312
|
type: "button",
|
|
333
313
|
variant: "outline",
|
|
334
314
|
size: "sm",
|
|
335
|
-
onClick:
|
|
336
|
-
children: [/* @__PURE__ */
|
|
315
|
+
onClick: X,
|
|
316
|
+
children: [/* @__PURE__ */ U(s, { size: 16 }), " Add Stop"]
|
|
337
317
|
})]
|
|
338
|
-
}), /* @__PURE__ */
|
|
318
|
+
}), /* @__PURE__ */ U(v, {
|
|
339
319
|
className: "space-y-4",
|
|
340
|
-
children:
|
|
320
|
+
children: j.stops.map((t, r) => /* @__PURE__ */ W("div", {
|
|
341
321
|
className: "grid grid-cols-1 md:grid-cols-12 gap-3 items-end",
|
|
342
322
|
children: [
|
|
343
|
-
/* @__PURE__ */
|
|
323
|
+
/* @__PURE__ */ W("div", {
|
|
344
324
|
className: "md:col-span-7 space-y-2",
|
|
345
|
-
children: [/* @__PURE__ */
|
|
325
|
+
children: [/* @__PURE__ */ W(S, {
|
|
346
326
|
htmlFor: `stop-address-${r}`,
|
|
347
327
|
children: [
|
|
348
328
|
"Stop ",
|
|
349
329
|
r + 1,
|
|
350
330
|
" address"
|
|
351
331
|
]
|
|
352
|
-
}), /* @__PURE__ */
|
|
332
|
+
}), /* @__PURE__ */ U(x, {
|
|
353
333
|
id: `stop-address-${r}`,
|
|
354
334
|
value: t.address,
|
|
355
|
-
onChange: (e) =>
|
|
335
|
+
onChange: (e) => Z(r, "address", e.target.value),
|
|
356
336
|
placeholder: "123 Main St, San Francisco, CA"
|
|
357
337
|
})]
|
|
358
338
|
}),
|
|
359
|
-
/* @__PURE__ */
|
|
339
|
+
/* @__PURE__ */ W("div", {
|
|
360
340
|
className: "md:col-span-4 space-y-2",
|
|
361
|
-
children: [/* @__PURE__ */
|
|
341
|
+
children: [/* @__PURE__ */ U(S, {
|
|
362
342
|
htmlFor: `stop-type-${r}`,
|
|
363
343
|
children: "Type"
|
|
364
|
-
}), /* @__PURE__ */
|
|
344
|
+
}), /* @__PURE__ */ W(C, {
|
|
365
345
|
value: t.type,
|
|
366
|
-
onValueChange: (e) =>
|
|
367
|
-
children: [/* @__PURE__ */
|
|
346
|
+
onValueChange: (e) => Z(r, "type", e),
|
|
347
|
+
children: [/* @__PURE__ */ U(E, {
|
|
368
348
|
id: `stop-type-${r}`,
|
|
369
|
-
children: /* @__PURE__ */
|
|
370
|
-
}), /* @__PURE__ */
|
|
349
|
+
children: /* @__PURE__ */ U(D, {})
|
|
350
|
+
}), /* @__PURE__ */ W(w, { children: [/* @__PURE__ */ U(T, {
|
|
371
351
|
value: "pickup",
|
|
372
352
|
children: "Pickup"
|
|
373
|
-
}), /* @__PURE__ */
|
|
353
|
+
}), /* @__PURE__ */ U(T, {
|
|
374
354
|
value: "delivery",
|
|
375
355
|
children: "Delivery"
|
|
376
356
|
})] })]
|
|
377
357
|
})]
|
|
378
358
|
}),
|
|
379
|
-
/* @__PURE__ */
|
|
359
|
+
/* @__PURE__ */ W("div", {
|
|
380
360
|
className: "md:col-span-1 flex justify-end gap-1",
|
|
381
361
|
children: [
|
|
382
|
-
/* @__PURE__ */
|
|
362
|
+
/* @__PURE__ */ U(g, {
|
|
383
363
|
type: "button",
|
|
384
364
|
variant: "ghost",
|
|
385
365
|
size: "icon",
|
|
386
|
-
onClick: () =>
|
|
366
|
+
onClick: () => Q(r, -1),
|
|
387
367
|
disabled: r === 0,
|
|
388
368
|
"aria-label": `Move stop ${r + 1} up`,
|
|
389
|
-
children: /* @__PURE__ */
|
|
369
|
+
children: /* @__PURE__ */ U(n, { size: 16 })
|
|
390
370
|
}),
|
|
391
|
-
/* @__PURE__ */
|
|
371
|
+
/* @__PURE__ */ U(g, {
|
|
392
372
|
type: "button",
|
|
393
373
|
variant: "ghost",
|
|
394
374
|
size: "icon",
|
|
395
|
-
onClick: () =>
|
|
396
|
-
disabled: r ===
|
|
375
|
+
onClick: () => Q(r, 1),
|
|
376
|
+
disabled: r === j.stops.length - 1,
|
|
397
377
|
"aria-label": `Move stop ${r + 1} down`,
|
|
398
|
-
children: /* @__PURE__ */
|
|
378
|
+
children: /* @__PURE__ */ U(e, { size: 16 })
|
|
399
379
|
}),
|
|
400
|
-
/* @__PURE__ */
|
|
380
|
+
/* @__PURE__ */ U(g, {
|
|
401
381
|
type: "button",
|
|
402
382
|
variant: "ghost",
|
|
403
383
|
size: "icon",
|
|
404
384
|
className: "text-status-error-text",
|
|
405
|
-
onClick: () =>
|
|
406
|
-
disabled:
|
|
385
|
+
onClick: () => ye(r),
|
|
386
|
+
disabled: j.stops.length === 1,
|
|
407
387
|
"aria-label": `Remove stop ${r + 1}`,
|
|
408
|
-
children: /* @__PURE__ */
|
|
388
|
+
children: /* @__PURE__ */ U(u, { size: 16 })
|
|
409
389
|
})
|
|
410
390
|
]
|
|
411
391
|
})
|
|
@@ -416,195 +396,195 @@ function Z({ editId: r }) {
|
|
|
416
396
|
})]
|
|
417
397
|
});
|
|
418
398
|
}
|
|
419
|
-
function
|
|
420
|
-
let { routeId: e } =
|
|
421
|
-
let n =
|
|
399
|
+
function X() {
|
|
400
|
+
let { routeId: e } = V(), n = B().pathname.endsWith("/edit"), { basePath: s, navigate: c } = te(), { route: p, isLoading: ie, error: ae, refetch: m } = ne(e), { optimizeRoute: x, updateRoute: S, deleteRoute: C } = re(), w = ue(e), { t: T } = fe(), E = (e, t) => {
|
|
401
|
+
let n = T(e);
|
|
422
402
|
return n === e ? t : n;
|
|
423
|
-
}, { message:
|
|
403
|
+
}, { message: D, notify: I } = ce(), [R, H] = z(null), [J, X] = z(!1), [ye, Z] = z(!1), [Q, $] = z(!1), [be, xe] = z(null), Se = () => c?.(f(s, "routes")), Ce = (e) => c?.(f(s, e)), we = async () => {
|
|
424
404
|
if (e) {
|
|
425
|
-
|
|
405
|
+
$(!0), xe(null);
|
|
426
406
|
try {
|
|
427
|
-
await
|
|
407
|
+
await C(e), Z(!1), Se();
|
|
428
408
|
} catch (e) {
|
|
429
|
-
xe(e instanceof Error ? e.message : "Failed to delete route."),
|
|
409
|
+
xe(e instanceof Error ? e.message : "Failed to delete route."), $(!1);
|
|
430
410
|
}
|
|
431
411
|
}
|
|
432
412
|
}, Te = async () => {
|
|
433
413
|
if (e) {
|
|
434
|
-
|
|
414
|
+
X(!0), H(null);
|
|
435
415
|
try {
|
|
436
|
-
await
|
|
416
|
+
await x(e), I("Route optimized — stops resequenced for the shortest run."), m();
|
|
437
417
|
} catch (e) {
|
|
438
|
-
|
|
418
|
+
H(e instanceof Error ? e.message : "Failed to optimize route.");
|
|
439
419
|
} finally {
|
|
440
|
-
|
|
420
|
+
X(!1);
|
|
441
421
|
}
|
|
442
422
|
}
|
|
443
423
|
}, Ee = async (t) => {
|
|
444
|
-
e && (await
|
|
424
|
+
e && (await S(e, t), I(E("movethewheels.routes.suggest.done", "Assignment saved.")), m(), w.refetch());
|
|
445
425
|
};
|
|
446
|
-
if (!e) return /* @__PURE__ */
|
|
447
|
-
if (n) return /* @__PURE__ */
|
|
448
|
-
if (
|
|
449
|
-
if (
|
|
426
|
+
if (!e) return /* @__PURE__ */ U(Y, {});
|
|
427
|
+
if (n) return /* @__PURE__ */ U(Y, { editId: e });
|
|
428
|
+
if (ie) return /* @__PURE__ */ U(se, { message: "Loading route details..." });
|
|
429
|
+
if (ae || !p) return /* @__PURE__ */ U(oe, {
|
|
450
430
|
title: "Route not found",
|
|
451
|
-
onRetry:
|
|
431
|
+
onRetry: m
|
|
452
432
|
});
|
|
453
|
-
let De =
|
|
454
|
-
let t =
|
|
433
|
+
let De = p.stops.map((e) => {
|
|
434
|
+
let t = L(e.address);
|
|
455
435
|
return t ? {
|
|
456
436
|
lat: t.lat,
|
|
457
437
|
lng: t.lng,
|
|
458
438
|
sequence: e.sequence,
|
|
459
|
-
label:
|
|
439
|
+
label: P(e.address) || `Order #${e.orderId || e.sequence}`
|
|
460
440
|
} : null;
|
|
461
441
|
}).filter((e) => e !== null);
|
|
462
|
-
return /* @__PURE__ */
|
|
463
|
-
title:
|
|
464
|
-
subtitle: `${
|
|
465
|
-
icon: /* @__PURE__ */
|
|
466
|
-
headerActions: /* @__PURE__ */
|
|
442
|
+
return /* @__PURE__ */ W(O, {
|
|
443
|
+
title: p.name,
|
|
444
|
+
subtitle: `${p.stops.length} stops - ${p.distance.toFixed(1)} km`,
|
|
445
|
+
icon: /* @__PURE__ */ U(o, { size: 24 }),
|
|
446
|
+
headerActions: /* @__PURE__ */ W("div", {
|
|
467
447
|
className: "flex gap-2",
|
|
468
448
|
children: [
|
|
469
|
-
/* @__PURE__ */
|
|
449
|
+
/* @__PURE__ */ W(g, {
|
|
470
450
|
variant: "outline",
|
|
471
451
|
onClick: Se,
|
|
472
|
-
children: [/* @__PURE__ */
|
|
452
|
+
children: [/* @__PURE__ */ U(t, { size: 16 }), " Back"]
|
|
473
453
|
}),
|
|
474
|
-
!
|
|
454
|
+
!p.optimized && /* @__PURE__ */ W(g, {
|
|
475
455
|
variant: "outline",
|
|
476
456
|
onClick: Te,
|
|
477
|
-
disabled:
|
|
457
|
+
disabled: J,
|
|
478
458
|
children: [
|
|
479
|
-
/* @__PURE__ */
|
|
459
|
+
/* @__PURE__ */ U(d, { size: 16 }),
|
|
480
460
|
" ",
|
|
481
|
-
|
|
461
|
+
J ? "Optimizing…" : "Optimize"
|
|
482
462
|
]
|
|
483
463
|
}),
|
|
484
|
-
/* @__PURE__ */
|
|
485
|
-
onClick: () => c?.(
|
|
486
|
-
children: [/* @__PURE__ */
|
|
464
|
+
/* @__PURE__ */ W(g, {
|
|
465
|
+
onClick: () => c?.(f(s, `routes/${e}/edit`)),
|
|
466
|
+
children: [/* @__PURE__ */ U(l, { size: 16 }), " Edit"]
|
|
487
467
|
})
|
|
488
468
|
]
|
|
489
469
|
}),
|
|
490
|
-
headerContent: /* @__PURE__ */
|
|
470
|
+
headerContent: /* @__PURE__ */ W("div", {
|
|
491
471
|
className: "flex gap-2",
|
|
492
|
-
children: [/* @__PURE__ */
|
|
493
|
-
status:
|
|
494
|
-
customColors:
|
|
495
|
-
}), /* @__PURE__ */
|
|
496
|
-
variant:
|
|
497
|
-
children:
|
|
472
|
+
children: [/* @__PURE__ */ U(j, {
|
|
473
|
+
status: p.status,
|
|
474
|
+
customColors: A[p.status]
|
|
475
|
+
}), /* @__PURE__ */ U(h, {
|
|
476
|
+
variant: p.optimized ? "default" : "secondary",
|
|
477
|
+
children: p.optimized ? "Optimized" : "Not Optimized"
|
|
498
478
|
})]
|
|
499
479
|
}),
|
|
500
480
|
children: [
|
|
501
|
-
/* @__PURE__ */
|
|
502
|
-
icon: /* @__PURE__ */
|
|
481
|
+
/* @__PURE__ */ U(he, {
|
|
482
|
+
icon: /* @__PURE__ */ U(o, { size: 18 }),
|
|
503
483
|
children: "A single optimized driving plan that chains together this route's stops. Review the sequence, distance and timing here, re-optimize if traffic or stops change, then hand the itinerary to a driver."
|
|
504
484
|
}),
|
|
505
|
-
/* @__PURE__ */
|
|
485
|
+
/* @__PURE__ */ U(me, {
|
|
506
486
|
storageKey: "movethewheels-route-details",
|
|
507
487
|
steps: [
|
|
508
|
-
...
|
|
488
|
+
...p.optimized ? [] : [{
|
|
509
489
|
id: "optimize",
|
|
510
490
|
label: "Optimize this route",
|
|
511
491
|
description: "Reorder stops to cut distance and driving time.",
|
|
512
|
-
icon: /* @__PURE__ */
|
|
492
|
+
icon: /* @__PURE__ */ U(d, { size: 16 }),
|
|
513
493
|
onClick: Te
|
|
514
494
|
}],
|
|
515
495
|
{
|
|
516
496
|
id: "edit",
|
|
517
497
|
label: "Adjust stops",
|
|
518
498
|
description: "Add, remove or reorder the delivery stops.",
|
|
519
|
-
icon: /* @__PURE__ */
|
|
499
|
+
icon: /* @__PURE__ */ U(l, { size: 16 }),
|
|
520
500
|
onClick: () => {}
|
|
521
501
|
},
|
|
522
502
|
{
|
|
523
503
|
id: "orders",
|
|
524
504
|
label: "Review the orders on this route",
|
|
525
505
|
description: "Check the deliveries bundled into this run.",
|
|
526
|
-
icon: /* @__PURE__ */
|
|
506
|
+
icon: /* @__PURE__ */ U(ee, { size: 16 }),
|
|
527
507
|
onClick: () => Ce("orders")
|
|
528
508
|
}
|
|
529
509
|
]
|
|
530
510
|
}),
|
|
531
|
-
R && /* @__PURE__ */
|
|
511
|
+
R && /* @__PURE__ */ U("div", {
|
|
532
512
|
className: "mb-2",
|
|
533
|
-
children: /* @__PURE__ */
|
|
513
|
+
children: /* @__PURE__ */ U(M, { message: R })
|
|
534
514
|
}),
|
|
535
|
-
|
|
515
|
+
D && /* @__PURE__ */ U("div", {
|
|
536
516
|
className: "mb-2",
|
|
537
|
-
children: /* @__PURE__ */
|
|
517
|
+
children: /* @__PURE__ */ U(N, { message: D })
|
|
538
518
|
}),
|
|
539
|
-
/* @__PURE__ */
|
|
519
|
+
/* @__PURE__ */ W("div", {
|
|
540
520
|
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
541
|
-
children: [/* @__PURE__ */
|
|
521
|
+
children: [/* @__PURE__ */ W("div", {
|
|
542
522
|
className: "lg:col-span-2 space-y-6",
|
|
543
|
-
children: [/* @__PURE__ */
|
|
523
|
+
children: [/* @__PURE__ */ W(_, { children: [/* @__PURE__ */ U(y, { children: /* @__PURE__ */ U(b, { children: "Route Map" }) }), /* @__PURE__ */ U(v, { children: De.length > 0 ? /* @__PURE__ */ U(k, {
|
|
544
524
|
className: "overflow-hidden rounded-lg border border-border-seam",
|
|
545
525
|
height: 360,
|
|
546
526
|
stops: De
|
|
547
|
-
}) : /* @__PURE__ */
|
|
527
|
+
}) : /* @__PURE__ */ W("div", {
|
|
548
528
|
className: "rounded-lg border border-border-seam bg-bg-sunken/40 p-4",
|
|
549
|
-
children: [/* @__PURE__ */
|
|
529
|
+
children: [/* @__PURE__ */ U("p", {
|
|
550
530
|
className: "mb-3 text-sm text-text-secondary",
|
|
551
531
|
children: "These stops don't have map coordinates yet — showing the planned sequence instead."
|
|
552
|
-
}), /* @__PURE__ */
|
|
532
|
+
}), /* @__PURE__ */ U("ol", {
|
|
553
533
|
className: "space-y-2",
|
|
554
|
-
children:
|
|
534
|
+
children: p.stops.map((e) => /* @__PURE__ */ W("li", {
|
|
555
535
|
className: "flex items-start gap-3",
|
|
556
|
-
children: [/* @__PURE__ */
|
|
536
|
+
children: [/* @__PURE__ */ U("span", {
|
|
557
537
|
className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-action-primary-bg/10 text-xs font-semibold text-primary",
|
|
558
538
|
children: e.sequence
|
|
559
|
-
}), /* @__PURE__ */
|
|
539
|
+
}), /* @__PURE__ */ U("span", {
|
|
560
540
|
className: "text-sm",
|
|
561
|
-
children:
|
|
541
|
+
children: P(e.address) || `Order #${e.orderId || e.sequence}`
|
|
562
542
|
})]
|
|
563
543
|
}, e.id))
|
|
564
544
|
})]
|
|
565
|
-
}) })] }), /* @__PURE__ */
|
|
545
|
+
}) })] }), /* @__PURE__ */ W(_, { children: [/* @__PURE__ */ U(y, { children: /* @__PURE__ */ W(b, { children: [
|
|
566
546
|
"Stops (",
|
|
567
|
-
|
|
547
|
+
p.stops.length,
|
|
568
548
|
")"
|
|
569
|
-
] }) }), /* @__PURE__ */
|
|
549
|
+
] }) }), /* @__PURE__ */ U(v, { children: /* @__PURE__ */ U("div", {
|
|
570
550
|
className: "space-y-4",
|
|
571
|
-
children:
|
|
551
|
+
children: p.stops.map((e, t) => /* @__PURE__ */ W("div", {
|
|
572
552
|
className: "flex gap-4",
|
|
573
|
-
children: [/* @__PURE__ */
|
|
553
|
+
children: [/* @__PURE__ */ W("div", {
|
|
574
554
|
className: "relative",
|
|
575
|
-
children: [/* @__PURE__ */
|
|
555
|
+
children: [/* @__PURE__ */ U("div", {
|
|
576
556
|
className: `w-8 h-8 rounded-full flex items-center justify-center ${e.status === "completed" ? "bg-status-success-text text-text-inverse" : "bg-bg-sunken"}`,
|
|
577
|
-
children: e.status === "completed" ? /* @__PURE__ */
|
|
578
|
-
}), t <
|
|
579
|
-
}), /* @__PURE__ */
|
|
557
|
+
children: e.status === "completed" ? /* @__PURE__ */ U(r, { size: 16 }) : e.sequence
|
|
558
|
+
}), t < p.stops.length - 1 && /* @__PURE__ */ U("div", { className: "absolute top-8 left-4 w-px h-12 bg-border" })]
|
|
559
|
+
}), /* @__PURE__ */ U("div", {
|
|
580
560
|
className: "flex-1 pb-4",
|
|
581
|
-
children: /* @__PURE__ */
|
|
561
|
+
children: /* @__PURE__ */ W("div", {
|
|
582
562
|
className: "flex items-center justify-between",
|
|
583
|
-
children: [/* @__PURE__ */
|
|
563
|
+
children: [/* @__PURE__ */ W("div", { children: [/* @__PURE__ */ W("div", {
|
|
584
564
|
className: "flex items-center gap-2",
|
|
585
|
-
children: [/* @__PURE__ */
|
|
565
|
+
children: [/* @__PURE__ */ U(h, {
|
|
586
566
|
variant: e.type === "pickup" ? "secondary" : "default",
|
|
587
567
|
className: "capitalize",
|
|
588
568
|
children: e.type
|
|
589
|
-
}), /* @__PURE__ */
|
|
569
|
+
}), /* @__PURE__ */ W("span", {
|
|
590
570
|
className: "font-medium",
|
|
591
571
|
children: ["Order #", e.orderId]
|
|
592
572
|
})]
|
|
593
|
-
}), /* @__PURE__ */
|
|
573
|
+
}), /* @__PURE__ */ U("p", {
|
|
594
574
|
className: "text-sm text-text-secondary mt-1",
|
|
595
|
-
children:
|
|
596
|
-
})] }), /* @__PURE__ */
|
|
575
|
+
children: P(e.address)
|
|
576
|
+
})] }), /* @__PURE__ */ W("div", {
|
|
597
577
|
className: "text-right",
|
|
598
578
|
children: [
|
|
599
|
-
/* @__PURE__ */
|
|
579
|
+
/* @__PURE__ */ W("p", {
|
|
600
580
|
className: "text-sm",
|
|
601
|
-
children: ["Scheduled: ",
|
|
581
|
+
children: ["Scheduled: ", F(e.scheduledTime, "time")]
|
|
602
582
|
}),
|
|
603
|
-
e.actualTime && /* @__PURE__ */
|
|
583
|
+
e.actualTime && /* @__PURE__ */ W("p", {
|
|
604
584
|
className: "text-sm text-status-success-text",
|
|
605
|
-
children: ["Actual: ",
|
|
585
|
+
children: ["Actual: ", F(e.actualTime, "time")]
|
|
606
586
|
}),
|
|
607
|
-
/* @__PURE__ */
|
|
587
|
+
/* @__PURE__ */ W("p", {
|
|
608
588
|
className: "text-xs text-text-secondary",
|
|
609
589
|
children: [e.duration, " min stop"]
|
|
610
590
|
})
|
|
@@ -614,116 +594,116 @@ function Q() {
|
|
|
614
594
|
})]
|
|
615
595
|
}, e.id))
|
|
616
596
|
}) })] })]
|
|
617
|
-
}), /* @__PURE__ */
|
|
597
|
+
}), /* @__PURE__ */ W("div", {
|
|
618
598
|
className: "space-y-6",
|
|
619
599
|
children: [
|
|
620
|
-
(
|
|
621
|
-
suggestions:
|
|
622
|
-
isLoading:
|
|
623
|
-
error:
|
|
624
|
-
onRetry:
|
|
625
|
-
assignedVehicleId:
|
|
626
|
-
assignedDriverId:
|
|
600
|
+
(p.status === "planned" || p.status === "in_progress") && /* @__PURE__ */ U(de, {
|
|
601
|
+
suggestions: w.data,
|
|
602
|
+
isLoading: w.isLoading,
|
|
603
|
+
error: w.error,
|
|
604
|
+
onRetry: w.refetch,
|
|
605
|
+
assignedVehicleId: p.vehicleId || void 0,
|
|
606
|
+
assignedDriverId: p.driverId || void 0,
|
|
627
607
|
onAssign: Ee,
|
|
628
|
-
t:
|
|
608
|
+
t: E
|
|
629
609
|
}),
|
|
630
|
-
/* @__PURE__ */
|
|
610
|
+
/* @__PURE__ */ W(pe, {
|
|
631
611
|
className: "space-y-4",
|
|
632
612
|
children: [
|
|
633
|
-
/* @__PURE__ */
|
|
613
|
+
/* @__PURE__ */ U("h2", {
|
|
634
614
|
className: "text-base font-semibold text-text-primary",
|
|
635
615
|
children: "Route Info"
|
|
636
616
|
}),
|
|
637
|
-
/* @__PURE__ */
|
|
617
|
+
/* @__PURE__ */ W("div", { children: [/* @__PURE__ */ U("p", {
|
|
638
618
|
className: "text-sm text-text-secondary",
|
|
639
619
|
children: "Total Distance"
|
|
640
|
-
}), /* @__PURE__ */
|
|
620
|
+
}), /* @__PURE__ */ W("p", {
|
|
641
621
|
className: "text-2xl font-bold",
|
|
642
|
-
children: [
|
|
622
|
+
children: [p.distance.toFixed(1), /* @__PURE__ */ U("span", {
|
|
643
623
|
className: "text-sm font-normal",
|
|
644
624
|
children: " km"
|
|
645
625
|
})]
|
|
646
626
|
})] }),
|
|
647
|
-
/* @__PURE__ */
|
|
627
|
+
/* @__PURE__ */ W("div", { children: [/* @__PURE__ */ U("p", {
|
|
648
628
|
className: "text-sm text-text-secondary",
|
|
649
629
|
children: "Est. Duration"
|
|
650
|
-
}), /* @__PURE__ */
|
|
630
|
+
}), /* @__PURE__ */ W("p", {
|
|
651
631
|
className: "text-2xl font-bold",
|
|
652
|
-
children: [
|
|
632
|
+
children: [p.estimatedDuration, /* @__PURE__ */ U("span", {
|
|
653
633
|
className: "text-sm font-normal",
|
|
654
634
|
children: " min"
|
|
655
635
|
})]
|
|
656
636
|
})] }),
|
|
657
|
-
|
|
637
|
+
p.fuelCost !== void 0 && /* @__PURE__ */ W("div", { children: [/* @__PURE__ */ W("p", {
|
|
658
638
|
className: "text-sm text-text-secondary flex items-center gap-1",
|
|
659
|
-
children: [/* @__PURE__ */
|
|
660
|
-
}), /* @__PURE__ */
|
|
639
|
+
children: [/* @__PURE__ */ U(a, { size: 14 }), " Est. Fuel Cost"]
|
|
640
|
+
}), /* @__PURE__ */ U("p", {
|
|
661
641
|
className: "text-2xl font-bold",
|
|
662
|
-
children:
|
|
642
|
+
children: le(p.fuelCost)
|
|
663
643
|
})] }),
|
|
664
|
-
|
|
644
|
+
p.actualDuration && /* @__PURE__ */ W("div", { children: [/* @__PURE__ */ U("p", {
|
|
665
645
|
className: "text-sm text-text-secondary",
|
|
666
646
|
children: "Actual Duration"
|
|
667
|
-
}), /* @__PURE__ */
|
|
647
|
+
}), /* @__PURE__ */ W("p", {
|
|
668
648
|
className: "text-2xl font-bold",
|
|
669
|
-
children: [
|
|
649
|
+
children: [p.actualDuration, /* @__PURE__ */ U("span", {
|
|
670
650
|
className: "text-sm font-normal",
|
|
671
651
|
children: " min"
|
|
672
652
|
})]
|
|
673
653
|
})] })
|
|
674
654
|
]
|
|
675
655
|
}),
|
|
676
|
-
/* @__PURE__ */
|
|
656
|
+
/* @__PURE__ */ W(_, { children: [/* @__PURE__ */ U(y, { children: /* @__PURE__ */ W(b, {
|
|
677
657
|
className: "flex items-center gap-2",
|
|
678
|
-
children: [/* @__PURE__ */
|
|
679
|
-
}) }), /* @__PURE__ */
|
|
658
|
+
children: [/* @__PURE__ */ U(i, { size: 18 }), " Timeline"]
|
|
659
|
+
}) }), /* @__PURE__ */ U(v, {
|
|
680
660
|
className: "space-y-3",
|
|
681
|
-
children: /* @__PURE__ */
|
|
661
|
+
children: /* @__PURE__ */ W("div", { children: [/* @__PURE__ */ U("p", {
|
|
682
662
|
className: "text-sm text-text-secondary",
|
|
683
663
|
children: "Created"
|
|
684
|
-
}), /* @__PURE__ */
|
|
664
|
+
}), /* @__PURE__ */ U("p", { children: F(p.createdAt, "full") })] })
|
|
685
665
|
})] }),
|
|
686
|
-
/* @__PURE__ */
|
|
666
|
+
/* @__PURE__ */ W(_, {
|
|
687
667
|
className: "border-status-error-border",
|
|
688
|
-
children: [/* @__PURE__ */
|
|
668
|
+
children: [/* @__PURE__ */ U(y, { children: /* @__PURE__ */ W(b, {
|
|
689
669
|
className: "flex items-center gap-2 text-status-error-text",
|
|
690
|
-
children: [/* @__PURE__ */
|
|
691
|
-
}) }), /* @__PURE__ */
|
|
670
|
+
children: [/* @__PURE__ */ U(u, { size: 18 }), " Delete Route"]
|
|
671
|
+
}) }), /* @__PURE__ */ W(v, { children: [/* @__PURE__ */ U("p", {
|
|
692
672
|
className: "mb-3 text-sm text-text-secondary",
|
|
693
673
|
children: "Removes this route. It can no longer be dispatched. This cannot be undone from here."
|
|
694
|
-
}), /* @__PURE__ */
|
|
674
|
+
}), /* @__PURE__ */ W(g, {
|
|
695
675
|
variant: "outline",
|
|
696
676
|
className: "border-status-error-border text-status-error-text hover:bg-status-error-bg-subtle",
|
|
697
|
-
onClick: () =>
|
|
698
|
-
children: [/* @__PURE__ */
|
|
677
|
+
onClick: () => Z(!0),
|
|
678
|
+
children: [/* @__PURE__ */ U(u, { size: 16 }), " Delete this route"]
|
|
699
679
|
})] })]
|
|
700
680
|
})
|
|
701
681
|
]
|
|
702
682
|
})]
|
|
703
683
|
}),
|
|
704
|
-
/* @__PURE__ */
|
|
705
|
-
open:
|
|
706
|
-
onOpenChange:
|
|
707
|
-
children: /* @__PURE__ */
|
|
708
|
-
/* @__PURE__ */
|
|
684
|
+
/* @__PURE__ */ U(ge, {
|
|
685
|
+
open: ye,
|
|
686
|
+
onOpenChange: Z,
|
|
687
|
+
children: /* @__PURE__ */ W(_e, { children: [
|
|
688
|
+
/* @__PURE__ */ W(ve, { children: [/* @__PURE__ */ U(q, { children: "Delete this route?" }), /* @__PURE__ */ W(G, { children: [
|
|
709
689
|
"This removes ",
|
|
710
|
-
|
|
690
|
+
p.name,
|
|
711
691
|
" and cannot be undone from here."
|
|
712
692
|
] })] }),
|
|
713
|
-
/* @__PURE__ */
|
|
693
|
+
/* @__PURE__ */ U("div", {
|
|
714
694
|
className: "px-1",
|
|
715
|
-
children: /* @__PURE__ */
|
|
695
|
+
children: /* @__PURE__ */ U(M, { message: be })
|
|
716
696
|
}),
|
|
717
|
-
/* @__PURE__ */ K
|
|
697
|
+
/* @__PURE__ */ W(K, { children: [/* @__PURE__ */ U(g, {
|
|
718
698
|
variant: "outline",
|
|
719
|
-
onClick: () =>
|
|
720
|
-
disabled:
|
|
699
|
+
onClick: () => Z(!1),
|
|
700
|
+
disabled: Q,
|
|
721
701
|
children: "Cancel"
|
|
722
|
-
}), /* @__PURE__ */
|
|
702
|
+
}), /* @__PURE__ */ U(g, {
|
|
723
703
|
className: "bg-status-error-text text-text-inverse hover:opacity-90",
|
|
724
704
|
onClick: we,
|
|
725
|
-
disabled:
|
|
726
|
-
children:
|
|
705
|
+
disabled: Q,
|
|
706
|
+
children: Q ? "Deleting..." : "Delete route"
|
|
727
707
|
})] })
|
|
728
708
|
] })
|
|
729
709
|
})
|
|
@@ -731,4 +711,4 @@ function Q() {
|
|
|
731
711
|
});
|
|
732
712
|
}
|
|
733
713
|
//#endregion
|
|
734
|
-
export {
|
|
714
|
+
export { X as default };
|
package/package.json
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
ArrowUp,
|
|
19
19
|
ArrowDown,
|
|
20
20
|
Fuel,
|
|
21
|
-
Search,
|
|
22
21
|
} from 'lucide-react';
|
|
23
22
|
import { PageLayout, LoadingState, ErrorState } from '../components/PageLayout';
|
|
24
23
|
import { StatusBadge } from '../components/StatusBadge';
|
|
@@ -57,7 +56,6 @@ import { useAssignmentSuggestions } from '../hooks/useFleetIntelligence';
|
|
|
57
56
|
import { AssignmentSuggestions } from '../components/AssignmentSuggestions';
|
|
58
57
|
import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
|
|
59
58
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
60
|
-
import { useDebouncedValue } from '../hooks/useDebouncedValue';
|
|
61
59
|
import { formatDate, formatAddress, formatCurrency } from '../utils/formatters';
|
|
62
60
|
import { joinPath } from '../utils/navigation';
|
|
63
61
|
import { ROUTE_STATUS_COLORS } from '../constants';
|
|
@@ -76,8 +74,8 @@ function NewRouteForm({ editId }: { editId?: string }) {
|
|
|
76
74
|
const { basePath, navigate } = useMoveTheWheels();
|
|
77
75
|
const { createRoute, updateRoute } = useRoutes();
|
|
78
76
|
const { route } = useRoute(editId);
|
|
79
|
-
const [
|
|
80
|
-
const
|
|
77
|
+
const [vehicleSearch, setVehicleSearch] = useState('');
|
|
78
|
+
const [driverSearch, setDriverSearch] = useState('');
|
|
81
79
|
const isEditing = !!editId;
|
|
82
80
|
const [form, setForm] = useState<{
|
|
83
81
|
name: string;
|
|
@@ -92,14 +90,24 @@ function NewRouteForm({ editId }: { editId?: string }) {
|
|
|
92
90
|
driverId: '',
|
|
93
91
|
stops: [{ address: '', type: 'delivery' }],
|
|
94
92
|
});
|
|
95
|
-
const {
|
|
93
|
+
const {
|
|
94
|
+
vehicles,
|
|
95
|
+
isLoading: vehiclesLoading,
|
|
96
|
+
hasMore: vehiclesHaveMore,
|
|
97
|
+
totalVehicles,
|
|
98
|
+
} = useVehicles({
|
|
96
99
|
limit: 20,
|
|
97
|
-
search:
|
|
100
|
+
search: vehicleSearch || undefined,
|
|
98
101
|
driverId: form.driverId || undefined,
|
|
99
102
|
});
|
|
100
|
-
const {
|
|
103
|
+
const {
|
|
104
|
+
drivers,
|
|
105
|
+
isLoading: driversLoading,
|
|
106
|
+
hasMore: driversHaveMore,
|
|
107
|
+
totalDrivers,
|
|
108
|
+
} = useDrivers({
|
|
101
109
|
limit: 20,
|
|
102
|
-
search:
|
|
110
|
+
search: driverSearch || undefined,
|
|
103
111
|
vehicleId: form.vehicleId || undefined,
|
|
104
112
|
});
|
|
105
113
|
// The selected vehicle/driver may fall outside the current search page (e.g. when
|
|
@@ -286,22 +294,6 @@ function NewRouteForm({ editId }: { editId?: string }) {
|
|
|
286
294
|
</Select>
|
|
287
295
|
</div>
|
|
288
296
|
</div>
|
|
289
|
-
<div className="space-y-2">
|
|
290
|
-
<Label htmlFor="fleet-search">Search vehicles & drivers</Label>
|
|
291
|
-
<div className="relative">
|
|
292
|
-
<Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" />
|
|
293
|
-
<Input
|
|
294
|
-
id="fleet-search"
|
|
295
|
-
value={fleetSearch}
|
|
296
|
-
onChange={(e) => setFleetSearch(e.target.value)}
|
|
297
|
-
placeholder="Vehicle number, driver name or employee ID"
|
|
298
|
-
className="pl-9"
|
|
299
|
-
/>
|
|
300
|
-
</div>
|
|
301
|
-
<p className="text-xs text-text-secondary">
|
|
302
|
-
Narrows both pickers below as you type — up to 20 matches at a time.
|
|
303
|
-
</p>
|
|
304
|
-
</div>
|
|
305
297
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
306
298
|
<div className="space-y-2">
|
|
307
299
|
<Label htmlFor="vehicle">Vehicle (optional)</Label>
|
|
@@ -320,10 +312,13 @@ function NewRouteForm({ editId }: { editId?: string }) {
|
|
|
320
312
|
)}
|
|
321
313
|
selectedOption={selectedVehicle}
|
|
322
314
|
selectedLoading={selectedVehicleLoading}
|
|
315
|
+
onSearchChange={setVehicleSearch}
|
|
316
|
+
searchPlaceholder="Search vehicle number or type…"
|
|
317
|
+
hasMore={vehiclesHaveMore}
|
|
318
|
+
totalCount={totalVehicles}
|
|
323
319
|
required
|
|
324
320
|
placeholder="Assign later"
|
|
325
321
|
emptyText="No available vehicles."
|
|
326
|
-
// Search is driven by the shared "Search fleet" box above.
|
|
327
322
|
/>
|
|
328
323
|
</div>
|
|
329
324
|
<div className="space-y-2">
|
|
@@ -343,6 +338,10 @@ function NewRouteForm({ editId }: { editId?: string }) {
|
|
|
343
338
|
)}
|
|
344
339
|
selectedOption={selectedDriver}
|
|
345
340
|
selectedLoading={selectedDriverLoading}
|
|
341
|
+
onSearchChange={setDriverSearch}
|
|
342
|
+
searchPlaceholder="Search driver name or employee ID…"
|
|
343
|
+
hasMore={driversHaveMore}
|
|
344
|
+
totalCount={totalDrivers}
|
|
346
345
|
required
|
|
347
346
|
placeholder="Assign later"
|
|
348
347
|
emptyText="No available drivers."
|