@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.
- package/dist/proserviceworld/components/CredentialDirectory.js +44 -43
- package/dist/proserviceworld/components/CredentialDirectory.js.map +1 -1
- package/dist/proserviceworld/components/CredentialReminderPanel.js +5 -4
- package/dist/proserviceworld/components/CredentialReminderPanel.js.map +1 -1
- package/dist/proserviceworld/components/ui.d.ts +7 -3
- package/dist/proserviceworld/components/ui.d.ts.map +1 -1
- package/dist/proserviceworld/components/ui.js +135 -121
- package/dist/proserviceworld/components/ui.js.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +28 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -1
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js +95 -73
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -1
- package/dist/proserviceworld/hooks/useTr.d.ts +49 -8
- package/dist/proserviceworld/hooks/useTr.d.ts.map +1 -1
- package/dist/proserviceworld/hooks/useTr.js +45 -21
- package/dist/proserviceworld/hooks/useTr.js.map +1 -1
- package/dist/proserviceworld/i18n/catalog/analytics.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/analytics.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/analytics.js +271 -0
- package/dist/proserviceworld/i18n/catalog/analytics.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/common.d.ts +9 -0
- package/dist/proserviceworld/i18n/catalog/common.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/common.js +163 -0
- package/dist/proserviceworld/i18n/catalog/common.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/compliance.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/compliance.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/compliance.js +157 -0
- package/dist/proserviceworld/i18n/catalog/compliance.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.js +145 -0
- package/dist/proserviceworld/i18n/catalog/conflicts.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/documents.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/documents.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/documents.js +157 -0
- package/dist/proserviceworld/i18n/catalog/documents.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/enums.d.ts +10 -0
- package/dist/proserviceworld/i18n/catalog/enums.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/enums.js +481 -0
- package/dist/proserviceworld/i18n/catalog/enums.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/index.d.ts +9 -0
- package/dist/proserviceworld/i18n/catalog/index.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/index.js +25 -0
- package/dist/proserviceworld/i18n/catalog/index.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/invoices.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/invoices.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/invoices.js +247 -0
- package/dist/proserviceworld/i18n/catalog/invoices.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.js +97 -0
- package/dist/proserviceworld/i18n/catalog/practiceAreas.js.map +1 -0
- package/dist/proserviceworld/i18n/catalog/time.d.ts +5 -0
- package/dist/proserviceworld/i18n/catalog/time.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/catalog/time.js +301 -0
- package/dist/proserviceworld/i18n/catalog/time.js.map +1 -0
- package/dist/proserviceworld/i18n/index.d.ts +10 -9
- package/dist/proserviceworld/i18n/index.d.ts.map +1 -1
- package/dist/proserviceworld/i18n/index.js +16 -12
- package/dist/proserviceworld/i18n/index.js.map +1 -1
- package/dist/proserviceworld/i18n/types.d.ts +13 -0
- package/dist/proserviceworld/i18n/types.d.ts.map +1 -0
- package/dist/proserviceworld/i18n/types.js +18 -0
- package/dist/proserviceworld/i18n/types.js.map +1 -0
- package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/AnalyticsPage.js +236 -152
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientDetailPage.js +99 -98
- package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/ClientsPage.js +181 -181
- package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/CompliancePage.js +210 -209
- package/dist/proserviceworld/pages/CompliancePage.js.map +1 -1
- package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/ConflictsPage.js +139 -138
- package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.js +150 -149
- package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementDetailPage.js +105 -104
- package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/EngagementsPage.js +137 -137
- package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/InvoicesPage.js +275 -258
- package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -1
- package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/MattersPage.js +166 -166
- package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/PracticeAreasPage.js +100 -99
- package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -1
- package/dist/proserviceworld/pages/PractitionerCredentialsPage.js +30 -29
- package/dist/proserviceworld/pages/PractitionerCredentialsPage.js.map +1 -1
- package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -1
- package/dist/proserviceworld/pages/TimePage.js +343 -350
- package/dist/proserviceworld/pages/TimePage.js.map +1 -1
- package/dist/proserviceworld/utils/humanize.d.ts +3 -0
- package/dist/proserviceworld/utils/humanize.d.ts.map +1 -0
- package/dist/proserviceworld/utils/humanize.js +6 -0
- package/dist/proserviceworld/utils/humanize.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,169 +1,251 @@
|
|
|
1
|
-
import { useDashboardStats as e } from "../hooks/useProServiceWorldApi.js";
|
|
2
|
-
import { cn as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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
|
|
8
|
-
let { data:
|
|
9
|
-
if (
|
|
10
|
-
if (
|
|
11
|
-
error:
|
|
12
|
-
onRetry: () => void
|
|
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 (!
|
|
15
|
-
let
|
|
16
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
20
|
-
title: "Analytics",
|
|
21
|
-
subtitle: "Real, live metrics across the practice — no estimates, straight from your records.",
|
|
22
|
-
icon: /* @__PURE__ */
|
|
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__ */
|
|
25
|
+
/* @__PURE__ */ T("div", {
|
|
25
26
|
className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
|
|
26
27
|
children: [
|
|
27
|
-
/* @__PURE__ */
|
|
28
|
-
label: "Collected revenue",
|
|
29
|
-
value:
|
|
30
|
-
hint:
|
|
31
|
-
icon: /* @__PURE__ */
|
|
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__ */
|
|
35
|
-
label: "Collection rate",
|
|
36
|
-
value: `${
|
|
37
|
-
hint:
|
|
38
|
-
icon: /* @__PURE__ */
|
|
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__ */
|
|
42
|
-
label: "Utilization",
|
|
43
|
-
value: `${
|
|
44
|
-
hint:
|
|
45
|
-
|
|
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__ */
|
|
49
|
-
label: "Active engagements",
|
|
50
|
-
value:
|
|
51
|
-
hint:
|
|
52
|
-
icon: /* @__PURE__ */
|
|
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__ */
|
|
61
|
+
/* @__PURE__ */ T("div", {
|
|
58
62
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
59
|
-
children: [/* @__PURE__ */
|
|
60
|
-
title: "Collection rate",
|
|
61
|
-
description: "Paid vs. total invoiced.",
|
|
62
|
-
children: /* @__PURE__ */
|
|
63
|
-
pct:
|
|
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:
|
|
66
|
-
primaryLabel: "Collected",
|
|
67
|
-
secondary:
|
|
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__ */
|
|
71
|
-
title: "Utilization",
|
|
72
|
-
description: "Billed vs. total logged hours.",
|
|
73
|
-
children: /* @__PURE__ */
|
|
74
|
-
pct:
|
|
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:
|
|
77
|
-
primaryLabel: "Billed",
|
|
78
|
-
secondary:
|
|
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__ */
|
|
84
|
-
title: "Revenue by month",
|
|
85
|
-
description: "Invoiced totals across recent months.",
|
|
86
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
92
|
+
/* @__PURE__ */ T("div", {
|
|
89
93
|
className: "grid grid-cols-1 gap-4 lg:grid-cols-3",
|
|
90
94
|
children: [
|
|
91
|
-
/* @__PURE__ */
|
|
92
|
-
title: "Engagements",
|
|
93
|
-
description: "By status",
|
|
94
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
97
|
-
title: "Matters",
|
|
98
|
-
description: "By status",
|
|
99
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
102
|
-
title: "Invoices",
|
|
103
|
-
description: "By status",
|
|
104
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
109
|
-
title: "Time & billing",
|
|
110
|
-
description: "Billable capacity across the practice.",
|
|
111
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
114
|
-
label: "Billed hours",
|
|
115
|
-
value:
|
|
116
|
-
total:
|
|
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__ */
|
|
119
|
-
label: "Unbilled hours",
|
|
120
|
-
value:
|
|
121
|
-
total:
|
|
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
|
-
},
|
|
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__ */
|
|
212
|
+
children: [/* @__PURE__ */ w(k, {
|
|
131
213
|
pct: e,
|
|
132
214
|
tone: t
|
|
133
|
-
}), /* @__PURE__ */
|
|
215
|
+
}), /* @__PURE__ */ T("div", {
|
|
134
216
|
className: "flex flex-1 flex-col gap-2.5",
|
|
135
217
|
children: [
|
|
136
|
-
/* @__PURE__ */
|
|
218
|
+
/* @__PURE__ */ T("div", {
|
|
137
219
|
className: "flex items-baseline justify-between gap-3",
|
|
138
|
-
children: [/* @__PURE__ */
|
|
220
|
+
children: [/* @__PURE__ */ w("span", {
|
|
139
221
|
className: "text-xs font-medium uppercase tracking-wider text-text-tertiary",
|
|
140
222
|
children: r
|
|
141
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
147
|
-
/* @__PURE__ */
|
|
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__ */
|
|
231
|
+
children: [/* @__PURE__ */ w("span", {
|
|
150
232
|
className: "text-xs font-medium uppercase tracking-wider text-text-tertiary",
|
|
151
233
|
children: a
|
|
152
|
-
}), /* @__PURE__ */
|
|
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
|
-
}),
|
|
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__ */
|
|
162
|
-
className:
|
|
163
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
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__ */
|
|
267
|
+
}), /* @__PURE__ */ w("div", {
|
|
186
268
|
className: "absolute inset-0 flex items-center justify-center",
|
|
187
|
-
children: /* @__PURE__ */
|
|
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
|
-
},
|
|
194
|
-
|
|
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
|
|
199
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
284
|
+
children: /* @__PURE__ */ T("div", {
|
|
202
285
|
className: "min-w-[520px]",
|
|
203
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
290
|
+
children: [/* @__PURE__ */ w("span", {
|
|
208
291
|
className: "whitespace-nowrap text-[10px] font-semibold tabular-nums text-text-secondary",
|
|
209
|
-
children:
|
|
210
|
-
}), /* @__PURE__ */
|
|
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 /
|
|
213
|
-
title:
|
|
295
|
+
style: { height: `${Math.max(e.amount / n * 90, 2)}%` },
|
|
296
|
+
title: _(e.amount)
|
|
214
297
|
})]
|
|
215
298
|
}, e.month))
|
|
216
|
-
}), /* @__PURE__ */
|
|
299
|
+
}), /* @__PURE__ */ w("div", {
|
|
217
300
|
className: "mt-2 flex gap-2",
|
|
218
|
-
children: e.map((e) => /* @__PURE__ */
|
|
301
|
+
children: e.map((e) => /* @__PURE__ */ w("span", {
|
|
219
302
|
className: "flex-1 text-center text-xs text-text-tertiary",
|
|
220
|
-
children:
|
|
303
|
+
children: I(e.month)
|
|
221
304
|
}, e.month))
|
|
222
305
|
})]
|
|
223
306
|
})
|
|
224
307
|
});
|
|
225
|
-
},
|
|
226
|
-
|
|
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
|
|
231
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
320
|
+
/* @__PURE__ */ w(d, {
|
|
237
321
|
status: e.status,
|
|
238
322
|
className: "justify-self-start"
|
|
239
323
|
}),
|
|
240
|
-
/* @__PURE__ */
|
|
324
|
+
/* @__PURE__ */ w("div", {
|
|
241
325
|
className: "h-2.5 overflow-hidden rounded-full bg-bg-sunken",
|
|
242
|
-
children: /* @__PURE__ */
|
|
243
|
-
className:
|
|
244
|
-
style: { width: `${Math.max(e.count /
|
|
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__ */
|
|
331
|
+
/* @__PURE__ */ T("span", {
|
|
248
332
|
className: "flex items-baseline justify-end gap-1.5 tabular-nums",
|
|
249
|
-
children: [/* @__PURE__ */
|
|
333
|
+
children: [/* @__PURE__ */ w("span", {
|
|
250
334
|
className: "text-sm font-semibold text-text-primary",
|
|
251
335
|
children: e.count
|
|
252
|
-
}), /* @__PURE__ */
|
|
336
|
+
}), /* @__PURE__ */ T("span", {
|
|
253
337
|
className: "text-xs text-text-tertiary",
|
|
254
|
-
children: [Math.round(e.count /
|
|
338
|
+
children: [Math.round(e.count / a * 100), "%"]
|
|
255
339
|
})]
|
|
256
340
|
})
|
|
257
341
|
]
|
|
258
342
|
}, e.status))
|
|
259
343
|
});
|
|
260
|
-
},
|
|
261
|
-
let a = r > 0 ? Math.round(
|
|
262
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
348
|
+
children: [/* @__PURE__ */ T("div", {
|
|
265
349
|
className: "mb-2.5 flex items-center justify-between gap-3",
|
|
266
|
-
children: [/* @__PURE__ */
|
|
350
|
+
children: [/* @__PURE__ */ w("span", {
|
|
267
351
|
className: "text-sm font-medium text-text-secondary",
|
|
268
352
|
children: e
|
|
269
|
-
}), /* @__PURE__ */
|
|
353
|
+
}), /* @__PURE__ */ T("span", {
|
|
270
354
|
className: "text-sm font-semibold tabular-nums text-text-primary",
|
|
271
355
|
children: [
|
|
272
|
-
|
|
356
|
+
g(t),
|
|
273
357
|
" · ",
|
|
274
358
|
a,
|
|
275
359
|
"%"
|
|
276
360
|
]
|
|
277
361
|
})]
|
|
278
|
-
}), /* @__PURE__ */
|
|
362
|
+
}), /* @__PURE__ */ w("div", {
|
|
279
363
|
className: "h-3 overflow-hidden rounded-full bg-bg-sunken",
|
|
280
|
-
children: /* @__PURE__ */
|
|
281
|
-
className:
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
|
334
|
-
return
|
|
417
|
+
function F(e) {
|
|
418
|
+
return N[P[e] ?? "accent"];
|
|
335
419
|
}
|
|
336
|
-
function
|
|
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 {
|
|
427
|
+
export { E as AnalyticsPage };
|
|
344
428
|
|
|
345
429
|
//# sourceMappingURL=AnalyticsPage.js.map
|