@burdenoff/microfe-atheletebridge 2026.801.3 → 2026.827.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.
@@ -1,31 +1,32 @@
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";
1
+ import { useAbTranslate as e } from "../../i18n.js";
2
+ import { useAthleteBridge as t } from "../../context/AthleteBridgeContext.js";
3
+ import { PageLayout as n } from "../../components/PageLayout.js";
4
+ import { STATUS as r } from "../../components/viz/lib/palette.js";
5
+ import { LineChart as i } from "../../components/viz/LineChart.js";
6
+ import { BarChart as a } from "../../components/viz/BarChart.js";
7
+ import { DonutChart as o } from "../../components/viz/DonutChart.js";
8
+ import { RatingStars as s } from "../../components/viz/RatingStars.js";
8
9
  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";
10
+ import { MetricsCard as c } from "../../components/MetricsCard.js";
11
+ import { humanizeEnum as l } from "../../components/domain.js";
12
+ import { Crest as u } from "../../components/Crest.js";
13
+ import { UserAvatar as d } from "../../components/UserAvatar.js";
14
+ import { EmptyState as f } from "../../components/EmptyState.js";
15
+ import { ErrorState as p, LoadingState as m } from "../../components/LoadingState.js";
16
+ import { useCoachAnalytics as h, useUserDirectory as g } from "../../hooks/useAthleteBridgeApi.js";
17
+ import { useMemo as _ } from "react";
18
+ import { Activity as v, BarChart3 as y, CheckCircle2 as b, Info as x, ListChecks as S, Star as C, Users as w } from "lucide-react";
19
+ import { Fragment as T, jsx as E, jsxs as D } from "react/jsx-runtime";
20
+ import { Badge as O, GlassCard as k, GradientText as A, ResponsiveTable as j, Tooltip as M, TooltipContent as N, TooltipProvider as P, TooltipTrigger as F } from "@burdenoff/fe-libs/ui";
20
21
  //#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,
22
+ var I = {
23
+ COMPLETED: r.success,
24
+ CONFIRMED: r.info,
25
+ REQUESTED: r.warning,
26
+ CANCELLED: r.danger,
26
27
  NO_SHOW: "var(--color-text-muted)"
27
28
  };
28
- function F(e) {
29
+ function L(e) {
29
30
  return e == null ? {
30
31
  label: "No data",
31
32
  variant: "secondary"
@@ -40,23 +41,35 @@ function F(e) {
40
41
  variant: "default"
41
42
  };
42
43
  }
43
- function I(e, t) {
44
- return e && e.trim() ? e : `Coach ${t.slice(0, 4)}`;
44
+ function R(e, t, n) {
45
+ return e && e.trim() ? e : `${n} ${t.slice(0, 4)}`;
45
46
  }
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),
47
+ var z = (e) => Math.round(e).toLocaleString();
48
+ function B({ value: e, max: t }) {
49
+ let n = t > 0 ? Math.round(e / t * 100) : 0;
50
+ return /* @__PURE__ */ E("span", {
51
+ className: "block h-1.5 w-16 overflow-hidden rounded-full bg-bg-sunken",
52
+ "aria-hidden": "true",
53
+ children: /* @__PURE__ */ E("span", {
54
+ className: "block h-1.5 rounded-full bg-[var(--color-accent-teal)]",
55
+ style: { width: `${Math.max(e > 0 ? 4 : 0, Math.min(100, n))}%` }
56
+ })
57
+ });
58
+ }
59
+ function V() {
60
+ let r = e(), { navigateTo: w } = t(), z = h(), B = g(_(() => [...z.coachIds, ...z.athleteIds], [z.coachIds, z.athleteIds])), V = _(() => z.sessionsByStatus.map((e) => ({
61
+ label: l(e.status),
49
62
  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),
63
+ color: I[e.status]
64
+ })), [z.sessionsByStatus]), U = _(() => z.ratingByCoach.map((e) => ({
65
+ label: R(B.nameOf(e.coachId), e.coachId, "Coach"),
53
66
  value: Number(e.avgRating.toFixed(2))
54
- })), [L.ratingByCoach, R]), V = [
67
+ })), [z.ratingByCoach, B]), W = [
55
68
  {
56
69
  key: "rank",
57
70
  header: "#",
58
71
  priority: "secondary",
59
- cell: (e, t) => /* @__PURE__ */ w("span", {
72
+ cell: (e, t) => /* @__PURE__ */ E("span", {
60
73
  className: "tabular-nums text-text-secondary",
61
74
  children: e.rank ?? t + 1
62
75
  })
@@ -65,14 +78,14 @@ function L() {
65
78
  key: "team",
66
79
  header: "Team",
67
80
  priority: "primary",
68
- cell: (e) => /* @__PURE__ */ T("span", {
81
+ cell: (e) => /* @__PURE__ */ D("span", {
69
82
  className: "flex items-center gap-2",
70
- children: [/* @__PURE__ */ w(l, {
83
+ children: [/* @__PURE__ */ E(u, {
71
84
  name: e.team?.name ?? "Team",
72
85
  sport: e.team?.sport,
73
86
  size: 20,
74
87
  showSportGlyph: !1
75
- }), /* @__PURE__ */ w("span", {
88
+ }), /* @__PURE__ */ E("span", {
76
89
  className: "truncate font-medium text-text-primary",
77
90
  children: e.team?.name ?? "Team"
78
91
  })]
@@ -82,7 +95,7 @@ function L() {
82
95
  key: "played",
83
96
  header: "P",
84
97
  priority: "hidden-on-mobile",
85
- cell: (e) => /* @__PURE__ */ w("span", {
98
+ cell: (e) => /* @__PURE__ */ E("span", {
86
99
  className: "tabular-nums text-text-secondary",
87
100
  children: e.played
88
101
  })
@@ -93,7 +106,7 @@ function L() {
93
106
  priority: "hidden-on-mobile",
94
107
  cell: (e) => {
95
108
  let t = e.goalsFor - e.goalsAgainst;
96
- return /* @__PURE__ */ T("span", {
109
+ return /* @__PURE__ */ D("span", {
97
110
  className: "tabular-nums text-text-secondary",
98
111
  children: [t > 0 ? "+" : "", t]
99
112
  });
@@ -103,133 +116,133 @@ function L() {
103
116
  key: "points",
104
117
  header: "Pts",
105
118
  priority: "secondary",
106
- cell: (e) => /* @__PURE__ */ w("span", {
119
+ cell: (e) => /* @__PURE__ */ E("span", {
107
120
  className: "font-semibold tabular-nums text-text-primary",
108
121
  children: e.points
109
122
  })
110
123
  }
111
124
  ];
112
- if (L.isLoading) return /* @__PURE__ */ w(t, {
125
+ if (z.isLoading) return /* @__PURE__ */ E(n, {
113
126
  title: "Coach analytics",
114
- children: /* @__PURE__ */ w(p, { label: "Crunching coaching data…" })
127
+ children: /* @__PURE__ */ E(m, { label: "Crunching coaching data…" })
115
128
  });
116
- if (L.isError) return /* @__PURE__ */ w(t, {
129
+ if (z.isError) return /* @__PURE__ */ E(n, {
117
130
  title: "Coach analytics",
118
- children: /* @__PURE__ */ w(f, {
131
+ children: /* @__PURE__ */ E(p, {
119
132
  title: "Analytics unavailable",
120
133
  message: "We could not load coaching analytics. Please try again."
121
134
  })
122
135
  });
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", {
136
+ let G = z.totalSessions > 0 || z.standings.length > 0 || z.loadByAthlete.length > 0, K = L(z.trainingLoad.ratio);
137
+ return /* @__PURE__ */ E(n, {
138
+ title: /* @__PURE__ */ D("span", {
126
139
  className: "flex items-center gap-2",
127
- children: [/* @__PURE__ */ w(O, { children: "Coach analytics" }), /* @__PURE__ */ w(E, {
140
+ children: [/* @__PURE__ */ E(A, { children: "Coach analytics" }), /* @__PURE__ */ E(O, {
128
141
  variant: "outline",
129
142
  children: "Beta"
130
143
  })]
131
144
  }),
132
145
  description: "Honest aggregates over your real sessions, workouts and results.",
133
- children: H ? /* @__PURE__ */ T("div", {
146
+ children: G ? /* @__PURE__ */ D("div", {
134
147
  className: "space-y-8",
135
148
  children: [
136
- /* @__PURE__ */ T("div", {
149
+ /* @__PURE__ */ D("div", {
137
150
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
138
151
  children: [
139
- /* @__PURE__ */ w(s, {
140
- icon: /* @__PURE__ */ w(x, { className: "h-5 w-5" }),
141
- value: L.totalSessions,
152
+ /* @__PURE__ */ E(c, {
153
+ icon: /* @__PURE__ */ E(S, { className: "h-5 w-5" }),
154
+ value: z.totalSessions,
142
155
  label: "Total sessions",
143
156
  tone: "accent"
144
157
  }),
145
- /* @__PURE__ */ T(D, {
158
+ /* @__PURE__ */ D(k, {
146
159
  treatment: "metric",
147
160
  className: "flex flex-col justify-between gap-3 p-5",
148
161
  children: [
149
- /* @__PURE__ */ T("div", {
162
+ /* @__PURE__ */ D("div", {
150
163
  className: "flex items-start justify-between gap-2",
151
- children: [/* @__PURE__ */ w("span", {
164
+ children: [/* @__PURE__ */ E("span", {
152
165
  className: "text-sm font-medium text-text-secondary",
153
166
  children: "Avg session rating"
154
- }), /* @__PURE__ */ w(S, { className: "h-5 w-5 text-text-muted" })]
167
+ }), /* @__PURE__ */ E(C, { className: "h-5 w-5 text-text-muted" })]
155
168
  }),
156
- L.avgRating == null ? /* @__PURE__ */ w("span", {
169
+ z.avgRating == null ? /* @__PURE__ */ E("span", {
157
170
  className: "text-sm text-text-muted",
158
171
  children: "No rated sessions yet"
159
- }) : /* @__PURE__ */ T("div", {
172
+ }) : /* @__PURE__ */ D("div", {
160
173
  className: "flex items-end gap-3",
161
- children: [/* @__PURE__ */ T("span", {
174
+ children: [/* @__PURE__ */ D("span", {
162
175
  className: "text-3xl font-semibold leading-none tabular-nums text-text-primary",
163
- children: [L.avgRating.toFixed(1), /* @__PURE__ */ w("span", {
176
+ children: [z.avgRating.toFixed(1), /* @__PURE__ */ E("span", {
164
177
  className: "ml-1 text-base text-text-secondary",
165
178
  children: "/5"
166
179
  })]
167
- }), /* @__PURE__ */ w("div", {
180
+ }), /* @__PURE__ */ E("div", {
168
181
  className: "pb-1",
169
- children: /* @__PURE__ */ w(o, {
170
- value: L.avgRating,
182
+ children: /* @__PURE__ */ E(s, {
183
+ value: z.avgRating,
171
184
  max: 5,
172
185
  size: 16
173
186
  })
174
187
  })]
175
188
  }),
176
- /* @__PURE__ */ T("span", {
189
+ /* @__PURE__ */ D("span", {
177
190
  className: "text-xs text-text-muted tabular-nums",
178
191
  children: [
179
- L.ratedCount,
192
+ z.ratedCount,
180
193
  " rated of ",
181
- L.totalSessions
194
+ z.totalSessions
182
195
  ]
183
196
  })
184
197
  ]
185
198
  }),
186
- /* @__PURE__ */ w(s, {
187
- icon: /* @__PURE__ */ w(y, { className: "h-5 w-5" }),
188
- value: `${Math.round(L.completedPct)}%`,
199
+ /* @__PURE__ */ E(c, {
200
+ icon: /* @__PURE__ */ E(b, { className: "h-5 w-5" }),
201
+ value: `${Math.round(z.completedPct)}%`,
189
202
  label: "Sessions completed",
190
203
  tone: "success"
191
204
  })
192
205
  ]
193
206
  }),
194
- /* @__PURE__ */ T("div", {
207
+ /* @__PURE__ */ D("div", {
195
208
  className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
196
- children: [/* @__PURE__ */ T(D, {
209
+ children: [/* @__PURE__ */ D(k, {
197
210
  treatment: "insight",
198
211
  className: "p-6",
199
- children: [/* @__PURE__ */ w("h2", {
212
+ children: [/* @__PURE__ */ E("h2", {
200
213
  className: "mb-4 text-lg font-semibold text-text-primary",
201
214
  children: "Session status overview"
202
- }), z.length > 0 ? /* @__PURE__ */ w(a, {
203
- segments: z,
204
- centerLabel: L.totalSessions,
215
+ }), V.length > 0 ? /* @__PURE__ */ E(o, {
216
+ segments: V,
217
+ centerLabel: z.totalSessions,
205
218
  centerCaption: "sessions",
206
219
  valueFormatter: (e) => e.toLocaleString()
207
- }) : /* @__PURE__ */ w("p", {
220
+ }) : /* @__PURE__ */ E("p", {
208
221
  className: "text-sm text-text-muted",
209
222
  children: "No sessions to break down yet."
210
223
  })]
211
- }), /* @__PURE__ */ T(D, {
224
+ }), /* @__PURE__ */ D(k, {
212
225
  treatment: "insight",
213
226
  className: "p-6",
214
- children: [/* @__PURE__ */ w("h2", {
227
+ children: [/* @__PURE__ */ E("h2", {
215
228
  className: "mb-4 text-lg font-semibold text-text-primary",
216
229
  children: "Average rating by coach"
217
- }), B.length > 0 ? /* @__PURE__ */ T(C, { children: [/* @__PURE__ */ w(i, {
218
- series: B,
230
+ }), U.length > 0 ? /* @__PURE__ */ D(T, { children: [/* @__PURE__ */ E(a, {
231
+ series: U,
219
232
  height: 220,
220
233
  colorful: !0,
221
234
  valueFormatter: (e) => e.toFixed(1)
222
- }), /* @__PURE__ */ w("div", {
235
+ }), /* @__PURE__ */ E("div", {
223
236
  className: "mt-3 flex flex-wrap gap-x-4 gap-y-2",
224
- children: L.ratingByCoach.map((e) => /* @__PURE__ */ T("span", {
237
+ children: z.ratingByCoach.map((e) => /* @__PURE__ */ D("span", {
225
238
  className: "flex items-center gap-2 text-xs text-text-secondary",
226
- children: [/* @__PURE__ */ w(u, {
227
- name: R.nameOf(e.coachId),
239
+ children: [/* @__PURE__ */ E(d, {
240
+ name: B.nameOf(e.coachId),
228
241
  id: e.coachId,
229
242
  size: "xs"
230
- }), /* @__PURE__ */ T("span", {
243
+ }), /* @__PURE__ */ D("span", {
231
244
  className: "truncate",
232
- children: [I(R.nameOf(e.coachId), e.coachId), /* @__PURE__ */ T("span", {
245
+ children: [R(B.nameOf(e.coachId), e.coachId, "Coach"), /* @__PURE__ */ D("span", {
233
246
  className: "ml-1 text-text-muted tabular-nums",
234
247
  children: [
235
248
  "(",
@@ -239,134 +252,275 @@ function L() {
239
252
  })]
240
253
  })]
241
254
  }, e.coachId))
242
- })] }) : /* @__PURE__ */ w("p", {
255
+ })] }) : /* @__PURE__ */ E("p", {
243
256
  className: "text-sm text-text-muted",
244
257
  children: "Rate completed sessions to compare coaches."
245
258
  })]
246
259
  })]
247
260
  }),
248
- /* @__PURE__ */ T("div", {
261
+ /* @__PURE__ */ D("div", {
249
262
  className: "grid grid-cols-1 gap-6 lg:grid-cols-2",
250
- children: [/* @__PURE__ */ T(D, {
263
+ children: [/* @__PURE__ */ D(k, {
251
264
  treatment: "insight",
252
265
  className: "p-6",
253
- children: [/* @__PURE__ */ T("div", {
266
+ children: [/* @__PURE__ */ D("div", {
254
267
  className: "mb-4 flex items-center justify-between gap-2",
255
- children: [/* @__PURE__ */ w("h2", {
268
+ children: [/* @__PURE__ */ E("h2", {
256
269
  className: "text-lg font-semibold text-text-primary",
257
270
  children: "Weekly training load"
258
- }), /* @__PURE__ */ w(M, { children: /* @__PURE__ */ T(A, { children: [/* @__PURE__ */ w(N, {
271
+ }), /* @__PURE__ */ E(P, { children: /* @__PURE__ */ D(M, { children: [/* @__PURE__ */ E(F, {
259
272
  asChild: !0,
260
- children: /* @__PURE__ */ w("button", {
273
+ children: /* @__PURE__ */ E("button", {
261
274
  type: "button",
262
275
  "aria-label": "About ACWR training load",
263
276
  className: "rounded-full p-1 text-text-muted transition-colors hover:text-text-primary",
264
- children: /* @__PURE__ */ w(b, { className: "h-4 w-4" })
277
+ children: /* @__PURE__ */ E(x, { className: "h-4 w-4" })
265
278
  })
266
- }), /* @__PURE__ */ T(j, {
279
+ }), /* @__PURE__ */ D(N, {
267
280
  className: "max-w-xs",
268
281
  children: [
269
282
  "Total workout load per week (sum of real ",
270
- /* @__PURE__ */ w("code", { children: "totalLoad" }),
283
+ /* @__PURE__ */ E("code", { children: "totalLoad" }),
271
284
  "). 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
285
  ]
273
286
  })] }) })]
274
- }), L.loadTrend.some((e) => e.value > 0) ? /* @__PURE__ */ T(C, { children: [/* @__PURE__ */ w(r, {
275
- series: L.loadTrend,
287
+ }), z.loadTrend.some((e) => e.value > 0) ? /* @__PURE__ */ D(T, { children: [/* @__PURE__ */ E(i, {
288
+ series: z.loadTrend,
276
289
  seriesLabel: "Training load",
277
290
  height: 200,
278
291
  valueFormatter: (e) => e.toLocaleString()
279
- }), /* @__PURE__ */ T("div", {
292
+ }), /* @__PURE__ */ D("div", {
280
293
  className: "mt-4 flex flex-wrap items-center gap-x-6 gap-y-2 text-sm",
281
294
  children: [
282
- /* @__PURE__ */ T("span", {
295
+ /* @__PURE__ */ D("span", {
283
296
  className: "text-text-secondary",
284
297
  children: [
285
298
  "Acute (7d)",
286
299
  " ",
287
- /* @__PURE__ */ w("span", {
300
+ /* @__PURE__ */ E("span", {
288
301
  className: "font-semibold tabular-nums text-text-primary",
289
- children: Math.round(L.trainingLoad.acute).toLocaleString()
302
+ children: Math.round(z.trainingLoad.acute).toLocaleString()
290
303
  })
291
304
  ]
292
305
  }),
293
- /* @__PURE__ */ T("span", {
306
+ /* @__PURE__ */ D("span", {
294
307
  className: "text-text-secondary",
295
308
  children: [
296
309
  "Chronic (28d avg)",
297
310
  " ",
298
- /* @__PURE__ */ w("span", {
311
+ /* @__PURE__ */ E("span", {
299
312
  className: "font-semibold tabular-nums text-text-primary",
300
- children: Math.round(L.trainingLoad.chronic).toLocaleString()
313
+ children: Math.round(z.trainingLoad.chronic).toLocaleString()
301
314
  })
302
315
  ]
303
316
  }),
304
- /* @__PURE__ */ T("span", {
317
+ /* @__PURE__ */ D("span", {
305
318
  className: "flex items-center gap-2 text-text-secondary",
306
- children: ["ACWR", /* @__PURE__ */ w(E, {
307
- variant: U.variant,
319
+ children: ["ACWR", /* @__PURE__ */ E(O, {
320
+ variant: K.variant,
308
321
  className: "tabular-nums",
309
- children: L.trainingLoad.ratio == null ? U.label : `${L.trainingLoad.ratio.toFixed(2)} · ${U.label}`
322
+ children: z.trainingLoad.ratio == null ? K.label : `${z.trainingLoad.ratio.toFixed(2)} · ${K.label}`
310
323
  })]
311
324
  })
312
325
  ]
313
- })] }) : /* @__PURE__ */ w("p", {
326
+ })] }) : /* @__PURE__ */ E("p", {
314
327
  className: "text-sm text-text-muted",
315
328
  children: "Log workouts with a load to see training trend."
316
329
  })]
317
- }), /* @__PURE__ */ T(D, {
330
+ }), /* @__PURE__ */ D(k, {
318
331
  treatment: "insight",
319
332
  className: "p-6",
320
- children: [/* @__PURE__ */ w("h2", {
333
+ children: [/* @__PURE__ */ E("h2", {
321
334
  className: "mb-4 text-lg font-semibold text-text-primary",
322
335
  children: "Sessions per week"
323
- }), L.sessionTrend.some((e) => e.value > 0) ? /* @__PURE__ */ w(i, {
324
- series: L.sessionTrend,
336
+ }), z.sessionTrend.some((e) => e.value > 0) ? /* @__PURE__ */ E(a, {
337
+ series: z.sessionTrend,
325
338
  height: 200,
326
339
  valueFormatter: (e) => e.toLocaleString()
327
- }) : /* @__PURE__ */ w("p", {
340
+ }) : /* @__PURE__ */ E("p", {
328
341
  className: "text-sm text-text-muted",
329
342
  children: "Schedule sessions to see weekly volume."
330
343
  })]
331
344
  })]
332
345
  }),
333
- L.standings.length > 0 ? /* @__PURE__ */ T("section", { children: [/* @__PURE__ */ T("div", {
346
+ /* @__PURE__ */ E(H, {
347
+ rows: z.loadByAthlete,
348
+ directory: B,
349
+ truncated: z.loadSampleTruncated,
350
+ tr: r
351
+ }),
352
+ z.standings.length > 0 ? /* @__PURE__ */ D("section", { children: [/* @__PURE__ */ D("div", {
334
353
  className: "mb-4 flex flex-wrap items-center justify-between gap-3",
335
- children: [/* @__PURE__ */ T("h2", {
354
+ children: [/* @__PURE__ */ D("h2", {
336
355
  className: "flex items-center gap-2 text-lg font-semibold text-text-primary",
337
356
  children: [
338
- /* @__PURE__ */ w(_, { className: "h-5 w-5 text-text-muted" }),
357
+ /* @__PURE__ */ E(v, { className: "h-5 w-5 text-text-muted" }),
339
358
  "League standings",
340
- L.competition ? /* @__PURE__ */ w(E, {
359
+ z.competition ? /* @__PURE__ */ E(O, {
341
360
  variant: "secondary",
342
- children: L.competition
361
+ children: z.competition
343
362
  }) : null
344
363
  ]
345
- }), /* @__PURE__ */ w("button", {
364
+ }), /* @__PURE__ */ E("button", {
346
365
  type: "button",
347
- onClick: () => n("/standings"),
366
+ onClick: () => w("/standings"),
348
367
  className: "text-sm font-medium text-[var(--color-accent-teal)] transition-colors hover:underline",
349
368
  children: "View full standings"
350
369
  })]
351
- }), /* @__PURE__ */ w(D, {
370
+ }), /* @__PURE__ */ E(k, {
352
371
  treatment: "insight",
353
372
  className: "p-2 sm:p-4",
354
- children: /* @__PURE__ */ w(k, {
355
- columns: V,
356
- data: L.standings,
373
+ children: /* @__PURE__ */ E(j, {
374
+ columns: W,
375
+ data: z.standings,
357
376
  rowKey: (e) => e.id
358
377
  })
359
378
  })] }) : null
360
379
  ]
361
- }) : /* @__PURE__ */ w(d, {
380
+ }) : /* @__PURE__ */ E(f, {
362
381
  illustration: "empty-data",
363
- icon: /* @__PURE__ */ w(v, { className: "h-10 w-10" }),
382
+ icon: /* @__PURE__ */ E(y, { className: "h-10 w-10" }),
364
383
  title: "No coaching data yet",
365
384
  description: "Book and complete sessions, log workouts and record fixtures to unlock analytics."
366
385
  })
367
386
  });
368
387
  }
388
+ function H({ rows: e, directory: t, truncated: n, tr: r }) {
389
+ let i = _(() => e.reduce((e, t) => Math.max(e, t.acute, t.chronic), 0), [e]), a = _(() => [
390
+ {
391
+ key: "athlete",
392
+ header: r("atheletebridge.pages.analytics.loadByAthlete.athlete", "Athlete"),
393
+ priority: "primary",
394
+ cell: (e) => /* @__PURE__ */ D("span", {
395
+ className: "flex items-center gap-2",
396
+ children: [/* @__PURE__ */ E(d, {
397
+ name: t.nameOf(e.athleteId),
398
+ id: e.athleteId,
399
+ size: "xs"
400
+ }), /* @__PURE__ */ D("span", {
401
+ className: "min-w-0",
402
+ children: [/* @__PURE__ */ E("span", {
403
+ className: "block truncate font-medium text-text-primary",
404
+ children: R(t.nameOf(e.athleteId), e.athleteId, "Athlete")
405
+ }), /* @__PURE__ */ D("span", {
406
+ className: "block text-xs tabular-nums text-text-muted",
407
+ children: [
408
+ e.workoutCount,
409
+ " ",
410
+ r("atheletebridge.pages.analytics.loadByAthlete.workouts28d", "workouts · 28d")
411
+ ]
412
+ })]
413
+ })]
414
+ })
415
+ },
416
+ {
417
+ key: "acute",
418
+ header: r("atheletebridge.pages.analytics.loadByAthlete.acute", "Acute load (7d)"),
419
+ priority: "secondary",
420
+ mobileLabel: r("atheletebridge.pages.analytics.loadByAthlete.acute", "Acute load (7d)"),
421
+ cell: (e) => e.loadedCount === 0 ? /* @__PURE__ */ E("span", {
422
+ className: "text-text-muted",
423
+ children: "—"
424
+ }) : /* @__PURE__ */ D("span", {
425
+ className: "flex items-center gap-2",
426
+ children: [/* @__PURE__ */ E("span", {
427
+ className: "w-14 text-right font-medium tabular-nums text-text-primary",
428
+ children: z(e.acute)
429
+ }), /* @__PURE__ */ E(B, {
430
+ value: e.acute,
431
+ max: i
432
+ })]
433
+ })
434
+ },
435
+ {
436
+ key: "chronic",
437
+ header: r("atheletebridge.pages.analytics.loadByAthlete.chronic", "Chronic load (28d avg)"),
438
+ priority: "secondary",
439
+ mobileLabel: r("atheletebridge.pages.analytics.loadByAthlete.chronic", "Chronic load (28d avg)"),
440
+ cell: (e) => e.loadedCount === 0 ? /* @__PURE__ */ E("span", {
441
+ className: "text-text-muted",
442
+ children: "—"
443
+ }) : /* @__PURE__ */ D("span", {
444
+ className: "flex items-center gap-2",
445
+ children: [/* @__PURE__ */ E("span", {
446
+ className: "w-14 text-right font-medium tabular-nums text-text-primary",
447
+ children: z(e.chronic)
448
+ }), /* @__PURE__ */ E(B, {
449
+ value: e.chronic,
450
+ max: i
451
+ })]
452
+ })
453
+ },
454
+ {
455
+ key: "ratio",
456
+ header: r("atheletebridge.pages.analytics.loadByAthlete.ratio", "Load ratio"),
457
+ priority: "secondary",
458
+ mobileLabel: r("atheletebridge.pages.analytics.loadByAthlete.ratio", "Load ratio"),
459
+ cell: (e) => e.ratio == null ? /* @__PURE__ */ E("span", {
460
+ className: "text-text-muted",
461
+ children: "—"
462
+ }) : /* @__PURE__ */ E("span", {
463
+ className: "font-semibold tabular-nums text-text-primary",
464
+ children: e.ratio.toFixed(2)
465
+ })
466
+ },
467
+ {
468
+ key: "band",
469
+ header: r("atheletebridge.pages.analytics.loadByAthlete.status", "Status"),
470
+ priority: "primary",
471
+ mobileLabel: r("atheletebridge.pages.analytics.loadByAthlete.status", "Status"),
472
+ cell: (e) => {
473
+ let t = L(e.ratio);
474
+ return /* @__PURE__ */ E(O, {
475
+ variant: t.variant,
476
+ children: t.label
477
+ });
478
+ }
479
+ }
480
+ ], [
481
+ t,
482
+ i,
483
+ r
484
+ ]);
485
+ return /* @__PURE__ */ D("section", { children: [/* @__PURE__ */ D("div", {
486
+ className: "mb-4 flex flex-wrap items-center gap-2",
487
+ children: [/* @__PURE__ */ D("h2", {
488
+ className: "flex items-center gap-2 text-lg font-semibold text-text-primary",
489
+ children: [/* @__PURE__ */ E(w, { className: "h-5 w-5 text-text-muted" }), r("atheletebridge.pages.analytics.loadByAthlete.title", "Training load by athlete")]
490
+ }), /* @__PURE__ */ E(P, { children: /* @__PURE__ */ D(M, { children: [/* @__PURE__ */ E(F, {
491
+ asChild: !0,
492
+ children: /* @__PURE__ */ E("button", {
493
+ type: "button",
494
+ "aria-label": r("atheletebridge.pages.analytics.loadByAthlete.aboutLabel", "About per-athlete training load"),
495
+ className: "rounded-full p-1 text-text-muted transition-colors hover:text-text-primary",
496
+ children: /* @__PURE__ */ E(x, { className: "h-4 w-4" })
497
+ })
498
+ }), /* @__PURE__ */ E(N, {
499
+ className: "max-w-xs",
500
+ children: r("atheletebridge.pages.analytics.loadByAthlete.about", "Each athlete’s acute:chronic workload ratio — their last 7 days of logged workout load against their 28-day weekly average. 0.8–1.3 is the typical sweet spot; above 1.5 is a spike worth reviewing.")
501
+ })] }) })]
502
+ }), e.length === 0 ? /* @__PURE__ */ E(k, {
503
+ treatment: "insight",
504
+ className: "p-6",
505
+ children: /* @__PURE__ */ E("p", {
506
+ className: "text-sm text-text-muted",
507
+ children: r("atheletebridge.pages.analytics.loadByAthlete.empty", "No workouts logged in the last 28 days. Log workouts with a total load to compare athletes.")
508
+ })
509
+ }) : /* @__PURE__ */ D(T, { children: [/* @__PURE__ */ E(k, {
510
+ treatment: "insight",
511
+ className: "p-2 sm:p-4",
512
+ children: /* @__PURE__ */ E(j, {
513
+ columns: a,
514
+ data: e,
515
+ rowKey: (e) => e.athleteId,
516
+ caption: r("atheletebridge.pages.analytics.loadByAthlete.caption", "Acute and chronic training load per athlete over the last 28 days")
517
+ })
518
+ }), n ? /* @__PURE__ */ E("p", {
519
+ className: "mt-3 text-xs text-text-muted",
520
+ children: r("atheletebridge.pages.analytics.loadByAthlete.truncated", "Computed from the most recent page of workout logs, which does not reach back a full 28 days — these loads are a floor, not a total.")
521
+ }) : null] })] });
522
+ }
369
523
  //#endregion
370
- export { L as CoachAnalyticsPage };
524
+ export { V as CoachAnalyticsPage };
371
525
 
372
526
  //# sourceMappingURL=CoachAnalyticsPage.js.map