@burdenoff/microfe-proserviceworld 2026.626.2 → 2026.706.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/index.js +2 -3
- package/dist/node_modules/clsx/dist/clsx.js +18 -0
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/dist/proserviceworld/ProServiceWorldRoot.js +92 -136
- package/dist/proserviceworld/ProServiceWorldRoot.js.map +1 -1
- package/dist/proserviceworld/ProServiceWorldRoutes.js +18 -26
- package/dist/proserviceworld/ProServiceWorldRoutes.js.map +1 -1
- package/dist/proserviceworld/components/ui.js +273 -0
- package/dist/proserviceworld/components/ui.js.map +1 -0
- package/dist/proserviceworld/hooks/useFiles.js +45 -0
- package/dist/proserviceworld/hooks/useFiles.js.map +1 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js +416 -0
- package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -0
- package/dist/proserviceworld/index.js +0 -1
- package/dist/proserviceworld/pages/AnalyticsPage.js +163 -475
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ClientDetailPage.js +238 -0
- package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -0
- package/dist/proserviceworld/pages/ClientsPage.js +295 -0
- package/dist/proserviceworld/pages/ClientsPage.js.map +1 -0
- package/dist/proserviceworld/pages/CompliancePage.js +307 -0
- package/dist/proserviceworld/pages/CompliancePage.js.map +1 -0
- package/dist/proserviceworld/pages/ConflictsPage.js +234 -0
- package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -0
- package/dist/proserviceworld/pages/DashboardPage.js +179 -632
- package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.js +235 -539
- package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/EngagementDetailPage.js +444 -0
- package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -0
- package/dist/proserviceworld/pages/EngagementsPage.js +256 -0
- package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -0
- package/dist/proserviceworld/pages/InvoicesPage.js +303 -0
- package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -0
- package/dist/proserviceworld/pages/MattersPage.js +275 -0
- package/dist/proserviceworld/pages/MattersPage.js.map +1 -0
- package/dist/proserviceworld/pages/PracticeAreasPage.js +176 -0
- package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -0
- package/dist/proserviceworld/pages/TimePage.js +310 -0
- package/dist/proserviceworld/pages/TimePage.js.map +1 -0
- package/dist/proserviceworld/utils/cn.js +10 -0
- package/dist/proserviceworld/utils/cn.js.map +1 -0
- package/dist/proserviceworld/utils/nav.js +11 -0
- package/dist/proserviceworld/utils/nav.js.map +1 -0
- package/package.json +3 -2
- package/dist/proserviceworld/pages/AdminReportsPage.js +0 -579
- package/dist/proserviceworld/pages/AdminReportsPage.js.map +0 -1
- package/dist/proserviceworld/pages/AdminUsersPage.js +0 -468
- package/dist/proserviceworld/pages/AdminUsersPage.js.map +0 -1
- package/dist/proserviceworld/pages/BookingsPage.js +0 -446
- package/dist/proserviceworld/pages/BookingsPage.js.map +0 -1
- package/dist/proserviceworld/pages/MessagesPage.js +0 -238
- package/dist/proserviceworld/pages/MessagesPage.js.map +0 -1
- package/dist/proserviceworld/pages/PaymentsPage.js +0 -537
- package/dist/proserviceworld/pages/PaymentsPage.js.map +0 -1
- package/dist/proserviceworld/pages/ProjectsPage.js +0 -627
- package/dist/proserviceworld/pages/ProjectsPage.js.map +0 -1
- package/dist/proserviceworld/pages/ProviderDetailPage.js +0 -538
- package/dist/proserviceworld/pages/ProviderDetailPage.js.map +0 -1
- package/dist/proserviceworld/pages/ProvidersPage.js +0 -347
- package/dist/proserviceworld/pages/ProvidersPage.js.map +0 -1
- package/dist/proserviceworld/pages/ReviewsPage.js +0 -356
- package/dist/proserviceworld/pages/ReviewsPage.js.map +0 -1
- package/dist/proserviceworld/pages/ServiceDetailsPage.js +0 -631
- package/dist/proserviceworld/pages/ServiceDetailsPage.js.map +0 -1
- package/dist/proserviceworld/pages/ServicesPage.js +0 -344
- package/dist/proserviceworld/pages/ServicesPage.js.map +0 -1
- package/dist/proserviceworld/pages/VerificationPage.js +0 -370
- package/dist/proserviceworld/pages/VerificationPage.js.map +0 -1
- package/dist/proserviceworld/store/proserviceworldStore.js +0 -2490
- package/dist/proserviceworld/store/proserviceworldStore.js.map +0 -1
- package/dist/proserviceworld/utils/i18n.js +0 -15
- package/dist/proserviceworld/utils/i18n.js.map +0 -1
|
@@ -1,491 +1,179 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { jsx as
|
|
5
|
-
import { AuroraBackground as g, Badge as _, Button as v, Card as y, CardContent as b, CardHeader as x, CardTitle as S, EmphasisPanel as C, GlassCard as w, GradientText as T, NextSteps as E, PagePurpose as D } from "@burdenoff/fe-libs/ui";
|
|
1
|
+
import { useDashboardStats as e } from "../hooks/useProServiceWorldApi.js";
|
|
2
|
+
import { ErrorState as t, LoadingBlock as n, MetricCard as r, PageHeader as i, SectionCard as a, StatusPill as o, fmtHours as s, fmtMoney as c } from "../components/ui.js";
|
|
3
|
+
import { BarChart3 as l, Clock as u, TrendingUp as d, Wallet as f } from "lucide-react";
|
|
4
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
6
5
|
//#region src/proserviceworld/pages/AnalyticsPage.tsx
|
|
7
|
-
|
|
8
|
-
let {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
key: "clients",
|
|
21
|
-
label: "Clients",
|
|
22
|
-
icon: p
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
key: "services",
|
|
26
|
-
label: "Services",
|
|
27
|
-
icon: n
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
key: "performance",
|
|
31
|
-
label: "Performance",
|
|
32
|
-
icon: f
|
|
33
|
-
}
|
|
34
|
-
], R = (e) => e === "positive" ? /* @__PURE__ */ m(f, { className: "h-4 w-4 text-status-success-text" }) : e === "negative" ? /* @__PURE__ */ m(d, { className: "h-4 w-4 text-status-error-text" }) : /* @__PURE__ */ m(u, { className: "h-4 w-4 text-text-muted" }), z = Math.max(...k.map((e) => e.value)), B = Math.max(...A.map((e) => e.value)), V = Math.max(...j.map((e) => e.value));
|
|
35
|
-
return /* @__PURE__ */ h("div", {
|
|
36
|
-
className: "space-y-6 p-6 bg-bg-canvas min-h-screen",
|
|
6
|
+
var h = () => {
|
|
7
|
+
let { data: o, isLoading: h, error: y, refetch: b } = e();
|
|
8
|
+
if (h) return /* @__PURE__ */ p(n, { label: "Crunching numbers…" });
|
|
9
|
+
if (y) return /* @__PURE__ */ p(t, {
|
|
10
|
+
error: y,
|
|
11
|
+
onRetry: () => void b()
|
|
12
|
+
});
|
|
13
|
+
if (!o) return null;
|
|
14
|
+
let x = o.unbilledHours + o.billedHours, S = x > 0 ? Math.round(o.billedHours / x * 100) : 0, C = o.paidInvoiceTotal + o.outstandingInvoiceTotal > 0 ? Math.round(o.paidInvoiceTotal / (o.paidInvoiceTotal + o.outstandingInvoiceTotal) * 100) : 0;
|
|
15
|
+
return /* @__PURE__ */ m("div", {
|
|
16
|
+
className: "space-y-6",
|
|
37
17
|
children: [
|
|
38
|
-
/* @__PURE__ */
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h1", {
|
|
43
|
-
className: "text-2xl font-semibold tracking-tight",
|
|
44
|
-
children: /* @__PURE__ */ m(T, { children: "Analytics" })
|
|
45
|
-
}), /* @__PURE__ */ m("p", {
|
|
46
|
-
className: "text-sm text-text-secondary",
|
|
47
|
-
children: "Insights and performance metrics for your professional services."
|
|
48
|
-
})] }), /* @__PURE__ */ h("div", {
|
|
49
|
-
className: "flex items-center gap-2",
|
|
50
|
-
children: [/* @__PURE__ */ m("div", {
|
|
51
|
-
className: "flex rounded border border-border-seam overflow-hidden",
|
|
52
|
-
children: [
|
|
53
|
-
"1m",
|
|
54
|
-
"3m",
|
|
55
|
-
"6m",
|
|
56
|
-
"1y"
|
|
57
|
-
].map((e) => /* @__PURE__ */ m("button", {
|
|
58
|
-
onClick: () => I(e),
|
|
59
|
-
"aria-pressed": F === e,
|
|
60
|
-
className: `px-3 py-1 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${F === e ? "bg-action-primary-bg text-action-primary-text" : "text-text-secondary hover:bg-bg-sunken/50"}`,
|
|
61
|
-
children: e.toUpperCase()
|
|
62
|
-
}, e))
|
|
63
|
-
}), /* @__PURE__ */ h(v, {
|
|
64
|
-
variant: "outline",
|
|
65
|
-
size: "sm",
|
|
66
|
-
children: [/* @__PURE__ */ m(c, { className: "mr-2 h-4 w-4" }), " Export"]
|
|
67
|
-
})]
|
|
68
|
-
})]
|
|
69
|
-
})]
|
|
70
|
-
}),
|
|
71
|
-
/* @__PURE__ */ m(D, {
|
|
72
|
-
icon: /* @__PURE__ */ m(a, { className: "h-4 w-4" }),
|
|
73
|
-
children: "Understand how your professional services are performing. Track revenue and client growth over time, see which services and regions drive the most demand, and export the numbers — so you can double down on what works and plan where to grow next."
|
|
18
|
+
/* @__PURE__ */ p(i, {
|
|
19
|
+
title: "Analytics",
|
|
20
|
+
subtitle: "Real, live metrics across the practice — no estimates, straight from your records.",
|
|
21
|
+
icon: /* @__PURE__ */ p(l, { className: "h-6 w-6" })
|
|
74
22
|
}),
|
|
75
|
-
/* @__PURE__ */ m(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
23
|
+
/* @__PURE__ */ m("div", {
|
|
24
|
+
className: "grid grid-cols-2 gap-3 lg:grid-cols-4",
|
|
25
|
+
children: [
|
|
26
|
+
/* @__PURE__ */ p(r, {
|
|
27
|
+
label: "Collected revenue",
|
|
28
|
+
value: c(o.paidInvoiceTotal),
|
|
29
|
+
icon: /* @__PURE__ */ p(f, { className: "h-4 w-4" }),
|
|
30
|
+
tone: "success"
|
|
31
|
+
}),
|
|
32
|
+
/* @__PURE__ */ p(r, {
|
|
33
|
+
label: "Collection rate",
|
|
34
|
+
value: `${C}%`,
|
|
35
|
+
hint: `${c(o.outstandingInvoiceTotal)} outstanding`,
|
|
36
|
+
icon: /* @__PURE__ */ p(d, { className: "h-4 w-4" }),
|
|
37
|
+
tone: "accent"
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ p(r, {
|
|
40
|
+
label: "Utilization",
|
|
41
|
+
value: `${S}%`,
|
|
42
|
+
hint: `${s(o.billedHours)} of ${s(x)}`,
|
|
43
|
+
icon: /* @__PURE__ */ p(u, { className: "h-4 w-4" }),
|
|
44
|
+
tone: "info"
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ p(r, {
|
|
47
|
+
label: "Active engagements",
|
|
48
|
+
value: o.activeEngagements,
|
|
49
|
+
icon: /* @__PURE__ */ p(l, { className: "h-4 w-4" })
|
|
50
|
+
})
|
|
99
51
|
]
|
|
100
52
|
}),
|
|
101
|
-
/* @__PURE__ */
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
"aria-pressed": N === e,
|
|
106
|
-
className: `flex items-center gap-2 border-b-2 px-4 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${N === e ? "border-action-primary-bg text-text-primary" : "border-transparent text-text-secondary hover:text-text-primary"}`,
|
|
107
|
-
children: [/* @__PURE__ */ m(n, { className: "h-4 w-4" }), t]
|
|
108
|
-
}, e))
|
|
53
|
+
/* @__PURE__ */ p(a, {
|
|
54
|
+
title: "Revenue by month",
|
|
55
|
+
description: "Invoiced totals across recent months.",
|
|
56
|
+
children: /* @__PURE__ */ p(g, { data: o.revenueByMonth })
|
|
109
57
|
}),
|
|
110
58
|
/* @__PURE__ */ m("div", {
|
|
111
|
-
className: "grid
|
|
112
|
-
children:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
children: e.value
|
|
127
|
-
}),
|
|
128
|
-
/* @__PURE__ */ h("p", {
|
|
129
|
-
className: `mt-0.5 text-xs ${e.changeType === "positive" ? "text-status-success-text" : e.changeType === "negative" ? "text-status-error-text" : "text-text-muted"}`,
|
|
130
|
-
children: [e.change, " from last period"]
|
|
131
|
-
})
|
|
132
|
-
]
|
|
133
|
-
}, t))
|
|
59
|
+
className: "grid grid-cols-1 gap-4 lg:grid-cols-3",
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ p(a, {
|
|
62
|
+
title: "Engagements",
|
|
63
|
+
children: /* @__PURE__ */ p(_, { items: o.engagementsByStatus })
|
|
64
|
+
}),
|
|
65
|
+
/* @__PURE__ */ p(a, {
|
|
66
|
+
title: "Matters",
|
|
67
|
+
children: /* @__PURE__ */ p(_, { items: o.mattersByStatus })
|
|
68
|
+
}),
|
|
69
|
+
/* @__PURE__ */ p(a, {
|
|
70
|
+
title: "Invoices",
|
|
71
|
+
children: /* @__PURE__ */ p(_, { items: o.invoicesByStatus })
|
|
72
|
+
})
|
|
73
|
+
]
|
|
134
74
|
}),
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
children:
|
|
138
|
-
className: "
|
|
139
|
-
children: [/* @__PURE__ */
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
className: "flex items-center gap-3",
|
|
150
|
-
children: [
|
|
151
|
-
/* @__PURE__ */ m("span", {
|
|
152
|
-
className: "w-10 text-xs text-text-secondary",
|
|
153
|
-
children: e.name
|
|
154
|
-
}),
|
|
155
|
-
/* @__PURE__ */ h("div", {
|
|
156
|
-
className: "relative flex-1 h-6 bg-bg-sunken rounded overflow-hidden",
|
|
157
|
-
children: [e.prev !== void 0 && /* @__PURE__ */ m("div", {
|
|
158
|
-
className: "absolute h-6 bg-text-muted/15 rounded",
|
|
159
|
-
style: { width: `${e.prev / z * 100}%` }
|
|
160
|
-
}), /* @__PURE__ */ m("div", {
|
|
161
|
-
className: "relative h-6 bg-action-primary-bg rounded shadow-[var(--shadow-glow)]",
|
|
162
|
-
style: { width: `${e.value / z * 100}%` }
|
|
163
|
-
})]
|
|
164
|
-
}),
|
|
165
|
-
/* @__PURE__ */ h("span", {
|
|
166
|
-
className: "w-20 text-right text-xs font-medium tabular-nums",
|
|
167
|
-
children: [
|
|
168
|
-
"$",
|
|
169
|
-
(e.value / 1e3).toFixed(1),
|
|
170
|
-
"k"
|
|
171
|
-
]
|
|
172
|
-
})
|
|
173
|
-
]
|
|
174
|
-
}, e.name))
|
|
175
|
-
})] }), /* @__PURE__ */ h(y, {
|
|
176
|
-
className: "border-border-seam",
|
|
177
|
-
children: [/* @__PURE__ */ m(x, { children: /* @__PURE__ */ h("div", {
|
|
178
|
-
className: "flex items-center justify-between",
|
|
179
|
-
children: [/* @__PURE__ */ m(S, {
|
|
180
|
-
className: "text-base",
|
|
181
|
-
children: "Client Growth"
|
|
182
|
-
}), /* @__PURE__ */ m(_, {
|
|
183
|
-
variant: "secondary",
|
|
184
|
-
children: "Monthly"
|
|
185
|
-
})]
|
|
186
|
-
}) }), /* @__PURE__ */ m(b, {
|
|
187
|
-
className: "space-y-3",
|
|
188
|
-
children: A.map((e) => /* @__PURE__ */ h("div", {
|
|
189
|
-
className: "flex items-center gap-3",
|
|
190
|
-
children: [
|
|
191
|
-
/* @__PURE__ */ m("span", {
|
|
192
|
-
className: "w-10 text-xs text-text-secondary",
|
|
193
|
-
children: e.name
|
|
194
|
-
}),
|
|
195
|
-
/* @__PURE__ */ m("div", {
|
|
196
|
-
className: "flex-1 h-6 bg-bg-sunken rounded overflow-hidden",
|
|
197
|
-
children: /* @__PURE__ */ m("div", {
|
|
198
|
-
className: "h-6 bg-accent-blue rounded",
|
|
199
|
-
style: { width: `${e.value / B * 100}%` }
|
|
200
|
-
})
|
|
201
|
-
}),
|
|
202
|
-
/* @__PURE__ */ m("span", {
|
|
203
|
-
className: "w-12 text-right text-xs font-medium tabular-nums",
|
|
204
|
-
children: e.value
|
|
205
|
-
})
|
|
206
|
-
]
|
|
207
|
-
}, e.name))
|
|
75
|
+
/* @__PURE__ */ p(a, {
|
|
76
|
+
title: "Time & billing",
|
|
77
|
+
children: /* @__PURE__ */ m("div", {
|
|
78
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
79
|
+
children: [/* @__PURE__ */ p(v, {
|
|
80
|
+
label: "Billed hours",
|
|
81
|
+
value: o.billedHours,
|
|
82
|
+
total: x,
|
|
83
|
+
tone: "accent"
|
|
84
|
+
}), /* @__PURE__ */ p(v, {
|
|
85
|
+
label: "Unbilled hours",
|
|
86
|
+
value: o.unbilledHours,
|
|
87
|
+
total: x,
|
|
88
|
+
tone: "warning"
|
|
208
89
|
})]
|
|
209
|
-
})]
|
|
210
|
-
}),
|
|
211
|
-
N === "revenue" && /* @__PURE__ */ m("div", {
|
|
212
|
-
className: "space-y-6",
|
|
213
|
-
children: /* @__PURE__ */ h(y, {
|
|
214
|
-
className: "border-border-seam",
|
|
215
|
-
children: [/* @__PURE__ */ m(x, { children: /* @__PURE__ */ m(S, {
|
|
216
|
-
className: "text-base",
|
|
217
|
-
children: "Revenue Breakdown"
|
|
218
|
-
}) }), /* @__PURE__ */ m(b, { children: /* @__PURE__ */ m("div", {
|
|
219
|
-
className: "space-y-4",
|
|
220
|
-
children: k.map((e) => {
|
|
221
|
-
let t = e.prev ? ((e.value - e.prev) / e.prev * 100).toFixed(1) : "0", n = e.prev ? e.value >= e.prev : !0;
|
|
222
|
-
return /* @__PURE__ */ h("div", {
|
|
223
|
-
className: "flex items-center justify-between rounded-lg border border-border-seam p-4 transition-shadow hover:shadow-pop",
|
|
224
|
-
children: [/* @__PURE__ */ h("div", {
|
|
225
|
-
className: "flex items-center gap-4",
|
|
226
|
-
children: [/* @__PURE__ */ m("div", {
|
|
227
|
-
className: "flex h-10 w-10 items-center justify-center rounded-lg bg-accent-soft",
|
|
228
|
-
children: /* @__PURE__ */ m(o, { className: "h-5 w-5 text-text-primary" })
|
|
229
|
-
}), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ h("p", {
|
|
230
|
-
className: "font-medium",
|
|
231
|
-
children: [e.name, " 2025"]
|
|
232
|
-
}), /* @__PURE__ */ h("p", {
|
|
233
|
-
className: "text-sm text-text-secondary tabular-nums",
|
|
234
|
-
children: [
|
|
235
|
-
"Previous: $",
|
|
236
|
-
((e.prev ?? 0) / 1e3).toFixed(1),
|
|
237
|
-
"k"
|
|
238
|
-
]
|
|
239
|
-
})] })]
|
|
240
|
-
}), /* @__PURE__ */ h("div", {
|
|
241
|
-
className: "text-right",
|
|
242
|
-
children: [/* @__PURE__ */ h("p", {
|
|
243
|
-
className: "text-lg font-bold tabular-nums",
|
|
244
|
-
children: [
|
|
245
|
-
"$",
|
|
246
|
-
(e.value / 1e3).toFixed(1),
|
|
247
|
-
"k"
|
|
248
|
-
]
|
|
249
|
-
}), /* @__PURE__ */ h("p", {
|
|
250
|
-
className: `flex items-center justify-end gap-1 text-xs tabular-nums ${n ? "text-status-success-text" : "text-status-error-text"}`,
|
|
251
|
-
children: [
|
|
252
|
-
m(n ? i : r, { className: "h-3 w-3" }),
|
|
253
|
-
t,
|
|
254
|
-
"%"
|
|
255
|
-
]
|
|
256
|
-
})]
|
|
257
|
-
})]
|
|
258
|
-
}, e.name);
|
|
259
|
-
})
|
|
260
|
-
}) })]
|
|
261
90
|
})
|
|
262
|
-
}),
|
|
263
|
-
N === "clients" && /* @__PURE__ */ h("div", {
|
|
264
|
-
className: "space-y-6",
|
|
265
|
-
children: [/* @__PURE__ */ h(y, {
|
|
266
|
-
className: "border-border-seam",
|
|
267
|
-
children: [/* @__PURE__ */ m(x, { children: /* @__PURE__ */ m(S, {
|
|
268
|
-
className: "text-base",
|
|
269
|
-
children: "Client Acquisition"
|
|
270
|
-
}) }), /* @__PURE__ */ m(b, {
|
|
271
|
-
className: "space-y-3",
|
|
272
|
-
children: A.map((e, t) => {
|
|
273
|
-
let n = t > 0 ? A[t - 1]?.value ?? 0 : 0, r = n > 0 ? ((e.value - n) / n * 100).toFixed(0) : "N/A";
|
|
274
|
-
return /* @__PURE__ */ h("div", {
|
|
275
|
-
className: "flex items-center gap-4 rounded-lg border border-border-seam p-3",
|
|
276
|
-
children: [/* @__PURE__ */ h("div", {
|
|
277
|
-
className: "flex-1",
|
|
278
|
-
children: [/* @__PURE__ */ h("div", {
|
|
279
|
-
className: "flex items-center justify-between",
|
|
280
|
-
children: [/* @__PURE__ */ m("span", {
|
|
281
|
-
className: "font-medium",
|
|
282
|
-
children: e.name
|
|
283
|
-
}), /* @__PURE__ */ h("span", {
|
|
284
|
-
className: "text-lg font-bold tabular-nums",
|
|
285
|
-
children: [e.value, " clients"]
|
|
286
|
-
})]
|
|
287
|
-
}), /* @__PURE__ */ m("div", {
|
|
288
|
-
className: "mt-2 h-2 overflow-hidden rounded-full bg-bg-sunken",
|
|
289
|
-
children: /* @__PURE__ */ m("div", {
|
|
290
|
-
className: "h-2 rounded-full bg-accent-blue",
|
|
291
|
-
style: { width: `${e.value / B * 100}%` }
|
|
292
|
-
})
|
|
293
|
-
})]
|
|
294
|
-
}), /* @__PURE__ */ m(_, {
|
|
295
|
-
variant: "secondary",
|
|
296
|
-
className: "text-xs tabular-nums",
|
|
297
|
-
children: typeof r == "string" ? r : `+${r}%`
|
|
298
|
-
})]
|
|
299
|
-
}, e.name);
|
|
300
|
-
})
|
|
301
|
-
})]
|
|
302
|
-
}), /* @__PURE__ */ h(y, {
|
|
303
|
-
className: "border-border-seam",
|
|
304
|
-
children: [/* @__PURE__ */ m(x, { children: /* @__PURE__ */ h("div", {
|
|
305
|
-
className: "flex items-center gap-2",
|
|
306
|
-
children: [/* @__PURE__ */ m(l, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ m(S, {
|
|
307
|
-
className: "text-base",
|
|
308
|
-
children: "Geographic Distribution"
|
|
309
|
-
})]
|
|
310
|
-
}) }), /* @__PURE__ */ m(b, { children: /* @__PURE__ */ m("div", {
|
|
311
|
-
className: "overflow-x-auto",
|
|
312
|
-
children: /* @__PURE__ */ h("table", {
|
|
313
|
-
className: "w-full text-sm",
|
|
314
|
-
children: [/* @__PURE__ */ m("thead", { children: /* @__PURE__ */ h("tr", {
|
|
315
|
-
className: "border-b border-border-seam text-left text-text-secondary",
|
|
316
|
-
children: [
|
|
317
|
-
/* @__PURE__ */ m("th", {
|
|
318
|
-
className: "p-3 font-medium",
|
|
319
|
-
children: "Country"
|
|
320
|
-
}),
|
|
321
|
-
/* @__PURE__ */ m("th", {
|
|
322
|
-
className: "p-3 text-right font-medium",
|
|
323
|
-
children: "Clients"
|
|
324
|
-
}),
|
|
325
|
-
/* @__PURE__ */ m("th", {
|
|
326
|
-
className: "p-3 text-right font-medium",
|
|
327
|
-
children: "Revenue"
|
|
328
|
-
}),
|
|
329
|
-
/* @__PURE__ */ m("th", {
|
|
330
|
-
className: "p-3 font-medium",
|
|
331
|
-
children: "Distribution"
|
|
332
|
-
})
|
|
333
|
-
]
|
|
334
|
-
}) }), /* @__PURE__ */ m("tbody", { children: M.map((e) => {
|
|
335
|
-
let t = M.reduce((e, t) => e + t.clients, 0), n = Math.round(e.clients / t * 100);
|
|
336
|
-
return /* @__PURE__ */ h("tr", {
|
|
337
|
-
className: "border-b border-border-seam transition-colors hover:bg-bg-sunken/50",
|
|
338
|
-
children: [
|
|
339
|
-
/* @__PURE__ */ m("td", {
|
|
340
|
-
className: "p-3 font-medium",
|
|
341
|
-
children: e.country
|
|
342
|
-
}),
|
|
343
|
-
/* @__PURE__ */ m("td", {
|
|
344
|
-
className: "p-3 text-right tabular-nums",
|
|
345
|
-
children: e.clients
|
|
346
|
-
}),
|
|
347
|
-
/* @__PURE__ */ h("td", {
|
|
348
|
-
className: "p-3 text-right tabular-nums",
|
|
349
|
-
children: [
|
|
350
|
-
"$",
|
|
351
|
-
(e.revenue / 1e3).toFixed(0),
|
|
352
|
-
"k"
|
|
353
|
-
]
|
|
354
|
-
}),
|
|
355
|
-
/* @__PURE__ */ m("td", {
|
|
356
|
-
className: "p-3",
|
|
357
|
-
children: /* @__PURE__ */ h("div", {
|
|
358
|
-
className: "flex items-center gap-2",
|
|
359
|
-
children: [/* @__PURE__ */ m("div", {
|
|
360
|
-
className: "h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken",
|
|
361
|
-
children: /* @__PURE__ */ m("div", {
|
|
362
|
-
className: "h-2 rounded-full bg-action-primary-bg",
|
|
363
|
-
style: { width: `${n}%` }
|
|
364
|
-
})
|
|
365
|
-
}), /* @__PURE__ */ h("span", {
|
|
366
|
-
className: "w-10 text-right text-xs text-text-secondary tabular-nums",
|
|
367
|
-
children: [n, "%"]
|
|
368
|
-
})]
|
|
369
|
-
})
|
|
370
|
-
})
|
|
371
|
-
]
|
|
372
|
-
}, e.country);
|
|
373
|
-
}) })]
|
|
374
|
-
})
|
|
375
|
-
}) })]
|
|
376
|
-
})]
|
|
377
|
-
}),
|
|
378
|
-
N === "services" && /* @__PURE__ */ h(y, {
|
|
379
|
-
className: "border-border-seam",
|
|
380
|
-
children: [/* @__PURE__ */ m(x, { children: /* @__PURE__ */ m(S, {
|
|
381
|
-
className: "text-base",
|
|
382
|
-
children: "Service Performance (Total Bookings)"
|
|
383
|
-
}) }), /* @__PURE__ */ m(b, {
|
|
384
|
-
className: "space-y-3",
|
|
385
|
-
children: [...j].sort((e, t) => t.value - e.value).map((e, t) => /* @__PURE__ */ h("div", {
|
|
386
|
-
className: "flex items-center gap-4",
|
|
387
|
-
children: [/* @__PURE__ */ h("span", {
|
|
388
|
-
className: "w-6 text-sm font-medium text-text-secondary tabular-nums",
|
|
389
|
-
children: ["#", t + 1]
|
|
390
|
-
}), /* @__PURE__ */ h("div", {
|
|
391
|
-
className: "flex-1",
|
|
392
|
-
children: [/* @__PURE__ */ h("div", {
|
|
393
|
-
className: "flex items-center justify-between",
|
|
394
|
-
children: [/* @__PURE__ */ m("span", {
|
|
395
|
-
className: "text-sm font-medium",
|
|
396
|
-
children: e.name
|
|
397
|
-
}), /* @__PURE__ */ m("span", {
|
|
398
|
-
className: "text-sm font-bold tabular-nums",
|
|
399
|
-
children: e.value
|
|
400
|
-
})]
|
|
401
|
-
}), /* @__PURE__ */ m("div", {
|
|
402
|
-
className: "mt-1 h-3 overflow-hidden rounded-full bg-bg-sunken",
|
|
403
|
-
children: /* @__PURE__ */ m("div", {
|
|
404
|
-
className: "h-3 rounded-full bg-action-primary-bg transition-all",
|
|
405
|
-
style: { width: `${e.value / V * 100}%` }
|
|
406
|
-
})
|
|
407
|
-
})]
|
|
408
|
-
})]
|
|
409
|
-
}, e.name))
|
|
410
|
-
})]
|
|
411
|
-
}),
|
|
412
|
-
N === "performance" && /* @__PURE__ */ h("div", {
|
|
413
|
-
className: "grid gap-6 lg:grid-cols-2",
|
|
414
|
-
children: [/* @__PURE__ */ h(y, {
|
|
415
|
-
className: "border-border-seam",
|
|
416
|
-
children: [/* @__PURE__ */ m(x, { children: /* @__PURE__ */ m(S, {
|
|
417
|
-
className: "text-base",
|
|
418
|
-
children: "Monthly Revenue vs Previous"
|
|
419
|
-
}) }), /* @__PURE__ */ h(b, {
|
|
420
|
-
className: "space-y-3",
|
|
421
|
-
children: [k.map((e) => /* @__PURE__ */ h("div", {
|
|
422
|
-
className: "space-y-1",
|
|
423
|
-
children: [/* @__PURE__ */ h("div", {
|
|
424
|
-
className: "flex items-center justify-between text-xs",
|
|
425
|
-
children: [/* @__PURE__ */ m("span", {
|
|
426
|
-
className: "font-medium",
|
|
427
|
-
children: e.name
|
|
428
|
-
}), /* @__PURE__ */ h("span", {
|
|
429
|
-
className: "text-text-secondary tabular-nums",
|
|
430
|
-
children: [
|
|
431
|
-
"$",
|
|
432
|
-
(e.value / 1e3).toFixed(1),
|
|
433
|
-
"k vs $",
|
|
434
|
-
((e.prev ?? 0) / 1e3).toFixed(1),
|
|
435
|
-
"k"
|
|
436
|
-
]
|
|
437
|
-
})]
|
|
438
|
-
}), /* @__PURE__ */ h("div", {
|
|
439
|
-
className: "flex gap-1",
|
|
440
|
-
children: [/* @__PURE__ */ m("div", {
|
|
441
|
-
className: "h-4 rounded bg-action-primary-bg/30",
|
|
442
|
-
style: { width: `${(e.prev ?? 0) / z * 100}%` }
|
|
443
|
-
}), /* @__PURE__ */ m("div", {
|
|
444
|
-
className: "h-4 rounded bg-action-primary-bg",
|
|
445
|
-
style: { width: `${e.value / z * 100 - (e.prev ?? 0) / z * 100}%` }
|
|
446
|
-
})]
|
|
447
|
-
})]
|
|
448
|
-
}, e.name)), /* @__PURE__ */ h("div", {
|
|
449
|
-
className: "mt-4 flex items-center gap-4 text-xs",
|
|
450
|
-
children: [/* @__PURE__ */ h("span", {
|
|
451
|
-
className: "flex items-center gap-1",
|
|
452
|
-
children: [/* @__PURE__ */ m("div", { className: "h-3 w-3 rounded bg-action-primary-bg/30" }), " Previous"]
|
|
453
|
-
}), /* @__PURE__ */ h("span", {
|
|
454
|
-
className: "flex items-center gap-1",
|
|
455
|
-
children: [/* @__PURE__ */ m("div", { className: "h-3 w-3 rounded bg-action-primary-bg" }), " Current"]
|
|
456
|
-
})]
|
|
457
|
-
})]
|
|
458
|
-
})]
|
|
459
|
-
}), /* @__PURE__ */ h(y, {
|
|
460
|
-
className: "border-border-seam",
|
|
461
|
-
children: [/* @__PURE__ */ m(x, { children: /* @__PURE__ */ m(S, {
|
|
462
|
-
className: "text-base",
|
|
463
|
-
children: "Top Performing Services"
|
|
464
|
-
}) }), /* @__PURE__ */ m(b, { children: /* @__PURE__ */ m("div", {
|
|
465
|
-
className: "space-y-3",
|
|
466
|
-
children: [...j].sort((e, t) => t.value - e.value).slice(0, 5).map((e, t) => /* @__PURE__ */ h("div", {
|
|
467
|
-
className: "flex items-center justify-between rounded-lg border border-border-seam p-3",
|
|
468
|
-
children: [/* @__PURE__ */ h("div", {
|
|
469
|
-
className: "flex items-center gap-3",
|
|
470
|
-
children: [/* @__PURE__ */ m("div", {
|
|
471
|
-
className: `flex h-8 w-8 items-center justify-center rounded-full text-sm font-bold tabular-nums ${t === 0 ? "bg-status-warning-bg-subtle text-status-warning-text" : t === 1 ? "bg-bg-sunken text-text-secondary" : t === 2 ? "bg-accent-soft text-text-primary" : "bg-bg-sunken text-text-secondary"}`,
|
|
472
|
-
children: t + 1
|
|
473
|
-
}), /* @__PURE__ */ m("span", {
|
|
474
|
-
className: "font-medium text-sm",
|
|
475
|
-
children: e.name
|
|
476
|
-
})]
|
|
477
|
-
}), /* @__PURE__ */ h(_, {
|
|
478
|
-
variant: "secondary",
|
|
479
|
-
children: [e.value, " bookings"]
|
|
480
|
-
})]
|
|
481
|
-
}, e.name))
|
|
482
|
-
}) })]
|
|
483
|
-
})]
|
|
484
91
|
})
|
|
485
92
|
]
|
|
486
93
|
});
|
|
487
|
-
}
|
|
94
|
+
}, g = ({ data: e }) => {
|
|
95
|
+
if (!e.length) return /* @__PURE__ */ p("p", {
|
|
96
|
+
className: "text-sm text-text-tertiary",
|
|
97
|
+
children: "No invoiced revenue yet."
|
|
98
|
+
});
|
|
99
|
+
let t = Math.max(...e.map((e) => e.amount), 1);
|
|
100
|
+
return /* @__PURE__ */ p("div", {
|
|
101
|
+
className: "flex h-52 items-end gap-2",
|
|
102
|
+
children: e.map((e) => /* @__PURE__ */ m("div", {
|
|
103
|
+
className: "flex flex-1 flex-col items-center gap-2",
|
|
104
|
+
children: [
|
|
105
|
+
/* @__PURE__ */ p("span", {
|
|
106
|
+
className: "text-[10px] text-text-tertiary",
|
|
107
|
+
children: c(e.amount)
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ p("div", {
|
|
110
|
+
className: "flex w-full flex-1 items-end",
|
|
111
|
+
children: /* @__PURE__ */ p("div", {
|
|
112
|
+
className: "w-full rounded-t bg-accent",
|
|
113
|
+
style: { height: `${Math.max(e.amount / t * 100, 2)}%` }
|
|
114
|
+
})
|
|
115
|
+
}),
|
|
116
|
+
/* @__PURE__ */ p("span", {
|
|
117
|
+
className: "text-[10px] text-text-tertiary",
|
|
118
|
+
children: e.month
|
|
119
|
+
})
|
|
120
|
+
]
|
|
121
|
+
}, e.month))
|
|
122
|
+
});
|
|
123
|
+
}, _ = ({ items: e }) => {
|
|
124
|
+
if (!e.length) return /* @__PURE__ */ p("p", {
|
|
125
|
+
className: "text-sm text-text-tertiary",
|
|
126
|
+
children: "No records yet."
|
|
127
|
+
});
|
|
128
|
+
let t = e.reduce((e, t) => e + t.count, 0) || 1;
|
|
129
|
+
return /* @__PURE__ */ p("ul", {
|
|
130
|
+
className: "space-y-2.5",
|
|
131
|
+
children: e.map((e) => /* @__PURE__ */ m("li", {
|
|
132
|
+
className: "flex items-center gap-3",
|
|
133
|
+
children: [
|
|
134
|
+
/* @__PURE__ */ p("div", {
|
|
135
|
+
className: "w-28 shrink-0",
|
|
136
|
+
children: /* @__PURE__ */ p(o, { status: e.status })
|
|
137
|
+
}),
|
|
138
|
+
/* @__PURE__ */ p("div", {
|
|
139
|
+
className: "h-2 flex-1 overflow-hidden rounded-full bg-bg-sunken",
|
|
140
|
+
children: /* @__PURE__ */ p("div", {
|
|
141
|
+
className: "h-full rounded-full bg-accent",
|
|
142
|
+
style: { width: `${e.count / t * 100}%` }
|
|
143
|
+
})
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ p("span", {
|
|
146
|
+
className: "w-8 text-right text-sm font-medium text-text-primary",
|
|
147
|
+
children: e.count
|
|
148
|
+
})
|
|
149
|
+
]
|
|
150
|
+
}, e.status))
|
|
151
|
+
});
|
|
152
|
+
}, v = ({ label: e, value: t, total: n, tone: r }) => {
|
|
153
|
+
let i = n > 0 ? Math.round(t / n * 100) : 0;
|
|
154
|
+
return /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("div", {
|
|
155
|
+
className: "mb-1 flex items-center justify-between text-sm",
|
|
156
|
+
children: [/* @__PURE__ */ p("span", {
|
|
157
|
+
className: "text-text-secondary",
|
|
158
|
+
children: e
|
|
159
|
+
}), /* @__PURE__ */ m("span", {
|
|
160
|
+
className: "font-medium text-text-primary",
|
|
161
|
+
children: [
|
|
162
|
+
s(t),
|
|
163
|
+
" · ",
|
|
164
|
+
i,
|
|
165
|
+
"%"
|
|
166
|
+
]
|
|
167
|
+
})]
|
|
168
|
+
}), /* @__PURE__ */ p("div", {
|
|
169
|
+
className: "h-2.5 overflow-hidden rounded-full bg-bg-sunken",
|
|
170
|
+
children: /* @__PURE__ */ p("div", {
|
|
171
|
+
className: r === "accent" ? "h-full rounded-full bg-accent" : "h-full rounded-full bg-status-warning-text",
|
|
172
|
+
style: { width: `${i}%` }
|
|
173
|
+
})
|
|
174
|
+
})] });
|
|
175
|
+
};
|
|
488
176
|
//#endregion
|
|
489
|
-
export {
|
|
177
|
+
export { h as AnalyticsPage };
|
|
490
178
|
|
|
491
179
|
//# sourceMappingURL=AnalyticsPage.js.map
|