@burdenoff/microfe-hookmovies 2026.706.2 → 2026.706.3
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/hookmovies/HookMoviesRoutes.js +54 -6
- package/dist/hookmovies/HookMoviesRoutes.js.map +1 -1
- package/dist/hookmovies/components/index.js +1 -1
- package/dist/hookmovies/context/HookMoviesContext.js +64 -40
- package/dist/hookmovies/context/HookMoviesContext.js.map +1 -1
- package/dist/hookmovies/hooks/useHookMoviesApi.js +592 -134
- package/dist/hookmovies/hooks/useHookMoviesApi.js.map +1 -1
- package/dist/hookmovies/pages/ai/ConciergePage.js +330 -0
- package/dist/hookmovies/pages/ai/ConciergePage.js.map +1 -0
- package/dist/hookmovies/pages/analytics/AnalyticsPage.js +450 -0
- package/dist/hookmovies/pages/analytics/AnalyticsPage.js.map +1 -0
- package/dist/hookmovies/pages/analytics/PayoutsPage.js +499 -0
- package/dist/hookmovies/pages/analytics/PayoutsPage.js.map +1 -0
- package/dist/hookmovies/pages/auditions/AuditionsPage.js +3 -3
- package/dist/hookmovies/pages/catalog/PeoplePage.js +3 -3
- package/dist/hookmovies/pages/catalog/StudiosPage.js +3 -3
- package/dist/hookmovies/pages/catalog/TitleDetailPage.js +7 -7
- package/dist/hookmovies/pages/catalog/TitlesPage.js +4 -4
- package/dist/hookmovies/pages/commerce/CheckoutPage.js +430 -0
- package/dist/hookmovies/pages/commerce/CheckoutPage.js.map +1 -0
- package/dist/hookmovies/pages/consumer/DiscoveryPage.js +7 -7
- package/dist/hookmovies/pages/consumer/HooksPage.js +5 -5
- package/dist/hookmovies/pages/consumer/TitleViewPage.js +27 -27
- package/dist/hookmovies/pages/consumer/TitleViewPage.js.map +1 -1
- package/dist/hookmovies/pages/developer/DevPortalPage.js +815 -0
- package/dist/hookmovies/pages/developer/DevPortalPage.js.map +1 -0
- package/dist/hookmovies/pages/distribution/RightsWindowsPage.js +3 -3
- package/dist/hookmovies/pages/engagement/ReviewsPage.js +201 -143
- package/dist/hookmovies/pages/engagement/ReviewsPage.js.map +1 -1
- package/dist/hookmovies/pages/library/EntitlementsPage.js +3 -3
- package/dist/hookmovies/pages/library/EntitlementsPage.js.map +1 -1
- package/dist/hookmovies/pages/library/ListsPage.js +3 -3
- package/dist/hookmovies/pages/live/LivePage.js +608 -0
- package/dist/hookmovies/pages/live/LivePage.js.map +1 -0
- package/dist/hookmovies/pages/localization/LocalizationPage.js +656 -0
- package/dist/hookmovies/pages/localization/LocalizationPage.js.map +1 -0
- package/dist/hookmovies/pages/onboarding/OnboardingPage.js +366 -0
- package/dist/hookmovies/pages/onboarding/OnboardingPage.js.map +1 -0
- package/dist/hookmovies/pages/productions/ProductionsPage.js +3 -3
- package/dist/hookmovies/pages/social/ProfilesPage.js +701 -0
- package/dist/hookmovies/pages/social/ProfilesPage.js.map +1 -0
- package/dist/hookmovies/pages/social/WatchPartyListPage.js +281 -0
- package/dist/hookmovies/pages/social/WatchPartyListPage.js.map +1 -0
- package/dist/hookmovies/pages/social/WatchPartyRoomPage.js +567 -0
- package/dist/hookmovies/pages/social/WatchPartyRoomPage.js.map +1 -0
- package/dist/hookmovies/pages/trust/ModerationPage.js +320 -0
- package/dist/hookmovies/pages/trust/ModerationPage.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { PageLayout as e } from "../../components/PageLayout.js";
|
|
2
|
+
import { MetricsCard as t } from "../../components/MetricsCard.js";
|
|
3
|
+
import { useMyBillingAccounts as n, useMyEarningsSummary as r, useReviews as i, useRightsWindows as a, useTitles as o } from "../../hooks/useHookMoviesApi.js";
|
|
4
|
+
import { formatEnumLabel as s, formatNumber as c } from "../../utils/formatters.js";
|
|
5
|
+
import { EmptyState as l } from "../../components/EmptyState.js";
|
|
6
|
+
import { ErrorState as u, LoadingState as d } from "../../components/StateViews.js";
|
|
7
|
+
import { useMemo as f } from "react";
|
|
8
|
+
import { Activity as p, BarChart3 as m, Film as h, Layers as ee, PieChart as g, ScrollText as _, Star as v, ThumbsUp as y, TrendingUp as b, Wallet as x } from "lucide-react";
|
|
9
|
+
import { Fragment as te, jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
10
|
+
import { GlassCard as w } from "@burdenoff/fe-libs/ui";
|
|
11
|
+
//#region src/hookmovies/pages/analytics/AnalyticsPage.tsx
|
|
12
|
+
var T = {
|
|
13
|
+
limit: 200,
|
|
14
|
+
offset: 0
|
|
15
|
+
}, E = [
|
|
16
|
+
"var(--color-accent-primary)",
|
|
17
|
+
"var(--color-accent-teal)",
|
|
18
|
+
"var(--color-accent-blue)",
|
|
19
|
+
"var(--color-accent-indigo)",
|
|
20
|
+
"var(--color-accent-purple)",
|
|
21
|
+
"var(--color-accent-secondary)",
|
|
22
|
+
"var(--color-accent-soft)"
|
|
23
|
+
], D = {
|
|
24
|
+
draft: "var(--color-text-muted)",
|
|
25
|
+
in_review: "var(--color-status-warning-text)",
|
|
26
|
+
scheduled: "var(--color-status-info-text)",
|
|
27
|
+
published: "var(--color-status-success-text)",
|
|
28
|
+
unpublished: "var(--color-text-muted)",
|
|
29
|
+
archived: "var(--color-text-muted)",
|
|
30
|
+
pending: "var(--color-status-warning-text)",
|
|
31
|
+
active: "var(--color-status-success-text)",
|
|
32
|
+
expired: "var(--color-text-muted)",
|
|
33
|
+
revoked: "var(--color-status-error-text)"
|
|
34
|
+
}, O = (e) => D[e.toLowerCase()] ?? "var(--color-text-muted)", k = ({ icon: e, title: t, hint: n, children: r }) => /* @__PURE__ */ C("section", {
|
|
35
|
+
className: "space-y-4",
|
|
36
|
+
children: [/* @__PURE__ */ C("div", {
|
|
37
|
+
className: "flex items-center gap-2",
|
|
38
|
+
children: [
|
|
39
|
+
/* @__PURE__ */ S("span", {
|
|
40
|
+
className: "text-text-secondary",
|
|
41
|
+
"aria-hidden": "true",
|
|
42
|
+
children: e
|
|
43
|
+
}),
|
|
44
|
+
/* @__PURE__ */ S("h2", {
|
|
45
|
+
className: "text-lg font-semibold text-text-primary",
|
|
46
|
+
children: t
|
|
47
|
+
}),
|
|
48
|
+
n && /* @__PURE__ */ S("span", {
|
|
49
|
+
className: "ml-auto text-xs text-text-muted",
|
|
50
|
+
children: n
|
|
51
|
+
})
|
|
52
|
+
]
|
|
53
|
+
}), r]
|
|
54
|
+
}), A = ({ segments: e, ariaLabel: t, valueSuffix: n }) => {
|
|
55
|
+
let r = Math.max(1, ...e.map((e) => e.value));
|
|
56
|
+
return /* @__PURE__ */ S("ul", {
|
|
57
|
+
className: "space-y-3",
|
|
58
|
+
"aria-label": t,
|
|
59
|
+
children: e.map((e) => {
|
|
60
|
+
let t = Math.round(e.value / r * 100);
|
|
61
|
+
return /* @__PURE__ */ C("li", {
|
|
62
|
+
className: "flex items-center gap-3",
|
|
63
|
+
children: [
|
|
64
|
+
/* @__PURE__ */ S("span", {
|
|
65
|
+
className: "w-28 shrink-0 truncate text-xs text-text-secondary sm:w-36",
|
|
66
|
+
children: e.label
|
|
67
|
+
}),
|
|
68
|
+
/* @__PURE__ */ S("div", {
|
|
69
|
+
className: "relative h-2.5 flex-1 overflow-hidden rounded-full bg-bg-sunken",
|
|
70
|
+
children: /* @__PURE__ */ S("div", {
|
|
71
|
+
className: "absolute inset-y-0 left-0 rounded-full",
|
|
72
|
+
style: {
|
|
73
|
+
width: `${t}%`,
|
|
74
|
+
backgroundColor: e.color
|
|
75
|
+
},
|
|
76
|
+
role: "img",
|
|
77
|
+
"aria-label": `${e.label}: ${c(e.value)}${n ? ` ${n}` : ""}`
|
|
78
|
+
})
|
|
79
|
+
}),
|
|
80
|
+
/* @__PURE__ */ S("span", {
|
|
81
|
+
className: "w-12 shrink-0 text-right text-xs font-medium tabular-nums text-text-primary",
|
|
82
|
+
children: c(e.value)
|
|
83
|
+
})
|
|
84
|
+
]
|
|
85
|
+
}, e.label);
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
}, j = ({ segments: e, centerLabel: t, centerSub: n, ariaLabel: r, formatValue: i }) => {
|
|
89
|
+
let a = e.reduce((e, t) => e + t.value, 0), o = 2 * Math.PI * 42, s = 0;
|
|
90
|
+
return /* @__PURE__ */ C("div", {
|
|
91
|
+
className: "flex flex-col items-center gap-6 sm:flex-row sm:items-center",
|
|
92
|
+
children: [/* @__PURE__ */ C("div", {
|
|
93
|
+
className: "relative shrink-0",
|
|
94
|
+
children: [/* @__PURE__ */ C("svg", {
|
|
95
|
+
viewBox: "0 0 120 120",
|
|
96
|
+
className: "h-40 w-40 -rotate-90",
|
|
97
|
+
role: "img",
|
|
98
|
+
"aria-label": r,
|
|
99
|
+
children: [/* @__PURE__ */ S("circle", {
|
|
100
|
+
cx: "60",
|
|
101
|
+
cy: "60",
|
|
102
|
+
r: 42,
|
|
103
|
+
fill: "none",
|
|
104
|
+
stroke: "var(--color-bg-sunken)",
|
|
105
|
+
strokeWidth: "14"
|
|
106
|
+
}), a > 0 && e.map((e) => {
|
|
107
|
+
let t = e.value / a * o, n = /* @__PURE__ */ S("circle", {
|
|
108
|
+
cx: "60",
|
|
109
|
+
cy: "60",
|
|
110
|
+
r: 42,
|
|
111
|
+
fill: "none",
|
|
112
|
+
stroke: e.color,
|
|
113
|
+
strokeWidth: "14",
|
|
114
|
+
strokeDasharray: `${t} ${o - t}`,
|
|
115
|
+
strokeDashoffset: -s,
|
|
116
|
+
strokeLinecap: "butt",
|
|
117
|
+
children: /* @__PURE__ */ S("title", { children: `${e.label}: ${i(e.value)}` })
|
|
118
|
+
}, e.label);
|
|
119
|
+
return s += t, n;
|
|
120
|
+
})]
|
|
121
|
+
}), /* @__PURE__ */ C("div", {
|
|
122
|
+
className: "pointer-events-none absolute inset-0 flex flex-col items-center justify-center",
|
|
123
|
+
children: [/* @__PURE__ */ S("span", {
|
|
124
|
+
className: "text-lg font-bold tabular-nums text-text-primary",
|
|
125
|
+
children: t
|
|
126
|
+
}), /* @__PURE__ */ S("span", {
|
|
127
|
+
className: "text-[11px] text-text-secondary",
|
|
128
|
+
children: n
|
|
129
|
+
})]
|
|
130
|
+
})]
|
|
131
|
+
}), /* @__PURE__ */ S("ul", {
|
|
132
|
+
className: "w-full space-y-2",
|
|
133
|
+
children: e.map((e) => /* @__PURE__ */ C("li", {
|
|
134
|
+
className: "flex items-center gap-2 text-sm",
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ S("span", {
|
|
137
|
+
className: "size-2.5 shrink-0 rounded-full",
|
|
138
|
+
style: { backgroundColor: e.color },
|
|
139
|
+
"aria-hidden": "true"
|
|
140
|
+
}),
|
|
141
|
+
/* @__PURE__ */ S("span", {
|
|
142
|
+
className: "min-w-0 flex-1 truncate text-text-secondary",
|
|
143
|
+
children: e.label
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ S("span", {
|
|
146
|
+
className: "shrink-0 font-medium tabular-nums text-text-primary",
|
|
147
|
+
children: i(e.value)
|
|
148
|
+
})
|
|
149
|
+
]
|
|
150
|
+
}, e.label))
|
|
151
|
+
})]
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
function M(e, t) {
|
|
155
|
+
let n = /* @__PURE__ */ new Map();
|
|
156
|
+
for (let r of e) {
|
|
157
|
+
let e = t(r);
|
|
158
|
+
n.set(e, (n.get(e) ?? 0) + 1);
|
|
159
|
+
}
|
|
160
|
+
return n;
|
|
161
|
+
}
|
|
162
|
+
function N(e, t) {
|
|
163
|
+
try {
|
|
164
|
+
return new Intl.NumberFormat(void 0, {
|
|
165
|
+
style: "currency",
|
|
166
|
+
currency: t,
|
|
167
|
+
maximumFractionDigits: 2
|
|
168
|
+
}).format(e);
|
|
169
|
+
} catch {
|
|
170
|
+
return `${e.toFixed(2)} ${t}`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
var ne = [
|
|
174
|
+
"DRAFT",
|
|
175
|
+
"IN_REVIEW",
|
|
176
|
+
"SCHEDULED",
|
|
177
|
+
"PUBLISHED",
|
|
178
|
+
"UNPUBLISHED",
|
|
179
|
+
"ARCHIVED"
|
|
180
|
+
], re = [
|
|
181
|
+
"DRAFT",
|
|
182
|
+
"PENDING",
|
|
183
|
+
"ACTIVE",
|
|
184
|
+
"EXPIRED",
|
|
185
|
+
"REVOKED"
|
|
186
|
+
], P = () => {
|
|
187
|
+
let D = o({}, T), P = a({}, T), F = i({}, T), I = n(), L = f(() => {
|
|
188
|
+
let e = I.data ?? [];
|
|
189
|
+
return e.find((e) => e.isDefault) ?? e[0];
|
|
190
|
+
}, [I.data]), R = r(L?.id), z = f(() => D.data?.items ?? [], [D.data]), B = D.data?.totalCount ?? 0, V = f(() => z.filter((e) => e.status === "PUBLISHED").length, [z]), H = f(() => z.filter((e) => e.status === "DRAFT" || e.status === "IN_REVIEW" || e.status === "SCHEDULED").length, [z]), U = f(() => {
|
|
191
|
+
let e = M(z, (e) => e.status);
|
|
192
|
+
return ne.filter((t) => (e.get(t) ?? 0) > 0).map((t) => ({
|
|
193
|
+
label: s(t),
|
|
194
|
+
value: e.get(t) ?? 0,
|
|
195
|
+
color: O(t)
|
|
196
|
+
}));
|
|
197
|
+
}, [z]), W = f(() => [...M(z, (e) => e.type).entries()].sort((e, t) => t[1] - e[1]).map(([e, t], n) => ({
|
|
198
|
+
label: s(e),
|
|
199
|
+
value: t,
|
|
200
|
+
color: E[n % E.length]
|
|
201
|
+
})), [z]), G = f(() => P.data?.items ?? [], [P.data]), K = P.data?.totalCount ?? 0, ie = f(() => G.filter((e) => e.status === "ACTIVE").length, [G]), q = f(() => {
|
|
202
|
+
let e = M(G, (e) => e.status);
|
|
203
|
+
return re.filter((t) => (e.get(t) ?? 0) > 0).map((t) => ({
|
|
204
|
+
label: s(t),
|
|
205
|
+
value: e.get(t) ?? 0,
|
|
206
|
+
color: O(t)
|
|
207
|
+
}));
|
|
208
|
+
}, [G]), J = f(() => F.data?.items ?? [], [F.data]), Y = F.data?.totalCount ?? 0, ae = f(() => J.filter((e) => e.status === "PUBLISHED").length, [J]), oe = f(() => J.length === 0 ? 0 : J.reduce((e, t) => e + t.score, 0) / J.length, [J]), se = f(() => J.reduce((e, t) => e + (t.helpfulCount ?? 0), 0), [J]), X = f(() => [...M(J, (e) => String(e.score)).entries()].sort((e, t) => Number(e[0]) - Number(t[0])).map(([e, t]) => ({
|
|
209
|
+
label: `${e} ★`,
|
|
210
|
+
value: t,
|
|
211
|
+
color: "var(--color-accent-primary)"
|
|
212
|
+
})), [J]), Z = L?.currency ?? "USD", Q = f(() => (R.data?.categoryBreakdown ?? []).filter((e) => e.amount > 0).sort((e, t) => t.amount - e.amount).map((e, t) => ({
|
|
213
|
+
label: s(e.category),
|
|
214
|
+
value: e.amount,
|
|
215
|
+
color: E[t % E.length]
|
|
216
|
+
})), [R.data]);
|
|
217
|
+
if (D.isLoading) return /* @__PURE__ */ S(e, {
|
|
218
|
+
title: "Studio Analytics",
|
|
219
|
+
description: "Performance across your catalog",
|
|
220
|
+
children: /* @__PURE__ */ S(d, { label: "Loading analytics…" })
|
|
221
|
+
});
|
|
222
|
+
if (D.isError) return /* @__PURE__ */ S(e, {
|
|
223
|
+
title: "Studio Analytics",
|
|
224
|
+
description: "Performance across your catalog",
|
|
225
|
+
children: /* @__PURE__ */ S(u, {
|
|
226
|
+
message: "We couldn't load your catalog analytics.",
|
|
227
|
+
onRetry: () => void D.refetch()
|
|
228
|
+
})
|
|
229
|
+
});
|
|
230
|
+
let ce = B > z.length ? `Distribution across the ${c(z.length)} most recent of ${c(B)} titles` : void 0, $ = K > G.length ? `${c(G.length)} of ${c(K)} windows` : void 0, le = Y > J.length ? `${c(J.length)} of ${c(Y)} reviews` : void 0, ue = !!L && !!R.data && (R.data.totalLifetimeAmount > 0 || Q.length > 0);
|
|
231
|
+
return /* @__PURE__ */ S(e, {
|
|
232
|
+
title: "Studio Analytics",
|
|
233
|
+
description: "Catalog health, community signal & revenue — from live data",
|
|
234
|
+
purpose: "A single view of how your studio is performing: what's in the catalog and its publishing pipeline, how the community is reviewing it, and what it's earning. Every figure here is read live from the platform — nothing is estimated.",
|
|
235
|
+
children: /* @__PURE__ */ C("div", {
|
|
236
|
+
className: "space-y-10",
|
|
237
|
+
children: [
|
|
238
|
+
/* @__PURE__ */ C(k, {
|
|
239
|
+
icon: /* @__PURE__ */ S(h, { className: "h-5 w-5" }),
|
|
240
|
+
title: "Catalog Health",
|
|
241
|
+
hint: ce,
|
|
242
|
+
children: [
|
|
243
|
+
/* @__PURE__ */ C("div", {
|
|
244
|
+
className: "grid grid-cols-2 gap-4 lg:grid-cols-4",
|
|
245
|
+
children: [
|
|
246
|
+
/* @__PURE__ */ S(t, {
|
|
247
|
+
icon: /* @__PURE__ */ S(h, { className: "h-5 w-5" }),
|
|
248
|
+
value: c(B),
|
|
249
|
+
label: "Total Titles",
|
|
250
|
+
featured: !0
|
|
251
|
+
}),
|
|
252
|
+
/* @__PURE__ */ S(t, {
|
|
253
|
+
icon: /* @__PURE__ */ S(b, { className: "h-5 w-5" }),
|
|
254
|
+
value: c(V),
|
|
255
|
+
label: "Published (loaded)"
|
|
256
|
+
}),
|
|
257
|
+
/* @__PURE__ */ S(t, {
|
|
258
|
+
icon: /* @__PURE__ */ S(ee, { className: "h-5 w-5" }),
|
|
259
|
+
value: c(H),
|
|
260
|
+
label: "In Pipeline (loaded)"
|
|
261
|
+
}),
|
|
262
|
+
/* @__PURE__ */ S(t, {
|
|
263
|
+
icon: /* @__PURE__ */ S(_, { className: "h-5 w-5" }),
|
|
264
|
+
value: c(ie),
|
|
265
|
+
label: "Active Rights Windows"
|
|
266
|
+
})
|
|
267
|
+
]
|
|
268
|
+
}),
|
|
269
|
+
/* @__PURE__ */ C("div", {
|
|
270
|
+
className: "grid grid-cols-1 gap-4 lg:grid-cols-2",
|
|
271
|
+
children: [/* @__PURE__ */ C(w, {
|
|
272
|
+
treatment: "metric",
|
|
273
|
+
className: "border-border-seam p-5",
|
|
274
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
275
|
+
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
276
|
+
children: "Titles by Status"
|
|
277
|
+
}), U.length > 0 ? /* @__PURE__ */ S(A, {
|
|
278
|
+
segments: U,
|
|
279
|
+
ariaLabel: "Titles by status"
|
|
280
|
+
}) : /* @__PURE__ */ S("p", {
|
|
281
|
+
className: "py-8 text-center text-sm text-text-secondary",
|
|
282
|
+
children: "No titles yet."
|
|
283
|
+
})]
|
|
284
|
+
}), /* @__PURE__ */ C(w, {
|
|
285
|
+
treatment: "metric",
|
|
286
|
+
className: "border-border-seam p-5",
|
|
287
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
288
|
+
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
289
|
+
children: "Titles by Type"
|
|
290
|
+
}), W.length > 0 ? /* @__PURE__ */ S(A, {
|
|
291
|
+
segments: W,
|
|
292
|
+
ariaLabel: "Titles by content type"
|
|
293
|
+
}) : /* @__PURE__ */ S("p", {
|
|
294
|
+
className: "py-8 text-center text-sm text-text-secondary",
|
|
295
|
+
children: "No titles yet."
|
|
296
|
+
})]
|
|
297
|
+
})]
|
|
298
|
+
}),
|
|
299
|
+
/* @__PURE__ */ C(w, {
|
|
300
|
+
treatment: "metric",
|
|
301
|
+
className: "border-border-seam p-5",
|
|
302
|
+
children: [/* @__PURE__ */ C("div", {
|
|
303
|
+
className: "mb-4 flex items-center justify-between",
|
|
304
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
305
|
+
className: "text-sm font-semibold text-text-primary",
|
|
306
|
+
children: "Rights Windows by Status"
|
|
307
|
+
}), $ && /* @__PURE__ */ S("span", {
|
|
308
|
+
className: "text-xs text-text-muted",
|
|
309
|
+
children: $
|
|
310
|
+
})]
|
|
311
|
+
}), q.length > 0 ? /* @__PURE__ */ S(A, {
|
|
312
|
+
segments: q,
|
|
313
|
+
ariaLabel: "Rights windows by status"
|
|
314
|
+
}) : /* @__PURE__ */ S("p", {
|
|
315
|
+
className: "py-8 text-center text-sm text-text-secondary",
|
|
316
|
+
children: "No rights windows defined yet."
|
|
317
|
+
})]
|
|
318
|
+
})
|
|
319
|
+
]
|
|
320
|
+
}),
|
|
321
|
+
/* @__PURE__ */ C(k, {
|
|
322
|
+
icon: /* @__PURE__ */ S(v, { className: "h-5 w-5" }),
|
|
323
|
+
title: "Community Engagement",
|
|
324
|
+
hint: le,
|
|
325
|
+
children: [/* @__PURE__ */ C("div", {
|
|
326
|
+
className: "grid grid-cols-2 gap-4 lg:grid-cols-4",
|
|
327
|
+
children: [
|
|
328
|
+
/* @__PURE__ */ S(t, {
|
|
329
|
+
icon: /* @__PURE__ */ S(v, { className: "h-5 w-5" }),
|
|
330
|
+
value: c(Y),
|
|
331
|
+
label: "Total Reviews"
|
|
332
|
+
}),
|
|
333
|
+
/* @__PURE__ */ S(t, {
|
|
334
|
+
icon: /* @__PURE__ */ S(b, { className: "h-5 w-5" }),
|
|
335
|
+
value: c(ae),
|
|
336
|
+
label: "Published (loaded)"
|
|
337
|
+
}),
|
|
338
|
+
/* @__PURE__ */ S(t, {
|
|
339
|
+
icon: /* @__PURE__ */ S(m, { className: "h-5 w-5" }),
|
|
340
|
+
value: J.length > 0 ? oe.toFixed(1) : "—",
|
|
341
|
+
label: "Avg Score (loaded)"
|
|
342
|
+
}),
|
|
343
|
+
/* @__PURE__ */ S(t, {
|
|
344
|
+
icon: /* @__PURE__ */ S(y, { className: "h-5 w-5" }),
|
|
345
|
+
value: c(se),
|
|
346
|
+
label: "Helpful Votes"
|
|
347
|
+
})
|
|
348
|
+
]
|
|
349
|
+
}), /* @__PURE__ */ C(w, {
|
|
350
|
+
treatment: "metric",
|
|
351
|
+
className: "border-border-seam p-5",
|
|
352
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
353
|
+
className: "mb-4 text-sm font-semibold text-text-primary",
|
|
354
|
+
children: "Score Distribution"
|
|
355
|
+
}), X.length > 0 ? /* @__PURE__ */ S(A, {
|
|
356
|
+
segments: X,
|
|
357
|
+
ariaLabel: "Review score distribution",
|
|
358
|
+
valueSuffix: "reviews"
|
|
359
|
+
}) : /* @__PURE__ */ S(l, {
|
|
360
|
+
icon: /* @__PURE__ */ S(v, { className: "h-10 w-10" }),
|
|
361
|
+
title: "No reviews yet",
|
|
362
|
+
description: "Once audiences start rating your titles, the score distribution will appear here."
|
|
363
|
+
})]
|
|
364
|
+
})]
|
|
365
|
+
}),
|
|
366
|
+
/* @__PURE__ */ S(k, {
|
|
367
|
+
icon: /* @__PURE__ */ S(x, { className: "h-5 w-5" }),
|
|
368
|
+
title: "Revenue",
|
|
369
|
+
children: I.isLoading || L && R.isLoading ? /* @__PURE__ */ S(d, { label: "Loading revenue…" }) : L ? R.isError ? /* @__PURE__ */ S(u, {
|
|
370
|
+
message: "We couldn't load revenue for this account.",
|
|
371
|
+
onRetry: () => void R.refetch()
|
|
372
|
+
}) : /* @__PURE__ */ C(te, { children: [/* @__PURE__ */ C("div", {
|
|
373
|
+
className: "grid grid-cols-2 gap-4 lg:grid-cols-4",
|
|
374
|
+
children: [
|
|
375
|
+
/* @__PURE__ */ S(t, {
|
|
376
|
+
icon: /* @__PURE__ */ S(x, { className: "h-5 w-5" }),
|
|
377
|
+
value: N(R.data?.totalLifetimeAmount ?? 0, Z),
|
|
378
|
+
label: "Lifetime Earnings",
|
|
379
|
+
featured: !0
|
|
380
|
+
}),
|
|
381
|
+
/* @__PURE__ */ S(t, {
|
|
382
|
+
icon: /* @__PURE__ */ S(b, { className: "h-5 w-5" }),
|
|
383
|
+
value: N(R.data?.availableAmount ?? 0, Z),
|
|
384
|
+
label: "Available"
|
|
385
|
+
}),
|
|
386
|
+
/* @__PURE__ */ S(t, {
|
|
387
|
+
icon: /* @__PURE__ */ S(m, { className: "h-5 w-5" }),
|
|
388
|
+
value: N(R.data?.paidAmount ?? 0, Z),
|
|
389
|
+
label: "Paid Out"
|
|
390
|
+
}),
|
|
391
|
+
/* @__PURE__ */ S(t, {
|
|
392
|
+
icon: /* @__PURE__ */ S(p, { className: "h-5 w-5" }),
|
|
393
|
+
value: N(R.data?.pendingAmount ?? 0, Z),
|
|
394
|
+
label: "Pending"
|
|
395
|
+
})
|
|
396
|
+
]
|
|
397
|
+
}), /* @__PURE__ */ C(w, {
|
|
398
|
+
treatment: "metric",
|
|
399
|
+
className: "border-border-seam p-5",
|
|
400
|
+
children: [/* @__PURE__ */ C("div", {
|
|
401
|
+
className: "mb-4 flex items-center gap-2",
|
|
402
|
+
children: [/* @__PURE__ */ S(g, {
|
|
403
|
+
className: "h-4 w-4 text-text-secondary",
|
|
404
|
+
"aria-hidden": "true"
|
|
405
|
+
}), /* @__PURE__ */ S("h3", {
|
|
406
|
+
className: "text-sm font-semibold text-text-primary",
|
|
407
|
+
children: "Earnings by Category"
|
|
408
|
+
})]
|
|
409
|
+
}), ue && Q.length > 0 ? /* @__PURE__ */ S(j, {
|
|
410
|
+
segments: Q,
|
|
411
|
+
centerLabel: N(R.data?.totalLifetimeAmount ?? 0, Z),
|
|
412
|
+
centerSub: "lifetime",
|
|
413
|
+
ariaLabel: "Earnings by category",
|
|
414
|
+
formatValue: (e) => N(e, Z)
|
|
415
|
+
}) : /* @__PURE__ */ S(l, {
|
|
416
|
+
icon: /* @__PURE__ */ S(g, { className: "h-10 w-10" }),
|
|
417
|
+
title: "No earnings yet",
|
|
418
|
+
description: "Revenue from purchases, rentals and subscriptions will break down by category here."
|
|
419
|
+
})]
|
|
420
|
+
})] }) : /* @__PURE__ */ S(w, {
|
|
421
|
+
treatment: "metric",
|
|
422
|
+
className: "border-border-seam p-5",
|
|
423
|
+
children: /* @__PURE__ */ S(l, {
|
|
424
|
+
icon: /* @__PURE__ */ S(x, { className: "h-10 w-10" }),
|
|
425
|
+
title: "No billing account connected",
|
|
426
|
+
description: "Connect a billing account to track title purchases, rentals and creator earnings here."
|
|
427
|
+
})
|
|
428
|
+
})
|
|
429
|
+
}),
|
|
430
|
+
/* @__PURE__ */ S(k, {
|
|
431
|
+
icon: /* @__PURE__ */ S(p, { className: "h-5 w-5" }),
|
|
432
|
+
title: "Audience & Playback",
|
|
433
|
+
children: /* @__PURE__ */ S(w, {
|
|
434
|
+
treatment: "metric",
|
|
435
|
+
className: "border-border-seam p-5",
|
|
436
|
+
children: /* @__PURE__ */ S(l, {
|
|
437
|
+
icon: /* @__PURE__ */ S(p, { className: "h-10 w-10" }),
|
|
438
|
+
title: "No audience telemetry yet",
|
|
439
|
+
description: "Studio-wide viewership and engagement metrics (plays, watch-time, completion) will appear here once the platform activity & usage feeds are connected to this workspace. We don't show estimated figures."
|
|
440
|
+
})
|
|
441
|
+
})
|
|
442
|
+
})
|
|
443
|
+
]
|
|
444
|
+
})
|
|
445
|
+
});
|
|
446
|
+
};
|
|
447
|
+
//#endregion
|
|
448
|
+
export { P as AnalyticsPage };
|
|
449
|
+
|
|
450
|
+
//# sourceMappingURL=AnalyticsPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsPage.js","names":[],"sources":["../../../../src/hookmovies/pages/analytics/AnalyticsPage.tsx"],"sourcesContent":["/**\n * Studio Analytics (creator / operator performance dashboard)\n * @module hookmovies/pages/analytics\n *\n * A studio-facing analytics surface built entirely on live data:\n * - Catalog health → `hokListTitles` / `hokListRightsWindows` (`totalCount`\n * for headline counts + status/type distributions bucketed\n * from the loaded page).\n * - Community signal → `hokListReviews` (review volume, average score, helpful\n * votes and score distribution).\n * - Revenue → global-billing earnings summary for the caller's default\n * billing account (lifetime / available / paid / pending +\n * a category split donut).\n *\n * There are NO fabricated numbers. Where a real source is not yet wired for this\n * workspace (studio-wide audience / playback telemetry from the platform\n * activity + usage services is not exposed to this MFE's data layer yet), the\n * section renders an honest \"no data yet\" state rather than inventing figures.\n */\n\nimport { type FC, type ReactNode, useMemo } from 'react';\nimport {\n BarChart3,\n Film,\n Layers,\n ScrollText,\n Star,\n ThumbsUp,\n Wallet,\n PieChart as PieChartIcon,\n Activity,\n TrendingUp,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/StateViews';\nimport {\n useTitles,\n useRightsWindows,\n useReviews,\n useMyBillingAccounts,\n useMyEarningsSummary,\n type HokTitle,\n type HokRightsWindow,\n type HokReview,\n type HokTitleStatus,\n type HokRightsWindowStatus,\n} from '../../hooks/useHookMoviesApi';\nimport { formatNumber, formatEnumLabel } from '../../utils/formatters';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/** Page size used for the distribution reads. Studio catalogs are bounded; a\n * single generous page yields exact distributions for most workspaces and a\n * clearly-labelled sample for very large ones. */\nconst SAMPLE_PAGE = { limit: 200, offset: 0 };\n\n/** Tokenised categorical series palette (CSS variables — never raw colours). */\nconst SERIES_COLORS = [\n 'var(--color-accent-primary)',\n 'var(--color-accent-teal)',\n 'var(--color-accent-blue)',\n 'var(--color-accent-indigo)',\n 'var(--color-accent-purple)',\n 'var(--color-accent-secondary)',\n 'var(--color-accent-soft)',\n] as const;\n\n/** Map a catalog/rights status to a semantic status colour (CSS variable). */\nconst STATUS_COLOR: Record<string, string> = {\n // Title statuses\n draft: 'var(--color-text-muted)',\n in_review: 'var(--color-status-warning-text)',\n scheduled: 'var(--color-status-info-text)',\n published: 'var(--color-status-success-text)',\n unpublished: 'var(--color-text-muted)',\n archived: 'var(--color-text-muted)',\n // Rights-window statuses\n pending: 'var(--color-status-warning-text)',\n active: 'var(--color-status-success-text)',\n expired: 'var(--color-text-muted)',\n revoked: 'var(--color-status-error-text)',\n};\n\nconst statusColor = (status: string): string =>\n STATUS_COLOR[status.toLowerCase()] ?? 'var(--color-text-muted)';\n\n// ============================================================================\n// Small inline viz kit (tokenised, responsive, a11y)\n// ============================================================================\n\ninterface Segment {\n label: string;\n value: number;\n color: string;\n}\n\n/** A labelled section container with an icon-led heading. */\nconst Section: FC<{ icon: ReactNode; title: string; hint?: string; children: ReactNode }> = ({\n icon,\n title,\n hint,\n children,\n}) => (\n <section className=\"space-y-4\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-text-secondary\" aria-hidden=\"true\">\n {icon}\n </span>\n <h2 className=\"text-lg font-semibold text-text-primary\">{title}</h2>\n {hint && <span className=\"ml-auto text-xs text-text-muted\">{hint}</span>}\n </div>\n {children}\n </section>\n);\n\n/**\n * Horizontal distribution bars. Simple, responsive and screen-reader friendly:\n * the whole chart is a labelled list, each row exposes its value via `aria`.\n */\nconst DistributionBars: FC<{\n segments: Segment[];\n ariaLabel: string;\n valueSuffix?: string;\n}> = ({ segments, ariaLabel, valueSuffix }) => {\n const max = Math.max(1, ...segments.map((s) => s.value));\n return (\n <ul className=\"space-y-3\" aria-label={ariaLabel}>\n {segments.map((s) => {\n const pct = Math.round((s.value / max) * 100);\n return (\n <li key={s.label} className=\"flex items-center gap-3\">\n <span className=\"w-28 shrink-0 truncate text-xs text-text-secondary sm:w-36\">\n {s.label}\n </span>\n <div className=\"relative h-2.5 flex-1 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"absolute inset-y-0 left-0 rounded-full\"\n style={{ width: `${pct}%`, backgroundColor: s.color }}\n role=\"img\"\n aria-label={`${s.label}: ${formatNumber(s.value)}${valueSuffix ? ` ${valueSuffix}` : ''}`}\n />\n </div>\n <span className=\"w-12 shrink-0 text-right text-xs font-medium tabular-nums text-text-primary\">\n {formatNumber(s.value)}\n </span>\n </li>\n );\n })}\n </ul>\n );\n};\n\n/**\n * Tokenised SVG donut for a categorical split. Renders as a single\n * `role=\"img\"` graphic with a descriptive label; an adjacent legend carries the\n * per-segment breakdown for sighted and assistive-tech users alike.\n */\nconst DonutChart: FC<{\n segments: Segment[];\n centerLabel: string;\n centerSub: string;\n ariaLabel: string;\n formatValue: (value: number) => string;\n}> = ({ segments, centerLabel, centerSub, ariaLabel, formatValue }) => {\n const total = segments.reduce((sum, s) => sum + s.value, 0);\n const radius = 42;\n const circumference = 2 * Math.PI * radius;\n let offset = 0;\n\n return (\n <div className=\"flex flex-col items-center gap-6 sm:flex-row sm:items-center\">\n <div className=\"relative shrink-0\">\n <svg\n viewBox=\"0 0 120 120\"\n className=\"h-40 w-40 -rotate-90\"\n role=\"img\"\n aria-label={ariaLabel}\n >\n <circle\n cx=\"60\"\n cy=\"60\"\n r={radius}\n fill=\"none\"\n stroke=\"var(--color-bg-sunken)\"\n strokeWidth=\"14\"\n />\n {total > 0 &&\n segments.map((s) => {\n const fraction = s.value / total;\n const dash = fraction * circumference;\n const segment = (\n <circle\n key={s.label}\n cx=\"60\"\n cy=\"60\"\n r={radius}\n fill=\"none\"\n stroke={s.color}\n strokeWidth=\"14\"\n strokeDasharray={`${dash} ${circumference - dash}`}\n strokeDashoffset={-offset}\n strokeLinecap=\"butt\"\n >\n <title>{`${s.label}: ${formatValue(s.value)}`}</title>\n </circle>\n );\n offset += dash;\n return segment;\n })}\n </svg>\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center\">\n <span className=\"text-lg font-bold tabular-nums text-text-primary\">{centerLabel}</span>\n <span className=\"text-[11px] text-text-secondary\">{centerSub}</span>\n </div>\n </div>\n <ul className=\"w-full space-y-2\">\n {segments.map((s) => (\n <li key={s.label} className=\"flex items-center gap-2 text-sm\">\n <span\n className=\"size-2.5 shrink-0 rounded-full\"\n style={{ backgroundColor: s.color }}\n aria-hidden=\"true\"\n />\n <span className=\"min-w-0 flex-1 truncate text-text-secondary\">{s.label}</span>\n <span className=\"shrink-0 font-medium tabular-nums text-text-primary\">\n {formatValue(s.value)}\n </span>\n </li>\n ))}\n </ul>\n </div>\n );\n};\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Count occurrences of `keyFn(item)` across a list, preserving insertion. */\nfunction tally<T>(items: T[], keyFn: (item: T) => string): Map<string, number> {\n const map = new Map<string, number>();\n for (const item of items) {\n const key = keyFn(item);\n map.set(key, (map.get(key) ?? 0) + 1);\n }\n return map;\n}\n\n/** Format money in the billing account's currency (falls back gracefully). */\nfunction formatMoney(amount: number, currency: string): string {\n try {\n return new Intl.NumberFormat(undefined, {\n style: 'currency',\n currency,\n maximumFractionDigits: 2,\n }).format(amount);\n } catch {\n return `${amount.toFixed(2)} ${currency}`;\n }\n}\n\nconst TITLE_STATUS_ORDER: HokTitleStatus[] = [\n 'DRAFT',\n 'IN_REVIEW',\n 'SCHEDULED',\n 'PUBLISHED',\n 'UNPUBLISHED',\n 'ARCHIVED',\n];\n\nconst RIGHTS_STATUS_ORDER: HokRightsWindowStatus[] = [\n 'DRAFT',\n 'PENDING',\n 'ACTIVE',\n 'EXPIRED',\n 'REVOKED',\n];\n\n// ============================================================================\n// Page\n// ============================================================================\n\nexport const AnalyticsPage: FC = () => {\n const titles = useTitles({}, SAMPLE_PAGE);\n const rights = useRightsWindows({}, SAMPLE_PAGE);\n const reviews = useReviews({}, SAMPLE_PAGE);\n const billingAccounts = useMyBillingAccounts();\n\n const defaultAccount = useMemo(() => {\n const accounts = billingAccounts.data ?? [];\n return accounts.find((a) => a.isDefault) ?? accounts[0];\n }, [billingAccounts.data]);\n\n const earnings = useMyEarningsSummary(defaultAccount?.id);\n\n // ---- Catalog health (real: hokListTitles) --------------------------------\n const titleItems: HokTitle[] = useMemo(() => titles.data?.items ?? [], [titles.data]);\n const titleTotal = titles.data?.totalCount ?? 0;\n\n const publishedCount = useMemo(\n () => titleItems.filter((t) => t.status === 'PUBLISHED').length,\n [titleItems]\n );\n const pipelineCount = useMemo(\n () =>\n titleItems.filter(\n (t) => t.status === 'DRAFT' || t.status === 'IN_REVIEW' || t.status === 'SCHEDULED'\n ).length,\n [titleItems]\n );\n\n const titlesByStatus: Segment[] = useMemo(() => {\n const counts = tally(titleItems, (t) => t.status);\n return TITLE_STATUS_ORDER.filter((s) => (counts.get(s) ?? 0) > 0).map((s) => ({\n label: formatEnumLabel(s),\n value: counts.get(s) ?? 0,\n color: statusColor(s),\n }));\n }, [titleItems]);\n\n const titlesByType: Segment[] = useMemo(() => {\n const counts = tally(titleItems, (t) => t.type);\n return [...counts.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([type, value], i) => ({\n label: formatEnumLabel(type),\n value,\n color: SERIES_COLORS[i % SERIES_COLORS.length],\n }));\n }, [titleItems]);\n\n // ---- Rights health (real: hokListRightsWindows) --------------------------\n const rightsItems: HokRightsWindow[] = useMemo(() => rights.data?.items ?? [], [rights.data]);\n const rightsTotal = rights.data?.totalCount ?? 0;\n const activeRights = useMemo(\n () => rightsItems.filter((r) => r.status === 'ACTIVE').length,\n [rightsItems]\n );\n const rightsByStatus: Segment[] = useMemo(() => {\n const counts = tally(rightsItems, (r) => r.status);\n return RIGHTS_STATUS_ORDER.filter((s) => (counts.get(s) ?? 0) > 0).map((s) => ({\n label: formatEnumLabel(s),\n value: counts.get(s) ?? 0,\n color: statusColor(s),\n }));\n }, [rightsItems]);\n\n // ---- Community engagement (real: hokListReviews) -------------------------\n const reviewItems: HokReview[] = useMemo(() => reviews.data?.items ?? [], [reviews.data]);\n const reviewTotal = reviews.data?.totalCount ?? 0;\n const publishedReviews = useMemo(\n () => reviewItems.filter((r) => r.status === 'PUBLISHED').length,\n [reviewItems]\n );\n const avgScore = useMemo(() => {\n if (reviewItems.length === 0) return 0;\n const sum = reviewItems.reduce((acc, r) => acc + r.score, 0);\n return sum / reviewItems.length;\n }, [reviewItems]);\n const helpfulVotes = useMemo(\n () => reviewItems.reduce((acc, r) => acc + (r.helpfulCount ?? 0), 0),\n [reviewItems]\n );\n const reviewsByScore: Segment[] = useMemo(() => {\n const counts = tally(reviewItems, (r) => String(r.score));\n return [...counts.entries()]\n .sort((a, b) => Number(a[0]) - Number(b[0]))\n .map(([score, value]) => ({\n label: `${score} ★`,\n value,\n color: 'var(--color-accent-primary)',\n }));\n }, [reviewItems]);\n\n // ---- Revenue (real: global-billing earnings summary) ---------------------\n const currency = defaultAccount?.currency ?? 'USD';\n const revenueSegments: Segment[] = useMemo(() => {\n const breakdown = earnings.data?.categoryBreakdown ?? [];\n return breakdown\n .filter((c) => c.amount > 0)\n .sort((a, b) => b.amount - a.amount)\n .map((c, i) => ({\n label: formatEnumLabel(c.category),\n value: c.amount,\n color: SERIES_COLORS[i % SERIES_COLORS.length],\n }));\n }, [earnings.data]);\n\n // ---- Page-level async gating (catalog is the primary read) ---------------\n if (titles.isLoading) {\n return (\n <PageLayout title=\"Studio Analytics\" description=\"Performance across your catalog\">\n <LoadingState label=\"Loading analytics…\" />\n </PageLayout>\n );\n }\n if (titles.isError) {\n return (\n <PageLayout title=\"Studio Analytics\" description=\"Performance across your catalog\">\n <ErrorState\n message=\"We couldn't load your catalog analytics.\"\n onRetry={() => void titles.refetch()}\n />\n </PageLayout>\n );\n }\n\n const catalogSampleHint =\n titleTotal > titleItems.length\n ? `Distribution across the ${formatNumber(titleItems.length)} most recent of ${formatNumber(titleTotal)} titles`\n : undefined;\n const rightsSampleHint =\n rightsTotal > rightsItems.length\n ? `${formatNumber(rightsItems.length)} of ${formatNumber(rightsTotal)} windows`\n : undefined;\n const reviewSampleHint =\n reviewTotal > reviewItems.length\n ? `${formatNumber(reviewItems.length)} of ${formatNumber(reviewTotal)} reviews`\n : undefined;\n\n const hasRevenue =\n !!defaultAccount &&\n !!earnings.data &&\n (earnings.data.totalLifetimeAmount > 0 || revenueSegments.length > 0);\n\n return (\n <PageLayout\n title=\"Studio Analytics\"\n description=\"Catalog health, community signal & revenue — from live data\"\n purpose=\"A single view of how your studio is performing: what's in the catalog and its publishing pipeline, how the community is reviewing it, and what it's earning. Every figure here is read live from the platform — nothing is estimated.\"\n >\n <div className=\"space-y-10\">\n {/* ---- Catalog health ------------------------------------------- */}\n <Section\n icon={<Film className=\"h-5 w-5\" />}\n title=\"Catalog Health\"\n hint={catalogSampleHint}\n >\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <MetricsCard\n icon={<Film className=\"h-5 w-5\" />}\n value={formatNumber(titleTotal)}\n label=\"Total Titles\"\n featured\n />\n <MetricsCard\n icon={<TrendingUp className=\"h-5 w-5\" />}\n value={formatNumber(publishedCount)}\n label=\"Published (loaded)\"\n />\n <MetricsCard\n icon={<Layers className=\"h-5 w-5\" />}\n value={formatNumber(pipelineCount)}\n label=\"In Pipeline (loaded)\"\n />\n <MetricsCard\n icon={<ScrollText className=\"h-5 w-5\" />}\n value={formatNumber(activeRights)}\n label=\"Active Rights Windows\"\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">Titles by Status</h3>\n {titlesByStatus.length > 0 ? (\n <DistributionBars segments={titlesByStatus} ariaLabel=\"Titles by status\" />\n ) : (\n <p className=\"py-8 text-center text-sm text-text-secondary\">No titles yet.</p>\n )}\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">Titles by Type</h3>\n {titlesByType.length > 0 ? (\n <DistributionBars segments={titlesByType} ariaLabel=\"Titles by content type\" />\n ) : (\n <p className=\"py-8 text-center text-sm text-text-secondary\">No titles yet.</p>\n )}\n </GlassCard>\n </div>\n\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h3 className=\"text-sm font-semibold text-text-primary\">Rights Windows by Status</h3>\n {rightsSampleHint && (\n <span className=\"text-xs text-text-muted\">{rightsSampleHint}</span>\n )}\n </div>\n {rightsByStatus.length > 0 ? (\n <DistributionBars segments={rightsByStatus} ariaLabel=\"Rights windows by status\" />\n ) : (\n <p className=\"py-8 text-center text-sm text-text-secondary\">\n No rights windows defined yet.\n </p>\n )}\n </GlassCard>\n </Section>\n\n {/* ---- Community engagement ------------------------------------- */}\n <Section\n icon={<Star className=\"h-5 w-5\" />}\n title=\"Community Engagement\"\n hint={reviewSampleHint}\n >\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <MetricsCard\n icon={<Star className=\"h-5 w-5\" />}\n value={formatNumber(reviewTotal)}\n label=\"Total Reviews\"\n />\n <MetricsCard\n icon={<TrendingUp className=\"h-5 w-5\" />}\n value={formatNumber(publishedReviews)}\n label=\"Published (loaded)\"\n />\n <MetricsCard\n icon={<BarChart3 className=\"h-5 w-5\" />}\n value={reviewItems.length > 0 ? avgScore.toFixed(1) : '—'}\n label=\"Avg Score (loaded)\"\n />\n <MetricsCard\n icon={<ThumbsUp className=\"h-5 w-5\" />}\n value={formatNumber(helpfulVotes)}\n label=\"Helpful Votes\"\n />\n </div>\n\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h3 className=\"mb-4 text-sm font-semibold text-text-primary\">Score Distribution</h3>\n {reviewsByScore.length > 0 ? (\n <DistributionBars\n segments={reviewsByScore}\n ariaLabel=\"Review score distribution\"\n valueSuffix=\"reviews\"\n />\n ) : (\n <EmptyState\n icon={<Star className=\"h-10 w-10\" />}\n title=\"No reviews yet\"\n description=\"Once audiences start rating your titles, the score distribution will appear here.\"\n />\n )}\n </GlassCard>\n </Section>\n\n {/* ---- Revenue -------------------------------------------------- */}\n <Section icon={<Wallet className=\"h-5 w-5\" />} title=\"Revenue\">\n {billingAccounts.isLoading || (defaultAccount && earnings.isLoading) ? (\n <LoadingState label=\"Loading revenue…\" />\n ) : !defaultAccount ? (\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <EmptyState\n icon={<Wallet className=\"h-10 w-10\" />}\n title=\"No billing account connected\"\n description=\"Connect a billing account to track title purchases, rentals and creator earnings here.\"\n />\n </GlassCard>\n ) : earnings.isError ? (\n <ErrorState\n message=\"We couldn't load revenue for this account.\"\n onRetry={() => void earnings.refetch()}\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <MetricsCard\n icon={<Wallet className=\"h-5 w-5\" />}\n value={formatMoney(earnings.data?.totalLifetimeAmount ?? 0, currency)}\n label=\"Lifetime Earnings\"\n featured\n />\n <MetricsCard\n icon={<TrendingUp className=\"h-5 w-5\" />}\n value={formatMoney(earnings.data?.availableAmount ?? 0, currency)}\n label=\"Available\"\n />\n <MetricsCard\n icon={<BarChart3 className=\"h-5 w-5\" />}\n value={formatMoney(earnings.data?.paidAmount ?? 0, currency)}\n label=\"Paid Out\"\n />\n <MetricsCard\n icon={<Activity className=\"h-5 w-5\" />}\n value={formatMoney(earnings.data?.pendingAmount ?? 0, currency)}\n label=\"Pending\"\n />\n </div>\n\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <div className=\"mb-4 flex items-center gap-2\">\n <PieChartIcon className=\"h-4 w-4 text-text-secondary\" aria-hidden=\"true\" />\n <h3 className=\"text-sm font-semibold text-text-primary\">Earnings by Category</h3>\n </div>\n {hasRevenue && revenueSegments.length > 0 ? (\n <DonutChart\n segments={revenueSegments}\n centerLabel={formatMoney(earnings.data?.totalLifetimeAmount ?? 0, currency)}\n centerSub=\"lifetime\"\n ariaLabel=\"Earnings by category\"\n formatValue={(v) => formatMoney(v, currency)}\n />\n ) : (\n <EmptyState\n icon={<PieChartIcon className=\"h-10 w-10\" />}\n title=\"No earnings yet\"\n description=\"Revenue from purchases, rentals and subscriptions will break down by category here.\"\n />\n )}\n </GlassCard>\n </>\n )}\n </Section>\n\n {/* ---- Audience & playback (no real source wired yet) ----------- */}\n <Section icon={<Activity className=\"h-5 w-5\" />} title=\"Audience & Playback\">\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <EmptyState\n icon={<Activity className=\"h-10 w-10\" />}\n title=\"No audience telemetry yet\"\n description=\"Studio-wide viewership and engagement metrics (plays, watch-time, completion) will appear here once the platform activity & usage feeds are connected to this workspace. We don't show estimated figures.\"\n />\n </GlassCard>\n </Section>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|