@burdenoff/microfe-movethewheels 2026.624.1 → 2026.625.1
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-BrHX2lQn.js → AIAssistantPage-CNyoKtID.js} +4 -4
- package/dist/{AnalyticsPage-DI6Wcaw5.js → AnalyticsPage-Ck615ox7.js} +8 -8
- package/dist/{CreateOrderPage-DfkSi6JF.js → CreateOrderPage-C9Vb57Yn.js} +5 -5
- package/dist/{CustomerDetailsPage-DzAIu_tH.js → CustomerDetailsPage-BVkHRZvi.js} +9 -9
- package/dist/CustomersPage-DhQg-6h_.js +118 -0
- package/dist/{DashboardPage-3ZOnwg1a.js → DashboardPage-DTmyuC11.js} +118 -111
- package/dist/{DataTable-CZGz3SJu.js → DataTable-CfWvFw5B.js} +6 -6
- package/dist/{DriverDetailsPage-YuZSlPSV.js → DriverDetailsPage-DaaCQ-2O.js} +10 -10
- package/dist/DriversPage-D0RMBB_t.js +129 -0
- package/dist/{FinancePage-CnjUNXOb.js → FinancePage-BUXqW1IM.js} +6 -6
- package/dist/{FleetPage-CPS7r4J3.js → FleetPage-DCfOmBa2.js} +66 -65
- package/dist/{ImportExportPage-zNjs7xsV.js → ImportExportPage-BM1BoRcE.js} +3 -3
- package/dist/{InventoryPage-C9g5d3SW.js → InventoryPage-BW0QXWuf.js} +61 -66
- package/dist/{LiveTrackingPage-DoBvtdBG.js → LiveTrackingPage-DqcGXdkw.js} +8 -8
- package/dist/{MarketplacePage-BEj5hcBF.js → MarketplacePage-DFqsxNYU.js} +7 -7
- package/dist/MetricCard-B7yMyvMX.js +146 -0
- package/dist/{OrderDetailsPage-D-9lDZYU.js → OrderDetailsPage-Dx1m3cVA.js} +13 -13
- package/dist/{OrdersListPage-CJzHbgY3.js → OrdersListPage-DHYBGrWf.js} +76 -77
- package/dist/{PageLayout-xDTiBTDS.js → PageLayout-D3N8MCTm.js} +213 -195
- package/dist/{ProductDetailsPage-3rKtzXpy.js → ProductDetailsPage-DOXO90kb.js} +6 -6
- package/dist/{ProductsPage-B0P_wjBJ.js → ProductsPage-RLMTwWN0.js} +41 -39
- package/dist/{ReportsPage-B8OyWGzl.js → ReportsPage-Df3hciPy.js} +4 -4
- package/dist/{RouteDetailsPage-DGjKTUMj.js → RouteDetailsPage-xzFDeR-X.js} +8 -8
- package/dist/{RoutesPage-CpopY8xN.js → RoutesPage-DDFy1QVi.js} +32 -30
- package/dist/{SettingsPage-BvXSa3gi.js → SettingsPage-JH_-UPbf.js} +4 -4
- package/dist/{StatusBadge-C--7NhoW.js → StatusBadge-CijYQXtb.js} +5 -2
- package/dist/{TrackingPage-BldUm_g7.js → TrackingPage-CU0Vk4mx.js} +11 -11
- package/dist/{VehicleDetailsPage-Dqv--MVW.js → VehicleDetailsPage-P4xDttKw.js} +8 -8
- package/dist/{VehiclesPage-CCBHRDHu.js → VehiclesPage-tJZ64QKV.js} +42 -40
- package/dist/{WarehouseDetailsPage-ZObC_c7W.js → WarehouseDetailsPage-Bt_w2Yf7.js} +8 -8
- package/dist/{WarehousesPage-CpgZEVW9.js → WarehousesPage-HsPpEFeG.js} +37 -32
- package/dist/{arrow-left-Bk5GsGNk.js → arrow-left-CBpZKkpq.js} +1 -1
- package/dist/{box-BAMv2-7M.js → box-CAaiElsb.js} +1 -1
- package/dist/{chart-column-CAfkf4o6.js → chart-column-D1Ym15-S.js} +1 -1
- package/dist/{chevron-right-Czrt_Qew.js → chevron-right-BIFGi0UA.js} +1 -1
- package/dist/{circle-alert-CEuV9Pij.js → circle-alert-DjmNo5_L.js} +1 -1
- package/dist/{circle-check-big-Cx8aO6B-.js → circle-check-big-CjuPVo3_.js} +1 -1
- package/dist/{clock-Be95bq7_.js → clock-BjkdnddD.js} +1 -1
- package/dist/{dollar-sign-kJqItPli.js → dollar-sign-IB4O0wuQ.js} +1 -1
- package/dist/{download-caab0D3V.js → download-Dpa9vqoG.js} +1 -1
- package/dist/{file-text-b1qhrJn1.js → file-text-C8Uioy11.js} +1 -1
- package/dist/{filter-BWmLTZB-.js → filter-Da5OZaHI.js} +1 -1
- package/dist/index.js +16 -16
- package/dist/{map-CS2aFgyO.js → map-_Per4sT9.js} +1 -1
- package/dist/{map-pin-96FeqL7H.js → map-pin-BSaf5IDL.js} +1 -1
- package/dist/{navigation-i6UXEjTC.js → navigation-DaTbrhw2.js} +1 -1
- package/dist/{package-KhSi3xaT.js → package-BE7U0wQE.js} +1 -1
- package/dist/{phone-B-h3tbsr.js → phone-DV4StZiA.js} +1 -1
- package/dist/{plus-D2BYAzMn.js → plus-Dl1rLeJR.js} +1 -1
- package/dist/{refresh-cw-D5Sy01s-.js → refresh-cw-CWfERAit.js} +1 -1
- package/dist/{route-CBDXuwH9.js → route-Dp9JiN_E.js} +1 -1
- package/dist/{save-CMc7h-Vi.js → save-XH8vydOn.js} +1 -1
- package/dist/{search-DVrUQbOg.js → search-OxoIiL_C.js} +1 -1
- package/dist/{settings-BwzIRYv3.js → settings-3Rw5NwFF.js} +1 -1
- package/dist/{square-pen-DmW36Bau.js → square-pen-hLIbFQFV.js} +1 -1
- package/dist/{star-Cv2MzxZL.js → star-YsVV3MNQ.js} +1 -1
- package/dist/{store-CLH957vl.js → store-RCBl7HB-.js} +1 -1
- package/dist/{trending-up-l8M0BO_w.js → trending-up-C-85AwGT.js} +1 -1
- package/dist/{triangle-alert-BI45s6bH.js → triangle-alert-BOhfGgmh.js} +1 -1
- package/dist/{truck-DX3lNQkz.js → truck-CtDjNFbi.js} +1 -1
- package/dist/{user-D8EY1uvt.js → user-Dz5TJZFs.js} +1 -1
- package/dist/{users-CfG0J8wP.js → users-g2N0eL-Z.js} +1 -1
- package/dist/{warehouse-Dt_bAr82.js → warehouse-D3WWDeTX.js} +1 -1
- package/dist/{wrench-C50eI_Iy.js → wrench-CmxY1n4I.js} +1 -1
- package/package.json +2 -2
- package/src/movethewheels/components/DataTable.tsx +4 -4
- package/src/movethewheels/components/MetricCard.tsx +49 -20
- package/src/movethewheels/components/PageLayout.tsx +60 -5
- package/src/movethewheels/components/StatusBadge.tsx +2 -1
- package/src/movethewheels/pages/CustomersPage.tsx +13 -12
- package/src/movethewheels/pages/DashboardPage.tsx +55 -48
- package/src/movethewheels/pages/DriversPage.tsx +9 -12
- package/src/movethewheels/pages/FleetPage.tsx +15 -10
- package/src/movethewheels/pages/InventoryPage.tsx +18 -11
- package/src/movethewheels/pages/OrdersListPage.tsx +20 -14
- package/src/movethewheels/pages/ProductsPage.tsx +9 -12
- package/src/movethewheels/pages/RoutesPage.tsx +12 -9
- package/src/movethewheels/pages/TrackingPage.tsx +2 -2
- package/src/movethewheels/pages/VehiclesPage.tsx +9 -15
- package/src/movethewheels/pages/WarehousesPage.tsx +8 -9
- package/dist/CustomersPage-d21ixOYa.js +0 -119
- package/dist/DriversPage-BOhqEBTv.js +0 -127
- package/dist/MetricCard-DeHVeVwl.js +0 -135
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
import { AuroraBackground, GradientText, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';
|
|
2
3
|
import { cn } from '../utils/cn';
|
|
3
4
|
|
|
4
5
|
interface PageLayoutProps {
|
|
@@ -21,6 +22,16 @@ interface PageLayoutProps {
|
|
|
21
22
|
className?: string;
|
|
22
23
|
/** Additional CSS classes for the content area */
|
|
23
24
|
contentClassName?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Boff UI 2.0 — render a subtle living aurora backdrop behind the page header.
|
|
27
|
+
* Reserved for the MFE's single primary page (the Dashboard). One per MFE.
|
|
28
|
+
*/
|
|
29
|
+
hero?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Boff UI 2.0 — the slice of the title to emphasise with a brand gradient.
|
|
32
|
+
* When provided, the title renders as `…<GradientText>{titleAccent}</GradientText>`.
|
|
33
|
+
*/
|
|
34
|
+
titleAccent?: string;
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
const maxWidthClasses = {
|
|
@@ -53,7 +64,24 @@ export function PageLayout({
|
|
|
53
64
|
showHeader = true,
|
|
54
65
|
className,
|
|
55
66
|
contentClassName,
|
|
67
|
+
hero = false,
|
|
68
|
+
titleAccent,
|
|
56
69
|
}: PageLayoutProps) {
|
|
70
|
+
// Render the title, optionally clipping a gradient into the accent slice.
|
|
71
|
+
const renderTitle = (value: string) => {
|
|
72
|
+
if (!titleAccent || !value.includes(titleAccent)) {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
const [before, after] = value.split(titleAccent);
|
|
76
|
+
return (
|
|
77
|
+
<>
|
|
78
|
+
{before}
|
|
79
|
+
<GradientText>{titleAccent}</GradientText>
|
|
80
|
+
{after}
|
|
81
|
+
</>
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
|
|
57
85
|
return (
|
|
58
86
|
<div
|
|
59
87
|
className={cn(
|
|
@@ -72,20 +100,27 @@ export function PageLayout({
|
|
|
72
100
|
<div className={cn('mx-auto w-full', maxWidthClasses[maxWidth], contentClassName)}>
|
|
73
101
|
{/* Page Header */}
|
|
74
102
|
{showHeader && (title || headerActions) && (
|
|
75
|
-
<header
|
|
103
|
+
<header
|
|
104
|
+
className={cn(
|
|
105
|
+
'mb-6 sm:mb-8',
|
|
106
|
+
hero &&
|
|
107
|
+
'relative overflow-hidden rounded-card border border-border-seam bg-hero-mesh px-5 py-6 sm:px-7 sm:py-8'
|
|
108
|
+
)}
|
|
109
|
+
>
|
|
110
|
+
{hero && <AuroraBackground intensity="subtle" />}
|
|
76
111
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
|
77
112
|
{/* Title Section */}
|
|
78
113
|
<div className="space-y-1">
|
|
79
114
|
{(title || icon) && (
|
|
80
115
|
<div className="flex items-center gap-3">
|
|
81
116
|
{icon && (
|
|
82
|
-
<div className="flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-primary">
|
|
117
|
+
<div className="flex-shrink-0 p-2.5 rounded-xl bg-action-primary-bg/10 text-action-primary-bg">
|
|
83
118
|
{icon}
|
|
84
119
|
</div>
|
|
85
120
|
)}
|
|
86
121
|
{title && (
|
|
87
122
|
<h1 className="text-2xl sm:text-3xl font-bold tracking-tight text-text-primary">
|
|
88
|
-
{title}
|
|
123
|
+
{renderTitle(title)}
|
|
89
124
|
</h1>
|
|
90
125
|
)}
|
|
91
126
|
</div>
|
|
@@ -148,7 +183,13 @@ export function PageSection({
|
|
|
148
183
|
}
|
|
149
184
|
|
|
150
185
|
/**
|
|
151
|
-
* EmptyState - A consistent empty state component
|
|
186
|
+
* EmptyState - A consistent empty/zero state component.
|
|
187
|
+
*
|
|
188
|
+
* Boff UI 2.0: when an `illustration` name is provided (one of the standard
|
|
189
|
+
* host-served names — empty-data, empty-search, empty-files, empty-people,
|
|
190
|
+
* empty-notifications, onboarding, empty-generic), it renders the on-brand
|
|
191
|
+
* IllustratedEmptyState. Otherwise it falls back to the legacy icon layout so
|
|
192
|
+
* existing callers keep working unchanged.
|
|
152
193
|
*/
|
|
153
194
|
export function EmptyState({
|
|
154
195
|
icon,
|
|
@@ -156,13 +197,27 @@ export function EmptyState({
|
|
|
156
197
|
description,
|
|
157
198
|
action,
|
|
158
199
|
className,
|
|
200
|
+
illustration = 'empty-data',
|
|
159
201
|
}: {
|
|
160
202
|
icon?: ReactNode;
|
|
161
203
|
title: string;
|
|
162
204
|
description?: string;
|
|
163
205
|
action?: ReactNode;
|
|
164
206
|
className?: string;
|
|
207
|
+
/** Standard illustration name served by the host at /illustrations/<name>.webp. */
|
|
208
|
+
illustration?: string;
|
|
165
209
|
}) {
|
|
210
|
+
if (!icon) {
|
|
211
|
+
return (
|
|
212
|
+
<IllustratedEmptyState
|
|
213
|
+
illustration={illustration}
|
|
214
|
+
title={title}
|
|
215
|
+
description={description}
|
|
216
|
+
action={action}
|
|
217
|
+
className={cn('animate-in fade-in-0 zoom-in-95 duration-300', className)}
|
|
218
|
+
/>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
166
221
|
return (
|
|
167
222
|
<div
|
|
168
223
|
className={cn(
|
|
@@ -173,7 +228,7 @@ export function EmptyState({
|
|
|
173
228
|
className
|
|
174
229
|
)}
|
|
175
230
|
>
|
|
176
|
-
|
|
231
|
+
<div className="mb-4 p-4 rounded-2xl bg-bg-sunken/50 text-text-secondary">{icon}</div>
|
|
177
232
|
<h3 className="text-lg font-semibold text-text-primary mb-1">{title}</h3>
|
|
178
233
|
{description && <p className="text-sm text-text-secondary max-w-sm mb-4">{description}</p>}
|
|
179
234
|
{action}
|
|
@@ -78,8 +78,9 @@ export function StatusBadge({
|
|
|
78
78
|
>
|
|
79
79
|
{showDot && (
|
|
80
80
|
<span
|
|
81
|
+
aria-hidden="true"
|
|
81
82
|
className={cn(
|
|
82
|
-
'w-1.5 h-1.5 rounded-full mr-1.5 flex-shrink-0',
|
|
83
|
+
'w-1.5 h-1.5 rounded-full mr-1.5 flex-shrink-0 motion-safe:animate-vc-glow-pulse',
|
|
83
84
|
colors.text.replace('text-', 'bg-')
|
|
84
85
|
)}
|
|
85
86
|
/>
|
|
@@ -6,7 +6,8 @@ import { Users, Plus, RefreshCw, Download, Star } from 'lucide-react';
|
|
|
6
6
|
import { PageLayout } from '../components/PageLayout';
|
|
7
7
|
import { DataTable, type Column } from '../components/DataTable';
|
|
8
8
|
import { TypeBadge } from '../components/StatusBadge';
|
|
9
|
-
import {
|
|
9
|
+
import { Badge, Avatar, AvatarFallback } from '../components/ui';
|
|
10
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
10
11
|
import { useCustomers } from '../hooks/useCustomers';
|
|
11
12
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
12
13
|
import { formatDate } from '../utils/formatters';
|
|
@@ -87,17 +88,17 @@ export default function CustomersPage() {
|
|
|
87
88
|
subtitle={`${totalCustomers} customers`}
|
|
88
89
|
icon={<Users size={24} />}
|
|
89
90
|
headerActions={
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
<
|
|
99
|
-
|
|
100
|
-
|
|
91
|
+
<CTAOverflowMenu
|
|
92
|
+
primary={{
|
|
93
|
+
label: 'Add Customer',
|
|
94
|
+
icon: <Plus size={16} />,
|
|
95
|
+
onSelect: () => goTo('customers/new'),
|
|
96
|
+
}}
|
|
97
|
+
actions={[
|
|
98
|
+
{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
|
|
99
|
+
{ label: 'Export', icon: <Download size={16} />, onSelect: () => {} },
|
|
100
|
+
]}
|
|
101
|
+
/>
|
|
101
102
|
}
|
|
102
103
|
>
|
|
103
104
|
<DataTable
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
Badge,
|
|
28
28
|
Progress,
|
|
29
29
|
} from '../components/ui';
|
|
30
|
+
import { CTAOverflowMenu, EmphasisPanel } from '@burdenoff/fe-libs/ui';
|
|
30
31
|
import { useDashboardMetrics } from '../hooks/useAnalytics';
|
|
31
32
|
import { useOrders, useOrderStats } from '../hooks/useOrders';
|
|
32
33
|
import { useFleetStats } from '../hooks/useFleet';
|
|
@@ -57,20 +58,26 @@ export default function DashboardPage() {
|
|
|
57
58
|
|
|
58
59
|
return (
|
|
59
60
|
<PageLayout
|
|
61
|
+
hero
|
|
62
|
+
titleAccent={t('movethewheels.dashboard.title', 'Dashboard')}
|
|
60
63
|
title={t('movethewheels.dashboard.title', 'Dashboard')}
|
|
61
64
|
subtitle={t('movethewheels.dashboard.subtitle', 'Overview of your logistics operations')}
|
|
62
65
|
icon={<TrendingUp size={24} />}
|
|
63
66
|
headerActions={
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
{
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
<CTAOverflowMenu
|
|
68
|
+
primary={{
|
|
69
|
+
label: t('movethewheels.dashboard.actions.newOrder', 'New Order'),
|
|
70
|
+
icon: <Package size={16} />,
|
|
71
|
+
onSelect: () => goTo('orders/new'),
|
|
72
|
+
}}
|
|
73
|
+
actions={[
|
|
74
|
+
{
|
|
75
|
+
label: t('movethewheels.dashboard.actions.liveMap', 'Live Map'),
|
|
76
|
+
icon: <MapPin size={16} />,
|
|
77
|
+
onSelect: () => goTo('tracking/live'),
|
|
78
|
+
},
|
|
79
|
+
]}
|
|
80
|
+
/>
|
|
74
81
|
}
|
|
75
82
|
>
|
|
76
83
|
{/* Key Metrics */}
|
|
@@ -99,6 +106,8 @@ export default function DashboardPage() {
|
|
|
99
106
|
onClick={() => goTo('fleet')}
|
|
100
107
|
/>
|
|
101
108
|
<MetricCard
|
|
109
|
+
treatment="glass"
|
|
110
|
+
glow
|
|
102
111
|
label={t('movethewheels.dashboard.metrics.revenue', 'Revenue')}
|
|
103
112
|
value={formatCurrency(metrics.revenue.total)}
|
|
104
113
|
icon={<DollarSign size={20} />}
|
|
@@ -234,45 +243,43 @@ export default function DashboardPage() {
|
|
|
234
243
|
</div>
|
|
235
244
|
|
|
236
245
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
237
|
-
{/* Order Status Summary */}
|
|
238
|
-
<
|
|
239
|
-
<
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
status.replace('_', ' ')
|
|
267
|
-
)}
|
|
268
|
-
</span>
|
|
269
|
-
</div>
|
|
270
|
-
<Badge variant="secondary">{count}</Badge>
|
|
246
|
+
{/* Order Status Summary — the page's single emphasis zone */}
|
|
247
|
+
<EmphasisPanel className="space-y-4">
|
|
248
|
+
<h2 className="text-base font-semibold text-text-primary">
|
|
249
|
+
{t('movethewheels.dashboard.orderStatus.title', 'Order Status')}
|
|
250
|
+
</h2>
|
|
251
|
+
<div className="space-y-3">
|
|
252
|
+
{[
|
|
253
|
+
{ status: 'pending', count: orderStats.byStatus.pending, color: 'bg-yellow-500' },
|
|
254
|
+
{
|
|
255
|
+
status: 'in_transit',
|
|
256
|
+
count: orderStats.byStatus.in_transit,
|
|
257
|
+
color: 'bg-blue-500',
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
status: 'delivered',
|
|
261
|
+
count: orderStats.byStatus.delivered,
|
|
262
|
+
color: 'bg-green-500',
|
|
263
|
+
},
|
|
264
|
+
{ status: 'cancelled', count: orderStats.byStatus.cancelled, color: 'bg-red-500' },
|
|
265
|
+
].map(({ status, count, color }) => (
|
|
266
|
+
<div key={status} className="flex items-center justify-between">
|
|
267
|
+
<div className="flex items-center gap-2">
|
|
268
|
+
<div className={`w-2 h-2 rounded-full ${color}`} />
|
|
269
|
+
<span className="text-sm capitalize">
|
|
270
|
+
{t(
|
|
271
|
+
`movethewheels.dashboard.orderStatus.status.${status}`,
|
|
272
|
+
status.replace('_', ' ')
|
|
273
|
+
)}
|
|
274
|
+
</span>
|
|
271
275
|
</div>
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
+
<Badge variant="secondary" className="tabular-nums">
|
|
277
|
+
{count}
|
|
278
|
+
</Badge>
|
|
279
|
+
</div>
|
|
280
|
+
))}
|
|
281
|
+
</div>
|
|
282
|
+
</EmphasisPanel>
|
|
276
283
|
|
|
277
284
|
{/* Fleet Status */}
|
|
278
285
|
<Card>
|
|
@@ -6,7 +6,8 @@ import { Users, Plus, RefreshCw, Download, Star } from 'lucide-react';
|
|
|
6
6
|
import { PageLayout } from '../components/PageLayout';
|
|
7
7
|
import { DataTable, type Column } from '../components/DataTable';
|
|
8
8
|
import { StatusBadge } from '../components/StatusBadge';
|
|
9
|
-
import {
|
|
9
|
+
import { Avatar, AvatarFallback } from '../components/ui';
|
|
10
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
10
11
|
import { useDrivers } from '../hooks/useFleet';
|
|
11
12
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
12
13
|
import { formatDate } from '../utils/formatters';
|
|
@@ -90,17 +91,13 @@ export default function DriversPage() {
|
|
|
90
91
|
subtitle={`${totalDrivers} drivers`}
|
|
91
92
|
icon={<Users size={24} />}
|
|
92
93
|
headerActions={
|
|
93
|
-
<
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<Button>
|
|
101
|
-
<Plus size={16} /> Add Driver
|
|
102
|
-
</Button>
|
|
103
|
-
</div>
|
|
94
|
+
<CTAOverflowMenu
|
|
95
|
+
primary={{ label: 'Add Driver', icon: <Plus size={16} />, onSelect: () => {} }}
|
|
96
|
+
actions={[
|
|
97
|
+
{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
|
|
98
|
+
{ label: 'Export', icon: <Download size={16} />, onSelect: () => {} },
|
|
99
|
+
]}
|
|
100
|
+
/>
|
|
104
101
|
}
|
|
105
102
|
>
|
|
106
103
|
<DataTable
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
Avatar,
|
|
19
19
|
AvatarFallback,
|
|
20
20
|
} from '../components/ui';
|
|
21
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
21
22
|
import { useFleetStats, useVehicles, useDrivers } from '../hooks/useFleet';
|
|
22
23
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
23
24
|
import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
|
|
@@ -46,16 +47,20 @@ export default function FleetPage() {
|
|
|
46
47
|
subtitle={t('movethewheels.fleet.subtitle', 'Manage your vehicles and drivers')}
|
|
47
48
|
icon={<Truck size={24} />}
|
|
48
49
|
headerActions={
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
{
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
<CTAOverflowMenu
|
|
51
|
+
primary={{
|
|
52
|
+
label: t('movethewheels.fleet.actions.allVehicles', 'All Vehicles'),
|
|
53
|
+
icon: <Truck size={16} />,
|
|
54
|
+
onSelect: () => goTo('fleet/vehicles'),
|
|
55
|
+
}}
|
|
56
|
+
actions={[
|
|
57
|
+
{
|
|
58
|
+
label: t('movethewheels.fleet.actions.allDrivers', 'All Drivers'),
|
|
59
|
+
icon: <Users size={16} />,
|
|
60
|
+
onSelect: () => goTo('fleet/drivers'),
|
|
61
|
+
},
|
|
62
|
+
]}
|
|
63
|
+
/>
|
|
59
64
|
}
|
|
60
65
|
>
|
|
61
66
|
{/* Key Metrics */}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
Badge,
|
|
15
15
|
Progress,
|
|
16
16
|
} from '../components/ui';
|
|
17
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
17
18
|
import { useInventory, useInventoryStats } from '../hooks/useInventory';
|
|
18
19
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
19
20
|
import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
|
|
@@ -39,17 +40,23 @@ export default function InventoryPage() {
|
|
|
39
40
|
subtitle={t('movethewheels.inventory.subtitle', 'Manage your products and warehouses')}
|
|
40
41
|
icon={<Package size={24} />}
|
|
41
42
|
headerActions={
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
43
|
+
<CTAOverflowMenu
|
|
44
|
+
primary={{
|
|
45
|
+
label: t('movethewheels.inventory.actions.addProduct', 'Add Product'),
|
|
46
|
+
icon: <Plus size={16} />,
|
|
47
|
+
onSelect: () => {},
|
|
48
|
+
}}
|
|
49
|
+
actions={[
|
|
50
|
+
{
|
|
51
|
+
label: t('movethewheels.inventory.actions.products', 'Products'),
|
|
52
|
+
onSelect: () => goTo('inventory/products'),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: t('movethewheels.inventory.actions.warehouses', 'Warehouses'),
|
|
56
|
+
onSelect: () => goTo('inventory/warehouses'),
|
|
57
|
+
},
|
|
58
|
+
]}
|
|
59
|
+
/>
|
|
53
60
|
}
|
|
54
61
|
>
|
|
55
62
|
<MetricGrid columns={4}>
|
|
@@ -9,6 +9,7 @@ import { Package, Plus, Filter, Download, RefreshCw } from 'lucide-react';
|
|
|
9
9
|
import { PageLayout } from '../components/PageLayout';
|
|
10
10
|
import { DataTable, type Column } from '../components/DataTable';
|
|
11
11
|
import { StatusBadge, PriorityBadge, TypeBadge } from '../components/StatusBadge';
|
|
12
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
12
13
|
import {
|
|
13
14
|
Button,
|
|
14
15
|
Card,
|
|
@@ -152,20 +153,25 @@ export default function OrdersListPage() {
|
|
|
152
153
|
subtitle={`${totalOrders} ${t('movethewheels.orders.subtitle', 'total orders')}`}
|
|
153
154
|
icon={<Package size={24} />}
|
|
154
155
|
headerActions={
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
{
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
{
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
156
|
+
<CTAOverflowMenu
|
|
157
|
+
primary={{
|
|
158
|
+
label: t('movethewheels.orders.actions.newOrder', 'New Order'),
|
|
159
|
+
icon: <Plus size={16} />,
|
|
160
|
+
onSelect: () => goTo('orders/new'),
|
|
161
|
+
}}
|
|
162
|
+
actions={[
|
|
163
|
+
{
|
|
164
|
+
label: t('movethewheels.orders.actions.refresh', 'Refresh'),
|
|
165
|
+
icon: <RefreshCw size={16} />,
|
|
166
|
+
onSelect: () => refetch(),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
label: t('movethewheels.orders.actions.export', 'Export'),
|
|
170
|
+
icon: <Download size={16} />,
|
|
171
|
+
onSelect: () => {},
|
|
172
|
+
},
|
|
173
|
+
]}
|
|
174
|
+
/>
|
|
169
175
|
}
|
|
170
176
|
>
|
|
171
177
|
{/* Filters */}
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
import { Package, Plus, RefreshCw, Download } from 'lucide-react';
|
|
6
6
|
import { PageLayout } from '../components/PageLayout';
|
|
7
7
|
import { DataTable, type Column } from '../components/DataTable';
|
|
8
|
-
import {
|
|
8
|
+
import { Badge } from '../components/ui';
|
|
9
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
9
10
|
import { useProducts } from '../hooks/useInventory';
|
|
10
11
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
11
12
|
import { formatCurrency } from '../utils/formatters';
|
|
@@ -96,17 +97,13 @@ export default function ProductsPage() {
|
|
|
96
97
|
subtitle={`${totalProducts} products`}
|
|
97
98
|
icon={<Package size={24} />}
|
|
98
99
|
headerActions={
|
|
99
|
-
<
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
<Button>
|
|
107
|
-
<Plus size={16} /> Add Product
|
|
108
|
-
</Button>
|
|
109
|
-
</div>
|
|
100
|
+
<CTAOverflowMenu
|
|
101
|
+
primary={{ label: 'Add Product', icon: <Plus size={16} />, onSelect: () => {} }}
|
|
102
|
+
actions={[
|
|
103
|
+
{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
|
|
104
|
+
{ label: 'Export', icon: <Download size={16} />, onSelect: () => {} },
|
|
105
|
+
]}
|
|
106
|
+
/>
|
|
110
107
|
}
|
|
111
108
|
>
|
|
112
109
|
<DataTable
|
|
@@ -6,7 +6,8 @@ import { Plus, RefreshCw, Navigation } from 'lucide-react';
|
|
|
6
6
|
import { PageLayout } from '../components/PageLayout';
|
|
7
7
|
import { DataTable, type Column } from '../components/DataTable';
|
|
8
8
|
import { StatusBadge } from '../components/StatusBadge';
|
|
9
|
-
import {
|
|
9
|
+
import { Badge } from '../components/ui';
|
|
10
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
10
11
|
import { useRoutes } from '../hooks/useRoutes';
|
|
11
12
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
12
13
|
import { formatDate } from '../utils/formatters';
|
|
@@ -79,14 +80,16 @@ export default function RoutesPage() {
|
|
|
79
80
|
subtitle={`${totalRoutes} routes`}
|
|
80
81
|
icon={<Navigation size={24} />}
|
|
81
82
|
headerActions={
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
<CTAOverflowMenu
|
|
84
|
+
primary={{
|
|
85
|
+
label: 'Create Route',
|
|
86
|
+
icon: <Plus size={16} />,
|
|
87
|
+
onSelect: () => goTo('routes/new'),
|
|
88
|
+
}}
|
|
89
|
+
actions={[
|
|
90
|
+
{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
|
|
91
|
+
]}
|
|
92
|
+
/>
|
|
90
93
|
}
|
|
91
94
|
>
|
|
92
95
|
<DataTable
|
|
@@ -106,7 +106,7 @@ export default function TrackingPage() {
|
|
|
106
106
|
{/* No Search Yet */}
|
|
107
107
|
{!searchedOrderId && !error && (
|
|
108
108
|
<EmptyState
|
|
109
|
-
|
|
109
|
+
illustration="onboarding"
|
|
110
110
|
title={t('movethewheels.tracking.empty.title', 'Enter a tracking number')}
|
|
111
111
|
description={t(
|
|
112
112
|
'movethewheels.tracking.empty.description',
|
|
@@ -404,7 +404,7 @@ export default function TrackingPage() {
|
|
|
404
404
|
{/* No Results */}
|
|
405
405
|
{searchedOrderId && !order && !isLoading && !error && (
|
|
406
406
|
<EmptyState
|
|
407
|
-
|
|
407
|
+
illustration="empty-search"
|
|
408
408
|
title={t('movethewheels.tracking.notFound.title', 'Shipment not found')}
|
|
409
409
|
description={`${t('movethewheels.tracking.notFound.descriptionPrefix', 'No shipment found with tracking number')} "${searchedOrderId}"`}
|
|
410
410
|
action={
|
|
@@ -6,7 +6,8 @@ import { Truck, Plus, RefreshCw, Download } from 'lucide-react';
|
|
|
6
6
|
import { PageLayout } from '../components/PageLayout';
|
|
7
7
|
import { DataTable, type Column } from '../components/DataTable';
|
|
8
8
|
import { StatusBadge, VehicleTypeBadge } from '../components/StatusBadge';
|
|
9
|
-
import {
|
|
9
|
+
import { Progress } from '../components/ui';
|
|
10
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
10
11
|
import { useVehicles } from '../hooks/useFleet';
|
|
11
12
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
12
13
|
import { joinPath } from '../utils/navigation';
|
|
@@ -93,20 +94,13 @@ export default function VehiclesPage() {
|
|
|
93
94
|
subtitle={`${totalVehicles} vehicles in fleet`}
|
|
94
95
|
icon={<Truck size={24} />}
|
|
95
96
|
headerActions={
|
|
96
|
-
<
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
Refresh
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
Export
|
|
104
|
-
</Button>
|
|
105
|
-
<Button>
|
|
106
|
-
<Plus size={16} />
|
|
107
|
-
Add Vehicle
|
|
108
|
-
</Button>
|
|
109
|
-
</div>
|
|
97
|
+
<CTAOverflowMenu
|
|
98
|
+
primary={{ label: 'Add Vehicle', icon: <Plus size={16} />, onSelect: () => {} }}
|
|
99
|
+
actions={[
|
|
100
|
+
{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
|
|
101
|
+
{ label: 'Export', icon: <Download size={16} />, onSelect: () => {} },
|
|
102
|
+
]}
|
|
103
|
+
/>
|
|
110
104
|
}
|
|
111
105
|
>
|
|
112
106
|
<DataTable
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
import { Warehouse, Plus, RefreshCw } from 'lucide-react';
|
|
6
6
|
import { PageLayout } from '../components/PageLayout';
|
|
7
7
|
import { DataTable, type Column } from '../components/DataTable';
|
|
8
|
-
import {
|
|
8
|
+
import { Badge, Progress } from '../components/ui';
|
|
9
|
+
import { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';
|
|
9
10
|
import { useWarehouses } from '../hooks/useInventory';
|
|
10
11
|
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
11
12
|
import { joinPath } from '../utils/navigation';
|
|
@@ -97,14 +98,12 @@ export default function WarehousesPage() {
|
|
|
97
98
|
subtitle={`${totalWarehouses} warehouses`}
|
|
98
99
|
icon={<Warehouse size={24} />}
|
|
99
100
|
headerActions={
|
|
100
|
-
<
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
</Button>
|
|
107
|
-
</div>
|
|
101
|
+
<CTAOverflowMenu
|
|
102
|
+
primary={{ label: 'Add Warehouse', icon: <Plus size={16} />, onSelect: () => {} }}
|
|
103
|
+
actions={[
|
|
104
|
+
{ label: 'Refresh', icon: <RefreshCw size={16} />, onSelect: () => refetch() },
|
|
105
|
+
]}
|
|
106
|
+
/>
|
|
108
107
|
}
|
|
109
108
|
>
|
|
110
109
|
<DataTable
|