@burdenoff/microfe-movethewheels 2026.925.1 → 2026.925.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.
Files changed (47) hide show
  1. package/dist/components/StatusBadge.js +31 -31
  2. package/dist/constants/index.js +19 -5
  3. package/dist/hooks/useCustomers.js +0 -3
  4. package/dist/hooks/useFleet.js +197 -175
  5. package/dist/hooks/useInventory.js +144 -145
  6. package/dist/hooks/useRoutes.js +5 -14
  7. package/dist/movethewheels/components/StatusBadge.d.ts +3 -1
  8. package/dist/movethewheels/constants/index.d.ts +2 -0
  9. package/dist/movethewheels/hooks/useFleet.d.ts +53 -1
  10. package/dist/movethewheels/hooks/useInventory.d.ts +10 -0
  11. package/dist/movethewheels/types/index.d.ts +29 -108
  12. package/dist/node_modules/lucide-react/dist/esm/icons/sticky-note.js +11 -0
  13. package/dist/node_modules/lucide-react/dist/esm/icons/user-x.js +30 -0
  14. package/dist/pages/CustomerDetailsPage.js +666 -344
  15. package/dist/pages/CustomersPage.js +71 -80
  16. package/dist/pages/DriverDetailsPage.js +702 -421
  17. package/dist/pages/DriversPage.js +106 -117
  18. package/dist/pages/FleetPage.js +5 -13
  19. package/dist/pages/InventoryPage.js +4 -4
  20. package/dist/pages/OrderDetailsPage.js +279 -274
  21. package/dist/pages/RouteDetailsPage.js +300 -263
  22. package/dist/pages/RoutesPage.js +130 -67
  23. package/dist/pages/VehicleDetailsPage.js +562 -287
  24. package/dist/pages/VehiclesPage.js +119 -70
  25. package/dist/pages/WarehouseDetailsPage.js +410 -370
  26. package/dist/pages/WarehousesPage.js +131 -82
  27. package/package.json +1 -1
  28. package/src/movethewheels/components/StatusBadge.tsx +16 -2
  29. package/src/movethewheels/constants/index.ts +21 -0
  30. package/src/movethewheels/hooks/useCustomers.ts +0 -3
  31. package/src/movethewheels/hooks/useFleet.ts +236 -62
  32. package/src/movethewheels/hooks/useInventory.ts +76 -32
  33. package/src/movethewheels/hooks/useRoutes.ts +17 -12
  34. package/src/movethewheels/pages/CustomerDetailsPage.tsx +376 -109
  35. package/src/movethewheels/pages/CustomersPage.tsx +6 -15
  36. package/src/movethewheels/pages/DriverDetailsPage.tsx +516 -156
  37. package/src/movethewheels/pages/DriversPage.tsx +28 -11
  38. package/src/movethewheels/pages/FleetPage.tsx +9 -11
  39. package/src/movethewheels/pages/InventoryPage.tsx +14 -5
  40. package/src/movethewheels/pages/OrderDetailsPage.tsx +12 -7
  41. package/src/movethewheels/pages/RouteDetailsPage.tsx +89 -41
  42. package/src/movethewheels/pages/RoutesPage.tsx +66 -2
  43. package/src/movethewheels/pages/VehicleDetailsPage.tsx +282 -20
  44. package/src/movethewheels/pages/VehiclesPage.tsx +68 -3
  45. package/src/movethewheels/pages/WarehouseDetailsPage.tsx +213 -135
  46. package/src/movethewheels/pages/WarehousesPage.tsx +77 -16
  47. package/src/movethewheels/types/index.ts +30 -108
@@ -1,85 +1,140 @@
1
1
  import { CircleCheck as e } from "../node_modules/lucide-react/dist/esm/icons/circle-check.js";
2
- import { Gauge as t } from "../node_modules/lucide-react/dist/esm/icons/gauge.js";
3
- import { Plus as n } from "../node_modules/lucide-react/dist/esm/icons/plus.js";
4
- import { RefreshCw as r } from "../node_modules/lucide-react/dist/esm/icons/refresh-cw.js";
5
- import { Warehouse as i } from "../node_modules/lucide-react/dist/esm/icons/warehouse.js";
6
- import { joinPath as a } from "../utils/navigation.js";
7
- import { useMoveTheWheels as o } from "../providers/MoveTheWheelsProvider.js";
8
- import { useWarehouseStats as s, useWarehouses as c } from "../hooks/useInventory.js";
9
- import { Badge as l, Progress as u } from "../components/ui.js";
10
- import { PageLayout as d } from "../components/PageLayout.js";
11
- import { MetricCard as f, MetricGrid as p } from "../components/MetricCard.js";
12
- import { DataTable as m } from "../components/DataTable.js";
13
- import { useDebouncedValue as h } from "../hooks/useDebouncedValue.js";
14
- import { useState as g } from "react";
15
- import { jsx as _, jsxs as v } from "react/jsx-runtime";
16
- import { CTAOverflowMenu as y, PagePurpose as b } from "@burdenoff/fe-libs/ui";
2
+ import { Filter as t } from "../node_modules/lucide-react/dist/esm/icons/filter.js";
3
+ import { Gauge as n } from "../node_modules/lucide-react/dist/esm/icons/gauge.js";
4
+ import { Plus as r } from "../node_modules/lucide-react/dist/esm/icons/plus.js";
5
+ import { RefreshCw as i } from "../node_modules/lucide-react/dist/esm/icons/refresh-cw.js";
6
+ import { Warehouse as a } from "../node_modules/lucide-react/dist/esm/icons/warehouse.js";
7
+ import { joinPath as o } from "../utils/navigation.js";
8
+ import { useMoveTheWheels as s } from "../providers/MoveTheWheelsProvider.js";
9
+ import { useWarehouseStats as c, useWarehouses as l } from "../hooks/useInventory.js";
10
+ import { Badge as u, Button as d, Card as f, CardContent as p, Progress as m, Select as h, SelectContent as g, SelectItem as _, SelectTrigger as v, SelectValue as y } from "../components/ui.js";
11
+ import { PageLayout as b } from "../components/PageLayout.js";
12
+ import { MetricCard as x, MetricGrid as S } from "../components/MetricCard.js";
13
+ import { DataTable as C } from "../components/DataTable.js";
14
+ import { useDebouncedValue as w } from "../hooks/useDebouncedValue.js";
15
+ import { useState as T } from "react";
16
+ import { jsx as E, jsxs as D } from "react/jsx-runtime";
17
+ import { CTAOverflowMenu as O, PagePurpose as k } from "@burdenoff/fe-libs/ui";
17
18
  //#region src/movethewheels/pages/WarehousesPage.tsx
18
- function x() {
19
- let { basePath: x, navigate: S } = o(), [C, w] = g(0), [T, E] = g(25), [D, O] = g(""), k = h(D), { warehouses: A, totalWarehouses: j, hasMore: M, isLoading: N, error: P, refetch: F } = c({
20
- limit: T,
21
- offset: C * T,
22
- search: k
23
- }), { stats: I } = s(), L = (e) => S?.(a(x, e));
24
- return /* @__PURE__ */ v(d, {
19
+ var A = [
20
+ {
21
+ value: "all",
22
+ label: "All statuses"
23
+ },
24
+ {
25
+ value: "ACTIVE",
26
+ label: "Active"
27
+ },
28
+ {
29
+ value: "INACTIVE",
30
+ label: "Inactive"
31
+ }
32
+ ];
33
+ function j() {
34
+ let { basePath: j, navigate: M } = s(), [N, P] = T(0), [F, I] = T(25), [L, R] = T(""), [z, B] = T("all"), V = w(L), { warehouses: H, totalWarehouses: U, hasMore: W, isLoading: G, error: K, refetch: q } = l({
35
+ limit: F,
36
+ offset: N * F,
37
+ search: V,
38
+ status: z === "all" ? void 0 : z
39
+ }), J = z !== "all" || L.length > 0, { stats: Y } = c(), X = (e) => M?.(o(j, e));
40
+ return /* @__PURE__ */ D(b, {
25
41
  title: "Warehouses",
26
- subtitle: `${I.total} warehouses`,
27
- icon: /* @__PURE__ */ _(i, { size: 24 }),
28
- headerActions: /* @__PURE__ */ _(y, {
42
+ subtitle: `${Y.total} warehouses`,
43
+ icon: /* @__PURE__ */ E(a, { size: 24 }),
44
+ headerActions: /* @__PURE__ */ E(O, {
29
45
  primary: {
30
46
  label: "Add Warehouse",
31
- icon: /* @__PURE__ */ _(n, { size: 16 }),
32
- onSelect: () => L("inventory/warehouses/new")
47
+ icon: /* @__PURE__ */ E(r, { size: 16 }),
48
+ onSelect: () => X("inventory/warehouses/new")
33
49
  },
34
50
  actions: [{
35
51
  label: "Refresh",
36
- icon: /* @__PURE__ */ _(r, { size: 16 }),
37
- onSelect: () => F()
52
+ icon: /* @__PURE__ */ E(i, { size: 16 }),
53
+ onSelect: () => q()
38
54
  }]
39
55
  }),
40
56
  children: [
41
- /* @__PURE__ */ _(b, {
42
- icon: /* @__PURE__ */ _(i, { size: 18 }),
57
+ /* @__PURE__ */ E(k, {
58
+ icon: /* @__PURE__ */ E(a, { size: 18 }),
43
59
  children: "Your storage and fulfilment sites. Watch space and pallet utilization across each warehouse to balance stock, spot capacity crunches, and decide where to fulfil an order from."
44
60
  }),
45
- /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
61
+ /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("p", {
46
62
  className: "mb-3 text-sm font-medium text-text-secondary",
47
63
  children: "Network at a glance"
48
- }), /* @__PURE__ */ v(p, {
64
+ }), /* @__PURE__ */ D(S, {
49
65
  columns: 3,
50
66
  children: [
51
- /* @__PURE__ */ _(f, {
67
+ /* @__PURE__ */ E(x, {
52
68
  label: "Total sites",
53
- value: I.total,
54
- icon: /* @__PURE__ */ _(i, { size: 20 }),
69
+ value: Y.total,
70
+ icon: /* @__PURE__ */ E(a, { size: 20 }),
55
71
  accent: "brand"
56
72
  }),
57
- /* @__PURE__ */ _(f, {
73
+ /* @__PURE__ */ E(x, {
58
74
  label: "Active",
59
- value: I.active,
60
- icon: /* @__PURE__ */ _(e, { size: 20 }),
75
+ value: Y.active,
76
+ icon: /* @__PURE__ */ E(e, { size: 20 }),
61
77
  accent: "success",
62
78
  subtitle: "Fulfilling orders"
63
79
  }),
64
- /* @__PURE__ */ _(f, {
80
+ /* @__PURE__ */ E(x, {
65
81
  label: "Avg utilization",
66
- value: I.total > 0 ? `${Math.round(I.avgUtilization * 100)}%` : "—",
67
- icon: /* @__PURE__ */ _(t, { size: 20 }),
82
+ value: Y.total > 0 ? `${Math.round(Y.avgUtilization * 100)}%` : "—",
83
+ icon: /* @__PURE__ */ E(n, { size: 20 }),
68
84
  accent: "blue"
69
85
  })
70
86
  ]
71
87
  })] }),
72
- /* @__PURE__ */ _(m, {
88
+ /* @__PURE__ */ E(f, { children: /* @__PURE__ */ E(p, {
89
+ className: "p-4",
90
+ children: /* @__PURE__ */ D("div", {
91
+ className: "flex flex-wrap items-center gap-4",
92
+ children: [
93
+ /* @__PURE__ */ D("div", {
94
+ className: "flex items-center gap-2",
95
+ children: [/* @__PURE__ */ E(t, {
96
+ size: 16,
97
+ className: "text-text-secondary"
98
+ }), /* @__PURE__ */ E("span", {
99
+ className: "text-sm font-medium",
100
+ children: "Filters:"
101
+ })]
102
+ }),
103
+ /* @__PURE__ */ D(h, {
104
+ value: z,
105
+ onValueChange: (e) => {
106
+ B(e), P(0);
107
+ },
108
+ children: [/* @__PURE__ */ E(v, {
109
+ className: "w-[180px]",
110
+ children: /* @__PURE__ */ E(y, { placeholder: "Status" })
111
+ }), /* @__PURE__ */ E(g, { children: A.map((e) => /* @__PURE__ */ E(_, {
112
+ value: e.value,
113
+ children: e.label
114
+ }, e.value)) })]
115
+ }),
116
+ J && /* @__PURE__ */ E(d, {
117
+ variant: "ghost",
118
+ size: "sm",
119
+ onClick: () => {
120
+ B("all"), R(""), P(0);
121
+ },
122
+ children: "Clear filters"
123
+ })
124
+ ]
125
+ })
126
+ }) }),
127
+ /* @__PURE__ */ E(C, {
73
128
  columns: [
74
129
  {
75
130
  id: "name",
76
131
  header: "Warehouse",
77
132
  accessorKey: "name",
78
133
  sortable: !0,
79
- cell: (e) => /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("p", {
134
+ cell: (e) => /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("p", {
80
135
  className: "font-medium",
81
136
  children: e.name
82
- }), /* @__PURE__ */ _("p", {
137
+ }), /* @__PURE__ */ E("p", {
83
138
  className: "text-sm text-text-secondary",
84
139
  children: e.code
85
140
  })] })
@@ -87,11 +142,11 @@ function x() {
87
142
  {
88
143
  id: "location",
89
144
  header: "Location",
90
- cell: (e) => /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ v("p", { children: [
145
+ cell: (e) => /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ D("p", { children: [
91
146
  e.address.city,
92
147
  ", ",
93
148
  e.address.state
94
- ] }), /* @__PURE__ */ _("p", {
149
+ ] }), /* @__PURE__ */ E("p", {
95
150
  className: "text-sm text-text-secondary",
96
151
  children: e.address.country
97
152
  })] })
@@ -100,7 +155,7 @@ function x() {
100
155
  id: "type",
101
156
  header: "Type",
102
157
  accessorKey: "type",
103
- cell: (e) => /* @__PURE__ */ _(l, {
158
+ cell: (e) => /* @__PURE__ */ E(u, {
104
159
  variant: "outline",
105
160
  className: "capitalize",
106
161
  children: e.type.replace("_", " ")
@@ -111,12 +166,12 @@ function x() {
111
166
  header: "Utilization",
112
167
  cell: (e) => {
113
168
  let t = e.capacity.usedSpace / e.capacity.totalSpace * 100;
114
- return /* @__PURE__ */ v("div", {
169
+ return /* @__PURE__ */ D("div", {
115
170
  className: "flex items-center gap-2",
116
- children: [/* @__PURE__ */ _(u, {
171
+ children: [/* @__PURE__ */ E(m, {
117
172
  value: t,
118
173
  className: "w-16 h-2"
119
- }), /* @__PURE__ */ v("span", {
174
+ }), /* @__PURE__ */ D("span", {
120
175
  className: "text-sm",
121
176
  children: [t.toFixed(0), "%"]
122
177
  })]
@@ -126,55 +181,49 @@ function x() {
126
181
  {
127
182
  id: "capacity",
128
183
  header: "Capacity",
129
- cell: (e) => /* @__PURE__ */ v("div", {
184
+ cell: (e) => /* @__PURE__ */ D("p", {
130
185
  className: "text-sm",
131
- children: [/* @__PURE__ */ v("p", { children: [
186
+ children: [
132
187
  e.capacity.usedSpace.toLocaleString(),
133
188
  " / ",
134
189
  e.capacity.totalSpace.toLocaleString(),
135
- " ",
136
- "sq ft"
137
- ] }), /* @__PURE__ */ v("p", {
138
- className: "text-text-secondary",
139
- children: [
140
- e.capacity.usedPallets,
141
- " / ",
142
- e.capacity.totalPallets,
143
- " pallets"
144
- ]
145
- })]
190
+ " sq ft"
191
+ ]
146
192
  })
147
193
  },
148
194
  {
149
195
  id: "status",
150
196
  header: "Status",
151
- cell: (e) => /* @__PURE__ */ _(l, {
152
- variant: e.isActive ? "default" : "secondary",
153
- children: e.isActive ? "Active" : "Inactive"
154
- })
197
+ cell: (e) => {
198
+ let t = e.status.toUpperCase() === "ACTIVE";
199
+ return /* @__PURE__ */ E(u, {
200
+ variant: t ? "default" : "secondary",
201
+ children: t ? "Active" : "Inactive"
202
+ });
203
+ }
155
204
  }
156
205
  ],
157
- data: A,
158
- isLoading: N,
159
- error: P,
160
- onRetry: F,
206
+ data: H,
207
+ isLoading: G,
208
+ error: K,
209
+ onRetry: q,
161
210
  searchable: !0,
162
211
  searchPlaceholder: "Search warehouses...",
163
212
  searchFields: ["name", "code"],
164
- searchQuery: D,
213
+ searchQuery: L,
165
214
  onSearchQueryChange: (e) => {
166
- O(e), w(0);
215
+ R(e), P(0);
167
216
  },
168
- onRowClick: (e) => L(`inventory/warehouses/${e.id}`),
217
+ onRowClick: (e) => X(`inventory/warehouses/${e.id}`),
169
218
  getRowId: (e) => e.id,
170
- pageIndex: C,
171
- pageSize: T,
172
- onPageChange: w,
219
+ pageIndex: N,
220
+ pageSize: F,
221
+ onPageChange: P,
173
222
  onPageSizeChange: (e) => {
174
- E(e), w(0);
223
+ I(e), P(0);
175
224
  },
176
- totalItems: j,
177
- hasNextPage: M,
225
+ totalItems: U,
226
+ hasNextPage: W,
178
227
  emptyIllustration: "empty-data",
179
228
  emptyTitle: "No warehouses yet",
180
229
  emptyDescription: "Add a warehouse to store inventory and fulfil orders from it."
@@ -183,4 +232,4 @@ function x() {
183
232
  });
184
233
  }
185
234
  //#endregion
186
- export { x as default };
235
+ export { j as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-movethewheels",
3
- "version": "2026.925.1",
3
+ "version": "2026.925.3",
4
4
  "description": "Burdenoff MoveTheWheels Microfrontend - Logistics & Supply Chain Management Platform",
5
5
  "type": "module",
6
6
  "files": [
@@ -4,7 +4,9 @@ import type { OrderStatus, VehicleStatus, DriverStatus } from '../types';
4
4
  import {
5
5
  ORDER_STATUS_COLORS,
6
6
  VEHICLE_STATUS_COLORS,
7
+ VEHICLE_STATUS_LABELS,
7
8
  DRIVER_STATUS_COLORS,
9
+ DRIVER_STATUS_LABELS,
8
10
  PRIORITY_COLORS,
9
11
  } from '../constants';
10
12
 
@@ -17,6 +19,8 @@ interface StatusBadgeProps {
17
19
  bg: string;
18
20
  text: string;
19
21
  };
22
+ /** Override the auto-derived display text (title-cased raw status). */
23
+ label?: string;
20
24
  size?: 'sm' | 'md' | 'lg';
21
25
  showDot?: boolean;
22
26
  className?: string;
@@ -35,6 +39,7 @@ export function StatusBadge({
35
39
  status,
36
40
  type = 'custom',
37
41
  customColors,
42
+ label,
38
43
  size = 'md',
39
44
  showDot = true,
40
45
  className,
@@ -59,8 +64,17 @@ export function StatusBadge({
59
64
  }
60
65
  }
61
66
 
62
- // Format status for display
63
- const displayStatus = status.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
67
+ // Format status for display — an explicit label always wins; driver status
68
+ // otherwise renders from the same shared label map the filters use, so the
69
+ // table and the filter dropdown can never drift apart again (BOFF-7909).
70
+ const sharedLabel =
71
+ type === 'driver'
72
+ ? DRIVER_STATUS_LABELS[status]
73
+ : type === 'vehicle'
74
+ ? VEHICLE_STATUS_LABELS[status]
75
+ : undefined;
76
+ const displayStatus =
77
+ label ?? sharedLabel ?? status.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
64
78
 
65
79
  return (
66
80
  <Badge
@@ -57,6 +57,15 @@ export const VEHICLE_STATUS_COLORS: Record<string, StatusColor> = {
57
57
  assigned: INFO,
58
58
  maintenance: WARNING,
59
59
  out_of_service: ERROR,
60
+ decommissioned: NEUTRAL,
61
+ };
62
+
63
+ export const VEHICLE_STATUS_LABELS: Record<string, string> = {
64
+ available: 'Available',
65
+ assigned: 'In Transit',
66
+ maintenance: 'Maintenance',
67
+ out_of_service: 'Out of Service',
68
+ decommissioned: 'Decommissioned',
60
69
  };
61
70
 
62
71
  // Driver status colors
@@ -65,6 +74,18 @@ export const DRIVER_STATUS_COLORS: Record<string, StatusColor> = {
65
74
  busy: INFO,
66
75
  offline: NEUTRAL,
67
76
  on_break: WARNING,
77
+ inactive: ERROR,
78
+ };
79
+
80
+ // Single source of truth for driver status display text — used by both the
81
+ // DriversPage status filter and the roster table's StatusBadge, so the two
82
+ // can never drift apart again (BOFF-7909).
83
+ export const DRIVER_STATUS_LABELS: Record<string, string> = {
84
+ available: 'Available',
85
+ busy: 'On Delivery',
86
+ offline: 'Off Duty',
87
+ on_break: 'On Break',
88
+ inactive: 'Inactive',
68
89
  };
69
90
 
70
91
  // Priority colors
@@ -142,9 +142,6 @@ function mapCustomer(customer: ApiCustomer): Customer {
142
142
  },
143
143
  businessLicense: customer.businessLicense ?? undefined,
144
144
  taxId: customer.taxId ?? undefined,
145
- preferredContactMethod: 'email',
146
- marketingOptIn: false,
147
- isActive: !customer.deletedAt,
148
145
  rating: customer.rating ?? 0,
149
146
  createdAt: new Date(customer.createdAt),
150
147
  updatedAt: new Date(customer.updatedAt),