@burdenoff/microfe-movethewheels 2026.1031.1 → 2026.1031.3
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 +144 -136
- package/dist/MoveTheWheelsRoutes.js +61 -57
- package/dist/components/ShipmentRiskDialog.js +228 -0
- package/dist/components/TrackingAlertList.js +149 -0
- package/dist/generated/tracking-quality-operations.d.ts +1154 -2
- package/dist/generated/wspace-types.d.ts +2895 -50
- package/dist/hooks/useEntityImport.js +68 -0
- package/dist/hooks/useShipmentRisk.js +72 -0
- package/dist/hooks/useTracking.js +96 -82
- package/dist/movethewheels/components/ShipmentRiskDialog.d.ts +20 -0
- package/dist/movethewheels/components/TrackingAlertList.d.ts +14 -0
- package/dist/movethewheels/hooks/useEntityImport.d.ts +19 -0
- package/dist/movethewheels/hooks/useShipmentRisk.d.ts +41 -0
- package/dist/movethewheels/pages/ImportExportPage.d.ts +9 -0
- package/dist/movethewheels/types/index.d.ts +15 -1
- package/dist/movethewheels/utils/entityImport.d.ts +109 -0
- package/dist/movethewheels/utils/trackingAlerts.d.ts +36 -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/file-spreadsheet.js +30 -0
- package/dist/node_modules/lucide-react/dist/esm/icons/file-up.js +22 -0
- package/dist/pages/CustomersPage.js +88 -79
- package/dist/pages/DashboardPage.js +147 -151
- package/dist/pages/DriversPage.js +115 -106
- package/dist/pages/ImportExportPage.js +435 -0
- package/dist/pages/LiveTrackingPage.js +169 -169
- package/dist/pages/ProductsPage.js +85 -76
- package/dist/pages/VehiclesPage.js +99 -90
- package/dist/pages/WarehousesPage.js +97 -88
- package/dist/utils/entityImport.js +73 -0
- package/dist/utils/trackingAlerts.js +86 -0
- package/package.json +4 -2
- package/src/generated/tracking-quality-operations.ts +1519 -1
- package/src/generated/wspace-types.ts +3248 -51
- package/src/movethewheels/MoveTheWheelsRoot.tsx +8 -0
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +4 -0
- package/src/movethewheels/components/ShipmentRiskDialog.tsx +315 -0
- package/src/movethewheels/components/TrackingAlertList.tsx +188 -0
- package/src/movethewheels/hooks/useEntityImport.ts +108 -0
- package/src/movethewheels/hooks/useShipmentRisk.ts +195 -0
- package/src/movethewheels/hooks/useTracking.ts +66 -22
- package/src/movethewheels/pages/CustomersPage.tsx +6 -1
- package/src/movethewheels/pages/DashboardPage.tsx +10 -20
- package/src/movethewheels/pages/DriversPage.tsx +6 -0
- package/src/movethewheels/pages/ImportExportPage.tsx +483 -0
- package/src/movethewheels/pages/LiveTrackingPage.tsx +20 -22
- package/src/movethewheels/pages/ProductsPage.tsx +14 -1
- package/src/movethewheels/pages/VehiclesPage.tsx +6 -0
- package/src/movethewheels/pages/WarehousesPage.tsx +6 -1
- package/src/movethewheels/types/index.ts +16 -1
- package/src/movethewheels/utils/entityImport.ts +239 -0
- package/src/movethewheels/utils/trackingAlerts.ts +151 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity import — client side of wspace-movethewheels-svc's bulk import (BOFF-3990).
|
|
3
|
+
*
|
|
4
|
+
* The service owns parsing and validation; this module only picks the right
|
|
5
|
+
* mutation for an entity, detects the file format, builds CSV templates from
|
|
6
|
+
* the server's column specification and shapes the result for display.
|
|
7
|
+
* Kept free of React so the contract can be unit-tested.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MTW_IMPORT_ENTITIES: readonly [{
|
|
10
|
+
readonly entityType: "CUSTOMER";
|
|
11
|
+
readonly label: "Customers";
|
|
12
|
+
readonly noun: "customer";
|
|
13
|
+
readonly field: "importMtwCustomers";
|
|
14
|
+
}, {
|
|
15
|
+
readonly entityType: "VEHICLE";
|
|
16
|
+
readonly label: "Vehicles";
|
|
17
|
+
readonly noun: "vehicle";
|
|
18
|
+
readonly field: "importMtwVehicles";
|
|
19
|
+
}, {
|
|
20
|
+
readonly entityType: "DRIVER";
|
|
21
|
+
readonly label: "Drivers";
|
|
22
|
+
readonly noun: "driver";
|
|
23
|
+
readonly field: "importMtwDrivers";
|
|
24
|
+
}, {
|
|
25
|
+
readonly entityType: "WAREHOUSE";
|
|
26
|
+
readonly label: "Warehouses";
|
|
27
|
+
readonly noun: "warehouse";
|
|
28
|
+
readonly field: "importMtwWarehouses";
|
|
29
|
+
}, {
|
|
30
|
+
readonly entityType: "CARGO_ITEM";
|
|
31
|
+
readonly label: "Products";
|
|
32
|
+
readonly noun: "product";
|
|
33
|
+
readonly field: "importMtwCargoItems";
|
|
34
|
+
}];
|
|
35
|
+
export type MtwImportEntityType = (typeof MTW_IMPORT_ENTITIES)[number]['entityType'];
|
|
36
|
+
export type MtwImportFormat = 'CSV' | 'JSON';
|
|
37
|
+
export type MtwImportStatus = 'DRY_RUN' | 'COMPLETED' | 'PARTIAL' | 'REJECTED';
|
|
38
|
+
/** Mirrors the service limits so an oversized file is refused before upload. */
|
|
39
|
+
export declare const MTW_IMPORT_MAX_BYTES: number;
|
|
40
|
+
export declare const MTW_IMPORT_MAX_ROWS = 1000;
|
|
41
|
+
export declare function isImportEntityType(value: string | null | undefined): value is MtwImportEntityType;
|
|
42
|
+
export declare function importEntity(entityType: MtwImportEntityType): {
|
|
43
|
+
readonly entityType: "CUSTOMER";
|
|
44
|
+
readonly label: "Customers";
|
|
45
|
+
readonly noun: "customer";
|
|
46
|
+
readonly field: "importMtwCustomers";
|
|
47
|
+
} | {
|
|
48
|
+
readonly entityType: "VEHICLE";
|
|
49
|
+
readonly label: "Vehicles";
|
|
50
|
+
readonly noun: "vehicle";
|
|
51
|
+
readonly field: "importMtwVehicles";
|
|
52
|
+
} | {
|
|
53
|
+
readonly entityType: "DRIVER";
|
|
54
|
+
readonly label: "Drivers";
|
|
55
|
+
readonly noun: "driver";
|
|
56
|
+
readonly field: "importMtwDrivers";
|
|
57
|
+
} | {
|
|
58
|
+
readonly entityType: "WAREHOUSE";
|
|
59
|
+
readonly label: "Warehouses";
|
|
60
|
+
readonly noun: "warehouse";
|
|
61
|
+
readonly field: "importMtwWarehouses";
|
|
62
|
+
} | {
|
|
63
|
+
readonly entityType: "CARGO_ITEM";
|
|
64
|
+
readonly label: "Products";
|
|
65
|
+
readonly noun: "product";
|
|
66
|
+
readonly field: "importMtwCargoItems";
|
|
67
|
+
};
|
|
68
|
+
export declare const IMPORT_MUTATIONS: Record<MtwImportEntityType, string>;
|
|
69
|
+
/** The mutation document for one entity's import. */
|
|
70
|
+
export declare function importMutation(entityType: MtwImportEntityType): string;
|
|
71
|
+
export declare const MTW_IMPORT_SPEC_QUERY = "\n query MtwImportSpec {\n mtwImportSpec {\n entityType\n keyColumn\n columns {\n name\n type\n required\n description\n allowedValues\n maxLength\n min\n max\n }\n }\n }\n";
|
|
72
|
+
export interface MtwImportColumn {
|
|
73
|
+
name: string;
|
|
74
|
+
type: string;
|
|
75
|
+
required: boolean;
|
|
76
|
+
description: string;
|
|
77
|
+
allowedValues: string[] | null;
|
|
78
|
+
maxLength: number | null;
|
|
79
|
+
min: number | null;
|
|
80
|
+
max: number | null;
|
|
81
|
+
}
|
|
82
|
+
export interface MtwImportEntitySpec {
|
|
83
|
+
entityType: MtwImportEntityType;
|
|
84
|
+
keyColumn: string | null;
|
|
85
|
+
columns: MtwImportColumn[];
|
|
86
|
+
}
|
|
87
|
+
export interface MtwImportRowError {
|
|
88
|
+
row: number;
|
|
89
|
+
field: string | null;
|
|
90
|
+
message: string;
|
|
91
|
+
}
|
|
92
|
+
export interface MtwImportResult {
|
|
93
|
+
entityType: MtwImportEntityType;
|
|
94
|
+
status: MtwImportStatus;
|
|
95
|
+
dryRun: boolean;
|
|
96
|
+
totalRows: number;
|
|
97
|
+
validRows: number;
|
|
98
|
+
importedRows: number;
|
|
99
|
+
failedRows: number;
|
|
100
|
+
createdIds: string[];
|
|
101
|
+
errorsTruncated: boolean;
|
|
102
|
+
errors: MtwImportRowError[];
|
|
103
|
+
}
|
|
104
|
+
/** Picks the format from the file name, falling back to the MIME type. */
|
|
105
|
+
export declare function detectImportFormat(fileName: string, mimeType?: string): MtwImportFormat | null;
|
|
106
|
+
/** A CSV template: the header row, required columns first, then optional ones. */
|
|
107
|
+
export declare function buildCsvTemplate(spec: MtwImportEntitySpec): string;
|
|
108
|
+
/** One-line summary of an import result for the status banner. */
|
|
109
|
+
export declare function summariseImport(result: MtwImportResult, noun: string): string;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { TrackingAlert, TrackingAlertSeverity } from '../types';
|
|
2
|
+
export type RiskSignalCode = 'LEG_SLIP' | 'OPEN_LEG_OVERDUE' | 'ROUTE_DURATION_OVERRUN' | 'EXCESS_DWELL' | 'TRACKING_STALE' | 'VEHICLE_UNAVAILABLE' | 'CARRIER_LATE_HISTORY';
|
|
3
|
+
export type TrackingAlertKind = 'DELAYED' | 'AT_RISK';
|
|
4
|
+
export interface ApiTrackingAlert {
|
|
5
|
+
id: string;
|
|
6
|
+
shipmentId: string;
|
|
7
|
+
shipmentNumber: string;
|
|
8
|
+
alertType: string;
|
|
9
|
+
message: string;
|
|
10
|
+
riskScore?: number | null;
|
|
11
|
+
promisedDelivery?: string | null;
|
|
12
|
+
predictedDelivery?: string | null;
|
|
13
|
+
signals?: RiskSignalCode[] | null;
|
|
14
|
+
acknowledged: boolean;
|
|
15
|
+
acknowledgedAt?: string | null;
|
|
16
|
+
}
|
|
17
|
+
/** Risk score at or above which an AT_RISK alert is shown as high severity (matches the backend HIGH level). */
|
|
18
|
+
export declare const HIGH_RISK_SCORE = 70;
|
|
19
|
+
/**
|
|
20
|
+
* DELAYED is always high: the promise is already broken. AT_RISK follows the
|
|
21
|
+
* forecast's risk score; the backend only raises AT_RISK at MEDIUM or above,
|
|
22
|
+
* so anything below the HIGH band is medium.
|
|
23
|
+
*/
|
|
24
|
+
export declare function trackingAlertSeverity(alertType: string, riskScore: number | null | undefined): TrackingAlertSeverity;
|
|
25
|
+
export declare function mapTrackingAlert(alert: ApiTrackingAlert): TrackingAlert;
|
|
26
|
+
export declare function sortTrackingAlerts(alerts: TrackingAlert[]): TrackingAlert[];
|
|
27
|
+
/** Translation key + English fallback for each risk signal code. */
|
|
28
|
+
export declare const RISK_SIGNAL_LABELS: Record<RiskSignalCode, {
|
|
29
|
+
key: string;
|
|
30
|
+
fallback: string;
|
|
31
|
+
}>;
|
|
32
|
+
export declare function riskSignalLabel(code: string, t: (key: string, fallback: string) => string): string;
|
|
33
|
+
/** Minutes between the promise and the predicted delivery, or null when unknown / not late. */
|
|
34
|
+
export declare function predictedSlipMinutes(alert: Pick<TrackingAlert, 'promisedDelivery' | 'predictedDelivery'>): number | null;
|
|
35
|
+
/** "45 min", "3 h 20 min", "2 d 4 h" — compact duration for alert cards. */
|
|
36
|
+
export declare function formatSlip(minutes: number): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/arrow-down-up.js
|
|
3
|
+
var t = e("ArrowDownUp", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "m3 16 4 4 4-4",
|
|
6
|
+
key: "1co6wj"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M7 20V4",
|
|
10
|
+
key: "1yoxec"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "m21 8-4-4-4 4",
|
|
14
|
+
key: "1c9v7m"
|
|
15
|
+
}],
|
|
16
|
+
["path", {
|
|
17
|
+
d: "M17 4v16",
|
|
18
|
+
key: "7dpous"
|
|
19
|
+
}]
|
|
20
|
+
]);
|
|
21
|
+
//#endregion
|
|
22
|
+
export { t as ArrowDownUp };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/file-spreadsheet.js
|
|
3
|
+
var t = e("FileSpreadsheet", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",
|
|
6
|
+
key: "1rqfz7"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M14 2v4a2 2 0 0 0 2 2h4",
|
|
10
|
+
key: "tnqrlb"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "M8 13h2",
|
|
14
|
+
key: "yr2amv"
|
|
15
|
+
}],
|
|
16
|
+
["path", {
|
|
17
|
+
d: "M14 13h2",
|
|
18
|
+
key: "un5t4a"
|
|
19
|
+
}],
|
|
20
|
+
["path", {
|
|
21
|
+
d: "M8 17h2",
|
|
22
|
+
key: "2yhykz"
|
|
23
|
+
}],
|
|
24
|
+
["path", {
|
|
25
|
+
d: "M14 17h2",
|
|
26
|
+
key: "10kma7"
|
|
27
|
+
}]
|
|
28
|
+
]);
|
|
29
|
+
//#endregion
|
|
30
|
+
export { t as FileSpreadsheet };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createLucideIcon as e } from "../createLucideIcon.js";
|
|
2
|
+
//#region node_modules/lucide-react/dist/esm/icons/file-up.js
|
|
3
|
+
var t = e("FileUp", [
|
|
4
|
+
["path", {
|
|
5
|
+
d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",
|
|
6
|
+
key: "1rqfz7"
|
|
7
|
+
}],
|
|
8
|
+
["path", {
|
|
9
|
+
d: "M14 2v4a2 2 0 0 0 2 2h4",
|
|
10
|
+
key: "tnqrlb"
|
|
11
|
+
}],
|
|
12
|
+
["path", {
|
|
13
|
+
d: "M12 12v6",
|
|
14
|
+
key: "3ahymv"
|
|
15
|
+
}],
|
|
16
|
+
["path", {
|
|
17
|
+
d: "m15 15-3-3-3 3",
|
|
18
|
+
key: "15xj92"
|
|
19
|
+
}]
|
|
20
|
+
]);
|
|
21
|
+
//#endregion
|
|
22
|
+
export { t as FileUp };
|
|
@@ -3,97 +3,106 @@ import { Download as t } from "../node_modules/lucide-react/dist/esm/icons/downl
|
|
|
3
3
|
import { Plus as n } from "../node_modules/lucide-react/dist/esm/icons/plus.js";
|
|
4
4
|
import { RefreshCw as r } from "../node_modules/lucide-react/dist/esm/icons/refresh-cw.js";
|
|
5
5
|
import { Star as i } from "../node_modules/lucide-react/dist/esm/icons/star.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
6
|
+
import { Upload as a } from "../node_modules/lucide-react/dist/esm/icons/upload.js";
|
|
7
|
+
import { Users as o } from "../node_modules/lucide-react/dist/esm/icons/users.js";
|
|
8
|
+
import { joinPath as s } from "../utils/navigation.js";
|
|
9
|
+
import { useMoveTheWheels as c } from "../providers/MoveTheWheelsProvider.js";
|
|
10
|
+
import { useCustomerStats as l, useCustomers as u } from "../hooks/useCustomers.js";
|
|
11
|
+
import { Avatar as d, AvatarFallback as f, Button as p } from "../components/ui.js";
|
|
12
|
+
import { PageLayout as m } from "../components/PageLayout.js";
|
|
13
|
+
import { MetricCard as h, MetricGrid as g } from "../components/MetricCard.js";
|
|
14
|
+
import { TypeBadge as _ } from "../components/StatusBadge.js";
|
|
15
|
+
import { DataTable as v } from "../components/DataTable.js";
|
|
16
|
+
import { formatDate as y } from "../utils/formatters.js";
|
|
17
|
+
import { useDebouncedValue as b } from "../hooks/useDebouncedValue.js";
|
|
18
|
+
import { useEntityExport as x } from "../hooks/useEntityExport.js";
|
|
19
|
+
import { ExportStatusBanner as S } from "../components/ExportStatusBanner.js";
|
|
20
|
+
import { useState as C } from "react";
|
|
21
|
+
import { jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
22
|
+
import { CTAOverflowMenu as E, PagePurpose as D } from "@burdenoff/fe-libs/ui";
|
|
22
23
|
//#region src/movethewheels/pages/CustomersPage.tsx
|
|
23
|
-
function
|
|
24
|
-
let { basePath:
|
|
25
|
-
limit:
|
|
26
|
-
offset:
|
|
27
|
-
filters: { search:
|
|
28
|
-
}), { stats:
|
|
29
|
-
return /* @__PURE__ */
|
|
24
|
+
function O() {
|
|
25
|
+
let { basePath: O, navigate: k } = c(), { state: A, isExporting: j, startExport: M, dismiss: N } = x("customers", "customer"), [P, F] = C(0), [I, L] = C(25), [R, z] = C(""), B = b(R), { customers: V, totalCustomers: H, hasMore: U, isLoading: W, error: G, refetch: K } = u({
|
|
26
|
+
limit: I,
|
|
27
|
+
offset: P * I,
|
|
28
|
+
filters: { search: B }
|
|
29
|
+
}), { stats: q } = l(), J = (e) => k?.(s(O, e));
|
|
30
|
+
return /* @__PURE__ */ T(m, {
|
|
30
31
|
title: "Customers",
|
|
31
|
-
subtitle: `${
|
|
32
|
-
icon: /* @__PURE__ */
|
|
33
|
-
headerActions: /* @__PURE__ */
|
|
32
|
+
subtitle: `${q.total} customers`,
|
|
33
|
+
icon: /* @__PURE__ */ w(o, { size: 24 }),
|
|
34
|
+
headerActions: /* @__PURE__ */ w(E, {
|
|
34
35
|
primary: {
|
|
35
36
|
label: "Add Customer",
|
|
36
|
-
icon: /* @__PURE__ */
|
|
37
|
-
onSelect: () =>
|
|
37
|
+
icon: /* @__PURE__ */ w(n, { size: 16 }),
|
|
38
|
+
onSelect: () => J("customers/new")
|
|
38
39
|
},
|
|
39
|
-
actions: [
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
actions: [
|
|
41
|
+
{
|
|
42
|
+
label: "Refresh",
|
|
43
|
+
icon: /* @__PURE__ */ w(r, { size: 16 }),
|
|
44
|
+
onSelect: () => K()
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: "Import",
|
|
48
|
+
icon: /* @__PURE__ */ w(a, { size: 16 }),
|
|
49
|
+
onSelect: () => J("import-export?entity=CUSTOMER")
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: j ? "Exporting…" : "Export",
|
|
53
|
+
icon: /* @__PURE__ */ w(t, { size: 16 }),
|
|
54
|
+
onSelect: M
|
|
55
|
+
}
|
|
56
|
+
]
|
|
48
57
|
}),
|
|
49
58
|
children: [
|
|
50
|
-
/* @__PURE__ */
|
|
51
|
-
icon: /* @__PURE__ */
|
|
59
|
+
/* @__PURE__ */ w(D, {
|
|
60
|
+
icon: /* @__PURE__ */ w(o, { size: 18 }),
|
|
52
61
|
children: "The businesses and individuals you deliver for. Keep contact details, locations and satisfaction ratings here, and open a customer to see their order history before booking the next shipment."
|
|
53
62
|
}),
|
|
54
|
-
/* @__PURE__ */
|
|
55
|
-
state:
|
|
56
|
-
onDismiss:
|
|
63
|
+
/* @__PURE__ */ w(S, {
|
|
64
|
+
state: A,
|
|
65
|
+
onDismiss: N
|
|
57
66
|
}),
|
|
58
|
-
/* @__PURE__ */
|
|
67
|
+
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
59
68
|
className: "mb-3 text-sm font-medium text-text-secondary",
|
|
60
69
|
children: "Customer base at a glance"
|
|
61
|
-
}), /* @__PURE__ */
|
|
70
|
+
}), /* @__PURE__ */ T(g, {
|
|
62
71
|
columns: 3,
|
|
63
72
|
children: [
|
|
64
|
-
/* @__PURE__ */
|
|
73
|
+
/* @__PURE__ */ w(h, {
|
|
65
74
|
label: "Total customers",
|
|
66
|
-
value:
|
|
67
|
-
icon: /* @__PURE__ */
|
|
75
|
+
value: q.total,
|
|
76
|
+
icon: /* @__PURE__ */ w(o, { size: 20 }),
|
|
68
77
|
accent: "brand"
|
|
69
78
|
}),
|
|
70
|
-
/* @__PURE__ */
|
|
79
|
+
/* @__PURE__ */ w(h, {
|
|
71
80
|
label: "Avg. rating",
|
|
72
|
-
value:
|
|
73
|
-
icon: /* @__PURE__ */
|
|
81
|
+
value: q.avgRating > 0 ? q.avgRating.toFixed(1) : "—",
|
|
82
|
+
icon: /* @__PURE__ */ w(i, { size: 20 }),
|
|
74
83
|
accent: "success",
|
|
75
84
|
subtitle: "Across all customers"
|
|
76
85
|
}),
|
|
77
|
-
/* @__PURE__ */
|
|
86
|
+
/* @__PURE__ */ w(h, {
|
|
78
87
|
label: "Business accounts",
|
|
79
|
-
value:
|
|
80
|
-
icon: /* @__PURE__ */
|
|
88
|
+
value: q.b2b,
|
|
89
|
+
icon: /* @__PURE__ */ w(e, { size: 20 }),
|
|
81
90
|
accent: "blue",
|
|
82
91
|
subtitle: "B2B relationships"
|
|
83
92
|
})
|
|
84
93
|
]
|
|
85
94
|
})] }),
|
|
86
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ w(v, {
|
|
87
96
|
columns: [
|
|
88
97
|
{
|
|
89
98
|
id: "customer",
|
|
90
99
|
header: "Customer",
|
|
91
|
-
cell: (e) => /* @__PURE__ */
|
|
100
|
+
cell: (e) => /* @__PURE__ */ T("div", {
|
|
92
101
|
className: "flex items-center gap-3",
|
|
93
|
-
children: [/* @__PURE__ */
|
|
102
|
+
children: [/* @__PURE__ */ w(d, { children: /* @__PURE__ */ w(f, { children: e.name.split(" ").map((e) => e[0]).join("") }) }), /* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("p", {
|
|
94
103
|
className: "font-medium",
|
|
95
104
|
children: e.name
|
|
96
|
-
}), /* @__PURE__ */
|
|
105
|
+
}), /* @__PURE__ */ w("p", {
|
|
97
106
|
className: "text-sm text-text-secondary",
|
|
98
107
|
children: e.email
|
|
99
108
|
})] })]
|
|
@@ -103,7 +112,7 @@ function D() {
|
|
|
103
112
|
id: "type",
|
|
104
113
|
header: "Type",
|
|
105
114
|
accessorKey: "type",
|
|
106
|
-
cell: (e) => /* @__PURE__ */
|
|
115
|
+
cell: (e) => /* @__PURE__ */ w(_, { type: e.type })
|
|
107
116
|
},
|
|
108
117
|
{
|
|
109
118
|
id: "company",
|
|
@@ -124,12 +133,12 @@ function D() {
|
|
|
124
133
|
{
|
|
125
134
|
id: "rating",
|
|
126
135
|
header: "Rating",
|
|
127
|
-
cell: (e) => /* @__PURE__ */
|
|
136
|
+
cell: (e) => /* @__PURE__ */ T("div", {
|
|
128
137
|
className: "flex items-center gap-1",
|
|
129
|
-
children: [/* @__PURE__ */
|
|
138
|
+
children: [/* @__PURE__ */ w(i, {
|
|
130
139
|
size: 14,
|
|
131
140
|
className: "text-status-warning-text fill-current"
|
|
132
|
-
}), /* @__PURE__ */
|
|
141
|
+
}), /* @__PURE__ */ w("span", { children: e.rating === void 0 ? "Not provided" : e.rating.toFixed(1) })]
|
|
133
142
|
})
|
|
134
143
|
},
|
|
135
144
|
{
|
|
@@ -137,13 +146,13 @@ function D() {
|
|
|
137
146
|
header: "Created",
|
|
138
147
|
accessorKey: "createdAt",
|
|
139
148
|
sortable: !0,
|
|
140
|
-
cell: (e) =>
|
|
149
|
+
cell: (e) => y(e.createdAt, "short")
|
|
141
150
|
}
|
|
142
151
|
],
|
|
143
|
-
data:
|
|
144
|
-
isLoading:
|
|
145
|
-
error:
|
|
146
|
-
onRetry:
|
|
152
|
+
data: V,
|
|
153
|
+
isLoading: W,
|
|
154
|
+
error: G,
|
|
155
|
+
onRetry: K,
|
|
147
156
|
searchable: !0,
|
|
148
157
|
searchPlaceholder: "Search customers...",
|
|
149
158
|
searchFields: [
|
|
@@ -151,26 +160,26 @@ function D() {
|
|
|
151
160
|
"email",
|
|
152
161
|
"company"
|
|
153
162
|
],
|
|
154
|
-
searchQuery:
|
|
163
|
+
searchQuery: R,
|
|
155
164
|
onSearchQueryChange: (e) => {
|
|
156
|
-
|
|
165
|
+
z(e), F(0);
|
|
157
166
|
},
|
|
158
|
-
onRowClick: (e) =>
|
|
167
|
+
onRowClick: (e) => J(`customers/${e.id}`),
|
|
159
168
|
getRowId: (e) => e.id,
|
|
160
|
-
pageIndex:
|
|
161
|
-
pageSize:
|
|
162
|
-
onPageChange:
|
|
169
|
+
pageIndex: P,
|
|
170
|
+
pageSize: I,
|
|
171
|
+
onPageChange: F,
|
|
163
172
|
onPageSizeChange: (e) => {
|
|
164
|
-
|
|
173
|
+
L(e), F(0);
|
|
165
174
|
},
|
|
166
|
-
totalItems:
|
|
167
|
-
hasNextPage:
|
|
175
|
+
totalItems: H,
|
|
176
|
+
hasNextPage: U,
|
|
168
177
|
emptyIllustration: "empty-people",
|
|
169
178
|
emptyTitle: "No customers yet",
|
|
170
179
|
emptyDescription: "Add your first customer to start booking deliveries for them.",
|
|
171
|
-
emptyAction: /* @__PURE__ */
|
|
172
|
-
onClick: () =>
|
|
173
|
-
children: [/* @__PURE__ */
|
|
180
|
+
emptyAction: /* @__PURE__ */ T(p, {
|
|
181
|
+
onClick: () => J("customers/new"),
|
|
182
|
+
children: [/* @__PURE__ */ w(n, {
|
|
174
183
|
size: 16,
|
|
175
184
|
className: "mr-1.5"
|
|
176
185
|
}), "Add Customer"]
|
|
@@ -180,4 +189,4 @@ function D() {
|
|
|
180
189
|
});
|
|
181
190
|
}
|
|
182
191
|
//#endregion
|
|
183
|
-
export {
|
|
192
|
+
export { O as default };
|