@burdenoff/microfe-atheletebridge 2026.805.1 → 2026.829.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 (54) hide show
  1. package/dist/atheletebridge/components/LoadingState.d.ts.map +1 -1
  2. package/dist/atheletebridge/components/LoadingState.js +39 -32
  3. package/dist/atheletebridge/components/LoadingState.js.map +1 -1
  4. package/dist/atheletebridge/components/TeamCard.d.ts.map +1 -1
  5. package/dist/atheletebridge/components/TeamCard.js +45 -49
  6. package/dist/atheletebridge/components/TeamCard.js.map +1 -1
  7. package/dist/atheletebridge/hooks/index.d.ts +1 -1
  8. package/dist/atheletebridge/hooks/index.d.ts.map +1 -1
  9. package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts +41 -1
  10. package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts.map +1 -1
  11. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +58 -28
  12. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  13. package/dist/atheletebridge/pages/DashboardPage.d.ts.map +1 -1
  14. package/dist/atheletebridge/pages/DashboardPage.js +56 -24
  15. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  16. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.d.ts +6 -2
  17. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.d.ts.map +1 -1
  18. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js +330 -174
  19. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js.map +1 -1
  20. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.d.ts.map +1 -1
  21. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +110 -106
  22. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -1
  23. package/dist/atheletebridge/pages/fixtures/FixturesListPage.d.ts.map +1 -1
  24. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js +80 -71
  25. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -1
  26. package/dist/atheletebridge/pages/onboarding/OnboardingPage.d.ts.map +1 -1
  27. package/dist/atheletebridge/pages/onboarding/OnboardingPage.js +244 -210
  28. package/dist/atheletebridge/pages/onboarding/OnboardingPage.js.map +1 -1
  29. package/dist/atheletebridge/pages/performance/PerformancePage.d.ts +7 -0
  30. package/dist/atheletebridge/pages/performance/PerformancePage.d.ts.map +1 -1
  31. package/dist/atheletebridge/pages/performance/PerformancePage.js +526 -362
  32. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -1
  33. package/dist/atheletebridge/pages/programs/ProgramDetailPage.d.ts.map +1 -1
  34. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +169 -143
  35. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  36. package/dist/atheletebridge/pages/programs/ProgramsListPage.d.ts.map +1 -1
  37. package/dist/atheletebridge/pages/programs/ProgramsListPage.js +77 -72
  38. package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -1
  39. package/dist/atheletebridge/pages/sessions/SessionDetailPage.d.ts.map +1 -1
  40. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +104 -86
  41. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
  42. package/dist/atheletebridge/pages/sessions/SessionsListPage.d.ts.map +1 -1
  43. package/dist/atheletebridge/pages/sessions/SessionsListPage.js +54 -49
  44. package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -1
  45. package/dist/atheletebridge/pages/teams/TeamDetailPage.d.ts.map +1 -1
  46. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +286 -267
  47. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  48. package/dist/atheletebridge/pages/teams/TeamFormPage.d.ts.map +1 -1
  49. package/dist/atheletebridge/pages/teams/TeamFormPage.js +185 -180
  50. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
  51. package/dist/atheletebridge/pages/teams/TeamsListPage.d.ts.map +1 -1
  52. package/dist/atheletebridge/pages/teams/TeamsListPage.js +70 -74
  53. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
  54. package/package.json +1 -1
@@ -1,122 +1,193 @@
1
- import { cn as e } from "../../utils/cn.js";
2
- import { PageLayout as t } from "../../components/PageLayout.js";
3
- import { Sparkline as n } from "../../components/viz/Sparkline.js";
1
+ import { useAbTranslate as e } from "../../i18n.js";
2
+ import { cn as t } from "../../utils/cn.js";
3
+ import { PageLayout as n } from "../../components/PageLayout.js";
4
+ import { Sparkline as r } from "../../components/viz/Sparkline.js";
4
5
  import "../../components/viz/index.js";
5
- import { StatusBadge as r } from "../../components/StatusBadge.js";
6
- import { METRIC_TYPE_LABELS as i } from "../../components/domain.js";
7
- import { formatDate as a, formatDuration as o } from "../../utils/formatters.js";
8
- import { EmptyState as s } from "../../components/EmptyState.js";
9
- import { ErrorState as c, LoadingState as l } from "../../components/LoadingState.js";
10
- import { useLogWorkout as u, usePerformanceMetrics as d, useRecordMetric as f, useWorkoutLogs as p } from "../../hooks/useAthleteBridgeApi.js";
11
- import { CursorPager as m } from "../../components/CursorPager.js";
12
- import { FormField as h, fieldInputClass as g } from "../../components/form.js";
13
- import { AthleteSelect as _ } from "../../components/AthleteSelect.js";
14
- import { useMemo as v, useState as y } from "react";
15
- import { Activity as b, ArrowDown as x, ArrowUp as S, Dumbbell as C, Gauge as w, HeartPulse as T, Loader2 as E, Move as D, Plus as O, Save as k, Scale as A, Target as j, Users as M, Zap as N } from "lucide-react";
16
- import { Fragment as P, jsx as F, jsxs as I } from "react/jsx-runtime";
17
- import { GlassCard as L, ResponsiveDialog as R, ResponsiveDialogContent as z, ResponsiveDialogFooter as B, ResponsiveDialogHeader as V, ResponsiveDialogTitle as H, ResponsiveTable as U } from "@burdenoff/fe-libs/ui";
6
+ import { StatusBadge as i } from "../../components/StatusBadge.js";
7
+ import { METRIC_TYPE_LABELS as a } from "../../components/domain.js";
8
+ import { formatDate as o, formatDuration as s } from "../../utils/formatters.js";
9
+ import { EmptyState as c } from "../../components/EmptyState.js";
10
+ import { ErrorState as l, LoadingState as u } from "../../components/LoadingState.js";
11
+ import { useLogWorkout as d, usePerformanceMetrics as f, useRecordMetric as p, useWorkoutLogs as m } from "../../hooks/useAthleteBridgeApi.js";
12
+ import { CursorPager as h } from "../../components/CursorPager.js";
13
+ import { FilterSelect as g } from "../../components/FilterSelect.js";
14
+ import { FormField as _, fieldInputClass as v } from "../../components/form.js";
15
+ import { AthleteSelect as y } from "../../components/AthleteSelect.js";
16
+ import { useMemo as b, useState as x } from "react";
17
+ import { Activity as S, ArrowDown as C, ArrowUp as w, CalendarRange as T, Dumbbell as E, Gauge as D, HeartPulse as O, Loader2 as k, Move as A, Plus as j, Save as M, Scale as N, Target as P, Users as F, Zap as I } from "lucide-react";
18
+ import { Fragment as L, jsx as R, jsxs as z } from "react/jsx-runtime";
19
+ import { GlassCard as B, ResponsiveDialog as V, ResponsiveDialogContent as H, ResponsiveDialogFooter as U, ResponsiveDialogHeader as W, ResponsiveDialogTitle as G, ResponsiveTable as ee } from "@burdenoff/fe-libs/ui";
18
20
  //#region src/atheletebridge/pages/performance/PerformancePage.tsx
19
- var W = 10, G = [
21
+ var K = 10, q = [
20
22
  "COMPLETED",
21
23
  "PLANNED",
22
24
  "SKIPPED"
23
- ], K = Object.keys(i), q = "inline-flex items-center justify-center gap-1.5 rounded-lg px-4 py-2 text-sm font-semibold text-action-primary-text shadow-elevation-1 transition-[filter,box-shadow] hover:shadow-elevation-2 hover:brightness-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] bg-[linear-gradient(120deg,var(--color-action-primary-bg),color-mix(in_oklab,var(--color-action-primary-bg)_62%,var(--color-accent-purple)),var(--color-action-primary-bg))]", J = {
24
- SPEED: N,
25
- ENDURANCE: b,
26
- STRENGTH: C,
27
- AGILITY: D,
28
- ACCURACY: j,
29
- WEIGHT: A,
30
- HEART_RATE: T,
31
- CUSTOM: w
32
- }, Y = (e) => {
25
+ ], J = Object.keys(a), te = 100, ne = { limit: 100 }, re = [
26
+ "7d",
27
+ "28d",
28
+ "90d"
29
+ ], Y = {
30
+ "7d": 7,
31
+ "28d": 28,
32
+ "90d": 90
33
+ }, ie = (e) => {
34
+ let t = /* @__PURE__ */ new Date();
35
+ t.setHours(23, 59, 59, 999);
36
+ let n = new Date(t);
37
+ return n.setHours(0, 0, 0, 0), n.setDate(n.getDate() - (Y[e] - 1)), {
38
+ start: n.getTime(),
39
+ end: t.getTime()
40
+ };
41
+ }, X = (e) => new Date(e).getTime(), ae = (e) => o(new Date(e), {
42
+ hour: void 0,
43
+ minute: void 0,
44
+ hour12: void 0
45
+ }), oe = (e) => `${ae(e.start)} – ${ae(e.end)}`, se = (e, t) => {
46
+ switch (e) {
47
+ case "7d": return t("atheletebridge.pages.performance.window.last7", "Last 7 days");
48
+ case "28d": return t("atheletebridge.pages.performance.window.last28", "Last 28 days");
49
+ case "90d": return t("atheletebridge.pages.performance.window.last90", "Last 90 days");
50
+ }
51
+ }, ce = (e, t) => {
52
+ switch (e) {
53
+ case "7d": return t("atheletebridge.pages.performance.window.vsLast7", "vs previous 7 days");
54
+ case "28d": return t("atheletebridge.pages.performance.window.vsLast28", "vs previous 28 days");
55
+ case "90d": return t("atheletebridge.pages.performance.window.vsLast90", "vs previous 90 days");
56
+ }
57
+ }, le = (e, t) => {
58
+ switch (e) {
59
+ case "7d": return t("atheletebridge.pages.performance.window.noPrior7", "No reading in the previous 7 days");
60
+ case "28d": return t("atheletebridge.pages.performance.window.noPrior28", "No reading in the previous 28 days");
61
+ case "90d": return t("atheletebridge.pages.performance.window.noPrior90", "No reading in the previous 90 days");
62
+ }
63
+ }, Z = "inline-flex items-center justify-center gap-1.5 rounded-lg px-4 py-2 text-sm font-semibold text-action-primary-text shadow-elevation-1 transition-[filter,box-shadow] hover:shadow-elevation-2 hover:brightness-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] bg-[linear-gradient(120deg,var(--color-action-primary-bg),color-mix(in_oklab,var(--color-action-primary-bg)_62%,var(--color-accent-purple)),var(--color-action-primary-bg))]", ue = {
64
+ SPEED: I,
65
+ ENDURANCE: S,
66
+ STRENGTH: E,
67
+ AGILITY: A,
68
+ ACCURACY: P,
69
+ WEIGHT: N,
70
+ HEART_RATE: O,
71
+ CUSTOM: D
72
+ }, de = (e) => {
33
73
  let t = e.trim();
34
74
  if (!t) return;
35
75
  let n = Number.parseInt(t, 10);
36
76
  return Number.isNaN(n) ? void 0 : n;
37
- }, X = (e) => {
77
+ }, fe = (e) => {
38
78
  let t = e.trim();
39
79
  if (!t) return;
40
80
  let n = Number.parseFloat(t);
41
81
  return Number.isNaN(n) ? void 0 : n;
42
- }, Z = () => {
82
+ }, Q = () => {
43
83
  let e = /* @__PURE__ */ new Date();
44
84
  return (/* @__PURE__ */ new Date(e.getTime() - e.getTimezoneOffset() * 6e4)).toISOString().slice(0, 16);
45
- }, Q = (e) => (Math.abs(e) >= 100 ? e.toFixed(0) : e.toFixed(2)).replace(/\.?0+$/, "");
46
- function $() {
47
- let [e, n] = y({
85
+ }, $ = (e) => (Math.abs(e) >= 100 ? e.toFixed(0) : e.toFixed(2)).replace(/\.?0+$/, "");
86
+ function pe() {
87
+ let t = e(), [r, i] = x({
48
88
  athleteId: "",
49
89
  displayName: ""
50
90
  });
51
- return /* @__PURE__ */ I(t, {
52
- title: "Performance",
53
- description: "Log workouts, record metrics and track an athlete's progress over time.",
54
- children: [/* @__PURE__ */ F("div", {
91
+ return /* @__PURE__ */ z(n, {
92
+ title: t("atheletebridge.pages.performance.title", "Performance"),
93
+ description: t("atheletebridge.pages.performance.description", "Log workouts, record metrics and track an athlete's progress over time."),
94
+ children: [/* @__PURE__ */ R("div", {
55
95
  "data-tour": "performance-athlete-picker",
56
96
  className: "sticky top-0 z-20 -mx-6 mb-8 bg-bg-canvas/80 px-6 pb-4 pt-1 backdrop-blur supports-[backdrop-filter]:bg-bg-canvas/60",
57
- children: /* @__PURE__ */ F(L, {
97
+ children: /* @__PURE__ */ R(B, {
58
98
  treatment: "insight",
59
99
  className: "p-5 sm:p-6",
60
- children: /* @__PURE__ */ F(_, {
61
- athleteId: e.athleteId,
62
- onSelect: n,
100
+ children: /* @__PURE__ */ R(y, {
101
+ athleteId: r.athleteId,
102
+ onSelect: i,
63
103
  idPrefix: "perf-athlete"
64
104
  })
65
105
  })
66
- }), e.athleteId ? /* @__PURE__ */ F(ee, {
67
- athleteId: e.athleteId,
68
- displayName: e.displayName
69
- }) : /* @__PURE__ */ F(s, {
106
+ }), r.athleteId ? /* @__PURE__ */ R(me, {
107
+ athleteId: r.athleteId,
108
+ displayName: r.displayName
109
+ }) : /* @__PURE__ */ R(c, {
70
110
  illustration: "empty-data",
71
- icon: /* @__PURE__ */ F(M, { className: "h-10 w-10" }),
72
- title: "Pick an athlete to begin",
73
- description: "Choose a team and an athlete above to log workouts, record metrics and review their history."
111
+ icon: /* @__PURE__ */ R(F, { className: "h-10 w-10" }),
112
+ title: t("atheletebridge.pages.performance.pickAthleteTitle", "Pick an athlete to begin"),
113
+ description: t("atheletebridge.pages.performance.pickAthleteHint", "Choose a team and an athlete above to log workouts, record metrics and review their history.")
74
114
  })]
75
115
  });
76
116
  }
77
- function ee({ athleteId: t, displayName: n }) {
78
- let [i, u] = y(0), [f, h] = y(!1), [g, _] = y(!1), x = p({
79
- athleteId: t,
80
- pagination: {
81
- limit: W,
82
- offset: i * W
117
+ function me({ athleteId: n, displayName: r }) {
118
+ let a = e(), [d, p] = x(0), [_, v] = x(""), [y, C] = x(!1), [w, O] = x(!1), k = b(() => _ === "" ? null : ie(_), [_]), A = m({
119
+ athleteId: n,
120
+ pagination: k ? { limit: te } : {
121
+ limit: K,
122
+ offset: d * K
83
123
  }
84
- }), S = d(t), T = x.data?.items ?? [], E = x.data?.pageInfo.hasMore ?? !1, D = v(() => {
124
+ }), M = f(n, ne), N = b(() => A.data?.items ?? [], [A.data]), P = A.data?.pageInfo.hasMore ?? !1, F = b(() => k ? N.filter((e) => {
125
+ let t = X(e.performedAt);
126
+ return t >= k.start && t <= k.end;
127
+ }) : N, [N, k]), I = k ? Math.max(0, Math.ceil(F.length / K) - 1) : d, V = Math.min(d, I), H = k ? F.slice(V * K, (V + 1) * K) : F, U = k ? F.length > (V + 1) * K : P, W = b(() => {
128
+ if (!k || !P) return !0;
129
+ let e = N[N.length - 1];
130
+ return e != null && X(e.performedAt) <= k.start;
131
+ }, [
132
+ k,
133
+ P,
134
+ N
135
+ ]), G = b(() => re.map((e) => ({
136
+ value: e,
137
+ label: `${se(e, a)} · ${oe(ie(e))}`
138
+ })), [a]), q = b(() => _ === "" ? {
139
+ comparison: a("atheletebridge.pages.performance.window.vsPrevious", "vs previous"),
140
+ noComparison: a("atheletebridge.pages.performance.window.firstReading", "First reading")
141
+ } : {
142
+ comparison: ce(_, a),
143
+ noComparison: le(_, a)
144
+ }, [_, a]), J = b(() => {
85
145
  let e = /* @__PURE__ */ new Map();
86
- for (let t of S.data ?? []) {
146
+ for (let t of M.data ?? []) {
87
147
  let n = `${t.type}::${t.label}`, r = e.get(n) ?? [];
88
148
  r.push(t), e.set(n, r);
89
149
  }
90
150
  return Array.from(e.entries()).map(([e, t]) => {
91
- let n = [...t].sort((e, t) => new Date(e.recordedAt).getTime() - new Date(t.recordedAt).getTime()), r = n.map((e) => e.value), i = n[n.length - 1], a = n.length > 1 ? n[n.length - 2] : null;
151
+ let n = [...t].sort((e, t) => X(e.recordedAt) - X(t.recordedAt)), r = k ? n.filter((e) => {
152
+ let t = X(e.recordedAt);
153
+ return t >= k.start && t <= k.end;
154
+ }) : n;
155
+ if (r.length === 0) return null;
156
+ let i = r.map((e) => e.value), a = r[r.length - 1], o = null;
157
+ if (k) {
158
+ let e = k.start - (k.end - k.start + 1), t = n.filter((t) => {
159
+ let n = X(t.recordedAt);
160
+ return n >= e && n < k.start;
161
+ });
162
+ o = t.length > 0 ? t[t.length - 1].value : null;
163
+ } else o = n.length > 1 ? n[n.length - 2].value : null;
92
164
  return {
93
165
  key: e,
94
- type: i.type,
95
- label: i.label,
96
- unit: i.unit,
97
- latest: i.value,
98
- previous: a ? a.value : null,
99
- min: Math.min(...r),
100
- max: Math.max(...r),
101
- series: r,
102
- recordedAt: i.recordedAt,
103
- count: n.length
166
+ type: a.type,
167
+ label: a.label,
168
+ unit: a.unit,
169
+ latest: a.value,
170
+ previous: o,
171
+ min: Math.min(...i),
172
+ max: Math.max(...i),
173
+ series: i,
174
+ recordedAt: a.recordedAt
104
175
  };
105
- }).sort((e, t) => new Date(t.recordedAt).getTime() - new Date(e.recordedAt).getTime());
106
- }, [S.data]), k = v(() => [
176
+ }).filter((e) => e !== null).sort((e, t) => X(t.recordedAt) - X(e.recordedAt));
177
+ }, [M.data, k]), Y = b(() => [
107
178
  {
108
179
  key: "workout",
109
- header: "Workout",
180
+ header: a("atheletebridge.pages.performance.column.workout", "Workout"),
110
181
  priority: "primary",
111
- cell: (e) => /* @__PURE__ */ I("div", {
182
+ cell: (e) => /* @__PURE__ */ z("div", {
112
183
  className: "flex items-center gap-3",
113
- children: [/* @__PURE__ */ F("span", {
184
+ children: [/* @__PURE__ */ R("span", {
114
185
  className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-[var(--color-accent-teal)]",
115
- children: /* @__PURE__ */ F(te(e.title), {
186
+ children: /* @__PURE__ */ R(he(e.title), {
116
187
  className: "h-4 w-4",
117
188
  "aria-hidden": "true"
118
189
  })
119
- }), /* @__PURE__ */ F("span", {
190
+ }), /* @__PURE__ */ R("span", {
120
191
  className: "min-w-0 truncate font-medium text-text-primary",
121
192
  children: e.title
122
193
  })]
@@ -124,201 +195,270 @@ function ee({ athleteId: t, displayName: n }) {
124
195
  },
125
196
  {
126
197
  key: "duration",
127
- header: "Duration",
198
+ header: a("atheletebridge.pages.performance.column.duration", "Duration"),
128
199
  priority: "secondary",
129
- mobileLabel: "Duration",
130
- cell: (e) => e.durationMin == null ? /* @__PURE__ */ F("span", {
200
+ mobileLabel: a("atheletebridge.pages.performance.column.duration", "Duration"),
201
+ cell: (e) => e.durationMin == null ? /* @__PURE__ */ R("span", {
131
202
  className: "text-text-muted",
132
203
  children: "—"
133
- }) : /* @__PURE__ */ F("span", {
204
+ }) : /* @__PURE__ */ R("span", {
134
205
  className: "tabular-nums text-text-secondary",
135
- children: o(e.durationMin)
206
+ children: s(e.durationMin)
136
207
  })
137
208
  },
138
209
  {
139
210
  key: "rpe",
140
- header: "RPE",
211
+ header: a("atheletebridge.pages.performance.column.rpe", "RPE"),
141
212
  priority: "secondary",
142
- mobileLabel: "RPE",
143
- cell: (e) => e.rpe == null ? /* @__PURE__ */ F("span", {
213
+ mobileLabel: a("atheletebridge.pages.performance.column.rpe", "RPE"),
214
+ cell: (e) => e.rpe == null ? /* @__PURE__ */ R("span", {
144
215
  className: "text-text-muted",
145
216
  children: "—"
146
- }) : /* @__PURE__ */ F(ne, { rpe: e.rpe })
217
+ }) : /* @__PURE__ */ R(ge, { rpe: e.rpe })
147
218
  },
148
219
  {
149
220
  key: "date",
150
- header: "Date",
221
+ header: a("atheletebridge.pages.performance.column.date", "Date"),
151
222
  priority: "secondary",
152
- mobileLabel: "Date",
153
- cell: (e) => /* @__PURE__ */ F("span", {
223
+ mobileLabel: a("atheletebridge.pages.performance.column.date", "Date"),
224
+ cell: (e) => /* @__PURE__ */ R("span", {
154
225
  className: "tabular-nums text-text-secondary",
155
- children: a(e.performedAt)
226
+ children: o(e.performedAt)
156
227
  })
157
228
  },
158
229
  {
159
230
  key: "status",
160
- header: "Status",
231
+ header: a("atheletebridge.pages.performance.column.status", "Status"),
161
232
  priority: "primary",
162
- mobileLabel: "Status",
163
- cell: (e) => /* @__PURE__ */ F(r, { status: e.status })
233
+ mobileLabel: a("atheletebridge.pages.performance.column.status", "Status"),
234
+ cell: (e) => /* @__PURE__ */ R(i, { status: e.status })
164
235
  },
165
236
  {
166
237
  key: "notes",
167
- header: "Notes",
238
+ header: a("atheletebridge.pages.performance.column.notes", "Notes"),
168
239
  priority: "hidden-on-mobile",
169
- cell: (e) => e.notes ? /* @__PURE__ */ F("span", {
240
+ cell: (e) => e.notes ? /* @__PURE__ */ R("span", {
170
241
  className: "line-clamp-2 max-w-[22ch] text-text-secondary",
171
242
  children: e.notes
172
- }) : /* @__PURE__ */ F("span", {
243
+ }) : /* @__PURE__ */ R("span", {
173
244
  className: "text-text-muted",
174
245
  children: "—"
175
246
  })
176
247
  }
177
- ], []);
178
- return /* @__PURE__ */ I("div", {
248
+ ], [a]);
249
+ return /* @__PURE__ */ z("div", {
179
250
  className: "space-y-8 pb-24 sm:pb-0",
180
251
  children: [
181
- /* @__PURE__ */ I("div", {
252
+ /* @__PURE__ */ z("div", {
182
253
  className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
183
- children: [/* @__PURE__ */ I("p", {
254
+ children: [/* @__PURE__ */ z("p", {
184
255
  className: "text-sm text-text-secondary",
185
- children: ["Tracking ", /* @__PURE__ */ F("span", {
186
- className: "font-medium text-text-primary",
187
- children: n || "athlete"
188
- })]
189
- }), /* @__PURE__ */ I("div", {
190
- className: "flex flex-wrap gap-2",
191
- children: [/* @__PURE__ */ I("button", {
192
- type: "button",
193
- onClick: () => _(!0),
194
- className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
195
- children: [/* @__PURE__ */ F(w, { className: "h-4 w-4" }), " Record metric"]
196
- }), /* @__PURE__ */ I("button", {
197
- type: "button",
198
- onClick: () => h(!0),
199
- className: e(q, "hidden sm:inline-flex"),
200
- children: [/* @__PURE__ */ F(C, { className: "h-4 w-4" }), " Log workout"]
201
- })]
256
+ children: [
257
+ a("atheletebridge.pages.performance.tracking", "Tracking"),
258
+ " ",
259
+ /* @__PURE__ */ R("span", {
260
+ className: "font-medium text-text-primary",
261
+ children: r || a("atheletebridge.pages.performance.athleteFallback", "athlete")
262
+ }),
263
+ k ? /* @__PURE__ */ z(L, { children: [" · ", /* @__PURE__ */ R("span", {
264
+ className: "tabular-nums text-text-muted",
265
+ children: oe(k)
266
+ })] }) : null
267
+ ]
268
+ }), /* @__PURE__ */ z("div", {
269
+ className: "flex flex-wrap items-center gap-2",
270
+ children: [
271
+ /* @__PURE__ */ z("span", {
272
+ className: "flex items-center gap-2",
273
+ "data-tour": "performance-date-range",
274
+ children: [/* @__PURE__ */ R(T, {
275
+ className: "h-4 w-4 shrink-0 text-text-muted",
276
+ "aria-hidden": "true"
277
+ }), /* @__PURE__ */ R(g, {
278
+ value: _,
279
+ onChange: (e) => {
280
+ v(e), p(0);
281
+ },
282
+ options: G,
283
+ allLabel: a("atheletebridge.pages.performance.window.allTime", "All time"),
284
+ ariaLabel: a("atheletebridge.pages.performance.window.ariaLabel", "Date range")
285
+ })]
286
+ }),
287
+ /* @__PURE__ */ z("button", {
288
+ type: "button",
289
+ onClick: () => O(!0),
290
+ className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
291
+ children: [
292
+ /* @__PURE__ */ R(D, { className: "h-4 w-4" }),
293
+ " ",
294
+ a("atheletebridge.pages.performance.recordMetric", "Record metric")
295
+ ]
296
+ }),
297
+ /* @__PURE__ */ z("button", {
298
+ type: "button",
299
+ onClick: () => C(!0),
300
+ className: t(Z, "hidden sm:inline-flex"),
301
+ children: [
302
+ /* @__PURE__ */ R(E, { className: "h-4 w-4" }),
303
+ " ",
304
+ a("atheletebridge.pages.performance.logWorkout", "Log workout")
305
+ ]
306
+ })
307
+ ]
202
308
  })]
203
309
  }),
204
- /* @__PURE__ */ I("section", { children: [/* @__PURE__ */ F("h2", {
310
+ /* @__PURE__ */ z("section", { children: [/* @__PURE__ */ R("h2", {
205
311
  className: "mb-4 text-lg font-semibold text-text-primary",
206
- children: "Performance metrics"
207
- }), S.isLoading ? /* @__PURE__ */ F(l, { label: "Loading metrics…" }) : S.isError ? /* @__PURE__ */ F(c, { onRetry: () => void S.refetch() }) : D.length === 0 ? /* @__PURE__ */ F(s, {
312
+ children: a("atheletebridge.pages.performance.metricsTitle", "Performance metrics")
313
+ }), M.isLoading ? /* @__PURE__ */ R(u, { label: a("atheletebridge.pages.performance.loadingMetrics", "Loading metrics…") }) : M.isError ? /* @__PURE__ */ R(l, { onRetry: () => void M.refetch() }) : J.length === 0 ? /* @__PURE__ */ R(c, {
208
314
  illustration: "empty-data",
209
- icon: /* @__PURE__ */ F(w, { className: "h-10 w-10" }),
210
- title: "No metrics recorded",
211
- description: "Record a metric — speed, strength, endurance and more — to start charting progress.",
212
- action: /* @__PURE__ */ I("button", {
315
+ icon: /* @__PURE__ */ R(D, { className: "h-10 w-10" }),
316
+ title: k ? a("atheletebridge.pages.performance.metrics.emptyWindowTitle", "No metrics in this window") : a("atheletebridge.pages.performance.metrics.emptyTitle", "No metrics recorded"),
317
+ description: k ? a("atheletebridge.pages.performance.metrics.emptyWindowDescription", "Nothing was recorded for this athlete in the selected period. Widen the date range, or record a metric.") : a("atheletebridge.pages.performance.noMetricsDescription", "Record a metric — speed, strength, endurance and more — to start charting progress."),
318
+ action: /* @__PURE__ */ z("button", {
213
319
  type: "button",
214
- onClick: () => _(!0),
215
- className: q,
216
- children: [/* @__PURE__ */ F(O, { className: "h-4 w-4" }), " Record metric"]
320
+ onClick: () => O(!0),
321
+ className: Z,
322
+ children: [
323
+ /* @__PURE__ */ R(j, { className: "h-4 w-4" }),
324
+ " ",
325
+ a("atheletebridge.pages.performance.recordMetricAction", "Record metric")
326
+ ]
217
327
  })
218
- }) : /* @__PURE__ */ F("div", {
328
+ }) : /* @__PURE__ */ R("div", {
219
329
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
220
- children: D.map((e) => /* @__PURE__ */ F(re, { metric: e }, e.key))
330
+ children: J.map((e) => /* @__PURE__ */ R(_e, {
331
+ metric: e,
332
+ labels: q,
333
+ tr: a
334
+ }, e.key))
221
335
  })] }),
222
- /* @__PURE__ */ I("section", { children: [/* @__PURE__ */ F("h2", {
223
- className: "mb-4 text-lg font-semibold text-text-primary",
224
- children: "Workout history"
225
- }), x.isLoading ? /* @__PURE__ */ F(l, { label: "Loading workouts…" }) : x.isError ? /* @__PURE__ */ F(c, { onRetry: () => void x.refetch() }) : T.length === 0 ? /* @__PURE__ */ F(s, {
226
- illustration: "empty-data",
227
- icon: /* @__PURE__ */ F(b, { className: "h-10 w-10" }),
228
- title: "No workouts logged",
229
- description: "Log a workout to build this athlete's training history.",
230
- action: /* @__PURE__ */ I("button", {
231
- type: "button",
232
- onClick: () => h(!0),
233
- className: q,
234
- children: [/* @__PURE__ */ F(C, { className: "h-4 w-4" }), " Log workout"]
235
- })
236
- }) : /* @__PURE__ */ I(P, { children: [/* @__PURE__ */ F(L, {
237
- treatment: "metric",
238
- className: "overflow-hidden p-1 sm:p-2",
239
- children: /* @__PURE__ */ F(U, {
240
- columns: k,
241
- data: T,
242
- rowKey: (e) => e.id,
243
- caption: `Workout history for ${n || "athlete"}`
336
+ /* @__PURE__ */ z("section", { children: [
337
+ /* @__PURE__ */ R("h2", {
338
+ className: "mb-4 text-lg font-semibold text-text-primary",
339
+ children: a("atheletebridge.pages.performance.workoutsTitle", "Workout history")
340
+ }),
341
+ A.isLoading ? /* @__PURE__ */ R(u, { label: a("atheletebridge.pages.performance.loadingWorkouts", "Loading workouts…") }) : A.isError ? /* @__PURE__ */ R(l, { onRetry: () => void A.refetch() }) : H.length === 0 ? /* @__PURE__ */ R(c, {
342
+ illustration: "empty-data",
343
+ icon: /* @__PURE__ */ R(S, { className: "h-10 w-10" }),
344
+ title: k ? a("atheletebridge.pages.performance.workouts.emptyWindowTitle", "No workouts in this window") : a("atheletebridge.pages.performance.workouts.emptyTitle", "No workouts logged"),
345
+ description: k ? a("atheletebridge.pages.performance.workouts.emptyWindowDescription", "Nothing was logged for this athlete in the selected period. Widen the date range, or log a workout.") : a("atheletebridge.pages.performance.noWorkoutsDescription", "Log a workout to build this athlete's training history."),
346
+ action: /* @__PURE__ */ z("button", {
347
+ type: "button",
348
+ onClick: () => C(!0),
349
+ className: Z,
350
+ children: [
351
+ /* @__PURE__ */ R(E, { className: "h-4 w-4" }),
352
+ " ",
353
+ a("atheletebridge.pages.performance.logWorkout", "Log workout")
354
+ ]
355
+ })
356
+ }) : /* @__PURE__ */ z(L, { children: [/* @__PURE__ */ R(B, {
357
+ treatment: "metric",
358
+ className: "overflow-hidden p-1 sm:p-2",
359
+ children: /* @__PURE__ */ R(ee, {
360
+ columns: Y,
361
+ data: H,
362
+ rowKey: (e) => e.id,
363
+ caption: a("atheletebridge.pages.performance.workouts.caption", "Workout history for {{name}}").replace("{{name}}", r || a("atheletebridge.pages.performance.athleteFallback", "athlete"))
364
+ })
365
+ }), /* @__PURE__ */ R(h, {
366
+ className: "mt-6",
367
+ page: V,
368
+ hasMore: U,
369
+ onPrev: () => p(Math.max(0, V - 1)),
370
+ onNext: () => p(V + 1)
371
+ })] }),
372
+ W ? null : /* @__PURE__ */ R("p", {
373
+ className: "mt-3 text-xs text-text-muted",
374
+ children: a("atheletebridge.pages.performance.workouts.windowTruncated", "Only the most recent page of workouts was searched, and it does not reach back to the start of this window — older sessions in the range are not listed.")
244
375
  })
245
- }), /* @__PURE__ */ F(m, {
246
- className: "mt-6",
247
- page: i,
248
- hasMore: E,
249
- onPrev: () => u((e) => Math.max(0, e - 1)),
250
- onNext: () => u((e) => e + 1)
251
- })] })] }),
252
- /* @__PURE__ */ F("div", {
376
+ ] }),
377
+ /* @__PURE__ */ R("div", {
253
378
  className: "sticky bottom-0 z-30 -mx-6 border-t border-border-seam bg-bg-canvas/85 px-6 pb-[max(env(safe-area-inset-bottom),0.75rem)] pt-3 backdrop-blur sm:hidden",
254
- children: /* @__PURE__ */ I("button", {
379
+ children: /* @__PURE__ */ z("button", {
255
380
  type: "button",
256
- onClick: () => h(!0),
257
- className: e(q, "w-full py-3 text-base"),
258
- children: [/* @__PURE__ */ F(O, { className: "h-5 w-5" }), " Log workout"]
381
+ onClick: () => C(!0),
382
+ className: t(Z, "w-full py-3 text-base"),
383
+ children: [
384
+ /* @__PURE__ */ R(j, { className: "h-5 w-5" }),
385
+ " ",
386
+ a("atheletebridge.pages.performance.logWorkout", "Log workout")
387
+ ]
259
388
  })
260
389
  }),
261
- /* @__PURE__ */ F(ie, {
262
- open: f,
263
- onOpenChange: h,
264
- athleteId: t,
265
- displayName: n
390
+ /* @__PURE__ */ R(ve, {
391
+ open: y,
392
+ onOpenChange: C,
393
+ athleteId: n,
394
+ displayName: r
266
395
  }),
267
- /* @__PURE__ */ F(ae, {
268
- open: g,
269
- onOpenChange: _,
270
- athleteId: t,
271
- displayName: n
396
+ /* @__PURE__ */ R(ye, {
397
+ open: w,
398
+ onOpenChange: O,
399
+ athleteId: n,
400
+ displayName: r
272
401
  })
273
402
  ]
274
403
  });
275
404
  }
276
- function te(e) {
405
+ function he(e) {
277
406
  let t = e.toLowerCase();
278
- return /strength|lift|squat|deadlift|bench|1rm|weight/.test(t) ? C : /speed|sprint|agility|accel|split/.test(t) ? N : /endurance|aerobic|cardio|run|beep|yo-?yo/.test(t) ? b : /recovery|mobility|stretch|rest/.test(t) ? T : /accuracy|shoot|target/.test(t) ? j : C;
407
+ return /strength|lift|squat|deadlift|bench|1rm|weight/.test(t) ? E : /speed|sprint|agility|accel|split/.test(t) ? I : /endurance|aerobic|cardio|run|beep|yo-?yo/.test(t) ? S : /recovery|mobility|stretch|rest/.test(t) ? O : /accuracy|shoot|target/.test(t) ? P : E;
279
408
  }
280
- function ne({ rpe: t }) {
281
- return /* @__PURE__ */ F("span", {
282
- className: e("inline-flex h-7 min-w-[1.75rem] items-center justify-center rounded-md border px-1.5 text-sm font-semibold tabular-nums", t >= 8 ? "border-status-error-border text-status-error-text" : t >= 5 ? "border-status-warning-border text-status-warning-text" : "border-border-seam text-text-secondary"),
283
- children: t
409
+ function ge({ rpe: e }) {
410
+ return /* @__PURE__ */ R("span", {
411
+ className: t("inline-flex h-7 min-w-[1.75rem] items-center justify-center rounded-md border px-1.5 text-sm font-semibold tabular-nums", e >= 8 ? "border-status-error-border text-status-error-text" : e >= 5 ? "border-status-warning-border text-status-warning-text" : "border-border-seam text-text-secondary"),
412
+ children: e
284
413
  });
285
414
  }
286
- function re({ metric: e }) {
287
- let t = J[e.type], r = e.previous == null ? null : e.latest - e.previous, o = e.max > e.min, s = o ? Math.round((e.latest - e.min) / (e.max - e.min) * 100) : 100, c = e.unit ? ` ${e.unit}` : "";
288
- return /* @__PURE__ */ I(L, {
415
+ function _e({ metric: e, labels: t, tr: n }) {
416
+ let i = ue[e.type], a = e.previous == null ? null : e.latest - e.previous, s = e.max > e.min, c = s ? Math.round((e.latest - e.min) / (e.max - e.min) * 100) : 100, l = e.unit ? ` ${e.unit}` : "";
417
+ return /* @__PURE__ */ z(B, {
289
418
  treatment: "metric",
290
419
  className: "flex flex-col gap-3 p-5",
291
420
  children: [
292
- /* @__PURE__ */ I("div", {
421
+ /* @__PURE__ */ z("div", {
293
422
  className: "flex items-center justify-between gap-2",
294
- children: [/* @__PURE__ */ I("span", {
423
+ children: [/* @__PURE__ */ z("span", {
295
424
  className: "flex items-center gap-2 text-xs font-semibold uppercase tracking-wide text-[var(--color-accent-teal)]",
296
- children: [/* @__PURE__ */ F(t, {
425
+ children: [/* @__PURE__ */ R(i, {
297
426
  className: "h-4 w-4",
298
427
  "aria-hidden": "true"
299
- }), i[e.type]]
300
- }), /* @__PURE__ */ F("span", {
428
+ }), ((e) => {
429
+ switch (e) {
430
+ case "SPEED": return n("atheletebridge.metricType.speed", "Speed");
431
+ case "ENDURANCE": return n("atheletebridge.metricType.endurance", "Endurance");
432
+ case "STRENGTH": return n("atheletebridge.metricType.strength", "Strength");
433
+ case "AGILITY": return n("atheletebridge.metricType.agility", "Agility");
434
+ case "ACCURACY": return n("atheletebridge.metricType.accuracy", "Accuracy");
435
+ case "WEIGHT": return n("atheletebridge.metricType.weight", "Weight");
436
+ case "HEART_RATE": return n("atheletebridge.metricType.heartRate", "Heart Rate");
437
+ case "CUSTOM": return n("atheletebridge.metricType.custom", "Custom");
438
+ }
439
+ })(e.type)]
440
+ }), /* @__PURE__ */ R("span", {
301
441
  className: "text-xs text-text-muted",
302
- children: a(e.recordedAt)
442
+ children: o(e.recordedAt)
303
443
  })]
304
444
  }),
305
- /* @__PURE__ */ I("div", {
445
+ /* @__PURE__ */ z("div", {
306
446
  className: "flex items-end justify-between gap-3",
307
- children: [/* @__PURE__ */ I("div", {
447
+ children: [/* @__PURE__ */ z("div", {
308
448
  className: "min-w-0",
309
- children: [/* @__PURE__ */ F("p", {
449
+ children: [/* @__PURE__ */ R("p", {
310
450
  className: "truncate text-sm text-text-secondary",
311
451
  children: e.label
312
- }), /* @__PURE__ */ I("p", {
452
+ }), /* @__PURE__ */ z("p", {
313
453
  className: "mt-0.5 text-3xl font-bold leading-none tracking-tight tabular-nums text-text-primary",
314
- children: [Q(e.latest), e.unit ? /* @__PURE__ */ F("span", {
454
+ children: [$(e.latest), e.unit ? /* @__PURE__ */ R("span", {
315
455
  className: "ml-1 text-base font-medium text-text-secondary",
316
456
  children: e.unit
317
457
  }) : null]
318
458
  })]
319
- }), e.series.length > 1 ? /* @__PURE__ */ F("div", {
459
+ }), e.series.length > 1 ? /* @__PURE__ */ R("div", {
320
460
  className: "w-24 shrink-0 sm:w-28",
321
- children: /* @__PURE__ */ F(n, {
461
+ children: /* @__PURE__ */ R(r, {
322
462
  data: e.series,
323
463
  variant: "area",
324
464
  height: 40,
@@ -326,323 +466,347 @@ function re({ metric: e }) {
326
466
  })
327
467
  }) : null]
328
468
  }),
329
- o ? /* @__PURE__ */ I("div", { children: [/* @__PURE__ */ F("span", {
469
+ s ? /* @__PURE__ */ z("div", { children: [/* @__PURE__ */ R("span", {
330
470
  className: "block h-1.5 overflow-hidden rounded-full bg-bg-sunken",
331
471
  "aria-hidden": "true",
332
- children: /* @__PURE__ */ F("span", {
472
+ children: /* @__PURE__ */ R("span", {
333
473
  className: "block h-1.5 rounded-full bg-[var(--color-accent-teal)]",
334
- style: { width: `${Math.max(4, Math.min(100, s))}%` }
474
+ style: { width: `${Math.max(4, Math.min(100, c))}%` }
335
475
  })
336
- }), /* @__PURE__ */ I("div", {
476
+ }), /* @__PURE__ */ z("div", {
337
477
  className: "mt-1 flex justify-between text-[0.7rem] tabular-nums text-text-muted",
338
478
  children: [
339
- /* @__PURE__ */ F("span", { children: Q(e.min) }),
340
- /* @__PURE__ */ F("span", { children: Q((e.min + e.max) / 2) }),
341
- /* @__PURE__ */ F("span", { children: Q(e.max) })
479
+ /* @__PURE__ */ R("span", { children: $(e.min) }),
480
+ /* @__PURE__ */ R("span", { children: $((e.min + e.max) / 2) }),
481
+ /* @__PURE__ */ R("span", { children: $(e.max) })
342
482
  ]
343
483
  })] }) : null,
344
- /* @__PURE__ */ F("div", {
484
+ /* @__PURE__ */ R("div", {
345
485
  className: "mt-auto flex items-center gap-1.5 text-sm",
346
- children: r == null || r === 0 ? /* @__PURE__ */ F("span", {
486
+ children: a == null ? /* @__PURE__ */ R("span", {
487
+ className: "text-text-muted",
488
+ children: t.noComparison
489
+ }) : a === 0 ? /* @__PURE__ */ z("span", {
347
490
  className: "text-text-muted",
348
- children: e.count > 1 ? "No change vs previous" : "First reading"
349
- }) : /* @__PURE__ */ I(P, { children: [/* @__PURE__ */ I("span", {
491
+ children: [
492
+ n("atheletebridge.pages.performance.window.noChange", "No change"),
493
+ " ",
494
+ t.comparison
495
+ ]
496
+ }) : /* @__PURE__ */ z(L, { children: [/* @__PURE__ */ z("span", {
350
497
  className: "inline-flex items-center gap-0.5 font-medium tabular-nums text-text-secondary",
351
498
  children: [
352
- F(r > 0 ? S : x, {
499
+ R(a > 0 ? w : C, {
353
500
  className: "h-4 w-4",
354
501
  "aria-hidden": "true"
355
502
  }),
356
- Q(Math.abs(r)),
357
- c
503
+ $(Math.abs(a)),
504
+ l
358
505
  ]
359
- }), /* @__PURE__ */ F("span", {
506
+ }), /* @__PURE__ */ R("span", {
360
507
  className: "text-text-muted",
361
- children: "vs previous"
508
+ children: t.comparison
362
509
  })] })
363
510
  })
364
511
  ]
365
512
  });
366
513
  }
367
- function ie({ open: t, onOpenChange: n, athleteId: r, displayName: i }) {
368
- let a = u(), [o, s] = y(""), [c, l] = y("COMPLETED"), [d, f] = y(Z), [p, m] = y(""), [_, v] = y(""), [b, x] = y(""), [S, C] = y(""), [w, T] = y(null), D = () => {
369
- s(""), l("COMPLETED"), f(Z()), m(""), v(""), x(""), C(""), T(null);
514
+ function ve({ open: n, onOpenChange: r, athleteId: i, displayName: a }) {
515
+ let o = e(), s = d(), [c, l] = x(""), [u, f] = x("COMPLETED"), [p, m] = x(Q), [h, g] = x(""), [y, b] = x(""), [S, C] = x(""), [w, T] = x(""), [E, D] = x(null), O = () => {
516
+ l(""), f("COMPLETED"), m(Q()), g(""), b(""), C(""), T(""), D(null);
517
+ }, A = (e) => {
518
+ switch (e) {
519
+ case "COMPLETED": return o("atheletebridge.workoutStatus.completed", "Completed");
520
+ case "PLANNED": return o("atheletebridge.workoutStatus.planned", "Planned");
521
+ case "SKIPPED": return o("atheletebridge.workoutStatus.skipped", "Skipped");
522
+ }
370
523
  };
371
- return /* @__PURE__ */ F(R, {
372
- open: t,
373
- onOpenChange: n,
374
- children: /* @__PURE__ */ I(z, { children: [/* @__PURE__ */ F(V, { children: /* @__PURE__ */ I(H, { children: ["Log workout", i ? ` — ${i}` : ""] }) }), /* @__PURE__ */ I("form", {
524
+ return /* @__PURE__ */ R(V, {
525
+ open: n,
526
+ onOpenChange: r,
527
+ children: /* @__PURE__ */ z(H, { children: [/* @__PURE__ */ R(W, { children: /* @__PURE__ */ z(G, { children: [o("atheletebridge.pages.performance.logWorkoutDialogTitle", "Log workout"), a ? ` — ${a}` : ""] }) }), /* @__PURE__ */ z("form", {
375
528
  onSubmit: async (e) => {
376
- if (e.preventDefault(), T(null), !o.trim()) {
377
- T("A workout title is required.");
529
+ if (e.preventDefault(), D(null), !c.trim()) {
530
+ D(o("atheletebridge.pages.performance.error.titleRequired", "A workout title is required."));
378
531
  return;
379
532
  }
380
- if (!d) {
381
- T("A performed date and time is required.");
533
+ if (!p) {
534
+ D(o("atheletebridge.pages.performance.error.performedAtRequired", "A performed date and time is required."));
382
535
  return;
383
536
  }
384
537
  try {
385
- await a.mutateAsync({
386
- athleteId: r,
387
- title: o.trim(),
388
- status: c,
389
- performedAt: new Date(d).toISOString(),
390
- durationMin: Y(p),
391
- rpe: Y(_),
392
- totalLoad: X(b),
393
- notes: S.trim() || void 0
394
- }), D(), n(!1);
538
+ await s.mutateAsync({
539
+ athleteId: i,
540
+ title: c.trim(),
541
+ status: u,
542
+ performedAt: new Date(p).toISOString(),
543
+ durationMin: de(h),
544
+ rpe: de(y),
545
+ totalLoad: fe(S),
546
+ notes: w.trim() || void 0
547
+ }), O(), r(!1);
395
548
  } catch (e) {
396
- T(e instanceof Error ? e.message : "Failed to log workout.");
549
+ D(e instanceof Error ? e.message : o("atheletebridge.pages.performance.error.logFailed", "Failed to log workout."));
397
550
  }
398
551
  },
399
552
  className: "space-y-4 px-1",
400
553
  children: [
401
- /* @__PURE__ */ F(h, {
402
- label: "Title",
554
+ /* @__PURE__ */ R(_, {
555
+ label: o("atheletebridge.pages.performance.label.title", "Title"),
403
556
  htmlFor: "workoutTitle",
404
557
  required: !0,
405
- children: /* @__PURE__ */ F("input", {
558
+ children: /* @__PURE__ */ R("input", {
406
559
  id: "workoutTitle",
407
- className: g,
408
- value: o,
409
- onChange: (e) => s(e.target.value),
410
- placeholder: "e.g. Lower-body strength"
560
+ className: v,
561
+ value: c,
562
+ onChange: (e) => l(e.target.value),
563
+ placeholder: o("atheletebridge.pages.performance.placeholder.title", "e.g. Lower-body strength")
411
564
  })
412
565
  }),
413
- /* @__PURE__ */ I("div", {
566
+ /* @__PURE__ */ z("div", {
414
567
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
415
- children: [/* @__PURE__ */ F(h, {
416
- label: "Status",
568
+ children: [/* @__PURE__ */ R(_, {
569
+ label: o("atheletebridge.pages.performance.label.status", "Status"),
417
570
  htmlFor: "workoutStatus",
418
- children: /* @__PURE__ */ F("select", {
571
+ children: /* @__PURE__ */ R("select", {
419
572
  id: "workoutStatus",
420
- className: g,
421
- value: c,
422
- onChange: (e) => l(e.target.value),
423
- children: G.map((e) => /* @__PURE__ */ F("option", {
573
+ className: v,
574
+ value: u,
575
+ onChange: (e) => f(e.target.value),
576
+ children: q.map((e) => /* @__PURE__ */ R("option", {
424
577
  value: e,
425
- children: e.charAt(0) + e.slice(1).toLowerCase()
578
+ children: A(e)
426
579
  }, e))
427
580
  })
428
- }), /* @__PURE__ */ F(h, {
429
- label: "Performed at",
581
+ }), /* @__PURE__ */ R(_, {
582
+ label: o("atheletebridge.pages.performance.label.performedAt", "Performed at"),
430
583
  htmlFor: "workoutPerformedAt",
431
584
  required: !0,
432
- children: /* @__PURE__ */ F("input", {
585
+ children: /* @__PURE__ */ R("input", {
433
586
  id: "workoutPerformedAt",
434
587
  type: "datetime-local",
435
- className: g,
436
- value: d,
437
- onChange: (e) => f(e.target.value)
588
+ className: v,
589
+ value: p,
590
+ onChange: (e) => m(e.target.value)
438
591
  })
439
592
  })]
440
593
  }),
441
- /* @__PURE__ */ I("div", {
594
+ /* @__PURE__ */ z("div", {
442
595
  className: "grid grid-cols-1 gap-4 sm:grid-cols-3",
443
596
  children: [
444
- /* @__PURE__ */ F(h, {
445
- label: "Duration (min)",
597
+ /* @__PURE__ */ R(_, {
598
+ label: o("atheletebridge.pages.performance.label.durationMin", "Duration (min)"),
446
599
  htmlFor: "workoutDuration",
447
- children: /* @__PURE__ */ F("input", {
600
+ children: /* @__PURE__ */ R("input", {
448
601
  id: "workoutDuration",
449
602
  inputMode: "numeric",
450
- className: g,
451
- value: p,
452
- onChange: (e) => m(e.target.value)
603
+ className: v,
604
+ value: h,
605
+ onChange: (e) => g(e.target.value)
453
606
  })
454
607
  }),
455
- /* @__PURE__ */ F(h, {
456
- label: "RPE (1–10)",
608
+ /* @__PURE__ */ R(_, {
609
+ label: o("atheletebridge.pages.performance.label.rpe", "RPE (1–10)"),
457
610
  htmlFor: "workoutRpe",
458
- children: /* @__PURE__ */ F("input", {
611
+ children: /* @__PURE__ */ R("input", {
459
612
  id: "workoutRpe",
460
613
  inputMode: "numeric",
461
- className: g,
462
- value: _,
463
- onChange: (e) => v(e.target.value)
614
+ className: v,
615
+ value: y,
616
+ onChange: (e) => b(e.target.value)
464
617
  })
465
618
  }),
466
- /* @__PURE__ */ F(h, {
467
- label: "Total load",
619
+ /* @__PURE__ */ R(_, {
620
+ label: o("atheletebridge.pages.performance.label.totalLoad", "Total load"),
468
621
  htmlFor: "workoutLoad",
469
- children: /* @__PURE__ */ F("input", {
622
+ children: /* @__PURE__ */ R("input", {
470
623
  id: "workoutLoad",
471
624
  inputMode: "decimal",
472
- className: g,
473
- value: b,
474
- onChange: (e) => x(e.target.value)
625
+ className: v,
626
+ value: S,
627
+ onChange: (e) => C(e.target.value)
475
628
  })
476
629
  })
477
630
  ]
478
631
  }),
479
- /* @__PURE__ */ F(h, {
480
- label: "Notes",
632
+ /* @__PURE__ */ R(_, {
633
+ label: o("atheletebridge.pages.performance.label.notes", "Notes"),
481
634
  htmlFor: "workoutNotes",
482
- children: /* @__PURE__ */ F("textarea", {
635
+ children: /* @__PURE__ */ R("textarea", {
483
636
  id: "workoutNotes",
484
637
  rows: 2,
485
- className: g,
486
- value: S,
487
- onChange: (e) => C(e.target.value),
488
- placeholder: "How did the session go?"
638
+ className: v,
639
+ value: w,
640
+ onChange: (e) => T(e.target.value),
641
+ placeholder: o("atheletebridge.pages.performance.notesPlaceholder", "How did the session go?")
489
642
  })
490
643
  }),
491
- w && /* @__PURE__ */ F("p", {
644
+ E && /* @__PURE__ */ R("p", {
492
645
  className: "text-sm text-status-error-text",
493
- children: w
646
+ children: E
494
647
  }),
495
- /* @__PURE__ */ I(B, { children: [/* @__PURE__ */ F("button", {
648
+ /* @__PURE__ */ z(U, { children: [/* @__PURE__ */ R("button", {
496
649
  type: "button",
497
- onClick: () => n(!1),
650
+ onClick: () => r(!1),
498
651
  className: "rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
499
- children: "Cancel"
500
- }), /* @__PURE__ */ I("button", {
652
+ children: o("common.cancel", "Cancel")
653
+ }), /* @__PURE__ */ z("button", {
501
654
  type: "submit",
502
- disabled: a.isPending,
503
- className: e(q, "disabled:opacity-60"),
504
- children: [a.isPending ? /* @__PURE__ */ F(E, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ F(k, { className: "h-4 w-4" }), "Log workout"]
655
+ disabled: s.isPending,
656
+ className: t(Z, "disabled:opacity-60"),
657
+ children: [s.isPending ? /* @__PURE__ */ R(k, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ R(M, { className: "h-4 w-4" }), o("atheletebridge.pages.performance.logWorkout", "Log workout")]
505
658
  })] })
506
659
  ]
507
660
  })] })
508
661
  });
509
662
  }
510
- function ae({ open: t, onOpenChange: n, athleteId: r, displayName: a }) {
511
- let o = f(), [s, c] = y("CUSTOM"), [l, u] = y(""), [d, p] = y(""), [m, _] = y(""), [v, b] = y(""), [x, S] = y(Z), [C, w] = y(null), T = () => {
512
- c("CUSTOM"), u(""), p(""), _(""), b(""), S(Z()), w(null);
663
+ function ye({ open: n, onOpenChange: r, athleteId: i, displayName: a }) {
664
+ let o = e(), s = p(), [c, l] = x("CUSTOM"), [u, d] = x(""), [f, m] = x(""), [h, g] = x(""), [y, b] = x(""), [S, C] = x(Q), [w, T] = x(null), E = () => {
665
+ l("CUSTOM"), d(""), m(""), g(""), b(""), C(Q()), T(null);
666
+ }, D = (e) => {
667
+ switch (e) {
668
+ case "SPEED": return o("atheletebridge.metricType.speed", "Speed");
669
+ case "ENDURANCE": return o("atheletebridge.metricType.endurance", "Endurance");
670
+ case "STRENGTH": return o("atheletebridge.metricType.strength", "Strength");
671
+ case "AGILITY": return o("atheletebridge.metricType.agility", "Agility");
672
+ case "ACCURACY": return o("atheletebridge.metricType.accuracy", "Accuracy");
673
+ case "WEIGHT": return o("atheletebridge.metricType.weight", "Weight");
674
+ case "HEART_RATE": return o("atheletebridge.metricType.heartRate", "Heart Rate");
675
+ case "CUSTOM": return o("atheletebridge.metricType.custom", "Custom");
676
+ }
513
677
  };
514
- return /* @__PURE__ */ F(R, {
515
- open: t,
516
- onOpenChange: n,
517
- children: /* @__PURE__ */ I(z, { children: [/* @__PURE__ */ F(V, { children: /* @__PURE__ */ I(H, { children: ["Record metric", a ? ` — ${a}` : ""] }) }), /* @__PURE__ */ I("form", {
678
+ return /* @__PURE__ */ R(V, {
679
+ open: n,
680
+ onOpenChange: r,
681
+ children: /* @__PURE__ */ z(H, { children: [/* @__PURE__ */ R(W, { children: /* @__PURE__ */ z(G, { children: [o("atheletebridge.pages.performance.recordMetricDialogTitle", "Record metric"), a ? ` — ${a}` : ""] }) }), /* @__PURE__ */ z("form", {
518
682
  onSubmit: async (e) => {
519
- if (e.preventDefault(), w(null), !l.trim()) {
520
- w("A metric label is required.");
683
+ if (e.preventDefault(), T(null), !u.trim()) {
684
+ T(o("atheletebridge.pages.performance.error.metricLabelRequired", "A metric label is required."));
521
685
  return;
522
686
  }
523
- let t = X(d);
687
+ let t = fe(f);
524
688
  if (t === void 0) {
525
- w("A numeric value is required.");
689
+ T(o("atheletebridge.pages.performance.error.metricValueRequired", "A numeric value is required."));
526
690
  return;
527
691
  }
528
- if (!x) {
529
- w("A recorded date and time is required.");
692
+ if (!S) {
693
+ T(o("atheletebridge.pages.performance.error.recordedAtRequired", "A recorded date and time is required."));
530
694
  return;
531
695
  }
532
696
  try {
533
- await o.mutateAsync({
534
- athleteId: r,
535
- type: s,
536
- label: l.trim(),
697
+ await s.mutateAsync({
698
+ athleteId: i,
699
+ type: c,
700
+ label: u.trim(),
537
701
  value: t,
538
- unit: m.trim() || void 0,
539
- source: v.trim() || void 0,
540
- recordedAt: new Date(x).toISOString()
541
- }), T(), n(!1);
702
+ unit: h.trim() || void 0,
703
+ source: y.trim() || void 0,
704
+ recordedAt: new Date(S).toISOString()
705
+ }), E(), r(!1);
542
706
  } catch (e) {
543
- w(e instanceof Error ? e.message : "Failed to record metric.");
707
+ T(e instanceof Error ? e.message : o("atheletebridge.pages.performance.error.recordFailed", "Failed to record metric."));
544
708
  }
545
709
  },
546
710
  className: "space-y-4 px-1",
547
711
  children: [
548
- /* @__PURE__ */ I("div", {
712
+ /* @__PURE__ */ z("div", {
549
713
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
550
- children: [/* @__PURE__ */ F(h, {
551
- label: "Type",
714
+ children: [/* @__PURE__ */ R(_, {
715
+ label: o("atheletebridge.pages.performance.label.metricType", "Metric type"),
552
716
  htmlFor: "metricType",
553
- children: /* @__PURE__ */ F("select", {
717
+ children: /* @__PURE__ */ R("select", {
554
718
  id: "metricType",
555
- className: g,
556
- value: s,
557
- onChange: (e) => c(e.target.value),
558
- children: K.map((e) => /* @__PURE__ */ F("option", {
719
+ className: v,
720
+ value: c,
721
+ onChange: (e) => l(e.target.value),
722
+ children: J.map((e) => /* @__PURE__ */ R("option", {
559
723
  value: e,
560
- children: i[e]
724
+ children: D(e)
561
725
  }, e))
562
726
  })
563
- }), /* @__PURE__ */ F(h, {
564
- label: "Recorded at",
727
+ }), /* @__PURE__ */ R(_, {
728
+ label: o("atheletebridge.pages.performance.label.recordedAt", "Recorded at"),
565
729
  htmlFor: "metricRecordedAt",
566
730
  required: !0,
567
- children: /* @__PURE__ */ F("input", {
731
+ children: /* @__PURE__ */ R("input", {
568
732
  id: "metricRecordedAt",
569
733
  type: "datetime-local",
570
- className: g,
571
- value: x,
572
- onChange: (e) => S(e.target.value)
734
+ className: v,
735
+ value: S,
736
+ onChange: (e) => C(e.target.value)
573
737
  })
574
738
  })]
575
739
  }),
576
- /* @__PURE__ */ F(h, {
577
- label: "Label",
740
+ /* @__PURE__ */ R(_, {
741
+ label: o("atheletebridge.pages.performance.label.metricLabel", "Label"),
578
742
  htmlFor: "metricLabel",
579
743
  required: !0,
580
- children: /* @__PURE__ */ F("input", {
744
+ children: /* @__PURE__ */ R("input", {
581
745
  id: "metricLabel",
582
- className: g,
583
- value: l,
584
- onChange: (e) => u(e.target.value),
585
- placeholder: "e.g. 40m sprint"
746
+ className: v,
747
+ value: u,
748
+ onChange: (e) => d(e.target.value),
749
+ placeholder: o("atheletebridge.pages.performance.placeholder.metricLabel", "e.g. 40m sprint")
586
750
  })
587
751
  }),
588
- /* @__PURE__ */ I("div", {
752
+ /* @__PURE__ */ z("div", {
589
753
  className: "grid grid-cols-2 gap-4",
590
- children: [/* @__PURE__ */ F(h, {
591
- label: "Value",
754
+ children: [/* @__PURE__ */ R(_, {
755
+ label: o("atheletebridge.pages.performance.label.value", "Value"),
592
756
  htmlFor: "metricValue",
593
757
  required: !0,
594
- children: /* @__PURE__ */ F("input", {
758
+ children: /* @__PURE__ */ R("input", {
595
759
  id: "metricValue",
596
760
  inputMode: "decimal",
597
- className: g,
598
- value: d,
599
- onChange: (e) => p(e.target.value),
600
- placeholder: "e.g. 4.8"
761
+ className: v,
762
+ value: f,
763
+ onChange: (e) => m(e.target.value),
764
+ placeholder: o("atheletebridge.pages.performance.placeholder.value", "e.g. 4.8")
601
765
  })
602
- }), /* @__PURE__ */ F(h, {
603
- label: "Unit",
766
+ }), /* @__PURE__ */ R(_, {
767
+ label: o("atheletebridge.pages.performance.label.unit", "Unit"),
604
768
  htmlFor: "metricUnit",
605
- children: /* @__PURE__ */ F("input", {
769
+ children: /* @__PURE__ */ R("input", {
606
770
  id: "metricUnit",
607
- className: g,
608
- value: m,
609
- onChange: (e) => _(e.target.value),
610
- placeholder: "e.g. s, kg, bpm"
771
+ className: v,
772
+ value: h,
773
+ onChange: (e) => g(e.target.value),
774
+ placeholder: o("atheletebridge.pages.performance.placeholder.unit", "e.g. s, kg, bpm")
611
775
  })
612
776
  })]
613
777
  }),
614
- /* @__PURE__ */ F(h, {
615
- label: "Source",
778
+ /* @__PURE__ */ R(_, {
779
+ label: o("atheletebridge.pages.performance.label.source", "Source"),
616
780
  htmlFor: "metricSource",
617
- hint: "Optional — device, test or coach.",
618
- children: /* @__PURE__ */ F("input", {
781
+ hint: o("atheletebridge.pages.performance.hint.source", "Optional — device, test or coach."),
782
+ children: /* @__PURE__ */ R("input", {
619
783
  id: "metricSource",
620
- className: g,
621
- value: v,
784
+ className: v,
785
+ value: y,
622
786
  onChange: (e) => b(e.target.value),
623
- placeholder: "e.g. GPS vest"
787
+ placeholder: o("atheletebridge.pages.performance.placeholder.source", "e.g. GPS vest")
624
788
  })
625
789
  }),
626
- C && /* @__PURE__ */ F("p", {
790
+ w && /* @__PURE__ */ R("p", {
627
791
  className: "text-sm text-status-error-text",
628
- children: C
792
+ children: w
629
793
  }),
630
- /* @__PURE__ */ I(B, { children: [/* @__PURE__ */ F("button", {
794
+ /* @__PURE__ */ z(U, { children: [/* @__PURE__ */ R("button", {
631
795
  type: "button",
632
- onClick: () => n(!1),
796
+ onClick: () => r(!1),
633
797
  className: "rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
634
- children: "Cancel"
635
- }), /* @__PURE__ */ I("button", {
798
+ children: o("common.cancel", "Cancel")
799
+ }), /* @__PURE__ */ z("button", {
636
800
  type: "submit",
637
- disabled: o.isPending,
638
- className: e(q, "disabled:opacity-60"),
639
- children: [o.isPending ? /* @__PURE__ */ F(E, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ F(O, { className: "h-4 w-4" }), "Record metric"]
801
+ disabled: s.isPending,
802
+ className: t(Z, "disabled:opacity-60"),
803
+ children: [s.isPending ? /* @__PURE__ */ R(k, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ R(j, { className: "h-4 w-4" }), o("atheletebridge.pages.performance.recordMetric", "Record metric")]
640
804
  })] })
641
805
  ]
642
806
  })] })
643
807
  });
644
808
  }
645
809
  //#endregion
646
- export { $ as PerformancePage };
810
+ export { pe as PerformancePage };
647
811
 
648
812
  //# sourceMappingURL=PerformancePage.js.map