@burdenoff/microfe-proserviceworld 2026.1026.2 → 2026.1031.1

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