@burdenoff/microfe-movethewheels 2026.924.2 → 2026.925.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.
Files changed (47) hide show
  1. package/dist/components/OrderItemRow.js +195 -109
  2. package/dist/components/StatusBadge.js +31 -31
  3. package/dist/constants/index.js +11 -3
  4. package/dist/generated/wspace-operations.d.ts +7 -0
  5. package/dist/hooks/useFleet.js +85 -76
  6. package/dist/hooks/useOrders.js +8 -4
  7. package/dist/hooks/useTracking.js +127 -66
  8. package/dist/movethewheels/components/OrderItemRow.d.ts +1 -2
  9. package/dist/movethewheels/components/StatusBadge.d.ts +3 -1
  10. package/dist/movethewheels/constants/index.d.ts +1 -0
  11. package/dist/movethewheels/hooks/useFleet.d.ts +41 -1
  12. package/dist/movethewheels/hooks/useOrders.d.ts +1 -0
  13. package/dist/movethewheels/hooks/useTracking.d.ts +2 -2
  14. package/dist/movethewheels/types/index.d.ts +17 -39
  15. package/dist/node_modules/lucide-react/dist/esm/icons/sticky-note.js +11 -0
  16. package/dist/node_modules/lucide-react/dist/esm/icons/user-x.js +30 -0
  17. package/dist/pages/CreateOrderPage.js +597 -420
  18. package/dist/pages/DriverDetailsPage.js +702 -421
  19. package/dist/pages/DriversPage.js +106 -117
  20. package/dist/pages/FleetPage.js +4 -10
  21. package/dist/pages/OrderDetailsPage.js +290 -262
  22. package/dist/pages/OrdersListPage.js +4 -0
  23. package/dist/pages/RouteDetailsPage.js +264 -252
  24. package/dist/pages/TrackingPage.js +205 -195
  25. package/dist/pages/VehicleDetailsPage.js +403 -243
  26. package/dist/utils/mapMarkers.js +2 -1
  27. package/package.json +1 -1
  28. package/src/generated/wspace-operations.ts +10 -3
  29. package/src/movethewheels/components/OrderItemRow.tsx +162 -99
  30. package/src/movethewheels/components/StatusBadge.tsx +11 -2
  31. package/src/movethewheels/constants/index.ts +13 -0
  32. package/src/movethewheels/hooks/useFleet.ts +163 -44
  33. package/src/movethewheels/hooks/useOrders.ts +17 -3
  34. package/src/movethewheels/hooks/useTracking.ts +208 -27
  35. package/src/movethewheels/pages/CreateOrderPage.tsx +372 -263
  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 +7 -10
  39. package/src/movethewheels/pages/OrderDetailsPage.tsx +67 -30
  40. package/src/movethewheels/pages/OrdersListPage.tsx +1 -0
  41. package/src/movethewheels/pages/RouteDetailsPage.tsx +15 -7
  42. package/src/movethewheels/pages/TrackingPage.tsx +44 -14
  43. package/src/movethewheels/pages/VehicleDetailsPage.tsx +137 -15
  44. package/src/movethewheels/types/index.ts +17 -38
  45. package/src/movethewheels/utils/mapMarkers.ts +1 -0
  46. package/src/operations/wspace/movethewheels/queries/dashboard.graphql +5 -0
  47. package/src/operations/wspace/movethewheels/queries/logistics.graphql +2 -2
@@ -15,6 +15,13 @@ export interface CreateVehicleInput {
15
15
  make?: string;
16
16
  model?: string;
17
17
  licensePlate?: string;
18
+ /** Free-text, e.g. "owned", "leased". */
19
+ ownershipType?: string;
20
+ year?: number;
21
+ /** VehicleStatus enum value, e.g. `ACTIVE`, `MAINTENANCE`. */
22
+ status?: string;
23
+ fuelType?: string;
24
+ fuelEfficiencyLPer100Km?: number;
18
25
  }
19
26
 
20
27
  export interface CreateDriverInput {
@@ -24,6 +31,24 @@ export interface CreateDriverInput {
24
31
  email?: string;
25
32
  phone?: string;
26
33
  licenseNumber?: string;
34
+ licenseClass?: string;
35
+ licenseExpiry?: string;
36
+ /** DriverStatus enum value, e.g. `AVAILABLE`, `OFF_DUTY`. */
37
+ status?: string;
38
+ vehicleId?: string;
39
+ rating?: number;
40
+ notes?: string;
41
+ hireDate?: string;
42
+ baseSalary?: number;
43
+ bonusYtd?: number;
44
+ payCurrency?: string;
45
+ }
46
+
47
+ /** Superset of `CreateDriverInput` with fields that only make sense on an existing driver. */
48
+ export interface UpdateDriverInput extends CreateDriverInput {
49
+ onLeaveUntil?: string | null;
50
+ terminatedAt?: string;
51
+ terminationReason?: string;
27
52
  }
28
53
 
29
54
  interface UseFleetResult {
@@ -37,7 +62,7 @@ interface UseFleetResult {
37
62
  createVehicle: (input: CreateVehicleInput) => Promise<Vehicle>;
38
63
  createDriver: (input: CreateDriverInput) => Promise<Driver>;
39
64
  updateVehicle: (id: string, input: CreateVehicleInput) => Promise<Vehicle>;
40
- updateDriver: (id: string, input: CreateDriverInput) => Promise<Driver>;
65
+ updateDriver: (id: string, input: UpdateDriverInput) => Promise<Driver>;
41
66
  }
42
67
 
43
68
  export interface ApiVehicle {
@@ -52,6 +77,8 @@ export interface ApiVehicle {
52
77
  capacity?: Record<string, unknown> | null;
53
78
  status: string;
54
79
  currentLocation?: Record<string, unknown> | null;
80
+ fuelType?: string | null;
81
+ fuelEfficiencyLPer100Km?: number | null;
55
82
  fuelLevel?: number | null;
56
83
  mileage?: number | null;
57
84
  lastServiceDate?: string | null;
@@ -76,6 +103,14 @@ export interface ApiDriver {
76
103
  currentLocation?: Record<string, unknown> | null;
77
104
  rating?: number | null;
78
105
  vehicleId?: string | null;
106
+ notes?: string | null;
107
+ hireDate?: string | null;
108
+ baseSalary?: number | null;
109
+ bonusYtd?: number | null;
110
+ payCurrency?: string | null;
111
+ onLeaveUntil?: string | null;
112
+ terminatedAt?: string | null;
113
+ terminationReason?: string | null;
79
114
  createdAt: string;
80
115
  }
81
116
 
@@ -93,6 +128,8 @@ const LIST_VEHICLES_QUERY = `
93
128
  capacity
94
129
  status
95
130
  currentLocation
131
+ fuelType
132
+ fuelEfficiencyLPer100Km
96
133
  fuelLevel
97
134
  mileage
98
135
  lastServiceDate
@@ -122,6 +159,14 @@ const LIST_DRIVERS_QUERY = `
122
159
  currentLocation
123
160
  rating
124
161
  vehicleId
162
+ notes
163
+ hireDate
164
+ baseSalary
165
+ bonusYtd
166
+ payCurrency
167
+ onLeaveUntil
168
+ terminatedAt
169
+ terminationReason
125
170
  createdAt
126
171
  }
127
172
  driversCount(filter: $filter)
@@ -142,6 +187,8 @@ const GET_VEHICLE_QUERY = `
142
187
  capacity
143
188
  status
144
189
  currentLocation
190
+ fuelType
191
+ fuelEfficiencyLPer100Km
145
192
  fuelLevel
146
193
  mileage
147
194
  lastServiceDate
@@ -170,6 +217,14 @@ const GET_DRIVER_QUERY = `
170
217
  currentLocation
171
218
  rating
172
219
  vehicleId
220
+ notes
221
+ hireDate
222
+ baseSalary
223
+ bonusYtd
224
+ payCurrency
225
+ onLeaveUntil
226
+ terminatedAt
227
+ terminationReason
173
228
  createdAt
174
229
  }
175
230
  }
@@ -189,6 +244,8 @@ const UPDATE_VEHICLE_STATUS_MUTATION = `
189
244
  capacity
190
245
  status
191
246
  currentLocation
247
+ fuelType
248
+ fuelEfficiencyLPer100Km
192
249
  fuelLevel
193
250
  mileage
194
251
  createdAt
@@ -214,6 +271,14 @@ const ASSIGN_DRIVER_VEHICLE_MUTATION = `
214
271
  currentLocation
215
272
  rating
216
273
  vehicleId
274
+ notes
275
+ hireDate
276
+ baseSalary
277
+ bonusYtd
278
+ payCurrency
279
+ onLeaveUntil
280
+ terminatedAt
281
+ terminationReason
217
282
  createdAt
218
283
  }
219
284
  }
@@ -236,6 +301,14 @@ const UPDATE_DRIVER_STATUS_MUTATION = `
236
301
  currentLocation
237
302
  rating
238
303
  vehicleId
304
+ notes
305
+ hireDate
306
+ baseSalary
307
+ bonusYtd
308
+ payCurrency
309
+ onLeaveUntil
310
+ terminatedAt
311
+ terminationReason
239
312
  createdAt
240
313
  }
241
314
  }
@@ -255,6 +328,8 @@ const CREATE_VEHICLE_MUTATION = `
255
328
  capacity
256
329
  status
257
330
  currentLocation
331
+ fuelType
332
+ fuelEfficiencyLPer100Km
258
333
  fuelLevel
259
334
  mileage
260
335
  createdAt
@@ -280,6 +355,14 @@ const CREATE_DRIVER_MUTATION = `
280
355
  currentLocation
281
356
  rating
282
357
  vehicleId
358
+ notes
359
+ hireDate
360
+ baseSalary
361
+ bonusYtd
362
+ payCurrency
363
+ onLeaveUntil
364
+ terminatedAt
365
+ terminationReason
283
366
  createdAt
284
367
  }
285
368
  }
@@ -299,6 +382,8 @@ const UPDATE_VEHICLE_MUTATION = `
299
382
  capacity
300
383
  status
301
384
  currentLocation
385
+ fuelType
386
+ fuelEfficiencyLPer100Km
302
387
  fuelLevel
303
388
  mileage
304
389
  createdAt
@@ -324,6 +409,14 @@ const UPDATE_DRIVER_MUTATION = `
324
409
  currentLocation
325
410
  rating
326
411
  vehicleId
412
+ notes
413
+ hireDate
414
+ baseSalary
415
+ bonusYtd
416
+ payCurrency
417
+ onLeaveUntil
418
+ terminatedAt
419
+ terminationReason
327
420
  createdAt
328
421
  }
329
422
  }
@@ -372,7 +465,8 @@ function mapVehicleStatus(status: string): VehicleStatus {
372
465
  }
373
466
  }
374
467
 
375
- function toApiVehicleStatus(status: VehicleStatus): string {
468
+ /** Exported so the vehicle edit form's status field can round-trip (BOFF-7909). */
469
+ export function toApiVehicleStatus(status: VehicleStatus): string {
376
470
  switch (status) {
377
471
  case 'available':
378
472
  return 'ACTIVE';
@@ -393,12 +487,15 @@ function mapDriverStatus(status: string): DriverStatus {
393
487
  return 'busy';
394
488
  case 'ON_BREAK':
395
489
  return 'on_break';
490
+ case 'INACTIVE':
491
+ return 'inactive';
396
492
  default:
397
493
  return 'offline';
398
494
  }
399
495
  }
400
496
 
401
- function toApiDriverStatus(status: DriverStatus): string {
497
+ /** Exported so the driver edit form's status field can round-trip losslessly (BOFF-7909). */
498
+ export function toApiDriverStatus(status: DriverStatus): string {
402
499
  switch (status) {
403
500
  case 'available':
404
501
  return 'AVAILABLE';
@@ -406,6 +503,8 @@ function toApiDriverStatus(status: DriverStatus): string {
406
503
  return 'ON_DELIVERY';
407
504
  case 'on_break':
408
505
  return 'ON_BREAK';
506
+ case 'inactive':
507
+ return 'INACTIVE';
409
508
  default:
410
509
  return 'OFF_DUTY';
411
510
  }
@@ -439,6 +538,8 @@ export function mapVehicle(vehicle: ApiVehicle): Vehicle {
439
538
  lastMaintenance: vehicle.lastServiceDate ? new Date(vehicle.lastServiceDate) : undefined,
440
539
  nextMaintenance: vehicle.nextServiceDueDate ? new Date(vehicle.nextServiceDueDate) : undefined,
441
540
  nextMaintenanceMileage: vehicle.nextServiceDueMileage ?? undefined,
541
+ fuelType: vehicle.fuelType ?? undefined,
542
+ fuelEfficiencyLPer100Km: vehicle.fuelEfficiencyLPer100Km ?? undefined,
442
543
  fuelLevel: vehicle.fuelLevel ?? undefined,
443
544
  mileage: vehicle.mileage ?? undefined,
444
545
  documents: [],
@@ -468,44 +569,16 @@ export function mapDriver(driver: ApiDriver): Driver {
468
569
  timestamp: new Date(),
469
570
  }
470
571
  : undefined,
471
- joinDate: new Date(driver.createdAt),
472
- baseSalary: 0,
473
- completedOrders: 0,
474
- todayOrders: 0,
475
- specializations: [],
476
- workingHours: {
477
- startTime: '09:00',
478
- endTime: '18:00',
479
- workingDays: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
480
- maxHoursPerDay: 8,
481
- maxHoursPerWeek: 40,
482
- currentHoursToday: 0,
483
- currentHoursThisWeek: 0,
484
- },
485
- ratings: {
486
- overall: driver.rating ?? 0,
487
- punctuality: driver.rating ?? 0,
488
- communication: driver.rating ?? 0,
489
- carefulHandling: driver.rating ?? 0,
490
- professionalism: driver.rating ?? 0,
491
- onTimeDelivery: driver.rating ?? 0,
492
- totalRatings: 0,
493
- },
572
+ rating: driver.rating ?? 0,
573
+ notes: driver.notes ?? undefined,
574
+ hireDate: driver.hireDate ? new Date(driver.hireDate) : undefined,
575
+ baseSalary: driver.baseSalary ?? undefined,
576
+ bonusYtd: driver.bonusYtd ?? undefined,
577
+ payCurrency: driver.payCurrency ?? undefined,
578
+ onLeaveUntil: driver.onLeaveUntil ? new Date(driver.onLeaveUntil) : undefined,
579
+ terminatedAt: driver.terminatedAt ? new Date(driver.terminatedAt) : undefined,
580
+ terminationReason: driver.terminationReason ?? undefined,
494
581
  documents: [],
495
- earnings: {
496
- totalEarnings: 0,
497
- weeklyEarnings: 0,
498
- monthlyEarnings: 0,
499
- pendingPayments: 0,
500
- completedDeliveries: 0,
501
- bonuses: 0,
502
- },
503
- compliance: {
504
- hoursOfService: true,
505
- documentation: true,
506
- vehicleInspection: true,
507
- lastUpdate: new Date(),
508
- },
509
582
  createdAt: new Date(driver.createdAt),
510
583
  };
511
584
  }
@@ -599,6 +672,11 @@ export function useFleet(options: UseFleetOptions = {}): UseFleetResult {
599
672
  make: input.make,
600
673
  model: input.model,
601
674
  licensePlate: input.licensePlate,
675
+ ownershipType: input.ownershipType,
676
+ year: input.year,
677
+ status: input.status,
678
+ fuelType: input.fuelType,
679
+ fuelEfficiencyLPer100Km: input.fuelEfficiencyLPer100Km,
602
680
  },
603
681
  }
604
682
  );
@@ -622,6 +700,16 @@ export function useFleet(options: UseFleetOptions = {}): UseFleetResult {
622
700
  email: input.email,
623
701
  phone: input.phone,
624
702
  licenseNumber: input.licenseNumber,
703
+ licenseClass: input.licenseClass,
704
+ licenseExpiry: input.licenseExpiry,
705
+ status: input.status,
706
+ vehicleId: input.vehicleId,
707
+ rating: input.rating,
708
+ notes: input.notes,
709
+ hireDate: input.hireDate,
710
+ baseSalary: input.baseSalary,
711
+ bonusYtd: input.bonusYtd,
712
+ payCurrency: input.payCurrency,
625
713
  },
626
714
  }
627
715
  );
@@ -645,6 +733,11 @@ export function useFleet(options: UseFleetOptions = {}): UseFleetResult {
645
733
  make: input.make,
646
734
  model: input.model,
647
735
  licensePlate: input.licensePlate,
736
+ ownershipType: input.ownershipType,
737
+ year: input.year,
738
+ status: input.status,
739
+ fuelType: input.fuelType,
740
+ fuelEfficiencyLPer100Km: input.fuelEfficiencyLPer100Km,
648
741
  },
649
742
  }
650
743
  );
@@ -656,7 +749,7 @@ export function useFleet(options: UseFleetOptions = {}): UseFleetResult {
656
749
  );
657
750
 
658
751
  const updateDriver = useCallback(
659
- async (id: string, input: CreateDriverInput): Promise<Driver> => {
752
+ async (id: string, input: UpdateDriverInput): Promise<Driver> => {
660
753
  const data = await executeGraphQL<{ updateDriver: ApiDriver }>(
661
754
  graphQLOptions,
662
755
  UPDATE_DRIVER_MUTATION,
@@ -668,6 +761,19 @@ export function useFleet(options: UseFleetOptions = {}): UseFleetResult {
668
761
  email: input.email,
669
762
  phone: input.phone,
670
763
  licenseNumber: input.licenseNumber,
764
+ licenseClass: input.licenseClass,
765
+ licenseExpiry: input.licenseExpiry,
766
+ status: input.status,
767
+ vehicleId: input.vehicleId,
768
+ rating: input.rating,
769
+ notes: input.notes,
770
+ hireDate: input.hireDate,
771
+ baseSalary: input.baseSalary,
772
+ bonusYtd: input.bonusYtd,
773
+ payCurrency: input.payCurrency,
774
+ onLeaveUntil: input.onLeaveUntil,
775
+ terminatedAt: input.terminatedAt,
776
+ terminationReason: input.terminationReason,
671
777
  },
672
778
  }
673
779
  );
@@ -704,6 +810,8 @@ interface UseVehiclesOptions extends UseListOptions {
704
810
  vehicleType?: Vehicle['type'];
705
811
  /** Narrows to vehicles linked to this driver server-side (VehicleFilterInput.driverId). */
706
812
  driverId?: string;
813
+ /** Fetch exactly these vehicles by id, regardless of how many there are. */
814
+ ids?: readonly string[];
707
815
  }
708
816
 
709
817
  interface UseVehiclesResult {
@@ -719,15 +827,25 @@ interface UseVehiclesResult {
719
827
  }
720
828
 
721
829
  export function useVehicles(options: UseVehiclesOptions = {}): UseVehiclesResult {
722
- const { limit = 20, offset = 0, search, status, vehicleType, driverId } = options;
830
+ const { limit = 20, offset = 0, search, status, vehicleType, driverId, ids } = options;
723
831
  const graphQLOptions = useGraphqlOptions();
724
832
  const [vehicles, setVehicles] = useState<Vehicle[]>([]);
725
833
  const [totalVehicles, setTotalVehicles] = useState(0);
726
834
  const [hasMore, setHasMore] = useState(false);
727
835
  const [isLoading, setIsLoading] = useState(false);
728
836
  const [error, setError] = useState<Error | null>(null);
837
+ // Stable dependency key for the `ids` array — a caller passing a fresh array
838
+ // literal each render must not defeat the callback's memoization.
839
+ const idsKey = ids ? [...ids].sort().join(',') : '';
729
840
 
730
841
  const load = useCallback(async () => {
842
+ if (ids && ids.length === 0) {
843
+ // Nothing to look up — skip the request and clear stale results.
844
+ setVehicles([]);
845
+ setTotalVehicles(0);
846
+ setHasMore(false);
847
+ return;
848
+ }
731
849
  setIsLoading(true);
732
850
  setError(null);
733
851
  try {
@@ -740,8 +858,9 @@ export function useVehicles(options: UseVehiclesOptions = {}): UseVehiclesResult
740
858
  status: status ? toApiVehicleStatus(status) : undefined,
741
859
  type: vehicleType?.toUpperCase(),
742
860
  driverId: driverId || undefined,
861
+ ids: ids && ids.length > 0 ? [...ids] : undefined,
743
862
  },
744
- pagination: { limit, offset },
863
+ pagination: { limit: ids && ids.length > 0 ? ids.length : limit, offset: ids ? 0 : offset },
745
864
  });
746
865
  setHasMore(offset + data.vehicles.length < data.vehiclesCount);
747
866
  setTotalVehicles(data.vehiclesCount);
@@ -751,7 +870,7 @@ export function useVehicles(options: UseVehiclesOptions = {}): UseVehiclesResult
751
870
  } finally {
752
871
  setIsLoading(false);
753
872
  }
754
- }, [graphQLOptions, limit, offset, search, status, vehicleType, driverId]);
873
+ }, [graphQLOptions, limit, offset, search, status, vehicleType, driverId, idsKey]);
755
874
 
756
875
  useEffect(() => {
757
876
  void load();
@@ -155,10 +155,14 @@ const ORDER_STATS_QUERY = `
155
155
  deliveryJobStats {
156
156
  total
157
157
  pending
158
+ confirmed
159
+ assigned
158
160
  inTransit
161
+ outForDelivery
159
162
  delivered
160
163
  cancelled
161
164
  failed
165
+ returned
162
166
  }
163
167
  financeMetrics {
164
168
  revenue {
@@ -221,6 +225,8 @@ export function mapOrderStatus(status: string): OrderStatus {
221
225
  return 'out_for_delivery';
222
226
  case 'DELIVERED':
223
227
  return 'delivered';
228
+ case 'RETURNED':
229
+ return 'returned';
224
230
  case 'CANCELLED':
225
231
  return 'cancelled';
226
232
  default:
@@ -263,6 +269,8 @@ function toApiStatus(status: OrderStatus): string {
263
269
  return 'OUT_FOR_DELIVERY';
264
270
  case 'delivered':
265
271
  return 'DELIVERED';
272
+ case 'returned':
273
+ return 'RETURNED';
266
274
  case 'cancelled':
267
275
  return 'CANCELLED';
268
276
  default:
@@ -593,6 +601,7 @@ export function useOrderStats() {
593
601
  in_transit: 0,
594
602
  out_for_delivery: 0,
595
603
  delivered: 0,
604
+ returned: 0,
596
605
  cancelled: 0,
597
606
  failed: 0,
598
607
  },
@@ -621,10 +630,14 @@ export function useOrderStats() {
621
630
  deliveryJobStats: {
622
631
  total: number;
623
632
  pending: number;
633
+ confirmed: number;
634
+ assigned: number;
624
635
  inTransit: number;
636
+ outForDelivery: number;
625
637
  delivered: number;
626
638
  cancelled: number;
627
639
  failed: number;
640
+ returned: number;
628
641
  };
629
642
  financeMetrics: {
630
643
  revenue: {
@@ -638,12 +651,13 @@ export function useOrderStats() {
638
651
  total: data.deliveryJobStats.total,
639
652
  byStatus: {
640
653
  pending: data.deliveryJobStats.pending,
641
- confirmed: 0,
642
- assigned: 0,
654
+ confirmed: data.deliveryJobStats.confirmed,
655
+ assigned: data.deliveryJobStats.assigned,
643
656
  picked_up: 0,
644
657
  in_transit: data.deliveryJobStats.inTransit,
645
- out_for_delivery: 0,
658
+ out_for_delivery: data.deliveryJobStats.outForDelivery,
646
659
  delivered: data.deliveryJobStats.delivered,
660
+ returned: data.deliveryJobStats.returned,
647
661
  cancelled: data.deliveryJobStats.cancelled,
648
662
  failed: data.deliveryJobStats.failed,
649
663
  },