@burdenoff/microfe-atheletebridge 2026.705.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.
Files changed (101) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.js +55 -39
  2. package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
  3. package/dist/atheletebridge/AthleteBridgeRoutes.js +18 -6
  4. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  5. package/dist/atheletebridge/components/Crest.js +70 -0
  6. package/dist/atheletebridge/components/Crest.js.map +1 -0
  7. package/dist/atheletebridge/components/FixtureCard.js +8 -72
  8. package/dist/atheletebridge/components/FixtureCard.js.map +1 -1
  9. package/dist/atheletebridge/components/MatchupRow.js +74 -0
  10. package/dist/atheletebridge/components/MatchupRow.js.map +1 -0
  11. package/dist/atheletebridge/components/MetricsCard.js +61 -21
  12. package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
  13. package/dist/atheletebridge/components/ProgramCard.js +75 -43
  14. package/dist/atheletebridge/components/ProgramCard.js.map +1 -1
  15. package/dist/atheletebridge/components/Scoreboard.js +163 -0
  16. package/dist/atheletebridge/components/Scoreboard.js.map +1 -0
  17. package/dist/atheletebridge/components/SessionCard.js +64 -41
  18. package/dist/atheletebridge/components/SessionCard.js.map +1 -1
  19. package/dist/atheletebridge/components/SessionStatusTimeline.js +80 -0
  20. package/dist/atheletebridge/components/SessionStatusTimeline.js.map +1 -0
  21. package/dist/atheletebridge/components/StatusBadge.js +5 -5
  22. package/dist/atheletebridge/components/StatusBadge.js.map +1 -1
  23. package/dist/atheletebridge/components/TeamCard.js +65 -35
  24. package/dist/atheletebridge/components/TeamCard.js.map +1 -1
  25. package/dist/atheletebridge/components/UserAvatar.js +33 -0
  26. package/dist/atheletebridge/components/UserAvatar.js.map +1 -0
  27. package/dist/atheletebridge/components/domain.js +5 -2
  28. package/dist/atheletebridge/components/domain.js.map +1 -1
  29. package/dist/atheletebridge/components/viz/AvatarStack.js +2 -0
  30. package/dist/atheletebridge/components/viz/BarChart.js +83 -0
  31. package/dist/atheletebridge/components/viz/BarChart.js.map +1 -0
  32. package/dist/atheletebridge/components/viz/DonutChart.js +109 -0
  33. package/dist/atheletebridge/components/viz/DonutChart.js.map +1 -0
  34. package/dist/atheletebridge/components/viz/LineChart.js +123 -0
  35. package/dist/atheletebridge/components/viz/LineChart.js.map +1 -0
  36. package/dist/atheletebridge/components/viz/ProgressRing.js +6 -0
  37. package/dist/atheletebridge/components/viz/ProgressRing.js.map +1 -0
  38. package/dist/atheletebridge/components/viz/RatingStars.js +92 -0
  39. package/dist/atheletebridge/components/viz/RatingStars.js.map +1 -0
  40. package/dist/atheletebridge/components/viz/Sparkline.js +74 -0
  41. package/dist/atheletebridge/components/viz/Sparkline.js.map +1 -0
  42. package/dist/atheletebridge/components/viz/StatCard.js +60 -0
  43. package/dist/atheletebridge/components/viz/StatCard.js.map +1 -0
  44. package/dist/atheletebridge/components/viz/StepProgress.js +3 -0
  45. package/dist/atheletebridge/components/viz/Timeline.js +66 -0
  46. package/dist/atheletebridge/components/viz/Timeline.js.map +1 -0
  47. package/dist/atheletebridge/components/viz/index.js +13 -0
  48. package/dist/atheletebridge/components/viz/lib/Avatar.js +1 -0
  49. package/dist/atheletebridge/components/viz/lib/CartesianFrame.js +119 -0
  50. package/dist/atheletebridge/components/viz/lib/CartesianFrame.js.map +1 -0
  51. package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.js +35 -0
  52. package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.js.map +1 -0
  53. package/dist/atheletebridge/components/viz/lib/format.js +17 -0
  54. package/dist/atheletebridge/components/viz/lib/format.js.map +1 -0
  55. package/dist/atheletebridge/components/viz/lib/geometry.js +61 -0
  56. package/dist/atheletebridge/components/viz/lib/geometry.js.map +1 -0
  57. package/dist/atheletebridge/components/viz/lib/hooks.js +39 -0
  58. package/dist/atheletebridge/components/viz/lib/hooks.js.map +1 -0
  59. package/dist/atheletebridge/components/viz/lib/palette.js +27 -0
  60. package/dist/atheletebridge/components/viz/lib/palette.js.map +1 -0
  61. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +369 -163
  62. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  63. package/dist/atheletebridge/pages/DashboardPage.js +182 -117
  64. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  65. package/dist/atheletebridge/pages/StandingsPage.js +119 -95
  66. package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
  67. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js +372 -0
  68. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js.map +1 -0
  69. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js +511 -0
  70. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js.map +1 -0
  71. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +120 -131
  72. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -1
  73. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js +264 -176
  74. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js.map +1 -1
  75. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js +84 -47
  76. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -1
  77. package/dist/atheletebridge/pages/performance/PerformancePage.js +432 -281
  78. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -1
  79. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +187 -123
  80. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  81. package/dist/atheletebridge/pages/programs/ProgramsListPage.js +56 -39
  82. package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -1
  83. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +267 -139
  84. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
  85. package/dist/atheletebridge/pages/sessions/SessionFormPage.js +253 -162
  86. package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -1
  87. package/dist/atheletebridge/pages/sessions/SessionsListPage.js +38 -36
  88. package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -1
  89. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +437 -189
  90. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  91. package/dist/atheletebridge/pages/teams/TeamFormPage.js +368 -177
  92. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
  93. package/dist/atheletebridge/pages/teams/TeamsListPage.js +3 -0
  94. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
  95. package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.js +298 -0
  96. package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.js.map +1 -0
  97. package/dist/atheletebridge/utils/identity.js +31 -0
  98. package/dist/atheletebridge/utils/identity.js.map +1 -0
  99. package/dist/atheletebridge/utils/timeAgo.js +20 -0
  100. package/dist/atheletebridge/utils/timeAgo.js.map +1 -0
  101. package/package.json +1 -1
@@ -0,0 +1,372 @@
1
+ import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
2
+ import { PageLayout as t } from "../../components/PageLayout.js";
3
+ import { STATUS as n } from "../../components/viz/lib/palette.js";
4
+ import { LineChart as r } from "../../components/viz/LineChart.js";
5
+ import { BarChart as i } from "../../components/viz/BarChart.js";
6
+ import { DonutChart as a } from "../../components/viz/DonutChart.js";
7
+ import { RatingStars as o } from "../../components/viz/RatingStars.js";
8
+ import "../../components/viz/index.js";
9
+ import { MetricsCard as s } from "../../components/MetricsCard.js";
10
+ import { humanizeEnum as c } from "../../components/domain.js";
11
+ import { Crest as l } from "../../components/Crest.js";
12
+ import { UserAvatar as u } from "../../components/UserAvatar.js";
13
+ import { EmptyState as d } from "../../components/EmptyState.js";
14
+ import { ErrorState as f, LoadingState as p } from "../../components/LoadingState.js";
15
+ import { useCoachAnalytics as m, useUserDirectory as h } from "../../hooks/useAthleteBridgeApi.js";
16
+ import { useMemo as g } from "react";
17
+ import { Activity as _, BarChart3 as v, CheckCircle2 as y, Info as b, ListChecks as x, Star as S } from "lucide-react";
18
+ import { Fragment as C, jsx as w, jsxs as T } from "react/jsx-runtime";
19
+ import { Badge as E, GlassCard as D, GradientText as O, ResponsiveTable as k, Tooltip as A, TooltipContent as j, TooltipProvider as M, TooltipTrigger as N } from "@burdenoff/fe-libs/ui";
20
+ //#region src/atheletebridge/pages/analytics/CoachAnalyticsPage.tsx
21
+ var P = {
22
+ COMPLETED: n.success,
23
+ CONFIRMED: n.info,
24
+ REQUESTED: n.warning,
25
+ CANCELLED: n.danger,
26
+ NO_SHOW: "var(--color-text-muted)"
27
+ };
28
+ function F(e) {
29
+ return e == null ? {
30
+ label: "No data",
31
+ variant: "secondary"
32
+ } : e > 1.5 ? {
33
+ label: "At risk",
34
+ variant: "destructive"
35
+ } : e < .8 || e > 1.3 ? {
36
+ label: "Watch",
37
+ variant: "secondary"
38
+ } : {
39
+ label: "Optimal",
40
+ variant: "default"
41
+ };
42
+ }
43
+ function I(e, t) {
44
+ return e && e.trim() ? e : `Coach ${t.slice(0, 4)}`;
45
+ }
46
+ function L() {
47
+ let { navigateTo: n } = e(), L = m(), R = h(L.coachIds), z = g(() => L.sessionsByStatus.map((e) => ({
48
+ label: c(e.status),
49
+ value: e.count,
50
+ color: P[e.status]
51
+ })), [L.sessionsByStatus]), B = g(() => L.ratingByCoach.map((e) => ({
52
+ label: I(R.nameOf(e.coachId), e.coachId),
53
+ value: Number(e.avgRating.toFixed(2))
54
+ })), [L.ratingByCoach, R]), V = [
55
+ {
56
+ key: "rank",
57
+ header: "#",
58
+ priority: "secondary",
59
+ cell: (e, t) => /* @__PURE__ */ w("span", {
60
+ className: "tabular-nums text-text-secondary",
61
+ children: e.rank ?? t + 1
62
+ })
63
+ },
64
+ {
65
+ key: "team",
66
+ header: "Team",
67
+ priority: "primary",
68
+ cell: (e) => /* @__PURE__ */ T("span", {
69
+ className: "flex items-center gap-2",
70
+ children: [/* @__PURE__ */ w(l, {
71
+ name: e.team?.name ?? "Team",
72
+ sport: e.team?.sport,
73
+ size: 20,
74
+ showSportGlyph: !1
75
+ }), /* @__PURE__ */ w("span", {
76
+ className: "truncate font-medium text-text-primary",
77
+ children: e.team?.name ?? "Team"
78
+ })]
79
+ })
80
+ },
81
+ {
82
+ key: "played",
83
+ header: "P",
84
+ priority: "hidden-on-mobile",
85
+ cell: (e) => /* @__PURE__ */ w("span", {
86
+ className: "tabular-nums text-text-secondary",
87
+ children: e.played
88
+ })
89
+ },
90
+ {
91
+ key: "gd",
92
+ header: "GD",
93
+ priority: "hidden-on-mobile",
94
+ cell: (e) => {
95
+ let t = e.goalsFor - e.goalsAgainst;
96
+ return /* @__PURE__ */ T("span", {
97
+ className: "tabular-nums text-text-secondary",
98
+ children: [t > 0 ? "+" : "", t]
99
+ });
100
+ }
101
+ },
102
+ {
103
+ key: "points",
104
+ header: "Pts",
105
+ priority: "secondary",
106
+ cell: (e) => /* @__PURE__ */ w("span", {
107
+ className: "font-semibold tabular-nums text-text-primary",
108
+ children: e.points
109
+ })
110
+ }
111
+ ];
112
+ if (L.isLoading) return /* @__PURE__ */ w(t, {
113
+ title: "Coach analytics",
114
+ children: /* @__PURE__ */ w(p, { label: "Crunching coaching data…" })
115
+ });
116
+ if (L.isError) return /* @__PURE__ */ w(t, {
117
+ title: "Coach analytics",
118
+ children: /* @__PURE__ */ w(f, {
119
+ title: "Analytics unavailable",
120
+ message: "We could not load coaching analytics. Please try again."
121
+ })
122
+ });
123
+ let H = L.totalSessions > 0 || L.standings.length > 0, U = F(L.trainingLoad.ratio);
124
+ return /* @__PURE__ */ w(t, {
125
+ title: /* @__PURE__ */ T("span", {
126
+ className: "flex items-center gap-2",
127
+ children: [/* @__PURE__ */ w(O, { children: "Coach analytics" }), /* @__PURE__ */ w(E, {
128
+ variant: "outline",
129
+ children: "Beta"
130
+ })]
131
+ }),
132
+ description: "Honest aggregates over your real sessions, workouts and results.",
133
+ children: H ? /* @__PURE__ */ T("div", {
134
+ className: "space-y-8",
135
+ children: [
136
+ /* @__PURE__ */ T("div", {
137
+ className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
138
+ children: [
139
+ /* @__PURE__ */ w(s, {
140
+ icon: /* @__PURE__ */ w(x, { className: "h-5 w-5" }),
141
+ value: L.totalSessions,
142
+ label: "Total sessions",
143
+ tone: "accent"
144
+ }),
145
+ /* @__PURE__ */ T(D, {
146
+ treatment: "metric",
147
+ className: "flex flex-col justify-between gap-3 p-5",
148
+ children: [
149
+ /* @__PURE__ */ T("div", {
150
+ className: "flex items-start justify-between gap-2",
151
+ children: [/* @__PURE__ */ w("span", {
152
+ className: "text-sm font-medium text-text-secondary",
153
+ children: "Avg session rating"
154
+ }), /* @__PURE__ */ w(S, { className: "h-5 w-5 text-text-muted" })]
155
+ }),
156
+ L.avgRating == null ? /* @__PURE__ */ w("span", {
157
+ className: "text-sm text-text-muted",
158
+ children: "No rated sessions yet"
159
+ }) : /* @__PURE__ */ T("div", {
160
+ className: "flex items-end gap-3",
161
+ children: [/* @__PURE__ */ T("span", {
162
+ className: "text-3xl font-semibold leading-none tabular-nums text-text-primary",
163
+ children: [L.avgRating.toFixed(1), /* @__PURE__ */ w("span", {
164
+ className: "ml-1 text-base text-text-secondary",
165
+ children: "/5"
166
+ })]
167
+ }), /* @__PURE__ */ w("div", {
168
+ className: "pb-1",
169
+ children: /* @__PURE__ */ w(o, {
170
+ value: L.avgRating,
171
+ max: 5,
172
+ size: 16
173
+ })
174
+ })]
175
+ }),
176
+ /* @__PURE__ */ T("span", {
177
+ className: "text-xs text-text-muted tabular-nums",
178
+ children: [
179
+ L.ratedCount,
180
+ " rated of ",
181
+ L.totalSessions
182
+ ]
183
+ })
184
+ ]
185
+ }),
186
+ /* @__PURE__ */ w(s, {
187
+ icon: /* @__PURE__ */ w(y, { className: "h-5 w-5" }),
188
+ value: `${Math.round(L.completedPct)}%`,
189
+ label: "Sessions completed",
190
+ tone: "success"
191
+ })
192
+ ]
193
+ }),
194
+ /* @__PURE__ */ T("div", {
195
+ className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
196
+ children: [/* @__PURE__ */ T(D, {
197
+ treatment: "insight",
198
+ className: "p-6",
199
+ children: [/* @__PURE__ */ w("h2", {
200
+ className: "mb-4 text-lg font-semibold text-text-primary",
201
+ children: "Session status overview"
202
+ }), z.length > 0 ? /* @__PURE__ */ w(a, {
203
+ segments: z,
204
+ centerLabel: L.totalSessions,
205
+ centerCaption: "sessions",
206
+ valueFormatter: (e) => e.toLocaleString()
207
+ }) : /* @__PURE__ */ w("p", {
208
+ className: "text-sm text-text-muted",
209
+ children: "No sessions to break down yet."
210
+ })]
211
+ }), /* @__PURE__ */ T(D, {
212
+ treatment: "insight",
213
+ className: "p-6",
214
+ children: [/* @__PURE__ */ w("h2", {
215
+ className: "mb-4 text-lg font-semibold text-text-primary",
216
+ children: "Average rating by coach"
217
+ }), B.length > 0 ? /* @__PURE__ */ T(C, { children: [/* @__PURE__ */ w(i, {
218
+ series: B,
219
+ height: 220,
220
+ colorful: !0,
221
+ valueFormatter: (e) => e.toFixed(1)
222
+ }), /* @__PURE__ */ w("div", {
223
+ className: "mt-3 flex flex-wrap gap-x-4 gap-y-2",
224
+ children: L.ratingByCoach.map((e) => /* @__PURE__ */ T("span", {
225
+ className: "flex items-center gap-2 text-xs text-text-secondary",
226
+ children: [/* @__PURE__ */ w(u, {
227
+ name: R.nameOf(e.coachId),
228
+ id: e.coachId,
229
+ size: "xs"
230
+ }), /* @__PURE__ */ T("span", {
231
+ className: "truncate",
232
+ children: [I(R.nameOf(e.coachId), e.coachId), /* @__PURE__ */ T("span", {
233
+ className: "ml-1 text-text-muted tabular-nums",
234
+ children: [
235
+ "(",
236
+ e.count,
237
+ ")"
238
+ ]
239
+ })]
240
+ })]
241
+ }, e.coachId))
242
+ })] }) : /* @__PURE__ */ w("p", {
243
+ className: "text-sm text-text-muted",
244
+ children: "Rate completed sessions to compare coaches."
245
+ })]
246
+ })]
247
+ }),
248
+ /* @__PURE__ */ T("div", {
249
+ className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
250
+ children: [/* @__PURE__ */ T(D, {
251
+ treatment: "insight",
252
+ className: "p-6",
253
+ children: [/* @__PURE__ */ T("div", {
254
+ className: "mb-4 flex items-center justify-between gap-2",
255
+ children: [/* @__PURE__ */ w("h2", {
256
+ className: "text-lg font-semibold text-text-primary",
257
+ children: "Weekly training load"
258
+ }), /* @__PURE__ */ w(M, { children: /* @__PURE__ */ T(A, { children: [/* @__PURE__ */ w(N, {
259
+ asChild: !0,
260
+ children: /* @__PURE__ */ w("button", {
261
+ type: "button",
262
+ "aria-label": "About ACWR training load",
263
+ className: "rounded-full p-1 text-text-muted transition-colors hover:text-text-primary",
264
+ children: /* @__PURE__ */ w(b, { className: "h-4 w-4" })
265
+ })
266
+ }), /* @__PURE__ */ T(j, {
267
+ className: "max-w-xs",
268
+ children: [
269
+ "Total workout load per week (sum of real ",
270
+ /* @__PURE__ */ w("code", { children: "totalLoad" }),
271
+ "). The badge is the acute:chronic workload ratio (last 7 days vs 28-day average) — a standard sports-science load indicator; 0.8–1.3 is the typical sweet spot."
272
+ ]
273
+ })] }) })]
274
+ }), L.loadTrend.some((e) => e.value > 0) ? /* @__PURE__ */ T(C, { children: [/* @__PURE__ */ w(r, {
275
+ series: L.loadTrend,
276
+ seriesLabel: "Training load",
277
+ height: 200,
278
+ valueFormatter: (e) => e.toLocaleString()
279
+ }), /* @__PURE__ */ T("div", {
280
+ className: "mt-4 flex flex-wrap items-center gap-x-6 gap-y-2 text-sm",
281
+ children: [
282
+ /* @__PURE__ */ T("span", {
283
+ className: "text-text-secondary",
284
+ children: [
285
+ "Acute (7d)",
286
+ " ",
287
+ /* @__PURE__ */ w("span", {
288
+ className: "font-semibold tabular-nums text-text-primary",
289
+ children: Math.round(L.trainingLoad.acute).toLocaleString()
290
+ })
291
+ ]
292
+ }),
293
+ /* @__PURE__ */ T("span", {
294
+ className: "text-text-secondary",
295
+ children: [
296
+ "Chronic (28d avg)",
297
+ " ",
298
+ /* @__PURE__ */ w("span", {
299
+ className: "font-semibold tabular-nums text-text-primary",
300
+ children: Math.round(L.trainingLoad.chronic).toLocaleString()
301
+ })
302
+ ]
303
+ }),
304
+ /* @__PURE__ */ T("span", {
305
+ className: "flex items-center gap-2 text-text-secondary",
306
+ children: ["ACWR", /* @__PURE__ */ w(E, {
307
+ variant: U.variant,
308
+ className: "tabular-nums",
309
+ children: L.trainingLoad.ratio == null ? U.label : `${L.trainingLoad.ratio.toFixed(2)} · ${U.label}`
310
+ })]
311
+ })
312
+ ]
313
+ })] }) : /* @__PURE__ */ w("p", {
314
+ className: "text-sm text-text-muted",
315
+ children: "Log workouts with a load to see training trend."
316
+ })]
317
+ }), /* @__PURE__ */ T(D, {
318
+ treatment: "insight",
319
+ className: "p-6",
320
+ children: [/* @__PURE__ */ w("h2", {
321
+ className: "mb-4 text-lg font-semibold text-text-primary",
322
+ children: "Sessions per week"
323
+ }), L.sessionTrend.some((e) => e.value > 0) ? /* @__PURE__ */ w(i, {
324
+ series: L.sessionTrend,
325
+ height: 200,
326
+ valueFormatter: (e) => e.toLocaleString()
327
+ }) : /* @__PURE__ */ w("p", {
328
+ className: "text-sm text-text-muted",
329
+ children: "Schedule sessions to see weekly volume."
330
+ })]
331
+ })]
332
+ }),
333
+ L.standings.length > 0 ? /* @__PURE__ */ T("section", { children: [/* @__PURE__ */ T("div", {
334
+ className: "mb-4 flex flex-wrap items-center justify-between gap-3",
335
+ children: [/* @__PURE__ */ T("h2", {
336
+ className: "flex items-center gap-2 text-lg font-semibold text-text-primary",
337
+ children: [
338
+ /* @__PURE__ */ w(_, { className: "h-5 w-5 text-text-muted" }),
339
+ "League standings",
340
+ L.competition ? /* @__PURE__ */ w(E, {
341
+ variant: "secondary",
342
+ children: L.competition
343
+ }) : null
344
+ ]
345
+ }), /* @__PURE__ */ w("button", {
346
+ type: "button",
347
+ onClick: () => n("/standings"),
348
+ className: "text-sm font-medium text-[var(--color-accent-teal)] transition-colors hover:underline",
349
+ children: "View full standings"
350
+ })]
351
+ }), /* @__PURE__ */ w(D, {
352
+ treatment: "insight",
353
+ className: "p-2 sm:p-4",
354
+ children: /* @__PURE__ */ w(k, {
355
+ columns: V,
356
+ data: L.standings,
357
+ rowKey: (e) => e.id
358
+ })
359
+ })] }) : null
360
+ ]
361
+ }) : /* @__PURE__ */ w(d, {
362
+ illustration: "empty-data",
363
+ icon: /* @__PURE__ */ w(v, { className: "h-10 w-10" }),
364
+ title: "No coaching data yet",
365
+ description: "Book and complete sessions, log workouts and record fixtures to unlock analytics."
366
+ })
367
+ });
368
+ }
369
+ //#endregion
370
+ export { L as CoachAnalyticsPage };
371
+
372
+ //# sourceMappingURL=CoachAnalyticsPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CoachAnalyticsPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/analytics/CoachAnalyticsPage.tsx"],"sourcesContent":["/**\n * Coach Analytics\n * @module atheletebridge/pages/analytics\n *\n * An honest coaching-analytics dashboard built ENTIRELY from real aggregates via\n * `useCoachAnalytics()` — total sessions, average session rating, completion\n * rate, session-status mix, average rating by coach, weekly training-load /\n * session trends, and a league-standings snapshot.\n *\n * Deliberately OMITS the mock's fabricated composite indices (Form Index,\n * Fitness Score, Fatigue Index, Injury Status, Availability %) — there is no\n * wellness / injury / availability data in the schema, so those are not faked.\n * The one derived metric shown (ACWR training load) uses standard sports-science\n * maths over real `workout.totalLoad` and carries an explanatory tooltip.\n * Semantic tokens only; responsive.\n */\n\nimport { useMemo } from 'react';\nimport { Activity, BarChart3, CheckCircle2, Info, ListChecks, Star } from 'lucide-react';\nimport {\n Badge,\n GlassCard,\n GradientText,\n ResponsiveTable,\n type ResponsiveTableColumn,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { MetricsCard } from '../../components/MetricsCard';\nimport { Crest } from '../../components/Crest';\nimport { UserAvatar } from '../../components/UserAvatar';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { LineChart, BarChart, DonutChart, RatingStars, STATUS } from '../../components/viz';\nimport { humanizeEnum } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useCoachAnalytics, useUserDirectory } from '../../hooks/useAthleteBridgeApi';\nimport type { AthSessionStatus, AthStanding } from '../../types';\n\n/** Tokenized color per session status for the status donut. */\nconst STATUS_COLOR: Record<AthSessionStatus, string> = {\n COMPLETED: STATUS.success,\n CONFIRMED: STATUS.info,\n REQUESTED: STATUS.warning,\n CANCELLED: STATUS.danger,\n NO_SHOW: 'var(--color-text-muted)',\n};\n\n/** ACWR banding (acute:chronic workload ratio) — standard sweet-spot 0.8–1.3. */\nfunction acwrBand(ratio: number | null): {\n label: string;\n variant: 'default' | 'secondary' | 'destructive';\n} {\n if (ratio == null) {\n return { label: 'No data', variant: 'secondary' };\n }\n if (ratio > 1.5) {\n return { label: 'At risk', variant: 'destructive' };\n }\n if (ratio < 0.8 || ratio > 1.3) {\n return { label: 'Watch', variant: 'secondary' };\n }\n return { label: 'Optimal', variant: 'default' };\n}\n\n/** Short coach display: resolved name, else a monogram-friendly id fragment. */\nfunction coachShortName(name: string | undefined, id: string): string {\n if (name && name.trim()) {\n return name;\n }\n return `Coach ${id.slice(0, 4)}`;\n}\n\nexport function CoachAnalyticsPage() {\n const { navigateTo } = useAthleteBridge();\n const analytics = useCoachAnalytics();\n const directory = useUserDirectory(analytics.coachIds);\n\n const statusSegments = useMemo(\n () =>\n analytics.sessionsByStatus.map((entry) => ({\n label: humanizeEnum(entry.status),\n value: entry.count,\n color: STATUS_COLOR[entry.status],\n })),\n [analytics.sessionsByStatus]\n );\n\n const coachBars = useMemo(\n () =>\n analytics.ratingByCoach.map((entry) => ({\n label: coachShortName(directory.nameOf(entry.coachId), entry.coachId),\n value: Number(entry.avgRating.toFixed(2)),\n })),\n [analytics.ratingByCoach, directory]\n );\n\n const standingsColumns: ResponsiveTableColumn<AthStanding>[] = [\n {\n key: 'rank',\n header: '#',\n priority: 'secondary',\n cell: (row, i) => (\n <span className=\"tabular-nums text-text-secondary\">{row.rank ?? i + 1}</span>\n ),\n },\n {\n key: 'team',\n header: 'Team',\n priority: 'primary',\n cell: (row) => (\n <span className=\"flex items-center gap-2\">\n <Crest\n name={row.team?.name ?? 'Team'}\n sport={row.team?.sport}\n size={20}\n showSportGlyph={false}\n />\n <span className=\"truncate font-medium text-text-primary\">{row.team?.name ?? 'Team'}</span>\n </span>\n ),\n },\n {\n key: 'played',\n header: 'P',\n priority: 'hidden-on-mobile',\n cell: (row) => <span className=\"tabular-nums text-text-secondary\">{row.played}</span>,\n },\n {\n key: 'gd',\n header: 'GD',\n priority: 'hidden-on-mobile',\n cell: (row) => {\n const gd = row.goalsFor - row.goalsAgainst;\n return (\n <span className=\"tabular-nums text-text-secondary\">\n {gd > 0 ? '+' : ''}\n {gd}\n </span>\n );\n },\n },\n {\n key: 'points',\n header: 'Pts',\n priority: 'secondary',\n cell: (row) => (\n <span className=\"font-semibold tabular-nums text-text-primary\">{row.points}</span>\n ),\n },\n ];\n\n if (analytics.isLoading) {\n return (\n <PageLayout title=\"Coach analytics\">\n <LoadingState label=\"Crunching coaching data…\" />\n </PageLayout>\n );\n }\n\n if (analytics.isError) {\n return (\n <PageLayout title=\"Coach analytics\">\n <ErrorState\n title=\"Analytics unavailable\"\n message=\"We could not load coaching analytics. Please try again.\"\n />\n </PageLayout>\n );\n }\n\n const hasData = analytics.totalSessions > 0 || analytics.standings.length > 0;\n const band = acwrBand(analytics.trainingLoad.ratio);\n\n return (\n <PageLayout\n title={\n <span className=\"flex items-center gap-2\">\n <GradientText>Coach analytics</GradientText>\n <Badge variant=\"outline\">Beta</Badge>\n </span>\n }\n description=\"Honest aggregates over your real sessions, workouts and results.\"\n >\n {!hasData ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<BarChart3 className=\"h-10 w-10\" />}\n title=\"No coaching data yet\"\n description=\"Book and complete sessions, log workouts and record fixtures to unlock analytics.\"\n />\n ) : (\n <div className=\"space-y-8\">\n {/* KPI row */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n <MetricsCard\n icon={<ListChecks className=\"h-5 w-5\" />}\n value={analytics.totalSessions}\n label=\"Total sessions\"\n tone=\"accent\"\n />\n <GlassCard treatment=\"metric\" className=\"flex flex-col justify-between gap-3 p-5\">\n <div className=\"flex items-start justify-between gap-2\">\n <span className=\"text-sm font-medium text-text-secondary\">Avg session rating</span>\n <Star className=\"h-5 w-5 text-text-muted\" />\n </div>\n {analytics.avgRating != null ? (\n <div className=\"flex items-end gap-3\">\n <span className=\"text-3xl font-semibold leading-none tabular-nums text-text-primary\">\n {analytics.avgRating.toFixed(1)}\n <span className=\"ml-1 text-base text-text-secondary\">/5</span>\n </span>\n <div className=\"pb-1\">\n <RatingStars value={analytics.avgRating} max={5} size={16} />\n </div>\n </div>\n ) : (\n <span className=\"text-sm text-text-muted\">No rated sessions yet</span>\n )}\n <span className=\"text-xs text-text-muted tabular-nums\">\n {analytics.ratedCount} rated of {analytics.totalSessions}\n </span>\n </GlassCard>\n <MetricsCard\n icon={<CheckCircle2 className=\"h-5 w-5\" />}\n value={`${Math.round(analytics.completedPct)}%`}\n label=\"Sessions completed\"\n tone=\"success\"\n />\n </div>\n\n {/* Charts row: status donut + rating-by-coach bars */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <GlassCard treatment=\"insight\" className=\"p-6\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">\n Session status overview\n </h2>\n {statusSegments.length > 0 ? (\n <DonutChart\n segments={statusSegments}\n centerLabel={analytics.totalSessions}\n centerCaption=\"sessions\"\n valueFormatter={(v) => v.toLocaleString()}\n />\n ) : (\n <p className=\"text-sm text-text-muted\">No sessions to break down yet.</p>\n )}\n </GlassCard>\n\n <GlassCard treatment=\"insight\" className=\"p-6\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">\n Average rating by coach\n </h2>\n {coachBars.length > 0 ? (\n <>\n <BarChart\n series={coachBars}\n height={220}\n colorful\n valueFormatter={(v) => v.toFixed(1)}\n />\n <div className=\"mt-3 flex flex-wrap gap-x-4 gap-y-2\">\n {analytics.ratingByCoach.map((entry) => (\n <span\n key={entry.coachId}\n className=\"flex items-center gap-2 text-xs text-text-secondary\"\n >\n <UserAvatar\n name={directory.nameOf(entry.coachId)}\n id={entry.coachId}\n size=\"xs\"\n />\n <span className=\"truncate\">\n {coachShortName(directory.nameOf(entry.coachId), entry.coachId)}\n <span className=\"ml-1 text-text-muted tabular-nums\">({entry.count})</span>\n </span>\n </span>\n ))}\n </div>\n </>\n ) : (\n <p className=\"text-sm text-text-muted\">\n Rate completed sessions to compare coaches.\n </p>\n )}\n </GlassCard>\n </div>\n\n {/* Trends row: training load + sessions per week */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n <GlassCard treatment=\"insight\" className=\"p-6\">\n <div className=\"mb-4 flex items-center justify-between gap-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Weekly training load</h2>\n <TooltipProvider>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"About ACWR training load\"\n className=\"rounded-full p-1 text-text-muted transition-colors hover:text-text-primary\"\n >\n <Info className=\"h-4 w-4\" />\n </button>\n </TooltipTrigger>\n <TooltipContent className=\"max-w-xs\">\n Total workout load per week (sum of real <code>totalLoad</code>). The badge is\n the acute:chronic workload ratio (last 7 days vs 28-day average) — a standard\n sports-science load indicator; 0.8–1.3 is the typical sweet spot.\n </TooltipContent>\n </Tooltip>\n </TooltipProvider>\n </div>\n {analytics.loadTrend.some((p) => p.value > 0) ? (\n <>\n <LineChart\n series={analytics.loadTrend}\n seriesLabel=\"Training load\"\n height={200}\n valueFormatter={(v) => v.toLocaleString()}\n />\n <div className=\"mt-4 flex flex-wrap items-center gap-x-6 gap-y-2 text-sm\">\n <span className=\"text-text-secondary\">\n Acute (7d){' '}\n <span className=\"font-semibold tabular-nums text-text-primary\">\n {Math.round(analytics.trainingLoad.acute).toLocaleString()}\n </span>\n </span>\n <span className=\"text-text-secondary\">\n Chronic (28d avg){' '}\n <span className=\"font-semibold tabular-nums text-text-primary\">\n {Math.round(analytics.trainingLoad.chronic).toLocaleString()}\n </span>\n </span>\n <span className=\"flex items-center gap-2 text-text-secondary\">\n ACWR\n <Badge variant={band.variant} className=\"tabular-nums\">\n {analytics.trainingLoad.ratio != null\n ? `${analytics.trainingLoad.ratio.toFixed(2)} · ${band.label}`\n : band.label}\n </Badge>\n </span>\n </div>\n </>\n ) : (\n <p className=\"text-sm text-text-muted\">\n Log workouts with a load to see training trend.\n </p>\n )}\n </GlassCard>\n\n <GlassCard treatment=\"insight\" className=\"p-6\">\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">Sessions per week</h2>\n {analytics.sessionTrend.some((p) => p.value > 0) ? (\n <BarChart\n series={analytics.sessionTrend}\n height={200}\n valueFormatter={(v) => v.toLocaleString()}\n />\n ) : (\n <p className=\"text-sm text-text-muted\">Schedule sessions to see weekly volume.</p>\n )}\n </GlassCard>\n </div>\n\n {/* League standings snapshot */}\n {analytics.standings.length > 0 ? (\n <section>\n <div className=\"mb-4 flex flex-wrap items-center justify-between gap-3\">\n <h2 className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Activity className=\"h-5 w-5 text-text-muted\" />\n League standings\n {analytics.competition ? (\n <Badge variant=\"secondary\">{analytics.competition}</Badge>\n ) : null}\n </h2>\n <button\n type=\"button\"\n onClick={() => navigateTo('/standings')}\n className=\"text-sm font-medium text-[var(--color-accent-teal)] transition-colors hover:underline\"\n >\n View full standings\n </button>\n </div>\n <GlassCard treatment=\"insight\" className=\"p-2 sm:p-4\">\n <ResponsiveTable\n columns={standingsColumns}\n data={analytics.standings}\n rowKey={(row) => row.id}\n />\n </GlassCard>\n </section>\n ) : null}\n </div>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}