@burdenoff/microfe-movethewheels 2026.1031.2 → 2026.1031.4
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/MoveTheWheelsRoot.js +121 -104
- package/dist/MoveTheWheelsRoutes.js +142 -133
- package/dist/components/DocumentsCard.js +11 -11
- package/dist/components/ProofOfDeliveryCard.js +13 -13
- package/dist/components/ShipmentRiskDialog.js +24 -24
- package/dist/components/ShippingQuoteResults.js +46 -46
- package/dist/components/TrackingAlertList.js +17 -17
- package/dist/generated/tracking-quality-operations.d.ts +140 -0
- package/dist/hooks/useEntityImport.js +68 -0
- package/dist/hooks/useOrderDispatch.js +17 -17
- package/dist/movethewheels/hooks/useEntityImport.d.ts +19 -0
- package/dist/movethewheels/pages/ImportExportPage.d.ts +9 -0
- package/dist/movethewheels/pages/SettingsPage.d.ts +1 -0
- package/dist/movethewheels/providers/ModuleSettingsProvider.d.ts +17 -0
- package/dist/movethewheels/utils/entityImport.d.ts +109 -0
- package/dist/movethewheels/utils/formatters.d.ts +23 -3
- package/dist/movethewheels/utils/moduleSettings.d.ts +52 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/arrow-down-up.js +22 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/bell.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js +30 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/file-up.js +22 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/key-round.js +14 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/plug.js +22 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/rotate-ccw.js +11 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/settings.js +13 -0
- package/dist/pages/AnalyticsPage.js +27 -27
- package/dist/pages/CreateOrderPage.js +340 -317
- package/dist/pages/CustomerDetailsPage.js +246 -246
- package/dist/pages/CustomersPage.js +88 -79
- package/dist/pages/DashboardPage.js +24 -24
- package/dist/pages/DeliveryCapturePage.js +74 -74
- package/dist/pages/DriverDetailsPage.js +337 -337
- package/dist/pages/DriversPage.js +119 -110
- package/dist/pages/FinancePage.js +26 -26
- package/dist/pages/ImportExportPage.js +435 -0
- package/dist/pages/InventoryPage.js +28 -28
- package/dist/pages/LiveTrackingPage.js +108 -108
- package/dist/pages/MarketplacePage.js +44 -44
- package/dist/pages/OrderDetailsPage.js +306 -306
- package/dist/pages/OrdersListPage.js +27 -27
- package/dist/pages/ProductDetailsPage.js +89 -89
- package/dist/pages/ProductsPage.js +86 -77
- package/dist/pages/RouteDetailsPage.js +282 -285
- package/dist/pages/RoutesPage.js +78 -78
- package/dist/pages/SettingsPage.js +459 -0
- package/dist/pages/TrackingPage.js +41 -41
- package/dist/pages/VehicleDetailsPage.js +207 -207
- package/dist/pages/VehiclesPage.js +100 -90
- package/dist/pages/WarehouseDetailsPage.js +132 -132
- package/dist/pages/WarehousesPage.js +97 -88
- package/dist/providers/ModuleSettingsProvider.js +74 -0
- package/dist/utils/entityImport.js +73 -0
- package/dist/utils/formatters.js +53 -26
- package/dist/utils/moduleSettings.js +132 -0
- package/package.json +4 -2
- package/src/generated/tracking-quality-operations.ts +184 -0
- package/src/movethewheels/MoveTheWheelsRoot.tsx +22 -3
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +13 -0
- package/src/movethewheels/hooks/useEntityImport.ts +108 -0
- package/src/movethewheels/pages/CreateOrderPage.tsx +38 -6
- package/src/movethewheels/pages/CustomersPage.tsx +6 -1
- package/src/movethewheels/pages/DriversPage.tsx +6 -0
- package/src/movethewheels/pages/ImportExportPage.tsx +483 -0
- package/src/movethewheels/pages/ProductsPage.tsx +16 -3
- package/src/movethewheels/pages/RouteDetailsPage.tsx +3 -6
- package/src/movethewheels/pages/RoutesPage.tsx +2 -2
- package/src/movethewheels/pages/SettingsPage.tsx +516 -0
- package/src/movethewheels/pages/VehicleDetailsPage.tsx +4 -2
- package/src/movethewheels/pages/VehiclesPage.tsx +8 -1
- package/src/movethewheels/pages/WarehousesPage.tsx +6 -1
- package/src/movethewheels/providers/ModuleSettingsProvider.tsx +133 -0
- package/src/movethewheels/utils/entityImport.ts +239 -0
- package/src/movethewheels/utils/formatters.ts +69 -10
- package/src/movethewheels/utils/moduleSettings.ts +224 -0
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { ArrowDownUp as e } from "../node_modules/lucide-react/dist/esm/icons/arrow-down-up.js";
|
|
2
|
+
import { CircleAlert as t } from "../node_modules/lucide-react/dist/esm/icons/circle-alert.js";
|
|
3
|
+
import { CircleCheckBig as n } from "../node_modules/lucide-react/dist/esm/icons/circle-check-big.js";
|
|
4
|
+
import { Download as r } from "../node_modules/lucide-react/dist/esm/icons/download.js";
|
|
5
|
+
import { FileSpreadsheet as i } from "../node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js";
|
|
6
|
+
import { FileUp as a } from "../node_modules/lucide-react/dist/esm/icons/file-up.js";
|
|
7
|
+
import { Info as o } from "../node_modules/lucide-react/dist/esm/icons/info.js";
|
|
8
|
+
import { LoaderCircle as s } from "../node_modules/lucide-react/dist/esm/icons/loader-circle.js";
|
|
9
|
+
import { ShieldCheck as c } from "../node_modules/lucide-react/dist/esm/icons/shield-check.js";
|
|
10
|
+
import { Upload as l } from "../node_modules/lucide-react/dist/esm/icons/upload.js";
|
|
11
|
+
import { joinPath as u } from "../utils/navigation.js";
|
|
12
|
+
import { useMoveTheWheels as d } from "../providers/MoveTheWheelsProvider.js";
|
|
13
|
+
import { Badge as f, Button as p, Card as m, CardContent as h, CardDescription as g, CardHeader as _, CardTitle as v, Checkbox as ee, Label as y, Select as b, SelectContent as te, SelectItem as ne, SelectTrigger as re, SelectValue as ie, Skeleton as x, Table as S, TableBody as C, TableCell as w, TableHead as T, TableHeader as E, TableRow as D } from "../components/ui.js";
|
|
14
|
+
import { PageLayout as ae } from "../components/PageLayout.js";
|
|
15
|
+
import { useEntityExport as O } from "../hooks/useEntityExport.js";
|
|
16
|
+
import { ExportStatusBanner as k } from "../components/ExportStatusBanner.js";
|
|
17
|
+
import { MTW_IMPORT_ENTITIES as A, MTW_IMPORT_MAX_ROWS as oe, buildCsvTemplate as se, detectImportFormat as ce, importEntity as le, isImportEntityType as j, summariseImport as M } from "../utils/entityImport.js";
|
|
18
|
+
import { useEntityImport as ue, useImportSpec as de } from "../hooks/useEntityImport.js";
|
|
19
|
+
import { useMemo as fe, useRef as pe, useState as N } from "react";
|
|
20
|
+
import { useSearchParams as P } from "react-router";
|
|
21
|
+
import { jsx as F, jsxs as I } from "react/jsx-runtime";
|
|
22
|
+
import { EmphasisPanel as L, PagePurpose as R } from "@burdenoff/fe-libs/ui";
|
|
23
|
+
//#region src/movethewheels/pages/ImportExportPage.tsx
|
|
24
|
+
var z = {
|
|
25
|
+
CUSTOMER: "customers",
|
|
26
|
+
VEHICLE: "fleet/vehicles",
|
|
27
|
+
DRIVER: "fleet/drivers",
|
|
28
|
+
WAREHOUSE: "inventory/warehouses",
|
|
29
|
+
CARGO_ITEM: "inventory/products"
|
|
30
|
+
}, me = [
|
|
31
|
+
{
|
|
32
|
+
entity: "orders",
|
|
33
|
+
label: "Orders",
|
|
34
|
+
noun: "order"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
entity: "customers",
|
|
38
|
+
label: "Customers",
|
|
39
|
+
noun: "customer"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
entity: "vehicles",
|
|
43
|
+
label: "Vehicles",
|
|
44
|
+
noun: "vehicle"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
entity: "drivers",
|
|
48
|
+
label: "Drivers",
|
|
49
|
+
noun: "driver"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
entity: "products",
|
|
53
|
+
label: "Products",
|
|
54
|
+
noun: "product"
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
function he(e, t, n) {
|
|
58
|
+
let r = URL.createObjectURL(new Blob([t], { type: n })), i = document.createElement("a");
|
|
59
|
+
i.href = r, i.download = e, document.body.appendChild(i), i.click(), i.remove(), URL.revokeObjectURL(r);
|
|
60
|
+
}
|
|
61
|
+
function ge(e) {
|
|
62
|
+
if (e.allowedValues?.length) return e.allowedValues.join(", ");
|
|
63
|
+
let t = [e.type.toLowerCase()];
|
|
64
|
+
return e.maxLength !== null && t.push(`max ${e.maxLength} chars`), e.min !== null && e.max !== null ? t.push(`${e.min} to ${e.max}`) : e.min !== null && t.push(`at least ${e.min}`), t.join(", ");
|
|
65
|
+
}
|
|
66
|
+
function _e({ result: e, noun: r, onOpenList: i }) {
|
|
67
|
+
let a = e.status === "REJECTED" || e.dryRun && e.failedRows > 0, o = a ? "border-status-error-border bg-status-error-bg-subtle text-status-error-text" : e.status === "PARTIAL" ? "border-status-warning-border bg-status-warning-bg-subtle text-status-warning-text" : "border-status-success-border bg-status-success-bg-subtle text-status-success-text", s = a ? t : n;
|
|
68
|
+
return /* @__PURE__ */ I("div", {
|
|
69
|
+
className: "space-y-3",
|
|
70
|
+
"data-testid": "mtw-import-result",
|
|
71
|
+
"data-status": e.status,
|
|
72
|
+
children: [
|
|
73
|
+
/* @__PURE__ */ I("div", {
|
|
74
|
+
role: a ? "alert" : "status",
|
|
75
|
+
className: `flex items-start gap-2 rounded-lg border px-4 py-3 text-sm ${o}`,
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ F(s, {
|
|
78
|
+
size: 18,
|
|
79
|
+
className: "mt-0.5 shrink-0"
|
|
80
|
+
}),
|
|
81
|
+
/* @__PURE__ */ F("span", {
|
|
82
|
+
className: "flex-1",
|
|
83
|
+
children: M(e, r)
|
|
84
|
+
}),
|
|
85
|
+
e.importedRows > 0 ? /* @__PURE__ */ I("button", {
|
|
86
|
+
type: "button",
|
|
87
|
+
className: "font-medium underline underline-offset-2",
|
|
88
|
+
onClick: i,
|
|
89
|
+
children: [
|
|
90
|
+
"View ",
|
|
91
|
+
r,
|
|
92
|
+
"s"
|
|
93
|
+
]
|
|
94
|
+
}) : null
|
|
95
|
+
]
|
|
96
|
+
}),
|
|
97
|
+
/* @__PURE__ */ I("div", {
|
|
98
|
+
className: "flex flex-wrap gap-2 text-sm",
|
|
99
|
+
children: [
|
|
100
|
+
/* @__PURE__ */ I(f, {
|
|
101
|
+
variant: "outline",
|
|
102
|
+
children: ["Rows: ", e.totalRows]
|
|
103
|
+
}),
|
|
104
|
+
/* @__PURE__ */ I(f, {
|
|
105
|
+
variant: "outline",
|
|
106
|
+
children: ["Valid: ", e.validRows]
|
|
107
|
+
}),
|
|
108
|
+
/* @__PURE__ */ I(f, {
|
|
109
|
+
variant: "outline",
|
|
110
|
+
children: ["Imported: ", e.importedRows]
|
|
111
|
+
}),
|
|
112
|
+
/* @__PURE__ */ I(f, {
|
|
113
|
+
variant: e.failedRows > 0 ? "destructive" : "outline",
|
|
114
|
+
children: ["Problems: ", e.failedRows]
|
|
115
|
+
})
|
|
116
|
+
]
|
|
117
|
+
}),
|
|
118
|
+
e.errors.length > 0 ? /* @__PURE__ */ F("div", {
|
|
119
|
+
className: "max-h-80 overflow-auto rounded-lg border border-border-default",
|
|
120
|
+
children: /* @__PURE__ */ I(S, { children: [/* @__PURE__ */ F(E, { children: /* @__PURE__ */ I(D, { children: [
|
|
121
|
+
/* @__PURE__ */ F(T, {
|
|
122
|
+
className: "w-20",
|
|
123
|
+
children: "Row"
|
|
124
|
+
}),
|
|
125
|
+
/* @__PURE__ */ F(T, {
|
|
126
|
+
className: "w-40",
|
|
127
|
+
children: "Column"
|
|
128
|
+
}),
|
|
129
|
+
/* @__PURE__ */ F(T, { children: "Problem" })
|
|
130
|
+
] }) }), /* @__PURE__ */ F(C, { children: e.errors.map((e, t) => /* @__PURE__ */ I(D, { children: [
|
|
131
|
+
/* @__PURE__ */ F(w, { children: e.row }),
|
|
132
|
+
/* @__PURE__ */ F(w, {
|
|
133
|
+
className: "font-mono text-xs",
|
|
134
|
+
children: e.field ?? "—"
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ F(w, { children: e.message })
|
|
137
|
+
] }, `${e.row}-${e.field ?? ""}-${t}`)) })] })
|
|
138
|
+
}) : null,
|
|
139
|
+
e.errorsTruncated ? /* @__PURE__ */ I("p", {
|
|
140
|
+
className: "text-sm text-text-secondary",
|
|
141
|
+
children: [
|
|
142
|
+
"Only the first ",
|
|
143
|
+
e.errors.length,
|
|
144
|
+
" problems are listed. Fix these and validate again to see the rest."
|
|
145
|
+
]
|
|
146
|
+
}) : null
|
|
147
|
+
]
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
function ve({ entity: e, label: t, noun: n }) {
|
|
151
|
+
let { state: i, isExporting: a, startExport: o, dismiss: c } = O(e, n);
|
|
152
|
+
return /* @__PURE__ */ I("div", {
|
|
153
|
+
className: "space-y-2 rounded-lg border border-border-default p-4",
|
|
154
|
+
children: [/* @__PURE__ */ I("div", {
|
|
155
|
+
className: "flex items-center justify-between gap-3",
|
|
156
|
+
children: [/* @__PURE__ */ I("div", { children: [/* @__PURE__ */ F("p", {
|
|
157
|
+
className: "font-medium text-text-primary",
|
|
158
|
+
children: t
|
|
159
|
+
}), /* @__PURE__ */ I("p", {
|
|
160
|
+
className: "text-sm text-text-secondary",
|
|
161
|
+
children: [
|
|
162
|
+
"Every ",
|
|
163
|
+
n,
|
|
164
|
+
" in this workspace, as CSV"
|
|
165
|
+
]
|
|
166
|
+
})] }), /* @__PURE__ */ I(p, {
|
|
167
|
+
variant: "outline",
|
|
168
|
+
size: "sm",
|
|
169
|
+
disabled: a,
|
|
170
|
+
"aria-label": `Export ${t}`,
|
|
171
|
+
onClick: o,
|
|
172
|
+
children: [a ? /* @__PURE__ */ F(s, {
|
|
173
|
+
size: 14,
|
|
174
|
+
className: "animate-spin"
|
|
175
|
+
}) : /* @__PURE__ */ F(r, { size: 14 }), /* @__PURE__ */ F("span", {
|
|
176
|
+
className: "ml-1",
|
|
177
|
+
children: a ? "Exporting…" : "Export"
|
|
178
|
+
})]
|
|
179
|
+
})]
|
|
180
|
+
}), /* @__PURE__ */ F(k, {
|
|
181
|
+
state: i,
|
|
182
|
+
onDismiss: c
|
|
183
|
+
})]
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function B() {
|
|
187
|
+
let { basePath: n, navigate: S } = d(), { specs: C, isLoading: w, error: T } = de(), { run: E, isRunning: D } = ue(), [O] = P(), [k, M] = N(() => {
|
|
188
|
+
let e = O.get("entity");
|
|
189
|
+
return j(e) ? e : "CUSTOMER";
|
|
190
|
+
}), [B, V] = N(null), [H, ye] = N(!1), [U, W] = N(null), [G, K] = N(null), [q, J] = N(null), Y = pe(null), X = le(k), Z = fe(() => C.find((e) => e.entityType === k) ?? null, [C, k]), Q = () => {
|
|
191
|
+
W(null), K(null), J(null);
|
|
192
|
+
}, be = (e) => {
|
|
193
|
+
j(e) && (M(e), V(null), Q());
|
|
194
|
+
}, xe = async (e) => {
|
|
195
|
+
let t = e.target.files?.[0];
|
|
196
|
+
if (e.target.value = "", Q(), !t) return;
|
|
197
|
+
let n = ce(t.name, t.type);
|
|
198
|
+
if (!n) {
|
|
199
|
+
V(null), K("Choose a .csv or .json file.");
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
V({
|
|
203
|
+
name: t.name,
|
|
204
|
+
format: n,
|
|
205
|
+
content: await t.text()
|
|
206
|
+
});
|
|
207
|
+
}, $ = async (e) => {
|
|
208
|
+
if (B) {
|
|
209
|
+
K(null), J(e ? "validate" : "import");
|
|
210
|
+
try {
|
|
211
|
+
W(await E({
|
|
212
|
+
entityType: k,
|
|
213
|
+
format: B.format,
|
|
214
|
+
content: B.content,
|
|
215
|
+
dryRun: e,
|
|
216
|
+
allowPartial: H
|
|
217
|
+
}));
|
|
218
|
+
} catch (e) {
|
|
219
|
+
W(null), K(e instanceof Error ? e.message : "The import could not be completed.");
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}, Se = () => {
|
|
223
|
+
Z && he(`${X.label.toLowerCase()}-import-template.csv`, se(Z), "text/csv");
|
|
224
|
+
}, Ce = B !== null && !D && U?.status !== "COMPLETED";
|
|
225
|
+
return /* @__PURE__ */ I(ae, {
|
|
226
|
+
title: "Import / Export",
|
|
227
|
+
subtitle: "Bring master data in from a file, or take a full copy out",
|
|
228
|
+
icon: /* @__PURE__ */ F(e, { size: 24 }),
|
|
229
|
+
children: [
|
|
230
|
+
/* @__PURE__ */ F(R, {
|
|
231
|
+
icon: /* @__PURE__ */ F(e, { size: 18 }),
|
|
232
|
+
children: "Onboard or migrate without re-keying: import customers, vehicles, drivers, warehouses or products from CSV or JSON. Every row is checked before anything is saved, so you can fix a file and try again. Export any dataset for accounting, BI tools or backups."
|
|
233
|
+
}),
|
|
234
|
+
/* @__PURE__ */ F("input", {
|
|
235
|
+
ref: Y,
|
|
236
|
+
type: "file",
|
|
237
|
+
accept: ".csv,.json,text/csv,application/json",
|
|
238
|
+
className: "hidden",
|
|
239
|
+
"data-testid": "mtw-import-file",
|
|
240
|
+
onChange: (e) => void xe(e)
|
|
241
|
+
}),
|
|
242
|
+
/* @__PURE__ */ I("div", {
|
|
243
|
+
className: "grid grid-cols-1 gap-6 xl:grid-cols-3",
|
|
244
|
+
children: [/* @__PURE__ */ I(L, {
|
|
245
|
+
className: "space-y-5 xl:col-span-2",
|
|
246
|
+
children: [
|
|
247
|
+
/* @__PURE__ */ I("div", {
|
|
248
|
+
className: "flex flex-wrap items-center justify-between gap-3",
|
|
249
|
+
children: [/* @__PURE__ */ I("h2", {
|
|
250
|
+
className: "flex items-center gap-2 text-base font-semibold text-text-primary",
|
|
251
|
+
children: [/* @__PURE__ */ F(l, { size: 18 }), " Import data"]
|
|
252
|
+
}), /* @__PURE__ */ I(f, {
|
|
253
|
+
variant: "outline",
|
|
254
|
+
children: [
|
|
255
|
+
"CSV or JSON · up to ",
|
|
256
|
+
oe,
|
|
257
|
+
" rows · 2 MB"
|
|
258
|
+
]
|
|
259
|
+
})]
|
|
260
|
+
}),
|
|
261
|
+
/* @__PURE__ */ I("div", {
|
|
262
|
+
className: "grid grid-cols-1 gap-4 md:grid-cols-2",
|
|
263
|
+
children: [/* @__PURE__ */ I("div", {
|
|
264
|
+
className: "space-y-2",
|
|
265
|
+
children: [/* @__PURE__ */ F(y, {
|
|
266
|
+
htmlFor: "mtw-import-entity",
|
|
267
|
+
children: "What are you importing?"
|
|
268
|
+
}), /* @__PURE__ */ I(b, {
|
|
269
|
+
value: k,
|
|
270
|
+
onValueChange: be,
|
|
271
|
+
children: [/* @__PURE__ */ F(re, {
|
|
272
|
+
id: "mtw-import-entity",
|
|
273
|
+
"aria-label": "Import type",
|
|
274
|
+
children: /* @__PURE__ */ F(ie, {})
|
|
275
|
+
}), /* @__PURE__ */ F(te, { children: A.map((e) => /* @__PURE__ */ F(ne, {
|
|
276
|
+
value: e.entityType,
|
|
277
|
+
children: e.label
|
|
278
|
+
}, e.entityType)) })]
|
|
279
|
+
})]
|
|
280
|
+
}), /* @__PURE__ */ I("div", {
|
|
281
|
+
className: "space-y-2",
|
|
282
|
+
children: [
|
|
283
|
+
/* @__PURE__ */ F(y, { children: "File" }),
|
|
284
|
+
/* @__PURE__ */ I("div", {
|
|
285
|
+
className: "flex flex-wrap items-center gap-2",
|
|
286
|
+
children: [/* @__PURE__ */ I(p, {
|
|
287
|
+
variant: "outline",
|
|
288
|
+
onClick: () => Y.current?.click(),
|
|
289
|
+
children: [/* @__PURE__ */ F(a, { size: 16 }), /* @__PURE__ */ F("span", {
|
|
290
|
+
className: "ml-1",
|
|
291
|
+
children: B ? "Choose another file" : "Choose file"
|
|
292
|
+
})]
|
|
293
|
+
}), /* @__PURE__ */ I(p, {
|
|
294
|
+
variant: "ghost",
|
|
295
|
+
disabled: !Z,
|
|
296
|
+
onClick: Se,
|
|
297
|
+
"aria-label": `Download ${X.label} CSV template`,
|
|
298
|
+
children: [/* @__PURE__ */ F(i, { size: 16 }), /* @__PURE__ */ F("span", {
|
|
299
|
+
className: "ml-1",
|
|
300
|
+
children: "Template"
|
|
301
|
+
})]
|
|
302
|
+
})]
|
|
303
|
+
}),
|
|
304
|
+
B ? /* @__PURE__ */ I("p", {
|
|
305
|
+
className: "text-sm text-text-secondary",
|
|
306
|
+
"data-testid": "mtw-import-file-name",
|
|
307
|
+
children: [
|
|
308
|
+
B.name,
|
|
309
|
+
" (",
|
|
310
|
+
B.format,
|
|
311
|
+
")"
|
|
312
|
+
]
|
|
313
|
+
}) : null
|
|
314
|
+
]
|
|
315
|
+
})]
|
|
316
|
+
}),
|
|
317
|
+
/* @__PURE__ */ I("div", {
|
|
318
|
+
className: "flex items-start gap-2",
|
|
319
|
+
children: [/* @__PURE__ */ F(ee, {
|
|
320
|
+
id: "mtw-import-partial",
|
|
321
|
+
checked: H,
|
|
322
|
+
onCheckedChange: (e) => {
|
|
323
|
+
ye(e === !0), U && !U.dryRun && Q();
|
|
324
|
+
}
|
|
325
|
+
}), /* @__PURE__ */ F(y, {
|
|
326
|
+
htmlFor: "mtw-import-partial",
|
|
327
|
+
className: "text-sm font-normal leading-snug",
|
|
328
|
+
children: "Import the valid rows even if some rows have problems. When this is off, a file with any problem imports nothing."
|
|
329
|
+
})]
|
|
330
|
+
}),
|
|
331
|
+
/* @__PURE__ */ I("div", {
|
|
332
|
+
className: "flex flex-wrap gap-2",
|
|
333
|
+
children: [/* @__PURE__ */ I(p, {
|
|
334
|
+
variant: "outline",
|
|
335
|
+
disabled: !B || D,
|
|
336
|
+
onClick: () => void $(!0),
|
|
337
|
+
children: [D && q === "validate" ? /* @__PURE__ */ F(s, {
|
|
338
|
+
size: 16,
|
|
339
|
+
className: "animate-spin"
|
|
340
|
+
}) : /* @__PURE__ */ F(c, { size: 16 }), /* @__PURE__ */ F("span", {
|
|
341
|
+
className: "ml-1",
|
|
342
|
+
children: "Validate"
|
|
343
|
+
})]
|
|
344
|
+
}), /* @__PURE__ */ I(p, {
|
|
345
|
+
disabled: !Ce,
|
|
346
|
+
onClick: () => void $(!1),
|
|
347
|
+
children: [D && q === "import" ? /* @__PURE__ */ F(s, {
|
|
348
|
+
size: 16,
|
|
349
|
+
className: "animate-spin"
|
|
350
|
+
}) : /* @__PURE__ */ F(l, { size: 16 }), /* @__PURE__ */ I("span", {
|
|
351
|
+
className: "ml-1",
|
|
352
|
+
children: ["Import ", X.label.toLowerCase()]
|
|
353
|
+
})]
|
|
354
|
+
})]
|
|
355
|
+
}),
|
|
356
|
+
G ? /* @__PURE__ */ I("div", {
|
|
357
|
+
role: "alert",
|
|
358
|
+
"data-testid": "mtw-import-error",
|
|
359
|
+
className: "flex items-start gap-2 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text",
|
|
360
|
+
children: [/* @__PURE__ */ F(t, {
|
|
361
|
+
size: 18,
|
|
362
|
+
className: "mt-0.5 shrink-0"
|
|
363
|
+
}), /* @__PURE__ */ F("span", { children: G })]
|
|
364
|
+
}) : null,
|
|
365
|
+
U ? /* @__PURE__ */ F(_e, {
|
|
366
|
+
result: U,
|
|
367
|
+
noun: X.noun,
|
|
368
|
+
onOpenList: () => S?.(u(n, z[k]))
|
|
369
|
+
}) : null
|
|
370
|
+
]
|
|
371
|
+
}), /* @__PURE__ */ I(m, { children: [/* @__PURE__ */ I(_, { children: [/* @__PURE__ */ I(v, {
|
|
372
|
+
className: "flex items-center gap-2 text-base",
|
|
373
|
+
children: [
|
|
374
|
+
/* @__PURE__ */ F(o, { size: 18 }),
|
|
375
|
+
" ",
|
|
376
|
+
X.label,
|
|
377
|
+
" columns"
|
|
378
|
+
]
|
|
379
|
+
}), /* @__PURE__ */ F(g, { children: "Use these column names as the CSV header or JSON keys. Values are not case-sensitive for lists." })] }), /* @__PURE__ */ F(h, { children: w ? /* @__PURE__ */ I("div", {
|
|
380
|
+
className: "space-y-2",
|
|
381
|
+
children: [
|
|
382
|
+
/* @__PURE__ */ F(x, { className: "h-6 w-full" }),
|
|
383
|
+
/* @__PURE__ */ F(x, { className: "h-6 w-full" }),
|
|
384
|
+
/* @__PURE__ */ F(x, { className: "h-6 w-2/3" })
|
|
385
|
+
]
|
|
386
|
+
}) : T ? /* @__PURE__ */ F("p", {
|
|
387
|
+
className: "text-sm text-status-error-text",
|
|
388
|
+
children: "The column guide could not be loaded. Imports still work."
|
|
389
|
+
}) : Z ? /* @__PURE__ */ F("ul", {
|
|
390
|
+
className: "space-y-3",
|
|
391
|
+
"data-testid": "mtw-import-columns",
|
|
392
|
+
children: Z.columns.map((e) => /* @__PURE__ */ I("li", {
|
|
393
|
+
className: "text-sm",
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ I("div", {
|
|
396
|
+
className: "flex flex-wrap items-center gap-2",
|
|
397
|
+
children: [
|
|
398
|
+
/* @__PURE__ */ F("code", {
|
|
399
|
+
className: "font-mono text-text-primary",
|
|
400
|
+
children: e.name
|
|
401
|
+
}),
|
|
402
|
+
e.required ? /* @__PURE__ */ F(f, {
|
|
403
|
+
variant: "default",
|
|
404
|
+
children: "required"
|
|
405
|
+
}) : null,
|
|
406
|
+
Z.keyColumn === e.name ? /* @__PURE__ */ F(f, {
|
|
407
|
+
variant: "outline",
|
|
408
|
+
children: "unique"
|
|
409
|
+
}) : null
|
|
410
|
+
]
|
|
411
|
+
}),
|
|
412
|
+
/* @__PURE__ */ F("p", {
|
|
413
|
+
className: "text-text-secondary",
|
|
414
|
+
children: e.description
|
|
415
|
+
}),
|
|
416
|
+
/* @__PURE__ */ F("p", {
|
|
417
|
+
className: "text-xs text-text-tertiary",
|
|
418
|
+
children: ge(e)
|
|
419
|
+
})
|
|
420
|
+
]
|
|
421
|
+
}, e.name))
|
|
422
|
+
}) : null })] })]
|
|
423
|
+
}),
|
|
424
|
+
/* @__PURE__ */ I(m, { children: [/* @__PURE__ */ I(_, { children: [/* @__PURE__ */ I(v, {
|
|
425
|
+
className: "flex items-center gap-2 text-base",
|
|
426
|
+
children: [/* @__PURE__ */ F(r, { size: 18 }), " Export data"]
|
|
427
|
+
}), /* @__PURE__ */ F(g, { children: "Exports run in the background and download as a ZIP. Large exports stay available on the Exports page." })] }), /* @__PURE__ */ F(h, {
|
|
428
|
+
className: "grid grid-cols-1 gap-3 md:grid-cols-2",
|
|
429
|
+
children: me.map((e) => /* @__PURE__ */ F(ve, { ...e }, e.entity))
|
|
430
|
+
})] })
|
|
431
|
+
]
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
//#endregion
|
|
435
|
+
export { B as default };
|
|
@@ -14,14 +14,14 @@ import { TriangleAlert as s } from "../node_modules/lucide-react/dist/esm/icons/
|
|
|
14
14
|
import { Warehouse as ae } from "../node_modules/lucide-react/dist/esm/icons/warehouse.js";
|
|
15
15
|
import { joinPath as c } from "../utils/navigation.js";
|
|
16
16
|
import { useMoveTheWheels as l } from "../providers/MoveTheWheelsProvider.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
17
|
+
import { formatCurrency as oe, formatDate as se } from "../utils/formatters.js";
|
|
18
|
+
import { useInventory as ce, useInventoryStats as le, useInventoryTransactions as ue } from "../hooks/useInventory.js";
|
|
19
|
+
import { Badge as u, Button as d, Card as f, CardContent as p, CardHeader as de, CardTitle as m, Progress as fe } from "../components/ui.js";
|
|
20
|
+
import { PageLayout as pe, PageSection as h } from "../components/PageLayout.js";
|
|
21
|
+
import { MetricCard as g, MetricCardSkeleton as me, MetricGrid as _ } from "../components/MetricCard.js";
|
|
22
|
+
import { StatusBadge as he } from "../components/StatusBadge.js";
|
|
23
|
+
import { DataTable as ge } from "../components/DataTable.js";
|
|
24
|
+
import { Notice as _e, useNotice as ve } from "../components/Notice.js";
|
|
25
25
|
import { useDebouncedValue as ye } from "../hooks/useDebouncedValue.js";
|
|
26
26
|
import { AdjustStockDialog as be, ReceiveStockDialog as xe, TransferStockDialog as Se } from "../components/StockActionDialogs.js";
|
|
27
27
|
import { useMemo as Ce, useState as v } from "react";
|
|
@@ -63,11 +63,11 @@ function O() {
|
|
|
63
63
|
let { t: O } = we(), k = (e, t) => {
|
|
64
64
|
let n = O(e);
|
|
65
65
|
return n === e ? t : n;
|
|
66
|
-
}, { basePath: Te, navigate: Ee } = l(), [A, De] = v(""), [j, M] = v(0), [N, Oe] = v(10), { inventory: P, lowStockItems: F, products: I, warehouses: ke, totalItems: Ae, hasMore: je, isLoading: L, error: R, refetch: z } =
|
|
66
|
+
}, { basePath: Te, navigate: Ee } = l(), [A, De] = v(""), [j, M] = v(0), [N, Oe] = v(10), { inventory: P, lowStockItems: F, products: I, warehouses: ke, totalItems: Ae, hasMore: je, isLoading: L, error: R, refetch: z } = ce({
|
|
67
67
|
search: ye(A),
|
|
68
68
|
limit: N,
|
|
69
69
|
offset: j * N
|
|
70
|
-
}), { stats: B, refetch: Me } =
|
|
70
|
+
}), { stats: B, refetch: Me } = le(), { transactions: V, isLoading: Ne, error: H, refetch: Pe } = ue({ limit: 8 }), { message: U, notify: Fe } = ve(6e3), [Ie, W] = v(!1), [G, K] = v(null), [q, J] = v(null), Y = (e) => ({
|
|
71
71
|
id: e.id,
|
|
72
72
|
productName: e.productName,
|
|
73
73
|
sku: e.sku,
|
|
@@ -155,7 +155,7 @@ function O() {
|
|
|
155
155
|
{
|
|
156
156
|
id: "state",
|
|
157
157
|
header: k("movethewheels.inventory.stock.status", "Status"),
|
|
158
|
-
cell: (e) => /* @__PURE__ */ y(
|
|
158
|
+
cell: (e) => /* @__PURE__ */ y(he, {
|
|
159
159
|
status: e.stockState === "out_of_stock" ? k("movethewheels.inventory.stock.outOfStock", "Out of stock") : e.stockState === "low" ? k("movethewheels.inventory.stock.low", "Low") : k("movethewheels.inventory.stock.inStock", "In stock"),
|
|
160
160
|
customColors: w[e.stockState],
|
|
161
161
|
size: "sm"
|
|
@@ -193,7 +193,7 @@ function O() {
|
|
|
193
193
|
})
|
|
194
194
|
}
|
|
195
195
|
];
|
|
196
|
-
return /* @__PURE__ */ b(
|
|
196
|
+
return /* @__PURE__ */ b(pe, {
|
|
197
197
|
title: k("movethewheels.inventory.title", "Inventory"),
|
|
198
198
|
subtitle: k("movethewheels.inventory.subtitle", "Manage your products and warehouses"),
|
|
199
199
|
icon: /* @__PURE__ */ y(o, { size: 24 }),
|
|
@@ -226,7 +226,7 @@ function O() {
|
|
|
226
226
|
}),
|
|
227
227
|
U && /* @__PURE__ */ y("div", {
|
|
228
228
|
className: "mb-2",
|
|
229
|
-
children: /* @__PURE__ */ y(
|
|
229
|
+
children: /* @__PURE__ */ y(_e, { message: U })
|
|
230
230
|
}),
|
|
231
231
|
R && !L ? /* @__PURE__ */ y(f, {
|
|
232
232
|
className: "border-status-error-border",
|
|
@@ -250,46 +250,46 @@ function O() {
|
|
|
250
250
|
})
|
|
251
251
|
}) : L ? /* @__PURE__ */ y(_, {
|
|
252
252
|
columns: 6,
|
|
253
|
-
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */ y(
|
|
253
|
+
children: Array.from({ length: 6 }).map((e, t) => /* @__PURE__ */ y(me, {}, t))
|
|
254
254
|
}) : /* @__PURE__ */ b(_, {
|
|
255
255
|
columns: 6,
|
|
256
256
|
children: [
|
|
257
|
-
/* @__PURE__ */ y(
|
|
257
|
+
/* @__PURE__ */ y(g, {
|
|
258
258
|
label: k("movethewheels.inventory.metrics.totalOnHand", "Total on-hand"),
|
|
259
259
|
value: B.totalOnHand.toLocaleString(),
|
|
260
260
|
icon: /* @__PURE__ */ y(r, { size: 20 }),
|
|
261
261
|
accent: "brand",
|
|
262
262
|
subtitle: k("movethewheels.inventory.metrics.onHandHint", "Units in the network")
|
|
263
263
|
}),
|
|
264
|
-
/* @__PURE__ */ y(
|
|
264
|
+
/* @__PURE__ */ y(g, {
|
|
265
265
|
label: k("movethewheels.inventory.metrics.available", "Available"),
|
|
266
266
|
value: B.totalAvailable.toLocaleString(),
|
|
267
267
|
icon: /* @__PURE__ */ y(a, { size: 20 }),
|
|
268
268
|
accent: "success",
|
|
269
269
|
subtitle: k("movethewheels.inventory.metrics.availableHint", "Free to promise")
|
|
270
270
|
}),
|
|
271
|
-
/* @__PURE__ */ y(
|
|
271
|
+
/* @__PURE__ */ y(g, {
|
|
272
272
|
label: k("movethewheels.inventory.metrics.allocated", "Allocated"),
|
|
273
273
|
value: B.totalAllocated.toLocaleString(),
|
|
274
274
|
icon: /* @__PURE__ */ y(te, { size: 20 }),
|
|
275
275
|
accent: "blue",
|
|
276
276
|
subtitle: k("movethewheels.inventory.metrics.allocatedHint", "Committed to orders")
|
|
277
277
|
}),
|
|
278
|
-
/* @__PURE__ */ y(
|
|
278
|
+
/* @__PURE__ */ y(g, {
|
|
279
279
|
label: k("movethewheels.inventory.metrics.lowStock", "Low-stock items"),
|
|
280
280
|
value: B.lowStockCount.toLocaleString(),
|
|
281
281
|
icon: /* @__PURE__ */ y(s, { size: 20 }),
|
|
282
282
|
accent: "warning",
|
|
283
283
|
subtitle: k("movethewheels.inventory.metrics.lowStockHint", "At or under reorder point")
|
|
284
284
|
}),
|
|
285
|
-
/* @__PURE__ */ y(
|
|
285
|
+
/* @__PURE__ */ y(g, {
|
|
286
286
|
label: k("movethewheels.inventory.metrics.totalProducts", "Catalog items"),
|
|
287
287
|
value: B.totalProducts.toLocaleString(),
|
|
288
288
|
icon: /* @__PURE__ */ y(o, { size: 20 }),
|
|
289
289
|
accent: "neutral",
|
|
290
290
|
onClick: () => Z("inventory/products")
|
|
291
291
|
}),
|
|
292
|
-
/* @__PURE__ */ y(
|
|
292
|
+
/* @__PURE__ */ y(g, {
|
|
293
293
|
label: k("movethewheels.inventory.metrics.warehouses", "Warehouses"),
|
|
294
294
|
value: B.totalWarehouses.toLocaleString(),
|
|
295
295
|
icon: /* @__PURE__ */ y(ae, { size: 20 }),
|
|
@@ -350,9 +350,9 @@ function O() {
|
|
|
350
350
|
className: "grid grid-cols-1 xl:grid-cols-3 gap-6",
|
|
351
351
|
children: [/* @__PURE__ */ y("div", {
|
|
352
352
|
className: "xl:col-span-2",
|
|
353
|
-
children: /* @__PURE__ */ y(
|
|
353
|
+
children: /* @__PURE__ */ y(h, {
|
|
354
354
|
title: k("movethewheels.inventory.stock.title", "Stock position"),
|
|
355
|
-
children: /* @__PURE__ */ y(
|
|
355
|
+
children: /* @__PURE__ */ y(ge, {
|
|
356
356
|
columns: Re,
|
|
357
357
|
data: Le,
|
|
358
358
|
isLoading: L,
|
|
@@ -386,7 +386,7 @@ function O() {
|
|
|
386
386
|
})
|
|
387
387
|
}), /* @__PURE__ */ b(f, {
|
|
388
388
|
className: "h-fit",
|
|
389
|
-
children: [/* @__PURE__ */ y(
|
|
389
|
+
children: [/* @__PURE__ */ y(de, { children: /* @__PURE__ */ b(m, {
|
|
390
390
|
className: "flex items-center gap-2",
|
|
391
391
|
children: [/* @__PURE__ */ y(ee, { size: 18 }), k("movethewheels.inventory.transactions.title", "Recent transactions")]
|
|
392
392
|
}) }), /* @__PURE__ */ y(p, {
|
|
@@ -428,7 +428,7 @@ function O() {
|
|
|
428
428
|
}),
|
|
429
429
|
/* @__PURE__ */ y("p", {
|
|
430
430
|
className: "text-xs text-text-secondary",
|
|
431
|
-
children:
|
|
431
|
+
children: se(r.createdAt, "short")
|
|
432
432
|
})
|
|
433
433
|
]
|
|
434
434
|
}), /* @__PURE__ */ y("span", {
|
|
@@ -443,7 +443,7 @@ function O() {
|
|
|
443
443
|
}),
|
|
444
444
|
/* @__PURE__ */ b("div", {
|
|
445
445
|
className: "grid grid-cols-1 lg:grid-cols-2 gap-6",
|
|
446
|
-
children: [/* @__PURE__ */ y(
|
|
446
|
+
children: [/* @__PURE__ */ y(h, {
|
|
447
447
|
title: k("movethewheels.inventory.warehouses.title", "Warehouses"),
|
|
448
448
|
actions: /* @__PURE__ */ b(d, {
|
|
449
449
|
variant: "ghost",
|
|
@@ -487,7 +487,7 @@ function O() {
|
|
|
487
487
|
}), e.utilization === void 0 ? /* @__PURE__ */ y("p", {
|
|
488
488
|
className: "text-xs text-text-tertiary",
|
|
489
489
|
children: "Not provided"
|
|
490
|
-
}) : /* @__PURE__ */ y(
|
|
490
|
+
}) : /* @__PURE__ */ y(fe, {
|
|
491
491
|
value: e.utilization,
|
|
492
492
|
className: "w-24 h-2"
|
|
493
493
|
})]
|
|
@@ -497,7 +497,7 @@ function O() {
|
|
|
497
497
|
}, e.id))
|
|
498
498
|
})
|
|
499
499
|
}) })
|
|
500
|
-
}), /* @__PURE__ */ y(
|
|
500
|
+
}), /* @__PURE__ */ y(h, {
|
|
501
501
|
title: k("movethewheels.inventory.products.title", "Recent Products"),
|
|
502
502
|
actions: /* @__PURE__ */ b(d, {
|
|
503
503
|
variant: "ghost",
|
|
@@ -532,7 +532,7 @@ function O() {
|
|
|
532
532
|
className: "text-right",
|
|
533
533
|
children: [/* @__PURE__ */ y("p", {
|
|
534
534
|
className: "font-medium",
|
|
535
|
-
children: e.value === void 0 ? "Not provided" :
|
|
535
|
+
children: e.value === void 0 ? "Not provided" : oe(e.value)
|
|
536
536
|
}), /* @__PURE__ */ y(u, {
|
|
537
537
|
variant: "outline",
|
|
538
538
|
children: e.category ?? "Not provided"
|