@burdenoff/microfe-movethewheels 2026.1102.1 → 2026.1102.2

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 (27) hide show
  1. package/dist/components/freight-cost/FreightCommercialFactEditor.js +46 -46
  2. package/dist/components/freight-cost/FreightCommercialHistory.js +7 -7
  3. package/dist/components/freight-cost/FreightDraftForm.js +20 -20
  4. package/dist/components/freight-invoice/InvoiceReviewPanel.js +255 -0
  5. package/dist/components/freight-invoice/InvoiceReviewQueue.js +93 -0
  6. package/dist/generated/freight-invoice-operations.d.ts +461 -0
  7. package/dist/hooks/useInvoiceComparisonRecovery.js +26 -26
  8. package/dist/hooks/useInvoiceReviewPermissions.js +14 -0
  9. package/dist/movethewheels/components/freight-invoice/InvoiceReviewPanel.d.ts +11 -0
  10. package/dist/movethewheels/components/freight-invoice/InvoiceReviewQueue.d.ts +22 -0
  11. package/dist/movethewheels/hooks/useInvoiceReviewPermissions.d.ts +5 -0
  12. package/dist/movethewheels/pages/FinancePage.d.ts +3 -1
  13. package/dist/movethewheels/utils/invoiceReview.d.ts +26 -0
  14. package/dist/pages/FinancePage.js +109 -67
  15. package/dist/pages/FreightEstimatePage.js +89 -89
  16. package/dist/pages/FreightInvoicePage.js +138 -120
  17. package/dist/src/generated/freight-invoice-operations.js +2100 -1
  18. package/dist/utils/invoiceReview.js +84 -0
  19. package/package.json +2 -2
  20. package/src/generated/freight-invoice-operations.ts +245 -1
  21. package/src/movethewheels/components/freight-invoice/InvoiceReviewPanel.tsx +319 -0
  22. package/src/movethewheels/components/freight-invoice/InvoiceReviewQueue.tsx +96 -0
  23. package/src/movethewheels/hooks/useInvoiceReviewPermissions.ts +25 -0
  24. package/src/movethewheels/pages/FinancePage.tsx +34 -2
  25. package/src/movethewheels/pages/FreightInvoicePage.tsx +44 -3
  26. package/src/movethewheels/utils/invoiceReview.ts +146 -0
  27. package/src/operations/freight-invoice/review.graphql +26 -0
@@ -1,14 +1,14 @@
1
1
  import { useMoveTheWheels as e } from "../providers/MoveTheWheelsProvider.js";
2
2
  import { resolveGraphqlUrl as t } from "../utils/graphqlClient.js";
3
3
  import { useConditionApi as n } from "./useContainerCondition.js";
4
- import { INVOICE_RECOVERY_STORAGE as r, decodeInvoiceIntent as i, encodeInvoiceIntent as a, invoiceCanonical as o, invoiceRecordInput as s, matchesInvoiceReceipt as c, sameInvoiceScope as l } from "../utils/invoiceComparison.js";
5
- import { InvoiceComparisonExactDocument as u, RecordInvoiceComparisonDocument as d, RecoverInvoiceComparisonDocument as f } from "../src/generated/freight-invoice-operations.js";
4
+ import { InvoiceComparisonExactDocument as r, RecordInvoiceComparisonDocument as i, RecoverInvoiceComparisonDocument as a } from "../src/generated/freight-invoice-operations.js";
5
+ import { INVOICE_RECOVERY_STORAGE as o, decodeInvoiceIntent as s, encodeInvoiceIntent as c, invoiceCanonical as l, invoiceRecordInput as u, matchesInvoiceReceipt as d, sameInvoiceScope as f } from "../utils/invoiceComparison.js";
6
6
  import { useLayoutEffect as p, useRef as m, useState as h } from "react";
7
7
  import { useActiveContext as g } from "@burdenoff/fe-libs/shared/providers/shell";
8
8
  //#region src/movethewheels/hooks/useInvoiceComparisonRecovery.ts
9
9
  function _() {
10
10
  try {
11
- let e = sessionStorage.getItem(r), t = i(e);
11
+ let e = sessionStorage.getItem(o), t = s(e);
12
12
  return {
13
13
  intent: t,
14
14
  blocked: e !== null && t === null
@@ -32,7 +32,7 @@ function v(n) {
32
32
  };
33
33
  }
34
34
  function y(e, t) {
35
- let g = n("SINGLE_ATTEMPT"), [v] = h(_), [y, b] = h(v.intent), x = m(y), [S, C] = h(v.blocked), w = m(!1), [T, E] = h(!1), [D, O] = h(0), k = o(e), A = m(e), [j, M] = h(null);
35
+ let g = n("SINGLE_ATTEMPT"), [v] = h(_), [y, b] = h(v.intent), x = m(y), [S, C] = h(v.blocked), w = m(!1), [T, E] = h(!1), [D, O] = h(0), k = l(e), A = m(e), [j, M] = h(null);
36
36
  p(() => (A.current = e, () => {
37
37
  A.current = null;
38
38
  }), [k]);
@@ -41,37 +41,37 @@ function y(e, t) {
41
41
  message: e,
42
42
  error: t
43
43
  }), P = (e, t) => {
44
- if (!e || !c(e, t) || !l(t.scope, A.current)) throw Error("UNCONFIRMED");
45
- let n = i(sessionStorage.getItem(r));
46
- if (!n || o(n) !== o(t)) throw Error("RETAINED_INTENT_CHANGED");
47
- return sessionStorage.removeItem(r), x.current = null, b(null), C(!1), O((e) => e + 1), N("The exact immutable comparison receipt is confirmed.", !1), e;
44
+ if (!e || !d(e, t) || !f(t.scope, A.current)) throw Error("UNCONFIRMED");
45
+ let n = s(sessionStorage.getItem(o));
46
+ if (!n || l(n) !== l(t)) throw Error("RETAINED_INTENT_CHANGED");
47
+ return sessionStorage.removeItem(o), x.current = null, b(null), C(!1), O((e) => e + 1), N("The exact immutable comparison receipt is confirmed.", !1), e;
48
48
  };
49
49
  return {
50
- run: async (n, c) => {
50
+ run: async (n, r) => {
51
51
  if (w.current || x.current || S) return N("Resolve the original request before starting another."), null;
52
- if (!e || !l(e, A.current) || !t()) return N("Current shipment update permission and workspace context are required. Nothing was sent."), null;
53
- let u;
52
+ if (!e || !f(e, A.current) || !t()) return N("Current shipment update permission and workspace context are required. Nothing was sent."), null;
53
+ let a;
54
54
  try {
55
55
  if (sessionStorage.getItem("movethewheels.freight-invoice.unresolved.v1") !== null) throw Error("EXISTING");
56
- u = {
56
+ a = {
57
57
  version: 1,
58
58
  scope: structuredClone(e),
59
- input: s({
59
+ input: u({
60
60
  ...n,
61
61
  idempotencyKey: crypto.randomUUID()
62
62
  }),
63
- estimate: structuredClone(c)
64
- }, sessionStorage.setItem(r, a(u)), x.current = u, b(u);
63
+ estimate: structuredClone(r)
64
+ }, sessionStorage.setItem(o, c(a)), x.current = a, b(a);
65
65
  } catch {
66
66
  return N("The original request could not be retained safely. Nothing was sent; reload and inspect any retained request."), null;
67
67
  }
68
68
  w.current = !0, E(!0), M(null);
69
69
  try {
70
- if (!l(u.scope, A.current) || !t()) {
71
- let e = i(sessionStorage.getItem(r));
72
- return e && o(e) === o(u) && (sessionStorage.removeItem(r), x.current = null, b(null)), N("Context or permission changed before dispatch. Nothing was sent."), null;
70
+ if (!f(a.scope, A.current) || !t()) {
71
+ let e = s(sessionStorage.getItem(o));
72
+ return e && l(e) === l(a) && (sessionStorage.removeItem(o), x.current = null, b(null)), N("Context or permission changed before dispatch. Nothing was sent."), null;
73
73
  }
74
- return P((await g(d, { input: u.input })).compareMtwFreightInvoice, u);
74
+ return P((await g(i, { input: a.input })).compareMtwFreightInvoice, a);
75
75
  } catch {
76
76
  return N("Save outcome is UNKNOWN. Keep the original intent and use read-only recovery; do not resend it."), null;
77
77
  } finally {
@@ -81,21 +81,21 @@ function y(e, t) {
81
81
  reconcile: async () => {
82
82
  let e = x.current;
83
83
  if (w.current || !e) return null;
84
- if (!l(e.scope, A.current)) return N("Return to the original account, organization, workspace and project to inspect its request."), null;
84
+ if (!f(e.scope, A.current)) return N("Return to the original account, organization, workspace and project to inspect its request."), null;
85
85
  w.current = !0, E(!0), M(null);
86
86
  try {
87
- let t = (await g(f, {
87
+ let t = (await g(a, {
88
88
  shipmentId: e.input.shipmentId,
89
89
  requestKey: e.input.idempotencyKey
90
90
  })).mtwFreightInvoiceComparisonByRequestKey;
91
91
  if (!t) return N("No original-context receipt was returned. This does not prove no effect; the request stays UNKNOWN and cannot be resent."), null;
92
- if (!c(t, e)) throw Error("MISMATCH");
93
- if (!l(e.scope, A.current)) throw Error("CONTEXT_CHANGED");
94
- let n = await g(u, {
92
+ if (!d(t, e)) throw Error("MISMATCH");
93
+ if (!f(e.scope, A.current)) throw Error("CONTEXT_CHANGED");
94
+ let n = await g(r, {
95
95
  shipmentId: e.input.shipmentId,
96
96
  id: t.id
97
97
  });
98
- if (!c(n.mtwFreightInvoiceComparison, e) || n.mtwFreightInvoiceComparison.requestFingerprint !== t.requestFingerprint || o(n.mtwFreightInvoiceComparison) !== o(t)) throw Error("MISMATCH");
98
+ if (!d(n.mtwFreightInvoiceComparison, e) || n.mtwFreightInvoiceComparison.requestFingerprint !== t.requestFingerprint || l(n.mtwFreightInvoiceComparison) !== l(t)) throw Error("MISMATCH");
99
99
  return P(n.mtwFreightInvoiceComparison, e);
100
100
  } catch {
101
101
  return N("Read-only recovery could not confirm the exact original receipt. Keep the intent; no save was sent."), null;
@@ -109,7 +109,7 @@ function y(e, t) {
109
109
  uncertain: y !== null || S,
110
110
  revision: D,
111
111
  scopeKey: k,
112
- canReconcile: !!y && l(y.scope, e),
112
+ canReconcile: !!y && f(y.scope, e),
113
113
  feedback: j?.scopeKey === k ? j : null,
114
114
  refresh: () => O((e) => e + 1)
115
115
  };
@@ -0,0 +1,14 @@
1
+ import { useMoveTheWheels as e } from "../providers/MoveTheWheelsProvider.js";
2
+ import { usePermissions as t } from "@burdenoff/fe-libs/shared/providers/shell";
3
+ //#region src/movethewheels/hooks/useInvoiceReviewPermissions.ts
4
+ function n() {
5
+ let n = t(), { workspaceId: r, currentUser: i } = e(), a = !!(r && i?.id && n.scopeId === r && (n.isSuperAdmin || n.permissions?.scopeId === r && n.permissions.actorId === i.id)) && !n.isLoading && !n.error && n.hasPermission("mtw-freight-invoice:read");
6
+ return {
7
+ canRead: a,
8
+ canUpdate: a && n.hasPermission("mtw-freight-invoice:update"),
9
+ canApprove: a && n.hasPermission("mtw-freight-invoice:approve"),
10
+ loading: n.isLoading
11
+ };
12
+ }
13
+ //#endregion
14
+ export { n as useInvoiceReviewPermissions };
@@ -0,0 +1,11 @@
1
+ import { InvoiceReceiptFragment } from '../../../generated/freight-invoice-operations';
2
+ import { ReviewPermissions } from '../../utils/invoiceReview';
3
+ /**
4
+ * Review, dispute and Billing hand-off for one exact comparison revision
5
+ * (BOFF-10588). Every step appends to the revision's history; nothing is edited.
6
+ */
7
+ export declare function InvoiceReviewPanel({ record, permissions, onChanged, }: {
8
+ record: Pick<InvoiceReceiptFragment, 'id' | 'shipmentId' | 'facts'>;
9
+ permissions: ReviewPermissions;
10
+ onChanged?: () => void;
11
+ }): import('react').JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { InvoiceReviewFragment } from '../../../generated/freight-invoice-operations';
2
+ /** The latest revision of every recorded carrier invoice, filtered by review status (BOFF-10588). */
3
+ export declare function InvoiceReviewQueue({ revision, onOpen, locked, }: {
4
+ revision: number;
5
+ onOpen: (review: InvoiceReviewFragment) => void;
6
+ /** True while an invoice or correction draft is open: opening a review would discard it. */
7
+ locked?: boolean;
8
+ }): import('react').JSX.Element;
9
+ /** Review counts over the latest revision of every recorded carrier invoice. */
10
+ export declare function useInvoiceReviewSummary(enabled: boolean): {
11
+ summary: {
12
+ total: number;
13
+ awaitingReview: number;
14
+ accepted: number;
15
+ acceptedWithVariance: number;
16
+ disputed: number;
17
+ supplierResponded: number;
18
+ settlementHandedOff: number;
19
+ } | null;
20
+ loading: boolean;
21
+ error: string | null;
22
+ };
@@ -0,0 +1,5 @@
1
+ import { ReviewPermissions } from '../utils/invoiceReview';
2
+ /** Freight invoice review grants for this page's current actor and workspace (BOFF-10588). */
3
+ export declare function useInvoiceReviewPermissions(): ReviewPermissions & {
4
+ loading: boolean;
5
+ };
@@ -7,6 +7,8 @@
7
7
  * settlement are handled by the platform Billing module, which this page
8
8
  * deep-links to rather than re-implementing an Invoice ledger here. Carrier
9
9
  * invoices are checked against the agreed freight estimate on the freight
10
- * invoice comparison page, which this page links to (BOFF-4395).
10
+ * invoice comparison page, which this page links to (BOFF-4395). The review
11
+ * counts (awaiting review, disputed, accepted, handed to Billing) come from
12
+ * Query.mtwFreightInvoiceReviewSummary over real recorded invoices (BOFF-10588).
11
13
  */
12
14
  export default function FinancePage(): import('react').JSX.Element;
@@ -0,0 +1,26 @@
1
+ import { DecideMtwFreightInvoiceInput, HandOffMtwFreightInvoiceSettlementInput, InvoiceReviewFragment, MtwFreightInvoiceDecision, MtwFreightInvoiceResolution, MtwFreightInvoiceReviewAction, MtwFreightInvoiceReviewStatus, RecordMtwFreightInvoiceSupplierResponseInput, ResolveMtwFreightInvoiceDisputeInput } from '../../generated/freight-invoice-operations';
2
+ export declare const REVIEW_STATUS_LABELS: Record<MtwFreightInvoiceReviewStatus, string>;
3
+ export declare const REVIEW_EVENT_LABELS: Record<InvoiceReviewFragment['events'][number]['kind'], string>;
4
+ /** Statuses a reviewer can filter the queue by; SUPERSEDED never appears in the queue. */
5
+ export declare const REVIEW_QUEUE_STATUSES: MtwFreightInvoiceReviewStatus[];
6
+ export interface ReviewPermissions {
7
+ canRead: boolean;
8
+ canUpdate: boolean;
9
+ canApprove: boolean;
10
+ }
11
+ /** Steps the server says are open (author separation included) that this viewer is also permitted to take. */
12
+ export declare function availableReviewActions(review: Pick<InvoiceReviewFragment, 'allowedActions'>, permissions: ReviewPermissions): MtwFreightInvoiceReviewAction[];
13
+ /** Why the author sees no decision: the server withholds it, so say so instead of showing nothing. */
14
+ export declare function authorNotice(review: Pick<InvoiceReviewFragment, 'viewerIsAuthor' | 'status'>): string | null;
15
+ interface Common {
16
+ review: Pick<InvoiceReviewFragment, 'shipmentId' | 'comparisonId' | 'sequence'>;
17
+ idempotencyKey: string;
18
+ }
19
+ export type DraftProblem = 'REASON_REQUIRED' | 'LINES_REQUIRED' | 'RESPONSE_REQUIRED';
20
+ export declare const DRAFT_PROBLEM_LABELS: Record<DraftProblem, string>;
21
+ export declare function decisionInput(base: Common, decision: MtwFreightInvoiceDecision, reason: string, disputedLineIds: readonly string[]): DecideMtwFreightInvoiceInput | DraftProblem;
22
+ export declare function supplierResponseInput(base: Common, response: string): RecordMtwFreightInvoiceSupplierResponseInput | DraftProblem;
23
+ export declare function resolutionInput(base: Common, resolution: MtwFreightInvoiceResolution, reason: string): ResolveMtwFreightInvoiceDisputeInput | DraftProblem;
24
+ export declare function handOffInput(base: Common, note: string): HandOffMtwFreightInvoiceSettlementInput;
25
+ export declare function isDraftProblem(value: unknown): value is DraftProblem;
26
+ export {};
@@ -17,87 +17,128 @@ import { MetricCard as b, MetricGrid as x } from "../components/MetricCard.js";
17
17
  import { TrendChart as S } from "../components/charts/TrendChart.js";
18
18
  import { VolumeBar as C } from "../components/charts/VolumeBar.js";
19
19
  import "../components/charts/index.js";
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
+ import { useInvoiceReviewSummary as w } from "../components/freight-invoice/InvoiceReviewQueue.js";
21
+ import { useMemo as T } from "react";
22
+ import { jsx as E, jsxs as D } from "react/jsx-runtime";
23
+ import { EmphasisPanel as O, PagePurpose as k } from "@burdenoff/fe-libs/ui";
23
24
  //#region src/movethewheels/pages/FinancePage.tsx
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) => ({
25
+ function A() {
26
+ let { summary: e, loading: t, error: n } = w(!0);
27
+ return t ? /* @__PURE__ */ E("p", {
28
+ className: "text-sm text-text-secondary",
29
+ children: "Loading invoice review counts…"
30
+ }) : n || !e ? /* @__PURE__ */ E("p", {
31
+ className: "text-sm text-text-secondary",
32
+ children: "Invoice review counts need freight invoice read permission."
33
+ }) : /* @__PURE__ */ E("dl", {
34
+ className: "grid grid-cols-2 gap-2",
35
+ "aria-label": "Carrier invoice review",
36
+ children: [
37
+ {
38
+ label: "Awaiting review",
39
+ value: e.awaitingReview
40
+ },
41
+ {
42
+ label: "Disputed",
43
+ value: e.disputed + e.supplierResponded
44
+ },
45
+ {
46
+ label: "Accepted",
47
+ value: e.accepted + e.acceptedWithVariance
48
+ },
49
+ {
50
+ label: "Handed to Billing",
51
+ value: e.settlementHandedOff
52
+ }
53
+ ].map((e) => /* @__PURE__ */ D("div", {
54
+ className: "rounded-lg border border-border-default p-3",
55
+ children: [/* @__PURE__ */ E("dt", {
56
+ className: "text-xs text-text-secondary",
57
+ children: e.label
58
+ }), /* @__PURE__ */ E("dd", {
59
+ className: "text-lg font-semibold text-text-primary",
60
+ children: e.value
61
+ })]
62
+ }, e.label))
63
+ });
64
+ }
65
+ function j() {
66
+ let { analytics: w } = d(), { metrics: j } = f(), { navigate: M, basePath: N } = l(), P = () => M("/billing"), F = () => M(c(N, "finance/freight-estimates")), I = () => M(c(N, "finance/freight-invoice-comparisons")), L = T(() => w.trends.revenue.map((e) => ({
26
67
  month: e.month,
27
68
  revenue: e.revenue
28
- })), [k.trends.revenue]), L = w(() => [
69
+ })), [w.trends.revenue]), R = T(() => [
29
70
  {
30
71
  label: "Total revenue",
31
- amount: A.totalRevenue
72
+ amount: j.totalRevenue
32
73
  },
33
74
  {
34
75
  label: "Collected",
35
- amount: A.deliveredRevenue
76
+ amount: j.deliveredRevenue
36
77
  },
37
78
  {
38
79
  label: "Fuel cost",
39
- amount: A.fuelCost
80
+ amount: j.fuelCost
40
81
  }
41
82
  ], [
42
- A.totalRevenue,
43
- A.deliveredRevenue,
44
- A.fuelCost
45
- ]), R = L.some((e) => e.amount > 0);
46
- return /* @__PURE__ */ E(v, {
83
+ j.totalRevenue,
84
+ j.deliveredRevenue,
85
+ j.fuelCost
86
+ ]), z = R.some((e) => e.amount > 0);
87
+ return /* @__PURE__ */ D(v, {
47
88
  title: "Finance",
48
89
  subtitle: "Financial overview and reports",
49
- icon: /* @__PURE__ */ T(n, { size: 24 }),
50
- headerActions: /* @__PURE__ */ E(p, {
90
+ icon: /* @__PURE__ */ E(n, { size: 24 }),
91
+ headerActions: /* @__PURE__ */ D(p, {
51
92
  variant: "outline",
52
- onClick: N,
53
- children: [/* @__PURE__ */ T(i, { size: 16 }), " Invoices & Billing"]
93
+ onClick: P,
94
+ children: [/* @__PURE__ */ E(i, { size: 16 }), " Invoices & Billing"]
54
95
  }),
55
96
  children: [
56
- /* @__PURE__ */ T(O, {
57
- icon: /* @__PURE__ */ T(n, { size: 18 }),
97
+ /* @__PURE__ */ E(k, {
98
+ icon: /* @__PURE__ */ E(n, { size: 18 }),
58
99
  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."
59
100
  }),
60
- /* @__PURE__ */ E(x, {
101
+ /* @__PURE__ */ D(x, {
61
102
  columns: 4,
62
103
  children: [
63
- /* @__PURE__ */ T(b, {
104
+ /* @__PURE__ */ E(b, {
64
105
  treatment: "glass",
65
106
  glow: !0,
66
107
  label: "Total Revenue",
67
- value: u(A.totalRevenue),
68
- icon: /* @__PURE__ */ T(n, { size: 20 }),
108
+ value: u(j.totalRevenue),
109
+ icon: /* @__PURE__ */ E(n, { size: 20 }),
69
110
  accent: "success"
70
111
  }),
71
- /* @__PURE__ */ T(b, {
112
+ /* @__PURE__ */ E(b, {
72
113
  label: "Collected (Delivered)",
73
- value: u(A.deliveredRevenue),
74
- icon: /* @__PURE__ */ T(s, { size: 20 }),
114
+ value: u(j.deliveredRevenue),
115
+ icon: /* @__PURE__ */ E(s, { size: 20 }),
75
116
  accent: "brand"
76
117
  }),
77
- /* @__PURE__ */ T(b, {
118
+ /* @__PURE__ */ E(b, {
78
119
  label: "Fuel Cost",
79
- value: u(A.fuelCost),
80
- icon: /* @__PURE__ */ T(a, { size: 20 }),
120
+ value: u(j.fuelCost),
121
+ icon: /* @__PURE__ */ E(a, { size: 20 }),
81
122
  accent: "warning"
82
123
  }),
83
- /* @__PURE__ */ T(b, {
124
+ /* @__PURE__ */ E(b, {
84
125
  label: "Open Invoices",
85
- value: String(A.openInvoices),
86
- icon: /* @__PURE__ */ T(t, { size: 20 }),
126
+ value: String(j.openInvoices),
127
+ icon: /* @__PURE__ */ E(t, { size: 20 }),
87
128
  accent: "blue"
88
129
  })
89
130
  ]
90
131
  }),
91
- /* @__PURE__ */ E("div", {
132
+ /* @__PURE__ */ D("div", {
92
133
  className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
93
- children: [/* @__PURE__ */ E(m, {
134
+ children: [/* @__PURE__ */ D(m, {
94
135
  className: "lg:col-span-2",
95
- children: [/* @__PURE__ */ T(g, { children: /* @__PURE__ */ T(_, { children: "Revenue trend" }) }), /* @__PURE__ */ T(h, { children: /* @__PURE__ */ T(S, {
136
+ children: [/* @__PURE__ */ E(g, { children: /* @__PURE__ */ E(_, { children: "Revenue trend" }) }), /* @__PURE__ */ E(h, { children: /* @__PURE__ */ E(S, {
96
137
  xKey: "month",
97
138
  variant: "area",
98
139
  height: 280,
99
140
  showLegend: !1,
100
- data: I,
141
+ data: L,
101
142
  series: [{
102
143
  dataKey: "revenue",
103
144
  name: "Revenue",
@@ -106,65 +147,66 @@ function k() {
106
147
  valueFormatter: (e) => u(Number(e)),
107
148
  emptyMessage: "No revenue recorded yet. Revenue appears here as orders are delivered."
108
149
  }) })]
109
- }), /* @__PURE__ */ E(D, {
150
+ }), /* @__PURE__ */ D(O, {
110
151
  className: "space-y-4",
111
152
  children: [
112
- /* @__PURE__ */ T("h2", {
153
+ /* @__PURE__ */ E("h2", {
113
154
  className: "text-base font-semibold text-text-primary",
114
155
  children: "Invoices & Settlement"
115
156
  }),
116
- /* @__PURE__ */ T("p", {
157
+ /* @__PURE__ */ E("p", {
117
158
  className: "text-sm text-text-secondary",
118
159
  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."
119
160
  }),
120
- /* @__PURE__ */ E("div", {
161
+ /* @__PURE__ */ D("div", {
121
162
  className: "flex items-center justify-between p-4 bg-status-warning-bg/10 rounded-lg",
122
- children: [/* @__PURE__ */ E("div", {
163
+ children: [/* @__PURE__ */ D("div", {
123
164
  className: "flex items-center gap-3",
124
- children: [/* @__PURE__ */ T("div", {
165
+ children: [/* @__PURE__ */ E("div", {
125
166
  className: "w-10 h-10 rounded-full bg-status-warning-bg/20 flex items-center justify-center",
126
- children: /* @__PURE__ */ T(t, {
167
+ children: /* @__PURE__ */ E(t, {
127
168
  size: 20,
128
169
  className: "text-status-warning-text"
129
170
  })
130
- }), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
171
+ }), /* @__PURE__ */ D("div", { children: [/* @__PURE__ */ E("p", {
131
172
  className: "font-medium",
132
173
  children: "Open invoices"
133
- }), /* @__PURE__ */ E("p", {
174
+ }), /* @__PURE__ */ D("p", {
134
175
  className: "text-sm text-text-secondary",
135
- children: [A.openInvoices, " awaiting settlement"]
176
+ children: [j.openInvoices, " awaiting settlement"]
136
177
  })] })]
137
- }), /* @__PURE__ */ T("span", {
178
+ }), /* @__PURE__ */ E("span", {
138
179
  className: "text-xl font-bold text-status-warning-text",
139
- children: A.openInvoices
180
+ children: j.openInvoices
140
181
  })]
141
182
  }),
142
- /* @__PURE__ */ E(p, {
183
+ /* @__PURE__ */ D(p, {
143
184
  className: "w-full",
144
- onClick: N,
145
- children: ["Open Billing ", /* @__PURE__ */ T(e, { size: 16 })]
185
+ onClick: P,
186
+ children: ["Open Billing ", /* @__PURE__ */ E(e, { size: 16 })]
146
187
  }),
147
- /* @__PURE__ */ E("div", {
188
+ /* @__PURE__ */ D("div", {
148
189
  className: "space-y-2 border-t border-border-default pt-4",
149
190
  children: [
150
- /* @__PURE__ */ T("h3", {
191
+ /* @__PURE__ */ E("h3", {
151
192
  className: "text-sm font-semibold text-text-primary",
152
193
  children: "Freight cost control"
153
194
  }),
154
- /* @__PURE__ */ T("p", {
195
+ /* @__PURE__ */ E("p", {
155
196
  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."
197
+ children: "Record the agreed freight estimate for a shipment, then check the carrier's invoice against it line by line. Someone other than its author accepts or disputes it, and accepted invoices are handed to Billing for settlement."
157
198
  }),
158
- /* @__PURE__ */ E("div", {
199
+ /* @__PURE__ */ E(A, {}),
200
+ /* @__PURE__ */ D("div", {
159
201
  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, {
202
+ children: [/* @__PURE__ */ D(p, {
165
203
  variant: "outline",
166
204
  onClick: F,
167
- children: [/* @__PURE__ */ T(r, { size: 16 }), " Invoice comparisons"]
205
+ children: [/* @__PURE__ */ E(o, { size: 16 }), " Freight estimates"]
206
+ }), /* @__PURE__ */ D(p, {
207
+ variant: "outline",
208
+ onClick: I,
209
+ children: [/* @__PURE__ */ E(r, { size: 16 }), " Invoice comparisons"]
168
210
  })]
169
211
  })
170
212
  ]
@@ -172,17 +214,17 @@ function k() {
172
214
  ]
173
215
  })]
174
216
  }),
175
- /* @__PURE__ */ E(m, { children: [/* @__PURE__ */ T(g, { children: /* @__PURE__ */ T(_, { children: "Revenue vs cost" }) }), /* @__PURE__ */ T(h, { children: R ? /* @__PURE__ */ T(C, {
217
+ /* @__PURE__ */ D(m, { children: [/* @__PURE__ */ E(g, { children: /* @__PURE__ */ E(_, { children: "Revenue vs cost" }) }), /* @__PURE__ */ E(h, { children: z ? /* @__PURE__ */ E(C, {
176
218
  xKey: "label",
177
219
  height: 260,
178
220
  showLegend: !1,
179
- data: L,
221
+ data: R,
180
222
  series: [{
181
223
  dataKey: "amount",
182
224
  name: "Amount"
183
225
  }],
184
226
  valueFormatter: (e) => u(Number(e))
185
- }) : /* @__PURE__ */ T("p", {
227
+ }) : /* @__PURE__ */ E("p", {
186
228
  className: "py-8 text-center text-sm text-text-secondary",
187
229
  children: "Revenue and cost figures appear here as orders are delivered."
188
230
  }) })] })
@@ -190,4 +232,4 @@ function k() {
190
232
  });
191
233
  }
192
234
  //#endregion
193
- export { k as default };
235
+ export { j as default };