@burdenoff/microfe-movethewheels 2026.626.2 → 2026.703.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AIAssistantPage-AvsMbunM.js → AIAssistantPage-C3cPsWt-.js} +100 -73
- package/dist/AnalyticsPage-Dz6g2MvK.js +215 -0
- package/dist/{CreateOrderPage-CjlnEtk3.js → CreateOrderPage-C5iwnjp4.js} +36 -67
- package/dist/CustomerDetailsPage-B6nwFyLO.js +406 -0
- package/dist/{CustomersPage-CGGfD4ki.js → CustomersPage-2Y05LVyh.js} +26 -28
- package/dist/{DashboardPage-D2HRqwg9.js → DashboardPage-BVjQi0EB.js} +85 -83
- package/dist/{DataTable-CD9ZhpLB.js → DataTable-DmciIKKM.js} +3 -3
- package/dist/DriverDetailsPage-CN3WQ0B9.js +507 -0
- package/dist/{DriversPage-DKiynISH.js → DriversPage-B0Zpx8OQ.js} +25 -27
- package/dist/{FinancePage-Vg8WPs38.js → FinancePage-DEDykSOP.js} +9 -9
- package/dist/FleetPage-DqkFi3s3.js +365 -0
- package/dist/FormError-BlOjnXOq.js +15 -0
- package/dist/ImportExportPage-DKJRCezl.js +290 -0
- package/dist/InventoryPage-DwfgCUQq.js +253 -0
- package/dist/{LiveTrackingPage-DQ1q4Id3.js → LiveTrackingPage-DCX-K-LR.js} +60 -56
- package/dist/MarketplacePage-CIQ97_zp.js +247 -0
- package/dist/{MetricCard-B7yMyvMX.js → MetricCard-BY0QrMD4.js} +1 -1
- package/dist/{OrderDetailsPage-CFASgsYX.js → OrderDetailsPage-DYiZ-9UK.js} +83 -85
- package/dist/{OrdersListPage-BHeT8S5o.js → OrdersListPage-BjDlCKJd.js} +31 -33
- package/dist/{PageLayout-D3N8MCTm.js → PageLayout-D4LDHJJq.js} +483 -422
- package/dist/ProductDetailsPage-C9uOiYLp.js +350 -0
- package/dist/{ProductsPage--xEpbQ8A.js → ProductsPage-C1G9h7Xd.js} +22 -24
- package/dist/ReportsPage-Zp53q3_8.js +284 -0
- package/dist/RouteDetailsPage-DUStXSf9.js +531 -0
- package/dist/RoutesPage-DMfoicM1.js +144 -0
- package/dist/SettingsPage-Bn-v0mbQ.js +421 -0
- package/dist/StatusBadge-BZurYHMy.js +152 -0
- package/dist/{TrackingPage-CcRc_dva.js → TrackingPage-W-jtdM3Y.js} +59 -61
- package/dist/VehicleDetailsPage-Bceo5oz3.js +410 -0
- package/dist/{VehiclesPage-UlxPWP9K.js → VehiclesPage-VBtOep91.js} +20 -22
- package/dist/WarehouseDetailsPage-L_6sWigM.js +493 -0
- package/dist/{WarehousesPage-CuTO-OPp.js → WarehousesPage-DCbXXXWE.js} +16 -18
- package/dist/{arrow-left-CBpZKkpq.js → arrow-left-n48Y-Wis.js} +1 -1
- package/dist/{box-CAaiElsb.js → box-D9Pal4HM.js} +1 -1
- package/dist/{chart-column-D1Ym15-S.js → chart-column-BFIJysDR.js} +1 -1
- package/dist/{chevron-right-BIFGi0UA.js → chevron-right-EMIIyyJ1.js} +1 -1
- package/dist/{circle-alert-DjmNo5_L.js → circle-alert-iY24lSlp.js} +1 -1
- package/dist/{circle-check-big-CjuPVo3_.js → circle-check-big-w0TrLKMF.js} +1 -1
- package/dist/{clock-BjkdnddD.js → clock-DJZtdl8u.js} +1 -1
- package/dist/{dollar-sign-IB4O0wuQ.js → dollar-sign-CgKQRz_e.js} +1 -1
- package/dist/{download-Dpa9vqoG.js → download-DRXxoiQR.js} +1 -1
- package/dist/{file-text-C8Uioy11.js → file-text-DWWY6_f5.js} +1 -1
- package/dist/{filter-Da5OZaHI.js → filter-DloLC2eE.js} +1 -1
- package/dist/index.js +186 -162
- package/dist/{map-_Per4sT9.js → map-CkJaULb2.js} +1 -1
- package/dist/{map-pin-BSaf5IDL.js → map-pin-BGiCvyCs.js} +1 -1
- package/dist/{navigation-DaTbrhw2.js → navigation-D36prnAn.js} +1 -1
- package/dist/{package-BE7U0wQE.js → package-BChUzpJS.js} +1 -1
- package/dist/{phone-DV4StZiA.js → phone-Ac9s3mo_.js} +1 -1
- package/dist/{plus-Dl1rLeJR.js → plus-Z76q-FZm.js} +1 -1
- package/dist/{refresh-cw-CWfERAit.js → refresh-cw-DKt6f5T6.js} +1 -1
- package/dist/{save-XH8vydOn.js → save-CojywNhG.js} +1 -1
- package/dist/{search-OxoIiL_C.js → search-CDGefqb3.js} +1 -1
- package/dist/{square-pen-hLIbFQFV.js → square-pen-CopE9GmB.js} +1 -1
- package/dist/{star-YsVV3MNQ.js → star-nHlLjDKR.js} +1 -1
- package/dist/{store-RCBl7HB-.js → store-BR9Voi5E.js} +1 -1
- package/dist/trash-2-BKhar6Hs.js +32 -0
- package/dist/{trending-up-C-85AwGT.js → trending-up-Dohgd4t_.js} +1 -1
- package/dist/{triangle-alert-BOhfGgmh.js → triangle-alert-i-XQL9Rd.js} +1 -1
- package/dist/{truck-CtDjNFbi.js → truck-C0v_hbLR.js} +1 -1
- package/dist/{useAnalytics-ph7eTIK6.js → useAnalytics-DS8n0xgg.js} +40 -40
- package/dist/useAssistant-D4v3oxD3.js +84 -0
- package/dist/{useCustomers-bS3a4ytk.js → useCustomers-BmTNGxiI.js} +24 -24
- package/dist/{useFleet-BdETplNE.js → useFleet-DKqXZ16m.js} +133 -109
- package/dist/useImportExport-DHr-SWSw.js +55 -0
- package/dist/{useInventory-Dwn18FPz.js → useInventory-DkyiVY_A.js} +95 -75
- package/dist/{useOrders-D_3_hGMp.js → useOrders-Cfk1GLiq.js} +42 -42
- package/dist/useReports-CTqZr-AB.js +78 -0
- package/dist/{useRoutes-v4aBaS-E.js → useRoutes-BQWO607N.js} +31 -31
- package/dist/useSettings-CkDH_-gM.js +81 -0
- package/dist/{useTracking-De2KIUNu.js → useTracking-B-va1kO3.js} +22 -22
- package/dist/{user-Dz5TJZFs.js → user-jyFU3lXk.js} +1 -1
- package/dist/{users-g2N0eL-Z.js → users-DZ-ilS6B.js} +1 -1
- package/dist/{warehouse-D3WWDeTX.js → warehouse-6m5kXMLu.js} +1 -1
- package/dist/{wrench-CmxY1n4I.js → wrench-CANXWxF-.js} +1 -1
- package/package.json +1 -1
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +31 -3
- package/src/movethewheels/components/FormError.tsx +25 -0
- package/src/movethewheels/components/StatusBadge.tsx +18 -37
- package/src/movethewheels/constants/index.ts +67 -26
- package/src/movethewheels/hooks/index.ts +12 -0
- package/src/movethewheels/hooks/useAnalytics.ts +20 -6
- package/src/movethewheels/hooks/useAssistant.ts +74 -0
- package/src/movethewheels/hooks/useFleet.ts +170 -59
- package/src/movethewheels/hooks/useImportExport.ts +101 -0
- package/src/movethewheels/hooks/useInventory.ts +107 -0
- package/src/movethewheels/hooks/useReports.ts +158 -0
- package/src/movethewheels/hooks/useSettings.ts +120 -0
- package/src/movethewheels/pages/AIAssistantPage.tsx +53 -15
- package/src/movethewheels/pages/AnalyticsPage.tsx +67 -64
- package/src/movethewheels/pages/CustomerDetailsPage.tsx +154 -21
- package/src/movethewheels/pages/CustomersPage.tsx +1 -1
- package/src/movethewheels/pages/DashboardPage.tsx +42 -22
- package/src/movethewheels/pages/DriverDetailsPage.tsx +160 -3
- package/src/movethewheels/pages/DriversPage.tsx +6 -2
- package/src/movethewheels/pages/FleetPage.tsx +96 -38
- package/src/movethewheels/pages/ImportExportPage.tsx +174 -68
- package/src/movethewheels/pages/InventoryPage.tsx +66 -28
- package/src/movethewheels/pages/LiveTrackingPage.tsx +12 -3
- package/src/movethewheels/pages/MarketplacePage.tsx +87 -45
- package/src/movethewheels/pages/OrderDetailsPage.tsx +2 -2
- package/src/movethewheels/pages/ProductDetailsPage.tsx +146 -3
- package/src/movethewheels/pages/ProductsPage.tsx +5 -1
- package/src/movethewheels/pages/ReportsPage.tsx +194 -90
- package/src/movethewheels/pages/RouteDetailsPage.tsx +290 -36
- package/src/movethewheels/pages/RoutesPage.tsx +4 -9
- package/src/movethewheels/pages/SettingsPage.tsx +234 -56
- package/src/movethewheels/pages/TrackingPage.tsx +6 -6
- package/src/movethewheels/pages/VehicleDetailsPage.tsx +158 -2
- package/src/movethewheels/pages/VehiclesPage.tsx +5 -1
- package/src/movethewheels/pages/WarehouseDetailsPage.tsx +224 -2
- package/src/movethewheels/pages/WarehousesPage.tsx +5 -1
- package/src/movethewheels/providers/MoveTheWheelsProvider.tsx +7 -6
- package/src/movethewheels/store/movethewheelsStore.ts +1 -1
- package/dist/AnalyticsPage-CCLfHgQZ.js +0 -212
- package/dist/CustomerDetailsPage-I6cdDHUi.js +0 -265
- package/dist/DriverDetailsPage-rg_pGNuP.js +0 -330
- package/dist/FleetPage-DddXt8r8.js +0 -332
- package/dist/ImportExportPage-BW6qO3kc.js +0 -248
- package/dist/InventoryPage-rMGuaJN-.js +0 -222
- package/dist/MarketplacePage-DKrXAv62.js +0 -219
- package/dist/ProductDetailsPage-CFGcbaHo.js +0 -195
- package/dist/ReportsPage-Bb7_90rK.js +0 -235
- package/dist/RouteDetailsPage-CVtDVb1N.js +0 -282
- package/dist/RoutesPage-s57PtgcQ.js +0 -163
- package/dist/SettingsPage-BYNCBOpN.js +0 -298
- package/dist/StatusBadge-CijYQXtb.js +0 -209
- package/dist/VehicleDetailsPage-3YDMPsPs.js +0 -220
- package/dist/WarehouseDetailsPage-Db7KeN-d.js +0 -238
- package/dist/graphqlClient-CdJyR_ed.js +0 -55
- package/dist/navigation-BgnOfsVd.js +0 -6
- package/dist/route-Dp9JiN_E.js +0 -51
- package/dist/settings-3Rw5NwFF.js +0 -28
- package/src/movethewheels/constants/mockData.ts +0 -1342
- /package/dist/{formatters-_vJlC-47.js → formatters-CF2S2l1m.js} +0 -0
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Warehouse Details Page
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { useState } from 'react';
|
|
5
6
|
import { useParams } from 'react-router-dom';
|
|
6
|
-
import { Warehouse, ArrowLeft, Edit, MapPin, Clock, Users, Box } from 'lucide-react';
|
|
7
|
+
import { Warehouse, ArrowLeft, Edit, MapPin, Clock, Users, Box, Save } from 'lucide-react';
|
|
7
8
|
import { PageLayout, LoadingState, ErrorState } from '../components/PageLayout';
|
|
8
9
|
import {
|
|
9
10
|
Card,
|
|
@@ -13,12 +14,232 @@ import {
|
|
|
13
14
|
Button,
|
|
14
15
|
Badge,
|
|
15
16
|
Progress,
|
|
17
|
+
Input,
|
|
18
|
+
Label,
|
|
19
|
+
Select,
|
|
20
|
+
SelectContent,
|
|
21
|
+
SelectItem,
|
|
22
|
+
SelectTrigger,
|
|
23
|
+
SelectValue,
|
|
16
24
|
} from '../components/ui';
|
|
17
25
|
import { EmphasisPanel, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';
|
|
18
|
-
import { useWarehouse } from '../hooks/useInventory';
|
|
26
|
+
import { useWarehouse, useInventory } from '../hooks/useInventory';
|
|
19
27
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
20
28
|
import { formatAddress } from '../utils/formatters';
|
|
21
29
|
import { joinPath } from '../utils/navigation';
|
|
30
|
+
import { FormError } from '../components/FormError';
|
|
31
|
+
|
|
32
|
+
const WAREHOUSE_TYPE_OPTIONS = [
|
|
33
|
+
{ value: 'DISTRIBUTION', label: 'Distribution' },
|
|
34
|
+
{ value: 'FULFILLMENT', label: 'Fulfillment' },
|
|
35
|
+
{ value: 'COLD_STORAGE', label: 'Cold Storage' },
|
|
36
|
+
{ value: 'CROSS_DOCK', label: 'Cross-Dock' },
|
|
37
|
+
{ value: 'RETAIL', label: 'Retail' },
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
function NewWarehouseForm() {
|
|
41
|
+
const { basePath, navigate } = useMoveTheWheels();
|
|
42
|
+
const { createWarehouse } = useInventory();
|
|
43
|
+
const [form, setForm] = useState({
|
|
44
|
+
code: '',
|
|
45
|
+
name: '',
|
|
46
|
+
type: 'DISTRIBUTION',
|
|
47
|
+
street: '',
|
|
48
|
+
city: '',
|
|
49
|
+
state: '',
|
|
50
|
+
postalCode: '',
|
|
51
|
+
country: 'USA',
|
|
52
|
+
totalCapacity: '',
|
|
53
|
+
});
|
|
54
|
+
const [submitting, setSubmitting] = useState(false);
|
|
55
|
+
const [error, setError] = useState<string | null>(null);
|
|
56
|
+
|
|
57
|
+
const goBack = () => navigate?.(joinPath(basePath, 'inventory/warehouses'));
|
|
58
|
+
|
|
59
|
+
const update = (field: keyof typeof form, value: string) =>
|
|
60
|
+
setForm((prev) => ({ ...prev, [field]: value }));
|
|
61
|
+
|
|
62
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
if (!form.code.trim() || !form.name.trim()) {
|
|
65
|
+
setError('Warehouse code and name are required.');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!form.street.trim() || !form.city.trim()) {
|
|
69
|
+
setError('A street and city are required for the warehouse address.');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
setSubmitting(true);
|
|
73
|
+
setError(null);
|
|
74
|
+
try {
|
|
75
|
+
const totalCapacity = form.totalCapacity.trim() ? Number(form.totalCapacity) : undefined;
|
|
76
|
+
const created = await createWarehouse({
|
|
77
|
+
code: form.code.trim(),
|
|
78
|
+
name: form.name.trim(),
|
|
79
|
+
type: form.type,
|
|
80
|
+
address: {
|
|
81
|
+
street: form.street.trim(),
|
|
82
|
+
city: form.city.trim(),
|
|
83
|
+
state: form.state.trim(),
|
|
84
|
+
postalCode: form.postalCode.trim(),
|
|
85
|
+
country: form.country.trim(),
|
|
86
|
+
},
|
|
87
|
+
totalCapacity:
|
|
88
|
+
totalCapacity !== undefined && !Number.isNaN(totalCapacity) ? totalCapacity : undefined,
|
|
89
|
+
});
|
|
90
|
+
navigate?.(joinPath(basePath, `inventory/warehouses/${created.id}`));
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.error('Failed to create warehouse:', err);
|
|
93
|
+
setError(err instanceof Error ? err.message : 'Failed to create warehouse. Please try again.');
|
|
94
|
+
setSubmitting(false);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<PageLayout
|
|
100
|
+
title="Add Warehouse"
|
|
101
|
+
subtitle="Register a storage and fulfilment site"
|
|
102
|
+
icon={<Warehouse size={24} />}
|
|
103
|
+
headerActions={
|
|
104
|
+
<div className="flex gap-2">
|
|
105
|
+
<Button variant="outline" onClick={goBack} disabled={submitting}>
|
|
106
|
+
<ArrowLeft size={16} /> Cancel
|
|
107
|
+
</Button>
|
|
108
|
+
<Button onClick={handleSubmit} disabled={submitting}>
|
|
109
|
+
<Save size={16} /> {submitting ? 'Saving...' : 'Add Warehouse'}
|
|
110
|
+
</Button>
|
|
111
|
+
</div>
|
|
112
|
+
}
|
|
113
|
+
>
|
|
114
|
+
<PagePurpose icon={<Warehouse size={18} />}>
|
|
115
|
+
Add a warehouse so you can store inventory and fulfil orders from it. A code, name, type and
|
|
116
|
+
location get it on the network — set a total capacity to track utilization.
|
|
117
|
+
</PagePurpose>
|
|
118
|
+
|
|
119
|
+
<form onSubmit={handleSubmit} className="max-w-2xl space-y-6">
|
|
120
|
+
<FormError message={error} />
|
|
121
|
+
<EmphasisPanel>
|
|
122
|
+
<h2 className="text-base font-semibold text-text-primary mb-4">Warehouse Details</h2>
|
|
123
|
+
<div className="space-y-4">
|
|
124
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
125
|
+
<div className="space-y-2">
|
|
126
|
+
<Label htmlFor="code">
|
|
127
|
+
Code <span className="text-status-error-text">*</span>
|
|
128
|
+
</Label>
|
|
129
|
+
<Input
|
|
130
|
+
id="code"
|
|
131
|
+
value={form.code}
|
|
132
|
+
onChange={(e) => update('code', e.target.value)}
|
|
133
|
+
placeholder="WH-SF-01"
|
|
134
|
+
required
|
|
135
|
+
/>
|
|
136
|
+
</div>
|
|
137
|
+
<div className="space-y-2">
|
|
138
|
+
<Label htmlFor="name">
|
|
139
|
+
Name <span className="text-status-error-text">*</span>
|
|
140
|
+
</Label>
|
|
141
|
+
<Input
|
|
142
|
+
id="name"
|
|
143
|
+
value={form.name}
|
|
144
|
+
onChange={(e) => update('name', e.target.value)}
|
|
145
|
+
placeholder="San Francisco DC"
|
|
146
|
+
required
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
<div className="space-y-2">
|
|
150
|
+
<Label htmlFor="type">
|
|
151
|
+
Type <span className="text-status-error-text">*</span>
|
|
152
|
+
</Label>
|
|
153
|
+
<Select value={form.type} onValueChange={(value) => update('type', value)}>
|
|
154
|
+
<SelectTrigger id="type">
|
|
155
|
+
<SelectValue />
|
|
156
|
+
</SelectTrigger>
|
|
157
|
+
<SelectContent>
|
|
158
|
+
{WAREHOUSE_TYPE_OPTIONS.map((option) => (
|
|
159
|
+
<SelectItem key={option.value} value={option.value}>
|
|
160
|
+
{option.label}
|
|
161
|
+
</SelectItem>
|
|
162
|
+
))}
|
|
163
|
+
</SelectContent>
|
|
164
|
+
</Select>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
<div className="space-y-2">
|
|
168
|
+
<Label htmlFor="totalCapacity">Total Capacity (sq ft)</Label>
|
|
169
|
+
<Input
|
|
170
|
+
id="totalCapacity"
|
|
171
|
+
type="number"
|
|
172
|
+
min="0"
|
|
173
|
+
value={form.totalCapacity}
|
|
174
|
+
onChange={(e) => update('totalCapacity', e.target.value)}
|
|
175
|
+
placeholder="50000"
|
|
176
|
+
/>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
</EmphasisPanel>
|
|
180
|
+
|
|
181
|
+
<Card>
|
|
182
|
+
<CardHeader>
|
|
183
|
+
<CardTitle className="flex items-center gap-2">
|
|
184
|
+
<MapPin size={18} /> Address <span className="text-status-error-text">*</span>
|
|
185
|
+
</CardTitle>
|
|
186
|
+
</CardHeader>
|
|
187
|
+
<CardContent className="space-y-4">
|
|
188
|
+
<div className="space-y-2">
|
|
189
|
+
<Label htmlFor="street">Street</Label>
|
|
190
|
+
<Input
|
|
191
|
+
id="street"
|
|
192
|
+
value={form.street}
|
|
193
|
+
onChange={(e) => update('street', e.target.value)}
|
|
194
|
+
placeholder="500 Industrial Way"
|
|
195
|
+
/>
|
|
196
|
+
</div>
|
|
197
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
198
|
+
<div className="space-y-2">
|
|
199
|
+
<Label htmlFor="city">City</Label>
|
|
200
|
+
<Input
|
|
201
|
+
id="city"
|
|
202
|
+
value={form.city}
|
|
203
|
+
onChange={(e) => update('city', e.target.value)}
|
|
204
|
+
placeholder="San Francisco"
|
|
205
|
+
/>
|
|
206
|
+
</div>
|
|
207
|
+
<div className="space-y-2">
|
|
208
|
+
<Label htmlFor="state">State</Label>
|
|
209
|
+
<Input
|
|
210
|
+
id="state"
|
|
211
|
+
value={form.state}
|
|
212
|
+
onChange={(e) => update('state', e.target.value)}
|
|
213
|
+
placeholder="CA"
|
|
214
|
+
/>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
218
|
+
<div className="space-y-2">
|
|
219
|
+
<Label htmlFor="postalCode">ZIP / Postal Code</Label>
|
|
220
|
+
<Input
|
|
221
|
+
id="postalCode"
|
|
222
|
+
value={form.postalCode}
|
|
223
|
+
onChange={(e) => update('postalCode', e.target.value)}
|
|
224
|
+
placeholder="94103"
|
|
225
|
+
/>
|
|
226
|
+
</div>
|
|
227
|
+
<div className="space-y-2">
|
|
228
|
+
<Label htmlFor="country">Country</Label>
|
|
229
|
+
<Input
|
|
230
|
+
id="country"
|
|
231
|
+
value={form.country}
|
|
232
|
+
onChange={(e) => update('country', e.target.value)}
|
|
233
|
+
placeholder="USA"
|
|
234
|
+
/>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</CardContent>
|
|
238
|
+
</Card>
|
|
239
|
+
</form>
|
|
240
|
+
</PageLayout>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
22
243
|
|
|
23
244
|
export default function WarehouseDetailsPage() {
|
|
24
245
|
const { warehouseId } = useParams<{ warehouseId: string }>();
|
|
@@ -28,6 +249,7 @@ export default function WarehouseDetailsPage() {
|
|
|
28
249
|
const goBack = () => navigate?.(joinPath(basePath, 'inventory/warehouses'));
|
|
29
250
|
const goTo = (path: string) => navigate?.(joinPath(basePath, path));
|
|
30
251
|
|
|
252
|
+
if (!warehouseId) return <NewWarehouseForm />;
|
|
31
253
|
if (isLoading) return <LoadingState message="Loading warehouse details..." />;
|
|
32
254
|
if (error || !warehouse) return <ErrorState title="Warehouse not found" onRetry={refetch} />;
|
|
33
255
|
|
|
@@ -99,7 +99,11 @@ export default function WarehousesPage() {
|
|
|
99
99
|
icon={<Warehouse size={24} />}
|
|
100
100
|
headerActions={
|
|
101
101
|
<CTAOverflowMenu
|
|
102
|
-
primary={{
|
|
102
|
+
primary={{
|
|
103
|
+
label: 'Add Warehouse',
|
|
104
|
+
icon: <Plus size={16} />,
|
|
105
|
+
onSelect: () => goTo('inventory/warehouses/new'),
|
|
106
|
+
}}
|
|
103
107
|
actions={[{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() }]}
|
|
104
108
|
/>
|
|
105
109
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { createContext, useContext, useMemo, type FC, type PropsWithChildren } from 'react';
|
|
9
9
|
import { MemoryRouter } from 'react-router-dom';
|
|
10
10
|
import type { MoveTheWheelsRootProps, MoveTheWheelsContextValue } from '../types';
|
|
11
|
+
import { joinPath } from '../utils/navigation';
|
|
11
12
|
|
|
12
13
|
const MoveTheWheelsContext = createContext<MoveTheWheelsContextValue | null>(null);
|
|
13
14
|
|
|
@@ -54,13 +55,13 @@ export function useMoveTheWheelsNavigate(): (path: string) => void {
|
|
|
54
55
|
const { navigate, basePath } = useMoveTheWheels();
|
|
55
56
|
|
|
56
57
|
return (path: string) => {
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
|
|
58
|
+
// Genuine external URLs (http/https or protocol-relative) pass through
|
|
59
|
+
// untouched. Everything else is an in-app path and MUST be resolved against
|
|
60
|
+
// basePath — otherwise a leading "/" would escape the microfrontend mount.
|
|
61
|
+
if (/^(https?:)?\/\//i.test(path)) {
|
|
60
62
|
navigate(path);
|
|
61
|
-
|
|
62
|
-
const cleanBase = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
|
|
63
|
-
navigate(`${cleanBase}/${path}`);
|
|
63
|
+
return;
|
|
64
64
|
}
|
|
65
|
+
navigate(joinPath(basePath, path));
|
|
65
66
|
};
|
|
66
67
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* MoveTheWheels Zustand Store
|
|
3
3
|
*
|
|
4
4
|
* Manages UI state for the microfrontend.
|
|
5
|
-
* Server/entity data comes from hooks
|
|
5
|
+
* Server/entity data comes from hooks that query the live backend via GraphQL.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { create } from 'zustand';
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import { M as e, d as t, f as n, g as r, h as i, i as a } from "./PageLayout-D3N8MCTm.js";
|
|
2
|
-
import { t as o } from "./chart-column-D1Ym15-S.js";
|
|
3
|
-
import { t as s } from "./dollar-sign-IB4O0wuQ.js";
|
|
4
|
-
import { t as c } from "./package-BE7U0wQE.js";
|
|
5
|
-
import { t as l } from "./trending-up-C-85AwGT.js";
|
|
6
|
-
import { t as u } from "./truck-CtDjNFbi.js";
|
|
7
|
-
import { t as d } from "./users-g2N0eL-Z.js";
|
|
8
|
-
import { i as f, r as p, t as m } from "./useAnalytics-ph7eTIK6.js";
|
|
9
|
-
import { r as h, t as g } from "./MetricCard-B7yMyvMX.js";
|
|
10
|
-
import { n as _ } from "./formatters-_vJlC-47.js";
|
|
11
|
-
import { jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
12
|
-
import { EmphasisPanel as b, PagePurpose as x } from "@burdenoff/fe-libs/ui";
|
|
13
|
-
//#region src/movethewheels/pages/AnalyticsPage.tsx
|
|
14
|
-
function S() {
|
|
15
|
-
let { analytics: S } = m(), { orderData: C } = f(), { fleetData: w } = p();
|
|
16
|
-
return /* @__PURE__ */ y(a, {
|
|
17
|
-
title: "Analytics",
|
|
18
|
-
subtitle: "Business performance and insights",
|
|
19
|
-
icon: /* @__PURE__ */ v(o, { size: 24 }),
|
|
20
|
-
children: [
|
|
21
|
-
/* @__PURE__ */ v(x, {
|
|
22
|
-
icon: /* @__PURE__ */ v(o, { size: 18 }),
|
|
23
|
-
children: "See how the operation is really performing. Track order volume, revenue, on-time rate and customer satisfaction over time so you can spot trends, find bottlenecks, and decide where to invest — whether that's more vehicles, better routes, or new customers."
|
|
24
|
-
}),
|
|
25
|
-
/* @__PURE__ */ y(h, {
|
|
26
|
-
columns: 5,
|
|
27
|
-
children: [
|
|
28
|
-
/* @__PURE__ */ v(g, {
|
|
29
|
-
label: "Total Orders",
|
|
30
|
-
value: S.overview.totalOrders.toLocaleString(),
|
|
31
|
-
icon: /* @__PURE__ */ v(c, { size: 20 }),
|
|
32
|
-
change: "+8.2%",
|
|
33
|
-
changeType: "positive",
|
|
34
|
-
trend: "up"
|
|
35
|
-
}),
|
|
36
|
-
/* @__PURE__ */ v(g, {
|
|
37
|
-
treatment: "glass",
|
|
38
|
-
glow: !0,
|
|
39
|
-
label: "Revenue",
|
|
40
|
-
value: _(S.overview.totalRevenue),
|
|
41
|
-
icon: /* @__PURE__ */ v(s, { size: 20 }),
|
|
42
|
-
change: "+12.5%",
|
|
43
|
-
changeType: "positive",
|
|
44
|
-
trend: "up"
|
|
45
|
-
}),
|
|
46
|
-
/* @__PURE__ */ v(g, {
|
|
47
|
-
label: "Active Vehicles",
|
|
48
|
-
value: S.overview.activeVehicles,
|
|
49
|
-
icon: /* @__PURE__ */ v(u, { size: 20 })
|
|
50
|
-
}),
|
|
51
|
-
/* @__PURE__ */ v(g, {
|
|
52
|
-
label: "On-Time Rate",
|
|
53
|
-
value: `${S.overview.onTimeDeliveryRate}%`,
|
|
54
|
-
icon: /* @__PURE__ */ v(l, { size: 20 }),
|
|
55
|
-
changeType: S.overview.onTimeDeliveryRate >= 90 ? "positive" : "negative"
|
|
56
|
-
}),
|
|
57
|
-
/* @__PURE__ */ v(g, {
|
|
58
|
-
label: "Satisfaction",
|
|
59
|
-
value: S.overview.customerSatisfaction.toFixed(1),
|
|
60
|
-
icon: /* @__PURE__ */ v(d, { size: 20 }),
|
|
61
|
-
subtitle: "out of 5"
|
|
62
|
-
})
|
|
63
|
-
]
|
|
64
|
-
}),
|
|
65
|
-
/* @__PURE__ */ y("div", {
|
|
66
|
-
className: "grid grid-cols-1 lg:grid-cols-2 gap-6",
|
|
67
|
-
children: [/* @__PURE__ */ y(t, { children: [/* @__PURE__ */ v(i, { children: /* @__PURE__ */ v(r, { children: "Order Trends" }) }), /* @__PURE__ */ y(n, { children: [/* @__PURE__ */ v("div", {
|
|
68
|
-
className: "h-64 flex items-center justify-center bg-bg-sunken/50 rounded-lg",
|
|
69
|
-
children: /* @__PURE__ */ y("div", {
|
|
70
|
-
className: "text-center text-text-secondary",
|
|
71
|
-
children: [
|
|
72
|
-
/* @__PURE__ */ v(o, {
|
|
73
|
-
size: 48,
|
|
74
|
-
className: "mx-auto mb-2 opacity-50"
|
|
75
|
-
}),
|
|
76
|
-
/* @__PURE__ */ v("p", { children: "Order trend chart" }),
|
|
77
|
-
/* @__PURE__ */ v("p", {
|
|
78
|
-
className: "text-xs",
|
|
79
|
-
children: "(Chart library integration needed)"
|
|
80
|
-
})
|
|
81
|
-
]
|
|
82
|
-
})
|
|
83
|
-
}), /* @__PURE__ */ v("div", {
|
|
84
|
-
className: "mt-4 grid grid-cols-4 gap-2",
|
|
85
|
-
children: C.trends.slice(-4).map((e) => /* @__PURE__ */ y("div", {
|
|
86
|
-
className: "text-center p-2 bg-bg-sunken/50 rounded",
|
|
87
|
-
children: [/* @__PURE__ */ v("p", {
|
|
88
|
-
className: "text-xs text-text-secondary",
|
|
89
|
-
children: e.date.split("-").slice(1).join("/")
|
|
90
|
-
}), /* @__PURE__ */ v("p", {
|
|
91
|
-
className: "font-medium",
|
|
92
|
-
children: e.orders
|
|
93
|
-
})]
|
|
94
|
-
}, e.date))
|
|
95
|
-
})] })] }), /* @__PURE__ */ y(t, { children: [/* @__PURE__ */ v(i, { children: /* @__PURE__ */ v(r, { children: "Revenue Trends" }) }), /* @__PURE__ */ y(n, { children: [/* @__PURE__ */ v("div", {
|
|
96
|
-
className: "h-64 flex items-center justify-center bg-bg-sunken/50 rounded-lg",
|
|
97
|
-
children: /* @__PURE__ */ y("div", {
|
|
98
|
-
className: "text-center text-text-secondary",
|
|
99
|
-
children: [/* @__PURE__ */ v(l, {
|
|
100
|
-
size: 48,
|
|
101
|
-
className: "mx-auto mb-2 opacity-50"
|
|
102
|
-
}), /* @__PURE__ */ v("p", { children: "Revenue trend chart" })]
|
|
103
|
-
})
|
|
104
|
-
}), /* @__PURE__ */ v("div", {
|
|
105
|
-
className: "mt-4 grid grid-cols-5 gap-2",
|
|
106
|
-
children: S.trends.revenue.map((e) => /* @__PURE__ */ y("div", {
|
|
107
|
-
className: "text-center p-2 bg-bg-sunken/50 rounded",
|
|
108
|
-
children: [/* @__PURE__ */ v("p", {
|
|
109
|
-
className: "text-xs text-text-secondary",
|
|
110
|
-
children: e.month
|
|
111
|
-
}), /* @__PURE__ */ y("p", {
|
|
112
|
-
className: "font-medium text-sm",
|
|
113
|
-
children: [_(e.revenue / 1e3), "k"]
|
|
114
|
-
})]
|
|
115
|
-
}, e.month))
|
|
116
|
-
})] })] })]
|
|
117
|
-
}),
|
|
118
|
-
/* @__PURE__ */ y("div", {
|
|
119
|
-
className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
|
|
120
|
-
children: [
|
|
121
|
-
/* @__PURE__ */ y(t, { children: [/* @__PURE__ */ v(i, { children: /* @__PURE__ */ v(r, { children: "Orders by Status" }) }), /* @__PURE__ */ v(n, {
|
|
122
|
-
className: "space-y-3",
|
|
123
|
-
children: C.byStatus.filter((e) => e.count > 0).map(({ status: t, count: n }) => /* @__PURE__ */ y("div", {
|
|
124
|
-
className: "flex items-center justify-between",
|
|
125
|
-
children: [/* @__PURE__ */ v("span", {
|
|
126
|
-
className: "text-sm capitalize",
|
|
127
|
-
children: t.replace("_", " ")
|
|
128
|
-
}), /* @__PURE__ */ y("div", {
|
|
129
|
-
className: "flex items-center gap-2",
|
|
130
|
-
children: [/* @__PURE__ */ v(e, {
|
|
131
|
-
value: n / S.overview.totalOrders * 100,
|
|
132
|
-
className: "w-20 h-2"
|
|
133
|
-
}), /* @__PURE__ */ v("span", {
|
|
134
|
-
className: "font-medium w-8 text-right",
|
|
135
|
-
children: n
|
|
136
|
-
})]
|
|
137
|
-
})]
|
|
138
|
-
}, t))
|
|
139
|
-
})] }),
|
|
140
|
-
/* @__PURE__ */ y(t, { children: [/* @__PURE__ */ v(i, { children: /* @__PURE__ */ v(r, { children: "Fleet Performance" }) }), /* @__PURE__ */ y(n, {
|
|
141
|
-
className: "space-y-4",
|
|
142
|
-
children: [
|
|
143
|
-
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ y("div", {
|
|
144
|
-
className: "flex justify-between text-sm mb-1",
|
|
145
|
-
children: [/* @__PURE__ */ v("span", { children: "Vehicle Utilization" }), /* @__PURE__ */ y("span", { children: [w.vehicleUtilization.toFixed(0), "%"] })]
|
|
146
|
-
}), /* @__PURE__ */ v(e, { value: w.vehicleUtilization })] }),
|
|
147
|
-
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ y("div", {
|
|
148
|
-
className: "flex justify-between text-sm mb-1",
|
|
149
|
-
children: [/* @__PURE__ */ v("span", { children: "Avg Fuel Level" }), /* @__PURE__ */ y("span", { children: [w.avgFuelLevel.toFixed(0), "%"] })]
|
|
150
|
-
}), /* @__PURE__ */ v(e, { value: w.avgFuelLevel })] }),
|
|
151
|
-
/* @__PURE__ */ y("div", {
|
|
152
|
-
className: "pt-2",
|
|
153
|
-
children: [/* @__PURE__ */ v("p", {
|
|
154
|
-
className: "text-sm text-text-secondary mb-2",
|
|
155
|
-
children: "Vehicles by Type"
|
|
156
|
-
}), w.vehiclesByType.map(({ type: e, count: t }) => /* @__PURE__ */ y("div", {
|
|
157
|
-
className: "flex justify-between text-sm py-1",
|
|
158
|
-
children: [/* @__PURE__ */ v("span", {
|
|
159
|
-
className: "capitalize",
|
|
160
|
-
children: e
|
|
161
|
-
}), /* @__PURE__ */ v("span", {
|
|
162
|
-
className: "font-medium",
|
|
163
|
-
children: t
|
|
164
|
-
})]
|
|
165
|
-
}, e))]
|
|
166
|
-
})
|
|
167
|
-
]
|
|
168
|
-
})] }),
|
|
169
|
-
/* @__PURE__ */ y(b, {
|
|
170
|
-
className: "space-y-4",
|
|
171
|
-
children: [
|
|
172
|
-
/* @__PURE__ */ v("h2", {
|
|
173
|
-
className: "text-base font-semibold text-text-primary",
|
|
174
|
-
children: "Performance Metrics"
|
|
175
|
-
}),
|
|
176
|
-
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
177
|
-
className: "text-sm text-text-secondary",
|
|
178
|
-
children: "On-Time Pickup"
|
|
179
|
-
}), /* @__PURE__ */ y("p", {
|
|
180
|
-
className: "text-2xl font-bold",
|
|
181
|
-
children: [S.performance.onTimePickup, "%"]
|
|
182
|
-
})] }),
|
|
183
|
-
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
184
|
-
className: "text-sm text-text-secondary",
|
|
185
|
-
children: "On-Time Delivery"
|
|
186
|
-
}), /* @__PURE__ */ y("p", {
|
|
187
|
-
className: "text-2xl font-bold",
|
|
188
|
-
children: [S.performance.onTimeDelivery, "%"]
|
|
189
|
-
})] }),
|
|
190
|
-
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
191
|
-
className: "text-sm text-text-secondary",
|
|
192
|
-
children: "Damaged Items"
|
|
193
|
-
}), /* @__PURE__ */ y("p", {
|
|
194
|
-
className: "text-2xl font-bold text-status-success-text",
|
|
195
|
-
children: [S.performance.damagedItems, "%"]
|
|
196
|
-
})] }),
|
|
197
|
-
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
|
|
198
|
-
className: "text-sm text-text-secondary",
|
|
199
|
-
children: "Driver Ratings"
|
|
200
|
-
}), /* @__PURE__ */ y("p", {
|
|
201
|
-
className: "text-2xl font-bold",
|
|
202
|
-
children: [S.performance.driverRatings, "/5"]
|
|
203
|
-
})] })
|
|
204
|
-
]
|
|
205
|
-
})
|
|
206
|
-
]
|
|
207
|
-
})
|
|
208
|
-
]
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
//#endregion
|
|
212
|
-
export { S as default };
|