@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.
- package/dist/generated/global-types.d.ts +9699 -583
- package/dist/generated/global-types.d.ts.map +1 -1
- package/dist/generated/wspace-types.d.ts +18076 -2999
- package/dist/generated/wspace-types.d.ts.map +1 -1
- package/dist/proserviceworld/__tests__/schemaStub.d.ts +20 -0
- package/dist/proserviceworld/__tests__/schemaStub.d.ts.map +1 -0
- 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.map +1 -1
- 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 +209 -197
- 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 +257 -256
- 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,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 {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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__ */ S
|
|
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
|
})
|
|
125
129
|
}),
|
|
126
|
-
/* @__PURE__ */
|
|
130
|
+
/* @__PURE__ */ T("div", {
|
|
127
131
|
className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
|
|
128
|
-
children: [/* @__PURE__ */
|
|
129
|
-
label: "Realization",
|
|
130
|
-
value: `${Math.round(
|
|
131
|
-
hint:
|
|
132
|
-
|
|
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__ */
|
|
135
|
-
label: "Write-offs",
|
|
136
|
-
value:
|
|
137
|
-
hint: "Total written off",
|
|
138
|
-
icon: /* @__PURE__ */
|
|
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__ */
|
|
143
|
-
title: "Aged receivables",
|
|
144
|
-
description: "Outstanding invoice value by age — the margin-leak early warning.",
|
|
145
|
-
children: /* @__PURE__ */
|
|
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__ */
|
|
149
|
-
label: "Current",
|
|
150
|
-
bucket:
|
|
155
|
+
/* @__PURE__ */ w(D, {
|
|
156
|
+
label: n("psw.analytics.agingCurrent", "Current"),
|
|
157
|
+
bucket: r.agedReceivables.current,
|
|
151
158
|
tone: "success"
|
|
152
159
|
}),
|
|
153
|
-
/* @__PURE__ */
|
|
154
|
-
label: "30 days",
|
|
155
|
-
bucket:
|
|
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__ */
|
|
159
|
-
label: "60 days",
|
|
160
|
-
bucket:
|
|
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__ */
|
|
164
|
-
label: "90+ days",
|
|
165
|
-
bucket:
|
|
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__ */
|
|
172
|
-
title: "Write-offs",
|
|
173
|
-
description: "Append-only audit of written-off amounts.",
|
|
174
|
-
children:
|
|
175
|
-
/* @__PURE__ */
|
|
176
|
-
/* @__PURE__ */
|
|
177
|
-
/* @__PURE__ */
|
|
178
|
-
className: "text-
|
|
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__ */
|
|
182
|
-
/* @__PURE__ */
|
|
183
|
-
/* @__PURE__ */
|
|
184
|
-
/* @__PURE__ */
|
|
185
|
-
className: "text-
|
|
186
|
-
children:
|
|
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__ */
|
|
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
|
-
},
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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__ */
|
|
212
|
+
children: [/* @__PURE__ */ w(k, {
|
|
203
213
|
pct: e,
|
|
204
214
|
tone: t
|
|
205
|
-
}), /* @__PURE__ */
|
|
215
|
+
}), /* @__PURE__ */ T("div", {
|
|
206
216
|
className: "flex flex-1 flex-col gap-2.5",
|
|
207
217
|
children: [
|
|
208
|
-
/* @__PURE__ */
|
|
218
|
+
/* @__PURE__ */ T("div", {
|
|
209
219
|
className: "flex items-baseline justify-between gap-3",
|
|
210
|
-
children: [/* @__PURE__ */
|
|
220
|
+
children: [/* @__PURE__ */ w("span", {
|
|
211
221
|
className: "text-xs font-medium uppercase tracking-wider text-text-tertiary",
|
|
212
222
|
children: r
|
|
213
|
-
}), /* @__PURE__ */
|
|
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__ */
|
|
219
|
-
/* @__PURE__ */
|
|
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__ */
|
|
231
|
+
children: [/* @__PURE__ */ w("span", {
|
|
222
232
|
className: "text-xs font-medium uppercase tracking-wider text-text-tertiary",
|
|
223
233
|
children: a
|
|
224
|
-
}), /* @__PURE__ */
|
|
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
|
-
}),
|
|
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__ */
|
|
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__ */
|
|
245
|
+
children: [/* @__PURE__ */ T("svg", {
|
|
236
246
|
viewBox: "0 0 80 80",
|
|
237
247
|
className: "h-full w-full -rotate-90",
|
|
238
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
267
|
+
}), /* @__PURE__ */ w("div", {
|
|
258
268
|
className: "absolute inset-0 flex items-center justify-center",
|
|
259
|
-
children: /* @__PURE__ */
|
|
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
|
-
},
|
|
266
|
-
|
|
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
|
|
271
|
-
return /* @__PURE__ */
|
|
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__ */
|
|
284
|
+
children: /* @__PURE__ */ T("div", {
|
|
274
285
|
className: "min-w-[520px]",
|
|
275
|
-
children: [/* @__PURE__ */
|
|
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__ */
|
|
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__ */
|
|
290
|
+
children: [/* @__PURE__ */ w("span", {
|
|
280
291
|
className: "whitespace-nowrap text-[10px] font-semibold tabular-nums text-text-secondary",
|
|
281
|
-
children:
|
|
282
|
-
}), /* @__PURE__ */
|
|
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 /
|
|
285
|
-
title:
|
|
295
|
+
style: { height: `${Math.max(e.amount / n * 90, 2)}%` },
|
|
296
|
+
title: _(e.amount)
|
|
286
297
|
})]
|
|
287
298
|
}, e.month))
|
|
288
|
-
}), /* @__PURE__ */
|
|
299
|
+
}), /* @__PURE__ */ w("div", {
|
|
289
300
|
className: "mt-2 flex gap-2",
|
|
290
|
-
children: e.map((e) => /* @__PURE__ */
|
|
301
|
+
children: e.map((e) => /* @__PURE__ */ w("span", {
|
|
291
302
|
className: "flex-1 text-center text-xs text-text-tertiary",
|
|
292
|
-
children:
|
|
303
|
+
children: I(e.month)
|
|
293
304
|
}, e.month))
|
|
294
305
|
})]
|
|
295
306
|
})
|
|
296
307
|
});
|
|
297
|
-
},
|
|
298
|
-
|
|
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
|
|
303
|
-
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", {
|
|
304
316
|
className: "space-y-3.5",
|
|
305
|
-
children: e.map((e) => /* @__PURE__ */
|
|
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__ */
|
|
320
|
+
/* @__PURE__ */ w(d, {
|
|
309
321
|
status: e.status,
|
|
310
322
|
className: "justify-self-start"
|
|
311
323
|
}),
|
|
312
|
-
/* @__PURE__ */
|
|
324
|
+
/* @__PURE__ */ w("div", {
|
|
313
325
|
className: "h-2.5 overflow-hidden rounded-full bg-bg-sunken",
|
|
314
|
-
children: /* @__PURE__ */
|
|
315
|
-
className: n("h-full rounded-full bg-gradient-to-r transition-all duration-500",
|
|
316
|
-
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)}%` }
|
|
317
329
|
})
|
|
318
330
|
}),
|
|
319
|
-
/* @__PURE__ */
|
|
331
|
+
/* @__PURE__ */ T("span", {
|
|
320
332
|
className: "flex items-baseline justify-end gap-1.5 tabular-nums",
|
|
321
|
-
children: [/* @__PURE__ */
|
|
333
|
+
children: [/* @__PURE__ */ w("span", {
|
|
322
334
|
className: "text-sm font-semibold text-text-primary",
|
|
323
335
|
children: e.count
|
|
324
|
-
}), /* @__PURE__ */
|
|
336
|
+
}), /* @__PURE__ */ T("span", {
|
|
325
337
|
className: "text-xs text-text-tertiary",
|
|
326
|
-
children: [Math.round(e.count /
|
|
338
|
+
children: [Math.round(e.count / a * 100), "%"]
|
|
327
339
|
})]
|
|
328
340
|
})
|
|
329
341
|
]
|
|
330
342
|
}, e.status))
|
|
331
343
|
});
|
|
332
|
-
},
|
|
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__ */
|
|
346
|
+
return /* @__PURE__ */ T("div", {
|
|
335
347
|
className: "rounded-xl border border-border-seam bg-bg-canvas p-4",
|
|
336
|
-
children: [/* @__PURE__ */
|
|
348
|
+
children: [/* @__PURE__ */ T("div", {
|
|
337
349
|
className: "mb-2.5 flex items-center justify-between gap-3",
|
|
338
|
-
children: [/* @__PURE__ */
|
|
350
|
+
children: [/* @__PURE__ */ w("span", {
|
|
339
351
|
className: "text-sm font-medium text-text-secondary",
|
|
340
352
|
children: e
|
|
341
|
-
}), /* @__PURE__ */
|
|
353
|
+
}), /* @__PURE__ */ T("span", {
|
|
342
354
|
className: "text-sm font-semibold tabular-nums text-text-primary",
|
|
343
355
|
children: [
|
|
344
|
-
|
|
356
|
+
g(t),
|
|
345
357
|
" · ",
|
|
346
358
|
a,
|
|
347
359
|
"%"
|
|
348
360
|
]
|
|
349
361
|
})]
|
|
350
|
-
}), /* @__PURE__ */
|
|
362
|
+
}), /* @__PURE__ */ w("div", {
|
|
351
363
|
className: "h-3 overflow-hidden rounded-full bg-bg-sunken",
|
|
352
|
-
children: /* @__PURE__ */
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
|
406
|
-
return
|
|
417
|
+
function F(e) {
|
|
418
|
+
return N[P[e] ?? "accent"];
|
|
407
419
|
}
|
|
408
|
-
function
|
|
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 {
|
|
427
|
+
export { E as AnalyticsPage };
|
|
416
428
|
|
|
417
429
|
//# sourceMappingURL=AnalyticsPage.js.map
|