@burdenoff/microfe-proserviceworld 2026.703.1 → 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.
Files changed (75) hide show
  1. package/dist/index.js +2 -3
  2. package/dist/node_modules/clsx/dist/clsx.js +18 -0
  3. package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
  4. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1716 -0
  5. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
  6. package/dist/proserviceworld/ProServiceWorldRoot.js +92 -136
  7. package/dist/proserviceworld/ProServiceWorldRoot.js.map +1 -1
  8. package/dist/proserviceworld/ProServiceWorldRoutes.js +18 -26
  9. package/dist/proserviceworld/ProServiceWorldRoutes.js.map +1 -1
  10. package/dist/proserviceworld/components/ui.js +273 -0
  11. package/dist/proserviceworld/components/ui.js.map +1 -0
  12. package/dist/proserviceworld/hooks/useFiles.js +45 -0
  13. package/dist/proserviceworld/hooks/useFiles.js.map +1 -0
  14. package/dist/proserviceworld/hooks/useProServiceWorldApi.js +416 -0
  15. package/dist/proserviceworld/hooks/useProServiceWorldApi.js.map +1 -0
  16. package/dist/proserviceworld/index.js +0 -1
  17. package/dist/proserviceworld/pages/AnalyticsPage.js +163 -475
  18. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  19. package/dist/proserviceworld/pages/ClientDetailPage.js +238 -0
  20. package/dist/proserviceworld/pages/ClientDetailPage.js.map +1 -0
  21. package/dist/proserviceworld/pages/ClientsPage.js +295 -0
  22. package/dist/proserviceworld/pages/ClientsPage.js.map +1 -0
  23. package/dist/proserviceworld/pages/CompliancePage.js +307 -0
  24. package/dist/proserviceworld/pages/CompliancePage.js.map +1 -0
  25. package/dist/proserviceworld/pages/ConflictsPage.js +234 -0
  26. package/dist/proserviceworld/pages/ConflictsPage.js.map +1 -0
  27. package/dist/proserviceworld/pages/DashboardPage.js +179 -632
  28. package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
  29. package/dist/proserviceworld/pages/DocumentsPage.js +235 -539
  30. package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
  31. package/dist/proserviceworld/pages/EngagementDetailPage.js +444 -0
  32. package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -0
  33. package/dist/proserviceworld/pages/EngagementsPage.js +256 -0
  34. package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -0
  35. package/dist/proserviceworld/pages/InvoicesPage.js +303 -0
  36. package/dist/proserviceworld/pages/InvoicesPage.js.map +1 -0
  37. package/dist/proserviceworld/pages/MattersPage.js +275 -0
  38. package/dist/proserviceworld/pages/MattersPage.js.map +1 -0
  39. package/dist/proserviceworld/pages/PracticeAreasPage.js +176 -0
  40. package/dist/proserviceworld/pages/PracticeAreasPage.js.map +1 -0
  41. package/dist/proserviceworld/pages/TimePage.js +310 -0
  42. package/dist/proserviceworld/pages/TimePage.js.map +1 -0
  43. package/dist/proserviceworld/utils/cn.js +10 -0
  44. package/dist/proserviceworld/utils/cn.js.map +1 -0
  45. package/dist/proserviceworld/utils/nav.js +11 -0
  46. package/dist/proserviceworld/utils/nav.js.map +1 -0
  47. package/package.json +1 -1
  48. package/dist/proserviceworld/pages/AdminReportsPage.js +0 -579
  49. package/dist/proserviceworld/pages/AdminReportsPage.js.map +0 -1
  50. package/dist/proserviceworld/pages/AdminUsersPage.js +0 -468
  51. package/dist/proserviceworld/pages/AdminUsersPage.js.map +0 -1
  52. package/dist/proserviceworld/pages/BookingsPage.js +0 -446
  53. package/dist/proserviceworld/pages/BookingsPage.js.map +0 -1
  54. package/dist/proserviceworld/pages/MessagesPage.js +0 -238
  55. package/dist/proserviceworld/pages/MessagesPage.js.map +0 -1
  56. package/dist/proserviceworld/pages/PaymentsPage.js +0 -537
  57. package/dist/proserviceworld/pages/PaymentsPage.js.map +0 -1
  58. package/dist/proserviceworld/pages/ProjectsPage.js +0 -627
  59. package/dist/proserviceworld/pages/ProjectsPage.js.map +0 -1
  60. package/dist/proserviceworld/pages/ProviderDetailPage.js +0 -538
  61. package/dist/proserviceworld/pages/ProviderDetailPage.js.map +0 -1
  62. package/dist/proserviceworld/pages/ProvidersPage.js +0 -347
  63. package/dist/proserviceworld/pages/ProvidersPage.js.map +0 -1
  64. package/dist/proserviceworld/pages/ReviewsPage.js +0 -356
  65. package/dist/proserviceworld/pages/ReviewsPage.js.map +0 -1
  66. package/dist/proserviceworld/pages/ServiceDetailsPage.js +0 -631
  67. package/dist/proserviceworld/pages/ServiceDetailsPage.js.map +0 -1
  68. package/dist/proserviceworld/pages/ServicesPage.js +0 -344
  69. package/dist/proserviceworld/pages/ServicesPage.js.map +0 -1
  70. package/dist/proserviceworld/pages/VerificationPage.js +0 -370
  71. package/dist/proserviceworld/pages/VerificationPage.js.map +0 -1
  72. package/dist/proserviceworld/store/proserviceworldStore.js +0 -2490
  73. package/dist/proserviceworld/store/proserviceworldStore.js.map +0 -1
  74. package/dist/proserviceworld/utils/i18n.js +0 -15
  75. package/dist/proserviceworld/utils/i18n.js.map +0 -1
@@ -1,491 +1,179 @@
1
- import { useProServiceWorldStore as e } from "../store/proserviceworldStore.js";
2
- import { useState as t } from "react";
3
- import { Activity as n, ArrowDownRight as r, ArrowUpRight as i, BarChart3 as a, Calendar as o, DollarSign as s, Download as c, Globe as l, Minus as u, TrendingDown as d, TrendingUp as f, Users as p } from "lucide-react";
4
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
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
- function O() {
8
- let { analyticsMetrics: O, revenueData: k, clientData: A, servicePerformance: j, geographicData: M } = e(), [N, P] = t("overview"), [F, I] = t("6m"), L = [
9
- {
10
- key: "overview",
11
- label: "Overview",
12
- icon: a
13
- },
14
- {
15
- key: "revenue",
16
- label: "Revenue",
17
- icon: s
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__ */ h("div", {
39
- className: "relative overflow-hidden rounded-card -mx-2 px-2 pt-1",
40
- children: [/* @__PURE__ */ m(g, { intensity: "subtle" }), /* @__PURE__ */ h("div", {
41
- className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
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(E, {
76
- storageKey: "proserviceworld-analytics",
77
- steps: [
78
- {
79
- id: "revenue",
80
- label: "Inspect revenue performance",
81
- description: "Open the Revenue tab to see month-over-month growth.",
82
- icon: /* @__PURE__ */ m(s, { className: "h-4 w-4" }),
83
- onClick: () => P("revenue")
84
- },
85
- {
86
- id: "services",
87
- label: "Find your top services",
88
- description: "See which services attract the most bookings.",
89
- icon: /* @__PURE__ */ m(n, { className: "h-4 w-4" }),
90
- onClick: () => P("services")
91
- },
92
- {
93
- id: "clients",
94
- label: "Track client acquisition",
95
- description: "Review client growth and geographic reach.",
96
- icon: /* @__PURE__ */ m(p, { className: "h-4 w-4" }),
97
- onClick: () => P("clients")
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__ */ m("div", {
102
- className: "flex flex-wrap gap-1 border-b border-border-seam",
103
- children: L.map(({ key: e, label: t, icon: n }) => /* @__PURE__ */ h("button", {
104
- onClick: () => P(e),
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 gap-4 sm:grid-cols-2 lg:grid-cols-5",
112
- children: O.map((e, t) => /* @__PURE__ */ h(w, {
113
- treatment: t === 0 ? "glass" : "metric",
114
- glow: t === 0,
115
- className: "border-border-seam",
116
- children: [
117
- /* @__PURE__ */ h("div", {
118
- className: "flex items-center justify-between",
119
- children: [/* @__PURE__ */ m("p", {
120
- className: "text-xs font-medium text-text-secondary",
121
- children: e.label
122
- }), R(e.changeType)]
123
- }),
124
- /* @__PURE__ */ m("p", {
125
- className: "mt-1 text-2xl font-bold tabular-nums",
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
- N === "overview" && /* @__PURE__ */ h("div", {
136
- className: "grid gap-6 lg:grid-cols-2",
137
- children: [/* @__PURE__ */ h(C, { children: [/* @__PURE__ */ h("div", {
138
- className: "flex items-center justify-between mb-4",
139
- children: [/* @__PURE__ */ m("h2", {
140
- className: "text-base font-semibold tracking-tight",
141
- children: "Revenue Trend"
142
- }), /* @__PURE__ */ m(_, {
143
- variant: "secondary",
144
- children: "Last 6 months"
145
- })]
146
- }), /* @__PURE__ */ m("div", {
147
- className: "space-y-3",
148
- children: k.map((e) => /* @__PURE__ */ h("div", {
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 { O as AnalyticsPage };
177
+ export { h as AnalyticsPage };
490
178
 
491
179
  //# sourceMappingURL=AnalyticsPage.js.map