@burdenoff/microfe-movethewheels 2026.1031.5 → 2026.1031.6

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.
@@ -5,6 +5,8 @@
5
5
  * revenue, fuel cost, open invoices) plus the real revenue trend series — no
6
6
  * simulated paid/pending splits and no fabricated cost categories. Invoicing and
7
7
  * settlement are handled by the platform Billing module, which this page
8
- * deep-links to rather than re-implementing an Invoice ledger here.
8
+ * deep-links to rather than re-implementing an Invoice ledger here. Carrier
9
+ * invoices are checked against the agreed freight estimate on the freight
10
+ * invoice comparison page, which this page links to (BOFF-4395).
9
11
  */
10
12
  export default function FinancePage(): import('react').JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { createLucideIcon as e } from "../createLucideIcon.js";
2
+ //#region node_modules/lucide-react/dist/esm/icons/file-check.js
3
+ var t = e("FileCheck", [
4
+ ["path", {
5
+ d: "M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",
6
+ key: "1rqfz7"
7
+ }],
8
+ ["path", {
9
+ d: "M14 2v4a2 2 0 0 0 2 2h4",
10
+ key: "tnqrlb"
11
+ }],
12
+ ["path", {
13
+ d: "m9 15 2 2 4-4",
14
+ key: "1grp1n"
15
+ }]
16
+ ]);
17
+ //#endregion
18
+ export { t as FileCheck };
@@ -0,0 +1,18 @@
1
+ import { createLucideIcon as e } from "../createLucideIcon.js";
2
+ //#region node_modules/lucide-react/dist/esm/icons/receipt.js
3
+ var t = e("Receipt", [
4
+ ["path", {
5
+ d: "M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z",
6
+ key: "q3az6g"
7
+ }],
8
+ ["path", {
9
+ d: "M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8",
10
+ key: "1h4pet"
11
+ }],
12
+ ["path", {
13
+ d: "M12 17.5v-11",
14
+ key: "1jc1ny"
15
+ }]
16
+ ]);
17
+ //#endregion
18
+ export { t as Receipt };
@@ -1,160 +1,188 @@
1
1
  import { ArrowRight as e } from "../node_modules/lucide-react/dist/esm/icons/arrow-right.js";
2
2
  import { CreditCard as t } from "../node_modules/lucide-react/dist/esm/icons/credit-card.js";
3
3
  import { DollarSign as n } from "../node_modules/lucide-react/dist/esm/icons/dollar-sign.js";
4
- import { FileText as r } from "../node_modules/lucide-react/dist/esm/icons/file-text.js";
5
- import { Fuel as i } from "../node_modules/lucide-react/dist/esm/icons/fuel.js";
6
- import { TrendingUp as a } from "../node_modules/lucide-react/dist/esm/icons/trending-up.js";
7
- import { useMoveTheWheels as o } from "../providers/MoveTheWheelsProvider.js";
8
- import { formatCurrency as s } from "../utils/formatters.js";
9
- import { useAnalytics as c, useFinanceMetrics as l } from "../hooks/useAnalytics.js";
10
- import { Button as u, Card as d, CardContent as f, CardHeader as p, CardTitle as m } from "../components/ui.js";
11
- import { PageLayout as h } from "../components/PageLayout.js";
12
- import { chartTokens as g } from "../components/charts/chartTokens.js";
13
- import { MetricCard as _, MetricGrid as v } from "../components/MetricCard.js";
14
- import { TrendChart as y } from "../components/charts/TrendChart.js";
15
- import { VolumeBar as b } from "../components/charts/VolumeBar.js";
4
+ import { FileCheck as r } from "../node_modules/lucide-react/dist/esm/icons/file-check.js";
5
+ import { FileText as i } from "../node_modules/lucide-react/dist/esm/icons/file-text.js";
6
+ import { Fuel as a } from "../node_modules/lucide-react/dist/esm/icons/fuel.js";
7
+ import { Receipt as o } from "../node_modules/lucide-react/dist/esm/icons/receipt.js";
8
+ import { TrendingUp as s } from "../node_modules/lucide-react/dist/esm/icons/trending-up.js";
9
+ import { joinPath as c } from "../utils/navigation.js";
10
+ import { useMoveTheWheels as l } from "../providers/MoveTheWheelsProvider.js";
11
+ import { formatCurrency as u } from "../utils/formatters.js";
12
+ import { useAnalytics as d, useFinanceMetrics as f } from "../hooks/useAnalytics.js";
13
+ import { Button as p, Card as m, CardContent as h, CardHeader as g, CardTitle as _ } from "../components/ui.js";
14
+ import { PageLayout as v } from "../components/PageLayout.js";
15
+ import { chartTokens as y } from "../components/charts/chartTokens.js";
16
+ import { MetricCard as b, MetricGrid as x } from "../components/MetricCard.js";
17
+ import { TrendChart as S } from "../components/charts/TrendChart.js";
18
+ import { VolumeBar as C } from "../components/charts/VolumeBar.js";
16
19
  import "../components/charts/index.js";
17
- import { useMemo as x } from "react";
18
- import { jsx as S, jsxs as C } from "react/jsx-runtime";
19
- import { EmphasisPanel as w, PagePurpose as T } from "@burdenoff/fe-libs/ui";
20
+ import { useMemo as w } from "react";
21
+ import { jsx as T, jsxs as E } from "react/jsx-runtime";
22
+ import { EmphasisPanel as D, PagePurpose as O } from "@burdenoff/fe-libs/ui";
20
23
  //#region src/movethewheels/pages/FinancePage.tsx
21
- function E() {
22
- let { analytics: E } = c(), { metrics: D } = l(), { navigate: O } = o(), k = () => O("/billing"), A = x(() => E.trends.revenue.map((e) => ({
24
+ function k() {
25
+ let { analytics: k } = d(), { metrics: A } = f(), { navigate: j, basePath: M } = l(), N = () => j("/billing"), P = () => j(c(M, "finance/freight-estimates")), F = () => j(c(M, "finance/freight-invoice-comparisons")), I = w(() => k.trends.revenue.map((e) => ({
23
26
  month: e.month,
24
27
  revenue: e.revenue
25
- })), [E.trends.revenue]), j = x(() => [
28
+ })), [k.trends.revenue]), L = w(() => [
26
29
  {
27
30
  label: "Total revenue",
28
- amount: D.totalRevenue
31
+ amount: A.totalRevenue
29
32
  },
30
33
  {
31
34
  label: "Collected",
32
- amount: D.deliveredRevenue
35
+ amount: A.deliveredRevenue
33
36
  },
34
37
  {
35
38
  label: "Fuel cost",
36
- amount: D.fuelCost
39
+ amount: A.fuelCost
37
40
  }
38
41
  ], [
39
- D.totalRevenue,
40
- D.deliveredRevenue,
41
- D.fuelCost
42
- ]), M = j.some((e) => e.amount > 0);
43
- return /* @__PURE__ */ C(h, {
42
+ A.totalRevenue,
43
+ A.deliveredRevenue,
44
+ A.fuelCost
45
+ ]), R = L.some((e) => e.amount > 0);
46
+ return /* @__PURE__ */ E(v, {
44
47
  title: "Finance",
45
48
  subtitle: "Financial overview and reports",
46
- icon: /* @__PURE__ */ S(n, { size: 24 }),
47
- headerActions: /* @__PURE__ */ C(u, {
49
+ icon: /* @__PURE__ */ T(n, { size: 24 }),
50
+ headerActions: /* @__PURE__ */ E(p, {
48
51
  variant: "outline",
49
- onClick: k,
50
- children: [/* @__PURE__ */ S(r, { size: 16 }), " Invoices & Billing"]
52
+ onClick: N,
53
+ children: [/* @__PURE__ */ T(i, { size: 16 }), " Invoices & Billing"]
51
54
  }),
52
55
  children: [
53
- /* @__PURE__ */ S(T, {
54
- icon: /* @__PURE__ */ S(n, { size: 18 }),
56
+ /* @__PURE__ */ T(O, {
57
+ icon: /* @__PURE__ */ T(n, { size: 18 }),
55
58
  children: "Follow the money behind your deliveries. See total revenue, how much has already been collected on delivered orders, fuel cost and how many invoices are still open — then head to Billing to raise and settle invoices."
56
59
  }),
57
- /* @__PURE__ */ C(v, {
60
+ /* @__PURE__ */ E(x, {
58
61
  columns: 4,
59
62
  children: [
60
- /* @__PURE__ */ S(_, {
63
+ /* @__PURE__ */ T(b, {
61
64
  treatment: "glass",
62
65
  glow: !0,
63
66
  label: "Total Revenue",
64
- value: s(D.totalRevenue),
65
- icon: /* @__PURE__ */ S(n, { size: 20 }),
67
+ value: u(A.totalRevenue),
68
+ icon: /* @__PURE__ */ T(n, { size: 20 }),
66
69
  accent: "success"
67
70
  }),
68
- /* @__PURE__ */ S(_, {
71
+ /* @__PURE__ */ T(b, {
69
72
  label: "Collected (Delivered)",
70
- value: s(D.deliveredRevenue),
71
- icon: /* @__PURE__ */ S(a, { size: 20 }),
73
+ value: u(A.deliveredRevenue),
74
+ icon: /* @__PURE__ */ T(s, { size: 20 }),
72
75
  accent: "brand"
73
76
  }),
74
- /* @__PURE__ */ S(_, {
77
+ /* @__PURE__ */ T(b, {
75
78
  label: "Fuel Cost",
76
- value: s(D.fuelCost),
77
- icon: /* @__PURE__ */ S(i, { size: 20 }),
79
+ value: u(A.fuelCost),
80
+ icon: /* @__PURE__ */ T(a, { size: 20 }),
78
81
  accent: "warning"
79
82
  }),
80
- /* @__PURE__ */ S(_, {
83
+ /* @__PURE__ */ T(b, {
81
84
  label: "Open Invoices",
82
- value: String(D.openInvoices),
83
- icon: /* @__PURE__ */ S(t, { size: 20 }),
85
+ value: String(A.openInvoices),
86
+ icon: /* @__PURE__ */ T(t, { size: 20 }),
84
87
  accent: "blue"
85
88
  })
86
89
  ]
87
90
  }),
88
- /* @__PURE__ */ C("div", {
91
+ /* @__PURE__ */ E("div", {
89
92
  className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
90
- children: [/* @__PURE__ */ C(d, {
93
+ children: [/* @__PURE__ */ E(m, {
91
94
  className: "lg:col-span-2",
92
- children: [/* @__PURE__ */ S(p, { children: /* @__PURE__ */ S(m, { children: "Revenue trend" }) }), /* @__PURE__ */ S(f, { children: /* @__PURE__ */ S(y, {
95
+ children: [/* @__PURE__ */ T(g, { children: /* @__PURE__ */ T(_, { children: "Revenue trend" }) }), /* @__PURE__ */ T(h, { children: /* @__PURE__ */ T(S, {
93
96
  xKey: "month",
94
97
  variant: "area",
95
98
  height: 280,
96
99
  showLegend: !1,
97
- data: A,
100
+ data: I,
98
101
  series: [{
99
102
  dataKey: "revenue",
100
103
  name: "Revenue",
101
- color: g.brandBlue
104
+ color: y.brandBlue
102
105
  }],
103
- valueFormatter: (e) => s(Number(e)),
106
+ valueFormatter: (e) => u(Number(e)),
104
107
  emptyMessage: "No revenue recorded yet. Revenue appears here as orders are delivered."
105
108
  }) })]
106
- }), /* @__PURE__ */ C(w, {
109
+ }), /* @__PURE__ */ E(D, {
107
110
  className: "space-y-4",
108
111
  children: [
109
- /* @__PURE__ */ S("h2", {
112
+ /* @__PURE__ */ T("h2", {
110
113
  className: "text-base font-semibold text-text-primary",
111
114
  children: "Invoices & Settlement"
112
115
  }),
113
- /* @__PURE__ */ S("p", {
116
+ /* @__PURE__ */ T("p", {
114
117
  className: "text-sm text-text-secondary",
115
118
  children: "Invoicing, payments and settlement run through the platform Billing module — the single source of truth for what's been billed and paid. MoveTheWheels doesn't keep its own invoice ledger."
116
119
  }),
117
- /* @__PURE__ */ C("div", {
120
+ /* @__PURE__ */ E("div", {
118
121
  className: "flex items-center justify-between p-4 bg-status-warning-bg/10 rounded-lg",
119
- children: [/* @__PURE__ */ C("div", {
122
+ children: [/* @__PURE__ */ E("div", {
120
123
  className: "flex items-center gap-3",
121
- children: [/* @__PURE__ */ S("div", {
124
+ children: [/* @__PURE__ */ T("div", {
122
125
  className: "w-10 h-10 rounded-full bg-status-warning-bg/20 flex items-center justify-center",
123
- children: /* @__PURE__ */ S(t, {
126
+ children: /* @__PURE__ */ T(t, {
124
127
  size: 20,
125
128
  className: "text-status-warning-text"
126
129
  })
127
- }), /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
130
+ }), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
128
131
  className: "font-medium",
129
132
  children: "Open invoices"
130
- }), /* @__PURE__ */ C("p", {
133
+ }), /* @__PURE__ */ E("p", {
131
134
  className: "text-sm text-text-secondary",
132
- children: [D.openInvoices, " awaiting settlement"]
135
+ children: [A.openInvoices, " awaiting settlement"]
133
136
  })] })]
134
- }), /* @__PURE__ */ S("span", {
137
+ }), /* @__PURE__ */ T("span", {
135
138
  className: "text-xl font-bold text-status-warning-text",
136
- children: D.openInvoices
139
+ children: A.openInvoices
137
140
  })]
138
141
  }),
139
- /* @__PURE__ */ C(u, {
142
+ /* @__PURE__ */ E(p, {
140
143
  className: "w-full",
141
- onClick: k,
142
- children: ["Open Billing ", /* @__PURE__ */ S(e, { size: 16 })]
144
+ onClick: N,
145
+ children: ["Open Billing ", /* @__PURE__ */ T(e, { size: 16 })]
146
+ }),
147
+ /* @__PURE__ */ E("div", {
148
+ className: "space-y-2 border-t border-border-default pt-4",
149
+ children: [
150
+ /* @__PURE__ */ T("h3", {
151
+ className: "text-sm font-semibold text-text-primary",
152
+ children: "Freight cost control"
153
+ }),
154
+ /* @__PURE__ */ T("p", {
155
+ className: "text-sm text-text-secondary",
156
+ children: "Record the agreed freight estimate for a shipment, then check the carrier's invoice against it line by line before it is settled in Billing."
157
+ }),
158
+ /* @__PURE__ */ E("div", {
159
+ className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
160
+ children: [/* @__PURE__ */ E(p, {
161
+ variant: "outline",
162
+ onClick: P,
163
+ children: [/* @__PURE__ */ T(o, { size: 16 }), " Freight estimates"]
164
+ }), /* @__PURE__ */ E(p, {
165
+ variant: "outline",
166
+ onClick: F,
167
+ children: [/* @__PURE__ */ T(r, { size: 16 }), " Invoice comparisons"]
168
+ })]
169
+ })
170
+ ]
143
171
  })
144
172
  ]
145
173
  })]
146
174
  }),
147
- /* @__PURE__ */ C(d, { children: [/* @__PURE__ */ S(p, { children: /* @__PURE__ */ S(m, { children: "Revenue vs cost" }) }), /* @__PURE__ */ S(f, { children: M ? /* @__PURE__ */ S(b, {
175
+ /* @__PURE__ */ E(m, { children: [/* @__PURE__ */ T(g, { children: /* @__PURE__ */ T(_, { children: "Revenue vs cost" }) }), /* @__PURE__ */ T(h, { children: R ? /* @__PURE__ */ T(C, {
148
176
  xKey: "label",
149
177
  height: 260,
150
178
  showLegend: !1,
151
- data: j,
179
+ data: L,
152
180
  series: [{
153
181
  dataKey: "amount",
154
182
  name: "Amount"
155
183
  }],
156
- valueFormatter: (e) => s(Number(e))
157
- }) : /* @__PURE__ */ S("p", {
184
+ valueFormatter: (e) => u(Number(e))
185
+ }) : /* @__PURE__ */ T("p", {
158
186
  className: "py-8 text-center text-sm text-text-secondary",
159
187
  children: "Revenue and cost figures appear here as orders are delivered."
160
188
  }) })] })
@@ -162,4 +190,4 @@ function E() {
162
190
  });
163
191
  }
164
192
  //#endregion
165
- export { E as default };
193
+ export { k as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-movethewheels",
3
- "version": "2026.1031.5",
3
+ "version": "2026.1031.6",
4
4
  "description": "Burdenoff MoveTheWheels Microfrontend - Logistics & Supply Chain Management Platform",
5
5
  "type": "module",
6
6
  "files": [
@@ -211,9 +211,7 @@ function VarianceList({ rows }: VarianceListProps) {
211
211
  {rows.map((row) => {
212
212
  const isOvershoot = row.volumeVariance > 0;
213
213
  const Icon = isOvershoot ? TrendingUp : TrendingDown;
214
- const tone = isOvershoot
215
- ? 'text-status-success-text'
216
- : 'text-status-error-text';
214
+ const tone = isOvershoot ? 'text-status-success-text' : 'text-status-error-text';
217
215
  return (
218
216
  <li
219
217
  key={`${row.scopeType}-${row.scopeKey}-${row.periodStart}`}
@@ -5,11 +5,22 @@
5
5
  * revenue, fuel cost, open invoices) plus the real revenue trend series — no
6
6
  * simulated paid/pending splits and no fabricated cost categories. Invoicing and
7
7
  * settlement are handled by the platform Billing module, which this page
8
- * deep-links to rather than re-implementing an Invoice ledger here.
8
+ * deep-links to rather than re-implementing an Invoice ledger here. Carrier
9
+ * invoices are checked against the agreed freight estimate on the freight
10
+ * invoice comparison page, which this page links to (BOFF-4395).
9
11
  */
10
12
 
11
13
  import { useMemo } from 'react';
12
- import { DollarSign, TrendingUp, CreditCard, FileText, Fuel, ArrowRight } from 'lucide-react';
14
+ import {
15
+ DollarSign,
16
+ TrendingUp,
17
+ CreditCard,
18
+ FileText,
19
+ Fuel,
20
+ ArrowRight,
21
+ Receipt,
22
+ FileCheck,
23
+ } from 'lucide-react';
13
24
  import { PageLayout } from '../components/PageLayout';
14
25
  import { MetricCard, MetricGrid } from '../components/MetricCard';
15
26
  import { Card, CardContent, CardHeader, CardTitle, Button } from '../components/ui';
@@ -18,14 +29,18 @@ import { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';
18
29
  import { useAnalytics, useFinanceMetrics } from '../hooks/useAnalytics';
19
30
  import { useMoveTheWheels } from '../providers/MoveTheWheelsProvider';
20
31
  import { formatCurrency } from '../utils/formatters';
32
+ import { joinPath } from '../utils/navigation';
21
33
 
22
34
  export default function FinancePage() {
23
35
  const { analytics } = useAnalytics();
24
36
  const { metrics } = useFinanceMetrics();
25
- const { navigate } = useMoveTheWheels();
37
+ const { navigate, basePath } = useMoveTheWheels();
26
38
 
27
39
  // Deep-link to the host Billing module (mounted at /billing in the app shell).
28
40
  const openBilling = () => navigate('/billing');
41
+ const openFreightEstimates = () => navigate(joinPath(basePath, 'finance/freight-estimates'));
42
+ const openInvoiceComparisons = () =>
43
+ navigate(joinPath(basePath, 'finance/freight-invoice-comparisons'));
29
44
 
30
45
  const revenueSeries = useMemo(
31
46
  () => analytics.trends.revenue.map((r) => ({ month: r.month, revenue: r.revenue })),
@@ -137,6 +152,21 @@ export default function FinancePage() {
137
152
  <Button className="w-full" onClick={openBilling}>
138
153
  Open Billing <ArrowRight size={16} />
139
154
  </Button>
155
+ <div className="space-y-2 border-t border-border-default pt-4">
156
+ <h3 className="text-sm font-semibold text-text-primary">Freight cost control</h3>
157
+ <p className="text-sm text-text-secondary">
158
+ Record the agreed freight estimate for a shipment, then check the carrier&apos;s
159
+ invoice against it line by line before it is settled in Billing.
160
+ </p>
161
+ <div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
162
+ <Button variant="outline" onClick={openFreightEstimates}>
163
+ <Receipt size={16} /> Freight estimates
164
+ </Button>
165
+ <Button variant="outline" onClick={openInvoiceComparisons}>
166
+ <FileCheck size={16} /> Invoice comparisons
167
+ </Button>
168
+ </div>
169
+ </div>
140
170
  </EmphasisPanel>
141
171
  </div>
142
172