@burdenoff/microfe-proserviceworld 2026.1028.1 → 2026.1031.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 (109) hide show
  1. package/dist/generated/global-types.d.ts +9699 -583
  2. package/dist/generated/global-types.d.ts.map +1 -1
  3. package/dist/generated/wspace-types.d.ts +18076 -2999
  4. package/dist/generated/wspace-types.d.ts.map +1 -1
  5. package/dist/proserviceworld/__tests__/schemaStub.d.ts +20 -0
  6. package/dist/proserviceworld/__tests__/schemaStub.d.ts.map +1 -0
  7. package/dist/proserviceworld/components/CredentialDirectory.js +44 -43
  8. package/dist/proserviceworld/components/CredentialDirectory.js.map +1 -1
  9. package/dist/proserviceworld/components/CredentialReminderPanel.js +5 -4
  10. package/dist/proserviceworld/components/CredentialReminderPanel.js.map +1 -1
  11. package/dist/proserviceworld/components/ui.d.ts +7 -3
  12. package/dist/proserviceworld/components/ui.d.ts.map +1 -1
  13. package/dist/proserviceworld/components/ui.js +135 -121
  14. package/dist/proserviceworld/components/ui.js.map +1 -1
  15. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
  16. package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
  17. package/dist/proserviceworld/hooks/useTr.d.ts +49 -8
  18. package/dist/proserviceworld/hooks/useTr.d.ts.map +1 -1
  19. package/dist/proserviceworld/hooks/useTr.js +45 -21
  20. package/dist/proserviceworld/hooks/useTr.js.map +1 -1
  21. package/dist/proserviceworld/i18n/catalog/analytics.d.ts +5 -0
  22. package/dist/proserviceworld/i18n/catalog/analytics.d.ts.map +1 -0
  23. package/dist/proserviceworld/i18n/catalog/analytics.js +271 -0
  24. package/dist/proserviceworld/i18n/catalog/analytics.js.map +1 -0
  25. package/dist/proserviceworld/i18n/catalog/common.d.ts +9 -0
  26. package/dist/proserviceworld/i18n/catalog/common.d.ts.map +1 -0
  27. package/dist/proserviceworld/i18n/catalog/common.js +163 -0
  28. package/dist/proserviceworld/i18n/catalog/common.js.map +1 -0
  29. package/dist/proserviceworld/i18n/catalog/compliance.d.ts +5 -0
  30. package/dist/proserviceworld/i18n/catalog/compliance.d.ts.map +1 -0
  31. package/dist/proserviceworld/i18n/catalog/compliance.js +157 -0
  32. package/dist/proserviceworld/i18n/catalog/compliance.js.map +1 -0
  33. package/dist/proserviceworld/i18n/catalog/conflicts.d.ts +5 -0
  34. package/dist/proserviceworld/i18n/catalog/conflicts.d.ts.map +1 -0
  35. package/dist/proserviceworld/i18n/catalog/conflicts.js +145 -0
  36. package/dist/proserviceworld/i18n/catalog/conflicts.js.map +1 -0
  37. package/dist/proserviceworld/i18n/catalog/documents.d.ts +5 -0
  38. package/dist/proserviceworld/i18n/catalog/documents.d.ts.map +1 -0
  39. package/dist/proserviceworld/i18n/catalog/documents.js +157 -0
  40. package/dist/proserviceworld/i18n/catalog/documents.js.map +1 -0
  41. package/dist/proserviceworld/i18n/catalog/enums.d.ts +10 -0
  42. package/dist/proserviceworld/i18n/catalog/enums.d.ts.map +1 -0
  43. package/dist/proserviceworld/i18n/catalog/enums.js +481 -0
  44. package/dist/proserviceworld/i18n/catalog/enums.js.map +1 -0
  45. package/dist/proserviceworld/i18n/catalog/index.d.ts +9 -0
  46. package/dist/proserviceworld/i18n/catalog/index.d.ts.map +1 -0
  47. package/dist/proserviceworld/i18n/catalog/index.js +25 -0
  48. package/dist/proserviceworld/i18n/catalog/index.js.map +1 -0
  49. package/dist/proserviceworld/i18n/catalog/invoices.d.ts +5 -0
  50. package/dist/proserviceworld/i18n/catalog/invoices.d.ts.map +1 -0
  51. package/dist/proserviceworld/i18n/catalog/invoices.js +247 -0
  52. package/dist/proserviceworld/i18n/catalog/invoices.js.map +1 -0
  53. package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts +5 -0
  54. package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts.map +1 -0
  55. package/dist/proserviceworld/i18n/catalog/practiceAreas.js +97 -0
  56. package/dist/proserviceworld/i18n/catalog/practiceAreas.js.map +1 -0
  57. package/dist/proserviceworld/i18n/catalog/time.d.ts +5 -0
  58. package/dist/proserviceworld/i18n/catalog/time.d.ts.map +1 -0
  59. package/dist/proserviceworld/i18n/catalog/time.js +301 -0
  60. package/dist/proserviceworld/i18n/catalog/time.js.map +1 -0
  61. package/dist/proserviceworld/i18n/index.d.ts +10 -9
  62. package/dist/proserviceworld/i18n/index.d.ts.map +1 -1
  63. package/dist/proserviceworld/i18n/index.js +16 -12
  64. package/dist/proserviceworld/i18n/index.js.map +1 -1
  65. package/dist/proserviceworld/i18n/types.d.ts +13 -0
  66. package/dist/proserviceworld/i18n/types.d.ts.map +1 -0
  67. package/dist/proserviceworld/i18n/types.js +18 -0
  68. package/dist/proserviceworld/i18n/types.js.map +1 -0
  69. package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -1
  70. package/dist/proserviceworld/pages/AnalyticsPage.js +209 -197
  71. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  72. package/dist/proserviceworld/pages/ClientDetailPage.js +99 -98
  73. package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
  74. package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -1
  75. package/dist/proserviceworld/pages/ClientsPage.js +181 -181
  76. package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
  77. package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -1
  78. package/dist/proserviceworld/pages/CompliancePage.js +210 -209
  79. package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
  80. package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -1
  81. package/dist/proserviceworld/pages/ConflictsPage.js +139 -138
  82. package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -1
  83. package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -1
  84. package/dist/proserviceworld/pages/DocumentsPage.js +150 -149
  85. package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
  86. package/dist/proserviceworld/pages/EngagementDetailPage.js +105 -104
  87. package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
  88. package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -1
  89. package/dist/proserviceworld/pages/EngagementsPage.js +137 -137
  90. package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
  91. package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -1
  92. package/dist/proserviceworld/pages/InvoicesPage.js +257 -256
  93. package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
  94. package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -1
  95. package/dist/proserviceworld/pages/MattersPage.js +166 -166
  96. package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
  97. package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -1
  98. package/dist/proserviceworld/pages/PracticeAreasPage.js +100 -99
  99. package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -1
  100. package/dist/proserviceworld/pages/PractitionerCredentialsPage.js +30 -29
  101. package/dist/proserviceworld/pages/PractitionerCredentialsPage.js.map +1 -1
  102. package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -1
  103. package/dist/proserviceworld/pages/TimePage.js +343 -350
  104. package/dist/proserviceworld/pages/TimePage.js.map +1 -1
  105. package/dist/proserviceworld/utils/humanize.d.ts +3 -0
  106. package/dist/proserviceworld/utils/humanize.d.ts.map +1 -0
  107. package/dist/proserviceworld/utils/humanize.js +6 -0
  108. package/dist/proserviceworld/utils/humanize.js.map +1 -0
  109. package/package.json +1 -1
@@ -1,241 +1,251 @@
1
1
  import { useDashboardStats as e, useWriteOffs as t } from "../hooks/useProServiceWorldApi.js";
2
2
  import { cn as n } from "../utils/cn.js";
3
- import { Empty as r, ErrorState as i, LoadingBlock as a, MetricCard as o, PageHeader as s, SectionCard as c, StatusPill as l, TableWrap as u, Td as d, Th as f, fmtDate as p, fmtHours as m, fmtMoney as h } from "../components/ui.js";
4
- import { AlertTriangle as g, BarChart3 as _, Clock as v, Scale as y, TrendingUp as b, Wallet as x } from "lucide-react";
5
- import { jsx as S, jsxs as C } from "react/jsx-runtime";
3
+ import { plural as r, useTr as i } from "../hooks/useTr.js";
4
+ import { Empty as a, ErrorState as o, LoadingBlock as s, MetricCard as c, PageHeader as l, SectionCard as u, StatusPill as d, TableWrap as f, Td as p, Th as m, fmtDate as h, fmtHours as g, fmtMoney as _ } from "../components/ui.js";
5
+ import { AlertTriangle as v, BarChart3 as y, Clock as b, Scale as x, TrendingUp as S, Wallet as C } from "lucide-react";
6
+ import { jsx as w, jsxs as T } from "react/jsx-runtime";
6
7
  //#region src/proserviceworld/pages/AnalyticsPage.tsx
7
- var w = () => {
8
- let { data: n, isLoading: l, error: w, refetch: D } = e(), j = t({ pagination: { limit: 10 } });
9
- if (l) return /* @__PURE__ */ S(a, { label: "Crunching numbers…" });
10
- if (w) return /* @__PURE__ */ S(i, {
11
- error: w,
12
- onRetry: () => void D()
8
+ var E = () => {
9
+ let n = i(), { data: r, isLoading: d, error: E, refetch: k } = e(), N = t({ pagination: { limit: 10 } });
10
+ if (d) return /* @__PURE__ */ w(s, { label: n("psw.analytics.loading", "Crunching numbers…") });
11
+ if (E) return /* @__PURE__ */ w(o, {
12
+ error: E,
13
+ onRetry: () => void k()
13
14
  });
14
- if (!n) return null;
15
- let M = n.unbilledHours + n.billedHours, N = M > 0 ? Math.round(n.billedHours / M * 100) : 0, P = n.paidInvoiceTotal + n.outstandingInvoiceTotal, F = P > 0 ? Math.round(n.paidInvoiceTotal / P * 100) : 0;
16
- return /* @__PURE__ */ C("div", {
15
+ if (!r) return null;
16
+ let P = r.unbilledHours + r.billedHours, F = P > 0 ? Math.round(r.billedHours / P * 100) : 0, I = r.paidInvoiceTotal + r.outstandingInvoiceTotal, L = I > 0 ? Math.round(r.paidInvoiceTotal / I * 100) : 0;
17
+ return /* @__PURE__ */ T("div", {
17
18
  className: "space-y-6",
18
19
  children: [
19
- /* @__PURE__ */ S(s, {
20
- title: "Analytics",
21
- subtitle: "Real, live metrics across the practice — no estimates, straight from your records.",
22
- icon: /* @__PURE__ */ S(_, { className: "h-6 w-6" })
20
+ /* @__PURE__ */ w(l, {
21
+ title: n("psw.analytics.title", "Analytics"),
22
+ subtitle: n("psw.analytics.subtitle", "Real, live metrics across the practice — no estimates, straight from your records."),
23
+ icon: /* @__PURE__ */ w(y, { className: "h-6 w-6" })
23
24
  }),
24
- /* @__PURE__ */ C("div", {
25
+ /* @__PURE__ */ T("div", {
25
26
  className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
26
27
  children: [
27
- /* @__PURE__ */ S(o, {
28
- label: "Collected revenue",
29
- value: h(n.paidInvoiceTotal),
30
- hint: `${h(P)} invoiced`,
31
- icon: /* @__PURE__ */ S(x, { className: "h-4 w-4" }),
28
+ /* @__PURE__ */ w(c, {
29
+ label: n("psw.analytics.collectedRevenue", "Collected revenue"),
30
+ value: _(r.paidInvoiceTotal),
31
+ hint: n("psw.analytics.invoicedHint", "{{amount}} invoiced", { amount: _(I) }),
32
+ icon: /* @__PURE__ */ w(C, { className: "h-4 w-4" }),
32
33
  tone: "success"
33
34
  }),
34
- /* @__PURE__ */ S(o, {
35
- label: "Collection rate",
36
- value: `${F}%`,
37
- hint: `${h(n.outstandingInvoiceTotal)} outstanding`,
38
- icon: /* @__PURE__ */ S(b, { className: "h-4 w-4" }),
35
+ /* @__PURE__ */ w(c, {
36
+ label: n("psw.analytics.collectionRate", "Collection rate"),
37
+ value: `${L}%`,
38
+ hint: n("psw.analytics.outstandingHint", "{{amount}} outstanding", { amount: _(r.outstandingInvoiceTotal) }),
39
+ icon: /* @__PURE__ */ w(S, { className: "h-4 w-4" }),
39
40
  tone: "accent"
40
41
  }),
41
- /* @__PURE__ */ S(o, {
42
- label: "Utilization",
43
- value: `${N}%`,
44
- hint: `${m(n.billedHours)} of ${m(M)}`,
45
- icon: /* @__PURE__ */ S(v, { className: "h-4 w-4" }),
42
+ /* @__PURE__ */ w(c, {
43
+ label: n("psw.analytics.utilization", "Utilization"),
44
+ value: `${F}%`,
45
+ hint: n("psw.analytics.hoursOfTotal", "{{billed}} of {{total}}", {
46
+ billed: g(r.billedHours),
47
+ total: g(P)
48
+ }),
49
+ icon: /* @__PURE__ */ w(b, { className: "h-4 w-4" }),
46
50
  tone: "info"
47
51
  }),
48
- /* @__PURE__ */ S(o, {
49
- label: "Active engagements",
50
- value: n.activeEngagements,
51
- hint: `${n.openMatters} open matters`,
52
- icon: /* @__PURE__ */ S(_, { className: "h-4 w-4" }),
52
+ /* @__PURE__ */ w(c, {
53
+ label: n("psw.analytics.activeEngagements", "Active engagements"),
54
+ value: r.activeEngagements,
55
+ hint: n("psw.analytics.openMattersHint", "{{count}} open matters", { count: r.openMatters }),
56
+ icon: /* @__PURE__ */ w(y, { className: "h-4 w-4" }),
53
57
  tone: "warning"
54
58
  })
55
59
  ]
56
60
  }),
57
- /* @__PURE__ */ C("div", {
61
+ /* @__PURE__ */ T("div", {
58
62
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
59
- children: [/* @__PURE__ */ S(c, {
60
- title: "Collection rate",
61
- description: "Paid vs. total invoiced.",
62
- children: /* @__PURE__ */ S(E, {
63
- pct: F,
63
+ children: [/* @__PURE__ */ w(u, {
64
+ title: n("psw.analytics.collectionRate", "Collection rate"),
65
+ description: n("psw.analytics.collectionRateDescription", "Paid vs. total invoiced."),
66
+ children: /* @__PURE__ */ w(O, {
67
+ pct: L,
64
68
  tone: "accent",
65
- primary: h(n.paidInvoiceTotal),
66
- primaryLabel: "Collected",
67
- secondary: h(n.outstandingInvoiceTotal),
68
- secondaryLabel: "Outstanding"
69
+ primary: _(r.paidInvoiceTotal),
70
+ primaryLabel: n("psw.analytics.collected", "Collected"),
71
+ secondary: _(r.outstandingInvoiceTotal),
72
+ secondaryLabel: n("psw.analytics.outstanding", "Outstanding")
69
73
  })
70
- }), /* @__PURE__ */ S(c, {
71
- title: "Utilization",
72
- description: "Billed vs. total logged hours.",
73
- children: /* @__PURE__ */ S(E, {
74
- pct: N,
74
+ }), /* @__PURE__ */ w(u, {
75
+ title: n("psw.analytics.utilization", "Utilization"),
76
+ description: n("psw.analytics.utilizationDescription", "Billed vs. total logged hours."),
77
+ children: /* @__PURE__ */ w(O, {
78
+ pct: F,
75
79
  tone: "info",
76
- primary: m(n.billedHours),
77
- primaryLabel: "Billed",
78
- secondary: m(n.unbilledHours),
79
- secondaryLabel: "Unbilled"
80
+ primary: g(r.billedHours),
81
+ primaryLabel: n("psw.analytics.billed", "Billed"),
82
+ secondary: g(r.unbilledHours),
83
+ secondaryLabel: n("psw.analytics.unbilled", "Unbilled")
80
84
  })
81
85
  })]
82
86
  }),
83
- /* @__PURE__ */ S(c, {
84
- title: "Revenue by month",
85
- description: "Invoiced totals across recent months.",
86
- children: /* @__PURE__ */ S(O, { data: n.revenueByMonth })
87
+ /* @__PURE__ */ w(u, {
88
+ title: n("psw.analytics.revenueByMonth", "Revenue by month"),
89
+ description: n("psw.analytics.revenueByMonthDescription", "Invoiced totals across recent months."),
90
+ children: /* @__PURE__ */ w(A, { data: r.revenueByMonth })
87
91
  }),
88
- /* @__PURE__ */ C("div", {
92
+ /* @__PURE__ */ T("div", {
89
93
  className: "grid grid-cols-1 gap-4 lg:grid-cols-3",
90
94
  children: [
91
- /* @__PURE__ */ S(c, {
92
- title: "Engagements",
93
- description: "By status",
94
- children: /* @__PURE__ */ S(k, { items: n.engagementsByStatus })
95
+ /* @__PURE__ */ w(u, {
96
+ title: n("psw.analytics.engagements", "Engagements"),
97
+ description: n("psw.analytics.byStatus", "By status"),
98
+ children: /* @__PURE__ */ w(j, { items: r.engagementsByStatus })
95
99
  }),
96
- /* @__PURE__ */ S(c, {
97
- title: "Matters",
98
- description: "By status",
99
- children: /* @__PURE__ */ S(k, { items: n.mattersByStatus })
100
+ /* @__PURE__ */ w(u, {
101
+ title: n("psw.analytics.matters", "Matters"),
102
+ description: n("psw.analytics.byStatus", "By status"),
103
+ children: /* @__PURE__ */ w(j, { items: r.mattersByStatus })
100
104
  }),
101
- /* @__PURE__ */ S(c, {
102
- title: "Invoices",
103
- description: "By status",
104
- children: /* @__PURE__ */ S(k, { items: n.invoicesByStatus })
105
+ /* @__PURE__ */ w(u, {
106
+ title: n("psw.analytics.invoices", "Invoices"),
107
+ description: n("psw.analytics.byStatus", "By status"),
108
+ children: /* @__PURE__ */ w(j, { items: r.invoicesByStatus })
105
109
  })
106
110
  ]
107
111
  }),
108
- /* @__PURE__ */ S(c, {
109
- title: "Time & billing",
110
- description: "Billable capacity across the practice.",
111
- children: /* @__PURE__ */ C("div", {
112
+ /* @__PURE__ */ w(u, {
113
+ title: n("psw.analytics.timeBilling", "Time & billing"),
114
+ description: n("psw.analytics.timeBillingDescription", "Billable capacity across the practice."),
115
+ children: /* @__PURE__ */ T("div", {
112
116
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
113
- children: [/* @__PURE__ */ S(A, {
114
- label: "Billed hours",
115
- value: n.billedHours,
116
- total: M,
117
+ children: [/* @__PURE__ */ w(M, {
118
+ label: n("psw.analytics.billedHours", "Billed hours"),
119
+ value: r.billedHours,
120
+ total: P,
117
121
  tone: "accent"
118
- }), /* @__PURE__ */ S(A, {
119
- label: "Unbilled hours",
120
- value: n.unbilledHours,
121
- total: M,
122
+ }), /* @__PURE__ */ w(M, {
123
+ label: n("psw.analytics.unbilledHours", "Unbilled hours"),
124
+ value: r.unbilledHours,
125
+ total: P,
122
126
  tone: "warning"
123
127
  })]
124
128
  })
125
129
  }),
126
- /* @__PURE__ */ C("div", {
130
+ /* @__PURE__ */ T("div", {
127
131
  className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
128
- children: [/* @__PURE__ */ S(o, {
129
- label: "Realization",
130
- value: `${Math.round(n.realizationPct)}%`,
131
- hint: `${h(n.billedValue)} of ${h(n.workedValue)} worked`,
132
- icon: /* @__PURE__ */ S(y, { className: "h-4 w-4" }),
132
+ children: [/* @__PURE__ */ w(c, {
133
+ label: n("psw.analytics.realization", "Realization"),
134
+ value: `${Math.round(r.realizationPct)}%`,
135
+ hint: n("psw.analytics.realizationHint", "{{billed}} of {{worked}} worked", {
136
+ billed: _(r.billedValue),
137
+ worked: _(r.workedValue)
138
+ }),
139
+ icon: /* @__PURE__ */ w(x, { className: "h-4 w-4" }),
133
140
  tone: "accent"
134
- }), /* @__PURE__ */ S(o, {
135
- label: "Write-offs",
136
- value: h(n.writeOffTotal),
137
- hint: "Total written off",
138
- icon: /* @__PURE__ */ S(g, { className: "h-4 w-4" }),
141
+ }), /* @__PURE__ */ w(c, {
142
+ label: n("psw.analytics.writeOffs", "Write-offs"),
143
+ value: _(r.writeOffTotal),
144
+ hint: n("psw.analytics.writeOffsHint", "Total written off"),
145
+ icon: /* @__PURE__ */ w(v, { className: "h-4 w-4" }),
139
146
  tone: "warning"
140
147
  })]
141
148
  }),
142
- /* @__PURE__ */ S(c, {
143
- title: "Aged receivables",
144
- description: "Outstanding invoice value by age — the margin-leak early warning.",
145
- children: /* @__PURE__ */ C("div", {
149
+ /* @__PURE__ */ w(u, {
150
+ title: n("psw.analytics.agedReceivables", "Aged receivables"),
151
+ description: n("psw.analytics.agedReceivablesDescription", "Outstanding invoice value by age — the margin-leak early warning."),
152
+ children: /* @__PURE__ */ T("div", {
146
153
  className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
147
154
  children: [
148
- /* @__PURE__ */ S(T, {
149
- label: "Current",
150
- bucket: n.agedReceivables.current,
155
+ /* @__PURE__ */ w(D, {
156
+ label: n("psw.analytics.agingCurrent", "Current"),
157
+ bucket: r.agedReceivables.current,
151
158
  tone: "success"
152
159
  }),
153
- /* @__PURE__ */ S(T, {
154
- label: "30 days",
155
- bucket: n.agedReceivables.thirty,
160
+ /* @__PURE__ */ w(D, {
161
+ label: n("psw.analytics.aging30", "30 days"),
162
+ bucket: r.agedReceivables.thirty,
156
163
  tone: "info"
157
164
  }),
158
- /* @__PURE__ */ S(T, {
159
- label: "60 days",
160
- bucket: n.agedReceivables.sixty,
165
+ /* @__PURE__ */ w(D, {
166
+ label: n("psw.analytics.aging60", "60 days"),
167
+ bucket: r.agedReceivables.sixty,
161
168
  tone: "warning"
162
169
  }),
163
- /* @__PURE__ */ S(T, {
164
- label: "90+ days",
165
- bucket: n.agedReceivables.ninetyPlus,
170
+ /* @__PURE__ */ w(D, {
171
+ label: n("psw.analytics.aging90", "90+ days"),
172
+ bucket: r.agedReceivables.ninetyPlus,
166
173
  tone: "danger"
167
174
  })
168
175
  ]
169
176
  })
170
177
  }),
171
- /* @__PURE__ */ S(c, {
172
- title: "Write-offs",
173
- description: "Append-only audit of written-off amounts.",
174
- children: j.isLoading ? /* @__PURE__ */ S(a, { label: "Loading write-offs…" }) : j.data?.length ? /* @__PURE__ */ C(u, { children: [/* @__PURE__ */ S("thead", { children: /* @__PURE__ */ C("tr", { children: [
175
- /* @__PURE__ */ S(f, { children: "Date" }),
176
- /* @__PURE__ */ S(f, { children: "Reason" }),
177
- /* @__PURE__ */ S(f, {
178
- className: "text-right",
179
- children: "Amount"
178
+ /* @__PURE__ */ w(u, {
179
+ title: n("psw.analytics.writeOffs", "Write-offs"),
180
+ description: n("psw.analytics.writeOffsDescription", "Append-only audit of written-off amounts."),
181
+ children: N.isLoading ? /* @__PURE__ */ w(s, { label: n("psw.analytics.writeOffsLoading", "Loading write-offs…") }) : N.data?.length ? /* @__PURE__ */ T(f, { children: [/* @__PURE__ */ w("thead", { children: /* @__PURE__ */ T("tr", { children: [
182
+ /* @__PURE__ */ w(m, { children: n("psw.common.date", "Date") }),
183
+ /* @__PURE__ */ w(m, { children: n("psw.analytics.reason", "Reason") }),
184
+ /* @__PURE__ */ w(m, {
185
+ className: "text-end",
186
+ children: n("psw.common.amount", "Amount")
180
187
  })
181
- ] }) }), /* @__PURE__ */ S("tbody", { children: j.data.map((e) => /* @__PURE__ */ C("tr", { children: [
182
- /* @__PURE__ */ S(d, { children: p(e.createdAt) }),
183
- /* @__PURE__ */ S(d, { children: e.reason }),
184
- /* @__PURE__ */ S(d, {
185
- className: "text-right",
186
- children: h(e.amount)
188
+ ] }) }), /* @__PURE__ */ w("tbody", { children: N.data.map((e) => /* @__PURE__ */ T("tr", { children: [
189
+ /* @__PURE__ */ w(p, { children: h(e.createdAt) }),
190
+ /* @__PURE__ */ w(p, { children: e.reason }),
191
+ /* @__PURE__ */ w(p, {
192
+ className: "text-end",
193
+ children: _(e.amount)
187
194
  })
188
- ] }, e.id)) })] }) : /* @__PURE__ */ S(r, {
189
- title: "No write-offs",
190
- description: "Nothing has been written off yet."
195
+ ] }, e.id)) })] }) : /* @__PURE__ */ w(a, {
196
+ title: n("psw.analytics.writeOffsEmptyTitle", "No write-offs"),
197
+ description: n("psw.analytics.writeOffsEmptyDescription", "Nothing has been written off yet.")
191
198
  })
192
199
  })
193
200
  ]
194
201
  });
195
- }, T = ({ label: e, bucket: t, tone: n }) => /* @__PURE__ */ S(o, {
196
- label: e,
197
- value: h(t.amount),
198
- hint: `${t.count} invoice${t.count === 1 ? "" : "s"}`,
199
- tone: n
200
- }), E = ({ pct: e, tone: t, primary: n, primaryLabel: r, secondary: i, secondaryLabel: a }) => /* @__PURE__ */ C("div", {
202
+ }, D = ({ label: e, bucket: t, tone: n }) => {
203
+ let a = i();
204
+ return /* @__PURE__ */ w(c, {
205
+ label: e,
206
+ value: _(t.amount),
207
+ hint: r(a, "psw.invoices.count", t.count, "{{count}} invoice", "{{count}} invoices"),
208
+ tone: n
209
+ });
210
+ }, O = ({ pct: e, tone: t, primary: n, primaryLabel: r, secondary: i, secondaryLabel: a }) => /* @__PURE__ */ T("div", {
201
211
  className: "flex items-center gap-5",
202
- children: [/* @__PURE__ */ S(D, {
212
+ children: [/* @__PURE__ */ w(k, {
203
213
  pct: e,
204
214
  tone: t
205
- }), /* @__PURE__ */ C("div", {
215
+ }), /* @__PURE__ */ T("div", {
206
216
  className: "flex flex-1 flex-col gap-2.5",
207
217
  children: [
208
- /* @__PURE__ */ C("div", {
218
+ /* @__PURE__ */ T("div", {
209
219
  className: "flex items-baseline justify-between gap-3",
210
- children: [/* @__PURE__ */ S("span", {
220
+ children: [/* @__PURE__ */ w("span", {
211
221
  className: "text-xs font-medium uppercase tracking-wider text-text-tertiary",
212
222
  children: r
213
- }), /* @__PURE__ */ S("span", {
223
+ }), /* @__PURE__ */ w("span", {
214
224
  className: "text-sm font-semibold tabular-nums text-text-primary",
215
225
  children: n
216
226
  })]
217
227
  }),
218
- /* @__PURE__ */ S("div", { className: "h-px bg-border-seam" }),
219
- /* @__PURE__ */ C("div", {
228
+ /* @__PURE__ */ w("div", { className: "h-px bg-border-seam" }),
229
+ /* @__PURE__ */ T("div", {
220
230
  className: "flex items-baseline justify-between gap-3",
221
- children: [/* @__PURE__ */ S("span", {
231
+ children: [/* @__PURE__ */ w("span", {
222
232
  className: "text-xs font-medium uppercase tracking-wider text-text-tertiary",
223
233
  children: a
224
- }), /* @__PURE__ */ S("span", {
234
+ }), /* @__PURE__ */ w("span", {
225
235
  className: "text-sm font-semibold tabular-nums text-text-secondary",
226
236
  children: i
227
237
  })]
228
238
  })
229
239
  ]
230
240
  })]
231
- }), D = ({ pct: e, tone: t }) => {
241
+ }), k = ({ pct: e, tone: t }) => {
232
242
  let r = Math.max(0, Math.min(100, e)), i = 2 * Math.PI * 34, a = r / 100 * i;
233
- return /* @__PURE__ */ C("div", {
243
+ return /* @__PURE__ */ T("div", {
234
244
  className: n("relative h-24 w-24 shrink-0", t === "accent" ? "text-accent" : "text-text-link"),
235
- children: [/* @__PURE__ */ C("svg", {
245
+ children: [/* @__PURE__ */ T("svg", {
236
246
  viewBox: "0 0 80 80",
237
247
  className: "h-full w-full -rotate-90",
238
- children: [/* @__PURE__ */ S("circle", {
248
+ children: [/* @__PURE__ */ w("circle", {
239
249
  cx: "40",
240
250
  cy: "40",
241
251
  r: 34,
@@ -243,7 +253,7 @@ var w = () => {
243
253
  strokeWidth: "8",
244
254
  className: "text-bg-sunken",
245
255
  stroke: "currentColor"
246
- }), /* @__PURE__ */ S("circle", {
256
+ }), /* @__PURE__ */ w("circle", {
247
257
  cx: "40",
248
258
  cy: "40",
249
259
  r: 34,
@@ -254,115 +264,117 @@ var w = () => {
254
264
  strokeDasharray: `${a} ${i}`,
255
265
  className: "transition-[stroke-dasharray] duration-700"
256
266
  })]
257
- }), /* @__PURE__ */ S("div", {
267
+ }), /* @__PURE__ */ w("div", {
258
268
  className: "absolute inset-0 flex items-center justify-center",
259
- children: /* @__PURE__ */ C("span", {
269
+ children: /* @__PURE__ */ T("span", {
260
270
  className: "text-lg font-bold tabular-nums text-text-primary",
261
271
  children: [r, "%"]
262
272
  })
263
273
  })]
264
274
  });
265
- }, O = ({ data: e }) => {
266
- if (!e.length) return /* @__PURE__ */ S("p", {
275
+ }, A = ({ data: e }) => {
276
+ let t = i();
277
+ if (!e.length) return /* @__PURE__ */ w("p", {
267
278
  className: "text-sm text-text-tertiary",
268
- children: "No invoiced revenue yet."
279
+ children: t("psw.dashboard.noRevenue", "No invoiced revenue yet.")
269
280
  });
270
- let t = Math.max(...e.map((e) => e.amount), 1);
271
- return /* @__PURE__ */ S("div", {
281
+ let n = Math.max(...e.map((e) => e.amount), 1);
282
+ return /* @__PURE__ */ w("div", {
272
283
  className: "overflow-x-auto",
273
- children: /* @__PURE__ */ C("div", {
284
+ children: /* @__PURE__ */ T("div", {
274
285
  className: "min-w-[520px]",
275
- children: [/* @__PURE__ */ S("div", {
286
+ children: [/* @__PURE__ */ w("div", {
276
287
  className: "flex h-60 items-end gap-2 border-b border-border-seam",
277
- children: e.map((e) => /* @__PURE__ */ C("div", {
288
+ children: e.map((e) => /* @__PURE__ */ T("div", {
278
289
  className: "group flex h-full flex-1 flex-col items-center justify-end gap-1.5",
279
- children: [/* @__PURE__ */ S("span", {
290
+ children: [/* @__PURE__ */ w("span", {
280
291
  className: "whitespace-nowrap text-[10px] font-semibold tabular-nums text-text-secondary",
281
- children: h(e.amount)
282
- }), /* @__PURE__ */ S("div", {
292
+ children: _(e.amount)
293
+ }), /* @__PURE__ */ w("div", {
283
294
  className: "w-full max-w-[3rem] rounded-t-lg bg-gradient-to-t from-accent/50 to-accent shadow-sm transition-all duration-200 group-hover:-translate-y-1 group-hover:shadow-md",
284
- style: { height: `${Math.max(e.amount / t * 90, 2)}%` },
285
- title: h(e.amount)
295
+ style: { height: `${Math.max(e.amount / n * 90, 2)}%` },
296
+ title: _(e.amount)
286
297
  })]
287
298
  }, e.month))
288
- }), /* @__PURE__ */ S("div", {
299
+ }), /* @__PURE__ */ w("div", {
289
300
  className: "mt-2 flex gap-2",
290
- children: e.map((e) => /* @__PURE__ */ S("span", {
301
+ children: e.map((e) => /* @__PURE__ */ w("span", {
291
302
  className: "flex-1 text-center text-xs text-text-tertiary",
292
- children: P(e.month)
303
+ children: I(e.month)
293
304
  }, e.month))
294
305
  })]
295
306
  })
296
307
  });
297
- }, k = ({ items: e }) => {
298
- if (!e.length) return /* @__PURE__ */ S("p", {
308
+ }, j = ({ items: e }) => {
309
+ let t = i();
310
+ if (!e.length) return /* @__PURE__ */ w("p", {
299
311
  className: "text-sm text-text-tertiary",
300
- children: "No records yet."
312
+ children: t("psw.dashboard.noRecords", "No records yet.")
301
313
  });
302
- let t = Math.max(...e.map((e) => e.count), 1), r = e.reduce((e, t) => e + t.count, 0) || 1;
303
- return /* @__PURE__ */ S("ul", {
314
+ let r = Math.max(...e.map((e) => e.count), 1), a = e.reduce((e, t) => e + t.count, 0) || 1;
315
+ return /* @__PURE__ */ w("ul", {
304
316
  className: "space-y-3.5",
305
- children: e.map((e) => /* @__PURE__ */ C("li", {
317
+ children: e.map((e) => /* @__PURE__ */ T("li", {
306
318
  className: "grid grid-cols-[7.5rem_minmax(0,1fr)_auto] items-center gap-3",
307
319
  children: [
308
- /* @__PURE__ */ S(l, {
320
+ /* @__PURE__ */ w(d, {
309
321
  status: e.status,
310
322
  className: "justify-self-start"
311
323
  }),
312
- /* @__PURE__ */ S("div", {
324
+ /* @__PURE__ */ w("div", {
313
325
  className: "h-2.5 overflow-hidden rounded-full bg-bg-sunken",
314
- children: /* @__PURE__ */ S("div", {
315
- className: n("h-full rounded-full bg-gradient-to-r transition-all duration-500", N(e.status)),
316
- style: { width: `${Math.max(e.count / t * 100, 4)}%` }
326
+ children: /* @__PURE__ */ w("div", {
327
+ className: n("h-full rounded-full bg-gradient-to-r transition-all duration-500", F(e.status)),
328
+ style: { width: `${Math.max(e.count / r * 100, 4)}%` }
317
329
  })
318
330
  }),
319
- /* @__PURE__ */ C("span", {
331
+ /* @__PURE__ */ T("span", {
320
332
  className: "flex items-baseline justify-end gap-1.5 tabular-nums",
321
- children: [/* @__PURE__ */ S("span", {
333
+ children: [/* @__PURE__ */ w("span", {
322
334
  className: "text-sm font-semibold text-text-primary",
323
335
  children: e.count
324
- }), /* @__PURE__ */ C("span", {
336
+ }), /* @__PURE__ */ T("span", {
325
337
  className: "text-xs text-text-tertiary",
326
- children: [Math.round(e.count / r * 100), "%"]
338
+ children: [Math.round(e.count / a * 100), "%"]
327
339
  })]
328
340
  })
329
341
  ]
330
342
  }, e.status))
331
343
  });
332
- }, A = ({ label: e, value: t, total: r, tone: i }) => {
344
+ }, M = ({ label: e, value: t, total: r, tone: i }) => {
333
345
  let a = r > 0 ? Math.round(t / r * 100) : 0, o = i === "accent" ? "from-accent/60 to-accent" : "from-status-warning-text/60 to-status-warning-text";
334
- return /* @__PURE__ */ C("div", {
346
+ return /* @__PURE__ */ T("div", {
335
347
  className: "rounded-xl border border-border-seam bg-bg-canvas p-4",
336
- children: [/* @__PURE__ */ C("div", {
348
+ children: [/* @__PURE__ */ T("div", {
337
349
  className: "mb-2.5 flex items-center justify-between gap-3",
338
- children: [/* @__PURE__ */ S("span", {
350
+ children: [/* @__PURE__ */ w("span", {
339
351
  className: "text-sm font-medium text-text-secondary",
340
352
  children: e
341
- }), /* @__PURE__ */ C("span", {
353
+ }), /* @__PURE__ */ T("span", {
342
354
  className: "text-sm font-semibold tabular-nums text-text-primary",
343
355
  children: [
344
- m(t),
356
+ g(t),
345
357
  " · ",
346
358
  a,
347
359
  "%"
348
360
  ]
349
361
  })]
350
- }), /* @__PURE__ */ S("div", {
362
+ }), /* @__PURE__ */ w("div", {
351
363
  className: "h-3 overflow-hidden rounded-full bg-bg-sunken",
352
- children: /* @__PURE__ */ S("div", {
364
+ children: /* @__PURE__ */ w("div", {
353
365
  className: n("h-full rounded-full bg-gradient-to-r transition-all duration-700", o),
354
366
  style: { width: `${a}%` }
355
367
  })
356
368
  })]
357
369
  });
358
- }, j = {
370
+ }, N = {
359
371
  success: "from-status-success-text/55 to-status-success-text",
360
372
  warning: "from-status-warning-text/55 to-status-warning-text",
361
373
  danger: "from-status-error-text/55 to-status-error-text",
362
374
  info: "from-text-link/55 to-text-link",
363
375
  accent: "from-accent/55 to-accent",
364
376
  neutral: "from-text-tertiary/30 to-text-tertiary/70"
365
- }, M = {
377
+ }, P = {
366
378
  ACTIVE: "success",
367
379
  DELIVERED: "success",
368
380
  INVOICED: "success",
@@ -402,16 +414,16 @@ var w = () => {
402
414
  DRAFT: "neutral",
403
415
  WAIVED: "neutral"
404
416
  };
405
- function N(e) {
406
- return j[M[e] ?? "accent"];
417
+ function F(e) {
418
+ return N[P[e] ?? "accent"];
407
419
  }
408
- function P(e) {
420
+ function I(e) {
409
421
  let [t, n] = e.split("-").map(Number);
410
422
  if (!t || !n) return e;
411
423
  let r = new Date(t, n - 1, 1);
412
424
  return Number.isNaN(r.getTime()) ? e : r.toLocaleDateString(void 0, { month: "short" });
413
425
  }
414
426
  //#endregion
415
- export { w as AnalyticsPage };
427
+ export { E as AnalyticsPage };
416
428
 
417
429
  //# sourceMappingURL=AnalyticsPage.js.map