@burdenoff/microfe-movethewheels 2026.830.5 → 2026.920.1

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 (38) hide show
  1. package/dist/MoveTheWheelsRoutes.js +7 -3
  2. package/dist/components/AssignmentSuggestions.js +135 -0
  3. package/dist/components/FleetAlertsPanel.js +114 -0
  4. package/dist/components/ShippingQuoteResults.js +142 -0
  5. package/dist/components/VehicleServiceCard.js +176 -0
  6. package/dist/hooks/useFleet.js +4 -3
  7. package/dist/hooks/useFleetIntelligence.js +91 -0
  8. package/dist/hooks/useShippingCarriers.js +29 -0
  9. package/dist/movethewheels/components/AssignmentSuggestions.d.ts +17 -0
  10. package/dist/movethewheels/components/FleetAlertsPanel.d.ts +14 -0
  11. package/dist/movethewheels/components/ShippingQuoteResults.d.ts +8 -0
  12. package/dist/movethewheels/components/VehicleServiceCard.d.ts +10 -0
  13. package/dist/movethewheels/hooks/useFleetIntelligence.d.ts +64 -0
  14. package/dist/movethewheels/hooks/useShippingCarriers.d.ts +43 -0
  15. package/dist/movethewheels/pages/ShippingRatesPage.d.ts +9 -0
  16. package/dist/movethewheels/types/index.d.ts +2 -0
  17. package/dist/node_modules/lucide-react/dist/esm/icons/scale.js +26 -0
  18. package/dist/node_modules/lucide-react/dist/esm/icons/sparkles.js +26 -0
  19. package/dist/pages/FleetPage.js +156 -146
  20. package/dist/pages/RouteDetailsPage.js +202 -184
  21. package/dist/pages/ShippingRatesPage.js +177 -0
  22. package/dist/pages/VehicleDetailsPage.js +149 -131
  23. package/dist/utils/graphqlClient.js +14 -5
  24. package/package.json +1 -1
  25. package/src/movethewheels/MoveTheWheelsRoutes.tsx +2 -0
  26. package/src/movethewheels/components/AssignmentSuggestions.tsx +234 -0
  27. package/src/movethewheels/components/FleetAlertsPanel.tsx +148 -0
  28. package/src/movethewheels/components/ShippingQuoteResults.tsx +199 -0
  29. package/src/movethewheels/components/VehicleServiceCard.tsx +220 -0
  30. package/src/movethewheels/hooks/useFleet.ts +12 -2
  31. package/src/movethewheels/hooks/useFleetIntelligence.ts +226 -0
  32. package/src/movethewheels/hooks/useShippingCarriers.ts +110 -0
  33. package/src/movethewheels/pages/FleetPage.tsx +21 -0
  34. package/src/movethewheels/pages/RouteDetailsPage.tsx +33 -1
  35. package/src/movethewheels/pages/ShippingRatesPage.tsx +216 -0
  36. package/src/movethewheels/pages/VehicleDetailsPage.tsx +27 -0
  37. package/src/movethewheels/types/index.ts +2 -0
  38. package/src/movethewheels/utils/graphqlClient.ts +20 -1
@@ -28,8 +28,8 @@ function d() {
28
28
  })
29
29
  });
30
30
  }
31
- var f = r(() => import("./pages/DashboardPage.js")), p = r(() => import("./pages/OrdersListPage.js")), m = r(() => import("./pages/OrderDetailsPage.js")), h = r(() => import("./pages/CreateOrderPage.js")), g = r(() => import("./pages/TrackingPage.js")), _ = r(() => import("./pages/LiveTrackingPage.js")), v = r(() => import("./pages/FleetPage.js")), y = r(() => import("./pages/VehiclesPage.js")), b = r(() => import("./pages/VehicleDetailsPage.js")), x = r(() => import("./pages/DriversPage.js")), S = r(() => import("./pages/DriverDetailsPage.js")), C = r(() => import("./pages/InventoryPage.js")), w = r(() => import("./pages/ProductsPage.js")), T = r(() => import("./pages/ProductDetailsPage.js")), E = r(() => import("./pages/WarehousesPage.js")), D = r(() => import("./pages/WarehouseDetailsPage.js")), O = r(() => import("./pages/CustomersPage.js")), k = r(() => import("./pages/CustomerDetailsPage.js")), A = r(() => import("./pages/RoutesPage.js")), j = r(() => import("./pages/RouteDetailsPage.js")), M = r(() => import("./pages/AnalyticsPage.js")), N = r(() => import("./pages/FinancePage.js")), P = r(() => import("./pages/MarketplacePage.js")), F = r(() => import("./pages/ImportExportPage.js")), I = r(() => import("./pages/ReportsPage.js")), L = r(() => import("./pages/SettingsPage.js")), R = r(() => import("./pages/AIAssistantPage.js")), z = r(() => import("./pages/DeliveryCapturePage.js")), B = r(() => import("./pages/MultiModalShipmentPage.js"));
32
- function V() {
31
+ var f = r(() => import("./pages/DashboardPage.js")), p = r(() => import("./pages/OrdersListPage.js")), m = r(() => import("./pages/OrderDetailsPage.js")), h = r(() => import("./pages/CreateOrderPage.js")), g = r(() => import("./pages/TrackingPage.js")), _ = r(() => import("./pages/LiveTrackingPage.js")), v = r(() => import("./pages/FleetPage.js")), y = r(() => import("./pages/VehiclesPage.js")), b = r(() => import("./pages/VehicleDetailsPage.js")), x = r(() => import("./pages/DriversPage.js")), S = r(() => import("./pages/DriverDetailsPage.js")), C = r(() => import("./pages/InventoryPage.js")), w = r(() => import("./pages/ProductsPage.js")), T = r(() => import("./pages/ProductDetailsPage.js")), E = r(() => import("./pages/WarehousesPage.js")), D = r(() => import("./pages/WarehouseDetailsPage.js")), O = r(() => import("./pages/CustomersPage.js")), k = r(() => import("./pages/CustomerDetailsPage.js")), A = r(() => import("./pages/RoutesPage.js")), j = r(() => import("./pages/RouteDetailsPage.js")), M = r(() => import("./pages/AnalyticsPage.js")), N = r(() => import("./pages/FinancePage.js")), P = r(() => import("./pages/MarketplacePage.js")), F = r(() => import("./pages/ImportExportPage.js")), I = r(() => import("./pages/ReportsPage.js")), L = r(() => import("./pages/SettingsPage.js")), R = r(() => import("./pages/AIAssistantPage.js")), z = r(() => import("./pages/DeliveryCapturePage.js")), B = r(() => import("./pages/MultiModalShipmentPage.js")), V = r(() => import("./pages/ShippingRatesPage.js"));
32
+ function H() {
33
33
  return /* @__PURE__ */ s(n, {
34
34
  fallback: /* @__PURE__ */ s(d, {}),
35
35
  children: /* @__PURE__ */ c(a, { children: [
@@ -69,6 +69,10 @@ function V() {
69
69
  path: "shipments/multi-modal",
70
70
  element: /* @__PURE__ */ s(B, {})
71
71
  }),
72
+ /* @__PURE__ */ s(i, {
73
+ path: "shipments/rates",
74
+ element: /* @__PURE__ */ s(V, {})
75
+ }),
72
76
  /* @__PURE__ */ s(i, {
73
77
  path: "fleet",
74
78
  element: /* @__PURE__ */ s(v, {})
@@ -205,4 +209,4 @@ function V() {
205
209
  });
206
210
  }
207
211
  //#endregion
208
- export { V as MoveTheWheelsRoutes };
212
+ export { H as MoveTheWheelsRoutes };
@@ -0,0 +1,135 @@
1
+ import { Sparkles as e } from "../node_modules/lucide-react/dist/esm/icons/sparkles.js";
2
+ import { Badge as t, Button as n, Card as r, CardContent as i, CardHeader as a, CardTitle as o, Skeleton as s } from "./ui.js";
3
+ import { FormError as c } from "./FormError.js";
4
+ import { useState as l } from "react";
5
+ import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
6
+ //#region src/movethewheels/components/AssignmentSuggestions.tsx
7
+ function p({ id: e, label: r, reasons: i, isBest: a, isAssigned: o, isPending: s, disabled: c, onAssign: l, t: u }) {
8
+ return /* @__PURE__ */ f("li", {
9
+ className: "flex items-start justify-between gap-3 py-3",
10
+ "data-suggestion-id": e,
11
+ children: [/* @__PURE__ */ f("div", {
12
+ className: "flex-1 min-w-0 space-y-1",
13
+ children: [/* @__PURE__ */ f("div", {
14
+ className: "flex flex-wrap items-center gap-x-2 gap-y-1",
15
+ children: [/* @__PURE__ */ d("span", {
16
+ className: "text-sm font-medium break-words",
17
+ children: r
18
+ }), a && /* @__PURE__ */ d(t, {
19
+ variant: "secondary",
20
+ children: u("movethewheels.routes.suggest.best", "Best match")
21
+ })]
22
+ }), /* @__PURE__ */ d("ul", {
23
+ className: "space-y-0.5",
24
+ children: i.map((e) => /* @__PURE__ */ d("li", {
25
+ className: "text-xs text-text-secondary",
26
+ children: e
27
+ }, e))
28
+ })]
29
+ }), /* @__PURE__ */ d(n, {
30
+ size: "sm",
31
+ className: "shrink-0",
32
+ variant: o ? "ghost" : "outline",
33
+ disabled: c || o,
34
+ onClick: l,
35
+ children: o ? u("movethewheels.routes.suggest.assigned", "Assigned") : s ? u("movethewheels.routes.suggest.assigning", "Assigning…") : u("movethewheels.routes.suggest.assign", "Assign")
36
+ })]
37
+ });
38
+ }
39
+ function m({ suggestions: t, isLoading: m, error: h, onRetry: g, assignedVehicleId: _, assignedDriverId: v, onAssign: y, t: b }) {
40
+ let [x, S] = l(null), [C, w] = l(null), T = b("movethewheels.routes.suggest.title", "Suggested assignment"), E = async (e, t) => {
41
+ S(e), w(null);
42
+ try {
43
+ await y(t);
44
+ } catch (e) {
45
+ w(e instanceof Error ? e.message : "Could not assign.");
46
+ } finally {
47
+ S(null);
48
+ }
49
+ };
50
+ if (h && !m) return /* @__PURE__ */ d(r, {
51
+ className: "border-status-error-border",
52
+ children: /* @__PURE__ */ f(i, {
53
+ className: "p-6 text-center space-y-3",
54
+ children: [
55
+ /* @__PURE__ */ d("p", {
56
+ className: "text-status-error-text font-medium",
57
+ children: b("movethewheels.routes.suggest.error", "Couldn't load suggestions")
58
+ }),
59
+ /* @__PURE__ */ d("p", {
60
+ className: "text-sm text-text-secondary",
61
+ children: h.message
62
+ }),
63
+ /* @__PURE__ */ d(n, {
64
+ variant: "outline",
65
+ onClick: g,
66
+ children: b("movethewheels.fleet.error.retry", "Retry")
67
+ })
68
+ ]
69
+ })
70
+ });
71
+ if (m) return /* @__PURE__ */ f(r, { children: [/* @__PURE__ */ d(a, { children: /* @__PURE__ */ d(o, { children: T }) }), /* @__PURE__ */ f(i, {
72
+ className: "space-y-3",
73
+ children: [/* @__PURE__ */ d(s, { className: "h-14 w-full" }), /* @__PURE__ */ d(s, { className: "h-14 w-full" })]
74
+ })] });
75
+ let { vehicles: D, drivers: O } = t, k = D.length === 0 && O.length === 0;
76
+ return /* @__PURE__ */ f(r, { children: [/* @__PURE__ */ d(a, { children: /* @__PURE__ */ f(o, {
77
+ className: "flex items-center gap-2",
78
+ children: [/* @__PURE__ */ d(e, {
79
+ size: 18,
80
+ "aria-hidden": "true"
81
+ }), T]
82
+ }) }), /* @__PURE__ */ f(i, {
83
+ className: "space-y-4",
84
+ children: [/* @__PURE__ */ d(c, { message: C }), k ? /* @__PURE__ */ d("p", {
85
+ className: "text-sm text-text-secondary",
86
+ children: b("movethewheels.routes.suggest.none", "No vehicle or driver is free right now. Vehicles must be in service and drivers must hold a valid licence and not be on another live route.")
87
+ }) : /* @__PURE__ */ f(u, { children: [/* @__PURE__ */ f("section", {
88
+ "aria-label": b("movethewheels.routes.suggest.vehicles", "Vehicles"),
89
+ children: [/* @__PURE__ */ d("h4", {
90
+ className: "text-xs font-semibold uppercase tracking-wide text-text-secondary",
91
+ children: b("movethewheels.routes.suggest.vehicles", "Vehicles")
92
+ }), D.length === 0 ? /* @__PURE__ */ d("p", {
93
+ className: "py-3 text-sm text-text-secondary",
94
+ children: b("movethewheels.routes.suggest.noVehicles", "No vehicle is free right now.")
95
+ }) : /* @__PURE__ */ d("ul", {
96
+ className: "divide-y",
97
+ children: D.map((e, t) => /* @__PURE__ */ d(p, {
98
+ id: e.vehicle.id,
99
+ label: [e.vehicle.vehicleNumber, [e.vehicle.make, e.vehicle.model].filter(Boolean).join(" ")].filter(Boolean).join(" — "),
100
+ reasons: e.reasons,
101
+ isBest: t === 0,
102
+ isAssigned: _ === e.vehicle.id,
103
+ isPending: x === e.vehicle.id,
104
+ disabled: x !== null,
105
+ onAssign: () => E(e.vehicle.id, { vehicleId: e.vehicle.id }),
106
+ t: b
107
+ }, e.vehicle.id))
108
+ })]
109
+ }), /* @__PURE__ */ f("section", {
110
+ "aria-label": b("movethewheels.routes.suggest.drivers", "Drivers"),
111
+ children: [/* @__PURE__ */ d("h4", {
112
+ className: "text-xs font-semibold uppercase tracking-wide text-text-secondary",
113
+ children: b("movethewheels.routes.suggest.drivers", "Drivers")
114
+ }), O.length === 0 ? /* @__PURE__ */ d("p", {
115
+ className: "py-3 text-sm text-text-secondary",
116
+ children: b("movethewheels.routes.suggest.noDrivers", "No driver is free right now.")
117
+ }) : /* @__PURE__ */ d("ul", {
118
+ className: "divide-y",
119
+ children: O.map((e, t) => /* @__PURE__ */ d(p, {
120
+ id: e.driver.id,
121
+ label: `${e.driver.firstName} ${e.driver.lastName}`.trim(),
122
+ reasons: e.reasons,
123
+ isBest: t === 0,
124
+ isAssigned: v === e.driver.id,
125
+ isPending: x === e.driver.id,
126
+ disabled: x !== null,
127
+ onAssign: () => E(e.driver.id, { driverId: e.driver.id }),
128
+ t: b
129
+ }, e.driver.id))
130
+ })]
131
+ })] })]
132
+ })] });
133
+ }
134
+ //#endregion
135
+ export { m as AssignmentSuggestions };
@@ -0,0 +1,114 @@
1
+ import { ChevronRight as e } from "../node_modules/lucide-react/dist/esm/icons/chevron-right.js";
2
+ import { CircleCheckBig as t } from "../node_modules/lucide-react/dist/esm/icons/circle-check-big.js";
3
+ import { TriangleAlert as n } from "../node_modules/lucide-react/dist/esm/icons/triangle-alert.js";
4
+ import { Button as r, Card as i, CardContent as a, CardHeader as o, CardTitle as s, Skeleton as c } from "./ui.js";
5
+ import { StatusBadge as l } from "./StatusBadge.js";
6
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
7
+ //#region src/movethewheels/components/FleetAlertsPanel.tsx
8
+ var f = {
9
+ CRITICAL: {
10
+ bg: "bg-status-error-bg-subtle",
11
+ text: "text-status-error-text"
12
+ },
13
+ WARNING: {
14
+ bg: "bg-status-warning-bg-subtle",
15
+ text: "text-status-warning-text"
16
+ }
17
+ }, p = (e, t) => `${e} ${t}${e === 1 ? "" : "s"}`;
18
+ function m(e) {
19
+ let t = [], { daysUntilDue: n, kmUntilDue: r } = e;
20
+ if (n !== null && (n < 0 ? t.push(`${p(-n, "day")} overdue`) : n === 0 ? t.push("due today") : t.push(`${p(n, "day")} left`)), r !== null) {
21
+ let e = Math.round(Math.abs(r));
22
+ t.push(r < 0 ? `${e} km overdue` : `${e} km left`);
23
+ }
24
+ return t.join(" · ");
25
+ }
26
+ function h({ alerts: p, isLoading: h, error: g, onRetry: _, onOpen: v, t: y }) {
27
+ let b = y("movethewheels.fleet.alerts.title", "Needs attention");
28
+ return g && !h ? /* @__PURE__ */ u(i, {
29
+ className: "border-status-error-border",
30
+ children: /* @__PURE__ */ d(a, {
31
+ className: "p-6 text-center space-y-3",
32
+ children: [
33
+ /* @__PURE__ */ u("p", {
34
+ className: "text-status-error-text font-medium",
35
+ children: y("movethewheels.fleet.alerts.error", "Couldn't load fleet alerts")
36
+ }),
37
+ /* @__PURE__ */ u("p", {
38
+ className: "text-sm text-text-secondary",
39
+ children: g.message
40
+ }),
41
+ /* @__PURE__ */ u(r, {
42
+ variant: "outline",
43
+ onClick: _,
44
+ children: y("movethewheels.fleet.error.retry", "Retry")
45
+ })
46
+ ]
47
+ })
48
+ }) : h ? /* @__PURE__ */ d(i, { children: [/* @__PURE__ */ u(o, { children: /* @__PURE__ */ u(s, { children: b }) }), /* @__PURE__ */ d(a, {
49
+ className: "space-y-3",
50
+ children: [/* @__PURE__ */ u(c, { className: "h-12 w-full" }), /* @__PURE__ */ u(c, { className: "h-12 w-full" })]
51
+ })] }) : p.length === 0 ? /* @__PURE__ */ d(i, { children: [/* @__PURE__ */ u(o, { children: /* @__PURE__ */ d(s, {
52
+ className: "flex items-center gap-2",
53
+ children: [/* @__PURE__ */ u(t, {
54
+ size: 18,
55
+ "aria-hidden": "true",
56
+ className: "text-status-success-text"
57
+ }), b]
58
+ }) }), /* @__PURE__ */ u(a, { children: /* @__PURE__ */ u("p", {
59
+ className: "text-sm text-text-secondary",
60
+ children: y("movethewheels.fleet.alerts.allClear", "All clear — every licence is valid and no vehicle is due for service.")
61
+ }) })] }) : /* @__PURE__ */ d(i, { children: [/* @__PURE__ */ u(o, { children: /* @__PURE__ */ d(s, {
62
+ className: "flex items-center gap-2",
63
+ children: [
64
+ /* @__PURE__ */ u(n, {
65
+ size: 18,
66
+ "aria-hidden": "true",
67
+ className: "text-status-warning-text"
68
+ }),
69
+ b,
70
+ " (",
71
+ p.length,
72
+ ")"
73
+ ]
74
+ }) }), /* @__PURE__ */ u(a, {
75
+ className: "p-0",
76
+ children: /* @__PURE__ */ u("ul", {
77
+ className: "divide-y",
78
+ "aria-label": b,
79
+ children: p.map((t) => {
80
+ let n = m(t);
81
+ return /* @__PURE__ */ u("li", { children: /* @__PURE__ */ d("button", {
82
+ type: "button",
83
+ onClick: () => v(t),
84
+ className: "flex w-full items-center gap-3 px-6 py-3 text-left hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg",
85
+ children: [
86
+ /* @__PURE__ */ u(l, {
87
+ status: t.severity === "CRITICAL" ? "Critical" : "Warning",
88
+ customColors: f[t.severity],
89
+ size: "sm",
90
+ showDot: !1
91
+ }),
92
+ /* @__PURE__ */ d("span", {
93
+ className: "flex-1 min-w-0",
94
+ children: [/* @__PURE__ */ u("span", {
95
+ className: "block text-sm font-medium truncate",
96
+ children: t.message
97
+ }), n && /* @__PURE__ */ u("span", {
98
+ className: "block text-xs text-text-secondary",
99
+ children: n
100
+ })]
101
+ }),
102
+ /* @__PURE__ */ u(e, {
103
+ size: 16,
104
+ "aria-hidden": "true",
105
+ className: "shrink-0"
106
+ })
107
+ ]
108
+ }) }, t.id);
109
+ })
110
+ })
111
+ })] });
112
+ }
113
+ //#endregion
114
+ export { h as FleetAlertsPanel };
@@ -0,0 +1,142 @@
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";
6
+ //#region src/movethewheels/components/ShippingQuoteResults.tsx
7
+ var g = {
8
+ bg: "bg-status-success-bg-subtle",
9
+ text: "text-status-success-text"
10
+ }, _ = {
11
+ bg: "bg-status-info-bg-subtle",
12
+ text: "text-status-info-text"
13
+ };
14
+ function v(e, t) {
15
+ if (e.estimatedDeliveryDays === null) return e.estimatedDeliveryDate ?? "—";
16
+ let n = e.estimatedDeliveryDays === 1 ? t("movethewheels.shipping.results.day", "day") : t("movethewheels.shipping.results.days", "days"), r = `${e.estimatedDeliveryDays} ${n}`;
17
+ return e.estimatedDeliveryDate ? `${r} · ${e.estimatedDeliveryDate}` : r;
18
+ }
19
+ function y(e, t) {
20
+ return e.mode === "AIR" ? t("movethewheels.shipping.results.air", "Air") : e.mode === "SURFACE" ? t("movethewheels.shipping.results.surface", "Surface") : "—";
21
+ }
22
+ function b({ quote: e, t }) {
23
+ return /* @__PURE__ */ h(p, { children: [
24
+ e.isCheapest && /* @__PURE__ */ m(d, {
25
+ status: t("movethewheels.shipping.results.cheapest", "Cheapest"),
26
+ customColors: g,
27
+ size: "sm",
28
+ showDot: !1
29
+ }),
30
+ e.isFastest && /* @__PURE__ */ m(d, {
31
+ status: t("movethewheels.shipping.results.fastest", "Fastest"),
32
+ customColors: _,
33
+ size: "sm",
34
+ showDot: !1
35
+ }),
36
+ e.isRecommended && /* @__PURE__ */ m(d, {
37
+ status: t("movethewheels.shipping.results.recommended", "Recommended"),
38
+ customColors: _,
39
+ size: "sm",
40
+ showDot: !1
41
+ })
42
+ ] });
43
+ }
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, {
52
+ size: 18,
53
+ className: "mt-0.5 shrink-0",
54
+ "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", {
91
+ className: "flex flex-wrap items-center gap-2",
92
+ children: /* @__PURE__ */ m(b, {
93
+ 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(" · ")
104
+ })
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}`)) })] })
137
+ })] })
138
+ })] })]
139
+ });
140
+ }
141
+ //#endregion
142
+ export { x as ShippingQuoteResults };
@@ -0,0 +1,176 @@
1
+ import { Wrench as e } from "../node_modules/lucide-react/dist/esm/icons/wrench.js";
2
+ import { Button as t, Card as n, CardContent as r, CardHeader as i, CardTitle as a, Input as o, Label as s } from "./ui.js";
3
+ import { FormError as c } from "./FormError.js";
4
+ import { useState as l } from "react";
5
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
+ //#region src/movethewheels/components/VehicleServiceCard.tsx
7
+ var f = 90, p = 1e4, m = (e) => e ? e.toLocaleDateString(void 0, {
8
+ year: "numeric",
9
+ month: "short",
10
+ day: "numeric"
11
+ }) : null, h = (e) => e.toISOString().slice(0, 10), g = (e) => {
12
+ if (e.trim() === "") return;
13
+ let t = Number(e);
14
+ return Number.isFinite(t) && t >= 0 ? t : NaN;
15
+ };
16
+ function _({ vehicle: _, onRecord: v, t: y }) {
17
+ let [b, x] = l(!1), [S, C] = l(!1), [w, T] = l(null), [E, D] = l({
18
+ serviceDate: h(/* @__PURE__ */ new Date()),
19
+ mileage: _.mileage === void 0 ? "" : String(_.mileage),
20
+ intervalDays: String(f),
21
+ intervalKm: String(p)
22
+ }), O = m(_.lastMaintenance), k = m(_.nextMaintenance), A = _.nextMaintenanceMileage, j = k !== null || A !== void 0;
23
+ return /* @__PURE__ */ d(n, { children: [/* @__PURE__ */ u(i, { children: /* @__PURE__ */ d(a, {
24
+ className: "flex items-center gap-2",
25
+ children: [/* @__PURE__ */ u(e, {
26
+ size: 18,
27
+ "aria-hidden": "true"
28
+ }), y("movethewheels.vehicles.service.title", "Service schedule")]
29
+ }) }), /* @__PURE__ */ d(r, {
30
+ className: "space-y-4",
31
+ children: [/* @__PURE__ */ d("dl", {
32
+ className: "grid grid-cols-2 gap-4 text-sm",
33
+ children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("dt", {
34
+ className: "text-text-secondary",
35
+ children: y("movethewheels.vehicles.service.last", "Last service")
36
+ }), /* @__PURE__ */ u("dd", {
37
+ className: "font-medium",
38
+ children: O ?? y("movethewheels.vehicles.service.none", "Not recorded")
39
+ })] }), /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("dt", {
40
+ className: "text-text-secondary",
41
+ children: y("movethewheels.vehicles.service.next", "Next service due")
42
+ }), /* @__PURE__ */ u("dd", {
43
+ className: "font-medium",
44
+ children: j ? [k, A === void 0 ? null : `${A.toLocaleString()} km`].filter(Boolean).join(" / ") : y("movethewheels.vehicles.service.noSchedule", "No schedule set")
45
+ })] })]
46
+ }), b ? /* @__PURE__ */ d("form", {
47
+ onSubmit: async (e) => {
48
+ e.preventDefault();
49
+ let t = g(E.mileage), n = g(E.intervalDays), r = g(E.intervalKm);
50
+ if ([
51
+ t,
52
+ n,
53
+ r
54
+ ].some((e) => e !== void 0 && Number.isNaN(e))) {
55
+ T(y("movethewheels.vehicles.service.invalid", "Enter valid, non-negative numbers."));
56
+ return;
57
+ }
58
+ if (r !== void 0 && t === void 0 && _.mileage === void 0) {
59
+ T(y("movethewheels.vehicles.service.needsMileage", "Enter the odometer reading to set a service-by-distance interval."));
60
+ return;
61
+ }
62
+ C(!0), T(null);
63
+ try {
64
+ await v({
65
+ serviceDate: `${E.serviceDate}T12:00:00.000Z`,
66
+ ...t === void 0 ? {} : { mileage: t },
67
+ ...n === void 0 ? {} : { intervalDays: Math.round(n) },
68
+ ...r === void 0 ? {} : { intervalKm: r }
69
+ }), x(!1);
70
+ } catch (e) {
71
+ T(e instanceof Error ? e.message : "Could not record the service.");
72
+ } finally {
73
+ C(!1);
74
+ }
75
+ },
76
+ className: "space-y-3",
77
+ children: [
78
+ /* @__PURE__ */ u(c, { message: w }),
79
+ /* @__PURE__ */ d("div", {
80
+ className: "grid grid-cols-2 gap-3",
81
+ children: [
82
+ /* @__PURE__ */ d("div", {
83
+ className: "space-y-1",
84
+ children: [/* @__PURE__ */ u(s, {
85
+ htmlFor: "service-date",
86
+ children: y("movethewheels.vehicles.service.date", "Service date")
87
+ }), /* @__PURE__ */ u(o, {
88
+ id: "service-date",
89
+ type: "date",
90
+ required: !0,
91
+ value: E.serviceDate,
92
+ onChange: (e) => D((t) => ({
93
+ ...t,
94
+ serviceDate: e.target.value
95
+ }))
96
+ })]
97
+ }),
98
+ /* @__PURE__ */ d("div", {
99
+ className: "space-y-1",
100
+ children: [/* @__PURE__ */ u(s, {
101
+ htmlFor: "service-mileage",
102
+ children: y("movethewheels.vehicles.service.mileage", "Odometer (km)")
103
+ }), /* @__PURE__ */ u(o, {
104
+ id: "service-mileage",
105
+ type: "number",
106
+ min: 0,
107
+ value: E.mileage,
108
+ onChange: (e) => D((t) => ({
109
+ ...t,
110
+ mileage: e.target.value
111
+ }))
112
+ })]
113
+ }),
114
+ /* @__PURE__ */ d("div", {
115
+ className: "space-y-1",
116
+ children: [/* @__PURE__ */ u(s, {
117
+ htmlFor: "service-interval-days",
118
+ children: y("movethewheels.vehicles.service.intervalDays", "Next service in (days)")
119
+ }), /* @__PURE__ */ u(o, {
120
+ id: "service-interval-days",
121
+ type: "number",
122
+ min: 0,
123
+ value: E.intervalDays,
124
+ onChange: (e) => D((t) => ({
125
+ ...t,
126
+ intervalDays: e.target.value
127
+ }))
128
+ })]
129
+ }),
130
+ /* @__PURE__ */ d("div", {
131
+ className: "space-y-1",
132
+ children: [/* @__PURE__ */ u(s, {
133
+ htmlFor: "service-interval-km",
134
+ children: y("movethewheels.vehicles.service.intervalKm", "Next service in (km)")
135
+ }), /* @__PURE__ */ u(o, {
136
+ id: "service-interval-km",
137
+ type: "number",
138
+ min: 0,
139
+ value: E.intervalKm,
140
+ onChange: (e) => D((t) => ({
141
+ ...t,
142
+ intervalKm: e.target.value
143
+ }))
144
+ })]
145
+ })
146
+ ]
147
+ }),
148
+ /* @__PURE__ */ d("div", {
149
+ className: "flex gap-2",
150
+ children: [/* @__PURE__ */ u(t, {
151
+ type: "submit",
152
+ size: "sm",
153
+ disabled: S,
154
+ children: S ? y("movethewheels.vehicles.service.saving", "Saving…") : y("movethewheels.vehicles.service.save", "Save service")
155
+ }), /* @__PURE__ */ u(t, {
156
+ type: "button",
157
+ variant: "ghost",
158
+ size: "sm",
159
+ disabled: S,
160
+ onClick: () => {
161
+ x(!1), T(null);
162
+ },
163
+ children: y("movethewheels.vehicles.service.cancel", "Cancel")
164
+ })]
165
+ })
166
+ ]
167
+ }) : /* @__PURE__ */ u(t, {
168
+ variant: "outline",
169
+ size: "sm",
170
+ onClick: () => x(!0),
171
+ children: y("movethewheels.vehicles.service.record", "Record service")
172
+ })]
173
+ })] });
174
+ }
175
+ //#endregion
176
+ export { _ as VehicleServiceCard };
@@ -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, useEffect as r, useMemo as i, useState as a } from "react";
4
4
  //#region src/movethewheels/hooks/useFleet.ts
5
- var o = "\n query ListVehicles($filter: VehicleFilterInput, $pagination: PaginationInput) {\n vehicles(filter: $filter, pagination: $pagination) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n createdAt\n updatedAt\n }\n }\n", s = "\n query ListDrivers($filter: DriverFilterInput, $pagination: PaginationInput) {\n drivers(filter: $filter, pagination: $pagination) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", c = "\n query GetVehicle($id: ID!) {\n vehicle(id: $id) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n createdAt\n updatedAt\n }\n }\n", l = "\n query GetDriver($id: ID!) {\n driver(id: $id) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", u = "\n mutation UpdateVehicleStatus($id: ID!, $status: VehicleStatus!) {\n updateVehicleStatus(id: $id, status: $status) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n createdAt\n updatedAt\n }\n }\n", d = "\n mutation AssignDriverVehicle($id: ID!, $vehicleId: ID) {\n assignDriverVehicle(id: $id, vehicleId: $vehicleId) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", f = "\n mutation UpdateDriverStatus($id: ID!, $status: DriverStatus!) {\n updateDriverStatus(id: $id, status: $status) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", p = "\n mutation CreateVehicle($input: CreateVehicleInput!) {\n createVehicle(input: $input) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n createdAt\n updatedAt\n }\n }\n", m = "\n mutation CreateDriver($input: CreateDriverInput!) {\n createDriver(input: $input) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", h = "\n mutation UpdateVehicle($id: ID!, $input: UpdateVehicleInput!) {\n updateVehicle(id: $id, input: $input) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n createdAt\n updatedAt\n }\n }\n", g = "\n mutation UpdateDriver($id: ID!, $input: UpdateDriverInput!) {\n updateDriver(id: $id, input: $input) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", _ = "\n query GetDriverStatusCounts {\n onBreak: driversCount(filter: { status: ON_BREAK })\n offDuty: driversCount(filter: { status: OFF_DUTY })\n inactive: driversCount(filter: { status: INACTIVE })\n }\n", v = "\n query GetFleetStats {\n fleetStats {\n totalVehicles\n activeVehicles\n inTransitVehicles\n maintenanceVehicles\n totalDrivers\n availableDrivers\n onDeliveryDrivers\n avgDriverRating\n }\n }\n";
5
+ var o = "\n query ListVehicles($filter: VehicleFilterInput, $pagination: PaginationInput) {\n vehicles(filter: $filter, pagination: $pagination) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n lastServiceDate\n nextServiceDueDate\n nextServiceDueMileage\n createdAt\n updatedAt\n }\n }\n", s = "\n query ListDrivers($filter: DriverFilterInput, $pagination: PaginationInput) {\n drivers(filter: $filter, pagination: $pagination) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", c = "\n query GetVehicle($id: ID!) {\n vehicle(id: $id) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n lastServiceDate\n nextServiceDueDate\n nextServiceDueMileage\n createdAt\n updatedAt\n }\n }\n", l = "\n query GetDriver($id: ID!) {\n driver(id: $id) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", u = "\n mutation UpdateVehicleStatus($id: ID!, $status: VehicleStatus!) {\n updateVehicleStatus(id: $id, status: $status) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n createdAt\n updatedAt\n }\n }\n", d = "\n mutation AssignDriverVehicle($id: ID!, $vehicleId: ID) {\n assignDriverVehicle(id: $id, vehicleId: $vehicleId) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", f = "\n mutation UpdateDriverStatus($id: ID!, $status: DriverStatus!) {\n updateDriverStatus(id: $id, status: $status) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", p = "\n mutation CreateVehicle($input: CreateVehicleInput!) {\n createVehicle(input: $input) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n createdAt\n updatedAt\n }\n }\n", m = "\n mutation CreateDriver($input: CreateDriverInput!) {\n createDriver(input: $input) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", h = "\n mutation UpdateVehicle($id: ID!, $input: UpdateVehicleInput!) {\n updateVehicle(id: $id, input: $input) {\n id\n vehicleNumber\n type\n make\n model\n licensePlate\n ownershipType\n year\n capacity\n status\n currentLocation\n fuelLevel\n mileage\n createdAt\n updatedAt\n }\n }\n", g = "\n mutation UpdateDriver($id: ID!, $input: UpdateDriverInput!) {\n updateDriver(id: $id, input: $input) {\n id\n userId\n firstName\n lastName\n email\n phone\n employeeId\n licenseNumber\n licenseClass\n licenseExpiry\n status\n currentLocation\n rating\n vehicleId\n createdAt\n }\n }\n", _ = "\n query GetDriverStatusCounts {\n onBreak: driversCount(filter: { status: ON_BREAK })\n offDuty: driversCount(filter: { status: OFF_DUTY })\n inactive: driversCount(filter: { status: INACTIVE })\n }\n", v = "\n query GetFleetStats {\n fleetStats {\n totalVehicles\n activeVehicles\n inTransitVehicles\n maintenanceVehicles\n totalDrivers\n availableDrivers\n onDeliveryDrivers\n avgDriverRating\n }\n }\n";
6
6
  function y(e) {
7
7
  switch (e) {
8
8
  case "ACTIVE": return "available";
@@ -58,8 +58,9 @@ function C(e) {
58
58
  address: e.currentLocation.address ?? void 0,
59
59
  timestamp: /* @__PURE__ */ new Date()
60
60
  } : void 0,
61
- lastMaintenance: void 0,
62
- nextMaintenance: void 0,
61
+ lastMaintenance: e.lastServiceDate ? new Date(e.lastServiceDate) : void 0,
62
+ nextMaintenance: e.nextServiceDueDate ? new Date(e.nextServiceDueDate) : void 0,
63
+ nextMaintenanceMileage: e.nextServiceDueMileage ?? void 0,
63
64
  fuelLevel: e.fuelLevel ?? void 0,
64
65
  mileage: e.mileage ?? void 0,
65
66
  documents: [],