@burdenoff/microfe-movethewheels 2026.925.2 → 2026.929.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 (43) hide show
  1. package/dist/components/StatusBadge.js +34 -31
  2. package/dist/constants/index.js +12 -5
  3. package/dist/hooks/useCustomers.js +0 -3
  4. package/dist/hooks/useFleet.js +148 -135
  5. package/dist/hooks/useInventory.js +146 -146
  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 +1 -0
  9. package/dist/movethewheels/hooks/useFleet.d.ts +17 -4
  10. package/dist/movethewheels/hooks/useInventory.d.ts +11 -0
  11. package/dist/movethewheels/types/index.d.ts +19 -75
  12. package/dist/pages/CustomerDetailsPage.js +666 -344
  13. package/dist/pages/CustomersPage.js +71 -80
  14. package/dist/pages/DriverDetailsPage.js +2 -2
  15. package/dist/pages/DriversPage.js +2 -2
  16. package/dist/pages/FleetPage.js +1 -3
  17. package/dist/pages/InventoryPage.js +5 -5
  18. package/dist/pages/RouteDetailsPage.js +273 -248
  19. package/dist/pages/RoutesPage.js +130 -67
  20. package/dist/pages/VehicleDetailsPage.js +527 -389
  21. package/dist/pages/VehiclesPage.js +120 -71
  22. package/dist/pages/WarehouseDetailsPage.js +411 -368
  23. package/dist/pages/WarehousesPage.js +132 -83
  24. package/package.json +1 -1
  25. package/src/movethewheels/components/StatusBadge.tsx +15 -7
  26. package/src/movethewheels/constants/index.ts +9 -0
  27. package/src/movethewheels/hooks/useCustomers.ts +0 -3
  28. package/src/movethewheels/hooks/useFleet.ts +89 -25
  29. package/src/movethewheels/hooks/useInventory.ts +77 -33
  30. package/src/movethewheels/hooks/useRoutes.ts +17 -12
  31. package/src/movethewheels/pages/CustomerDetailsPage.tsx +376 -109
  32. package/src/movethewheels/pages/CustomersPage.tsx +6 -15
  33. package/src/movethewheels/pages/DriverDetailsPage.tsx +3 -1
  34. package/src/movethewheels/pages/DriversPage.tsx +5 -1
  35. package/src/movethewheels/pages/FleetPage.tsx +2 -1
  36. package/src/movethewheels/pages/InventoryPage.tsx +18 -6
  37. package/src/movethewheels/pages/RouteDetailsPage.tsx +74 -34
  38. package/src/movethewheels/pages/RoutesPage.tsx +66 -2
  39. package/src/movethewheels/pages/VehicleDetailsPage.tsx +185 -23
  40. package/src/movethewheels/pages/VehiclesPage.tsx +72 -5
  41. package/src/movethewheels/pages/WarehouseDetailsPage.tsx +217 -138
  42. package/src/movethewheels/pages/WarehousesPage.tsx +81 -17
  43. package/src/movethewheels/types/index.ts +28 -75
@@ -3,11 +3,22 @@
3
3
  */
4
4
 
5
5
  import { useState } from 'react';
6
- import { Warehouse, Plus, RefreshCw, CircleCheck, Gauge } from 'lucide-react';
6
+ import { Warehouse, Plus, RefreshCw, CircleCheck, Gauge, Filter } from 'lucide-react';
7
7
  import { PageLayout } from '../components/PageLayout';
8
8
  import { MetricCard, MetricGrid } from '../components/MetricCard';
9
9
  import { DataTable, type Column } from '../components/DataTable';
10
- import { Badge, Progress } from '../components/ui';
10
+ import {
11
+ Badge,
12
+ Progress,
13
+ Card,
14
+ CardContent,
15
+ Select,
16
+ SelectContent,
17
+ SelectItem,
18
+ SelectTrigger,
19
+ SelectValue,
20
+ Button,
21
+ } from '../components/ui';
11
22
  import { CTAOverflowMenu, PagePurpose } from '@burdenoff/fe-libs/ui';
12
23
  import { useWarehouses, useWarehouseStats } from '../hooks/useInventory';
13
24
  import { useDebouncedValue } from '../hooks/useDebouncedValue';
@@ -15,17 +26,26 @@ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
15
26
  import { joinPath } from '../utils/navigation';
16
27
  import type { Warehouse as WarehouseType } from '../types';
17
28
 
29
+ const STATUS_OPTIONS = [
30
+ { value: 'all', label: 'All statuses' },
31
+ { value: 'ACTIVE', label: 'Active' },
32
+ { value: 'INACTIVE', label: 'Inactive' },
33
+ ];
34
+
18
35
  export default function WarehousesPage() {
19
36
  const { basePath, navigate } = useMoveTheWheels();
20
37
  const [page, setPage] = useState(0);
21
38
  const [pageSize, setPageSize] = useState(25);
22
39
  const [search, setSearch] = useState('');
40
+ const [statusFilter, setStatusFilter] = useState('all');
23
41
  const debouncedSearch = useDebouncedValue(search);
24
42
  const { warehouses, totalWarehouses, hasMore, isLoading, error, refetch } = useWarehouses({
25
43
  limit: pageSize,
26
44
  offset: page * pageSize,
27
45
  search: debouncedSearch,
46
+ status: statusFilter === 'all' ? undefined : statusFilter,
28
47
  });
48
+ const filtersActive = statusFilter !== 'all' || search.length > 0;
29
49
  // Bounded aggregate for the tiles + subtitle — not the truncated page.
30
50
  const { stats } = useWarehouseStats();
31
51
 
@@ -70,7 +90,10 @@ export default function WarehousesPage() {
70
90
  id: 'utilization',
71
91
  header: 'Utilization',
72
92
  cell: (row) => {
73
- const pct = (row.capacity.usedSpace / row.capacity.totalSpace) * 100;
93
+ const pct =
94
+ row.capacity.totalSpace > 0
95
+ ? (row.capacity.usedSpace / row.capacity.totalSpace) * 100
96
+ : 0;
74
97
  return (
75
98
  <div className="flex items-center gap-2">
76
99
  <Progress value={pct} className="w-16 h-2" />
@@ -83,25 +106,23 @@ export default function WarehousesPage() {
83
106
  id: 'capacity',
84
107
  header: 'Capacity',
85
108
  cell: (row) => (
86
- <div className="text-sm">
87
- <p>
88
- {row.capacity.usedSpace.toLocaleString()} / {row.capacity.totalSpace.toLocaleString()}{' '}
89
- sq ft
90
- </p>
91
- <p className="text-text-secondary">
92
- {row.capacity.usedPallets} / {row.capacity.totalPallets} pallets
93
- </p>
94
- </div>
109
+ <p className="text-sm">
110
+ {row.capacity.usedSpace.toLocaleString()} / {row.capacity.totalSpace.toLocaleString()} sq
111
+ ft
112
+ </p>
95
113
  ),
96
114
  },
97
115
  {
98
116
  id: 'status',
99
117
  header: 'Status',
100
- cell: (row) => (
101
- <Badge variant={row.isActive ? 'default' : 'secondary'}>
102
- {row.isActive ? 'Active' : 'Inactive'}
103
- </Badge>
104
- ),
118
+ cell: (row) => {
119
+ const isActive = row.status.toUpperCase() === 'ACTIVE';
120
+ return (
121
+ <Badge variant={isActive ? 'default' : 'secondary'}>
122
+ {isActive ? 'Active' : 'Inactive'}
123
+ </Badge>
124
+ );
125
+ },
105
126
  },
106
127
  ];
107
128
 
@@ -152,6 +173,49 @@ export default function WarehousesPage() {
152
173
  </MetricGrid>
153
174
  </div>
154
175
 
176
+ {/* Filters */}
177
+ <Card>
178
+ <CardContent className="p-4">
179
+ <div className="flex flex-wrap items-center gap-4">
180
+ <div className="flex items-center gap-2">
181
+ <Filter size={16} className="text-text-secondary" />
182
+ <span className="text-sm font-medium">Filters:</span>
183
+ </div>
184
+ <Select
185
+ value={statusFilter}
186
+ onValueChange={(value) => {
187
+ setStatusFilter(value);
188
+ setPage(0);
189
+ }}
190
+ >
191
+ <SelectTrigger className="w-[180px]">
192
+ <SelectValue placeholder="Status" />
193
+ </SelectTrigger>
194
+ <SelectContent>
195
+ {STATUS_OPTIONS.map((option) => (
196
+ <SelectItem key={option.value} value={option.value}>
197
+ {option.label}
198
+ </SelectItem>
199
+ ))}
200
+ </SelectContent>
201
+ </Select>
202
+ {filtersActive && (
203
+ <Button
204
+ variant="ghost"
205
+ size="sm"
206
+ onClick={() => {
207
+ setStatusFilter('all');
208
+ setSearch('');
209
+ setPage(0);
210
+ }}
211
+ >
212
+ Clear filters
213
+ </Button>
214
+ )}
215
+ </div>
216
+ </CardContent>
217
+ </Card>
218
+
155
219
  <DataTable
156
220
  columns={columns}
157
221
  data={warehouses}
@@ -171,11 +171,6 @@ export interface Customer {
171
171
  address: Address;
172
172
  businessLicense?: string;
173
173
  taxId?: string;
174
- website?: string;
175
- preferredContactMethod: 'email' | 'phone' | 'both';
176
- marketingOptIn: boolean;
177
- notes?: string;
178
- isActive: boolean;
179
174
  rating: number;
180
175
  createdAt: Date;
181
176
  updatedAt: Date;
@@ -313,8 +308,18 @@ export interface ProofOfDelivery {
313
308
  }
314
309
 
315
310
  // Vehicle type
316
- export type VehicleType = 'van' | 'truck' | 'motorcycle' | 'bicycle' | 'car';
317
- export type VehicleStatus = 'available' | 'assigned' | 'maintenance' | 'out_of_service';
311
+ export type VehicleType =
312
+ | 'van'
313
+ | 'truck'
314
+ | 'motorcycle'
315
+ | 'bicycle'
316
+ | 'flatbed'
317
+ | 'refrigerated'
318
+ | 'semi_trailer'
319
+ | 'drone';
320
+ export type VehicleFuelType = 'DIESEL' | 'PETROL' | 'CNG' | 'ELECTRIC' | 'HYBRID';
321
+ export type VehicleStatus =
322
+ 'available' | 'assigned' | 'maintenance' | 'out_of_service' | 'decommissioned';
318
323
 
319
324
  export interface VehicleDocument {
320
325
  id: string;
@@ -333,10 +338,10 @@ export interface Vehicle {
333
338
  licensePlate: string;
334
339
  /** MtwVehicle.ownershipType — free-text, e.g. "owned", "leased". */
335
340
  ownershipType?: string;
336
- year: number;
341
+ year?: number;
337
342
  capacity: {
338
- weight: number;
339
- volume: number;
343
+ weight?: number;
344
+ volume?: number;
340
345
  pallets?: number;
341
346
  };
342
347
  status: VehicleStatus;
@@ -346,7 +351,7 @@ export interface Vehicle {
346
351
  nextMaintenance?: Date;
347
352
  /** Odometer reading (km) at which the next service is due. */
348
353
  nextMaintenanceMileage?: number;
349
- fuelType?: string;
354
+ fuelType?: VehicleFuelType;
350
355
  /** Fuel consumption, litres per 100km. */
351
356
  fuelEfficiencyLPer100Km?: number;
352
357
  fuelLevel?: number;
@@ -375,7 +380,7 @@ export interface Driver {
375
380
  employeeId: string;
376
381
  licenseNumber: string;
377
382
  licenseType: string;
378
- licenseExpiry: Date;
383
+ licenseExpiry?: Date;
379
384
  vehicleIds: string[];
380
385
  assignedVehicle?: string;
381
386
  status: DriverStatus;
@@ -396,44 +401,18 @@ export interface Driver {
396
401
  createdAt: Date;
397
402
  }
398
403
 
399
- // Warehouse zone type
400
- export interface WarehouseZone {
401
- id: string;
402
- name: string;
403
- type: 'receiving' | 'storage' | 'picking' | 'packing' | 'shipping';
404
- location: string;
405
- capacity: number;
406
- currentOccupancy: number;
407
- }
408
-
409
- // Warehouse equipment type
410
- export interface WarehouseEquipment {
411
- id: string;
412
- type: string;
413
- model: string;
414
- status: 'operational' | 'maintenance' | 'out_of_service';
415
- lastMaintenance: Date;
416
- nextMaintenance: Date;
417
- }
418
-
419
404
  // Warehouse type
420
405
  export interface Warehouse {
421
406
  id: string;
422
407
  name: string;
423
408
  code: string;
424
409
  address: Address;
425
- type: 'distribution' | 'fulfillment' | 'cold_storage' | 'cross_dock';
410
+ type: 'distribution' | 'fulfillment' | 'cold_storage' | 'cross_dock' | 'retail';
411
+ /** Raw backend value (free-text, e.g. "ACTIVE"/"INACTIVE" — defaults to ACTIVE). */
412
+ status: string;
426
413
  capacity: {
427
414
  totalSpace: number;
428
415
  usedSpace: number;
429
- totalPallets: number;
430
- usedPallets: number;
431
- specialAreas: Array<{
432
- type: string;
433
- capacity: number;
434
- currentUsage: number;
435
- temperature?: { min: number; max: number; unit: string };
436
- }>;
437
416
  };
438
417
  operatingHours: Record<
439
418
  string,
@@ -442,28 +421,12 @@ export interface Warehouse {
442
421
  close: string;
443
422
  } | null
444
423
  >;
445
- contacts: Array<{
446
- primaryEmail: string;
447
- primaryPhone: string;
448
- }>;
449
- zones: WarehouseZone[];
450
- equipment: WarehouseEquipment[];
451
- staff: Array<{
452
- userId: string;
453
- role: string;
454
- shift: string;
455
- permissions: string[];
456
- }>;
457
- metrics: {
458
- throughput: number;
459
- accuracy: number;
460
- productivity: number;
461
- utilization: number;
462
- ordersFulfilled: number;
463
- averageProcessingTime: number;
464
- lastUpdated: Date;
424
+ contactInfo?: {
425
+ email?: string;
426
+ phone?: string;
465
427
  };
466
- isActive: boolean;
428
+ /** Real computed value: usedSpace / totalSpace. No other backend metrics exist for a warehouse. */
429
+ utilization: number;
467
430
  createdAt: Date;
468
431
  }
469
432
 
@@ -487,20 +450,13 @@ export interface Inventory {
487
450
  productSku?: string;
488
451
  warehouseId: string;
489
452
  warehouseName?: string;
490
- zoneId: string;
491
453
  quantity: number;
492
454
  reservedQuantity: number;
493
455
  availableQuantity: number;
494
- reorderLevel: number;
495
- maxLevel: number;
456
+ damagedQuantity: number;
457
+ /** Undefined means no reorder point is configured — never treat as 0 (matches the backend's low-stock rule, which requires one to be set). */
458
+ reorderLevel?: number;
496
459
  lastRestocked: Date;
497
- location: {
498
- aisle: string;
499
- shelf: string;
500
- position: string;
501
- level: number;
502
- };
503
- movements: InventoryMovement[];
504
460
  createdAt: Date;
505
461
  updatedAt: Date;
506
462
  }
@@ -540,10 +496,7 @@ export interface Route {
540
496
  /** Estimated fuel cost for the route (svc MtwRoute.fuelCost). */
541
497
  fuelCost?: number;
542
498
  actualDuration?: number;
543
- startTime?: Date;
544
- endTime?: Date;
545
499
  optimized: boolean;
546
- trafficConditions: TrafficCondition[];
547
500
  createdAt: Date;
548
501
  }
549
502