@burdenoff/microfe-atheletebridge 2026.827.1 → 2026.829.2

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 (46) 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/pages/DashboardPage.d.ts.map +1 -1
  8. package/dist/atheletebridge/pages/DashboardPage.js +56 -24
  9. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  10. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.d.ts.map +1 -1
  11. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js +58 -56
  12. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js.map +1 -1
  13. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.d.ts.map +1 -1
  14. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +110 -106
  15. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -1
  16. package/dist/atheletebridge/pages/fixtures/FixturesListPage.d.ts.map +1 -1
  17. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js +80 -71
  18. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -1
  19. package/dist/atheletebridge/pages/onboarding/OnboardingPage.d.ts.map +1 -1
  20. package/dist/atheletebridge/pages/onboarding/OnboardingPage.js +244 -210
  21. package/dist/atheletebridge/pages/onboarding/OnboardingPage.js.map +1 -1
  22. package/dist/atheletebridge/pages/performance/PerformancePage.d.ts.map +1 -1
  23. package/dist/atheletebridge/pages/performance/PerformancePage.js +197 -148
  24. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -1
  25. package/dist/atheletebridge/pages/programs/ProgramDetailPage.d.ts.map +1 -1
  26. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +169 -143
  27. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  28. package/dist/atheletebridge/pages/programs/ProgramsListPage.d.ts.map +1 -1
  29. package/dist/atheletebridge/pages/programs/ProgramsListPage.js +77 -72
  30. package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -1
  31. package/dist/atheletebridge/pages/sessions/SessionDetailPage.d.ts.map +1 -1
  32. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +104 -86
  33. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
  34. package/dist/atheletebridge/pages/sessions/SessionsListPage.d.ts.map +1 -1
  35. package/dist/atheletebridge/pages/sessions/SessionsListPage.js +54 -49
  36. package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -1
  37. package/dist/atheletebridge/pages/teams/TeamDetailPage.d.ts.map +1 -1
  38. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +286 -267
  39. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  40. package/dist/atheletebridge/pages/teams/TeamFormPage.d.ts.map +1 -1
  41. package/dist/atheletebridge/pages/teams/TeamFormPage.js +185 -180
  42. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
  43. package/dist/atheletebridge/pages/teams/TeamsListPage.d.ts.map +1 -1
  44. package/dist/atheletebridge/pages/teams/TeamsListPage.js +70 -74
  45. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
  46. package/package.json +1 -1
@@ -1,202 +1,206 @@
1
- import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
2
- import { PageLayout as t } from "../../components/PageLayout.js";
3
- import { FIXTURE_TYPE_LABELS as n } from "../../components/domain.js";
4
- import { Crest as r } from "../../components/Crest.js";
5
- import { Scoreboard as i } from "../../components/Scoreboard.js";
6
- import { ErrorState as a, LoadingState as o } from "../../components/LoadingState.js";
7
- import { useFixture as s, useRecordFixtureResult as c } from "../../hooks/useAthleteBridgeApi.js";
8
- import { FormField as l, fieldInputClass as u } from "../../components/form.js";
9
- import { AvailabilityRsvpControl as d } from "../../components/availability/AvailabilityRsvpControl.js";
10
- import { AvailabilityRosterPanel as f } from "../../components/availability/AvailabilityRosterPanel.js";
11
- import { useState as p } from "react";
12
- import { ArrowLeft as m, Flag as h, Loader2 as g, Minus as _, Trophy as v } from "lucide-react";
13
- import { useParams as y } from "react-router";
14
- import { jsx as b, jsxs as x } from "react/jsx-runtime";
15
- import { EmphasisPanel as S, GlassCard as C } from "@burdenoff/fe-libs/ui";
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 { FIXTURE_TYPE_LABELS as r } from "../../components/domain.js";
5
+ import { Crest as i } from "../../components/Crest.js";
6
+ import { Scoreboard as a } from "../../components/Scoreboard.js";
7
+ import { ErrorState as o, LoadingState as s } from "../../components/LoadingState.js";
8
+ import { useFixture as c, useRecordFixtureResult as l } from "../../hooks/useAthleteBridgeApi.js";
9
+ import { FormField as u, fieldInputClass as d } from "../../components/form.js";
10
+ import { AvailabilityRsvpControl as f } from "../../components/availability/AvailabilityRsvpControl.js";
11
+ import { AvailabilityRosterPanel as p } from "../../components/availability/AvailabilityRosterPanel.js";
12
+ import { useState as m } from "react";
13
+ import { ArrowLeft as h, Flag as g, Loader2 as _, Minus as v, Trophy as y } from "lucide-react";
14
+ import { useParams as b } from "react-router";
15
+ import { jsx as x, jsxs as S } from "react/jsx-runtime";
16
+ import { EmphasisPanel as C, GlassCard as w } from "@burdenoff/fe-libs/ui";
16
17
  //#region src/atheletebridge/pages/fixtures/FixtureDetailPage.tsx
17
- function w() {
18
- let { id: w } = y(), { navigateTo: T } = e(), E = s(w), D = c(), [O, k] = p(""), [A, j] = p(""), [M, N] = p(null);
19
- if (E.isLoading) return /* @__PURE__ */ b(t, {
20
- title: "Fixture",
21
- children: /* @__PURE__ */ b(o, { label: "Loading fixture…" })
18
+ function T() {
19
+ let T = e(), { id: E } = b(), { navigateTo: D } = t(), O = c(E), k = l(), [A, j] = m(""), [M, N] = m(""), [P, F] = m(null);
20
+ if (O.isLoading) return /* @__PURE__ */ x(n, {
21
+ title: T("atheletebridge.pages.fixtureDetail.title", "Fixture"),
22
+ children: /* @__PURE__ */ x(s, { label: T("atheletebridge.pages.fixtureDetail.loading", "Loading fixture…") })
22
23
  });
23
- if (E.isError || !E.data) return /* @__PURE__ */ b(t, {
24
- title: "Fixture",
25
- children: /* @__PURE__ */ b(a, {
26
- title: "Fixture not found",
27
- message: "This fixture does not exist or you do not have access to it.",
28
- onRetry: () => T("/fixtures")
24
+ if (O.isError || !O.data) return /* @__PURE__ */ x(n, {
25
+ title: T("atheletebridge.pages.fixtureDetail.title", "Fixture"),
26
+ children: /* @__PURE__ */ x(o, {
27
+ title: T("atheletebridge.pages.fixtureDetail.notFoundTitle", "Fixture not found"),
28
+ message: T("atheletebridge.pages.fixtureDetail.notFoundMessage", "This fixture does not exist or you do not have access to it."),
29
+ onRetry: () => D("/fixtures")
29
30
  })
30
31
  });
31
- let P = E.data, F = P.homeTeam?.name ?? "Home", I = P.awayTeam?.name ?? (P.awayTeamId ? "Away" : "TBD"), L = !!P.awayTeamId && (P.status === "SCHEDULED" || P.status === "LIVE");
32
- return /* @__PURE__ */ x(t, {
33
- title: `${F} vs ${I}`,
34
- description: `${n[P.type]}${P.competition ? ` · ${P.competition}` : ""}`,
35
- actions: /* @__PURE__ */ x("button", {
32
+ let I = O.data, L = I.homeTeam?.name ?? T("atheletebridge.pages.fixtureDetail.home", "Home"), R = I.awayTeam?.name ?? (I.awayTeamId ? T("atheletebridge.pages.fixtureDetail.away", "Away") : "TBD"), z = !!I.awayTeamId && (I.status === "SCHEDULED" || I.status === "LIVE");
33
+ return /* @__PURE__ */ S(n, {
34
+ title: `${L} vs ${R}`,
35
+ description: `${r[I.type]}${I.competition ? ` · ${I.competition}` : ""}`,
36
+ actions: /* @__PURE__ */ S("button", {
36
37
  type: "button",
37
- onClick: () => T("/fixtures"),
38
+ onClick: () => D("/fixtures"),
38
39
  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",
39
- children: [/* @__PURE__ */ b(m, { className: "h-4 w-4" }), " Back"]
40
+ children: [
41
+ /* @__PURE__ */ x(h, { className: "h-4 w-4" }),
42
+ " ",
43
+ T("atheletebridge.pages.fixtureDetail.back", "Back")
44
+ ]
40
45
  }),
41
46
  children: [
42
- /* @__PURE__ */ b(i, {
43
- fixture: P,
47
+ /* @__PURE__ */ x(a, {
48
+ fixture: I,
44
49
  variant: "hero",
45
50
  className: "mb-8"
46
51
  }),
47
- /* @__PURE__ */ x("div", {
52
+ /* @__PURE__ */ S("div", {
48
53
  className: "mb-8 grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_2fr]",
49
- children: [/* @__PURE__ */ b(d, {
50
- teamId: P.homeTeamId,
51
- fixtureId: P.id
52
- }), /* @__PURE__ */ b(f, {
53
- teamId: P.homeTeamId,
54
- fixtureId: P.id
54
+ children: [/* @__PURE__ */ x(f, {
55
+ teamId: I.homeTeamId,
56
+ fixtureId: I.id
57
+ }), /* @__PURE__ */ x(p, {
58
+ teamId: I.homeTeamId,
59
+ fixtureId: I.id
55
60
  })]
56
61
  }),
57
- P.notes && /* @__PURE__ */ x(S, {
62
+ I.notes && /* @__PURE__ */ S(C, {
58
63
  className: "mb-8",
59
- children: [/* @__PURE__ */ b("h2", {
64
+ children: [/* @__PURE__ */ x("h2", {
60
65
  className: "mb-2 text-sm font-semibold text-text-primary",
61
- children: "Notes"
62
- }), /* @__PURE__ */ b("p", {
66
+ children: T("atheletebridge.pages.fixtureDetail.notes", "Notes")
67
+ }), /* @__PURE__ */ x("p", {
63
68
  className: "text-sm text-text-secondary",
64
- children: P.notes
69
+ children: I.notes
65
70
  })]
66
71
  }),
67
- L && /* @__PURE__ */ x("section", {
72
+ z && /* @__PURE__ */ S("section", {
68
73
  className: "mb-8",
69
- children: [/* @__PURE__ */ x("h2", {
74
+ children: [/* @__PURE__ */ S("h2", {
70
75
  className: "mb-4 flex items-center gap-2 text-lg font-semibold text-text-primary",
71
- children: [/* @__PURE__ */ b(h, { className: "h-5 w-5" }), " Record result"]
72
- }), /* @__PURE__ */ x(C, {
76
+ children: [
77
+ /* @__PURE__ */ x(g, { className: "h-5 w-5" }),
78
+ " ",
79
+ T("atheletebridge.pages.fixtureDetail.recordResult", "Record result")
80
+ ]
81
+ }), /* @__PURE__ */ S(w, {
73
82
  treatment: "insight",
74
83
  className: "p-5 sm:p-6",
75
84
  children: [
76
85
  /* @__PURE__ */ x("p", {
77
86
  className: "mb-5 text-sm text-text-secondary",
78
- children: [
79
- "Recording a final score marks this fixture ",
80
- /* @__PURE__ */ b("strong", { children: "Completed" }),
81
- " and recomputes the competition standings for both teams."
82
- ]
87
+ children: T("atheletebridge.pages.fixtureDetail.recordResultDescription", "Recording a final score marks this fixture Completed and recomputes the competition standings for both teams.")
83
88
  }),
84
- /* @__PURE__ */ x("form", {
89
+ /* @__PURE__ */ S("form", {
85
90
  onSubmit: async (e) => {
86
- if (e.preventDefault(), N(null), !w) return;
87
- let t = Number.parseInt(O, 10), n = Number.parseInt(A, 10);
91
+ if (e.preventDefault(), F(null), !E) return;
92
+ let t = Number.parseInt(A, 10), n = Number.parseInt(M, 10);
88
93
  if (Number.isNaN(t) || Number.isNaN(n)) {
89
- N("Both scores are required and must be numbers.");
94
+ F("Both scores are required and must be numbers.");
90
95
  return;
91
96
  }
92
97
  if (t < 0 || n < 0) {
93
- N("Scores cannot be negative.");
98
+ F("Scores cannot be negative.");
94
99
  return;
95
100
  }
96
101
  try {
97
- await D.mutateAsync({
98
- id: w,
102
+ await k.mutateAsync({
103
+ id: E,
99
104
  input: {
100
105
  homeScore: t,
101
106
  awayScore: n
102
107
  }
103
- }), k(""), j("");
108
+ }), j(""), N("");
104
109
  } catch (e) {
105
- N(e instanceof Error ? e.message : "Failed to record result.");
110
+ F(e instanceof Error ? e.message : "Failed to record result.");
106
111
  }
107
112
  },
108
- children: [/* @__PURE__ */ x("div", {
113
+ children: [/* @__PURE__ */ S("div", {
109
114
  className: "flex flex-wrap items-end justify-center gap-4 sm:gap-6",
110
115
  children: [
111
- /* @__PURE__ */ x("div", {
116
+ /* @__PURE__ */ S("div", {
112
117
  className: "flex items-end gap-3",
113
- children: [/* @__PURE__ */ x("div", {
118
+ children: [/* @__PURE__ */ S("div", {
114
119
  className: "flex flex-col items-center gap-2",
115
- children: [/* @__PURE__ */ b(r, {
116
- name: F,
117
- sport: P.homeTeam?.sport,
120
+ children: [/* @__PURE__ */ x(i, {
121
+ name: L,
122
+ sport: I.homeTeam?.sport,
118
123
  size: 40
119
- }), /* @__PURE__ */ b("span", {
124
+ }), /* @__PURE__ */ x("span", {
120
125
  className: "max-w-[8rem] truncate text-center text-xs font-medium text-text-secondary",
121
- children: F
126
+ children: L
122
127
  })]
123
- }), /* @__PURE__ */ b(l, {
124
- label: "Home",
128
+ }), /* @__PURE__ */ x(u, {
129
+ label: T("atheletebridge.pages.fixtureDetail.home", "Home"),
125
130
  htmlFor: "homeScore",
126
131
  className: "w-24",
127
- children: /* @__PURE__ */ b("input", {
132
+ children: /* @__PURE__ */ x("input", {
128
133
  id: "homeScore",
129
134
  inputMode: "numeric",
130
- className: `${u} text-center text-lg font-bold tabular-nums`,
131
- value: O,
132
- onChange: (e) => k(e.target.value),
135
+ className: `${d} text-center text-lg font-bold tabular-nums`,
136
+ value: A,
137
+ onChange: (e) => j(e.target.value),
133
138
  placeholder: "0"
134
139
  })
135
140
  })]
136
141
  }),
137
- /* @__PURE__ */ b(_, {
142
+ /* @__PURE__ */ x(v, {
138
143
  className: "mb-3 h-5 w-5 shrink-0 text-text-muted",
139
144
  "aria-hidden": "true"
140
145
  }),
141
- /* @__PURE__ */ x("div", {
146
+ /* @__PURE__ */ S("div", {
142
147
  className: "flex items-end gap-3",
143
- children: [/* @__PURE__ */ b(l, {
144
- label: "Away",
148
+ children: [/* @__PURE__ */ x(u, {
149
+ label: T("atheletebridge.pages.fixtureDetail.away", "Away"),
145
150
  htmlFor: "awayScore",
146
151
  className: "w-24",
147
- children: /* @__PURE__ */ b("input", {
152
+ children: /* @__PURE__ */ x("input", {
148
153
  id: "awayScore",
149
154
  inputMode: "numeric",
150
- className: `${u} text-center text-lg font-bold tabular-nums`,
151
- value: A,
152
- onChange: (e) => j(e.target.value),
155
+ className: `${d} text-center text-lg font-bold tabular-nums`,
156
+ value: M,
157
+ onChange: (e) => N(e.target.value),
153
158
  placeholder: "0"
154
159
  })
155
- }), /* @__PURE__ */ x("div", {
160
+ }), /* @__PURE__ */ S("div", {
156
161
  className: "flex flex-col items-center gap-2",
157
- children: [/* @__PURE__ */ b(r, {
158
- name: I,
159
- sport: P.awayTeam?.sport,
162
+ children: [/* @__PURE__ */ x(i, {
163
+ name: R,
164
+ sport: I.awayTeam?.sport,
160
165
  size: 40
161
- }), /* @__PURE__ */ b("span", {
166
+ }), /* @__PURE__ */ x("span", {
162
167
  className: "max-w-[8rem] truncate text-center text-xs font-medium text-text-secondary",
163
- children: I
168
+ children: R
164
169
  })]
165
170
  })]
166
171
  })
167
172
  ]
168
- }), /* @__PURE__ */ b("div", {
173
+ }), /* @__PURE__ */ x("div", {
169
174
  className: "mt-6 flex justify-center",
170
- children: /* @__PURE__ */ x("button", {
175
+ children: /* @__PURE__ */ S("button", {
171
176
  type: "submit",
172
- disabled: D.isPending,
177
+ disabled: k.isPending,
173
178
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-6 py-2.5 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60",
174
- children: [D.isPending ? /* @__PURE__ */ b(g, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ b(v, { className: "h-4 w-4" }), "Record result"]
179
+ children: [k.isPending ? /* @__PURE__ */ x(_, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ x(y, { className: "h-4 w-4" }), T("atheletebridge.pages.fixtureDetail.recordResultAction", "Record result")]
175
180
  })
176
181
  })]
177
182
  }),
178
- M && /* @__PURE__ */ b("p", {
183
+ P && /* @__PURE__ */ x("p", {
179
184
  className: "mt-3 text-center text-sm text-status-error-text",
180
- children: M
185
+ children: P
181
186
  })
182
187
  ]
183
188
  })]
184
189
  }),
185
- P.competition && /* @__PURE__ */ x("button", {
190
+ I.competition && /* @__PURE__ */ S("button", {
186
191
  type: "button",
187
- onClick: () => T(`/standings?competition=${encodeURIComponent(P.competition ?? "")}`),
192
+ onClick: () => D(`/standings?competition=${encodeURIComponent(I.competition ?? "")}`),
188
193
  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",
189
194
  children: [
190
- /* @__PURE__ */ b(v, { className: "h-4 w-4" }),
191
- " View ",
192
- P.competition,
193
- " standings"
195
+ /* @__PURE__ */ x(y, { className: "h-4 w-4" }),
196
+ " ",
197
+ T("atheletebridge.pages.fixtureDetail.viewStandings", `View ${I.competition} standings`)
194
198
  ]
195
199
  })
196
200
  ]
197
201
  });
198
202
  }
199
203
  //#endregion
200
- export { w as FixtureDetailPage };
204
+ export { T as FixtureDetailPage };
201
205
 
202
206
  //# sourceMappingURL=FixtureDetailPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FixtureDetailPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/fixtures/FixtureDetailPage.tsx"],"sourcesContent":["/**\n * Fixture Detail\n * @module atheletebridge/pages/fixtures\n *\n * Reads a single fixture (athFixture) and lets the user record a final result\n * (athRecordFixtureResult) which marks it COMPLETED and recomputes standings.\n *\n * The header is a crest-vs-crest Scoreboard hero; the record-result panel shows\n * each team's crest beside its score input. Semantic tokens only, responsive.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router';\nimport { ArrowLeft, Trophy, Loader2, Flag, Minus } from 'lucide-react';\nimport { GlassCard, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Scoreboard } from '../../components/Scoreboard';\nimport { Crest } from '../../components/Crest';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { FIXTURE_TYPE_LABELS } from '../../components/domain';\nimport { AvailabilityRsvpControl } from '../../components/availability/AvailabilityRsvpControl';\nimport { AvailabilityRosterPanel } from '../../components/availability/AvailabilityRosterPanel';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useFixture, useRecordFixtureResult } from '../../hooks/useAthleteBridgeApi';\n\nexport function FixtureDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useAthleteBridge();\n\n const fixture = useFixture(id);\n const recordResult = useRecordFixtureResult();\n\n const [homeScore, setHomeScore] = useState('');\n const [awayScore, setAwayScore] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n if (fixture.isLoading) {\n return (\n <PageLayout title=\"Fixture\">\n <LoadingState label=\"Loading fixture…\" />\n </PageLayout>\n );\n }\n\n if (fixture.isError || !fixture.data) {\n return (\n <PageLayout title=\"Fixture\">\n <ErrorState\n title=\"Fixture not found\"\n message=\"This fixture does not exist or you do not have access to it.\"\n onRetry={() => navigateTo('/fixtures')}\n />\n </PageLayout>\n );\n }\n\n const f = fixture.data;\n const homeName = f.homeTeam?.name ?? 'Home';\n const awayName = f.awayTeam?.name ?? (f.awayTeamId ? 'Away' : 'TBD');\n const canRecordResult =\n Boolean(f.awayTeamId) && (f.status === 'SCHEDULED' || f.status === 'LIVE');\n\n const handleRecord = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!id) return;\n const home = Number.parseInt(homeScore, 10);\n const away = Number.parseInt(awayScore, 10);\n if (Number.isNaN(home) || Number.isNaN(away)) {\n setError('Both scores are required and must be numbers.');\n return;\n }\n if (home < 0 || away < 0) {\n setError('Scores cannot be negative.');\n return;\n }\n try {\n await recordResult.mutateAsync({ id, input: { homeScore: home, awayScore: away } });\n setHomeScore('');\n setAwayScore('');\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to record result.');\n }\n };\n\n return (\n <PageLayout\n title={`${homeName} vs ${awayName}`}\n description={`${FIXTURE_TYPE_LABELS[f.type]}${f.competition ? ` · ${f.competition}` : ''}`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n {/* Crest-vs-crest hero scoreboard */}\n <Scoreboard fixture={f} variant=\"hero\" className=\"mb-8\" />\n\n {/* Availability / RSVP (BOFF-4134) — athlete's own response + coach roster view */}\n <div className=\"mb-8 grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_2fr]\">\n <AvailabilityRsvpControl teamId={f.homeTeamId} fixtureId={f.id} />\n <AvailabilityRosterPanel teamId={f.homeTeamId} fixtureId={f.id} />\n </div>\n\n {f.notes && (\n <EmphasisPanel className=\"mb-8\">\n <h2 className=\"mb-2 text-sm font-semibold text-text-primary\">Notes</h2>\n <p className=\"text-sm text-text-secondary\">{f.notes}</p>\n </EmphasisPanel>\n )}\n\n {/* Record result */}\n {canRecordResult && (\n <section className=\"mb-8\">\n <h2 className=\"mb-4 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Flag className=\"h-5 w-5\" /> Record result\n </h2>\n <GlassCard treatment=\"insight\" className=\"p-5 sm:p-6\">\n <p className=\"mb-5 text-sm text-text-secondary\">\n Recording a final score marks this fixture <strong>Completed</strong> and recomputes\n the competition standings for both teams.\n </p>\n <form onSubmit={handleRecord}>\n <div className=\"flex flex-wrap items-end justify-center gap-4 sm:gap-6\">\n <div className=\"flex items-end gap-3\">\n <div className=\"flex flex-col items-center gap-2\">\n <Crest name={homeName} sport={f.homeTeam?.sport} size={40} />\n <span className=\"max-w-[8rem] truncate text-center text-xs font-medium text-text-secondary\">\n {homeName}\n </span>\n </div>\n <FormField label=\"Home\" htmlFor=\"homeScore\" className=\"w-24\">\n <input\n id=\"homeScore\"\n inputMode=\"numeric\"\n className={`${fieldInputClass} text-center text-lg font-bold tabular-nums`}\n value={homeScore}\n onChange={(e) => setHomeScore(e.target.value)}\n placeholder=\"0\"\n />\n </FormField>\n </div>\n\n <Minus className=\"mb-3 h-5 w-5 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n\n <div className=\"flex items-end gap-3\">\n <FormField label=\"Away\" htmlFor=\"awayScore\" className=\"w-24\">\n <input\n id=\"awayScore\"\n inputMode=\"numeric\"\n className={`${fieldInputClass} text-center text-lg font-bold tabular-nums`}\n value={awayScore}\n onChange={(e) => setAwayScore(e.target.value)}\n placeholder=\"0\"\n />\n </FormField>\n <div className=\"flex flex-col items-center gap-2\">\n <Crest name={awayName} sport={f.awayTeam?.sport} size={40} />\n <span className=\"max-w-[8rem] truncate text-center text-xs font-medium text-text-secondary\">\n {awayName}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"mt-6 flex justify-center\">\n <button\n type=\"submit\"\n disabled={recordResult.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-6 py-2.5 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60\"\n >\n {recordResult.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trophy className=\"h-4 w-4\" />\n )}\n Record result\n </button>\n </div>\n </form>\n {error && <p className=\"mt-3 text-center text-sm text-status-error-text\">{error}</p>}\n </GlassCard>\n </section>\n )}\n\n {f.competition && (\n <button\n type=\"button\"\n onClick={() =>\n navigateTo(`/standings?competition=${encodeURIComponent(f.competition ?? '')}`)\n }\n 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\"\n >\n <Trophy className=\"h-4 w-4\" /> View {f.competition} standings\n </button>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA0BA,SAAgB,IAAoB;CAClC,IAAM,EAAE,UAAO,EAA0B,GACnC,EAAE,kBAAe,EAAiB,GAElC,IAAU,EAAW,CAAE,GACvB,IAAe,EAAuB,GAEtC,CAAC,GAAW,KAAgB,EAAS,EAAE,GACvC,CAAC,GAAW,KAAgB,EAAS,EAAE,GACvC,CAAC,GAAO,KAAY,EAAwB,IAAI;CAEtD,IAAI,EAAQ,WACV,OACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAc,OAAM,mBAAoB,CAAA;CAC9B,CAAA;CAIhB,IAAI,EAAQ,WAAW,CAAC,EAAQ,MAC9B,OACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GACE,OAAM;GACN,SAAQ;GACR,eAAe,EAAW,WAAW;EACtC,CAAA;CACS,CAAA;CAIhB,IAAM,IAAI,EAAQ,MACZ,IAAW,EAAE,UAAU,QAAQ,QAC/B,IAAW,EAAE,UAAU,SAAS,EAAE,aAAa,SAAS,QACxD,IACJ,EAAQ,EAAE,eAAgB,EAAE,WAAW,eAAe,EAAE,WAAW;CAyBrE,OACE,kBAAC,GAAD;EACE,OAAO,GAAG,EAAS,MAAM;EACzB,aAAa,GAAG,EAAoB,EAAE,QAAQ,EAAE,cAAc,MAAM,EAAE,gBAAgB;EACtF,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,WAAW;GACrC,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA,GAAC,OAC3B;;YAVZ;GAcE,kBAAC,GAAD;IAAY,SAAS;IAAG,SAAQ;IAAO,WAAU;GAAQ,CAAA;GAGzD,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAyB,QAAQ,EAAE;KAAY,WAAW,EAAE;IAAK,CAAA,GACjE,kBAAC,GAAD;KAAyB,QAAQ,EAAE;KAAY,WAAW,EAAE;IAAK,CAAA,CAC9D;;GAEJ,EAAE,SACD,kBAAC,GAAD;IAAe,WAAU;cAAzB,CACE,kBAAC,MAAD;KAAI,WAAU;eAA+C;IAAS,CAAA,GACtE,kBAAC,KAAD;KAAG,WAAU;eAA+B,EAAE;IAAS,CAAA,CAC1C;;GAIhB,KACC,kBAAC,WAAD;IAAS,WAAU;cAAnB,CACE,kBAAC,MAAD;KAAI,WAAU;eAAd,CACE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,GAAC,gBAC1B;QACJ,kBAAC,GAAD;KAAW,WAAU;KAAU,WAAU;eAAzC;MACE,kBAAC,KAAD;OAAG,WAAU;iBAAb;QAAgD;QACH,kBAAC,UAAD,EAAA,UAAQ,YAAiB,CAAA;QAAC;OAEpE;;MACH,kBAAC,QAAD;OAAM,UAAU,OAhEE,MAAuB;QAGjD,IAFA,EAAE,eAAe,GACjB,EAAS,IAAI,GACT,CAAC,GAAI;QACT,IAAM,IAAO,OAAO,SAAS,GAAW,EAAE,GACpC,IAAO,OAAO,SAAS,GAAW,EAAE;QAC1C,IAAI,OAAO,MAAM,CAAI,KAAK,OAAO,MAAM,CAAI,GAAG;SAC5C,EAAS,+CAA+C;SACxD;QACF;QACA,IAAI,IAAO,KAAK,IAAO,GAAG;SACxB,EAAS,4BAA4B;SACrC;QACF;QACA,IAAI;SAGF,AAFA,MAAM,EAAa,YAAY;UAAE;UAAI,OAAO;WAAE,WAAW;WAAM,WAAW;UAAK;SAAE,CAAC,GAClF,EAAa,EAAE,GACf,EAAa,EAAE;QACjB,SAAS,GAAK;SACZ,EAAS,aAAe,QAAQ,EAAI,UAAU,0BAA0B;QAC1E;OACF;iBA2CU,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YAAO,MAAM;YAAU,OAAO,EAAE,UAAU;YAAO,MAAM;WAAK,CAAA,GAC5D,kBAAC,QAAD;YAAM,WAAU;sBACb;WACG,CAAA,CACH;cACL,kBAAC,GAAD;WAAW,OAAM;WAAO,SAAQ;WAAY,WAAU;qBACpD,kBAAC,SAAD;YACE,IAAG;YACH,WAAU;YACV,WAAW,GAAG,EAAgB;YAC9B,OAAO;YACP,WAAW,MAAM,EAAa,EAAE,OAAO,KAAK;YAC5C,aAAY;WACb,CAAA;UACQ,CAAA,CACR;;SAEL,kBAAC,GAAD;UAAO,WAAU;UAAwC,eAAY;SAAQ,CAAA;SAE7E,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAW,OAAM;WAAO,SAAQ;WAAY,WAAU;qBACpD,kBAAC,SAAD;YACE,IAAG;YACH,WAAU;YACV,WAAW,GAAG,EAAgB;YAC9B,OAAO;YACP,WAAW,MAAM,EAAa,EAAE,OAAO,KAAK;YAC5C,aAAY;WACb,CAAA;UACQ,CAAA,GACX,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YAAO,MAAM;YAAU,OAAO,EAAE,UAAU;YAAO,MAAM;WAAK,CAAA,GAC5D,kBAAC,QAAD;YAAM,WAAU;sBACb;WACG,CAAA,CACH;YACF;;QACF;WAEL,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,EAAa;SACvB,WAAU;mBAHZ,CAKG,EAAa,YACZ,kBAAC,GAAD,EAAS,WAAU,uBAAwB,CAAA,IAE3C,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,GAC7B,eAEI;;OACL,CAAA,CACD;;MACL,KAAS,kBAAC,KAAD;OAAG,WAAU;iBAAmD;MAAS,CAAA;KAC1E;MACJ;;GAGV,EAAE,eACD,kBAAC,UAAD;IACE,MAAK;IACL,eACE,EAAW,0BAA0B,mBAAmB,EAAE,eAAe,EAAE,GAAG;IAEhF,WAAU;cALZ;KAOE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;KAAC;KAAO,EAAE;KAAY;IAC7C;;EAEA;;AAEhB"}
1
+ {"version":3,"file":"FixtureDetailPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/fixtures/FixtureDetailPage.tsx"],"sourcesContent":["/**\n * Fixture Detail\n * @module atheletebridge/pages/fixtures\n *\n * Reads a single fixture (athFixture) and lets the user record a final result\n * (athRecordFixtureResult) which marks it COMPLETED and recomputes standings.\n *\n * The header is a crest-vs-crest Scoreboard hero; the record-result panel shows\n * each team's crest beside its score input. Semantic tokens only, responsive.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router';\nimport { ArrowLeft, Trophy, Loader2, Flag, Minus } from 'lucide-react';\nimport { GlassCard, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Scoreboard } from '../../components/Scoreboard';\nimport { Crest } from '../../components/Crest';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { FIXTURE_TYPE_LABELS } from '../../components/domain';\nimport { AvailabilityRsvpControl } from '../../components/availability/AvailabilityRsvpControl';\nimport { AvailabilityRosterPanel } from '../../components/availability/AvailabilityRosterPanel';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useFixture, useRecordFixtureResult } from '../../hooks/useAthleteBridgeApi';\nimport { useAbTranslate } from '../../i18n';\n\nexport function FixtureDetailPage() {\n const tr = useAbTranslate();\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useAthleteBridge();\n\n const fixture = useFixture(id);\n const recordResult = useRecordFixtureResult();\n\n const [homeScore, setHomeScore] = useState('');\n const [awayScore, setAwayScore] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n if (fixture.isLoading) {\n return (\n <PageLayout title={tr('atheletebridge.pages.fixtureDetail.title', 'Fixture')}>\n <LoadingState\n label={tr('atheletebridge.pages.fixtureDetail.loading', 'Loading fixture…')}\n />\n </PageLayout>\n );\n }\n\n if (fixture.isError || !fixture.data) {\n return (\n <PageLayout title={tr('atheletebridge.pages.fixtureDetail.title', 'Fixture')}>\n <ErrorState\n title={tr('atheletebridge.pages.fixtureDetail.notFoundTitle', 'Fixture not found')}\n message={tr(\n 'atheletebridge.pages.fixtureDetail.notFoundMessage',\n 'This fixture does not exist or you do not have access to it.'\n )}\n onRetry={() => navigateTo('/fixtures')}\n />\n </PageLayout>\n );\n }\n\n const f = fixture.data;\n const homeName = f.homeTeam?.name ?? tr('atheletebridge.pages.fixtureDetail.home', 'Home');\n const awayName =\n f.awayTeam?.name ??\n (f.awayTeamId ? tr('atheletebridge.pages.fixtureDetail.away', 'Away') : 'TBD');\n const canRecordResult =\n Boolean(f.awayTeamId) && (f.status === 'SCHEDULED' || f.status === 'LIVE');\n\n const handleRecord = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!id) return;\n const home = Number.parseInt(homeScore, 10);\n const away = Number.parseInt(awayScore, 10);\n if (Number.isNaN(home) || Number.isNaN(away)) {\n setError('Both scores are required and must be numbers.');\n return;\n }\n if (home < 0 || away < 0) {\n setError('Scores cannot be negative.');\n return;\n }\n try {\n await recordResult.mutateAsync({ id, input: { homeScore: home, awayScore: away } });\n setHomeScore('');\n setAwayScore('');\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to record result.');\n }\n };\n\n return (\n <PageLayout\n title={`${homeName} vs ${awayName}`}\n description={`${FIXTURE_TYPE_LABELS[f.type]}${f.competition ? ` · ${f.competition}` : ''}`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures')}\n 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\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> {tr('atheletebridge.pages.fixtureDetail.back', 'Back')}\n </button>\n }\n >\n {/* Crest-vs-crest hero scoreboard */}\n <Scoreboard fixture={f} variant=\"hero\" className=\"mb-8\" />\n\n {/* Availability / RSVP (BOFF-4134) — athlete's own response + coach roster view */}\n <div className=\"mb-8 grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_2fr]\">\n <AvailabilityRsvpControl teamId={f.homeTeamId} fixtureId={f.id} />\n <AvailabilityRosterPanel teamId={f.homeTeamId} fixtureId={f.id} />\n </div>\n\n {f.notes && (\n <EmphasisPanel className=\"mb-8\">\n <h2 className=\"mb-2 text-sm font-semibold text-text-primary\">\n {tr('atheletebridge.pages.fixtureDetail.notes', 'Notes')}\n </h2>\n <p className=\"text-sm text-text-secondary\">{f.notes}</p>\n </EmphasisPanel>\n )}\n\n {/* Record result */}\n {canRecordResult && (\n <section className=\"mb-8\">\n <h2 className=\"mb-4 flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Flag className=\"h-5 w-5\" />{' '}\n {tr('atheletebridge.pages.fixtureDetail.recordResult', 'Record result')}\n </h2>\n <GlassCard treatment=\"insight\" className=\"p-5 sm:p-6\">\n <p className=\"mb-5 text-sm text-text-secondary\">\n {tr(\n 'atheletebridge.pages.fixtureDetail.recordResultDescription',\n 'Recording a final score marks this fixture Completed and recomputes the competition standings for both teams.'\n )}\n </p>\n <form onSubmit={handleRecord}>\n <div className=\"flex flex-wrap items-end justify-center gap-4 sm:gap-6\">\n <div className=\"flex items-end gap-3\">\n <div className=\"flex flex-col items-center gap-2\">\n <Crest name={homeName} sport={f.homeTeam?.sport} size={40} />\n <span className=\"max-w-[8rem] truncate text-center text-xs font-medium text-text-secondary\">\n {homeName}\n </span>\n </div>\n <FormField\n label={tr('atheletebridge.pages.fixtureDetail.home', 'Home')}\n htmlFor=\"homeScore\"\n className=\"w-24\"\n >\n <input\n id=\"homeScore\"\n inputMode=\"numeric\"\n className={`${fieldInputClass} text-center text-lg font-bold tabular-nums`}\n value={homeScore}\n onChange={(e) => setHomeScore(e.target.value)}\n placeholder=\"0\"\n />\n </FormField>\n </div>\n\n <Minus className=\"mb-3 h-5 w-5 shrink-0 text-text-muted\" aria-hidden=\"true\" />\n\n <div className=\"flex items-end gap-3\">\n <FormField\n label={tr('atheletebridge.pages.fixtureDetail.away', 'Away')}\n htmlFor=\"awayScore\"\n className=\"w-24\"\n >\n <input\n id=\"awayScore\"\n inputMode=\"numeric\"\n className={`${fieldInputClass} text-center text-lg font-bold tabular-nums`}\n value={awayScore}\n onChange={(e) => setAwayScore(e.target.value)}\n placeholder=\"0\"\n />\n </FormField>\n <div className=\"flex flex-col items-center gap-2\">\n <Crest name={awayName} sport={f.awayTeam?.sport} size={40} />\n <span className=\"max-w-[8rem] truncate text-center text-xs font-medium text-text-secondary\">\n {awayName}\n </span>\n </div>\n </div>\n </div>\n\n <div className=\"mt-6 flex justify-center\">\n <button\n type=\"submit\"\n disabled={recordResult.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-6 py-2.5 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60\"\n >\n {recordResult.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Trophy className=\"h-4 w-4\" />\n )}\n {tr('atheletebridge.pages.fixtureDetail.recordResultAction', 'Record result')}\n </button>\n </div>\n </form>\n {error && <p className=\"mt-3 text-center text-sm text-status-error-text\">{error}</p>}\n </GlassCard>\n </section>\n )}\n\n {f.competition && (\n <button\n type=\"button\"\n onClick={() =>\n navigateTo(`/standings?competition=${encodeURIComponent(f.competition ?? '')}`)\n }\n 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\"\n >\n <Trophy className=\"h-4 w-4\" />{' '}\n {tr(\n 'atheletebridge.pages.fixtureDetail.viewStandings',\n `View ${f.competition} standings`\n )}\n </button>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA2BA,SAAgB,IAAoB;CAClC,IAAM,IAAK,EAAe,GACpB,EAAE,UAAO,EAA0B,GACnC,EAAE,kBAAe,EAAiB,GAElC,IAAU,EAAW,CAAE,GACvB,IAAe,EAAuB,GAEtC,CAAC,GAAW,KAAgB,EAAS,EAAE,GACvC,CAAC,GAAW,KAAgB,EAAS,EAAE,GACvC,CAAC,GAAO,KAAY,EAAwB,IAAI;CAEtD,IAAI,EAAQ,WACV,OACE,kBAAC,GAAD;EAAY,OAAO,EAAG,4CAA4C,SAAS;YACzE,kBAAC,GAAD,EACE,OAAO,EAAG,8CAA8C,kBAAkB,EAC3E,CAAA;CACS,CAAA;CAIhB,IAAI,EAAQ,WAAW,CAAC,EAAQ,MAC9B,OACE,kBAAC,GAAD;EAAY,OAAO,EAAG,4CAA4C,SAAS;YACzE,kBAAC,GAAD;GACE,OAAO,EAAG,oDAAoD,mBAAmB;GACjF,SAAS,EACP,sDACA,8DACF;GACA,eAAe,EAAW,WAAW;EACtC,CAAA;CACS,CAAA;CAIhB,IAAM,IAAI,EAAQ,MACZ,IAAW,EAAE,UAAU,QAAQ,EAAG,2CAA2C,MAAM,GACnF,IACJ,EAAE,UAAU,SACX,EAAE,aAAa,EAAG,2CAA2C,MAAM,IAAI,QACpE,IACJ,EAAQ,EAAE,eAAgB,EAAE,WAAW,eAAe,EAAE,WAAW;CAyBrE,OACE,kBAAC,GAAD;EACE,OAAO,GAAG,EAAS,MAAM;EACzB,aAAa,GAAG,EAAoB,EAAE,QAAQ,EAAE,cAAc,MAAM,EAAE,gBAAgB;EACtF,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,WAAW;GACrC,WAAU;aAHZ;IAKE,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA;IAAC;IAAE,EAAG,2CAA2C,MAAM;GACjF;;YAVZ;GAcE,kBAAC,GAAD;IAAY,SAAS;IAAG,SAAQ;IAAO,WAAU;GAAQ,CAAA;GAGzD,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KAAyB,QAAQ,EAAE;KAAY,WAAW,EAAE;IAAK,CAAA,GACjE,kBAAC,GAAD;KAAyB,QAAQ,EAAE;KAAY,WAAW,EAAE;IAAK,CAAA,CAC9D;;GAEJ,EAAE,SACD,kBAAC,GAAD;IAAe,WAAU;cAAzB,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,4CAA4C,OAAO;IACrD,CAAA,GACJ,kBAAC,KAAD;KAAG,WAAU;eAA+B,EAAE;IAAS,CAAA,CAC1C;;GAIhB,KACC,kBAAC,WAAD;IAAS,WAAU;cAAnB,CACE,kBAAC,MAAD;KAAI,WAAU;eAAd;MACE,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA;MAAE;MAC5B,EAAG,mDAAmD,eAAe;KACpE;QACJ,kBAAC,GAAD;KAAW,WAAU;KAAU,WAAU;eAAzC;MACE,kBAAC,KAAD;OAAG,WAAU;iBACV,EACC,8DACA,+GACF;MACC,CAAA;MACH,kBAAC,QAAD;OAAM,UAAU,OArEE,MAAuB;QAGjD,IAFA,EAAE,eAAe,GACjB,EAAS,IAAI,GACT,CAAC,GAAI;QACT,IAAM,IAAO,OAAO,SAAS,GAAW,EAAE,GACpC,IAAO,OAAO,SAAS,GAAW,EAAE;QAC1C,IAAI,OAAO,MAAM,CAAI,KAAK,OAAO,MAAM,CAAI,GAAG;SAC5C,EAAS,+CAA+C;SACxD;QACF;QACA,IAAI,IAAO,KAAK,IAAO,GAAG;SACxB,EAAS,4BAA4B;SACrC;QACF;QACA,IAAI;SAGF,AAFA,MAAM,EAAa,YAAY;UAAE;UAAI,OAAO;WAAE,WAAW;WAAM,WAAW;UAAK;SAAE,CAAC,GAClF,EAAa,EAAE,GACf,EAAa,EAAE;QACjB,SAAS,GAAK;SACZ,EAAS,aAAe,QAAQ,EAAI,UAAU,0BAA0B;QAC1E;OACF;iBAgDU,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YAAO,MAAM;YAAU,OAAO,EAAE,UAAU;YAAO,MAAM;WAAK,CAAA,GAC5D,kBAAC,QAAD;YAAM,WAAU;sBACb;WACG,CAAA,CACH;cACL,kBAAC,GAAD;WACE,OAAO,EAAG,2CAA2C,MAAM;WAC3D,SAAQ;WACR,WAAU;qBAEV,kBAAC,SAAD;YACE,IAAG;YACH,WAAU;YACV,WAAW,GAAG,EAAgB;YAC9B,OAAO;YACP,WAAW,MAAM,EAAa,EAAE,OAAO,KAAK;YAC5C,aAAY;WACb,CAAA;UACQ,CAAA,CACR;;SAEL,kBAAC,GAAD;UAAO,WAAU;UAAwC,eAAY;SAAQ,CAAA;SAE7E,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WACE,OAAO,EAAG,2CAA2C,MAAM;WAC3D,SAAQ;WACR,WAAU;qBAEV,kBAAC,SAAD;YACE,IAAG;YACH,WAAU;YACV,WAAW,GAAG,EAAgB;YAC9B,OAAO;YACP,WAAW,MAAM,EAAa,EAAE,OAAO,KAAK;YAC5C,aAAY;WACb,CAAA;UACQ,CAAA,GACX,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YAAO,MAAM;YAAU,OAAO,EAAE,UAAU;YAAO,MAAM;WAAK,CAAA,GAC5D,kBAAC,QAAD;YAAM,WAAU;sBACb;WACG,CAAA,CACH;YACF;;QACF;WAEL,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,UAAD;SACE,MAAK;SACL,UAAU,EAAa;SACvB,WAAU;mBAHZ,CAKG,EAAa,YACZ,kBAAC,GAAD,EAAS,WAAU,uBAAwB,CAAA,IAE3C,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA,GAE9B,EAAG,yDAAyD,eAAe,CACtE;;OACL,CAAA,CACD;;MACL,KAAS,kBAAC,KAAD;OAAG,WAAU;iBAAmD;MAAS,CAAA;KAC1E;MACJ;;GAGV,EAAE,eACD,kBAAC,UAAD;IACE,MAAK;IACL,eACE,EAAW,0BAA0B,mBAAmB,EAAE,eAAe,EAAE,GAAG;IAEhF,WAAU;cALZ;KAOE,kBAAC,GAAD,EAAQ,WAAU,UAAW,CAAA;KAAE;KAC9B,EACC,oDACA,QAAQ,EAAE,YAAY,WACxB;IACM;;EAEA;;AAEhB"}
@@ -1 +1 @@
1
- {"version":3,"file":"FixturesListPage.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/pages/fixtures/FixturesListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6BH,wBAAgB,gBAAgB,gCAgI/B"}
1
+ {"version":3,"file":"FixturesListPage.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/pages/fixtures/FixturesListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA8BH,wBAAgB,gBAAgB,gCA4I/B"}
@@ -1,17 +1,18 @@
1
- import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
2
- import { PageLayout as t } from "../../components/PageLayout.js";
3
- import { FIXTURE_TYPE_LABELS as n, FIXTURE_TYPE_OPTIONS as r } from "../../components/domain.js";
4
- import { EmptyState as i } from "../../components/EmptyState.js";
5
- import { ErrorState as a, LoadingState as o } from "../../components/LoadingState.js";
6
- import { useFixtures as s, useTeams as c } from "../../hooks/useAthleteBridgeApi.js";
7
- import { CursorPager as l } from "../../components/CursorPager.js";
8
- import { FilterSelect as u } from "../../components/FilterSelect.js";
9
- import { FixtureCard as d } from "../../components/FixtureCard.js";
10
- import { useMemo as f, useState as p } from "react";
11
- import { CalendarDays as m, Plus as h, Trophy as g } from "lucide-react";
12
- import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
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 { FIXTURE_TYPE_LABELS as r, FIXTURE_TYPE_OPTIONS as i } from "../../components/domain.js";
5
+ import { EmptyState as a } from "../../components/EmptyState.js";
6
+ import { ErrorState as o, LoadingState as s } from "../../components/LoadingState.js";
7
+ import { useFixtures as c, useTeams as l } from "../../hooks/useAthleteBridgeApi.js";
8
+ import { CursorPager as u } from "../../components/CursorPager.js";
9
+ import { FilterSelect as d } from "../../components/FilterSelect.js";
10
+ import { FixtureCard as f } from "../../components/FixtureCard.js";
11
+ import { useMemo as p, useState as m } from "react";
12
+ import { CalendarDays as h, Plus as g, Trophy as _ } from "lucide-react";
13
+ import { Fragment as v, jsx as y, jsxs as b } from "react/jsx-runtime";
13
14
  //#region src/atheletebridge/pages/fixtures/FixturesListPage.tsx
14
- var b = 12, x = [
15
+ var x = 12, S = [
15
16
  {
16
17
  value: "SCHEDULED",
17
18
  label: "Scheduled"
@@ -32,100 +33,108 @@ var b = 12, x = [
32
33
  value: "CANCELLED",
33
34
  label: "Cancelled"
34
35
  }
35
- ], S = r.map((e) => ({
36
+ ], C = i.map((e) => ({
36
37
  value: e,
37
- label: n[e]
38
+ label: r[e]
38
39
  }));
39
- function C() {
40
- let { navigateTo: n } = e(), [r, C] = p(""), [w, T] = p(""), [E, D] = p(""), [O, k] = p(0), A = c({ pagination: { limit: 100 } }), j = f(() => (A.data?.items ?? []).map((e) => ({
40
+ function w() {
41
+ let r = e(), { navigateTo: i } = t(), [w, T] = m(""), [E, D] = m(""), [O, k] = m(""), [A, j] = m(0), M = l({ pagination: { limit: 100 } }), N = p(() => (M.data?.items ?? []).map((e) => ({
41
42
  value: e.id,
42
43
  label: e.name
43
- })), [A.data]), M = s({
44
- status: r || void 0,
45
- teamId: w || void 0,
44
+ })), [M.data]), P = c({
45
+ status: w || void 0,
46
+ teamId: E || void 0,
46
47
  pagination: {
47
- limit: b,
48
- offset: O * b
48
+ limit: x,
49
+ offset: A * x
49
50
  }
50
- }), N = f(() => {
51
- let e = M.data?.items ?? [];
52
- return E ? e.filter((e) => e.type === E) : e;
53
- }, [M.data, E]), P = M.data?.pageInfo.hasMore ?? !1, F = !!(r || w || E), I = () => k(0);
54
- return /* @__PURE__ */ y(t, {
55
- title: "Fixtures",
56
- description: "Matches across friendlies, league games, cups, tournaments and scrimmages.",
57
- actions: /* @__PURE__ */ y("div", {
51
+ }), F = p(() => {
52
+ let e = P.data?.items ?? [];
53
+ return O ? e.filter((e) => e.type === O) : e;
54
+ }, [P.data, O]), I = P.data?.pageInfo.hasMore ?? !1, L = !!(w || E || O), R = () => j(0);
55
+ return /* @__PURE__ */ b(n, {
56
+ title: r("atheletebridge.pages.fixtures.title", "Fixtures"),
57
+ description: r("atheletebridge.pages.fixtures.description", "Matches across friendlies, league games, cups, tournaments and scrimmages."),
58
+ actions: /* @__PURE__ */ b("div", {
58
59
  className: "flex flex-wrap items-center gap-2",
59
- children: [/* @__PURE__ */ y("button", {
60
+ children: [/* @__PURE__ */ b("button", {
60
61
  type: "button",
61
- onClick: () => n("/tournaments"),
62
+ onClick: () => i("/tournaments"),
62
63
  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",
63
- children: [/* @__PURE__ */ v(g, { className: "h-4 w-4" }), " Tournament bracket"]
64
- }), /* @__PURE__ */ y("button", {
64
+ children: [
65
+ /* @__PURE__ */ y(_, { className: "h-4 w-4" }),
66
+ " ",
67
+ r("atheletebridge.pages.fixtures.tournamentBracket", "Tournament bracket")
68
+ ]
69
+ }), /* @__PURE__ */ b("button", {
65
70
  type: "button",
66
71
  "data-tour": "fixtures-create",
67
- onClick: () => n("/fixtures/new"),
72
+ onClick: () => i("/fixtures/new"),
68
73
  className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
69
- children: [/* @__PURE__ */ v(h, { className: "h-4 w-4" }), " Schedule fixture"]
74
+ children: [
75
+ /* @__PURE__ */ y(g, { className: "h-4 w-4" }),
76
+ " ",
77
+ r("atheletebridge.pages.fixtures.scheduleFixture", "Schedule fixture")
78
+ ]
70
79
  })]
71
80
  }),
72
- children: [/* @__PURE__ */ y("div", {
81
+ children: [/* @__PURE__ */ b("div", {
73
82
  "data-tour": "fixtures-filters",
74
83
  className: "mb-6 flex flex-wrap items-center gap-3",
75
84
  children: [
76
- /* @__PURE__ */ v(u, {
77
- ariaLabel: "Filter by status",
78
- allLabel: "All statuses",
79
- value: r,
85
+ /* @__PURE__ */ y(d, {
86
+ ariaLabel: r("atheletebridge.pages.fixtures.filterStatus", "Filter by status"),
87
+ allLabel: r("atheletebridge.pages.fixtures.allStatuses", "All statuses"),
88
+ value: w,
80
89
  onChange: (e) => {
81
- C(e), I();
90
+ T(e), R();
82
91
  },
83
- options: x
92
+ options: S
84
93
  }),
85
- /* @__PURE__ */ v(u, {
86
- ariaLabel: "Filter by team",
87
- allLabel: "All teams",
88
- value: w,
94
+ /* @__PURE__ */ y(d, {
95
+ ariaLabel: r("atheletebridge.pages.fixtures.filterTeam", "Filter by team"),
96
+ allLabel: r("atheletebridge.pages.fixtures.allTeams", "All teams"),
97
+ value: E,
89
98
  onChange: (e) => {
90
- T(e), I();
99
+ D(e), R();
91
100
  },
92
- options: j
101
+ options: N
93
102
  }),
94
- /* @__PURE__ */ v(u, {
95
- ariaLabel: "Filter by type",
96
- allLabel: "All types",
97
- value: E,
98
- onChange: (e) => D(e),
99
- options: S
103
+ /* @__PURE__ */ y(d, {
104
+ ariaLabel: r("atheletebridge.pages.fixtures.filterType", "Filter by type"),
105
+ allLabel: r("atheletebridge.pages.fixtures.allTypes", "All types"),
106
+ value: O,
107
+ onChange: (e) => k(e),
108
+ options: C
100
109
  })
101
110
  ]
102
- }), M.isLoading ? /* @__PURE__ */ v(o, { label: "Loading fixtures…" }) : M.isError ? /* @__PURE__ */ v(a, { onRetry: () => void M.refetch() }) : N.length === 0 ? /* @__PURE__ */ v(i, {
111
+ }), P.isLoading ? /* @__PURE__ */ y(s, { label: r("atheletebridge.pages.fixtures.loading", "Loading fixtures…") }) : P.isError ? /* @__PURE__ */ y(o, { onRetry: () => void P.refetch() }) : F.length === 0 ? /* @__PURE__ */ y(a, {
103
112
  illustration: "empty-calendar",
104
- icon: /* @__PURE__ */ v(m, { className: "h-10 w-10" }),
105
- title: "No fixtures found",
106
- description: F ? "Try clearing your filters to see all fixtures." : "Schedule a match to start tracking results and standings.",
107
- action: /* @__PURE__ */ v("button", {
113
+ icon: /* @__PURE__ */ y(h, { className: "h-10 w-10" }),
114
+ title: r("atheletebridge.pages.fixtures.noFixtures", "No fixtures found"),
115
+ description: L ? r("atheletebridge.pages.fixtures.noFixturesFilterHint", "Try clearing your filters to see all fixtures.") : r("atheletebridge.pages.fixtures.noFixturesHint", "Schedule a match to start tracking results and standings."),
116
+ action: /* @__PURE__ */ y("button", {
108
117
  type: "button",
109
- onClick: () => n("/fixtures/new"),
118
+ onClick: () => i("/fixtures/new"),
110
119
  className: "rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
111
- children: "Schedule fixture"
120
+ children: r("atheletebridge.pages.fixtures.scheduleFixtureAction", "Schedule fixture")
112
121
  })
113
- }) : /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v("div", {
122
+ }) : /* @__PURE__ */ b(v, { children: [/* @__PURE__ */ y("div", {
114
123
  className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",
115
- children: N.map((e) => /* @__PURE__ */ v(d, {
124
+ children: F.map((e) => /* @__PURE__ */ y(f, {
116
125
  fixture: e,
117
- onClick: () => n(`/fixtures/${e.id}`)
126
+ onClick: () => i(`/fixtures/${e.id}`)
118
127
  }, e.id))
119
- }), /* @__PURE__ */ v(l, {
128
+ }), /* @__PURE__ */ y(u, {
120
129
  className: "mt-6",
121
- page: O,
122
- hasMore: P,
123
- onPrev: () => k((e) => Math.max(0, e - 1)),
124
- onNext: () => k((e) => e + 1)
130
+ page: A,
131
+ hasMore: I,
132
+ onPrev: () => j((e) => Math.max(0, e - 1)),
133
+ onNext: () => j((e) => e + 1)
125
134
  })] })]
126
135
  });
127
136
  }
128
137
  //#endregion
129
- export { C as FixturesListPage };
138
+ export { w as FixturesListPage };
130
139
 
131
140
  //# sourceMappingURL=FixturesListPage.js.map