@burdenoff/microfe-movethewheels 2026.703.3 → 2026.703.5

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.
Files changed (173) hide show
  1. package/dist/{AIAssistantPage-C3cPsWt-.js → AIAssistantPage-D2gaEL1U.js} +16 -15
  2. package/dist/AnalyticsPage-DZMlEoBi.js +194 -0
  3. package/dist/CreateOrderPage-CWHx8yys.js +490 -0
  4. package/dist/CustomerDetailsPage-nR4oZ_ju.js +615 -0
  5. package/dist/CustomersPage-Bbvwvn8k.js +205 -0
  6. package/dist/DashboardPage-DrEhNf7N.js +542 -0
  7. package/dist/DataTable-CqMUD4er.js +340 -0
  8. package/dist/DocumentsCard-edDkgnJj.js +169 -0
  9. package/dist/DriverDetailsPage-whEMOWs9.js +490 -0
  10. package/dist/DriversPage-CHF2ZEzd.js +221 -0
  11. package/dist/FinancePage-Dn9GrW-1.js +175 -0
  12. package/dist/{FleetPage-DqkFi3s3.js → FleetPage-CrtGPy-p.js} +36 -35
  13. package/dist/{FormError-BlOjnXOq.js → FormError-BKcb_wT-.js} +1 -1
  14. package/dist/{ImportExportPage-DKJRCezl.js → ImportExportPage-WYdwZomZ.js} +52 -72
  15. package/dist/InventoryPage-l5A1f753.js +259 -0
  16. package/dist/LiveTrackingPage-DhEaNKZ4.js +429 -0
  17. package/dist/MarketplacePage-B9RYOb1Y.js +426 -0
  18. package/dist/MetricCard-y3bWHKUQ.js +191 -0
  19. package/dist/Notice-DOO-tjpV.js +46 -0
  20. package/dist/OrderDetailsPage-CwYHwk1K.js +584 -0
  21. package/dist/OrdersListPage-DhZJoQeI.js +386 -0
  22. package/dist/{PageLayout-D4LDHJJq.js → PageLayout-BniRJaQ6.js} +1 -1
  23. package/dist/{ProductDetailsPage-C9uOiYLp.js → ProductDetailsPage-1Gm9JKy0.js} +56 -56
  24. package/dist/ProductsPage-C8sn-1tN.js +186 -0
  25. package/dist/ReportsPage-D1tb0dcz.js +377 -0
  26. package/dist/RouteDetailsPage-CkMyR9b_.js +610 -0
  27. package/dist/{RoutesPage-DMfoicM1.js → RoutesPage-QkENzsE5.js} +58 -47
  28. package/dist/{SettingsPage-Bn-v0mbQ.js → SettingsPage-DV3_tU_X.js} +16 -38
  29. package/dist/Sparkline-K2RMJ58u.js +16729 -0
  30. package/dist/{StatusBadge-BZurYHMy.js → StatusBadge-BNHXYvZx.js} +7 -7
  31. package/dist/TrackingPage-BZrg4RCu.js +368 -0
  32. package/dist/VehicleDetailsPage-D-8XPZ2G.js +393 -0
  33. package/dist/VehiclesPage-D5BELbtM.js +184 -0
  34. package/dist/{WarehouseDetailsPage-L_6sWigM.js → WarehouseDetailsPage-Cmg-8Frn.js} +70 -70
  35. package/dist/WarehousesPage-C1Y1M867.js +182 -0
  36. package/dist/{arrow-left-n48Y-Wis.js → arrow-left-ClW4Isj7.js} +1 -1
  37. package/dist/arrow-right-CmKOmIkh.js +11 -0
  38. package/dist/arrow-up-BJijRLAZ.js +17 -0
  39. package/dist/{box-D9Pal4HM.js → box-BT3NsRQP.js} +1 -1
  40. package/dist/boxes-B_OGvQiW.js +54 -0
  41. package/dist/{chart-column-BFIJysDR.js → chart-column-DQTTdUPk.js} +1 -1
  42. package/dist/charts-Tj_PPTfA.js +2018 -0
  43. package/dist/chevron-left-B1rZyWWb.js +8 -0
  44. package/dist/{chevron-right-EMIIyyJ1.js → chevron-right-BIcwUJZq.js} +1 -1
  45. package/dist/chunk-BdsCSvBP.js +20 -0
  46. package/dist/{circle-alert-iY24lSlp.js → circle-alert-CNkuDNc6.js} +1 -1
  47. package/dist/circle-check-Cs1OVjtV.js +13 -0
  48. package/dist/{circle-check-big-w0TrLKMF.js → circle-check-big-C-p4eNwn.js} +1 -1
  49. package/dist/{clock-DJZtdl8u.js → clock-dRGG4rkF.js} +1 -1
  50. package/dist/{dollar-sign-CgKQRz_e.js → dollar-sign-B6RoYHHz.js} +1 -1
  51. package/dist/{download-DRXxoiQR.js → download-DP04iWTd.js} +1 -1
  52. package/dist/{file-text-DWWY6_f5.js → file-text-BuDx4hZp.js} +1 -1
  53. package/dist/{filter-DloLC2eE.js → filter-BD483_8g.js} +1 -1
  54. package/dist/{wrench-CANXWxF-.js → fuel-DLH1ag04.js} +3 -6
  55. package/dist/index.css +2 -0
  56. package/dist/index.js +150 -172
  57. package/dist/{map-CkJaULb2.js → map-DNQn9fyY.js} +1 -1
  58. package/dist/{map-pin-BGiCvyCs.js → map-pin-CqN1bbT1.js} +1 -1
  59. package/dist/mapMarkers-NCV9MRKR.js +28 -0
  60. package/dist/maps-yzLqiK_C.js +5070 -0
  61. package/dist/{navigation-D36prnAn.js → navigation-CgGUt2tR.js} +1 -1
  62. package/dist/{package-BChUzpJS.js → package-DmRF7iQD.js} +1 -1
  63. package/dist/{phone-Ac9s3mo_.js → phone-Cl32EXKW.js} +1 -1
  64. package/dist/{plus-Z76q-FZm.js → plus-DlANgOFx.js} +1 -1
  65. package/dist/{refresh-cw-DKt6f5T6.js → refresh-cw-rW59D4b7.js} +1 -1
  66. package/dist/route-CWjPrtAN.js +22 -0
  67. package/dist/{save-CojywNhG.js → save-UDlog7hg.js} +1 -1
  68. package/dist/{search-CDGefqb3.js → search-DNIG5Ck7.js} +1 -1
  69. package/dist/{square-pen-CopE9GmB.js → square-pen-BcfB3Grd.js} +1 -1
  70. package/dist/{star-nHlLjDKR.js → star-CVZHFwDx.js} +1 -1
  71. package/dist/{store-BR9Voi5E.js → store-bwnmCK9f.js} +1 -1
  72. package/dist/{trash-2-BKhar6Hs.js → trash-2-B80G12d4.js} +1 -1
  73. package/dist/{trending-up-Dohgd4t_.js → trending-up-CH4R4KOa.js} +1 -1
  74. package/dist/{triangle-alert-i-XQL9Rd.js → triangle-alert-CmS8AUU6.js} +1 -1
  75. package/dist/{truck-C0v_hbLR.js → truck-9rLDncav.js} +1 -1
  76. package/dist/upload-DanJY1Vo.js +21 -0
  77. package/dist/{useAssistant-D4v3oxD3.js → useAssistant-CnEwkTLm.js} +11 -28
  78. package/dist/{useCustomers-BmTNGxiI.js → useCustomers-ChJao1ET.js} +30 -27
  79. package/dist/{useFleet-DKqXZ16m.js → useFleet-g5Yri0G8.js} +82 -70
  80. package/dist/{useImportExport-DHr-SWSw.js → useImportExport-MYwIT3rE.js} +1 -1
  81. package/dist/{useInventory-DkyiVY_A.js → useInventory-BSOn-R1c.js} +84 -39
  82. package/dist/{useOrders-Cfk1GLiq.js → useOrders-BSiqo61w.js} +59 -48
  83. package/dist/{useReports-CTqZr-AB.js → useReports-fWESfsF9.js} +41 -35
  84. package/dist/{useRoutes-BQWO607N.js → useRoutes-zD8Yp323.js} +50 -42
  85. package/dist/{useSettings-CkDH_-gM.js → useSettings-B1lsWeZ1.js} +6 -6
  86. package/dist/{useTracking-B-va1kO3.js → useTracking-BKG0I2ln.js} +3 -3
  87. package/dist/{user-jyFU3lXk.js → user-DU51el3m.js} +1 -1
  88. package/dist/user-check-IMhk-qkX.js +20 -0
  89. package/dist/{users-DZ-ilS6B.js → users-B8KhJBGg.js} +1 -1
  90. package/dist/{warehouse-6m5kXMLu.js → warehouse-CcMMioeY.js} +1 -1
  91. package/dist/wrench-Dg-sgH2e.js +8 -0
  92. package/dist/x-C4ObLVEa.js +11 -0
  93. package/package.json +5 -1
  94. package/src/movethewheels/components/DataTable.tsx +252 -84
  95. package/src/movethewheels/components/DocumentsCard.tsx +102 -0
  96. package/src/movethewheels/components/GlassPanel.tsx +71 -0
  97. package/src/movethewheels/components/MetricCard.tsx +171 -73
  98. package/src/movethewheels/components/Notice.tsx +61 -0
  99. package/src/movethewheels/components/StatusBadge.tsx +7 -6
  100. package/src/movethewheels/components/charts/ChartShell.tsx +78 -0
  101. package/src/movethewheels/components/charts/Sparkline.tsx +85 -0
  102. package/src/movethewheels/components/charts/StatusDonut.tsx +115 -0
  103. package/src/movethewheels/components/charts/TrendChart.tsx +179 -0
  104. package/src/movethewheels/components/charts/VolumeBar.tsx +97 -0
  105. package/src/movethewheels/components/charts/chartTokens.ts +43 -0
  106. package/src/movethewheels/components/charts/index.ts +9 -0
  107. package/src/movethewheels/components/index.ts +51 -1
  108. package/src/movethewheels/components/maps/LogisticsMap.tsx +94 -0
  109. package/src/movethewheels/components/maps/MapCanvas.tsx +118 -0
  110. package/src/movethewheels/components/maps/RouteMap.tsx +71 -0
  111. package/src/movethewheels/components/maps/TrackingMap.tsx +102 -0
  112. package/src/movethewheels/components/maps/index.ts +16 -0
  113. package/src/movethewheels/components/maps/leaflet-setup.ts +124 -0
  114. package/src/movethewheels/components/maps/map-markers.css +121 -0
  115. package/src/movethewheels/hooks/index.ts +9 -0
  116. package/src/movethewheels/hooks/useAnalytics.ts +109 -4
  117. package/src/movethewheels/hooks/useCustomers.ts +11 -4
  118. package/src/movethewheels/hooks/useEntityDocuments.ts +132 -0
  119. package/src/movethewheels/hooks/useFleet.ts +26 -7
  120. package/src/movethewheels/hooks/useInventory.ts +70 -7
  121. package/src/movethewheels/hooks/useOrders.ts +32 -2
  122. package/src/movethewheels/hooks/useReports.ts +14 -4
  123. package/src/movethewheels/hooks/useRoutes.ts +20 -3
  124. package/src/movethewheels/pages/AnalyticsPage.tsx +93 -73
  125. package/src/movethewheels/pages/CreateOrderPage.tsx +48 -20
  126. package/src/movethewheels/pages/CustomerDetailsPage.tsx +239 -33
  127. package/src/movethewheels/pages/CustomersPage.tsx +53 -28
  128. package/src/movethewheels/pages/DashboardPage.tsx +238 -12
  129. package/src/movethewheels/pages/DriverDetailsPage.tsx +17 -31
  130. package/src/movethewheels/pages/DriversPage.tsx +59 -31
  131. package/src/movethewheels/pages/FinancePage.tsx +103 -82
  132. package/src/movethewheels/pages/InventoryPage.tsx +15 -3
  133. package/src/movethewheels/pages/LiveTrackingPage.tsx +124 -16
  134. package/src/movethewheels/pages/MarketplacePage.tsx +265 -50
  135. package/src/movethewheels/pages/OrderDetailsPage.tsx +214 -10
  136. package/src/movethewheels/pages/OrdersListPage.tsx +118 -47
  137. package/src/movethewheels/pages/ProductsPage.tsx +52 -28
  138. package/src/movethewheels/pages/ReportsPage.tsx +88 -4
  139. package/src/movethewheels/pages/RouteDetailsPage.tsx +119 -19
  140. package/src/movethewheels/pages/RoutesPage.tsx +22 -6
  141. package/src/movethewheels/pages/SettingsPage.tsx +5 -21
  142. package/src/movethewheels/pages/TrackingPage.tsx +76 -6
  143. package/src/movethewheels/pages/VehicleDetailsPage.tsx +4 -34
  144. package/src/movethewheels/pages/VehiclesPage.tsx +58 -27
  145. package/src/movethewheels/pages/WarehouseDetailsPage.tsx +1 -1
  146. package/src/movethewheels/pages/WarehousesPage.tsx +47 -36
  147. package/src/movethewheels/types/index.ts +9 -1
  148. package/src/movethewheels/utils/download.ts +62 -0
  149. package/src/movethewheels/utils/mapMarkers.ts +58 -0
  150. package/dist/AnalyticsPage-Dz6g2MvK.js +0 -215
  151. package/dist/CreateOrderPage-C5iwnjp4.js +0 -479
  152. package/dist/CustomerDetailsPage-B6nwFyLO.js +0 -406
  153. package/dist/CustomersPage-BKxMS1AV.js +0 -161
  154. package/dist/DashboardPage-BVjQi0EB.js +0 -387
  155. package/dist/DataTable-DmciIKKM.js +0 -249
  156. package/dist/DriverDetailsPage-CN3WQ0B9.js +0 -507
  157. package/dist/DriversPage-CH9rjQC-.js +0 -165
  158. package/dist/FinancePage-DEDykSOP.js +0 -158
  159. package/dist/InventoryPage-e0ze63iX.js +0 -253
  160. package/dist/LiveTrackingPage-DCX-K-LR.js +0 -379
  161. package/dist/MarketplacePage-CIQ97_zp.js +0 -247
  162. package/dist/MetricCard-BY0QrMD4.js +0 -146
  163. package/dist/OrderDetailsPage-DYiZ-9UK.js +0 -429
  164. package/dist/OrdersListPage-Cn90P1Xx.js +0 -307
  165. package/dist/ProductsPage-QJfHHpqB.js +0 -169
  166. package/dist/ReportsPage-Zp53q3_8.js +0 -284
  167. package/dist/RouteDetailsPage-DUStXSf9.js +0 -531
  168. package/dist/TrackingPage-W-jtdM3Y.js +0 -325
  169. package/dist/VehicleDetailsPage-Bceo5oz3.js +0 -410
  170. package/dist/VehiclesPage-ApKThYeG.js +0 -165
  171. package/dist/WarehousesPage-DCbXXXWE.js +0 -162
  172. package/dist/useAnalytics-DS8n0xgg.js +0 -297
  173. /package/dist/{formatters-CF2S2l1m.js → formatters-FWJDwTFv.js} +0 -0
@@ -1,22 +1,49 @@
1
1
  /**
2
2
  * Finance Page
3
+ *
4
+ * Shows only REAL figures returned by Query.financeMetrics (revenue, delivered
5
+ * revenue, fuel cost, open invoices) plus the real revenue trend series — no
6
+ * simulated paid/pending splits and no fabricated cost categories. Invoicing and
7
+ * settlement are handled by the platform Billing module, which this page
8
+ * deep-links to rather than re-implementing an Invoice ledger here.
3
9
  */
4
10
 
5
- import { DollarSign, TrendingUp, CreditCard, FileText, Download } from 'lucide-react';
11
+ import { useMemo } from 'react';
12
+ import { DollarSign, TrendingUp, CreditCard, FileText, Fuel, ArrowRight } from 'lucide-react';
6
13
  import { PageLayout } from '../components/PageLayout';
7
14
  import { MetricCard, MetricGrid } from '../components/MetricCard';
8
15
  import { Card, CardContent, CardHeader, CardTitle, Button } from '../components/ui';
9
- import { EmphasisPanel, IllustratedEmptyState, PagePurpose } from '@burdenoff/fe-libs/ui';
10
- import { useAnalytics } from '../hooks/useAnalytics';
11
- import { useOrderStats } from '../hooks/useOrders';
16
+ import { TrendChart, VolumeBar, chartTokens } from '../components/charts';
17
+ import { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
18
+ import { useAnalytics, useFinanceMetrics } from '../hooks/useAnalytics';
19
+ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
12
20
  import { formatCurrency } from '../utils/formatters';
13
21
 
14
22
  export default function FinancePage() {
15
23
  const { analytics } = useAnalytics();
16
- const { stats } = useOrderStats();
24
+ const { metrics } = useFinanceMetrics();
25
+ const { navigate } = useMoveTheWheels();
17
26
 
18
- const pendingPayments = stats.totalRevenue * 0.15; // Simulated
19
- const completedPayments = stats.totalRevenue * 0.85;
27
+ // Deep-link to the host Billing module (mounted at /billing in the app shell).
28
+ const openBilling = () => navigate('/billing');
29
+
30
+ const revenueSeries = useMemo(
31
+ () => analytics.trends.revenue.map((r) => ({ month: r.month, revenue: r.revenue })),
32
+ [analytics.trends.revenue]
33
+ );
34
+
35
+ // Real dollar figures only — total revenue, money already collected on delivered
36
+ // orders, and fuel spend. No invented category breakdown.
37
+ const economics = useMemo(
38
+ () => [
39
+ { label: 'Total revenue', amount: metrics.totalRevenue },
40
+ { label: 'Collected', amount: metrics.deliveredRevenue },
41
+ { label: 'Fuel cost', amount: metrics.fuelCost },
42
+ ],
43
+ [metrics.totalRevenue, metrics.deliveredRevenue, metrics.fuelCost]
44
+ );
45
+
46
+ const hasEconomics = economics.some((e) => e.amount > 0);
20
47
 
21
48
  return (
22
49
  <PageLayout
@@ -24,20 +51,15 @@ export default function FinancePage() {
24
51
  subtitle="Financial overview and reports"
25
52
  icon={<DollarSign size={24} />}
26
53
  headerActions={
27
- <div className="flex gap-2">
28
- <Button variant="outline">
29
- <FileText size={16} /> Invoices
30
- </Button>
31
- <Button variant="outline">
32
- <Download size={16} /> Export
33
- </Button>
34
- </div>
54
+ <Button variant="outline" onClick={openBilling}>
55
+ <FileText size={16} /> Invoices &amp; Billing
56
+ </Button>
35
57
  }
36
58
  >
37
59
  <PagePurpose icon={<DollarSign size={18} />}>
38
- Follow the money behind your deliveries. See revenue earned, what&apos;s been collected
39
- versus still owed, and average order value — use it to chase pending payments, forecast cash
40
- flow, and confirm which shipments have actually been paid for.
60
+ Follow the money behind your deliveries. See total revenue, how much has already been
61
+ collected on delivered orders, fuel cost and how many invoices are still open — then head to
62
+ Billing to raise and settle invoices.
41
63
  </PagePurpose>
42
64
 
43
65
  <MetricGrid columns={4}>
@@ -45,99 +67,98 @@ export default function FinancePage() {
45
67
  treatment="glass"
46
68
  glow
47
69
  label="Total Revenue"
48
- value={formatCurrency(analytics.overview.totalRevenue)}
70
+ value={formatCurrency(metrics.totalRevenue)}
49
71
  icon={<DollarSign size={20} />}
50
- change="+12.5%"
51
- changeType="positive"
52
- trend="up"
72
+ accent="success"
53
73
  />
54
74
  <MetricCard
55
- label="Completed"
56
- value={formatCurrency(completedPayments)}
75
+ label="Collected (Delivered)"
76
+ value={formatCurrency(metrics.deliveredRevenue)}
57
77
  icon={<TrendingUp size={20} />}
58
- changeType="positive"
78
+ accent="brand"
59
79
  />
60
80
  <MetricCard
61
- label="Pending"
62
- value={formatCurrency(pendingPayments)}
63
- icon={<CreditCard size={20} />}
64
- changeType="neutral"
81
+ label="Fuel Cost"
82
+ value={formatCurrency(metrics.fuelCost)}
83
+ icon={<Fuel size={20} />}
84
+ accent="warning"
65
85
  />
66
86
  <MetricCard
67
- label="Avg Order Value"
68
- value={formatCurrency(stats.avgOrderValue)}
69
- icon={<DollarSign size={20} />}
87
+ label="Open Invoices"
88
+ value={String(metrics.openInvoices)}
89
+ icon={<CreditCard size={20} />}
90
+ accent="blue"
70
91
  />
71
92
  </MetricGrid>
72
93
 
73
- <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
74
- <Card>
94
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
95
+ <Card className="lg:col-span-2">
75
96
  <CardHeader>
76
- <CardTitle>Revenue by Month</CardTitle>
97
+ <CardTitle>Revenue trend</CardTitle>
77
98
  </CardHeader>
78
99
  <CardContent>
79
- <div className="space-y-4">
80
- {analytics.trends.revenue.map((r) => (
81
- <div
82
- key={r.month}
83
- className="flex items-center justify-between p-3 bg-bg-sunken/50 rounded-lg"
84
- >
85
- <span className="font-medium">{r.month} 2024</span>
86
- <span className="text-lg font-bold">{formatCurrency(r.revenue)}</span>
87
- </div>
88
- ))}
89
- </div>
100
+ <TrendChart
101
+ xKey="month"
102
+ variant="area"
103
+ height={280}
104
+ showLegend={false}
105
+ data={revenueSeries}
106
+ series={[{ dataKey: 'revenue', name: 'Revenue', color: chartTokens.brandBlue }]}
107
+ valueFormatter={(v) => formatCurrency(Number(v))}
108
+ emptyMessage="No revenue recorded yet. Revenue appears here as orders are delivered."
109
+ />
90
110
  </CardContent>
91
111
  </Card>
92
112
 
93
- {/* Payment Status — the page's single emphasis zone */}
113
+ {/* Invoices & Settlement — reuse of the Billing module */}
94
114
  <EmphasisPanel className="space-y-4">
95
- <h2 className="text-base font-semibold text-text-primary">Payment Status</h2>
96
- <div className="space-y-4">
97
- <div className="flex items-center justify-between p-4 bg-status-success-bg/10 rounded-lg">
98
- <div className="flex items-center gap-3">
99
- <div className="w-10 h-10 rounded-full bg-status-success-bg/20 flex items-center justify-center">
100
- <TrendingUp size={20} className="text-status-success-text" />
101
- </div>
102
- <div>
103
- <p className="font-medium">Paid</p>
104
- <p className="text-sm text-text-secondary">{stats.byStatus.delivered} orders</p>
105
- </div>
115
+ <h2 className="text-base font-semibold text-text-primary">Invoices &amp; Settlement</h2>
116
+ <p className="text-sm text-text-secondary">
117
+ Invoicing, payments and settlement run through the platform Billing module — the single
118
+ source of truth for what&apos;s been billed and paid. MoveTheWheels doesn&apos;t keep
119
+ its own invoice ledger.
120
+ </p>
121
+ <div className="flex items-center justify-between p-4 bg-status-warning-bg/10 rounded-lg">
122
+ <div className="flex items-center gap-3">
123
+ <div className="w-10 h-10 rounded-full bg-status-warning-bg/20 flex items-center justify-center">
124
+ <CreditCard size={20} className="text-status-warning-text" />
106
125
  </div>
107
- <span className="text-xl font-bold text-status-success-text">
108
- {formatCurrency(completedPayments)}
109
- </span>
110
- </div>
111
- <div className="flex items-center justify-between p-4 bg-status-warning-bg/10 rounded-lg">
112
- <div className="flex items-center gap-3">
113
- <div className="w-10 h-10 rounded-full bg-status-warning-bg/20 flex items-center justify-center">
114
- <CreditCard size={20} className="text-status-warning-text" />
115
- </div>
116
- <div>
117
- <p className="font-medium">Pending</p>
118
- <p className="text-sm text-text-secondary">
119
- {stats.byStatus.pending + stats.byStatus.in_transit} orders
120
- </p>
121
- </div>
126
+ <div>
127
+ <p className="font-medium">Open invoices</p>
128
+ <p className="text-sm text-text-secondary">
129
+ {metrics.openInvoices} awaiting settlement
130
+ </p>
122
131
  </div>
123
- <span className="text-xl font-bold text-status-warning-text">
124
- {formatCurrency(pendingPayments)}
125
- </span>
126
132
  </div>
133
+ <span className="text-xl font-bold text-status-warning-text">
134
+ {metrics.openInvoices}
135
+ </span>
127
136
  </div>
137
+ <Button className="w-full" onClick={openBilling}>
138
+ Open Billing <ArrowRight size={16} />
139
+ </Button>
128
140
  </EmphasisPanel>
129
141
  </div>
130
142
 
131
143
  <Card>
132
144
  <CardHeader>
133
- <CardTitle>Recent Transactions</CardTitle>
145
+ <CardTitle>Revenue vs cost</CardTitle>
134
146
  </CardHeader>
135
147
  <CardContent>
136
- <IllustratedEmptyState
137
- illustration="empty-data"
138
- title="No transactions yet"
139
- description="Once payments are processed, your transaction history will appear here. Connect a payment gateway to start recording transactions."
140
- />
148
+ {hasEconomics ? (
149
+ <VolumeBar
150
+ xKey="label"
151
+ height={260}
152
+ showLegend={false}
153
+ data={economics}
154
+ series={[{ dataKey: 'amount', name: 'Amount' }]}
155
+ valueFormatter={(v) => formatCurrency(Number(v))}
156
+ />
157
+ ) : (
158
+ <p className="py-8 text-center text-sm text-text-secondary">
159
+ Revenue and cost figures appear here as orders are delivered.
160
+ </p>
161
+ )}
141
162
  </CardContent>
142
163
  </Card>
143
164
  </PageLayout>
@@ -2,7 +2,15 @@
2
2
  * Inventory Page - Overview of inventory management
3
3
  */
4
4
 
5
- import { Package, Warehouse, AlertTriangle, ChevronRight, Plus } from 'lucide-react';
5
+ import {
6
+ Package,
7
+ Warehouse,
8
+ AlertTriangle,
9
+ ChevronRight,
10
+ Plus,
11
+ Boxes,
12
+ DollarSign,
13
+ } from 'lucide-react';
6
14
  import { PageLayout, PageSection } from '../components/PageLayout';
7
15
  import { MetricCard, MetricGrid, MetricCardSkeleton } from '../components/MetricCard';
8
16
  import { Card, CardContent, Button, Badge, Progress } from '../components/ui';
@@ -88,22 +96,26 @@ export default function InventoryPage() {
88
96
  label={t('movethewheels.inventory.metrics.totalProducts', 'Total Products')}
89
97
  value={stats.totalProducts}
90
98
  icon={<Package size={20} />}
99
+ accent="brand"
91
100
  onClick={() => goTo('inventory/products')}
92
101
  />
93
102
  <MetricCard
94
103
  label={t('movethewheels.inventory.metrics.totalItems', 'Total Items')}
95
104
  value={stats.totalItems.toLocaleString()}
96
- icon={<Package size={20} />}
105
+ icon={<Boxes size={20} />}
106
+ accent="success"
97
107
  />
98
108
  <MetricCard
99
109
  label={t('movethewheels.inventory.metrics.inventoryValue', 'Inventory Value')}
100
110
  value={formatCurrency(stats.totalValue)}
101
- icon={<Package size={20} />}
111
+ icon={<DollarSign size={20} />}
112
+ accent="blue"
102
113
  />
103
114
  <MetricCard
104
115
  label={t('movethewheels.inventory.metrics.warehouses', 'Warehouses')}
105
116
  value={stats.totalWarehouses}
106
117
  icon={<Warehouse size={20} />}
118
+ accent="neutral"
107
119
  onClick={() => goTo('inventory/warehouses')}
108
120
  />
109
121
  </MetricGrid>
@@ -4,11 +4,13 @@
4
4
  * Real-time map view of all active deliveries.
5
5
  */
6
6
 
7
- import { useState } from 'react';
7
+ import { useMemo, useState } from 'react';
8
8
  import { MapPin, Truck, Package, RefreshCw, List, Map } from 'lucide-react';
9
9
  import { PageLayout, EmptyState } from '../components/PageLayout';
10
10
  import { StatusBadge } from '../components/StatusBadge';
11
11
  import { MetricCard, MetricGrid } from '../components/MetricCard';
12
+ import { LogisticsMap, type LogisticsMarker } from '../components/maps';
13
+ import { deliveryMarkerStatus, firstRealLatLng } from '../utils/mapMarkers';
12
14
  import {
13
15
  Card,
14
16
  CardContent,
@@ -27,12 +29,15 @@ import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
27
29
  import { formatDate } from '../utils/formatters';
28
30
  import { joinPath } from '../utils/navigation';
29
31
 
32
+ type LiveFilter = 'all' | 'in_transit' | 'out_for_delivery' | 'other';
33
+
30
34
  export default function LiveTrackingPage() {
31
35
  const { basePath, navigate } = useMoveTheWheels();
32
36
  const { activeDeliveries, isLoading, refetch } = useLiveTracking();
33
37
  const { unacknowledgedAlerts } = useTrackingAlerts();
34
38
  const [viewMode, setViewMode] = useState<'map' | 'list'>('map');
35
39
  const [selectedDelivery, setSelectedDelivery] = useState<string | null>(null);
40
+ const [filter, setFilter] = useState<LiveFilter>('all');
36
41
 
37
42
  const goTo = (path: string) => {
38
43
  if (navigate) {
@@ -44,6 +49,70 @@ export default function LiveTrackingPage() {
44
49
  ? activeDeliveries.find((d) => d.order?.id === selectedDelivery)
45
50
  : null;
46
51
 
52
+ const filteredDeliveries = useMemo(
53
+ () =>
54
+ activeDeliveries.filter((d) => {
55
+ const status = d.order?.status;
56
+ if (filter === 'all') return true;
57
+ if (filter === 'in_transit') return status === 'in_transit';
58
+ if (filter === 'out_for_delivery') return status === 'out_for_delivery';
59
+ return status !== 'in_transit' && status !== 'out_for_delivery';
60
+ }),
61
+ [activeDeliveries, filter]
62
+ );
63
+
64
+ // Build brand markers from the best real coordinate we hold for each delivery —
65
+ // the vehicle GPS fix, else the driver's, else the latest tracking event.
66
+ // Deliveries with no real coordinate are honestly omitted (never plotted at 0,0).
67
+ const markers = useMemo<LogisticsMarker[]>(() => {
68
+ return filteredDeliveries.flatMap((d) => {
69
+ if (!d.order) return [];
70
+ const coord = firstRealLatLng(
71
+ d.vehicle?.currentLocation,
72
+ d.driver?.currentLocation,
73
+ d.tracking?.currentLocation
74
+ );
75
+ if (!coord) return [];
76
+ return [
77
+ {
78
+ id: d.order.id,
79
+ lat: coord.lat,
80
+ lng: coord.lng,
81
+ label: d.order.orderNumber,
82
+ status: deliveryMarkerStatus(d.order.status),
83
+ sublabel:
84
+ d.driver?.fullName ||
85
+ d.vehicle?.vehicleNumber ||
86
+ d.tracking?.currentLocation.address ||
87
+ undefined,
88
+ },
89
+ ];
90
+ });
91
+ }, [filteredDeliveries]);
92
+
93
+ const locatedCount = markers.length;
94
+
95
+ const filterChips: { value: LiveFilter; label: string; count: number }[] = [
96
+ { value: 'all', label: 'All', count: activeDeliveries.length },
97
+ {
98
+ value: 'in_transit',
99
+ label: 'In transit',
100
+ count: activeDeliveries.filter((d) => d.order?.status === 'in_transit').length,
101
+ },
102
+ {
103
+ value: 'out_for_delivery',
104
+ label: 'Out for delivery',
105
+ count: activeDeliveries.filter((d) => d.order?.status === 'out_for_delivery').length,
106
+ },
107
+ {
108
+ value: 'other',
109
+ label: 'Other',
110
+ count: activeDeliveries.filter(
111
+ (d) => d.order?.status !== 'in_transit' && d.order?.status !== 'out_for_delivery'
112
+ ).length,
113
+ },
114
+ ];
115
+
47
116
  return (
48
117
  <PageLayout
49
118
  title="Live Tracking"
@@ -134,20 +203,37 @@ export default function LiveTrackingPage() {
134
203
  {/* Map / List View */}
135
204
  <div className="lg:col-span-2">
136
205
  {viewMode === 'map' ? (
137
- <Card className="h-[600px]">
138
- <CardContent className="p-0 h-full">
139
- <div className="w-full h-full bg-bg-sunken rounded-lg flex items-center justify-center">
140
- <div className="text-center text-text-secondary">
141
- <MapPin size={64} className="mx-auto mb-4 opacity-50" />
142
- <p className="text-lg font-medium">Map View</p>
143
- <p className="text-sm">
144
- Interactive map showing {activeDeliveries.length} active deliveries
145
- </p>
146
- <p className="text-xs mt-2">
147
- (Map integration with Mapbox/Google Maps would go here)
148
- </p>
149
- </div>
206
+ <Card className="overflow-hidden">
207
+ <CardContent className="p-0">
208
+ <div className="flex flex-wrap items-center gap-2 border-b border-border-seam p-3">
209
+ {filterChips.map((chip) => (
210
+ <button
211
+ key={chip.value}
212
+ type="button"
213
+ onClick={() => setFilter(chip.value)}
214
+ className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-action-primary-bg ${
215
+ filter === chip.value
216
+ ? 'border-transparent bg-action-primary-bg text-action-primary-text'
217
+ : 'border-border-seam text-text-secondary hover:bg-bg-sunken/60'
218
+ }`}
219
+ >
220
+ {chip.label}
221
+ <span className="tabular-nums opacity-80">{chip.count}</span>
222
+ </button>
223
+ ))}
224
+ <span className="ml-auto text-xs text-text-secondary">
225
+ {locatedCount} of {filteredDeliveries.length} located
226
+ </span>
150
227
  </div>
228
+ <LogisticsMap
229
+ markers={markers}
230
+ height={560}
231
+ emptyMessage={
232
+ filteredDeliveries.length === 0
233
+ ? 'No active deliveries to plot'
234
+ : 'Awaiting live GPS positions for these deliveries'
235
+ }
236
+ />
151
237
  </CardContent>
152
238
  </Card>
153
239
  ) : (
@@ -158,7 +244,7 @@ export default function LiveTrackingPage() {
158
244
  <CardContent className="p-0">
159
245
  <ScrollArea className="h-[550px]">
160
246
  <div className="divide-y">
161
- {activeDeliveries.map((delivery) => {
247
+ {filteredDeliveries.map((delivery) => {
162
248
  if (!delivery.order) {
163
249
  return null;
164
250
  }
@@ -214,7 +300,7 @@ export default function LiveTrackingPage() {
214
300
  </div>
215
301
  );
216
302
  })}
217
- {activeDeliveries.length === 0 && (
303
+ {filteredDeliveries.length === 0 && (
218
304
  <EmptyState
219
305
  illustration="empty-sessions"
220
306
  title="No active deliveries"
@@ -268,6 +354,28 @@ export default function LiveTrackingPage() {
268
354
  <p className="text-sm">
269
355
  {selected.tracking?.currentLocation.address || 'Updating...'}
270
356
  </p>
357
+ {(() => {
358
+ const coord = firstRealLatLng(
359
+ selected.vehicle?.currentLocation,
360
+ selected.driver?.currentLocation,
361
+ selected.tracking?.currentLocation
362
+ );
363
+ return coord ? (
364
+ <LogisticsMap
365
+ className="mt-3 overflow-hidden rounded-lg border border-border-seam"
366
+ height={160}
367
+ markers={[
368
+ {
369
+ id: selected.order?.id ?? 'selected',
370
+ lat: coord.lat,
371
+ lng: coord.lng,
372
+ label: selected.order?.orderNumber ?? 'Delivery',
373
+ status: deliveryMarkerStatus(selected.order?.status),
374
+ },
375
+ ]}
376
+ />
377
+ ) : null;
378
+ })()}
271
379
  </div>
272
380
  <div>
273
381
  <p className="text-sm text-text-secondary">Estimated Arrival</p>