@burdenoff/microfe-movethewheels 2026.510.105
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -0
- package/dist/AIAssistantPage-hD0VYJdH.js +210 -0
- package/dist/AnalyticsPage-DHTHCUtr.js +201 -0
- package/dist/CreateOrderPage-Cprg4Y9V.js +471 -0
- package/dist/CustomerDetailsPage-DNDEw7IW.js +239 -0
- package/dist/CustomersPage-CDjjeCEL.js +119 -0
- package/dist/DashboardPage-8iTPXRAG.js +374 -0
- package/dist/DataTable-CRIKfdIN.js +239 -0
- package/dist/DriverDetailsPage-CRyRCno7.js +297 -0
- package/dist/DriversPage-16O8fVmf.js +127 -0
- package/dist/FinancePage-BYUxK5dR.js +154 -0
- package/dist/FleetPage-CHYETCWT.js +293 -0
- package/dist/ImportExportPage-C3MKKxfc.js +232 -0
- package/dist/InventoryPage--822AxZM.js +223 -0
- package/dist/LiveTrackingPage-Dp3rTJDr.js +332 -0
- package/dist/MarketplacePage-DjEqudfM.js +192 -0
- package/dist/MetricCard-GTbxAk1a.js +135 -0
- package/dist/OrderDetailsPage-BIuYG0ub.js +398 -0
- package/dist/OrdersListPage-CW5V0Uvh.js +257 -0
- package/dist/PageLayout-B7b0vl0R.js +1894 -0
- package/dist/ProductDetailsPage-Q3X7AT-7.js +168 -0
- package/dist/ProductsPage-CUj9JpnW.js +131 -0
- package/dist/ReportsPage-DblO5CdJ.js +227 -0
- package/dist/RouteDetailsPage-CLctgk6A.js +240 -0
- package/dist/RoutesPage-8hrv6RWT.js +116 -0
- package/dist/SettingsPage-BJ5BQeqn.js +247 -0
- package/dist/StatusBadge-BrrwraIA.js +206 -0
- package/dist/TrackingPage-BGqHDh-w.js +322 -0
- package/dist/VehicleDetailsPage-XnDH4iQR.js +194 -0
- package/dist/VehiclesPage-Cs4XxHkA.js +127 -0
- package/dist/WarehouseDetailsPage-GemdMvr_.js +215 -0
- package/dist/WarehousesPage-QTiuDuXy.js +121 -0
- package/dist/arrow-left-6CiLhqVp.js +11 -0
- package/dist/box-BunB_4UH.js +18 -0
- package/dist/chart-column-DWwVEVQ-.js +22 -0
- package/dist/chevron-right-DhZVf20o.js +8 -0
- package/dist/circle-alert-D5f6RZxt.js +26 -0
- package/dist/circle-check-big-D-JMHcTe.js +11 -0
- package/dist/clock-CvwBKbQP.js +13 -0
- package/dist/dev/main.d.ts +1 -0
- package/dist/dollar-sign-CP9qeU5d.js +14 -0
- package/dist/download-CIuG04pJ.js +21 -0
- package/dist/file-text-Dd_thxkn.js +26 -0
- package/dist/filter-DyRMX9CU.js +8 -0
- package/dist/formatters-_vJlC-47.js +50 -0
- package/dist/generated/global-operations.d.ts +1 -0
- package/dist/generated/global-types.d.ts +20715 -0
- package/dist/generated/wspace-operations.d.ts +3704 -0
- package/dist/generated/wspace-types.d.ts +53362 -0
- package/dist/graphqlClient-CdJyR_ed.js +55 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +772 -0
- package/dist/map-BqH1cBJi.js +18 -0
- package/dist/map-pin-CFBOmh-A.js +13 -0
- package/dist/movethewheels/MoveTheWheelsRoot.d.ts +25 -0
- package/dist/movethewheels/MoveTheWheelsRoutes.d.ts +7 -0
- package/dist/movethewheels/components/DataTable.d.ts +32 -0
- package/dist/movethewheels/components/MetricCard.d.ts +43 -0
- package/dist/movethewheels/components/PageLayout.d.ts +68 -0
- package/dist/movethewheels/components/StatusBadge.d.ts +49 -0
- package/dist/movethewheels/components/index.d.ts +10 -0
- package/dist/movethewheels/components/ui.d.ts +22 -0
- package/dist/movethewheels/constants/index.d.ts +24 -0
- package/dist/movethewheels/constants/mockData.d.ts +33 -0
- package/dist/movethewheels/hooks/index.d.ts +12 -0
- package/dist/movethewheels/hooks/useAnalytics.d.ts +118 -0
- package/dist/movethewheels/hooks/useCustomers.d.ts +37 -0
- package/dist/movethewheels/hooks/useFleet.d.ts +71 -0
- package/dist/movethewheels/hooks/useInventory.d.ts +60 -0
- package/dist/movethewheels/hooks/useOrders.d.ts +47 -0
- package/dist/movethewheels/hooks/useRoutes.d.ts +41 -0
- package/dist/movethewheels/hooks/useTracking.d.ts +69 -0
- package/dist/movethewheels/index.d.ts +30 -0
- package/dist/movethewheels/pages/AIAssistantPage.d.ts +4 -0
- package/dist/movethewheels/pages/AnalyticsPage.d.ts +4 -0
- package/dist/movethewheels/pages/CreateOrderPage.d.ts +6 -0
- package/dist/movethewheels/pages/CustomerDetailsPage.d.ts +4 -0
- package/dist/movethewheels/pages/CustomersPage.d.ts +4 -0
- package/dist/movethewheels/pages/DashboardPage.d.ts +6 -0
- package/dist/movethewheels/pages/DriverDetailsPage.d.ts +4 -0
- package/dist/movethewheels/pages/DriversPage.d.ts +4 -0
- package/dist/movethewheels/pages/FinancePage.d.ts +4 -0
- package/dist/movethewheels/pages/FleetPage.d.ts +6 -0
- package/dist/movethewheels/pages/ImportExportPage.d.ts +4 -0
- package/dist/movethewheels/pages/InventoryPage.d.ts +4 -0
- package/dist/movethewheels/pages/LiveTrackingPage.d.ts +6 -0
- package/dist/movethewheels/pages/MarketplacePage.d.ts +4 -0
- package/dist/movethewheels/pages/OrderDetailsPage.d.ts +6 -0
- package/dist/movethewheels/pages/OrdersListPage.d.ts +6 -0
- package/dist/movethewheels/pages/ProductDetailsPage.d.ts +4 -0
- package/dist/movethewheels/pages/ProductsPage.d.ts +4 -0
- package/dist/movethewheels/pages/ReportsPage.d.ts +4 -0
- package/dist/movethewheels/pages/RouteDetailsPage.d.ts +4 -0
- package/dist/movethewheels/pages/RoutesPage.d.ts +4 -0
- package/dist/movethewheels/pages/SettingsPage.d.ts +4 -0
- package/dist/movethewheels/pages/TrackingPage.d.ts +6 -0
- package/dist/movethewheels/pages/VehicleDetailsPage.d.ts +4 -0
- package/dist/movethewheels/pages/VehiclesPage.d.ts +4 -0
- package/dist/movethewheels/pages/WarehouseDetailsPage.d.ts +4 -0
- package/dist/movethewheels/pages/WarehousesPage.d.ts +4 -0
- package/dist/movethewheels/providers/MoveTheWheelsProvider.d.ts +16 -0
- package/dist/movethewheels/store/movethewheelsStore.d.ts +73 -0
- package/dist/movethewheels/types/index.d.ts +655 -0
- package/dist/movethewheels/utils/cn.d.ts +6 -0
- package/dist/movethewheels/utils/formatters.d.ts +60 -0
- package/dist/movethewheels/utils/graphqlClient.d.ts +11 -0
- package/dist/movethewheels/utils/index.d.ts +7 -0
- package/dist/movethewheels/utils/navigation.d.ts +23 -0
- package/dist/navigation-BgnOfsVd.js +6 -0
- package/dist/navigation-C2fY_aS9.js +8 -0
- package/dist/package-DVZbDRcV.js +22 -0
- package/dist/phone-KdwpVmC4.js +18 -0
- package/dist/plus-Bl7uX6Ji.js +11 -0
- package/dist/refresh-cw-BYjl3K-8.js +22 -0
- package/dist/route-Ce_poKFi.js +51 -0
- package/dist/save-C-qDVat-.js +18 -0
- package/dist/search-5pdn5eOO.js +13 -0
- package/dist/settings-C4kIDsYg.js +28 -0
- package/dist/square-pen-BwQ67vLE.js +11 -0
- package/dist/star-BlVsC3Ad.js +8 -0
- package/dist/store-DTmQT5M0.js +26 -0
- package/dist/trending-up-C1faflCI.js +11 -0
- package/dist/triangle-alert-CUoVAA4L.js +18 -0
- package/dist/truck-BmDAzu05.js +30 -0
- package/dist/useAnalytics-ph7eTIK6.js +297 -0
- package/dist/useCustomers-bS3a4ytk.js +186 -0
- package/dist/useFleet-BdETplNE.js +398 -0
- package/dist/useInventory-Dwn18FPz.js +323 -0
- package/dist/useOrders-D_3_hGMp.js +324 -0
- package/dist/useRoutes-v4aBaS-E.js +224 -0
- package/dist/useTracking-De2KIUNu.js +261 -0
- package/dist/user-BplzDrLP.js +13 -0
- package/dist/users-i-igmsP4.js +24 -0
- package/dist/warehouse-DewG0PXh.js +25 -0
- package/dist/wrench-CoSDEIC7.js +31 -0
- package/package.json +107 -0
- package/src/dev/main.tsx +110 -0
- package/src/dev/styles.css +139 -0
- package/src/generated/global-operations.ts +2 -0
- package/src/generated/global-types.ts +24048 -0
- package/src/generated/wspace-operations.ts +3734 -0
- package/src/generated/wspace-types.ts +60715 -0
- package/src/index.ts +4 -0
- package/src/movethewheels/MoveTheWheelsRoot.tsx +258 -0
- package/src/movethewheels/MoveTheWheelsRoutes.tsx +119 -0
- package/src/movethewheels/components/DataTable.tsx +367 -0
- package/src/movethewheels/components/MetricCard.tsx +180 -0
- package/src/movethewheels/components/PageLayout.tsx +234 -0
- package/src/movethewheels/components/StatusBadge.tsx +243 -0
- package/src/movethewheels/components/index.ts +26 -0
- package/src/movethewheels/components/ui.tsx +124 -0
- package/src/movethewheels/constants/index.ts +65 -0
- package/src/movethewheels/constants/mockData.ts +1342 -0
- package/src/movethewheels/hooks/index.ts +55 -0
- package/src/movethewheels/hooks/useAnalytics.ts +476 -0
- package/src/movethewheels/hooks/useCustomers.ts +359 -0
- package/src/movethewheels/hooks/useFleet.ts +778 -0
- package/src/movethewheels/hooks/useInventory.ts +632 -0
- package/src/movethewheels/hooks/useOrders.ts +703 -0
- package/src/movethewheels/hooks/useRoutes.ts +453 -0
- package/src/movethewheels/hooks/useTracking.ts +505 -0
- package/src/movethewheels/index.ts +68 -0
- package/src/movethewheels/pages/AIAssistantPage.tsx +160 -0
- package/src/movethewheels/pages/AnalyticsPage.tsx +190 -0
- package/src/movethewheels/pages/CreateOrderPage.tsx +454 -0
- package/src/movethewheels/pages/CustomerDetailsPage.tsx +207 -0
- package/src/movethewheels/pages/CustomersPage.tsx +115 -0
- package/src/movethewheels/pages/DashboardPage.tsx +414 -0
- package/src/movethewheels/pages/DriverDetailsPage.tsx +261 -0
- package/src/movethewheels/pages/DriversPage.tsx +118 -0
- package/src/movethewheels/pages/FinancePage.tsx +141 -0
- package/src/movethewheels/pages/FleetPage.tsx +289 -0
- package/src/movethewheels/pages/ImportExportPage.tsx +165 -0
- package/src/movethewheels/pages/InventoryPage.tsx +212 -0
- package/src/movethewheels/pages/LiveTrackingPage.tsx +325 -0
- package/src/movethewheels/pages/MarketplacePage.tsx +235 -0
- package/src/movethewheels/pages/OrderDetailsPage.tsx +387 -0
- package/src/movethewheels/pages/OrdersListPage.tsx +241 -0
- package/src/movethewheels/pages/ProductDetailsPage.tsx +155 -0
- package/src/movethewheels/pages/ProductsPage.tsx +124 -0
- package/src/movethewheels/pages/ReportsPage.tsx +164 -0
- package/src/movethewheels/pages/RouteDetailsPage.tsx +245 -0
- package/src/movethewheels/pages/RoutesPage.tsx +104 -0
- package/src/movethewheels/pages/SettingsPage.tsx +242 -0
- package/src/movethewheels/pages/TrackingPage.tsx +419 -0
- package/src/movethewheels/pages/VehicleDetailsPage.tsx +218 -0
- package/src/movethewheels/pages/VehiclesPage.tsx +124 -0
- package/src/movethewheels/pages/WarehouseDetailsPage.tsx +216 -0
- package/src/movethewheels/pages/WarehousesPage.tsx +122 -0
- package/src/movethewheels/providers/MoveTheWheelsProvider.tsx +66 -0
- package/src/movethewheels/store/movethewheelsStore.ts +136 -0
- package/src/movethewheels/types/index.ts +744 -0
- package/src/movethewheels/utils/cn.ts +9 -0
- package/src/movethewheels/utils/formatters.ts +215 -0
- package/src/movethewheels/utils/graphqlClient.ts +63 -0
- package/src/movethewheels/utils/index.ts +8 -0
- package/src/movethewheels/utils/navigation.ts +70 -0
- package/src/operations/global/.gitkeep +0 -0
- package/src/operations/wspace/movethewheels/fragments/core.graphql +191 -0
- package/src/operations/wspace/movethewheels/mutations/entities.graphql +87 -0
- package/src/operations/wspace/movethewheels/mutations/logistics.graphql +86 -0
- package/src/operations/wspace/movethewheels/mutations/marketplace-reports.graphql +81 -0
- package/src/operations/wspace/movethewheels/mutations/orders.graphql +21 -0
- package/src/operations/wspace/movethewheels/queries/dashboard.graphql +61 -0
- package/src/operations/wspace/movethewheels/queries/entities.graphql +83 -0
- package/src/operations/wspace/movethewheels/queries/logistics.graphql +84 -0
- package/src/operations/wspace/movethewheels/queries/marketplace-reports.graphql +40 -0
- package/src/operations/wspace/movethewheels/queries/orders.graphql +43 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Order Details Page
|
|
3
|
+
*
|
|
4
|
+
* Displays detailed information about a specific order.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useParams } from 'react-router-dom';
|
|
8
|
+
import {
|
|
9
|
+
Package,
|
|
10
|
+
ArrowLeft,
|
|
11
|
+
MapPin,
|
|
12
|
+
User,
|
|
13
|
+
Truck,
|
|
14
|
+
Clock,
|
|
15
|
+
DollarSign,
|
|
16
|
+
Phone,
|
|
17
|
+
Mail,
|
|
18
|
+
FileText,
|
|
19
|
+
CheckCircle,
|
|
20
|
+
Edit,
|
|
21
|
+
Printer,
|
|
22
|
+
} from 'lucide-react';
|
|
23
|
+
import { PageLayout, LoadingState, ErrorState } from '../components/PageLayout';
|
|
24
|
+
import {
|
|
25
|
+
StatusBadge,
|
|
26
|
+
PriorityBadge,
|
|
27
|
+
TypeBadge,
|
|
28
|
+
PaymentStatusBadge,
|
|
29
|
+
} from '../components/StatusBadge';
|
|
30
|
+
import {
|
|
31
|
+
Card,
|
|
32
|
+
CardContent,
|
|
33
|
+
CardHeader,
|
|
34
|
+
CardTitle,
|
|
35
|
+
Button,
|
|
36
|
+
Badge,
|
|
37
|
+
Separator,
|
|
38
|
+
Table,
|
|
39
|
+
TableBody,
|
|
40
|
+
TableCell,
|
|
41
|
+
TableHead,
|
|
42
|
+
TableHeader,
|
|
43
|
+
TableRow,
|
|
44
|
+
} from '../components/ui';
|
|
45
|
+
import { useOrder } from '../hooks/useOrders';
|
|
46
|
+
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
47
|
+
import { formatCurrency, formatDate, formatAddress } from '../utils/formatters';
|
|
48
|
+
import { joinPath } from '../utils/navigation';
|
|
49
|
+
|
|
50
|
+
export default function OrderDetailsPage() {
|
|
51
|
+
const { orderId } = useParams<{ orderId: string }>();
|
|
52
|
+
const { basePath, navigate } = useMoveTheWheels();
|
|
53
|
+
const { order, isLoading, error, refetch } = useOrder(orderId);
|
|
54
|
+
|
|
55
|
+
const goTo = (path: string) => {
|
|
56
|
+
if (navigate) {
|
|
57
|
+
navigate(joinPath(basePath, path));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const goBack = () => {
|
|
62
|
+
if (navigate) {
|
|
63
|
+
navigate(joinPath(basePath, 'orders'));
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
if (isLoading) {
|
|
68
|
+
return <LoadingState message="Loading order details..." />;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (error || !order) {
|
|
72
|
+
return (
|
|
73
|
+
<ErrorState
|
|
74
|
+
title="Order not found"
|
|
75
|
+
message="The order you're looking for doesn't exist or has been removed."
|
|
76
|
+
onRetry={refetch}
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<PageLayout
|
|
83
|
+
title={order.orderNumber}
|
|
84
|
+
subtitle={`Created ${formatDate(order.createdAt, 'full')}`}
|
|
85
|
+
icon={<Package size={24} />}
|
|
86
|
+
headerActions={
|
|
87
|
+
<div className="flex gap-2">
|
|
88
|
+
<Button variant="outline" onClick={goBack}>
|
|
89
|
+
<ArrowLeft size={16} />
|
|
90
|
+
Back
|
|
91
|
+
</Button>
|
|
92
|
+
<Button variant="outline">
|
|
93
|
+
<Printer size={16} />
|
|
94
|
+
Print
|
|
95
|
+
</Button>
|
|
96
|
+
<Button onClick={() => goTo(`orders/${orderId}/edit`)}>
|
|
97
|
+
<Edit size={16} />
|
|
98
|
+
Edit
|
|
99
|
+
</Button>
|
|
100
|
+
</div>
|
|
101
|
+
}
|
|
102
|
+
headerContent={
|
|
103
|
+
<div className="flex flex-wrap gap-2">
|
|
104
|
+
<StatusBadge status={order.status} type="order" />
|
|
105
|
+
<PriorityBadge priority={order.priority} />
|
|
106
|
+
<TypeBadge type={order.orderType} />
|
|
107
|
+
<PaymentStatusBadge status={order.pricing.paymentStatus} />
|
|
108
|
+
</div>
|
|
109
|
+
}
|
|
110
|
+
>
|
|
111
|
+
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
112
|
+
{/* Main Content */}
|
|
113
|
+
<div className="lg:col-span-2 space-y-6">
|
|
114
|
+
{/* Customer Information */}
|
|
115
|
+
<Card>
|
|
116
|
+
<CardHeader>
|
|
117
|
+
<CardTitle className="flex items-center gap-2">
|
|
118
|
+
<User size={18} />
|
|
119
|
+
Customer Information
|
|
120
|
+
</CardTitle>
|
|
121
|
+
</CardHeader>
|
|
122
|
+
<CardContent>
|
|
123
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
124
|
+
<div>
|
|
125
|
+
<h4 className="font-medium mb-2">{order.customerInfo.name}</h4>
|
|
126
|
+
{order.customerInfo.company && (
|
|
127
|
+
<p className="text-sm text-muted-foreground mb-2">
|
|
128
|
+
{order.customerInfo.company}
|
|
129
|
+
</p>
|
|
130
|
+
)}
|
|
131
|
+
<div className="space-y-1 text-sm">
|
|
132
|
+
<p className="flex items-center gap-2">
|
|
133
|
+
<Mail size={14} className="text-muted-foreground" />
|
|
134
|
+
{order.customerInfo.email}
|
|
135
|
+
</p>
|
|
136
|
+
<p className="flex items-center gap-2">
|
|
137
|
+
<Phone size={14} className="text-muted-foreground" />
|
|
138
|
+
{order.customerInfo.phone}
|
|
139
|
+
</p>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
<div>
|
|
143
|
+
{order.customerInfo.preferredDeliveryTime && (
|
|
144
|
+
<div className="mb-2">
|
|
145
|
+
<p className="text-sm text-muted-foreground">Preferred Delivery Time</p>
|
|
146
|
+
<p className="text-sm">{order.customerInfo.preferredDeliveryTime}</p>
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
{order.customerInfo.deliveryInstructions && (
|
|
150
|
+
<div>
|
|
151
|
+
<p className="text-sm text-muted-foreground">Delivery Instructions</p>
|
|
152
|
+
<p className="text-sm">{order.customerInfo.deliveryInstructions}</p>
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</CardContent>
|
|
158
|
+
</Card>
|
|
159
|
+
|
|
160
|
+
{/* Addresses */}
|
|
161
|
+
<Card>
|
|
162
|
+
<CardHeader>
|
|
163
|
+
<CardTitle className="flex items-center gap-2">
|
|
164
|
+
<MapPin size={18} />
|
|
165
|
+
Addresses
|
|
166
|
+
</CardTitle>
|
|
167
|
+
</CardHeader>
|
|
168
|
+
<CardContent>
|
|
169
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
170
|
+
<div>
|
|
171
|
+
<h4 className="font-medium mb-2 flex items-center gap-2">
|
|
172
|
+
<Badge variant="outline">Pickup</Badge>
|
|
173
|
+
</h4>
|
|
174
|
+
<p className="text-sm">{formatAddress(order.pickupAddress)}</p>
|
|
175
|
+
{order.scheduledPickup && (
|
|
176
|
+
<p className="text-sm text-muted-foreground mt-2">
|
|
177
|
+
Scheduled: {formatDate(order.scheduledPickup, 'full')}
|
|
178
|
+
</p>
|
|
179
|
+
)}
|
|
180
|
+
{order.actualPickup && (
|
|
181
|
+
<p className="text-sm text-green-600 mt-1">
|
|
182
|
+
<CheckCircle size={14} className="inline mr-1" />
|
|
183
|
+
Picked up: {formatDate(order.actualPickup, 'full')}
|
|
184
|
+
</p>
|
|
185
|
+
)}
|
|
186
|
+
</div>
|
|
187
|
+
<div>
|
|
188
|
+
<h4 className="font-medium mb-2 flex items-center gap-2">
|
|
189
|
+
<Badge variant="outline">Delivery</Badge>
|
|
190
|
+
</h4>
|
|
191
|
+
<p className="text-sm">{formatAddress(order.deliveryAddress)}</p>
|
|
192
|
+
{order.scheduledDelivery && (
|
|
193
|
+
<p className="text-sm text-muted-foreground mt-2">
|
|
194
|
+
Scheduled: {formatDate(order.scheduledDelivery, 'full')}
|
|
195
|
+
</p>
|
|
196
|
+
)}
|
|
197
|
+
{order.actualDelivery && (
|
|
198
|
+
<p className="text-sm text-green-600 mt-1">
|
|
199
|
+
<CheckCircle size={14} className="inline mr-1" />
|
|
200
|
+
Delivered: {formatDate(order.actualDelivery, 'full')}
|
|
201
|
+
</p>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</CardContent>
|
|
206
|
+
</Card>
|
|
207
|
+
|
|
208
|
+
{/* Order Items */}
|
|
209
|
+
<Card>
|
|
210
|
+
<CardHeader>
|
|
211
|
+
<CardTitle className="flex items-center gap-2">
|
|
212
|
+
<Package size={18} />
|
|
213
|
+
Order Items ({order.items.length})
|
|
214
|
+
</CardTitle>
|
|
215
|
+
</CardHeader>
|
|
216
|
+
<CardContent className="p-0">
|
|
217
|
+
<Table>
|
|
218
|
+
<TableHeader>
|
|
219
|
+
<TableRow>
|
|
220
|
+
<TableHead>Item</TableHead>
|
|
221
|
+
<TableHead>SKU</TableHead>
|
|
222
|
+
<TableHead className="text-center">Qty</TableHead>
|
|
223
|
+
<TableHead className="text-right">Unit Price</TableHead>
|
|
224
|
+
<TableHead className="text-right">Total</TableHead>
|
|
225
|
+
</TableRow>
|
|
226
|
+
</TableHeader>
|
|
227
|
+
<TableBody>
|
|
228
|
+
{order.items.map((item) => (
|
|
229
|
+
<TableRow key={item.id}>
|
|
230
|
+
<TableCell>
|
|
231
|
+
<div>
|
|
232
|
+
<p className="font-medium">{item.name}</p>
|
|
233
|
+
{item.description && (
|
|
234
|
+
<p className="text-sm text-muted-foreground">{item.description}</p>
|
|
235
|
+
)}
|
|
236
|
+
</div>
|
|
237
|
+
</TableCell>
|
|
238
|
+
<TableCell className="font-mono text-sm">{item.sku}</TableCell>
|
|
239
|
+
<TableCell className="text-center">{item.quantity}</TableCell>
|
|
240
|
+
<TableCell className="text-right">{formatCurrency(item.value)}</TableCell>
|
|
241
|
+
<TableCell className="text-right font-medium">
|
|
242
|
+
{formatCurrency(item.value * item.quantity)}
|
|
243
|
+
</TableCell>
|
|
244
|
+
</TableRow>
|
|
245
|
+
))}
|
|
246
|
+
</TableBody>
|
|
247
|
+
</Table>
|
|
248
|
+
</CardContent>
|
|
249
|
+
</Card>
|
|
250
|
+
|
|
251
|
+
{/* Timeline */}
|
|
252
|
+
<Card>
|
|
253
|
+
<CardHeader>
|
|
254
|
+
<CardTitle className="flex items-center gap-2">
|
|
255
|
+
<Clock size={18} />
|
|
256
|
+
Order Timeline
|
|
257
|
+
</CardTitle>
|
|
258
|
+
</CardHeader>
|
|
259
|
+
<CardContent>
|
|
260
|
+
<div className="relative">
|
|
261
|
+
{order.timeline.map((event, index) => (
|
|
262
|
+
<div key={index} className="flex gap-4 pb-6 last:pb-0">
|
|
263
|
+
<div className="relative">
|
|
264
|
+
<div className="w-3 h-3 rounded-full bg-primary mt-1.5" />
|
|
265
|
+
{index < order.timeline.length - 1 && (
|
|
266
|
+
<div className="absolute top-4 left-1.5 w-px h-full -ml-px bg-border" />
|
|
267
|
+
)}
|
|
268
|
+
</div>
|
|
269
|
+
<div className="flex-1">
|
|
270
|
+
<div className="flex items-center gap-2 mb-1">
|
|
271
|
+
<StatusBadge status={event.status} type="order" size="sm" />
|
|
272
|
+
<span className="text-sm text-muted-foreground">
|
|
273
|
+
{formatDate(event.timestamp, 'full')}
|
|
274
|
+
</span>
|
|
275
|
+
</div>
|
|
276
|
+
{event.notes && <p className="text-sm">{event.notes}</p>}
|
|
277
|
+
<p className="text-xs text-muted-foreground">by {event.performedBy}</p>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
))}
|
|
281
|
+
</div>
|
|
282
|
+
</CardContent>
|
|
283
|
+
</Card>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
{/* Sidebar */}
|
|
287
|
+
<div className="space-y-6">
|
|
288
|
+
{/* Order Summary */}
|
|
289
|
+
<Card>
|
|
290
|
+
<CardHeader>
|
|
291
|
+
<CardTitle className="flex items-center gap-2">
|
|
292
|
+
<DollarSign size={18} />
|
|
293
|
+
Order Summary
|
|
294
|
+
</CardTitle>
|
|
295
|
+
</CardHeader>
|
|
296
|
+
<CardContent>
|
|
297
|
+
<div className="space-y-3">
|
|
298
|
+
<div className="flex justify-between text-sm">
|
|
299
|
+
<span className="text-muted-foreground">Subtotal</span>
|
|
300
|
+
<span>{formatCurrency(order.pricing.subtotal)}</span>
|
|
301
|
+
</div>
|
|
302
|
+
<div className="flex justify-between text-sm">
|
|
303
|
+
<span className="text-muted-foreground">Delivery</span>
|
|
304
|
+
<span>{formatCurrency(order.pricing.fees.delivery)}</span>
|
|
305
|
+
</div>
|
|
306
|
+
<div className="flex justify-between text-sm">
|
|
307
|
+
<span className="text-muted-foreground">Handling</span>
|
|
308
|
+
<span>{formatCurrency(order.pricing.fees.handling)}</span>
|
|
309
|
+
</div>
|
|
310
|
+
{order.pricing.fees.insurance && (
|
|
311
|
+
<div className="flex justify-between text-sm">
|
|
312
|
+
<span className="text-muted-foreground">Insurance</span>
|
|
313
|
+
<span>{formatCurrency(order.pricing.fees.insurance)}</span>
|
|
314
|
+
</div>
|
|
315
|
+
)}
|
|
316
|
+
<div className="flex justify-between text-sm">
|
|
317
|
+
<span className="text-muted-foreground">Taxes</span>
|
|
318
|
+
<span>{formatCurrency(order.pricing.taxes)}</span>
|
|
319
|
+
</div>
|
|
320
|
+
<Separator />
|
|
321
|
+
<div className="flex justify-between font-medium">
|
|
322
|
+
<span>Total</span>
|
|
323
|
+
<span className="text-lg">{formatCurrency(order.pricing.total)}</span>
|
|
324
|
+
</div>
|
|
325
|
+
<div className="pt-2">
|
|
326
|
+
<p className="text-sm text-muted-foreground">Payment Method</p>
|
|
327
|
+
<p className="text-sm capitalize">
|
|
328
|
+
{order.pricing.paymentMethod.replace('_', ' ')}
|
|
329
|
+
</p>
|
|
330
|
+
</div>
|
|
331
|
+
</div>
|
|
332
|
+
</CardContent>
|
|
333
|
+
</Card>
|
|
334
|
+
|
|
335
|
+
{/* Assignment Info */}
|
|
336
|
+
<Card>
|
|
337
|
+
<CardHeader>
|
|
338
|
+
<CardTitle className="flex items-center gap-2">
|
|
339
|
+
<Truck size={18} />
|
|
340
|
+
Assignment
|
|
341
|
+
</CardTitle>
|
|
342
|
+
</CardHeader>
|
|
343
|
+
<CardContent>
|
|
344
|
+
<div className="space-y-4">
|
|
345
|
+
<div>
|
|
346
|
+
<p className="text-sm text-muted-foreground">Driver</p>
|
|
347
|
+
<p className="text-sm">{order.driverId || 'Not assigned'}</p>
|
|
348
|
+
</div>
|
|
349
|
+
<div>
|
|
350
|
+
<p className="text-sm text-muted-foreground">Vehicle</p>
|
|
351
|
+
<p className="text-sm">{order.vehicleId || 'Not assigned'}</p>
|
|
352
|
+
</div>
|
|
353
|
+
<div>
|
|
354
|
+
<p className="text-sm text-muted-foreground">Tracking Number</p>
|
|
355
|
+
<p className="text-sm font-mono">{order.trackingNumber}</p>
|
|
356
|
+
</div>
|
|
357
|
+
<Button
|
|
358
|
+
variant="outline"
|
|
359
|
+
className="w-full"
|
|
360
|
+
onClick={() => goTo(`tracking?order=${order.id}`)}
|
|
361
|
+
>
|
|
362
|
+
<MapPin size={16} />
|
|
363
|
+
Track Order
|
|
364
|
+
</Button>
|
|
365
|
+
</div>
|
|
366
|
+
</CardContent>
|
|
367
|
+
</Card>
|
|
368
|
+
|
|
369
|
+
{/* Special Instructions */}
|
|
370
|
+
{order.specialInstructions && (
|
|
371
|
+
<Card>
|
|
372
|
+
<CardHeader>
|
|
373
|
+
<CardTitle className="flex items-center gap-2">
|
|
374
|
+
<FileText size={18} />
|
|
375
|
+
Special Instructions
|
|
376
|
+
</CardTitle>
|
|
377
|
+
</CardHeader>
|
|
378
|
+
<CardContent>
|
|
379
|
+
<p className="text-sm">{order.specialInstructions}</p>
|
|
380
|
+
</CardContent>
|
|
381
|
+
</Card>
|
|
382
|
+
)}
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
385
|
+
</PageLayout>
|
|
386
|
+
);
|
|
387
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orders List Page
|
|
3
|
+
*
|
|
4
|
+
* Displays all orders with filtering, search, and pagination.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useState } from 'react';
|
|
8
|
+
import { Package, Plus, Filter, Download, RefreshCw } from 'lucide-react';
|
|
9
|
+
import { PageLayout } from '../components/PageLayout';
|
|
10
|
+
import { DataTable, type Column } from '../components/DataTable';
|
|
11
|
+
import { StatusBadge, PriorityBadge, TypeBadge } from '../components/StatusBadge';
|
|
12
|
+
import {
|
|
13
|
+
Button,
|
|
14
|
+
Card,
|
|
15
|
+
CardContent,
|
|
16
|
+
Select,
|
|
17
|
+
SelectContent,
|
|
18
|
+
SelectItem,
|
|
19
|
+
SelectTrigger,
|
|
20
|
+
SelectValue,
|
|
21
|
+
Badge,
|
|
22
|
+
} from '../components/ui';
|
|
23
|
+
import { useOrders } from '../hooks/useOrders';
|
|
24
|
+
import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
|
|
25
|
+
import { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';
|
|
26
|
+
import { formatCurrency, formatDate } from '../utils/formatters';
|
|
27
|
+
import { joinPath } from '../utils/navigation';
|
|
28
|
+
import type { Order, OrderStatus } from '../types';
|
|
29
|
+
|
|
30
|
+
export default function OrdersListPage() {
|
|
31
|
+
const { t: translate } = useI18n();
|
|
32
|
+
const t = (key: string, fallback: string): string => {
|
|
33
|
+
const value = translate(key);
|
|
34
|
+
return value === key ? fallback : value;
|
|
35
|
+
};
|
|
36
|
+
const { basePath, navigate } = useMoveTheWheels();
|
|
37
|
+
const [statusFilter, setStatusFilter] = useState<OrderStatus | 'all'>('all');
|
|
38
|
+
const [typeFilter, setTypeFilter] = useState<'b2b' | 'b2c' | 'all'>('all');
|
|
39
|
+
|
|
40
|
+
const { orders, totalOrders, isLoading, refetch } = useOrders({
|
|
41
|
+
filters: {
|
|
42
|
+
status: statusFilter === 'all' ? undefined : statusFilter,
|
|
43
|
+
orderType: typeFilter === 'all' ? undefined : typeFilter,
|
|
44
|
+
},
|
|
45
|
+
limit: 50,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const goTo = (path: string) => {
|
|
49
|
+
if (navigate) {
|
|
50
|
+
navigate(joinPath(basePath, path));
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const columns: Column<Order>[] = [
|
|
55
|
+
{
|
|
56
|
+
id: 'orderNumber',
|
|
57
|
+
header: t('movethewheels.orders.table.orderNumber', 'Order #'),
|
|
58
|
+
accessorKey: 'orderNumber',
|
|
59
|
+
sortable: true,
|
|
60
|
+
className: 'min-w-[100px] whitespace-nowrap',
|
|
61
|
+
cell: (row) => <span className="font-medium text-primary">{row.orderNumber}</span>,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'customer',
|
|
65
|
+
header: t('movethewheels.orders.table.customer', 'Customer'),
|
|
66
|
+
className: 'min-w-[180px] max-w-[220px]',
|
|
67
|
+
cell: (row) => (
|
|
68
|
+
<div className="min-w-0">
|
|
69
|
+
<p className="font-medium truncate">{row.customerInfo.name}</p>
|
|
70
|
+
<p className="text-sm text-muted-foreground truncate">{row.customerInfo.email}</p>
|
|
71
|
+
</div>
|
|
72
|
+
),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 'status',
|
|
76
|
+
header: t('movethewheels.orders.table.status', 'Status'),
|
|
77
|
+
accessorKey: 'status',
|
|
78
|
+
sortable: true,
|
|
79
|
+
className: 'min-w-[130px] whitespace-nowrap',
|
|
80
|
+
cell: (row) => <StatusBadge status={row.status} type="order" />,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 'type',
|
|
84
|
+
header: t('movethewheels.orders.table.type', 'Type'),
|
|
85
|
+
accessorKey: 'orderType',
|
|
86
|
+
className: 'min-w-[70px] whitespace-nowrap',
|
|
87
|
+
cell: (row) => <TypeBadge type={row.orderType} />,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'priority',
|
|
91
|
+
header: t('movethewheels.orders.table.priority', 'Priority'),
|
|
92
|
+
accessorKey: 'priority',
|
|
93
|
+
sortable: true,
|
|
94
|
+
className: 'min-w-[90px] whitespace-nowrap',
|
|
95
|
+
cell: (row) => <PriorityBadge priority={row.priority} />,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: 'items',
|
|
99
|
+
header: t('movethewheels.orders.table.items', 'Items'),
|
|
100
|
+
className: 'min-w-[80px] whitespace-nowrap',
|
|
101
|
+
cell: (row) => (
|
|
102
|
+
<Badge variant="secondary">
|
|
103
|
+
{row.items.length} {t('movethewheels.orders.table.itemsSuffix', 'items')}
|
|
104
|
+
</Badge>
|
|
105
|
+
),
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 'total',
|
|
109
|
+
header: t('movethewheels.orders.table.total', 'Total'),
|
|
110
|
+
accessorKey: 'pricing',
|
|
111
|
+
sortable: true,
|
|
112
|
+
className: 'min-w-[100px] whitespace-nowrap text-right',
|
|
113
|
+
cell: (row) => <span className="font-medium">{formatCurrency(row.pricing.total)}</span>,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'scheduledDelivery',
|
|
117
|
+
header: t('movethewheels.orders.table.deliveryDate', 'Delivery Date'),
|
|
118
|
+
accessorKey: 'scheduledDelivery',
|
|
119
|
+
sortable: true,
|
|
120
|
+
className: 'min-w-[110px] whitespace-nowrap',
|
|
121
|
+
cell: (row) => (row.scheduledDelivery ? formatDate(row.scheduledDelivery) : '-'),
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: 'createdAt',
|
|
125
|
+
header: t('movethewheels.orders.table.created', 'Created'),
|
|
126
|
+
accessorKey: 'createdAt',
|
|
127
|
+
sortable: true,
|
|
128
|
+
className: 'min-w-[100px] whitespace-nowrap',
|
|
129
|
+
cell: (row) => formatDate(row.createdAt, 'relative'),
|
|
130
|
+
},
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
const statusOptions: { value: OrderStatus | 'all'; label: string }[] = [
|
|
134
|
+
{ value: 'all', label: t('movethewheels.orders.filters.allStatuses', 'All Statuses') },
|
|
135
|
+
{ value: 'pending', label: t('movethewheels.orders.status.pending', 'Pending') },
|
|
136
|
+
{ value: 'confirmed', label: t('movethewheels.orders.status.confirmed', 'Confirmed') },
|
|
137
|
+
{ value: 'assigned', label: t('movethewheels.orders.status.assigned', 'Assigned') },
|
|
138
|
+
{ value: 'picked_up', label: t('movethewheels.orders.status.pickedUp', 'Picked Up') },
|
|
139
|
+
{ value: 'in_transit', label: t('movethewheels.orders.status.inTransit', 'In Transit') },
|
|
140
|
+
{
|
|
141
|
+
value: 'out_for_delivery',
|
|
142
|
+
label: t('movethewheels.orders.status.outForDelivery', 'Out for Delivery'),
|
|
143
|
+
},
|
|
144
|
+
{ value: 'delivered', label: t('movethewheels.orders.status.delivered', 'Delivered') },
|
|
145
|
+
{ value: 'cancelled', label: t('movethewheels.orders.status.cancelled', 'Cancelled') },
|
|
146
|
+
{ value: 'failed', label: t('movethewheels.orders.status.failed', 'Failed') },
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<PageLayout
|
|
151
|
+
title={t('movethewheels.orders.title', 'Orders')}
|
|
152
|
+
subtitle={`${totalOrders} ${t('movethewheels.orders.subtitle', 'total orders')}`}
|
|
153
|
+
icon={<Package size={24} />}
|
|
154
|
+
headerActions={
|
|
155
|
+
<div className="flex gap-2">
|
|
156
|
+
<Button variant="outline" onClick={refetch}>
|
|
157
|
+
<RefreshCw size={16} />
|
|
158
|
+
{t('movethewheels.orders.actions.refresh', 'Refresh')}
|
|
159
|
+
</Button>
|
|
160
|
+
<Button variant="outline">
|
|
161
|
+
<Download size={16} />
|
|
162
|
+
{t('movethewheels.orders.actions.export', 'Export')}
|
|
163
|
+
</Button>
|
|
164
|
+
<Button onClick={() => goTo('orders/new')}>
|
|
165
|
+
<Plus size={16} />
|
|
166
|
+
{t('movethewheels.orders.actions.newOrder', 'New Order')}
|
|
167
|
+
</Button>
|
|
168
|
+
</div>
|
|
169
|
+
}
|
|
170
|
+
>
|
|
171
|
+
{/* Filters */}
|
|
172
|
+
<Card>
|
|
173
|
+
<CardContent className="p-4">
|
|
174
|
+
<div className="flex flex-wrap items-center gap-4">
|
|
175
|
+
<div className="flex items-center gap-2">
|
|
176
|
+
<Filter size={16} className="text-muted-foreground" />
|
|
177
|
+
<span className="text-sm font-medium">
|
|
178
|
+
{t('movethewheels.orders.filters.label', 'Filters:')}
|
|
179
|
+
</span>
|
|
180
|
+
</div>
|
|
181
|
+
<Select
|
|
182
|
+
value={statusFilter}
|
|
183
|
+
onValueChange={(value) => setStatusFilter(value as OrderStatus | 'all')}
|
|
184
|
+
>
|
|
185
|
+
<SelectTrigger className="w-[180px]">
|
|
186
|
+
<SelectValue placeholder={t('movethewheels.orders.filters.status', 'Status')} />
|
|
187
|
+
</SelectTrigger>
|
|
188
|
+
<SelectContent>
|
|
189
|
+
{statusOptions.map((option) => (
|
|
190
|
+
<SelectItem key={option.value} value={option.value}>
|
|
191
|
+
{option.label}
|
|
192
|
+
</SelectItem>
|
|
193
|
+
))}
|
|
194
|
+
</SelectContent>
|
|
195
|
+
</Select>
|
|
196
|
+
<Select
|
|
197
|
+
value={typeFilter}
|
|
198
|
+
onValueChange={(value) => setTypeFilter(value as 'b2b' | 'b2c' | 'all')}
|
|
199
|
+
>
|
|
200
|
+
<SelectTrigger className="w-[150px]">
|
|
201
|
+
<SelectValue placeholder={t('movethewheels.orders.filters.type', 'Type')} />
|
|
202
|
+
</SelectTrigger>
|
|
203
|
+
<SelectContent>
|
|
204
|
+
<SelectItem value="all">
|
|
205
|
+
{t('movethewheels.orders.filters.allTypes', 'All Types')}
|
|
206
|
+
</SelectItem>
|
|
207
|
+
<SelectItem value="b2b">B2B</SelectItem>
|
|
208
|
+
<SelectItem value="b2c">B2C</SelectItem>
|
|
209
|
+
</SelectContent>
|
|
210
|
+
</Select>
|
|
211
|
+
{(statusFilter !== 'all' || typeFilter !== 'all') && (
|
|
212
|
+
<Button
|
|
213
|
+
variant="ghost"
|
|
214
|
+
size="sm"
|
|
215
|
+
onClick={() => {
|
|
216
|
+
setStatusFilter('all');
|
|
217
|
+
setTypeFilter('all');
|
|
218
|
+
}}
|
|
219
|
+
>
|
|
220
|
+
{t('movethewheels.orders.filters.clear', 'Clear filters')}
|
|
221
|
+
</Button>
|
|
222
|
+
)}
|
|
223
|
+
</div>
|
|
224
|
+
</CardContent>
|
|
225
|
+
</Card>
|
|
226
|
+
|
|
227
|
+
{/* Orders Table */}
|
|
228
|
+
<DataTable
|
|
229
|
+
columns={columns}
|
|
230
|
+
data={orders}
|
|
231
|
+
isLoading={isLoading}
|
|
232
|
+
searchable
|
|
233
|
+
searchPlaceholder={t('movethewheels.orders.searchPlaceholder', 'Search orders...')}
|
|
234
|
+
searchFields={['orderNumber', 'customerInfo'] as (keyof Order)[]}
|
|
235
|
+
onRowClick={(row) => goTo(`orders/${row.id}`)}
|
|
236
|
+
getRowId={(row) => row.id}
|
|
237
|
+
emptyMessage={t('movethewheels.orders.empty', 'No orders found')}
|
|
238
|
+
/>
|
|
239
|
+
</PageLayout>
|
|
240
|
+
);
|
|
241
|
+
}
|