@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,632 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
3
+ import type { Inventory, InventoryFilter, Product, Warehouse } from '../types';
4
+ import { executeGraphQL } from '../utils/graphqlClient';
5
+
6
+ interface UseInventoryOptions {
7
+ filters?: InventoryFilter;
8
+ }
9
+
10
+ interface UseInventoryResult {
11
+ inventory: Inventory[];
12
+ products: Product[];
13
+ warehouses: Warehouse[];
14
+ totalItems: number;
15
+ isLoading: boolean;
16
+ error: Error | null;
17
+ refetch: () => void;
18
+ updateStock: (inventoryId: string, quantity: number, reason: string) => Promise<Inventory>;
19
+ transferStock: (
20
+ fromWarehouseId: string,
21
+ toWarehouseId: string,
22
+ productId: string,
23
+ quantity: number
24
+ ) => Promise<void>;
25
+ }
26
+
27
+ interface ApiInventoryItem {
28
+ id: string;
29
+ productId: string;
30
+ warehouseId: string;
31
+ onHand: number;
32
+ available: number;
33
+ allocated: number;
34
+ damaged: number;
35
+ reorderPoint?: number | null;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ }
39
+
40
+ interface ApiProduct {
41
+ id: string;
42
+ sku: string;
43
+ name: string;
44
+ description?: string | null;
45
+ category?: string | null;
46
+ brand?: string | null;
47
+ dimensions?: Record<string, unknown> | null;
48
+ weight?: number | null;
49
+ value?: number | null;
50
+ hazardous: boolean;
51
+ fragile: boolean;
52
+ temperatureControlled: boolean;
53
+ createdAt: string;
54
+ updatedAt: string;
55
+ }
56
+
57
+ interface ApiWarehouse {
58
+ id: string;
59
+ name: string;
60
+ code: string;
61
+ type: string;
62
+ address: Record<string, unknown>;
63
+ totalCapacity?: number | null;
64
+ usedCapacity?: number | null;
65
+ createdAt: string;
66
+ }
67
+
68
+ const LIST_INVENTORY_QUERY = `
69
+ query ListInventoryItems($filter: InventoryFilterInput, $pagination: PaginationInput) {
70
+ inventoryItems(filter: $filter, pagination: $pagination) {
71
+ id
72
+ productId
73
+ warehouseId
74
+ onHand
75
+ available
76
+ allocated
77
+ damaged
78
+ reorderPoint
79
+ createdAt
80
+ updatedAt
81
+ }
82
+ }
83
+ `;
84
+
85
+ const LIST_PRODUCTS_QUERY = `
86
+ query ListProducts($filter: ProductFilterInput, $pagination: PaginationInput) {
87
+ products(filter: $filter, pagination: $pagination) {
88
+ id
89
+ sku
90
+ name
91
+ description
92
+ category
93
+ brand
94
+ dimensions
95
+ weight
96
+ value
97
+ hazardous
98
+ fragile
99
+ temperatureControlled
100
+ createdAt
101
+ updatedAt
102
+ }
103
+ }
104
+ `;
105
+
106
+ const LIST_WAREHOUSES_QUERY = `
107
+ query ListWarehouses($filter: WarehouseFilterInput, $pagination: PaginationInput) {
108
+ warehouses(filter: $filter, pagination: $pagination) {
109
+ id
110
+ name
111
+ code
112
+ type
113
+ address
114
+ totalCapacity
115
+ usedCapacity
116
+ createdAt
117
+ }
118
+ }
119
+ `;
120
+
121
+ const GET_PRODUCT_QUERY = `
122
+ query GetProduct($id: ID!) {
123
+ product(id: $id) {
124
+ id
125
+ sku
126
+ name
127
+ description
128
+ category
129
+ brand
130
+ dimensions
131
+ weight
132
+ value
133
+ hazardous
134
+ fragile
135
+ temperatureControlled
136
+ createdAt
137
+ updatedAt
138
+ }
139
+ }
140
+ `;
141
+
142
+ const GET_WAREHOUSE_QUERY = `
143
+ query GetWarehouse($id: ID!) {
144
+ warehouse(id: $id) {
145
+ id
146
+ name
147
+ code
148
+ type
149
+ address
150
+ totalCapacity
151
+ usedCapacity
152
+ createdAt
153
+ }
154
+ }
155
+ `;
156
+
157
+ const INVENTORY_STATS_QUERY = `
158
+ query GetInventoryStats {
159
+ inventoryStats {
160
+ totalOnHand
161
+ totalAvailable
162
+ totalAllocated
163
+ totalDamaged
164
+ lowStockCount
165
+ }
166
+ }
167
+ `;
168
+
169
+ const ADJUST_INVENTORY_MUTATION = `
170
+ mutation AdjustInventoryStock($input: AdjustInventoryStockInput!) {
171
+ adjustInventoryStock(input: $input) {
172
+ id
173
+ productId
174
+ warehouseId
175
+ onHand
176
+ available
177
+ allocated
178
+ damaged
179
+ reorderPoint
180
+ createdAt
181
+ updatedAt
182
+ }
183
+ }
184
+ `;
185
+
186
+ function mapProduct(product: ApiProduct): Product {
187
+ return {
188
+ id: product.id,
189
+ sku: product.sku,
190
+ name: product.name,
191
+ description: product.description ?? '',
192
+ category: product.category ?? 'general',
193
+ brand: product.brand ?? undefined,
194
+ dimensions: {
195
+ length: 0,
196
+ width: 0,
197
+ height: 0,
198
+ unit: 'cm',
199
+ ...(product.dimensions ?? {}),
200
+ } as Product['dimensions'],
201
+ weight: product.weight ?? 0,
202
+ value: product.value ?? 0,
203
+ barcode: undefined,
204
+ images: [],
205
+ attributes: [],
206
+ hazardous: product.hazardous,
207
+ temperatureControlled: product.temperatureControlled,
208
+ fragile: product.fragile,
209
+ createdAt: new Date(product.createdAt),
210
+ updatedAt: new Date(product.updatedAt),
211
+ };
212
+ }
213
+
214
+ function mapWarehouse(warehouse: ApiWarehouse): Warehouse {
215
+ const totalSpace = warehouse.totalCapacity ?? 0;
216
+ const usedSpace = warehouse.usedCapacity ?? 0;
217
+ return {
218
+ id: warehouse.id,
219
+ name: warehouse.name,
220
+ code: warehouse.code,
221
+ address: {
222
+ street: '',
223
+ city: '',
224
+ state: '',
225
+ postalCode: '',
226
+ country: '',
227
+ ...(warehouse.address ?? {}),
228
+ },
229
+ type: (warehouse.type?.toLowerCase() ?? 'distribution') as Warehouse['type'],
230
+ capacity: {
231
+ totalSpace,
232
+ usedSpace,
233
+ totalPallets: 0,
234
+ usedPallets: 0,
235
+ specialAreas: [],
236
+ },
237
+ operatingHours: {},
238
+ contacts: [],
239
+ zones: [],
240
+ equipment: [],
241
+ staff: [],
242
+ metrics: {
243
+ throughput: 0,
244
+ accuracy: 0,
245
+ productivity: 0,
246
+ utilization: totalSpace > 0 ? (usedSpace / totalSpace) * 100 : 0,
247
+ ordersFulfilled: 0,
248
+ averageProcessingTime: 0,
249
+ lastUpdated: new Date(),
250
+ },
251
+ isActive: true,
252
+ createdAt: new Date(warehouse.createdAt),
253
+ };
254
+ }
255
+
256
+ function mapInventory(item: ApiInventoryItem): Inventory {
257
+ return {
258
+ id: item.id,
259
+ productId: item.productId,
260
+ warehouseId: item.warehouseId,
261
+ zoneId: '',
262
+ quantity: item.onHand,
263
+ reservedQuantity: item.allocated,
264
+ availableQuantity: item.available,
265
+ reorderLevel: item.reorderPoint ?? 0,
266
+ maxLevel: Math.max(item.onHand * 2, item.available),
267
+ lastRestocked: new Date(item.updatedAt),
268
+ location: {
269
+ aisle: '',
270
+ shelf: '',
271
+ position: '',
272
+ level: 0,
273
+ },
274
+ movements: [],
275
+ createdAt: new Date(item.createdAt),
276
+ updatedAt: new Date(item.updatedAt),
277
+ };
278
+ }
279
+
280
+ function useGraphqlOptions() {
281
+ const { apiGatewayUrl, authToken, workspaceToken, workspaceId, tenantId, currentUser } =
282
+ useMoveTheWheels();
283
+ return useMemo(
284
+ () => ({
285
+ apiGatewayUrl,
286
+ authToken,
287
+ workspaceToken,
288
+ workspaceId,
289
+ tenantId,
290
+ actorId: currentUser?.id,
291
+ }),
292
+ [apiGatewayUrl, authToken, workspaceToken, workspaceId, tenantId, currentUser?.id]
293
+ );
294
+ }
295
+
296
+ export function useInventory(options: UseInventoryOptions = {}): UseInventoryResult {
297
+ const { filters: rawFilters } = options;
298
+ // Stabilize filters reference for React Compiler memoization.
299
+ const filters = useMemo(
300
+ () => rawFilters,
301
+ [rawFilters?.lowStock, rawFilters?.productId, rawFilters?.warehouseId]
302
+ );
303
+ const graphQLOptions = useGraphqlOptions();
304
+ const [inventory, setInventory] = useState<Inventory[]>([]);
305
+ const [products, setProducts] = useState<Product[]>([]);
306
+ const [warehouses, setWarehouses] = useState<Warehouse[]>([]);
307
+ const [isLoading, setIsLoading] = useState(false);
308
+ const [error, setError] = useState<Error | null>(null);
309
+
310
+ const load = useCallback(async () => {
311
+ setIsLoading(true);
312
+ setError(null);
313
+ try {
314
+ const [inventoryData, productData, warehouseData] = await Promise.all([
315
+ executeGraphQL<{ inventoryItems: ApiInventoryItem[] }>(
316
+ graphQLOptions,
317
+ LIST_INVENTORY_QUERY,
318
+ {
319
+ filter: {
320
+ warehouseId: filters?.warehouseId,
321
+ productId: filters?.productId,
322
+ },
323
+ pagination: { limit: 500, offset: 0 },
324
+ }
325
+ ),
326
+ executeGraphQL<{ products: ApiProduct[] }>(graphQLOptions, LIST_PRODUCTS_QUERY, {
327
+ pagination: { limit: 500, offset: 0 },
328
+ }),
329
+ executeGraphQL<{ warehouses: ApiWarehouse[] }>(graphQLOptions, LIST_WAREHOUSES_QUERY, {
330
+ pagination: { limit: 500, offset: 0 },
331
+ }),
332
+ ]);
333
+
334
+ let nextInventory = inventoryData.inventoryItems.map(mapInventory);
335
+ if (filters?.lowStock) {
336
+ nextInventory = nextInventory.filter((item) => item.availableQuantity <= item.reorderLevel);
337
+ }
338
+
339
+ setInventory(nextInventory);
340
+ setProducts(productData.products.map(mapProduct));
341
+ setWarehouses(warehouseData.warehouses.map(mapWarehouse));
342
+ } catch (fetchError) {
343
+ setError(
344
+ fetchError instanceof Error ? fetchError : new Error('Failed to load inventory data')
345
+ );
346
+ } finally {
347
+ setIsLoading(false);
348
+ }
349
+ }, [filters, graphQLOptions]);
350
+
351
+ useEffect(() => {
352
+ void load();
353
+ }, [load]);
354
+
355
+ const refetch = useCallback(() => {
356
+ void load();
357
+ }, [load]);
358
+
359
+ const updateStock = useCallback(
360
+ async (inventoryId: string, quantity: number, _reason: string): Promise<Inventory> => {
361
+ const current = inventory.find((item) => item.id === inventoryId);
362
+ if (!current) {
363
+ throw new Error('Inventory item not found');
364
+ }
365
+
366
+ const data = await executeGraphQL<{ adjustInventoryStock: ApiInventoryItem }>(
367
+ graphQLOptions,
368
+ ADJUST_INVENTORY_MUTATION,
369
+ {
370
+ input: {
371
+ id: inventoryId,
372
+ onHand: current.quantity + quantity,
373
+ available: current.availableQuantity + quantity,
374
+ allocated: current.reservedQuantity,
375
+ damaged: 0,
376
+ },
377
+ }
378
+ );
379
+
380
+ const updated = mapInventory(data.adjustInventoryStock);
381
+ setInventory((previous) =>
382
+ previous.map((item) => (item.id === inventoryId ? updated : item))
383
+ );
384
+ return updated;
385
+ },
386
+ [graphQLOptions, inventory]
387
+ );
388
+
389
+ const transferStock = useCallback(
390
+ async (
391
+ fromWarehouseId: string,
392
+ toWarehouseId: string,
393
+ productId: string,
394
+ quantity: number
395
+ ): Promise<void> => {
396
+ const source = inventory.find(
397
+ (item) => item.warehouseId === fromWarehouseId && item.productId === productId
398
+ );
399
+ if (!source) {
400
+ throw new Error('Source inventory not found');
401
+ }
402
+
403
+ await updateStock(source.id, -Math.abs(quantity), 'transfer out');
404
+
405
+ const destination = inventory.find(
406
+ (item) => item.warehouseId === toWarehouseId && item.productId === productId
407
+ );
408
+ if (destination) {
409
+ await updateStock(destination.id, Math.abs(quantity), 'transfer in');
410
+ }
411
+ },
412
+ [inventory, updateStock]
413
+ );
414
+
415
+ return {
416
+ inventory,
417
+ products,
418
+ warehouses,
419
+ totalItems: inventory.length,
420
+ isLoading,
421
+ error,
422
+ refetch,
423
+ updateStock,
424
+ transferStock,
425
+ };
426
+ }
427
+
428
+ export function useProducts() {
429
+ const graphQLOptions = useGraphqlOptions();
430
+ const [products, setProducts] = useState<Product[]>([]);
431
+ const [isLoading, setIsLoading] = useState(false);
432
+ const [error, setError] = useState<Error | null>(null);
433
+
434
+ const load = useCallback(async () => {
435
+ setIsLoading(true);
436
+ setError(null);
437
+ try {
438
+ const data = await executeGraphQL<{ products: ApiProduct[] }>(
439
+ graphQLOptions,
440
+ LIST_PRODUCTS_QUERY,
441
+ {
442
+ pagination: { limit: 500, offset: 0 },
443
+ }
444
+ );
445
+ setProducts(data.products.map(mapProduct));
446
+ } catch (fetchError) {
447
+ setError(fetchError instanceof Error ? fetchError : new Error('Failed to load products'));
448
+ } finally {
449
+ setIsLoading(false);
450
+ }
451
+ }, [graphQLOptions]);
452
+
453
+ useEffect(() => {
454
+ void load();
455
+ }, [load]);
456
+
457
+ return {
458
+ products,
459
+ totalProducts: products.length,
460
+ isLoading,
461
+ error,
462
+ refetch: () => void load(),
463
+ };
464
+ }
465
+
466
+ export function useProduct(productId: string | undefined) {
467
+ const graphQLOptions = useGraphqlOptions();
468
+ const [product, setProduct] = useState<Product | null>(null);
469
+ const [isLoading, setIsLoading] = useState(false);
470
+ const [error, setError] = useState<Error | null>(null);
471
+
472
+ const load = useCallback(async () => {
473
+ if (!productId) {
474
+ setProduct(null);
475
+ return;
476
+ }
477
+ setIsLoading(true);
478
+ setError(null);
479
+ try {
480
+ const data = await executeGraphQL<{ product: ApiProduct | null }>(
481
+ graphQLOptions,
482
+ GET_PRODUCT_QUERY,
483
+ {
484
+ id: productId,
485
+ }
486
+ );
487
+ setProduct(data.product ? mapProduct(data.product) : null);
488
+ } catch (fetchError) {
489
+ setError(fetchError instanceof Error ? fetchError : new Error('Failed to load product'));
490
+ } finally {
491
+ setIsLoading(false);
492
+ }
493
+ }, [graphQLOptions, productId]);
494
+
495
+ useEffect(() => {
496
+ void load();
497
+ }, [load]);
498
+
499
+ return { product, isLoading, error, refetch: () => void load() };
500
+ }
501
+
502
+ export function useWarehouses() {
503
+ const graphQLOptions = useGraphqlOptions();
504
+ const [warehouses, setWarehouses] = useState<Warehouse[]>([]);
505
+ const [isLoading, setIsLoading] = useState(false);
506
+ const [error, setError] = useState<Error | null>(null);
507
+
508
+ const load = useCallback(async () => {
509
+ setIsLoading(true);
510
+ setError(null);
511
+ try {
512
+ const data = await executeGraphQL<{ warehouses: ApiWarehouse[] }>(
513
+ graphQLOptions,
514
+ LIST_WAREHOUSES_QUERY,
515
+ {
516
+ pagination: { limit: 500, offset: 0 },
517
+ }
518
+ );
519
+ setWarehouses(data.warehouses.map(mapWarehouse));
520
+ } catch (fetchError) {
521
+ setError(fetchError instanceof Error ? fetchError : new Error('Failed to load warehouses'));
522
+ } finally {
523
+ setIsLoading(false);
524
+ }
525
+ }, [graphQLOptions]);
526
+
527
+ useEffect(() => {
528
+ void load();
529
+ }, [load]);
530
+
531
+ return {
532
+ warehouses,
533
+ totalWarehouses: warehouses.length,
534
+ isLoading,
535
+ error,
536
+ refetch: () => void load(),
537
+ };
538
+ }
539
+
540
+ export function useWarehouse(warehouseId: string | undefined) {
541
+ const graphQLOptions = useGraphqlOptions();
542
+ const [warehouse, setWarehouse] = useState<Warehouse | null>(null);
543
+ const [isLoading, setIsLoading] = useState(false);
544
+ const [error, setError] = useState<Error | null>(null);
545
+
546
+ const load = useCallback(async () => {
547
+ if (!warehouseId) {
548
+ setWarehouse(null);
549
+ return;
550
+ }
551
+ setIsLoading(true);
552
+ setError(null);
553
+ try {
554
+ const data = await executeGraphQL<{ warehouse: ApiWarehouse | null }>(
555
+ graphQLOptions,
556
+ GET_WAREHOUSE_QUERY,
557
+ { id: warehouseId }
558
+ );
559
+ setWarehouse(data.warehouse ? mapWarehouse(data.warehouse) : null);
560
+ } catch (fetchError) {
561
+ setError(fetchError instanceof Error ? fetchError : new Error('Failed to load warehouse'));
562
+ } finally {
563
+ setIsLoading(false);
564
+ }
565
+ }, [graphQLOptions, warehouseId]);
566
+
567
+ useEffect(() => {
568
+ void load();
569
+ }, [load]);
570
+
571
+ return { warehouse, isLoading, error, refetch: () => void load() };
572
+ }
573
+
574
+ export function useInventoryStats() {
575
+ const graphQLOptions = useGraphqlOptions();
576
+ const [stats, setStats] = useState({
577
+ totalItems: 0,
578
+ lowStockItems: 0,
579
+ totalValue: 0,
580
+ totalProducts: 0,
581
+ totalWarehouses: 0,
582
+ warehouseUtilization: [] as Array<{ id: string; name: string; utilization: number }>,
583
+ });
584
+ const [isLoading, setIsLoading] = useState(false);
585
+ const [error, setError] = useState<Error | null>(null);
586
+
587
+ useEffect(() => {
588
+ const load = async () => {
589
+ setIsLoading(true);
590
+ setError(null);
591
+ try {
592
+ const [inventoryStats, warehouses] = await Promise.all([
593
+ executeGraphQL<{
594
+ inventoryStats: {
595
+ totalOnHand: number;
596
+ lowStockCount: number;
597
+ };
598
+ }>(graphQLOptions, INVENTORY_STATS_QUERY),
599
+ executeGraphQL<{ warehouses: ApiWarehouse[] }>(graphQLOptions, LIST_WAREHOUSES_QUERY, {
600
+ pagination: { limit: 500, offset: 0 },
601
+ }),
602
+ ]);
603
+
604
+ setStats({
605
+ totalItems: inventoryStats.inventoryStats.totalOnHand,
606
+ lowStockItems: inventoryStats.inventoryStats.lowStockCount,
607
+ totalValue: 0,
608
+ totalProducts: 0,
609
+ totalWarehouses: warehouses.warehouses.length,
610
+ warehouseUtilization: warehouses.warehouses.map((warehouse) => ({
611
+ id: warehouse.id,
612
+ name: warehouse.name,
613
+ utilization:
614
+ (warehouse.totalCapacity ?? 0) > 0
615
+ ? ((warehouse.usedCapacity ?? 0) / (warehouse.totalCapacity ?? 1)) * 100
616
+ : 0,
617
+ })),
618
+ });
619
+ } catch (fetchError) {
620
+ setError(
621
+ fetchError instanceof Error ? fetchError : new Error('Failed to load inventory stats')
622
+ );
623
+ } finally {
624
+ setIsLoading(false);
625
+ }
626
+ };
627
+
628
+ void load();
629
+ }, [graphQLOptions]);
630
+
631
+ return { stats, isLoading, error };
632
+ }