@burdenoff/microfe-movethewheels 2026.929.2 → 2026.929.4

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 (50) hide show
  1. package/dist/generated/wspace-types.d.ts +1547 -64
  2. package/dist/hooks/useCustomers.js +3 -9
  3. package/dist/hooks/useFleet.js +147 -150
  4. package/dist/hooks/useInventory.js +178 -153
  5. package/dist/hooks/useRoutes.js +9 -9
  6. package/dist/hooks/useTracking.js +14 -16
  7. package/dist/movethewheels/hooks/useFleet.d.ts +11 -4
  8. package/dist/movethewheels/hooks/useInventory.d.ts +13 -12
  9. package/dist/movethewheels/hooks/useRoutes.d.ts +4 -1
  10. package/dist/movethewheels/types/index.d.ts +33 -23
  11. package/dist/movethewheels/utils/formatters.d.ts +1 -1
  12. package/dist/pages/CustomerDetailsPage.js +6 -6
  13. package/dist/pages/CustomersPage.js +2 -2
  14. package/dist/pages/DashboardPage.js +1 -1
  15. package/dist/pages/DriverDetailsPage.js +68 -43
  16. package/dist/pages/DriversPage.js +4 -4
  17. package/dist/pages/FleetPage.js +1 -1
  18. package/dist/pages/InventoryPage.js +11 -12
  19. package/dist/pages/LiveTrackingPage.js +4 -4
  20. package/dist/pages/ProductDetailsPage.js +408 -249
  21. package/dist/pages/ProductsPage.js +5 -5
  22. package/dist/pages/RouteDetailsPage.js +8 -10
  23. package/dist/pages/RoutesPage.js +2 -2
  24. package/dist/pages/TrackingPage.js +14 -8
  25. package/dist/pages/WarehouseDetailsPage.js +166 -163
  26. package/dist/pages/WarehousesPage.js +29 -21
  27. package/package.json +1 -1
  28. package/src/generated/wspace-types.ts +1762 -64
  29. package/src/movethewheels/hooks/useCustomers.ts +7 -9
  30. package/src/movethewheels/hooks/useFleet.ts +92 -34
  31. package/src/movethewheels/hooks/useInventory.ts +143 -49
  32. package/src/movethewheels/hooks/useRoutes.ts +36 -16
  33. package/src/movethewheels/hooks/useTracking.ts +23 -15
  34. package/src/movethewheels/pages/CustomerDetailsPage.tsx +14 -8
  35. package/src/movethewheels/pages/CustomersPage.tsx +5 -2
  36. package/src/movethewheels/pages/DashboardPage.tsx +3 -1
  37. package/src/movethewheels/pages/DriverDetailsPage.tsx +44 -12
  38. package/src/movethewheels/pages/DriversPage.tsx +1 -1
  39. package/src/movethewheels/pages/FleetPage.tsx +1 -1
  40. package/src/movethewheels/pages/InventoryPage.tsx +20 -16
  41. package/src/movethewheels/pages/LiveTrackingPage.tsx +6 -4
  42. package/src/movethewheels/pages/ProductDetailsPage.tsx +228 -49
  43. package/src/movethewheels/pages/ProductsPage.tsx +13 -5
  44. package/src/movethewheels/pages/RouteDetailsPage.tsx +16 -8
  45. package/src/movethewheels/pages/RoutesPage.tsx +4 -2
  46. package/src/movethewheels/pages/TrackingPage.tsx +25 -10
  47. package/src/movethewheels/pages/WarehouseDetailsPage.tsx +42 -29
  48. package/src/movethewheels/pages/WarehousesPage.tsx +23 -15
  49. package/src/movethewheels/types/index.ts +36 -24
  50. package/src/movethewheels/utils/formatters.ts +1 -1
@@ -21,7 +21,13 @@ interface UseRoutesResult {
21
21
  error: Error | null;
22
22
  refetch: () => void;
23
23
  createRoute: (route: Partial<Route>) => Promise<Route>;
24
- updateRoute: (id: string, updates: Partial<Route>) => Promise<Route>;
24
+ updateRoute: (
25
+ id: string,
26
+ updates: Omit<Partial<Route>, 'vehicleId' | 'driverId'> & {
27
+ vehicleId?: string | null;
28
+ driverId?: string | null;
29
+ }
30
+ ) => Promise<Route>;
25
31
  deleteRoute: (id: string) => Promise<void>;
26
32
  optimizeRoute: (routeId: string) => Promise<Route>;
27
33
  updateStopStatus: (
@@ -205,13 +211,19 @@ function mapWaypoints(waypoints: unknown): RouteStop[] {
205
211
  state: String(addrObj.state ?? item.state ?? ''),
206
212
  postalCode: String(addrObj.postalCode ?? item.postalCode ?? ''),
207
213
  country: String(addrObj.country ?? item.country ?? ''),
208
- latitude: Number(addrObj.latitude ?? item.latitude ?? item.lat ?? 0),
209
- longitude: Number(addrObj.longitude ?? item.longitude ?? item.lng ?? 0),
214
+ latitude:
215
+ typeof (addrObj.latitude ?? item.latitude ?? item.lat) === 'number'
216
+ ? ((addrObj.latitude ?? item.latitude ?? item.lat) as number)
217
+ : undefined,
218
+ longitude:
219
+ typeof (addrObj.longitude ?? item.longitude ?? item.lng) === 'number'
220
+ ? ((addrObj.longitude ?? item.longitude ?? item.lng) as number)
221
+ : undefined,
210
222
  },
211
223
  type: item.type === 'pickup' ? 'pickup' : 'delivery',
212
- scheduledTime: item.scheduledTime ? new Date(String(item.scheduledTime)) : new Date(),
224
+ scheduledTime: item.scheduledTime ? new Date(String(item.scheduledTime)) : undefined,
213
225
  actualTime: item.actualTime ? new Date(String(item.actualTime)) : undefined,
214
- duration: Number(item.duration ?? 0),
226
+ duration: typeof item.duration === 'number' ? item.duration : undefined,
215
227
  status: (item.status as RouteStop['status']) ?? 'pending',
216
228
  notes: item.notes ? String(item.notes) : undefined,
217
229
  };
@@ -222,8 +234,8 @@ export function mapRoute(route: ApiRoute): Route {
222
234
  return {
223
235
  id: route.id,
224
236
  name: route.name,
225
- driverId: route.driverId ?? '',
226
- vehicleId: route.vehicleId ?? '',
237
+ driverId: route.driverId ?? undefined,
238
+ vehicleId: route.vehicleId ?? undefined,
227
239
  status: mapRouteStatus(route.status),
228
240
  stops: mapWaypoints(route.waypoints),
229
241
  // Prefer the real post-drive distance once it exists; the backend fetches
@@ -232,12 +244,10 @@ export function mapRoute(route: ApiRoute): Route {
232
244
  estimatedDuration: route.estimatedDuration ?? 0,
233
245
  fuelCost: route.fuelCost ?? undefined,
234
246
  actualDuration: route.actualDuration ?? undefined,
235
- // No `optimized` flag exists on the backend — `optimizeRoute` is the only
236
- // path that computes a real `estimatedDistance` (create/update never
237
- // collect one), so a positive value is a reasonably honest proxy. This
238
- // used to be hardcoded `false` and reset on every reload even for a
239
- // route that really had been optimized (BOFF-7909 follow-up).
240
- optimized: (route.estimatedDistance ?? 0) > 0,
247
+ // The route object has no optimization marker. `estimatedDistance` is a
248
+ // measurement, not proof that the optimize mutation ran, so leave this
249
+ // unknown rather than presenting an inferred Yes/No.
250
+ optimized: undefined,
241
251
  createdAt: new Date(route.createdAt),
242
252
  };
243
253
  }
@@ -334,7 +344,13 @@ export function useRoutes(options: UseRoutesOptions = {}): UseRoutesResult {
334
344
  );
335
345
 
336
346
  const updateRoute = useCallback(
337
- async (id: string, updates: Partial<Route>): Promise<Route> => {
347
+ async (
348
+ id: string,
349
+ updates: Omit<Partial<Route>, 'vehicleId' | 'driverId'> & {
350
+ vehicleId?: string | null;
351
+ driverId?: string | null;
352
+ }
353
+ ): Promise<Route> => {
338
354
  const data = await executeGraphQL<{ updateRoute: ApiRoute }>(
339
355
  graphQLOptions,
340
356
  UPDATE_ROUTE_MUTATION,
@@ -344,8 +360,12 @@ export function useRoutes(options: UseRoutesOptions = {}): UseRoutesResult {
344
360
  name: updates.name,
345
361
  status: toApiRouteStatus(updates.status),
346
362
  shipmentId: undefined,
347
- vehicleId: updates.vehicleId,
348
- driverId: updates.driverId,
363
+ vehicleId: Object.prototype.hasOwnProperty.call(updates, 'vehicleId')
364
+ ? (updates.vehicleId ?? null)
365
+ : undefined,
366
+ driverId: Object.prototype.hasOwnProperty.call(updates, 'driverId')
367
+ ? (updates.driverId ?? null)
368
+ : undefined,
349
369
  waypoints: updates.stops,
350
370
  // See createRoute — the edit form doesn't collect a distance
351
371
  // either, and `distance` must never masquerade as `actualDistance`.
@@ -209,11 +209,23 @@ const TRACKING_ALERTS_QUERY = `
209
209
  }
210
210
  `;
211
211
 
212
- function mapTrackingEventToLocation(event: ApiTrackingEvent): Location {
212
+ function mapTrackingEventToLocation(event: ApiTrackingEvent): Location | null {
213
+ const raw = event.location;
214
+ if (!raw) return null;
215
+ const latitude = raw.latitude ?? raw.lat;
216
+ const longitude = raw.longitude ?? raw.lng;
217
+ if (
218
+ typeof latitude !== 'number' ||
219
+ !Number.isFinite(latitude) ||
220
+ typeof longitude !== 'number' ||
221
+ !Number.isFinite(longitude)
222
+ ) {
223
+ return null;
224
+ }
213
225
  return {
214
- latitude: Number((event.location?.latitude as number | undefined) ?? 0),
215
- longitude: Number((event.location?.longitude as number | undefined) ?? 0),
216
- address: (event.location?.address as string | undefined) ?? undefined,
226
+ latitude,
227
+ longitude,
228
+ address: typeof raw.address === 'string' ? raw.address : undefined,
217
229
  timestamp: new Date(event.timestamp),
218
230
  };
219
231
  }
@@ -225,9 +237,10 @@ function mapTrackingEventsToTracking(
225
237
  const latest = events[0];
226
238
  if (!latest) return null;
227
239
 
228
- const locationHistory = events.map(mapTrackingEventToLocation);
240
+ const locationHistory = events
241
+ .map(mapTrackingEventToLocation)
242
+ .filter((location): location is Location => location !== null);
229
243
  const currentLocation = locationHistory[0];
230
- if (!currentLocation) return null;
231
244
 
232
245
  return {
233
246
  id: latest.id,
@@ -307,11 +320,7 @@ export function useTracking(options: UseTrackingOptions = {}): UseTrackingResult
307
320
  id: shipment.id,
308
321
  entityId: entityId ?? shipment.deliveryJobId ?? shipment.id,
309
322
  entityType: entityType ?? 'order',
310
- currentLocation: {
311
- latitude: 0,
312
- longitude: 0,
313
- timestamp: new Date(),
314
- },
323
+ currentLocation: undefined,
315
324
  locationHistory: [],
316
325
  status: shipment.status.toLowerCase(),
317
326
  estimatedArrival: shipment.estimatedDelivery
@@ -319,7 +328,7 @@ export function useTracking(options: UseTrackingOptions = {}): UseTrackingResult
319
328
  : undefined,
320
329
  nextCheckpoint: shipment.shipmentNumber,
321
330
  alerts: [],
322
- lastUpdated: new Date(),
331
+ lastUpdated: undefined,
323
332
  }));
324
333
 
325
334
  setTracking(mapped);
@@ -518,7 +527,7 @@ export function useVehicleTracking(vehicleId: string | undefined) {
518
527
  currentLocation: vehicle.currentLocation,
519
528
  locationHistory: [vehicle.currentLocation],
520
529
  status: vehicle.status,
521
- lastUpdated: vehicle.currentLocation.timestamp ?? new Date(),
530
+ lastUpdated: vehicle.currentLocation.timestamp,
522
531
  alerts: [],
523
532
  };
524
533
  }, [vehicle]);
@@ -538,7 +547,7 @@ export function useDriverTracking(driverId: string | undefined) {
538
547
  currentLocation: driver.currentLocation,
539
548
  locationHistory: [driver.currentLocation],
540
549
  status: driver.status,
541
- lastUpdated: driver.currentLocation.timestamp ?? new Date(),
550
+ lastUpdated: driver.currentLocation.timestamp,
542
551
  alerts: [],
543
552
  };
544
553
  }, [driver]);
@@ -622,7 +631,6 @@ export function useTrackingAlerts() {
622
631
  type: 'delay',
623
632
  severity: 'medium',
624
633
  message: `${alert.shipmentNumber}: ${alert.message}`,
625
- timestamp: new Date(),
626
634
  acknowledged: false,
627
635
  }))
628
636
  );
@@ -333,10 +333,16 @@ function customerToForm(customer: {
333
333
  phone: string;
334
334
  company?: string;
335
335
  type: 'b2b' | 'b2c';
336
- address: { street: string; city: string; state: string; postalCode: string; country: string };
336
+ address: Partial<{
337
+ street: string;
338
+ city: string;
339
+ state: string;
340
+ postalCode: string;
341
+ country: string;
342
+ }>;
337
343
  businessLicense?: string;
338
344
  taxId?: string;
339
- rating: number;
345
+ rating?: number;
340
346
  }): CustomerFormState {
341
347
  return {
342
348
  name: customer.name,
@@ -344,11 +350,11 @@ function customerToForm(customer: {
344
350
  phone: customer.phone,
345
351
  company: customer.company ?? '',
346
352
  type: customer.type,
347
- street: customer.address.street,
348
- city: customer.address.city,
349
- state: customer.address.state,
350
- postalCode: customer.address.postalCode,
351
- country: customer.address.country,
353
+ street: customer.address.street ?? '',
354
+ city: customer.address.city ?? '',
355
+ state: customer.address.state ?? '',
356
+ postalCode: customer.address.postalCode ?? '',
357
+ country: customer.address.country ?? '',
352
358
  businessLicense: customer.businessLicense ?? '',
353
359
  taxId: customer.taxId ?? '',
354
360
  rating: customer.rating ? String(customer.rating) : '',
@@ -480,7 +486,7 @@ export default function CustomerDetailsPage() {
480
486
  headerContent={
481
487
  <div className="flex items-center gap-4">
482
488
  <TypeBadge type={customer.type} />
483
- {customer.rating > 0 && (
489
+ {customer.rating !== undefined && (
484
490
  <div className="flex items-center gap-1">
485
491
  <Star size={16} className="text-status-warning-text fill-current" />
486
492
  <span className="font-medium">{customer.rating.toFixed(1)}</span>
@@ -65,7 +65,10 @@ export default function CustomersPage() {
65
65
  {
66
66
  id: 'location',
67
67
  header: 'Location',
68
- cell: (row) => `${row.address.city}, ${row.address.state}`,
68
+ cell: (row) => {
69
+ const location = [row.address.city, row.address.state].filter(Boolean).join(', ');
70
+ return location || 'Not provided';
71
+ },
69
72
  },
70
73
  {
71
74
  id: 'rating',
@@ -73,7 +76,7 @@ export default function CustomersPage() {
73
76
  cell: (row) => (
74
77
  <div className="flex items-center gap-1">
75
78
  <Star size={14} className="text-status-warning-text fill-current" />
76
- <span>{row.rating.toFixed(1)}</span>
79
+ <span>{row.rating !== undefined ? row.rating.toFixed(1) : 'Not provided'}</span>
77
80
  </div>
78
81
  ),
79
82
  },
@@ -277,7 +277,9 @@ export default function DashboardPage() {
277
277
  >
278
278
  <p className="font-medium">{alert.message}</p>
279
279
  <p className="mt-1 text-xs text-text-secondary">
280
- {formatDate(alert.timestamp, 'relative')}
280
+ {alert.timestamp
281
+ ? formatDate(alert.timestamp, 'relative')
282
+ : 'Time not recorded'}
281
283
  </p>
282
284
  </div>
283
285
  ))}
@@ -53,6 +53,7 @@ import {
53
53
  useVehicle,
54
54
  useVehicles,
55
55
  toApiDriverStatus,
56
+ type CreateDriverInput,
56
57
  type UpdateDriverInput,
57
58
  } from '../hooks/useFleet';
58
59
  import { useDebouncedValue } from '../hooks/useDebouncedValue';
@@ -85,6 +86,7 @@ interface DriverFormState {
85
86
  licenseExpiry: string;
86
87
  status: DriverStatus;
87
88
  vehicleId: string;
89
+ vehicleIds: string[];
88
90
  rating: string;
89
91
  notes: string;
90
92
  hireDate: string;
@@ -105,6 +107,7 @@ const emptyForm: DriverFormState = {
105
107
  licenseExpiry: '',
106
108
  status: 'available',
107
109
  vehicleId: '',
110
+ vehicleIds: [],
108
111
  rating: '',
109
112
  notes: '',
110
113
  hireDate: '',
@@ -151,6 +154,7 @@ function NewDriverForm({ editId }: { editId?: string }) {
151
154
  licenseExpiry: toDateInput(driver.licenseExpiry),
152
155
  status: driver.status,
153
156
  vehicleId: driver.assignedVehicle || '',
157
+ vehicleIds: driver.vehicleIds,
154
158
  rating: driver.rating ? String(driver.rating) : '',
155
159
  notes: driver.notes || '',
156
160
  hireDate: toDateInput(driver.hireDate),
@@ -163,8 +167,7 @@ function NewDriverForm({ editId }: { editId?: string }) {
163
167
 
164
168
  const goBack = () => navigate?.(joinPath(basePath, 'fleet/drivers'));
165
169
 
166
- const buildPayload = (): UpdateDriverInput => ({
167
- employeeId: form.employeeId.trim(),
170
+ const buildPayload = (includeLeaveFields = true): UpdateDriverInput => ({
168
171
  firstName: form.firstName.trim(),
169
172
  lastName: form.lastName.trim(),
170
173
  email: form.email.trim() || undefined,
@@ -173,13 +176,20 @@ function NewDriverForm({ editId }: { editId?: string }) {
173
176
  licenseClass: form.licenseClass.trim() || undefined,
174
177
  licenseExpiry: fromDateInput(form.licenseExpiry),
175
178
  status: toApiDriverStatus(form.status),
176
- vehicleId: form.vehicleId || undefined,
177
- rating: form.rating ? Number(form.rating) : undefined,
179
+ vehicleId: form.vehicleId || null,
180
+ vehicleIds: form.vehicleIds,
181
+ rating: form.rating.trim() ? Number(form.rating) : undefined,
178
182
  notes: form.notes.trim() || undefined,
179
183
  hireDate: fromDateInput(form.hireDate),
180
- baseSalary: form.baseSalary ? Number(form.baseSalary) : undefined,
181
- bonusYtd: form.bonusYtd ? Number(form.bonusYtd) : undefined,
184
+ baseSalary: form.baseSalary.trim() ? Number(form.baseSalary) : undefined,
185
+ bonusYtd: form.bonusYtd.trim() ? Number(form.bonusYtd) : undefined,
182
186
  payCurrency: form.payCurrency.trim() || undefined,
187
+ ...(includeLeaveFields ? { onLeaveUntil: fromDateInput(form.onLeaveUntil) ?? null } : {}),
188
+ });
189
+
190
+ const buildCreatePayload = (): CreateDriverInput => ({
191
+ employeeId: form.employeeId.trim(),
192
+ ...buildPayload(false),
183
193
  });
184
194
 
185
195
  const handleSubmit = async (e: React.FormEvent) => {
@@ -199,7 +209,7 @@ function NewDriverForm({ editId }: { editId?: string }) {
199
209
  const updated = await updateDriver(editId, buildPayload());
200
210
  navigate?.(joinPath(basePath, `fleet/drivers/${updated.id}`));
201
211
  } else {
202
- const created = await createDriver(buildPayload());
212
+ const created = await createDriver(buildCreatePayload());
203
213
  navigate?.(joinPath(basePath, `fleet/drivers/${created.id}`));
204
214
  }
205
215
  } catch (err) {
@@ -280,7 +290,8 @@ function NewDriverForm({ editId }: { editId?: string }) {
280
290
  <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
281
291
  <div className="space-y-2">
282
292
  <Label htmlFor="employeeId">
283
- Employee ID <span className="text-status-error-text">*</span>
293
+ Employee ID {isEditing ? '(immutable)' : ''}{' '}
294
+ <span className="text-status-error-text">{!isEditing && '*'}</span>
284
295
  </Label>
285
296
  <Input
286
297
  id="employeeId"
@@ -288,6 +299,7 @@ function NewDriverForm({ editId }: { editId?: string }) {
288
299
  onChange={(e) => setForm((prev) => ({ ...prev, employeeId: e.target.value }))}
289
300
  placeholder="EMP-001"
290
301
  required
302
+ disabled={isEditing}
291
303
  />
292
304
  </div>
293
305
  <div className="space-y-2">
@@ -403,7 +415,13 @@ function NewDriverForm({ editId }: { editId?: string }) {
403
415
  <EntityCombobox
404
416
  id="vehicle"
405
417
  value={form.vehicleId}
406
- onChange={(value) => setForm((prev) => ({ ...prev, vehicleId: value }))}
418
+ onChange={(value) =>
419
+ setForm((prev) => ({
420
+ ...prev,
421
+ vehicleId: value,
422
+ vehicleIds: value ? [value] : [],
423
+ }))
424
+ }
407
425
  options={vehicles}
408
426
  loading={vehiclesLoading}
409
427
  getId={(vehicle) => vehicle.id}
@@ -445,7 +463,19 @@ function NewDriverForm({ editId }: { editId?: string }) {
445
463
  />
446
464
  </div>
447
465
  <div className="space-y-2">
448
- <Label htmlFor="onLeaveUntil">On Leave Until</Label>
466
+ <div className="flex items-center justify-between gap-2">
467
+ <Label htmlFor="onLeaveUntil">On Leave Until</Label>
468
+ {form.onLeaveUntil && (
469
+ <Button
470
+ type="button"
471
+ variant="ghost"
472
+ size="sm"
473
+ onClick={() => setForm((prev) => ({ ...prev, onLeaveUntil: '' }))}
474
+ >
475
+ Clear
476
+ </Button>
477
+ )}
478
+ </div>
449
479
  <Input
450
480
  id="onLeaveUntil"
451
481
  type="date"
@@ -641,7 +671,7 @@ export default function DriverDetailsPage() {
641
671
  customColors={{ bg: 'bg-status-warning-bg-subtle', text: 'text-status-warning-text' }}
642
672
  />
643
673
  )}
644
- {driver.rating > 0 && (
674
+ {driver.rating !== undefined && (
645
675
  <div className="flex items-center gap-1">
646
676
  <Star size={16} className="text-status-warning-text fill-current" />
647
677
  <span className="font-medium">{driver.rating.toFixed(1)}</span>
@@ -823,7 +853,9 @@ export default function DriverDetailsPage() {
823
853
  {driver.currentLocation.address || 'Location updating...'}
824
854
  </p>
825
855
  <p className="text-xs text-text-secondary mt-1">
826
- Updated {formatDate(driver.currentLocation.timestamp || new Date(), 'relative')}
856
+ {driver.currentLocation.timestamp
857
+ ? `Updated ${formatDate(driver.currentLocation.timestamp, 'relative')}`
858
+ : 'Update time not recorded'}
827
859
  </p>
828
860
  </CardContent>
829
861
  </Card>
@@ -170,7 +170,7 @@ export default function DriversPage() {
170
170
  id: 'rating',
171
171
  header: 'Rating',
172
172
  cell: (row) =>
173
- row.rating > 0 ? (
173
+ row.rating !== undefined ? (
174
174
  <div className="flex items-center gap-1">
175
175
  <Star size={14} className="text-status-warning-text fill-current" />
176
176
  <span className="font-medium">{row.rating.toFixed(1)}</span>
@@ -308,7 +308,7 @@ export default function FleetPage() {
308
308
  </div>
309
309
  <div className="text-right">
310
310
  <StatusBadge status={driver.status} type="driver" size="sm" />
311
- {driver.rating > 0 && (
311
+ {driver.rating !== undefined && (
312
312
  <div className="mt-1 flex items-center gap-1 justify-end">
313
313
  <Star size={12} className="text-status-warning-text fill-current" />
314
314
  <span className="text-sm font-medium">{driver.rating.toFixed(1)}</span>
@@ -502,32 +502,32 @@ export default function InventoryPage() {
502
502
  <div>
503
503
  <p className="font-medium">{warehouse.name}</p>
504
504
  <p className="text-sm text-text-secondary">
505
- {warehouse.address.city}, {warehouse.address.state}
505
+ {[warehouse.address.city, warehouse.address.state]
506
+ .filter(Boolean)
507
+ .join(', ') || 'Not provided'}
506
508
  </p>
507
509
  </div>
508
510
  <div className="text-right">
509
511
  <Badge
510
512
  variant={
511
- warehouse.status.toUpperCase() === 'ACTIVE' ? 'default' : 'secondary'
513
+ warehouse.status?.toUpperCase() === 'ACTIVE' ? 'default' : 'secondary'
512
514
  }
513
515
  >
514
- {warehouse.status.toUpperCase() === 'ACTIVE'
515
- ? t('movethewheels.inventory.warehouses.active', 'Active')
516
- : t('movethewheels.inventory.warehouses.inactive', 'Inactive')}
516
+ {warehouse.status
517
+ ? warehouse.status.toUpperCase() === 'ACTIVE'
518
+ ? t('movethewheels.inventory.warehouses.active', 'Active')
519
+ : t('movethewheels.inventory.warehouses.inactive', 'Inactive')
520
+ : 'Not provided'}
517
521
  </Badge>
518
522
  <div className="mt-2">
519
523
  <p className="text-xs text-text-secondary">
520
524
  {t('movethewheels.inventory.warehouses.utilization', 'Utilization')}
521
525
  </p>
522
- <Progress
523
- value={
524
- warehouse.capacity.totalSpace > 0
525
- ? (warehouse.capacity.usedSpace / warehouse.capacity.totalSpace) *
526
- 100
527
- : 0
528
- }
529
- className="w-24 h-2"
530
- />
526
+ {warehouse.utilization !== undefined ? (
527
+ <Progress value={warehouse.utilization} className="w-24 h-2" />
528
+ ) : (
529
+ <p className="text-xs text-text-tertiary">Not provided</p>
530
+ )}
531
531
  </div>
532
532
  </div>
533
533
  </div>
@@ -567,8 +567,12 @@ export default function InventoryPage() {
567
567
  <p className="text-sm text-text-secondary">{product.sku}</p>
568
568
  </div>
569
569
  <div className="text-right">
570
- <p className="font-medium">{formatCurrency(product.value)}</p>
571
- <Badge variant="outline">{product.category}</Badge>
570
+ <p className="font-medium">
571
+ {product.value !== undefined
572
+ ? formatCurrency(product.value)
573
+ : 'Not provided'}
574
+ </p>
575
+ <Badge variant="outline">{product.category ?? 'Not provided'}</Badge>
572
576
  </div>
573
577
  </div>
574
578
  </div>
@@ -83,7 +83,7 @@ export default function LiveTrackingPage() {
83
83
  sublabel:
84
84
  d.driver?.fullName ||
85
85
  d.vehicle?.vehicleNumber ||
86
- d.tracking?.currentLocation.address ||
86
+ d.tracking?.currentLocation?.address ||
87
87
  undefined,
88
88
  },
89
89
  ];
@@ -292,7 +292,7 @@ export default function LiveTrackingPage() {
292
292
  : 'N/A'}
293
293
  </p>
294
294
  <p className="text-xs text-text-secondary">
295
- {delivery.tracking?.currentLocation.address ||
295
+ {delivery.tracking?.currentLocation?.address ||
296
296
  'Location updating...'}
297
297
  </p>
298
298
  </div>
@@ -352,7 +352,7 @@ export default function LiveTrackingPage() {
352
352
  <div>
353
353
  <p className="text-sm text-text-secondary">Current Location</p>
354
354
  <p className="text-sm">
355
- {selected.tracking?.currentLocation.address || 'Updating...'}
355
+ {selected.tracking?.currentLocation?.address || 'Updating...'}
356
356
  </p>
357
357
  {(() => {
358
358
  const coord = firstRealLatLng(
@@ -440,7 +440,9 @@ export default function LiveTrackingPage() {
440
440
  >
441
441
  <p className="font-medium">{alert.message}</p>
442
442
  <p className="text-xs text-text-secondary mt-1">
443
- {formatDate(alert.timestamp, 'relative')}
443
+ {alert.timestamp
444
+ ? formatDate(alert.timestamp, 'relative')
445
+ : 'Time not recorded'}
444
446
  </p>
445
447
  </div>
446
448
  ))}