@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,155 @@
1
+ /**
2
+ * Product Details Page
3
+ */
4
+
5
+ import { useParams } from 'react-router-dom';
6
+ import { Package, ArrowLeft, Edit, Box, DollarSign, Tag } from 'lucide-react';
7
+ import { PageLayout, LoadingState, ErrorState } from '../components/PageLayout';
8
+ import { Card, CardContent, CardHeader, CardTitle, Button, Badge } from '../components/ui';
9
+ import { useProduct } from '../hooks/useInventory';
10
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
11
+ import { formatCurrency } from '../utils/formatters';
12
+ import { joinPath } from '../utils/navigation';
13
+
14
+ export default function ProductDetailsPage() {
15
+ const { productId } = useParams<{ productId: string }>();
16
+ const { basePath, navigate } = useMoveTheWheels();
17
+ const { product, isLoading, error, refetch } = useProduct(productId);
18
+
19
+ const goBack = () => navigate?.(joinPath(basePath, 'inventory/products'));
20
+
21
+ if (isLoading) return <LoadingState message="Loading product details..." />;
22
+ if (error || !product) return <ErrorState title="Product not found" onRetry={refetch} />;
23
+
24
+ return (
25
+ <PageLayout
26
+ title={product.name}
27
+ subtitle={`SKU: ${product.sku}`}
28
+ icon={<Package size={24} />}
29
+ headerActions={
30
+ <div className="flex gap-2">
31
+ <Button variant="outline" onClick={goBack}>
32
+ <ArrowLeft size={16} /> Back
33
+ </Button>
34
+ <Button>
35
+ <Edit size={16} /> Edit
36
+ </Button>
37
+ </div>
38
+ }
39
+ headerContent={
40
+ <div className="flex gap-2">
41
+ <Badge variant="outline">{product.category}</Badge>
42
+ {product.brand && <Badge variant="secondary">{product.brand}</Badge>}
43
+ {product.fragile && <Badge variant="destructive">Fragile</Badge>}
44
+ {product.hazardous && <Badge variant="destructive">Hazardous</Badge>}
45
+ {product.temperatureControlled && <Badge variant="secondary">Temp Controlled</Badge>}
46
+ </div>
47
+ }
48
+ >
49
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
50
+ <div className="lg:col-span-2 space-y-6">
51
+ <Card>
52
+ <CardHeader>
53
+ <CardTitle>Description</CardTitle>
54
+ </CardHeader>
55
+ <CardContent>
56
+ <p>{product.description}</p>
57
+ </CardContent>
58
+ </Card>
59
+
60
+ <Card>
61
+ <CardHeader>
62
+ <CardTitle className="flex items-center gap-2">
63
+ <Box size={18} /> Dimensions & Weight
64
+ </CardTitle>
65
+ </CardHeader>
66
+ <CardContent>
67
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
68
+ <div>
69
+ <p className="text-sm text-muted-foreground">Length</p>
70
+ <p className="text-2xl font-bold">
71
+ {product.dimensions.length}
72
+ <span className="text-sm font-normal"> {product.dimensions.unit}</span>
73
+ </p>
74
+ </div>
75
+ <div>
76
+ <p className="text-sm text-muted-foreground">Width</p>
77
+ <p className="text-2xl font-bold">
78
+ {product.dimensions.width}
79
+ <span className="text-sm font-normal"> {product.dimensions.unit}</span>
80
+ </p>
81
+ </div>
82
+ <div>
83
+ <p className="text-sm text-muted-foreground">Height</p>
84
+ <p className="text-2xl font-bold">
85
+ {product.dimensions.height}
86
+ <span className="text-sm font-normal"> {product.dimensions.unit}</span>
87
+ </p>
88
+ </div>
89
+ <div>
90
+ <p className="text-sm text-muted-foreground">Weight</p>
91
+ <p className="text-2xl font-bold">
92
+ {product.weight}
93
+ <span className="text-sm font-normal"> kg</span>
94
+ </p>
95
+ </div>
96
+ </div>
97
+ </CardContent>
98
+ </Card>
99
+
100
+ {product.attributes.length > 0 && (
101
+ <Card>
102
+ <CardHeader>
103
+ <CardTitle className="flex items-center gap-2">
104
+ <Tag size={18} /> Attributes
105
+ </CardTitle>
106
+ </CardHeader>
107
+ <CardContent>
108
+ <div className="grid grid-cols-2 md:grid-cols-3 gap-4">
109
+ {product.attributes.map((attr, i) => (
110
+ <div key={i}>
111
+ <p className="text-sm text-muted-foreground">{attr.name}</p>
112
+ <p className="font-medium">{attr.value}</p>
113
+ </div>
114
+ ))}
115
+ </div>
116
+ </CardContent>
117
+ </Card>
118
+ )}
119
+ </div>
120
+
121
+ <div className="space-y-6">
122
+ <Card>
123
+ <CardHeader>
124
+ <CardTitle className="flex items-center gap-2">
125
+ <DollarSign size={18} /> Pricing
126
+ </CardTitle>
127
+ </CardHeader>
128
+ <CardContent>
129
+ <p className="text-3xl font-bold">{formatCurrency(product.value)}</p>
130
+ <p className="text-sm text-muted-foreground">Unit price</p>
131
+ </CardContent>
132
+ </Card>
133
+
134
+ <Card>
135
+ <CardHeader>
136
+ <CardTitle>Identifiers</CardTitle>
137
+ </CardHeader>
138
+ <CardContent className="space-y-3">
139
+ <div>
140
+ <p className="text-sm text-muted-foreground">SKU</p>
141
+ <p className="font-mono">{product.sku}</p>
142
+ </div>
143
+ {product.barcode && (
144
+ <div>
145
+ <p className="text-sm text-muted-foreground">Barcode</p>
146
+ <p className="font-mono">{product.barcode}</p>
147
+ </div>
148
+ )}
149
+ </CardContent>
150
+ </Card>
151
+ </div>
152
+ </div>
153
+ </PageLayout>
154
+ );
155
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Products Page - List of all products
3
+ */
4
+
5
+ import { Package, Plus, RefreshCw, Download } from 'lucide-react';
6
+ import { PageLayout } from '../components/PageLayout';
7
+ import { DataTable, type Column } from '../components/DataTable';
8
+ import { Button, Badge } from '../components/ui';
9
+ import { useProducts } from '../hooks/useInventory';
10
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
11
+ import { formatCurrency } from '../utils/formatters';
12
+ import { joinPath } from '../utils/navigation';
13
+ import type { Product } from '../types';
14
+
15
+ export default function ProductsPage() {
16
+ const { basePath, navigate } = useMoveTheWheels();
17
+ const { products, totalProducts, isLoading, refetch } = useProducts();
18
+
19
+ const goTo = (path: string) => navigate?.(joinPath(basePath, path));
20
+
21
+ const columns: Column<Product>[] = [
22
+ {
23
+ id: 'sku',
24
+ header: 'SKU',
25
+ accessorKey: 'sku',
26
+ sortable: true,
27
+ cell: (row) => <span className="font-mono">{row.sku}</span>,
28
+ },
29
+ {
30
+ id: 'name',
31
+ header: 'Product Name',
32
+ accessorKey: 'name',
33
+ sortable: true,
34
+ cell: (row) => (
35
+ <div>
36
+ <p className="font-medium">{row.name}</p>
37
+ <p className="text-sm text-muted-foreground line-clamp-1">{row.description}</p>
38
+ </div>
39
+ ),
40
+ },
41
+ {
42
+ id: 'category',
43
+ header: 'Category',
44
+ accessorKey: 'category',
45
+ sortable: true,
46
+ cell: (row) => <Badge variant="outline">{row.category}</Badge>,
47
+ },
48
+ {
49
+ id: 'dimensions',
50
+ header: 'Dimensions',
51
+ cell: (row) =>
52
+ `${row.dimensions.length}x${row.dimensions.width}x${row.dimensions.height} ${row.dimensions.unit}`,
53
+ },
54
+ {
55
+ id: 'weight',
56
+ header: 'Weight',
57
+ accessorKey: 'weight',
58
+ sortable: true,
59
+ cell: (row) => `${row.weight} kg`,
60
+ },
61
+ {
62
+ id: 'value',
63
+ header: 'Value',
64
+ accessorKey: 'value',
65
+ sortable: true,
66
+ cell: (row) => <span className="font-medium">{formatCurrency(row.value)}</span>,
67
+ },
68
+ {
69
+ id: 'flags',
70
+ header: 'Flags',
71
+ cell: (row) => (
72
+ <div className="flex gap-1">
73
+ {row.fragile && (
74
+ <Badge variant="destructive" className="text-xs">
75
+ Fragile
76
+ </Badge>
77
+ )}
78
+ {row.hazardous && (
79
+ <Badge variant="destructive" className="text-xs">
80
+ Hazardous
81
+ </Badge>
82
+ )}
83
+ {row.temperatureControlled && (
84
+ <Badge variant="secondary" className="text-xs">
85
+ Temp Control
86
+ </Badge>
87
+ )}
88
+ </div>
89
+ ),
90
+ },
91
+ ];
92
+
93
+ return (
94
+ <PageLayout
95
+ title="Products"
96
+ subtitle={`${totalProducts} products`}
97
+ icon={<Package size={24} />}
98
+ headerActions={
99
+ <div className="flex gap-2">
100
+ <Button variant="outline" onClick={refetch}>
101
+ <RefreshCw size={16} /> Refresh
102
+ </Button>
103
+ <Button variant="outline">
104
+ <Download size={16} /> Export
105
+ </Button>
106
+ <Button>
107
+ <Plus size={16} /> Add Product
108
+ </Button>
109
+ </div>
110
+ }
111
+ >
112
+ <DataTable
113
+ columns={columns}
114
+ data={products}
115
+ isLoading={isLoading}
116
+ searchable
117
+ searchPlaceholder="Search products..."
118
+ searchFields={['name', 'sku', 'category'] as (keyof Product)[]}
119
+ onRowClick={(row) => goTo(`inventory/products/${row.id}`)}
120
+ getRowId={(row) => row.id}
121
+ />
122
+ </PageLayout>
123
+ );
124
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Reports Page
3
+ */
4
+
5
+ import { FileBarChart, Download, Calendar, Filter, Clock } from 'lucide-react';
6
+ import { PageLayout } from '../components/PageLayout';
7
+ import {
8
+ Card,
9
+ CardContent,
10
+ CardHeader,
11
+ CardTitle,
12
+ Button,
13
+ Badge,
14
+ Select,
15
+ SelectContent,
16
+ SelectItem,
17
+ SelectTrigger,
18
+ SelectValue,
19
+ } from '../components/ui';
20
+
21
+ export default function ReportsPage() {
22
+ const reports = [
23
+ {
24
+ name: 'Daily Operations Summary',
25
+ description: 'Overview of daily deliveries and performance',
26
+ frequency: 'Daily',
27
+ lastGenerated: '2024-01-15',
28
+ },
29
+ {
30
+ name: 'Weekly Performance Report',
31
+ description: 'KPIs and metrics for the week',
32
+ frequency: 'Weekly',
33
+ lastGenerated: '2024-01-14',
34
+ },
35
+ {
36
+ name: 'Monthly Financial Report',
37
+ description: 'Revenue, expenses, and profit analysis',
38
+ frequency: 'Monthly',
39
+ lastGenerated: '2024-01-01',
40
+ },
41
+ {
42
+ name: 'Fleet Utilization Report',
43
+ description: 'Vehicle and driver utilization metrics',
44
+ frequency: 'Weekly',
45
+ lastGenerated: '2024-01-14',
46
+ },
47
+ {
48
+ name: 'Customer Analytics Report',
49
+ description: 'Customer satisfaction and retention',
50
+ frequency: 'Monthly',
51
+ lastGenerated: '2024-01-01',
52
+ },
53
+ {
54
+ name: 'Inventory Status Report',
55
+ description: 'Stock levels and movement analysis',
56
+ frequency: 'Daily',
57
+ lastGenerated: '2024-01-15',
58
+ },
59
+ ];
60
+
61
+ const scheduledReports = [
62
+ { name: 'Daily Summary', nextRun: 'Tomorrow 6:00 AM', recipients: 3 },
63
+ { name: 'Weekly Review', nextRun: 'Monday 9:00 AM', recipients: 5 },
64
+ ];
65
+
66
+ return (
67
+ <PageLayout
68
+ title="Reports"
69
+ subtitle="Generate and schedule reports"
70
+ icon={<FileBarChart size={24} />}
71
+ headerActions={
72
+ <div className="flex gap-2">
73
+ <Select defaultValue="30d">
74
+ <SelectTrigger className="w-[150px]">
75
+ <SelectValue />
76
+ </SelectTrigger>
77
+ <SelectContent>
78
+ <SelectItem value="7d">Last 7 days</SelectItem>
79
+ <SelectItem value="30d">Last 30 days</SelectItem>
80
+ <SelectItem value="90d">Last 90 days</SelectItem>
81
+ <SelectItem value="custom">Custom</SelectItem>
82
+ </SelectContent>
83
+ </Select>
84
+ <Button>
85
+ <FileBarChart size={16} /> Create Report
86
+ </Button>
87
+ </div>
88
+ }
89
+ >
90
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
91
+ <div className="lg:col-span-2 space-y-4">
92
+ <h3 className="font-semibold">Available Reports</h3>
93
+ {reports.map((report) => (
94
+ <Card key={report.name}>
95
+ <CardContent className="p-4">
96
+ <div className="flex items-center justify-between">
97
+ <div className="flex items-center gap-3">
98
+ <div className="w-10 h-10 rounded-lg bg-primary/10 flex items-center justify-center">
99
+ <FileBarChart size={20} className="text-primary" />
100
+ </div>
101
+ <div>
102
+ <p className="font-medium">{report.name}</p>
103
+ <p className="text-sm text-muted-foreground">{report.description}</p>
104
+ </div>
105
+ </div>
106
+ <div className="flex items-center gap-3">
107
+ <div className="text-right">
108
+ <Badge variant="outline">{report.frequency}</Badge>
109
+ <p className="text-xs text-muted-foreground mt-1">
110
+ Last: {report.lastGenerated}
111
+ </p>
112
+ </div>
113
+ <Button variant="outline" size="sm">
114
+ <Download size={14} />
115
+ </Button>
116
+ </div>
117
+ </div>
118
+ </CardContent>
119
+ </Card>
120
+ ))}
121
+ </div>
122
+
123
+ <div className="space-y-6">
124
+ <Card>
125
+ <CardHeader>
126
+ <CardTitle className="flex items-center gap-2">
127
+ <Clock size={18} /> Scheduled Reports
128
+ </CardTitle>
129
+ </CardHeader>
130
+ <CardContent className="space-y-3">
131
+ {scheduledReports.map((report) => (
132
+ <div key={report.name} className="p-3 border rounded-lg">
133
+ <p className="font-medium">{report.name}</p>
134
+ <p className="text-sm text-muted-foreground">Next: {report.nextRun}</p>
135
+ <p className="text-xs text-muted-foreground">{report.recipients} recipients</p>
136
+ </div>
137
+ ))}
138
+ <Button variant="outline" className="w-full">
139
+ Schedule New Report
140
+ </Button>
141
+ </CardContent>
142
+ </Card>
143
+
144
+ <Card>
145
+ <CardHeader>
146
+ <CardTitle>Quick Actions</CardTitle>
147
+ </CardHeader>
148
+ <CardContent className="space-y-2">
149
+ <Button variant="outline" className="w-full justify-start">
150
+ <Calendar size={16} /> Schedule Report
151
+ </Button>
152
+ <Button variant="outline" className="w-full justify-start">
153
+ <Filter size={16} /> Custom Report
154
+ </Button>
155
+ <Button variant="outline" className="w-full justify-start">
156
+ <Download size={16} /> Export All
157
+ </Button>
158
+ </CardContent>
159
+ </Card>
160
+ </div>
161
+ </div>
162
+ </PageLayout>
163
+ );
164
+ }
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Route Details Page
3
+ */
4
+
5
+ import { useParams } from 'react-router-dom';
6
+ import { Navigation, ArrowLeft, Edit, MapPin, Clock, Zap, CheckCircle } from 'lucide-react';
7
+ import { PageLayout, LoadingState, ErrorState } from '../components/PageLayout';
8
+ import { StatusBadge } from '../components/StatusBadge';
9
+ import { Card, CardContent, CardHeader, CardTitle, Button, Badge } from '../components/ui';
10
+ import { useRoute, useRoutes } from '../hooks/useRoutes';
11
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
12
+ import { formatDate, formatAddress } from '../utils/formatters';
13
+ import { joinPath } from '../utils/navigation';
14
+
15
+ export default function RouteDetailsPage() {
16
+ const { routeId } = useParams<{ routeId: string }>();
17
+ const { basePath, navigate } = useMoveTheWheels();
18
+ const { route, isLoading, error, refetch } = useRoute(routeId);
19
+ const { optimizeRoute } = useRoutes();
20
+
21
+ const goBack = () => navigate?.(joinPath(basePath, 'routes'));
22
+
23
+ // Handle new route form
24
+ if (!routeId) {
25
+ return (
26
+ <PageLayout
27
+ title="Create Route"
28
+ subtitle="Plan a new delivery route"
29
+ icon={<Navigation size={24} />}
30
+ headerActions={
31
+ <Button variant="outline" onClick={goBack}>
32
+ <ArrowLeft size={16} /> Back
33
+ </Button>
34
+ }
35
+ >
36
+ <Card>
37
+ <CardContent className="p-8 text-center">
38
+ <p className="text-muted-foreground">Route creation form would go here</p>
39
+ </CardContent>
40
+ </Card>
41
+ </PageLayout>
42
+ );
43
+ }
44
+
45
+ if (isLoading) return <LoadingState message="Loading route details..." />;
46
+ if (error || !route) return <ErrorState title="Route not found" onRetry={refetch} />;
47
+
48
+ const handleOptimize = async () => {
49
+ try {
50
+ await optimizeRoute(route.id);
51
+ refetch();
52
+ } catch (e) {
53
+ console.error(e);
54
+ }
55
+ };
56
+
57
+ const statusColors = {
58
+ planned: { bg: 'bg-blue-100', text: 'text-blue-700' },
59
+ in_progress: { bg: 'bg-yellow-100', text: 'text-yellow-700' },
60
+ completed: { bg: 'bg-green-100', text: 'text-green-700' },
61
+ cancelled: { bg: 'bg-red-100', text: 'text-red-700' },
62
+ };
63
+
64
+ return (
65
+ <PageLayout
66
+ title={route.name}
67
+ subtitle={`${route.stops.length} stops - ${route.distance.toFixed(1)} km`}
68
+ icon={<Navigation size={24} />}
69
+ headerActions={
70
+ <div className="flex gap-2">
71
+ <Button variant="outline" onClick={goBack}>
72
+ <ArrowLeft size={16} /> Back
73
+ </Button>
74
+ {!route.optimized && (
75
+ <Button variant="outline" onClick={handleOptimize}>
76
+ <Zap size={16} /> Optimize
77
+ </Button>
78
+ )}
79
+ <Button>
80
+ <Edit size={16} /> Edit
81
+ </Button>
82
+ </div>
83
+ }
84
+ headerContent={
85
+ <div className="flex gap-2">
86
+ <StatusBadge status={route.status} customColors={statusColors[route.status]} />
87
+ <Badge variant={route.optimized ? 'default' : 'secondary'}>
88
+ {route.optimized ? 'Optimized' : 'Not Optimized'}
89
+ </Badge>
90
+ </div>
91
+ }
92
+ >
93
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
94
+ <div className="lg:col-span-2 space-y-6">
95
+ <Card>
96
+ <CardHeader>
97
+ <CardTitle>Route Map</CardTitle>
98
+ </CardHeader>
99
+ <CardContent>
100
+ <div className="aspect-video bg-muted rounded-lg flex items-center justify-center">
101
+ <div className="text-center text-muted-foreground">
102
+ <MapPin size={48} className="mx-auto mb-2 opacity-50" />
103
+ <p>Route map visualization</p>
104
+ </div>
105
+ </div>
106
+ </CardContent>
107
+ </Card>
108
+
109
+ <Card>
110
+ <CardHeader>
111
+ <CardTitle>Stops ({route.stops.length})</CardTitle>
112
+ </CardHeader>
113
+ <CardContent>
114
+ <div className="space-y-4">
115
+ {route.stops.map((stop, index) => (
116
+ <div key={stop.id} className="flex gap-4">
117
+ <div className="relative">
118
+ <div
119
+ className={`w-8 h-8 rounded-full flex items-center justify-center ${stop.status === 'completed' ? 'bg-green-500 text-white' : 'bg-muted'}`}
120
+ >
121
+ {stop.status === 'completed' ? <CheckCircle size={16} /> : stop.sequence}
122
+ </div>
123
+ {index < route.stops.length - 1 && (
124
+ <div className="absolute top-8 left-4 w-px h-12 bg-border" />
125
+ )}
126
+ </div>
127
+ <div className="flex-1 pb-4">
128
+ <div className="flex items-center justify-between">
129
+ <div>
130
+ <div className="flex items-center gap-2">
131
+ <Badge
132
+ variant={stop.type === 'pickup' ? 'secondary' : 'default'}
133
+ className="capitalize"
134
+ >
135
+ {stop.type}
136
+ </Badge>
137
+ <span className="font-medium">Order #{stop.orderId}</span>
138
+ </div>
139
+ <p className="text-sm text-muted-foreground mt-1">
140
+ {formatAddress(stop.address)}
141
+ </p>
142
+ </div>
143
+ <div className="text-right">
144
+ <p className="text-sm">
145
+ Scheduled: {formatDate(stop.scheduledTime, 'time')}
146
+ </p>
147
+ {stop.actualTime && (
148
+ <p className="text-sm text-green-600">
149
+ Actual: {formatDate(stop.actualTime, 'time')}
150
+ </p>
151
+ )}
152
+ <p className="text-xs text-muted-foreground">{stop.duration} min stop</p>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ ))}
158
+ </div>
159
+ </CardContent>
160
+ </Card>
161
+ </div>
162
+
163
+ <div className="space-y-6">
164
+ <Card>
165
+ <CardHeader>
166
+ <CardTitle>Route Info</CardTitle>
167
+ </CardHeader>
168
+ <CardContent className="space-y-4">
169
+ <div>
170
+ <p className="text-sm text-muted-foreground">Total Distance</p>
171
+ <p className="text-2xl font-bold">
172
+ {route.distance.toFixed(1)}
173
+ <span className="text-sm font-normal"> km</span>
174
+ </p>
175
+ </div>
176
+ <div>
177
+ <p className="text-sm text-muted-foreground">Est. Duration</p>
178
+ <p className="text-2xl font-bold">
179
+ {route.estimatedDuration}
180
+ <span className="text-sm font-normal"> min</span>
181
+ </p>
182
+ </div>
183
+ {route.actualDuration && (
184
+ <div>
185
+ <p className="text-sm text-muted-foreground">Actual Duration</p>
186
+ <p className="text-2xl font-bold">
187
+ {route.actualDuration}
188
+ <span className="text-sm font-normal"> min</span>
189
+ </p>
190
+ </div>
191
+ )}
192
+ </CardContent>
193
+ </Card>
194
+
195
+ <Card>
196
+ <CardHeader>
197
+ <CardTitle className="flex items-center gap-2">
198
+ <Clock size={18} /> Timeline
199
+ </CardTitle>
200
+ </CardHeader>
201
+ <CardContent className="space-y-3">
202
+ {route.startTime && (
203
+ <div>
204
+ <p className="text-sm text-muted-foreground">Started</p>
205
+ <p>{formatDate(route.startTime, 'full')}</p>
206
+ </div>
207
+ )}
208
+ {route.endTime && (
209
+ <div>
210
+ <p className="text-sm text-muted-foreground">Completed</p>
211
+ <p>{formatDate(route.endTime, 'full')}</p>
212
+ </div>
213
+ )}
214
+ <div>
215
+ <p className="text-sm text-muted-foreground">Created</p>
216
+ <p>{formatDate(route.createdAt, 'full')}</p>
217
+ </div>
218
+ </CardContent>
219
+ </Card>
220
+
221
+ {route.trafficConditions.length > 0 && (
222
+ <Card>
223
+ <CardHeader>
224
+ <CardTitle>Traffic Conditions</CardTitle>
225
+ </CardHeader>
226
+ <CardContent>
227
+ {route.trafficConditions.map((tc, i) => (
228
+ <div
229
+ key={i}
230
+ className={`p-2 rounded mb-2 ${tc.condition === 'severe' ? 'bg-red-50' : tc.condition === 'heavy' ? 'bg-orange-50' : 'bg-yellow-50'}`}
231
+ >
232
+ <p className="text-sm font-medium capitalize">{tc.condition} traffic</p>
233
+ <p className="text-xs text-muted-foreground">
234
+ {tc.location} - +{tc.delay} min delay
235
+ </p>
236
+ </div>
237
+ ))}
238
+ </CardContent>
239
+ </Card>
240
+ )}
241
+ </div>
242
+ </div>
243
+ </PageLayout>
244
+ );
245
+ }