@burdenoff/microfe-movethewheels 2026.510.105

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 (208) hide show
  1. package/README.md +82 -0
  2. package/dist/AIAssistantPage-hD0VYJdH.js +210 -0
  3. package/dist/AnalyticsPage-DHTHCUtr.js +201 -0
  4. package/dist/CreateOrderPage-Cprg4Y9V.js +471 -0
  5. package/dist/CustomerDetailsPage-DNDEw7IW.js +239 -0
  6. package/dist/CustomersPage-CDjjeCEL.js +119 -0
  7. package/dist/DashboardPage-8iTPXRAG.js +374 -0
  8. package/dist/DataTable-CRIKfdIN.js +239 -0
  9. package/dist/DriverDetailsPage-CRyRCno7.js +297 -0
  10. package/dist/DriversPage-16O8fVmf.js +127 -0
  11. package/dist/FinancePage-BYUxK5dR.js +154 -0
  12. package/dist/FleetPage-CHYETCWT.js +293 -0
  13. package/dist/ImportExportPage-C3MKKxfc.js +232 -0
  14. package/dist/InventoryPage--822AxZM.js +223 -0
  15. package/dist/LiveTrackingPage-Dp3rTJDr.js +332 -0
  16. package/dist/MarketplacePage-DjEqudfM.js +192 -0
  17. package/dist/MetricCard-GTbxAk1a.js +135 -0
  18. package/dist/OrderDetailsPage-BIuYG0ub.js +398 -0
  19. package/dist/OrdersListPage-CW5V0Uvh.js +257 -0
  20. package/dist/PageLayout-B7b0vl0R.js +1894 -0
  21. package/dist/ProductDetailsPage-Q3X7AT-7.js +168 -0
  22. package/dist/ProductsPage-CUj9JpnW.js +131 -0
  23. package/dist/ReportsPage-DblO5CdJ.js +227 -0
  24. package/dist/RouteDetailsPage-CLctgk6A.js +240 -0
  25. package/dist/RoutesPage-8hrv6RWT.js +116 -0
  26. package/dist/SettingsPage-BJ5BQeqn.js +247 -0
  27. package/dist/StatusBadge-BrrwraIA.js +206 -0
  28. package/dist/TrackingPage-BGqHDh-w.js +322 -0
  29. package/dist/VehicleDetailsPage-XnDH4iQR.js +194 -0
  30. package/dist/VehiclesPage-Cs4XxHkA.js +127 -0
  31. package/dist/WarehouseDetailsPage-GemdMvr_.js +215 -0
  32. package/dist/WarehousesPage-QTiuDuXy.js +121 -0
  33. package/dist/arrow-left-6CiLhqVp.js +11 -0
  34. package/dist/box-BunB_4UH.js +18 -0
  35. package/dist/chart-column-DWwVEVQ-.js +22 -0
  36. package/dist/chevron-right-DhZVf20o.js +8 -0
  37. package/dist/circle-alert-D5f6RZxt.js +26 -0
  38. package/dist/circle-check-big-D-JMHcTe.js +11 -0
  39. package/dist/clock-CvwBKbQP.js +13 -0
  40. package/dist/dev/main.d.ts +1 -0
  41. package/dist/dollar-sign-CP9qeU5d.js +14 -0
  42. package/dist/download-CIuG04pJ.js +21 -0
  43. package/dist/file-text-Dd_thxkn.js +26 -0
  44. package/dist/filter-DyRMX9CU.js +8 -0
  45. package/dist/formatters-_vJlC-47.js +50 -0
  46. package/dist/generated/global-operations.d.ts +1 -0
  47. package/dist/generated/global-types.d.ts +20715 -0
  48. package/dist/generated/wspace-operations.d.ts +3704 -0
  49. package/dist/generated/wspace-types.d.ts +53362 -0
  50. package/dist/graphqlClient-CdJyR_ed.js +55 -0
  51. package/dist/index.d.ts +4 -0
  52. package/dist/index.js +772 -0
  53. package/dist/map-BqH1cBJi.js +18 -0
  54. package/dist/map-pin-CFBOmh-A.js +13 -0
  55. package/dist/movethewheels/MoveTheWheelsRoot.d.ts +25 -0
  56. package/dist/movethewheels/MoveTheWheelsRoutes.d.ts +7 -0
  57. package/dist/movethewheels/components/DataTable.d.ts +32 -0
  58. package/dist/movethewheels/components/MetricCard.d.ts +43 -0
  59. package/dist/movethewheels/components/PageLayout.d.ts +68 -0
  60. package/dist/movethewheels/components/StatusBadge.d.ts +49 -0
  61. package/dist/movethewheels/components/index.d.ts +10 -0
  62. package/dist/movethewheels/components/ui.d.ts +22 -0
  63. package/dist/movethewheels/constants/index.d.ts +24 -0
  64. package/dist/movethewheels/constants/mockData.d.ts +33 -0
  65. package/dist/movethewheels/hooks/index.d.ts +12 -0
  66. package/dist/movethewheels/hooks/useAnalytics.d.ts +118 -0
  67. package/dist/movethewheels/hooks/useCustomers.d.ts +37 -0
  68. package/dist/movethewheels/hooks/useFleet.d.ts +71 -0
  69. package/dist/movethewheels/hooks/useInventory.d.ts +60 -0
  70. package/dist/movethewheels/hooks/useOrders.d.ts +47 -0
  71. package/dist/movethewheels/hooks/useRoutes.d.ts +41 -0
  72. package/dist/movethewheels/hooks/useTracking.d.ts +69 -0
  73. package/dist/movethewheels/index.d.ts +30 -0
  74. package/dist/movethewheels/pages/AIAssistantPage.d.ts +4 -0
  75. package/dist/movethewheels/pages/AnalyticsPage.d.ts +4 -0
  76. package/dist/movethewheels/pages/CreateOrderPage.d.ts +6 -0
  77. package/dist/movethewheels/pages/CustomerDetailsPage.d.ts +4 -0
  78. package/dist/movethewheels/pages/CustomersPage.d.ts +4 -0
  79. package/dist/movethewheels/pages/DashboardPage.d.ts +6 -0
  80. package/dist/movethewheels/pages/DriverDetailsPage.d.ts +4 -0
  81. package/dist/movethewheels/pages/DriversPage.d.ts +4 -0
  82. package/dist/movethewheels/pages/FinancePage.d.ts +4 -0
  83. package/dist/movethewheels/pages/FleetPage.d.ts +6 -0
  84. package/dist/movethewheels/pages/ImportExportPage.d.ts +4 -0
  85. package/dist/movethewheels/pages/InventoryPage.d.ts +4 -0
  86. package/dist/movethewheels/pages/LiveTrackingPage.d.ts +6 -0
  87. package/dist/movethewheels/pages/MarketplacePage.d.ts +4 -0
  88. package/dist/movethewheels/pages/OrderDetailsPage.d.ts +6 -0
  89. package/dist/movethewheels/pages/OrdersListPage.d.ts +6 -0
  90. package/dist/movethewheels/pages/ProductDetailsPage.d.ts +4 -0
  91. package/dist/movethewheels/pages/ProductsPage.d.ts +4 -0
  92. package/dist/movethewheels/pages/ReportsPage.d.ts +4 -0
  93. package/dist/movethewheels/pages/RouteDetailsPage.d.ts +4 -0
  94. package/dist/movethewheels/pages/RoutesPage.d.ts +4 -0
  95. package/dist/movethewheels/pages/SettingsPage.d.ts +4 -0
  96. package/dist/movethewheels/pages/TrackingPage.d.ts +6 -0
  97. package/dist/movethewheels/pages/VehicleDetailsPage.d.ts +4 -0
  98. package/dist/movethewheels/pages/VehiclesPage.d.ts +4 -0
  99. package/dist/movethewheels/pages/WarehouseDetailsPage.d.ts +4 -0
  100. package/dist/movethewheels/pages/WarehousesPage.d.ts +4 -0
  101. package/dist/movethewheels/providers/MoveTheWheelsProvider.d.ts +16 -0
  102. package/dist/movethewheels/store/movethewheelsStore.d.ts +73 -0
  103. package/dist/movethewheels/types/index.d.ts +655 -0
  104. package/dist/movethewheels/utils/cn.d.ts +6 -0
  105. package/dist/movethewheels/utils/formatters.d.ts +60 -0
  106. package/dist/movethewheels/utils/graphqlClient.d.ts +11 -0
  107. package/dist/movethewheels/utils/index.d.ts +7 -0
  108. package/dist/movethewheels/utils/navigation.d.ts +23 -0
  109. package/dist/navigation-BgnOfsVd.js +6 -0
  110. package/dist/navigation-C2fY_aS9.js +8 -0
  111. package/dist/package-DVZbDRcV.js +22 -0
  112. package/dist/phone-KdwpVmC4.js +18 -0
  113. package/dist/plus-Bl7uX6Ji.js +11 -0
  114. package/dist/refresh-cw-BYjl3K-8.js +22 -0
  115. package/dist/route-Ce_poKFi.js +51 -0
  116. package/dist/save-C-qDVat-.js +18 -0
  117. package/dist/search-5pdn5eOO.js +13 -0
  118. package/dist/settings-C4kIDsYg.js +28 -0
  119. package/dist/square-pen-BwQ67vLE.js +11 -0
  120. package/dist/star-BlVsC3Ad.js +8 -0
  121. package/dist/store-DTmQT5M0.js +26 -0
  122. package/dist/trending-up-C1faflCI.js +11 -0
  123. package/dist/triangle-alert-CUoVAA4L.js +18 -0
  124. package/dist/truck-BmDAzu05.js +30 -0
  125. package/dist/useAnalytics-ph7eTIK6.js +297 -0
  126. package/dist/useCustomers-bS3a4ytk.js +186 -0
  127. package/dist/useFleet-BdETplNE.js +398 -0
  128. package/dist/useInventory-Dwn18FPz.js +323 -0
  129. package/dist/useOrders-D_3_hGMp.js +324 -0
  130. package/dist/useRoutes-v4aBaS-E.js +224 -0
  131. package/dist/useTracking-De2KIUNu.js +261 -0
  132. package/dist/user-BplzDrLP.js +13 -0
  133. package/dist/users-i-igmsP4.js +24 -0
  134. package/dist/warehouse-DewG0PXh.js +25 -0
  135. package/dist/wrench-CoSDEIC7.js +31 -0
  136. package/package.json +107 -0
  137. package/src/dev/main.tsx +110 -0
  138. package/src/dev/styles.css +139 -0
  139. package/src/generated/global-operations.ts +2 -0
  140. package/src/generated/global-types.ts +24048 -0
  141. package/src/generated/wspace-operations.ts +3734 -0
  142. package/src/generated/wspace-types.ts +60715 -0
  143. package/src/index.ts +4 -0
  144. package/src/movethewheels/MoveTheWheelsRoot.tsx +258 -0
  145. package/src/movethewheels/MoveTheWheelsRoutes.tsx +119 -0
  146. package/src/movethewheels/components/DataTable.tsx +367 -0
  147. package/src/movethewheels/components/MetricCard.tsx +180 -0
  148. package/src/movethewheels/components/PageLayout.tsx +234 -0
  149. package/src/movethewheels/components/StatusBadge.tsx +243 -0
  150. package/src/movethewheels/components/index.ts +26 -0
  151. package/src/movethewheels/components/ui.tsx +124 -0
  152. package/src/movethewheels/constants/index.ts +65 -0
  153. package/src/movethewheels/constants/mockData.ts +1342 -0
  154. package/src/movethewheels/hooks/index.ts +55 -0
  155. package/src/movethewheels/hooks/useAnalytics.ts +476 -0
  156. package/src/movethewheels/hooks/useCustomers.ts +359 -0
  157. package/src/movethewheels/hooks/useFleet.ts +778 -0
  158. package/src/movethewheels/hooks/useInventory.ts +632 -0
  159. package/src/movethewheels/hooks/useOrders.ts +703 -0
  160. package/src/movethewheels/hooks/useRoutes.ts +453 -0
  161. package/src/movethewheels/hooks/useTracking.ts +505 -0
  162. package/src/movethewheels/index.ts +68 -0
  163. package/src/movethewheels/pages/AIAssistantPage.tsx +160 -0
  164. package/src/movethewheels/pages/AnalyticsPage.tsx +190 -0
  165. package/src/movethewheels/pages/CreateOrderPage.tsx +454 -0
  166. package/src/movethewheels/pages/CustomerDetailsPage.tsx +207 -0
  167. package/src/movethewheels/pages/CustomersPage.tsx +115 -0
  168. package/src/movethewheels/pages/DashboardPage.tsx +414 -0
  169. package/src/movethewheels/pages/DriverDetailsPage.tsx +261 -0
  170. package/src/movethewheels/pages/DriversPage.tsx +118 -0
  171. package/src/movethewheels/pages/FinancePage.tsx +141 -0
  172. package/src/movethewheels/pages/FleetPage.tsx +289 -0
  173. package/src/movethewheels/pages/ImportExportPage.tsx +165 -0
  174. package/src/movethewheels/pages/InventoryPage.tsx +212 -0
  175. package/src/movethewheels/pages/LiveTrackingPage.tsx +325 -0
  176. package/src/movethewheels/pages/MarketplacePage.tsx +235 -0
  177. package/src/movethewheels/pages/OrderDetailsPage.tsx +387 -0
  178. package/src/movethewheels/pages/OrdersListPage.tsx +241 -0
  179. package/src/movethewheels/pages/ProductDetailsPage.tsx +155 -0
  180. package/src/movethewheels/pages/ProductsPage.tsx +124 -0
  181. package/src/movethewheels/pages/ReportsPage.tsx +164 -0
  182. package/src/movethewheels/pages/RouteDetailsPage.tsx +245 -0
  183. package/src/movethewheels/pages/RoutesPage.tsx +104 -0
  184. package/src/movethewheels/pages/SettingsPage.tsx +242 -0
  185. package/src/movethewheels/pages/TrackingPage.tsx +419 -0
  186. package/src/movethewheels/pages/VehicleDetailsPage.tsx +218 -0
  187. package/src/movethewheels/pages/VehiclesPage.tsx +124 -0
  188. package/src/movethewheels/pages/WarehouseDetailsPage.tsx +216 -0
  189. package/src/movethewheels/pages/WarehousesPage.tsx +122 -0
  190. package/src/movethewheels/providers/MoveTheWheelsProvider.tsx +66 -0
  191. package/src/movethewheels/store/movethewheelsStore.ts +136 -0
  192. package/src/movethewheels/types/index.ts +744 -0
  193. package/src/movethewheels/utils/cn.ts +9 -0
  194. package/src/movethewheels/utils/formatters.ts +215 -0
  195. package/src/movethewheels/utils/graphqlClient.ts +63 -0
  196. package/src/movethewheels/utils/index.ts +8 -0
  197. package/src/movethewheels/utils/navigation.ts +70 -0
  198. package/src/operations/global/.gitkeep +0 -0
  199. package/src/operations/wspace/movethewheels/fragments/core.graphql +191 -0
  200. package/src/operations/wspace/movethewheels/mutations/entities.graphql +87 -0
  201. package/src/operations/wspace/movethewheels/mutations/logistics.graphql +86 -0
  202. package/src/operations/wspace/movethewheels/mutations/marketplace-reports.graphql +81 -0
  203. package/src/operations/wspace/movethewheels/mutations/orders.graphql +21 -0
  204. package/src/operations/wspace/movethewheels/queries/dashboard.graphql +61 -0
  205. package/src/operations/wspace/movethewheels/queries/entities.graphql +83 -0
  206. package/src/operations/wspace/movethewheels/queries/logistics.graphql +84 -0
  207. package/src/operations/wspace/movethewheels/queries/marketplace-reports.graphql +40 -0
  208. package/src/operations/wspace/movethewheels/queries/orders.graphql +43 -0
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Fleet Page
3
+ *
4
+ * Overview of vehicles and drivers.
5
+ */
6
+
7
+ import { Truck, Users, Wrench, Fuel, Star, ChevronRight } from 'lucide-react';
8
+ import { PageLayout, PageSection } from '../components/PageLayout';
9
+ import { MetricCard, MetricGrid } from '../components/MetricCard';
10
+ import { StatusBadge, VehicleTypeBadge } from '../components/StatusBadge';
11
+ import {
12
+ Card,
13
+ CardContent,
14
+ CardHeader,
15
+ CardTitle,
16
+ Button,
17
+ Progress,
18
+ Avatar,
19
+ AvatarFallback,
20
+ } from '../components/ui';
21
+ import { useFleetStats, useVehicles, useDrivers } from '../hooks/useFleet';
22
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
23
+ import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
24
+ import { joinPath } from '../utils/navigation';
25
+
26
+ export default function FleetPage() {
27
+ const { t: translate } = useI18n();
28
+ const t = (key: string, fallback: string): string => {
29
+ const value = translate(key);
30
+ return value === key ? fallback : value;
31
+ };
32
+ const { basePath, navigate } = useMoveTheWheels();
33
+ const { stats } = useFleetStats();
34
+ const { vehicles } = useVehicles();
35
+ const { drivers } = useDrivers();
36
+
37
+ const goTo = (path: string) => {
38
+ if (navigate) {
39
+ navigate(joinPath(basePath, path));
40
+ }
41
+ };
42
+
43
+ return (
44
+ <PageLayout
45
+ title={t('movethewheels.fleet.title', 'Fleet Management')}
46
+ subtitle={t('movethewheels.fleet.subtitle', 'Manage your vehicles and drivers')}
47
+ icon={<Truck size={24} />}
48
+ headerActions={
49
+ <div className="flex gap-2">
50
+ <Button variant="outline" onClick={() => goTo('fleet/vehicles')}>
51
+ <Truck size={16} />
52
+ {t('movethewheels.fleet.actions.allVehicles', 'All Vehicles')}
53
+ </Button>
54
+ <Button variant="outline" onClick={() => goTo('fleet/drivers')}>
55
+ <Users size={16} />
56
+ {t('movethewheels.fleet.actions.allDrivers', 'All Drivers')}
57
+ </Button>
58
+ </div>
59
+ }
60
+ >
61
+ {/* Key Metrics */}
62
+ <MetricGrid columns={4}>
63
+ <MetricCard
64
+ label={t('movethewheels.fleet.metrics.totalVehicles', 'Total Vehicles')}
65
+ value={stats.totalVehicles}
66
+ icon={<Truck size={20} />}
67
+ subtitle={`${stats.vehiclesByStatus.available} ${t('movethewheels.fleet.metrics.available', 'available')}`}
68
+ onClick={() => goTo('fleet/vehicles')}
69
+ />
70
+ <MetricCard
71
+ label={t('movethewheels.fleet.metrics.totalDrivers', 'Total Drivers')}
72
+ value={stats.totalDrivers}
73
+ icon={<Users size={20} />}
74
+ subtitle={`${stats.driversByStatus.available} ${t('movethewheels.fleet.metrics.available', 'available')}`}
75
+ onClick={() => goTo('fleet/drivers')}
76
+ />
77
+ <MetricCard
78
+ label={t('movethewheels.fleet.metrics.utilization', 'Fleet Utilization')}
79
+ value={`${stats.utilization.toFixed(0)}%`}
80
+ icon={<Truck size={20} />}
81
+ changeType={stats.utilization >= 70 ? 'positive' : 'neutral'}
82
+ />
83
+ <MetricCard
84
+ label={t('movethewheels.fleet.metrics.avgDriverRating', 'Avg Driver Rating')}
85
+ value={stats.avgDriverRating.toFixed(1)}
86
+ icon={<Star size={20} />}
87
+ subtitle={t('movethewheels.fleet.metrics.outOfFive', 'out of 5')}
88
+ changeType={stats.avgDriverRating >= 4.5 ? 'positive' : 'neutral'}
89
+ />
90
+ </MetricGrid>
91
+
92
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
93
+ {/* Vehicles Overview */}
94
+ <PageSection
95
+ title={t('movethewheels.fleet.vehicles.title', 'Vehicles')}
96
+ actions={
97
+ <Button variant="ghost" size="sm" onClick={() => goTo('fleet/vehicles')}>
98
+ {t('movethewheels.fleet.common.viewAll', 'View all')} <ChevronRight size={16} />
99
+ </Button>
100
+ }
101
+ >
102
+ <Card>
103
+ <CardContent className="p-0">
104
+ <div className="divide-y">
105
+ {vehicles.slice(0, 5).map((vehicle) => (
106
+ <div
107
+ key={vehicle.id}
108
+ className="p-4 hover:bg-muted/50 cursor-pointer transition-colors"
109
+ onClick={() => goTo(`fleet/vehicles/${vehicle.id}`)}
110
+ >
111
+ <div className="flex items-center justify-between">
112
+ <div className="flex items-center gap-3">
113
+ <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center">
114
+ <Truck size={20} className="text-primary" />
115
+ </div>
116
+ <div>
117
+ <div className="flex items-center gap-2">
118
+ <span className="font-medium">{vehicle.vehicleNumber}</span>
119
+ <VehicleTypeBadge type={vehicle.type} size="sm" />
120
+ </div>
121
+ <p className="text-sm text-muted-foreground">
122
+ {vehicle.make} {vehicle.model} ({vehicle.year})
123
+ </p>
124
+ </div>
125
+ </div>
126
+ <div className="text-right">
127
+ <StatusBadge status={vehicle.status} type="vehicle" size="sm" />
128
+ {vehicle.fuelLevel !== undefined && (
129
+ <div className="mt-2 flex items-center gap-2">
130
+ <Fuel size={12} className="text-muted-foreground" />
131
+ <Progress value={vehicle.fuelLevel} className="w-16 h-2" />
132
+ <span className="text-xs text-muted-foreground">
133
+ {vehicle.fuelLevel}%
134
+ </span>
135
+ </div>
136
+ )}
137
+ </div>
138
+ </div>
139
+ </div>
140
+ ))}
141
+ </div>
142
+ </CardContent>
143
+ </Card>
144
+ </PageSection>
145
+
146
+ {/* Drivers Overview */}
147
+ <PageSection
148
+ title={t('movethewheels.fleet.drivers.title', 'Drivers')}
149
+ actions={
150
+ <Button variant="ghost" size="sm" onClick={() => goTo('fleet/drivers')}>
151
+ {t('movethewheels.fleet.common.viewAll', 'View all')} <ChevronRight size={16} />
152
+ </Button>
153
+ }
154
+ >
155
+ <Card>
156
+ <CardContent className="p-0">
157
+ <div className="divide-y">
158
+ {drivers.slice(0, 5).map((driver) => (
159
+ <div
160
+ key={driver.id}
161
+ className="p-4 hover:bg-muted/50 cursor-pointer transition-colors"
162
+ onClick={() => goTo(`fleet/drivers/${driver.id}`)}
163
+ >
164
+ <div className="flex items-center justify-between">
165
+ <div className="flex items-center gap-3">
166
+ <Avatar>
167
+ <AvatarFallback>
168
+ {driver.fullName
169
+ .split(' ')
170
+ .map((n) => n[0])
171
+ .join('')}
172
+ </AvatarFallback>
173
+ </Avatar>
174
+ <div>
175
+ <p className="font-medium">{driver.fullName}</p>
176
+ <p className="text-sm text-muted-foreground">
177
+ {driver.employeeId} - {driver.completedOrders}{' '}
178
+ {t('movethewheels.fleet.drivers.deliveries', 'deliveries')}
179
+ </p>
180
+ </div>
181
+ </div>
182
+ <div className="text-right">
183
+ <StatusBadge status={driver.status} type="driver" size="sm" />
184
+ <div className="mt-1 flex items-center gap-1 justify-end">
185
+ <Star size={12} className="text-yellow-500 fill-yellow-500" />
186
+ <span className="text-sm font-medium">
187
+ {driver.ratings.overall.toFixed(1)}
188
+ </span>
189
+ </div>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ ))}
194
+ </div>
195
+ </CardContent>
196
+ </Card>
197
+ </PageSection>
198
+ </div>
199
+
200
+ {/* Status Summary */}
201
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
202
+ {/* Vehicle Status */}
203
+ <Card>
204
+ <CardHeader>
205
+ <CardTitle>{t('movethewheels.fleet.status.vehicleTitle', 'Vehicle Status')}</CardTitle>
206
+ </CardHeader>
207
+ <CardContent>
208
+ <div className="space-y-4">
209
+ {Object.entries(stats.vehiclesByStatus).map(([status, count]) => (
210
+ <div key={status} className="flex items-center justify-between">
211
+ <div className="flex items-center gap-3">
212
+ <StatusBadge status={status} type="vehicle" />
213
+ </div>
214
+ <div className="flex items-center gap-3">
215
+ <span className="font-medium">{count}</span>
216
+ <Progress value={(count / stats.totalVehicles) * 100} className="w-24 h-2" />
217
+ </div>
218
+ </div>
219
+ ))}
220
+ </div>
221
+ </CardContent>
222
+ </Card>
223
+
224
+ {/* Driver Status */}
225
+ <Card>
226
+ <CardHeader>
227
+ <CardTitle>{t('movethewheels.fleet.status.driverTitle', 'Driver Status')}</CardTitle>
228
+ </CardHeader>
229
+ <CardContent>
230
+ <div className="space-y-4">
231
+ {Object.entries(stats.driversByStatus).map(([status, count]) => (
232
+ <div key={status} className="flex items-center justify-between">
233
+ <div className="flex items-center gap-3">
234
+ <StatusBadge status={status} type="driver" />
235
+ </div>
236
+ <div className="flex items-center gap-3">
237
+ <span className="font-medium">{count}</span>
238
+ <Progress value={(count / stats.totalDrivers) * 100} className="w-24 h-2" />
239
+ </div>
240
+ </div>
241
+ ))}
242
+ </div>
243
+ </CardContent>
244
+ </Card>
245
+ </div>
246
+
247
+ {/* Maintenance Alerts */}
248
+ {stats.vehiclesByStatus.maintenance > 0 && (
249
+ <Card className="border-yellow-200 dark:border-yellow-800">
250
+ <CardHeader>
251
+ <CardTitle className="flex items-center gap-2 text-yellow-600">
252
+ <Wrench size={18} />
253
+ {t('movethewheels.fleet.maintenance.title', 'Maintenance Required')}
254
+ </CardTitle>
255
+ </CardHeader>
256
+ <CardContent>
257
+ <div className="space-y-3">
258
+ {vehicles
259
+ .filter((v) => v.status === 'maintenance')
260
+ .map((vehicle) => (
261
+ <div
262
+ key={vehicle.id}
263
+ className="flex items-center justify-between p-3 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg"
264
+ >
265
+ <div className="flex items-center gap-3">
266
+ <Truck size={20} className="text-yellow-600" />
267
+ <div>
268
+ <p className="font-medium">{vehicle.vehicleNumber}</p>
269
+ <p className="text-sm text-muted-foreground">
270
+ {vehicle.make} {vehicle.model}
271
+ </p>
272
+ </div>
273
+ </div>
274
+ <Button
275
+ variant="outline"
276
+ size="sm"
277
+ onClick={() => goTo(`fleet/vehicles/${vehicle.id}`)}
278
+ >
279
+ {t('movethewheels.fleet.maintenance.viewDetails', 'View Details')}
280
+ </Button>
281
+ </div>
282
+ ))}
283
+ </div>
284
+ </CardContent>
285
+ </Card>
286
+ )}
287
+ </PageLayout>
288
+ );
289
+ }
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Import/Export Page
3
+ */
4
+
5
+ import { Upload, Download, FileText, FileSpreadsheet, Check } from 'lucide-react';
6
+ import { PageLayout } from '../components/PageLayout';
7
+ import { Card, CardContent, CardHeader, CardTitle, Button, Badge } from '../components/ui';
8
+
9
+ export default function ImportExportPage() {
10
+ const importOptions = [
11
+ {
12
+ name: 'Orders',
13
+ description: 'Import orders from CSV or Excel',
14
+ icon: FileSpreadsheet,
15
+ format: 'CSV, XLSX',
16
+ },
17
+ {
18
+ name: 'Customers',
19
+ description: 'Import customer database',
20
+ icon: FileSpreadsheet,
21
+ format: 'CSV, XLSX',
22
+ },
23
+ {
24
+ name: 'Products',
25
+ description: 'Import product catalog',
26
+ icon: FileSpreadsheet,
27
+ format: 'CSV, XLSX',
28
+ },
29
+ {
30
+ name: 'Inventory',
31
+ description: 'Import inventory levels',
32
+ icon: FileSpreadsheet,
33
+ format: 'CSV, XLSX',
34
+ },
35
+ ];
36
+
37
+ const exportOptions = [
38
+ {
39
+ name: 'Orders Report',
40
+ description: 'Export all orders data',
41
+ formats: ['CSV', 'Excel', 'PDF'],
42
+ },
43
+ {
44
+ name: 'Financial Report',
45
+ description: 'Export revenue and payments',
46
+ formats: ['CSV', 'Excel', 'PDF'],
47
+ },
48
+ {
49
+ name: 'Fleet Report',
50
+ description: 'Export vehicle and driver data',
51
+ formats: ['CSV', 'Excel'],
52
+ },
53
+ {
54
+ name: 'Analytics Report',
55
+ description: 'Export performance metrics',
56
+ formats: ['CSV', 'Excel', 'PDF'],
57
+ },
58
+ ];
59
+
60
+ const recentActivity = [
61
+ { type: 'export', name: 'Orders Report', date: '2024-01-15', status: 'completed' },
62
+ { type: 'import', name: 'Customer Data', date: '2024-01-14', status: 'completed' },
63
+ { type: 'export', name: 'Financial Report', date: '2024-01-13', status: 'completed' },
64
+ ];
65
+
66
+ return (
67
+ <PageLayout
68
+ title="Import / Export"
69
+ subtitle="Import and export your data"
70
+ icon={<FileText size={24} />}
71
+ >
72
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
73
+ <Card>
74
+ <CardHeader>
75
+ <CardTitle className="flex items-center gap-2">
76
+ <Upload size={18} /> Import Data
77
+ </CardTitle>
78
+ </CardHeader>
79
+ <CardContent className="space-y-4">
80
+ {importOptions.map((opt) => (
81
+ <div
82
+ key={opt.name}
83
+ className="flex items-center justify-between p-4 border rounded-lg hover:border-primary/50 transition-colors"
84
+ >
85
+ <div className="flex items-center gap-3">
86
+ <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center">
87
+ <opt.icon size={20} className="text-primary" />
88
+ </div>
89
+ <div>
90
+ <p className="font-medium">{opt.name}</p>
91
+ <p className="text-sm text-muted-foreground">{opt.description}</p>
92
+ </div>
93
+ </div>
94
+ <div className="text-right">
95
+ <Badge variant="outline">{opt.format}</Badge>
96
+ <Button variant="outline" size="sm" className="ml-2">
97
+ <Upload size={14} />
98
+ </Button>
99
+ </div>
100
+ </div>
101
+ ))}
102
+ </CardContent>
103
+ </Card>
104
+
105
+ <Card>
106
+ <CardHeader>
107
+ <CardTitle className="flex items-center gap-2">
108
+ <Download size={18} /> Export Data
109
+ </CardTitle>
110
+ </CardHeader>
111
+ <CardContent className="space-y-4">
112
+ {exportOptions.map((opt) => (
113
+ <div
114
+ key={opt.name}
115
+ className="flex items-center justify-between p-4 border rounded-lg hover:border-primary/50 transition-colors"
116
+ >
117
+ <div>
118
+ <p className="font-medium">{opt.name}</p>
119
+ <p className="text-sm text-muted-foreground">{opt.description}</p>
120
+ </div>
121
+ <div className="flex gap-1">
122
+ {opt.formats.map((f) => (
123
+ <Button key={f} variant="outline" size="sm">
124
+ {f}
125
+ </Button>
126
+ ))}
127
+ </div>
128
+ </div>
129
+ ))}
130
+ </CardContent>
131
+ </Card>
132
+ </div>
133
+
134
+ <Card>
135
+ <CardHeader>
136
+ <CardTitle>Recent Activity</CardTitle>
137
+ </CardHeader>
138
+ <CardContent>
139
+ <div className="space-y-3">
140
+ {recentActivity.map((activity, i) => (
141
+ <div key={i} className="flex items-center justify-between p-3 bg-muted/50 rounded-lg">
142
+ <div className="flex items-center gap-3">
143
+ {activity.type === 'import' ? (
144
+ <Upload size={16} className="text-primary" />
145
+ ) : (
146
+ <Download size={16} className="text-primary" />
147
+ )}
148
+ <div>
149
+ <p className="font-medium">{activity.name}</p>
150
+ <p className="text-sm text-muted-foreground">
151
+ {activity.type === 'import' ? 'Imported' : 'Exported'} on {activity.date}
152
+ </p>
153
+ </div>
154
+ </div>
155
+ <Badge variant="default" className="gap-1">
156
+ <Check size={12} /> {activity.status}
157
+ </Badge>
158
+ </div>
159
+ ))}
160
+ </div>
161
+ </CardContent>
162
+ </Card>
163
+ </PageLayout>
164
+ );
165
+ }
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Inventory Page - Overview of inventory management
3
+ */
4
+
5
+ import { Package, Warehouse, AlertTriangle, ChevronRight, Plus } from 'lucide-react';
6
+ import { PageLayout, PageSection } from '../components/PageLayout';
7
+ import { MetricCard, MetricGrid } from '../components/MetricCard';
8
+ import {
9
+ Card,
10
+ CardContent,
11
+ CardHeader,
12
+ CardTitle,
13
+ Button,
14
+ Badge,
15
+ Progress,
16
+ } from '../components/ui';
17
+ import { useInventory, useInventoryStats } from '../hooks/useInventory';
18
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
19
+ import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
20
+ import { formatCurrency } from '../utils/formatters';
21
+ import { joinPath } from '../utils/navigation';
22
+
23
+ export default function InventoryPage() {
24
+ const { t: translate } = useI18n();
25
+ const t = (key: string, fallback: string): string => {
26
+ const value = translate(key);
27
+ return value === key ? fallback : value;
28
+ };
29
+ const { basePath, navigate } = useMoveTheWheels();
30
+ const { inventory, products, warehouses } = useInventory();
31
+ const { stats } = useInventoryStats();
32
+
33
+ const goTo = (path: string) => navigate?.(joinPath(basePath, path));
34
+ const lowStockItems = inventory.filter((inv) => inv.availableQuantity <= inv.reorderLevel);
35
+
36
+ return (
37
+ <PageLayout
38
+ title={t('movethewheels.inventory.title', 'Inventory')}
39
+ subtitle={t('movethewheels.inventory.subtitle', 'Manage your products and warehouses')}
40
+ icon={<Package size={24} />}
41
+ headerActions={
42
+ <div className="flex gap-2">
43
+ <Button variant="outline" onClick={() => goTo('inventory/products')}>
44
+ {t('movethewheels.inventory.actions.products', 'Products')}
45
+ </Button>
46
+ <Button variant="outline" onClick={() => goTo('inventory/warehouses')}>
47
+ {t('movethewheels.inventory.actions.warehouses', 'Warehouses')}
48
+ </Button>
49
+ <Button>
50
+ <Plus size={16} /> {t('movethewheels.inventory.actions.addProduct', 'Add Product')}
51
+ </Button>
52
+ </div>
53
+ }
54
+ >
55
+ <MetricGrid columns={4}>
56
+ <MetricCard
57
+ label={t('movethewheels.inventory.metrics.totalProducts', 'Total Products')}
58
+ value={stats.totalProducts}
59
+ icon={<Package size={20} />}
60
+ onClick={() => goTo('inventory/products')}
61
+ />
62
+ <MetricCard
63
+ label={t('movethewheels.inventory.metrics.totalItems', 'Total Items')}
64
+ value={stats.totalItems.toLocaleString()}
65
+ icon={<Package size={20} />}
66
+ />
67
+ <MetricCard
68
+ label={t('movethewheels.inventory.metrics.inventoryValue', 'Inventory Value')}
69
+ value={formatCurrency(stats.totalValue)}
70
+ icon={<Package size={20} />}
71
+ />
72
+ <MetricCard
73
+ label={t('movethewheels.inventory.metrics.warehouses', 'Warehouses')}
74
+ value={stats.totalWarehouses}
75
+ icon={<Warehouse size={20} />}
76
+ onClick={() => goTo('inventory/warehouses')}
77
+ />
78
+ </MetricGrid>
79
+
80
+ {lowStockItems.length > 0 && (
81
+ <Card className="border-yellow-200">
82
+ <CardHeader>
83
+ <CardTitle className="flex items-center gap-2 text-yellow-600">
84
+ <AlertTriangle size={18} />
85
+ {t('movethewheels.inventory.lowStock.title', 'Low Stock Alert')} (
86
+ {lowStockItems.length} {t('movethewheels.inventory.lowStock.items', 'items')})
87
+ </CardTitle>
88
+ </CardHeader>
89
+ <CardContent>
90
+ <div className="space-y-3">
91
+ {lowStockItems.slice(0, 5).map((item) => {
92
+ const product = products.find((p) => p.id === item.productId);
93
+ return (
94
+ <div
95
+ key={item.id}
96
+ className="flex items-center justify-between p-3 bg-yellow-50 dark:bg-yellow-900/20 rounded-lg"
97
+ >
98
+ <div>
99
+ <p className="font-medium">
100
+ {product?.name ||
101
+ t('movethewheels.inventory.lowStock.unknownProduct', 'Unknown Product')}
102
+ </p>
103
+ <p className="text-sm text-muted-foreground">
104
+ {t('movethewheels.inventory.lowStock.sku', 'SKU:')} {product?.sku}
105
+ </p>
106
+ </div>
107
+ <div className="text-right">
108
+ <p className="font-medium text-yellow-600">
109
+ {item.availableQuantity}{' '}
110
+ {t('movethewheels.inventory.lowStock.left', 'left')}
111
+ </p>
112
+ <p className="text-sm text-muted-foreground">
113
+ {t('movethewheels.inventory.lowStock.reorderAt', 'Reorder at:')}{' '}
114
+ {item.reorderLevel}
115
+ </p>
116
+ </div>
117
+ </div>
118
+ );
119
+ })}
120
+ </div>
121
+ </CardContent>
122
+ </Card>
123
+ )}
124
+
125
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
126
+ <PageSection
127
+ title={t('movethewheels.inventory.warehouses.title', 'Warehouses')}
128
+ actions={
129
+ <Button variant="ghost" size="sm" onClick={() => goTo('inventory/warehouses')}>
130
+ {t('movethewheels.inventory.common.viewAll', 'View all')} <ChevronRight size={16} />
131
+ </Button>
132
+ }
133
+ >
134
+ <Card>
135
+ <CardContent className="p-0">
136
+ <div className="divide-y">
137
+ {warehouses.map((warehouse) => (
138
+ <div
139
+ key={warehouse.id}
140
+ className="p-4 hover:bg-muted/50 cursor-pointer"
141
+ onClick={() => goTo(`inventory/warehouses/${warehouse.id}`)}
142
+ >
143
+ <div className="flex items-center justify-between">
144
+ <div>
145
+ <p className="font-medium">{warehouse.name}</p>
146
+ <p className="text-sm text-muted-foreground">
147
+ {warehouse.address.city}, {warehouse.address.state}
148
+ </p>
149
+ </div>
150
+ <div className="text-right">
151
+ <Badge variant={warehouse.isActive ? 'default' : 'secondary'}>
152
+ {warehouse.isActive
153
+ ? t('movethewheels.inventory.warehouses.active', 'Active')
154
+ : t('movethewheels.inventory.warehouses.inactive', 'Inactive')}
155
+ </Badge>
156
+ <div className="mt-2">
157
+ <p className="text-xs text-muted-foreground">
158
+ {t('movethewheels.inventory.warehouses.utilization', 'Utilization')}
159
+ </p>
160
+ <Progress
161
+ value={
162
+ (warehouse.capacity.usedSpace / warehouse.capacity.totalSpace) * 100
163
+ }
164
+ className="w-24 h-2"
165
+ />
166
+ </div>
167
+ </div>
168
+ </div>
169
+ </div>
170
+ ))}
171
+ </div>
172
+ </CardContent>
173
+ </Card>
174
+ </PageSection>
175
+
176
+ <PageSection
177
+ title={t('movethewheels.inventory.products.title', 'Recent Products')}
178
+ actions={
179
+ <Button variant="ghost" size="sm" onClick={() => goTo('inventory/products')}>
180
+ {t('movethewheels.inventory.common.viewAll', 'View all')} <ChevronRight size={16} />
181
+ </Button>
182
+ }
183
+ >
184
+ <Card>
185
+ <CardContent className="p-0">
186
+ <div className="divide-y">
187
+ {products.slice(0, 5).map((product) => (
188
+ <div
189
+ key={product.id}
190
+ className="p-4 hover:bg-muted/50 cursor-pointer"
191
+ onClick={() => goTo(`inventory/products/${product.id}`)}
192
+ >
193
+ <div className="flex items-center justify-between">
194
+ <div>
195
+ <p className="font-medium">{product.name}</p>
196
+ <p className="text-sm text-muted-foreground">{product.sku}</p>
197
+ </div>
198
+ <div className="text-right">
199
+ <p className="font-medium">{formatCurrency(product.value)}</p>
200
+ <Badge variant="outline">{product.category}</Badge>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ ))}
205
+ </div>
206
+ </CardContent>
207
+ </Card>
208
+ </PageSection>
209
+ </div>
210
+ </PageLayout>
211
+ );
212
+ }