@burdenoff/microfe-atheletebridge 2026.713.1 → 2026.716.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 (72) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.js +50 -53
  2. package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
  3. package/dist/atheletebridge/AthleteBridgeRoutes.d.ts.map +1 -1
  4. package/dist/atheletebridge/AthleteBridgeRoutes.js +29 -25
  5. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  6. package/dist/atheletebridge/admin/AdminDashboardPage.d.ts +4 -0
  7. package/dist/atheletebridge/admin/AdminDashboardPage.d.ts.map +1 -0
  8. package/dist/atheletebridge/admin/AdminDashboardPage.js +553 -0
  9. package/dist/atheletebridge/admin/AdminDashboardPage.js.map +1 -0
  10. package/dist/atheletebridge/admin/AdminRoot.d.ts +9 -0
  11. package/dist/atheletebridge/admin/AdminRoot.d.ts.map +1 -0
  12. package/dist/atheletebridge/admin/AdminRoot.js +23 -0
  13. package/dist/atheletebridge/admin/AdminRoot.js.map +1 -0
  14. package/dist/atheletebridge/admin/index.d.ts +11 -0
  15. package/dist/atheletebridge/admin/index.d.ts.map +1 -0
  16. package/dist/atheletebridge/admin/index.js +2 -0
  17. package/dist/atheletebridge/components/DrillVideoLink.js +1 -1
  18. package/dist/atheletebridge/components/DrillVideoLink.js.map +1 -1
  19. package/dist/atheletebridge/components/ProgramCard.js +1 -1
  20. package/dist/atheletebridge/components/ProgramCard.js.map +1 -1
  21. package/dist/atheletebridge/components/TeamCard.js +1 -1
  22. package/dist/atheletebridge/components/TeamCard.js.map +1 -1
  23. package/dist/atheletebridge/components/UserSearchSelect.js +2 -2
  24. package/dist/atheletebridge/components/UserSearchSelect.js.map +1 -1
  25. package/dist/atheletebridge/components/domain.js +3 -3
  26. package/dist/atheletebridge/components/domain.js.map +1 -1
  27. package/dist/atheletebridge/hooks/index.js +1 -0
  28. package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts.map +1 -1
  29. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +39 -39
  30. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  31. package/dist/atheletebridge/i18n.d.ts +26 -0
  32. package/dist/atheletebridge/i18n.d.ts.map +1 -0
  33. package/dist/atheletebridge/i18n.js +14 -0
  34. package/dist/atheletebridge/i18n.js.map +1 -0
  35. package/dist/atheletebridge/index.d.ts +1 -0
  36. package/dist/atheletebridge/index.d.ts.map +1 -1
  37. package/dist/atheletebridge/index.js +3 -0
  38. package/dist/atheletebridge/pages/DashboardPage.d.ts.map +1 -1
  39. package/dist/atheletebridge/pages/DashboardPage.js +166 -144
  40. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  41. package/dist/atheletebridge/pages/StandingsPage.d.ts.map +1 -1
  42. package/dist/atheletebridge/pages/StandingsPage.js +98 -92
  43. package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
  44. package/dist/atheletebridge/pages/fixtures/FixturesListPage.d.ts.map +1 -1
  45. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js +6 -4
  46. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -1
  47. package/dist/atheletebridge/pages/onboarding/OnboardingPage.d.ts +4 -0
  48. package/dist/atheletebridge/pages/onboarding/OnboardingPage.d.ts.map +1 -0
  49. package/dist/atheletebridge/pages/onboarding/OnboardingPage.js +371 -0
  50. package/dist/atheletebridge/pages/onboarding/OnboardingPage.js.map +1 -0
  51. package/dist/atheletebridge/pages/performance/PerformancePage.d.ts.map +1 -1
  52. package/dist/atheletebridge/pages/performance/PerformancePage.js +42 -41
  53. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -1
  54. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +3 -3
  55. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  56. package/dist/atheletebridge/pages/programs/ProgramsListPage.d.ts.map +1 -1
  57. package/dist/atheletebridge/pages/programs/ProgramsListPage.js +9 -7
  58. package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -1
  59. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +1 -1
  60. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
  61. package/dist/atheletebridge/pages/sessions/SessionsListPage.d.ts.map +1 -1
  62. package/dist/atheletebridge/pages/sessions/SessionsListPage.js +6 -4
  63. package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -1
  64. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +1 -1
  65. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  66. package/dist/atheletebridge/pages/teams/TeamsListPage.d.ts.map +1 -1
  67. package/dist/atheletebridge/pages/teams/TeamsListPage.js +8 -6
  68. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
  69. package/dist/atheletebridge/types/index.d.ts +19 -3
  70. package/dist/atheletebridge/types/index.d.ts.map +1 -1
  71. package/dist/index.js +5 -3
  72. package/package.json +13 -2
@@ -1,190 +1,196 @@
1
- import { cn as e } from "../utils/cn.js";
2
- import { PageLayout as t } from "../components/PageLayout.js";
3
- import { Crest as n } from "../components/Crest.js";
4
- import { EmptyState as r } from "../components/EmptyState.js";
5
- import { ErrorState as i, LoadingState as a } from "../components/LoadingState.js";
6
- import { useFixtures as o, useStandings as s } from "../hooks/useAthleteBridgeApi.js";
7
- import { fieldInputClass as c } from "../components/form.js";
8
- import { useEffect as l, useMemo as u, useState as d } from "react";
9
- import { Search as f, Trophy as p } from "lucide-react";
10
- import { useSearchParams as m } from "react-router-dom";
11
- import { jsx as h, jsxs as g } from "react/jsx-runtime";
12
- import { EmphasisPanel as _ } from "@burdenoff/fe-libs/ui";
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 { Crest as r } from "../components/Crest.js";
5
+ import { EmptyState as i } from "../components/EmptyState.js";
6
+ import { ErrorState as a, LoadingState as o } from "../components/LoadingState.js";
7
+ import { useFixtures as s, useStandings as c } from "../hooks/useAthleteBridgeApi.js";
8
+ import { fieldInputClass as l } from "../components/form.js";
9
+ import { useEffect as u, useMemo as d, useState as f } from "react";
10
+ import { Search as p, Trophy as m } from "lucide-react";
11
+ import { useSearchParams as h } from "react-router-dom";
12
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
13
+ import { EmphasisPanel as v } from "@burdenoff/fe-libs/ui";
13
14
  //#region src/atheletebridge/pages/StandingsPage.tsx
14
- function v() {
15
- let [v] = m(), y = v.get("competition") ?? "", [b, x] = d(y), [S, C] = d(y), w = o({ pagination: { limit: 100 } }), T = u(() => {
15
+ function y() {
16
+ let y = e(), [b] = h(), x = b.get("competition") ?? "", [S, C] = f(x), [w, T] = f(x), E = s({ pagination: { limit: 100 } }), D = d(() => {
16
17
  let e = /* @__PURE__ */ new Set();
17
- for (let t of w.data?.items ?? []) t.competition && e.add(t.competition);
18
+ for (let t of E.data?.items ?? []) t.competition && e.add(t.competition);
18
19
  return Array.from(e).sort();
19
- }, [w.data]);
20
- l(() => {
21
- !S && T.length > 0 && (x(T[0]), C(T[0]));
22
- }, [S, T]);
23
- let E = s(S || void 0), D = u(() => [...E.data ?? []].sort((e, t) => t.points === e.points ? t.goalsFor - e.goalsFor : t.points - e.points), [E.data]);
24
- return /* @__PURE__ */ g(t, {
25
- title: "Standings",
26
- description: "Live competition tables — recomputed automatically from results.",
27
- children: [/* @__PURE__ */ g("form", {
20
+ }, [E.data]);
21
+ u(() => {
22
+ !w && D.length > 0 && (C(D[0]), T(D[0]));
23
+ }, [w, D]);
24
+ let O = c(w || void 0), k = d(() => [...O.data ?? []].sort((e, t) => t.points === e.points ? t.goalsFor - e.goalsFor : t.points - e.points), [O.data]);
25
+ return /* @__PURE__ */ _(n, {
26
+ title: y("atheletebridge.pages.standings.title", "Standings"),
27
+ description: y("atheletebridge.pages.standings.description", "Live competition tables — recomputed automatically from results."),
28
+ children: [/* @__PURE__ */ _("form", {
28
29
  onSubmit: (e) => {
29
- e.preventDefault(), C(b.trim());
30
+ e.preventDefault(), T(S.trim());
30
31
  },
32
+ "data-tour": "standings-competition",
31
33
  className: "mb-6 flex flex-wrap items-end gap-3",
32
- children: [/* @__PURE__ */ g("div", {
34
+ children: [/* @__PURE__ */ _("div", {
33
35
  className: "flex-1 min-w-[220px]",
34
36
  children: [
35
- /* @__PURE__ */ h("label", {
37
+ /* @__PURE__ */ g("label", {
36
38
  htmlFor: "competition",
37
39
  className: "mb-1.5 block text-sm font-medium text-text-primary",
38
- children: "Competition"
40
+ children: y("atheletebridge.pages.standings.competitionLabel", "Competition")
39
41
  }),
40
- /* @__PURE__ */ h("input", {
42
+ /* @__PURE__ */ g("input", {
41
43
  id: "competition",
42
44
  list: "ath-competitions",
43
- className: c,
44
- value: b,
45
- onChange: (e) => x(e.target.value),
46
- placeholder: "e.g. Spring League 2026"
45
+ className: l,
46
+ value: S,
47
+ onChange: (e) => C(e.target.value),
48
+ placeholder: y("atheletebridge.pages.standings.competitionPlaceholder", "e.g. Spring League 2026")
47
49
  }),
48
- /* @__PURE__ */ h("datalist", {
50
+ /* @__PURE__ */ g("datalist", {
49
51
  id: "ath-competitions",
50
- children: T.map((e) => /* @__PURE__ */ h("option", { value: e }, e))
52
+ children: D.map((e) => /* @__PURE__ */ g("option", { value: e }, e))
51
53
  })
52
54
  ]
53
- }), /* @__PURE__ */ g("button", {
55
+ }), /* @__PURE__ */ _("button", {
54
56
  type: "submit",
55
57
  className: "inline-flex h-[38px] items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
56
- children: [/* @__PURE__ */ h(f, { className: "h-4 w-4" }), " View table"]
58
+ children: [
59
+ /* @__PURE__ */ g(p, { className: "h-4 w-4" }),
60
+ " ",
61
+ y("atheletebridge.pages.standings.viewTable", "View table")
62
+ ]
57
63
  })]
58
- }), S ? E.isLoading ? /* @__PURE__ */ h(a, { label: "Loading standings…" }) : E.isError ? /* @__PURE__ */ h(i, { onRetry: () => void E.refetch() }) : D.length === 0 ? /* @__PURE__ */ h(r, {
64
+ }), w ? O.isLoading ? /* @__PURE__ */ g(o, { label: y("atheletebridge.pages.standings.loading", "Loading standings…") }) : O.isError ? /* @__PURE__ */ g(a, { onRetry: () => void O.refetch() }) : k.length === 0 ? /* @__PURE__ */ g(i, {
59
65
  illustration: "empty-data",
60
- icon: /* @__PURE__ */ h(p, { className: "h-10 w-10" }),
61
- title: "No standings yet",
62
- description: `No results have been recorded for "${S}". Record a fixture result to build the table.`
63
- }) : /* @__PURE__ */ h(_, {
66
+ icon: /* @__PURE__ */ g(m, { className: "h-10 w-10" }),
67
+ title: y("atheletebridge.pages.standings.empty", "No standings yet"),
68
+ description: `No results have been recorded for "${w}". Record a fixture result to build the table.`
69
+ }) : /* @__PURE__ */ g(v, {
64
70
  className: "overflow-x-auto",
65
- children: /* @__PURE__ */ g("table", {
71
+ children: /* @__PURE__ */ _("table", {
66
72
  className: "w-full min-w-[640px] text-sm",
67
- children: [/* @__PURE__ */ h("thead", { children: /* @__PURE__ */ g("tr", {
73
+ children: [/* @__PURE__ */ g("thead", { children: /* @__PURE__ */ _("tr", {
68
74
  className: "border-b border-border-seam text-left text-xs uppercase tracking-wide text-text-secondary",
69
75
  children: [
70
- /* @__PURE__ */ h("th", {
76
+ /* @__PURE__ */ g("th", {
71
77
  className: "px-3 py-2 font-medium",
72
78
  children: "#"
73
79
  }),
74
- /* @__PURE__ */ h("th", {
80
+ /* @__PURE__ */ g("th", {
75
81
  className: "px-3 py-2 font-medium",
76
82
  children: "Team"
77
83
  }),
78
- /* @__PURE__ */ h("th", {
84
+ /* @__PURE__ */ g("th", {
79
85
  className: "px-3 py-2 text-center font-medium",
80
86
  children: "P"
81
87
  }),
82
- /* @__PURE__ */ h("th", {
88
+ /* @__PURE__ */ g("th", {
83
89
  className: "px-3 py-2 text-center font-medium",
84
90
  children: "W"
85
91
  }),
86
- /* @__PURE__ */ h("th", {
92
+ /* @__PURE__ */ g("th", {
87
93
  className: "px-3 py-2 text-center font-medium",
88
94
  children: "D"
89
95
  }),
90
- /* @__PURE__ */ h("th", {
96
+ /* @__PURE__ */ g("th", {
91
97
  className: "px-3 py-2 text-center font-medium",
92
98
  children: "L"
93
99
  }),
94
- /* @__PURE__ */ h("th", {
100
+ /* @__PURE__ */ g("th", {
95
101
  className: "px-3 py-2 text-center font-medium",
96
102
  children: "GF"
97
103
  }),
98
- /* @__PURE__ */ h("th", {
104
+ /* @__PURE__ */ g("th", {
99
105
  className: "px-3 py-2 text-center font-medium",
100
106
  children: "GA"
101
107
  }),
102
- /* @__PURE__ */ h("th", {
108
+ /* @__PURE__ */ g("th", {
103
109
  className: "px-3 py-2 text-center font-medium",
104
110
  children: "GD"
105
111
  }),
106
- /* @__PURE__ */ h("th", {
112
+ /* @__PURE__ */ g("th", {
107
113
  className: "px-3 py-2 text-center font-semibold text-text-primary",
108
114
  children: "Pts"
109
115
  })
110
116
  ]
111
- }) }), /* @__PURE__ */ h("tbody", { children: D.map((t, r) => {
112
- let i = t.rank ?? r + 1, a = i === 1, o = t.goalsFor - t.goalsAgainst, s = t.team?.name ?? "Unknown team";
113
- return /* @__PURE__ */ g("tr", {
114
- className: e("border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/50", a && "bg-[var(--color-accent-soft)]/40"),
117
+ }) }), /* @__PURE__ */ g("tbody", { children: k.map((e, n) => {
118
+ let i = e.rank ?? n + 1, a = i === 1, o = e.goalsFor - e.goalsAgainst, s = e.team?.name ?? "Unknown team";
119
+ return /* @__PURE__ */ _("tr", {
120
+ className: t("border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/50", a && "bg-[var(--color-accent-soft)]/40"),
115
121
  children: [
116
- /* @__PURE__ */ h("td", {
122
+ /* @__PURE__ */ g("td", {
117
123
  className: "py-2.5 pl-0 pr-3",
118
- children: /* @__PURE__ */ g("span", {
124
+ children: /* @__PURE__ */ _("span", {
119
125
  className: "flex items-center",
120
- children: [/* @__PURE__ */ h("span", {
126
+ children: [/* @__PURE__ */ g("span", {
121
127
  "aria-hidden": "true",
122
- className: e("mr-2 h-6 w-1 rounded-full", a ? "bg-action-primary-bg" : "bg-transparent")
123
- }), /* @__PURE__ */ h("span", {
124
- className: e("tabular-nums", a ? "font-bold text-primary" : "text-text-secondary"),
128
+ className: t("mr-2 h-6 w-1 rounded-full", a ? "bg-action-primary-bg" : "bg-transparent")
129
+ }), /* @__PURE__ */ g("span", {
130
+ className: t("tabular-nums", a ? "font-bold text-text-primary" : "text-text-secondary"),
125
131
  children: i
126
132
  })]
127
133
  })
128
134
  }),
129
- /* @__PURE__ */ h("td", {
135
+ /* @__PURE__ */ g("td", {
130
136
  className: "px-3 py-2.5",
131
- children: /* @__PURE__ */ g("span", {
137
+ children: /* @__PURE__ */ _("span", {
132
138
  className: "flex min-w-0 items-center gap-2.5",
133
- children: [/* @__PURE__ */ h(n, {
139
+ children: [/* @__PURE__ */ g(r, {
134
140
  name: s,
135
- sport: t.team?.sport,
141
+ sport: e.team?.sport,
136
142
  size: 26
137
- }), /* @__PURE__ */ h("span", {
143
+ }), /* @__PURE__ */ g("span", {
138
144
  className: "truncate font-medium text-text-primary",
139
145
  children: s
140
146
  })]
141
147
  })
142
148
  }),
143
- /* @__PURE__ */ h("td", {
149
+ /* @__PURE__ */ g("td", {
144
150
  className: "px-3 py-2.5 text-center tabular-nums text-text-secondary",
145
- children: t.played
151
+ children: e.played
146
152
  }),
147
- /* @__PURE__ */ h("td", {
153
+ /* @__PURE__ */ g("td", {
148
154
  className: "px-3 py-2.5 text-center tabular-nums text-text-secondary",
149
- children: t.won
155
+ children: e.won
150
156
  }),
151
- /* @__PURE__ */ h("td", {
157
+ /* @__PURE__ */ g("td", {
152
158
  className: "px-3 py-2.5 text-center tabular-nums text-text-secondary",
153
- children: t.drawn
159
+ children: e.drawn
154
160
  }),
155
- /* @__PURE__ */ h("td", {
161
+ /* @__PURE__ */ g("td", {
156
162
  className: "px-3 py-2.5 text-center tabular-nums text-text-secondary",
157
- children: t.lost
163
+ children: e.lost
158
164
  }),
159
- /* @__PURE__ */ h("td", {
165
+ /* @__PURE__ */ g("td", {
160
166
  className: "px-3 py-2.5 text-center tabular-nums text-text-secondary",
161
- children: t.goalsFor
167
+ children: e.goalsFor
162
168
  }),
163
- /* @__PURE__ */ h("td", {
169
+ /* @__PURE__ */ g("td", {
164
170
  className: "px-3 py-2.5 text-center tabular-nums text-text-secondary",
165
- children: t.goalsAgainst
171
+ children: e.goalsAgainst
166
172
  }),
167
- /* @__PURE__ */ h("td", {
168
- className: e("px-3 py-2.5 text-center font-medium tabular-nums", o > 0 ? "text-status-success-text" : o < 0 ? "text-status-error-text" : "text-text-secondary"),
173
+ /* @__PURE__ */ g("td", {
174
+ className: t("px-3 py-2.5 text-center font-medium tabular-nums", o > 0 ? "text-status-success-text" : o < 0 ? "text-status-error-text" : "text-text-secondary"),
169
175
  children: o > 0 ? `+${o}` : o
170
176
  }),
171
- /* @__PURE__ */ h("td", {
172
- className: e("px-3 py-2.5 text-center font-bold tabular-nums", a ? "text-primary" : "text-text-primary"),
173
- children: t.points
177
+ /* @__PURE__ */ g("td", {
178
+ className: t("px-3 py-2.5 text-center font-bold tabular-nums", a ? "text-primary" : "text-text-primary"),
179
+ children: e.points
174
180
  })
175
181
  ]
176
- }, t.id);
182
+ }, e.id);
177
183
  }) })]
178
184
  })
179
- }) : /* @__PURE__ */ h(r, {
185
+ }) : /* @__PURE__ */ g(i, {
180
186
  illustration: "empty-data",
181
- icon: /* @__PURE__ */ h(p, { className: "h-10 w-10" }),
182
- title: "Pick a competition",
183
- description: "Enter a competition name to see its live standings. Standings are computed from recorded fixture results on a 3-1-0 model."
187
+ icon: /* @__PURE__ */ g(m, { className: "h-10 w-10" }),
188
+ title: y("atheletebridge.pages.standings.pickCompetition", "Pick a competition"),
189
+ description: y("atheletebridge.pages.standings.pickCompetitionHint", "Enter a competition name to see its live standings. Standings are computed from recorded fixture results on a 3-1-0 model.")
184
190
  })]
185
191
  });
186
192
  }
187
193
  //#endregion
188
- export { v as StandingsPage };
194
+ export { y as StandingsPage };
189
195
 
190
196
  //# sourceMappingURL=StandingsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StandingsPage.js","names":[],"sources":["../../../src/atheletebridge/pages/StandingsPage.tsx"],"sourcesContent":["/**\n * Standings\n * @module atheletebridge/pages\n *\n * Reads the live competition table (athStandings) for a chosen competition.\n * The svc requires a competition name, so the user picks one (seeded from\n * fixtures that carry a competition, or typed directly).\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Search, Trophy } from 'lucide-react';\nimport { EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { EmptyState } from '../components/EmptyState';\nimport { LoadingState, ErrorState } from '../components/LoadingState';\nimport { Crest } from '../components/Crest';\nimport { fieldInputClass } from '../components/form';\nimport { cn } from '../utils/cn';\nimport { useFixtures, useStandings } from '../hooks/useAthleteBridgeApi';\n\nexport function StandingsPage() {\n const [searchParams] = useSearchParams();\n const initialCompetition = searchParams.get('competition') ?? '';\n\n const [competition, setCompetition] = useState(initialCompetition);\n const [activeCompetition, setActiveCompetition] = useState(initialCompetition);\n\n // Suggest competitions that appear on existing fixtures.\n const fixtures = useFixtures({ pagination: { limit: 100 } });\n const competitions = useMemo(() => {\n const set = new Set<string>();\n for (const f of fixtures.data?.items ?? []) {\n if (f.competition) set.add(f.competition);\n }\n return Array.from(set).sort();\n }, [fixtures.data]);\n\n // If no competition selected yet but fixtures have one, default to the first.\n useEffect(() => {\n if (!activeCompetition && competitions.length > 0) {\n setCompetition(competitions[0]);\n setActiveCompetition(competitions[0]);\n }\n }, [activeCompetition, competitions]);\n\n const standings = useStandings(activeCompetition || undefined);\n const rows = useMemo(() => {\n const items = standings.data ?? [];\n return [...items].sort((a, b) => {\n if (b.points !== a.points) return b.points - a.points;\n return b.goalsFor - a.goalsFor;\n });\n }, [standings.data]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setActiveCompetition(competition.trim());\n };\n\n return (\n <PageLayout\n title=\"Standings\"\n description=\"Live competition tables — recomputed automatically from results.\"\n >\n <form onSubmit={handleSubmit} className=\"mb-6 flex flex-wrap items-end gap-3\">\n <div className=\"flex-1 min-w-[220px]\">\n <label\n htmlFor=\"competition\"\n className=\"mb-1.5 block text-sm font-medium text-text-primary\"\n >\n Competition\n </label>\n <input\n id=\"competition\"\n list=\"ath-competitions\"\n className={fieldInputClass}\n value={competition}\n onChange={(e) => setCompetition(e.target.value)}\n placeholder=\"e.g. Spring League 2026\"\n />\n <datalist id=\"ath-competitions\">\n {competitions.map((c) => (\n <option key={c} value={c} />\n ))}\n </datalist>\n </div>\n <button\n type=\"submit\"\n className=\"inline-flex h-[38px] items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Search className=\"h-4 w-4\" /> View table\n </button>\n </form>\n\n {!activeCompetition ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Trophy className=\"h-10 w-10\" />}\n title=\"Pick a competition\"\n description=\"Enter a competition name to see its live standings. Standings are computed from recorded fixture results on a 3-1-0 model.\"\n />\n ) : standings.isLoading ? (\n <LoadingState label=\"Loading standings…\" />\n ) : standings.isError ? (\n <ErrorState onRetry={() => void standings.refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Trophy className=\"h-10 w-10\" />}\n title=\"No standings yet\"\n description={`No results have been recorded for \"${activeCompetition}\". Record a fixture result to build the table.`}\n />\n ) : (\n <EmphasisPanel className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[640px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam text-left text-xs uppercase tracking-wide text-text-secondary\">\n <th className=\"px-3 py-2 font-medium\">#</th>\n <th className=\"px-3 py-2 font-medium\">Team</th>\n <th className=\"px-3 py-2 text-center font-medium\">P</th>\n <th className=\"px-3 py-2 text-center font-medium\">W</th>\n <th className=\"px-3 py-2 text-center font-medium\">D</th>\n <th className=\"px-3 py-2 text-center font-medium\">L</th>\n <th className=\"px-3 py-2 text-center font-medium\">GF</th>\n <th className=\"px-3 py-2 text-center font-medium\">GA</th>\n <th className=\"px-3 py-2 text-center font-medium\">GD</th>\n <th className=\"px-3 py-2 text-center font-semibold text-text-primary\">Pts</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row, idx) => {\n const rank = row.rank ?? idx + 1;\n const isLeader = rank === 1;\n const gd = row.goalsFor - row.goalsAgainst;\n const teamName = row.team?.name ?? 'Unknown team';\n return (\n <tr\n key={row.id}\n className={cn(\n 'border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/50',\n isLeader && 'bg-[var(--color-accent-soft)]/40'\n )}\n >\n <td className=\"py-2.5 pl-0 pr-3\">\n <span className=\"flex items-center\">\n <span\n aria-hidden=\"true\"\n className={cn(\n 'mr-2 h-6 w-1 rounded-full',\n isLeader ? 'bg-action-primary-bg' : 'bg-transparent'\n )}\n />\n <span\n className={cn(\n 'tabular-nums',\n isLeader ? 'font-bold text-primary' : 'text-text-secondary'\n )}\n >\n {rank}\n </span>\n </span>\n </td>\n <td className=\"px-3 py-2.5\">\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <Crest name={teamName} sport={row.team?.sport} size={26} />\n <span className=\"truncate font-medium text-text-primary\">{teamName}</span>\n </span>\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.played}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.won}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.drawn}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.lost}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.goalsFor}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.goalsAgainst}\n </td>\n <td\n className={cn(\n 'px-3 py-2.5 text-center font-medium tabular-nums',\n gd > 0\n ? 'text-status-success-text'\n : gd < 0\n ? 'text-status-error-text'\n : 'text-text-secondary'\n )}\n >\n {gd > 0 ? `+${gd}` : gd}\n </td>\n <td\n className={cn(\n 'px-3 py-2.5 text-center font-bold tabular-nums',\n isLeader ? 'text-primary' : 'text-text-primary'\n )}\n >\n {row.points}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </EmphasisPanel>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"StandingsPage.js","names":[],"sources":["../../../src/atheletebridge/pages/StandingsPage.tsx"],"sourcesContent":["/**\n * Standings\n * @module atheletebridge/pages\n *\n * Reads the live competition table (athStandings) for a chosen competition.\n * The svc requires a competition name, so the user picks one (seeded from\n * fixtures that carry a competition, or typed directly).\n */\n\nimport { useEffect, useMemo, useState } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { Search, Trophy } from 'lucide-react';\nimport { EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../components/PageLayout';\nimport { EmptyState } from '../components/EmptyState';\nimport { LoadingState, ErrorState } from '../components/LoadingState';\nimport { Crest } from '../components/Crest';\nimport { fieldInputClass } from '../components/form';\nimport { cn } from '../utils/cn';\nimport { useFixtures, useStandings } from '../hooks/useAthleteBridgeApi';\nimport { useAbTranslate } from '../i18n';\n\nexport function StandingsPage() {\n const tr = useAbTranslate();\n const [searchParams] = useSearchParams();\n const initialCompetition = searchParams.get('competition') ?? '';\n\n const [competition, setCompetition] = useState(initialCompetition);\n const [activeCompetition, setActiveCompetition] = useState(initialCompetition);\n\n // Suggest competitions that appear on existing fixtures.\n const fixtures = useFixtures({ pagination: { limit: 100 } });\n const competitions = useMemo(() => {\n const set = new Set<string>();\n for (const f of fixtures.data?.items ?? []) {\n if (f.competition) set.add(f.competition);\n }\n return Array.from(set).sort();\n }, [fixtures.data]);\n\n // If no competition selected yet but fixtures have one, default to the first.\n useEffect(() => {\n if (!activeCompetition && competitions.length > 0) {\n setCompetition(competitions[0]);\n setActiveCompetition(competitions[0]);\n }\n }, [activeCompetition, competitions]);\n\n const standings = useStandings(activeCompetition || undefined);\n const rows = useMemo(() => {\n const items = standings.data ?? [];\n return [...items].sort((a, b) => {\n if (b.points !== a.points) return b.points - a.points;\n return b.goalsFor - a.goalsFor;\n });\n }, [standings.data]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setActiveCompetition(competition.trim());\n };\n\n return (\n <PageLayout\n title={tr('atheletebridge.pages.standings.title', 'Standings')}\n description={tr(\n 'atheletebridge.pages.standings.description',\n 'Live competition tables — recomputed automatically from results.'\n )}\n >\n <form\n onSubmit={handleSubmit}\n data-tour=\"standings-competition\"\n className=\"mb-6 flex flex-wrap items-end gap-3\"\n >\n <div className=\"flex-1 min-w-[220px]\">\n <label\n htmlFor=\"competition\"\n className=\"mb-1.5 block text-sm font-medium text-text-primary\"\n >\n {tr('atheletebridge.pages.standings.competitionLabel', 'Competition')}\n </label>\n <input\n id=\"competition\"\n list=\"ath-competitions\"\n className={fieldInputClass}\n value={competition}\n onChange={(e) => setCompetition(e.target.value)}\n placeholder={tr(\n 'atheletebridge.pages.standings.competitionPlaceholder',\n 'e.g. Spring League 2026'\n )}\n />\n <datalist id=\"ath-competitions\">\n {competitions.map((c) => (\n <option key={c} value={c} />\n ))}\n </datalist>\n </div>\n <button\n type=\"submit\"\n className=\"inline-flex h-[38px] items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Search className=\"h-4 w-4\" />{' '}\n {tr('atheletebridge.pages.standings.viewTable', 'View table')}\n </button>\n </form>\n\n {!activeCompetition ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Trophy className=\"h-10 w-10\" />}\n title={tr('atheletebridge.pages.standings.pickCompetition', 'Pick a competition')}\n description={tr(\n 'atheletebridge.pages.standings.pickCompetitionHint',\n 'Enter a competition name to see its live standings. Standings are computed from recorded fixture results on a 3-1-0 model.'\n )}\n />\n ) : standings.isLoading ? (\n <LoadingState label={tr('atheletebridge.pages.standings.loading', 'Loading standings…')} />\n ) : standings.isError ? (\n <ErrorState onRetry={() => void standings.refetch()} />\n ) : rows.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Trophy className=\"h-10 w-10\" />}\n title={tr('atheletebridge.pages.standings.empty', 'No standings yet')}\n description={`No results have been recorded for \"${activeCompetition}\". Record a fixture result to build the table.`}\n />\n ) : (\n <EmphasisPanel className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[640px] text-sm\">\n <thead>\n <tr className=\"border-b border-border-seam text-left text-xs uppercase tracking-wide text-text-secondary\">\n <th className=\"px-3 py-2 font-medium\">#</th>\n <th className=\"px-3 py-2 font-medium\">Team</th>\n <th className=\"px-3 py-2 text-center font-medium\">P</th>\n <th className=\"px-3 py-2 text-center font-medium\">W</th>\n <th className=\"px-3 py-2 text-center font-medium\">D</th>\n <th className=\"px-3 py-2 text-center font-medium\">L</th>\n <th className=\"px-3 py-2 text-center font-medium\">GF</th>\n <th className=\"px-3 py-2 text-center font-medium\">GA</th>\n <th className=\"px-3 py-2 text-center font-medium\">GD</th>\n <th className=\"px-3 py-2 text-center font-semibold text-text-primary\">Pts</th>\n </tr>\n </thead>\n <tbody>\n {rows.map((row, idx) => {\n const rank = row.rank ?? idx + 1;\n const isLeader = rank === 1;\n const gd = row.goalsFor - row.goalsAgainst;\n const teamName = row.team?.name ?? 'Unknown team';\n return (\n <tr\n key={row.id}\n className={cn(\n 'border-b border-border-seam/60 last:border-0 hover:bg-bg-sunken/50',\n isLeader && 'bg-[var(--color-accent-soft)]/40'\n )}\n >\n <td className=\"py-2.5 pl-0 pr-3\">\n <span className=\"flex items-center\">\n <span\n aria-hidden=\"true\"\n className={cn(\n 'mr-2 h-6 w-1 rounded-full',\n isLeader ? 'bg-action-primary-bg' : 'bg-transparent'\n )}\n />\n <span\n className={cn(\n 'tabular-nums',\n isLeader ? 'font-bold text-text-primary' : 'text-text-secondary'\n )}\n >\n {rank}\n </span>\n </span>\n </td>\n <td className=\"px-3 py-2.5\">\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <Crest name={teamName} sport={row.team?.sport} size={26} />\n <span className=\"truncate font-medium text-text-primary\">{teamName}</span>\n </span>\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.played}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.won}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.drawn}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.lost}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.goalsFor}\n </td>\n <td className=\"px-3 py-2.5 text-center tabular-nums text-text-secondary\">\n {row.goalsAgainst}\n </td>\n <td\n className={cn(\n 'px-3 py-2.5 text-center font-medium tabular-nums',\n gd > 0\n ? 'text-status-success-text'\n : gd < 0\n ? 'text-status-error-text'\n : 'text-text-secondary'\n )}\n >\n {gd > 0 ? `+${gd}` : gd}\n </td>\n <td\n className={cn(\n 'px-3 py-2.5 text-center font-bold tabular-nums',\n isLeader ? 'text-primary' : 'text-text-primary'\n )}\n >\n {row.points}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </EmphasisPanel>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAsBA,SAAgB,IAAgB;CAC9B,IAAM,IAAK,GAAgB,EACrB,CAAC,KAAgB,GAAiB,EAClC,IAAqB,EAAa,IAAI,cAAc,IAAI,IAExD,CAAC,GAAa,KAAkB,EAAS,EAAmB,EAC5D,CAAC,GAAmB,KAAwB,EAAS,EAAmB,EAGxE,IAAW,EAAY,EAAE,YAAY,EAAE,OAAO,KAAK,EAAE,CAAC,EACtD,IAAe,QAAc;EACjC,IAAM,oBAAM,IAAI,KAAa;AAC7B,OAAK,IAAM,KAAK,EAAS,MAAM,SAAS,EAAE,CACxC,CAAI,EAAE,eAAa,EAAI,IAAI,EAAE,YAAY;AAE3C,SAAO,MAAM,KAAK,EAAI,CAAC,MAAM;IAC5B,CAAC,EAAS,KAAK,CAAC;AAGnB,SAAgB;AACd,EAAI,CAAC,KAAqB,EAAa,SAAS,MAC9C,EAAe,EAAa,GAAG,EAC/B,EAAqB,EAAa,GAAG;IAEtC,CAAC,GAAmB,EAAa,CAAC;CAErC,IAAM,IAAY,EAAa,KAAqB,KAAA,EAAU,EACxD,IAAO,QAEJ,CAAC,GADM,EAAU,QAAQ,EAAE,CACjB,CAAC,MAAM,GAAG,MACrB,EAAE,WAAW,EAAE,SACZ,EAAE,WAAW,EAAE,WADY,EAAE,SAAS,EAAE,OAE/C,EACD,CAAC,EAAU,KAAK,CAAC;AAOpB,QACE,kBAAC,GAAD;EACE,OAAO,EAAG,wCAAwC,YAAY;EAC9D,aAAa,EACX,8CACA,mEACD;YALH,CAOE,kBAAC,QAAD;GACE,WAdgB,MAAuB;AAE3C,IADA,EAAE,gBAAgB,EAClB,EAAqB,EAAY,MAAM,CAAC;;GAapC,aAAU;GACV,WAAU;aAHZ,CAKE,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,SAAD;MACE,SAAQ;MACR,WAAU;gBAET,EAAG,mDAAmD,cAAc;MAC/D,CAAA;KACR,kBAAC,SAAD;MACE,IAAG;MACH,MAAK;MACL,WAAW;MACX,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;MAC/C,aAAa,EACX,yDACA,0BACD;MACD,CAAA;KACF,kBAAC,YAAD;MAAU,IAAG;gBACV,EAAa,KAAK,MACjB,kBAAC,UAAD,EAAgB,OAAO,GAAK,EAAf,EAAe,CAC5B;MACO,CAAA;KACP;OACN,kBAAC,UAAD;IACE,MAAK;IACL,WAAU;cAFZ;KAIE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;KAAC;KAC9B,EAAG,4CAA4C,aAAa;KACtD;MACJ;MAEL,IAUE,EAAU,YACZ,kBAAC,GAAD,EAAc,OAAO,EAAG,0CAA0C,qBAAqB,EAAI,CAAA,GACzF,EAAU,UACZ,kBAAC,GAAD,EAAY,eAAe,KAAK,EAAU,SAAS,EAAI,CAAA,GACrD,EAAK,WAAW,IAClB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;GACtC,OAAO,EAAG,wCAAwC,mBAAmB;GACrE,aAAa,sCAAsC,EAAkB;GACrE,CAAA,GAEF,kBAAC,GAAD;GAAe,WAAU;aACvB,kBAAC,SAAD;IAAO,WAAU;cAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;KAAI,WAAU;eAAd;MACE,kBAAC,MAAD;OAAI,WAAU;iBAAwB;OAAM,CAAA;MAC5C,kBAAC,MAAD;OAAI,WAAU;iBAAwB;OAAS,CAAA;MAC/C,kBAAC,MAAD;OAAI,WAAU;iBAAoC;OAAM,CAAA;MACxD,kBAAC,MAAD;OAAI,WAAU;iBAAoC;OAAM,CAAA;MACxD,kBAAC,MAAD;OAAI,WAAU;iBAAoC;OAAM,CAAA;MACxD,kBAAC,MAAD;OAAI,WAAU;iBAAoC;OAAM,CAAA;MACxD,kBAAC,MAAD;OAAI,WAAU;iBAAoC;OAAO,CAAA;MACzD,kBAAC,MAAD;OAAI,WAAU;iBAAoC;OAAO,CAAA;MACzD,kBAAC,MAAD;OAAI,WAAU;iBAAoC;OAAO,CAAA;MACzD,kBAAC,MAAD;OAAI,WAAU;iBAAwD;OAAQ,CAAA;MAC3E;QACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAK,KAAK,GAAK,MAAQ;KACtB,IAAM,IAAO,EAAI,QAAQ,IAAM,GACzB,IAAW,MAAS,GACpB,IAAK,EAAI,WAAW,EAAI,cACxB,IAAW,EAAI,MAAM,QAAQ;AACnC,YACE,kBAAC,MAAD;MAEE,WAAW,EACT,sEACA,KAAY,mCACb;gBALH;OAOE,kBAAC,MAAD;QAAI,WAAU;kBACZ,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACE,kBAAC,QAAD;UACE,eAAY;UACZ,WAAW,EACT,6BACA,IAAW,yBAAyB,iBACrC;UACD,CAAA,EACF,kBAAC,QAAD;UACE,WAAW,EACT,gBACA,IAAW,gCAAgC,sBAC5C;oBAEA;UACI,CAAA,CACF;;QACJ,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACZ,kBAAC,QAAD;SAAM,WAAU;mBAAhB,CACE,kBAAC,GAAD;UAAO,MAAM;UAAU,OAAO,EAAI,MAAM;UAAO,MAAM;UAAM,CAAA,EAC3D,kBAAC,QAAD;UAAM,WAAU;oBAA0C;UAAgB,CAAA,CACrE;;QACJ,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAI;QACF,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAI;QACF,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAI;QACF,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAI;QACF,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAI;QACF,CAAA;OACL,kBAAC,MAAD;QAAI,WAAU;kBACX,EAAI;QACF,CAAA;OACL,kBAAC,MAAD;QACE,WAAW,EACT,oDACA,IAAK,IACD,6BACA,IAAK,IACH,2BACA,sBACP;kBAEA,IAAK,IAAI,IAAI,MAAO;QAClB,CAAA;OACL,kBAAC,MAAD;QACE,WAAW,EACT,kDACA,IAAW,iBAAiB,oBAC7B;kBAEA,EAAI;QACF,CAAA;OACF;QArEE,EAAI,GAqEN;MAEP,EACI,CAAA,CACF;;GACM,CAAA,GAvHhB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAQ,WAAU,aAAc,CAAA;GACtC,OAAO,EAAG,kDAAkD,qBAAqB;GACjF,aAAa,EACX,sDACA,6HACD;GACD,CAAA,CAiHO"}
@@ -1 +1 @@
1
- {"version":3,"file":"FixturesListPage.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/pages/fixtures/FixturesListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6BH,wBAAgB,gBAAgB,gCA+H/B"}
1
+ {"version":3,"file":"FixturesListPage.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/pages/fixtures/FixturesListPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6BH,wBAAgB,gBAAgB,gCAgI/B"}
@@ -4,9 +4,9 @@ import { FIXTURE_TYPE_LABELS as n, FIXTURE_TYPE_OPTIONS as r } from "../../compo
4
4
  import { EmptyState as i } from "../../components/EmptyState.js";
5
5
  import { ErrorState as a, LoadingState as o } from "../../components/LoadingState.js";
6
6
  import { useFixtures as s, useTeams as c } from "../../hooks/useAthleteBridgeApi.js";
7
- import { FixtureCard as l } from "../../components/FixtureCard.js";
7
+ import { CursorPager as l } from "../../components/CursorPager.js";
8
8
  import { FilterSelect as u } from "../../components/FilterSelect.js";
9
- import { CursorPager as d } from "../../components/CursorPager.js";
9
+ import { FixtureCard as d } from "../../components/FixtureCard.js";
10
10
  import { useMemo as f, useState as p } from "react";
11
11
  import { CalendarDays as m, Plus as h, Trophy as g } from "lucide-react";
12
12
  import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
@@ -63,12 +63,14 @@ function C() {
63
63
  children: [/* @__PURE__ */ v(g, { className: "h-4 w-4" }), " Tournament bracket"]
64
64
  }), /* @__PURE__ */ y("button", {
65
65
  type: "button",
66
+ "data-tour": "fixtures-create",
66
67
  onClick: () => n("/fixtures/new"),
67
68
  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",
68
69
  children: [/* @__PURE__ */ v(h, { className: "h-4 w-4" }), " Schedule fixture"]
69
70
  })]
70
71
  }),
71
72
  children: [/* @__PURE__ */ y("div", {
73
+ "data-tour": "fixtures-filters",
72
74
  className: "mb-6 flex flex-wrap items-center gap-3",
73
75
  children: [
74
76
  /* @__PURE__ */ v(u, {
@@ -110,11 +112,11 @@ function C() {
110
112
  })
111
113
  }) : /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v("div", {
112
114
  className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",
113
- children: N.map((e) => /* @__PURE__ */ v(l, {
115
+ children: N.map((e) => /* @__PURE__ */ v(d, {
114
116
  fixture: e,
115
117
  onClick: () => n(`/fixtures/${e.id}`)
116
118
  }, e.id))
117
- }), /* @__PURE__ */ v(d, {
119
+ }), /* @__PURE__ */ v(l, {
118
120
  className: "mt-6",
119
121
  page: O,
120
122
  hasMore: P,
@@ -1 +1 @@
1
- {"version":3,"file":"FixturesListPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/fixtures/FixturesListPage.tsx"],"sourcesContent":["/**\n * Fixtures List\n * @module atheletebridge/pages/fixtures\n *\n * Crest-vs-crest FixtureCard grid with status, team and type filters. The team\n * filter is server-backed (athListFixtures accepts teamId); the type filter is\n * applied over the loaded page. A \"Tournament bracket\" shortcut links to the\n * tournaments view. Semantic tokens only, responsive.\n */\n\nimport { useMemo, useState } from 'react';\nimport { CalendarDays, Plus, Trophy } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { FixtureCard } from '../../components/FixtureCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FilterSelect } from '../../components/FilterSelect';\nimport { CursorPager } from '../../components/CursorPager';\nimport { FIXTURE_TYPE_LABELS, FIXTURE_TYPE_OPTIONS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useFixtures, useTeams } from '../../hooks/useAthleteBridgeApi';\nimport type { AthFixtureStatus, AthFixtureType } from '../../types';\n\nconst PAGE_SIZE = 12;\n\nconst STATUS_OPTS: ReadonlyArray<{ value: AthFixtureStatus; label: string }> = [\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'LIVE', label: 'Live' },\n { value: 'COMPLETED', label: 'Completed' },\n { value: 'POSTPONED', label: 'Postponed' },\n { value: 'CANCELLED', label: 'Cancelled' },\n];\n\nconst TYPE_OPTS: ReadonlyArray<{ value: AthFixtureType; label: string }> = FIXTURE_TYPE_OPTIONS.map(\n (t) => ({ value: t, label: FIXTURE_TYPE_LABELS[t] })\n);\n\nexport function FixturesListPage() {\n const { navigateTo } = useAthleteBridge();\n const [status, setStatus] = useState<AthFixtureStatus | ''>('');\n const [teamId, setTeamId] = useState<string>('');\n const [type, setType] = useState<AthFixtureType | ''>('');\n const [page, setPage] = useState(0);\n\n const teams = useTeams({ pagination: { limit: 100 } });\n const teamOpts = useMemo(\n () => (teams.data?.items ?? []).map((t) => ({ value: t.id, label: t.name })),\n [teams.data]\n );\n\n const fixtures = useFixtures({\n status: status || undefined,\n teamId: teamId || undefined,\n pagination: { limit: PAGE_SIZE, offset: page * PAGE_SIZE },\n });\n\n const items = useMemo(() => {\n const raw = fixtures.data?.items ?? [];\n return type ? raw.filter((f) => f.type === type) : raw;\n }, [fixtures.data, type]);\n const hasMore = fixtures.data?.pageInfo.hasMore ?? false;\n const hasFilters = Boolean(status || teamId || type);\n\n const resetPage = () => setPage(0);\n\n return (\n <PageLayout\n title=\"Fixtures\"\n description=\"Matches across friendlies, league games, cups, tournaments and scrimmages.\"\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/tournaments')}\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\" /> Tournament bracket\n </button>\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures/new')}\n 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\"\n >\n <Plus className=\"h-4 w-4\" /> Schedule fixture\n </button>\n </div>\n }\n >\n <div className=\"mb-6 flex flex-wrap items-center gap-3\">\n <FilterSelect\n ariaLabel=\"Filter by status\"\n allLabel=\"All statuses\"\n value={status}\n onChange={(v) => {\n setStatus(v);\n resetPage();\n }}\n options={STATUS_OPTS}\n />\n <FilterSelect\n ariaLabel=\"Filter by team\"\n allLabel=\"All teams\"\n value={teamId}\n onChange={(v) => {\n setTeamId(v);\n resetPage();\n }}\n options={teamOpts}\n />\n <FilterSelect\n ariaLabel=\"Filter by type\"\n allLabel=\"All types\"\n value={type}\n onChange={(v) => setType(v)}\n options={TYPE_OPTS}\n />\n </div>\n\n {fixtures.isLoading ? (\n <LoadingState label=\"Loading fixtures…\" />\n ) : fixtures.isError ? (\n <ErrorState onRetry={() => void fixtures.refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<CalendarDays className=\"h-10 w-10\" />}\n title=\"No fixtures found\"\n description={\n hasFilters\n ? 'Try clearing your filters to see all fixtures.'\n : 'Schedule a match to start tracking results and standings.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures/new')}\n 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\"\n >\n Schedule fixture\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {items.map((fixture) => (\n <FixtureCard\n key={fixture.id}\n fixture={fixture}\n onClick={() => navigateTo(`/fixtures/${fixture.id}`)}\n />\n ))}\n </div>\n <CursorPager\n className=\"mt-6\"\n page={page}\n hasMore={hasMore}\n onPrev={() => setPage((p) => Math.max(0, p - 1))}\n onNext={() => setPage((p) => p + 1)}\n />\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"FixturesListPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/fixtures/FixturesListPage.tsx"],"sourcesContent":["/**\n * Fixtures List\n * @module atheletebridge/pages/fixtures\n *\n * Crest-vs-crest FixtureCard grid with status, team and type filters. The team\n * filter is server-backed (athListFixtures accepts teamId); the type filter is\n * applied over the loaded page. A \"Tournament bracket\" shortcut links to the\n * tournaments view. Semantic tokens only, responsive.\n */\n\nimport { useMemo, useState } from 'react';\nimport { CalendarDays, Plus, Trophy } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { FixtureCard } from '../../components/FixtureCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FilterSelect } from '../../components/FilterSelect';\nimport { CursorPager } from '../../components/CursorPager';\nimport { FIXTURE_TYPE_LABELS, FIXTURE_TYPE_OPTIONS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useFixtures, useTeams } from '../../hooks/useAthleteBridgeApi';\nimport type { AthFixtureStatus, AthFixtureType } from '../../types';\n\nconst PAGE_SIZE = 12;\n\nconst STATUS_OPTS: ReadonlyArray<{ value: AthFixtureStatus; label: string }> = [\n { value: 'SCHEDULED', label: 'Scheduled' },\n { value: 'LIVE', label: 'Live' },\n { value: 'COMPLETED', label: 'Completed' },\n { value: 'POSTPONED', label: 'Postponed' },\n { value: 'CANCELLED', label: 'Cancelled' },\n];\n\nconst TYPE_OPTS: ReadonlyArray<{ value: AthFixtureType; label: string }> = FIXTURE_TYPE_OPTIONS.map(\n (t) => ({ value: t, label: FIXTURE_TYPE_LABELS[t] })\n);\n\nexport function FixturesListPage() {\n const { navigateTo } = useAthleteBridge();\n const [status, setStatus] = useState<AthFixtureStatus | ''>('');\n const [teamId, setTeamId] = useState<string>('');\n const [type, setType] = useState<AthFixtureType | ''>('');\n const [page, setPage] = useState(0);\n\n const teams = useTeams({ pagination: { limit: 100 } });\n const teamOpts = useMemo(\n () => (teams.data?.items ?? []).map((t) => ({ value: t.id, label: t.name })),\n [teams.data]\n );\n\n const fixtures = useFixtures({\n status: status || undefined,\n teamId: teamId || undefined,\n pagination: { limit: PAGE_SIZE, offset: page * PAGE_SIZE },\n });\n\n const items = useMemo(() => {\n const raw = fixtures.data?.items ?? [];\n return type ? raw.filter((f) => f.type === type) : raw;\n }, [fixtures.data, type]);\n const hasMore = fixtures.data?.pageInfo.hasMore ?? false;\n const hasFilters = Boolean(status || teamId || type);\n\n const resetPage = () => setPage(0);\n\n return (\n <PageLayout\n title=\"Fixtures\"\n description=\"Matches across friendlies, league games, cups, tournaments and scrimmages.\"\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/tournaments')}\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\" /> Tournament bracket\n </button>\n <button\n type=\"button\"\n data-tour=\"fixtures-create\"\n onClick={() => navigateTo('/fixtures/new')}\n 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\"\n >\n <Plus className=\"h-4 w-4\" /> Schedule fixture\n </button>\n </div>\n }\n >\n <div data-tour=\"fixtures-filters\" className=\"mb-6 flex flex-wrap items-center gap-3\">\n <FilterSelect\n ariaLabel=\"Filter by status\"\n allLabel=\"All statuses\"\n value={status}\n onChange={(v) => {\n setStatus(v);\n resetPage();\n }}\n options={STATUS_OPTS}\n />\n <FilterSelect\n ariaLabel=\"Filter by team\"\n allLabel=\"All teams\"\n value={teamId}\n onChange={(v) => {\n setTeamId(v);\n resetPage();\n }}\n options={teamOpts}\n />\n <FilterSelect\n ariaLabel=\"Filter by type\"\n allLabel=\"All types\"\n value={type}\n onChange={(v) => setType(v)}\n options={TYPE_OPTS}\n />\n </div>\n\n {fixtures.isLoading ? (\n <LoadingState label=\"Loading fixtures…\" />\n ) : fixtures.isError ? (\n <ErrorState onRetry={() => void fixtures.refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<CalendarDays className=\"h-10 w-10\" />}\n title=\"No fixtures found\"\n description={\n hasFilters\n ? 'Try clearing your filters to see all fixtures.'\n : 'Schedule a match to start tracking results and standings.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures/new')}\n 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\"\n >\n Schedule fixture\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {items.map((fixture) => (\n <FixtureCard\n key={fixture.id}\n fixture={fixture}\n onClick={() => navigateTo(`/fixtures/${fixture.id}`)}\n />\n ))}\n </div>\n <CursorPager\n className=\"mt-6\"\n page={page}\n hasMore={hasMore}\n onPrev={() => setPage((p) => Math.max(0, p - 1))}\n onNext={() => setPage((p) => p + 1)}\n />\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAM,IAAY,IAEZ,IAAyE;CAC7E;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAQ,OAAO;EAAQ;CAChC;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAa,OAAO;EAAa;CAC3C,EAEK,IAAqE,EAAqB,KAC7F,OAAO;CAAE,OAAO;CAAG,OAAO,EAAoB;CAAI,EACpD;AAED,SAAgB,IAAmB;CACjC,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAQ,KAAa,EAAgC,GAAG,EACzD,CAAC,GAAQ,KAAa,EAAiB,GAAG,EAC1C,CAAC,GAAM,KAAW,EAA8B,GAAG,EACnD,CAAC,GAAM,KAAW,EAAS,EAAE,EAE7B,IAAQ,EAAS,EAAE,YAAY,EAAE,OAAO,KAAK,EAAE,CAAC,EAChD,IAAW,SACR,EAAM,MAAM,SAAS,EAAE,EAAE,KAAK,OAAO;EAAE,OAAO,EAAE;EAAI,OAAO,EAAE;EAAM,EAAE,EAC5E,CAAC,EAAM,KAAK,CACb,EAEK,IAAW,EAAY;EAC3B,QAAQ,KAAU,KAAA;EAClB,QAAQ,KAAU,KAAA;EAClB,YAAY;GAAE,OAAO;GAAW,QAAQ,IAAO;GAAW;EAC3D,CAAC,EAEI,IAAQ,QAAc;EAC1B,IAAM,IAAM,EAAS,MAAM,SAAS,EAAE;AACtC,SAAO,IAAO,EAAI,QAAQ,MAAM,EAAE,SAAS,EAAK,GAAG;IAClD,CAAC,EAAS,MAAM,EAAK,CAAC,EACnB,IAAU,EAAS,MAAM,SAAS,WAAW,IAC7C,IAAa,GAAQ,KAAU,KAAU,IAEzC,UAAkB,EAAQ,EAAE;AAElC,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,eAAe;IACzC,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAAA,sBACvB;OACT,kBAAC,UAAD;IACE,MAAK;IACL,aAAU;IACV,eAAe,EAAW,gBAAgB;IAC1C,WAAU;cAJZ,CAME,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,oBACrB;MACL;;YApBV,CAuBE,kBAAC,OAAD;GAAK,aAAU;GAAmB,WAAU;aAA5C;IACE,kBAAC,GAAD;KACE,WAAU;KACV,UAAS;KACT,OAAO;KACP,WAAW,MAAM;AAEf,MADA,EAAU,EAAE,EACZ,GAAW;;KAEb,SAAS;KACT,CAAA;IACF,kBAAC,GAAD;KACE,WAAU;KACV,UAAS;KACT,OAAO;KACP,WAAW,MAAM;AAEf,MADA,EAAU,EAAE,EACZ,GAAW;;KAEb,SAAS;KACT,CAAA;IACF,kBAAC,GAAD;KACE,WAAU;KACV,UAAS;KACT,OAAO;KACP,WAAW,MAAM,EAAQ,EAAE;KAC3B,SAAS;KACT,CAAA;IACE;MAEL,EAAS,YACR,kBAAC,GAAD,EAAc,OAAM,qBAAsB,CAAA,GACxC,EAAS,UACX,kBAAC,GAAD,EAAY,eAAe,KAAK,EAAS,SAAS,EAAI,CAAA,GACpD,EAAM,WAAW,IACnB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAc,WAAU,aAAc,CAAA;GAC5C,OAAM;GACN,aACE,IACI,mDACA;GAEN,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,gBAAgB;IAC1C,WAAU;cACX;IAEQ,CAAA;GAEX,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,GAAD;IAEW;IACT,eAAe,EAAW,aAAa,EAAQ,KAAK;IACpD,EAHK,EAAQ,GAGb,CACF;GACE,CAAA,EACN,kBAAC,GAAD;GACE,WAAU;GACJ;GACG;GACT,cAAc,GAAS,MAAM,KAAK,IAAI,GAAG,IAAI,EAAE,CAAC;GAChD,cAAc,GAAS,MAAM,IAAI,EAAE;GACnC,CAAA,CACD,EAAA,CAAA,CAEM"}
@@ -0,0 +1,4 @@
1
+ import { FC } from 'react';
2
+
3
+ export declare const OnboardingPage: FC;
4
+ //# sourceMappingURL=OnboardingPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OnboardingPage.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/pages/onboarding/OnboardingPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAkC,KAAK,EAAE,EAAkB,MAAM,OAAO,CAAC;AAwNhF,eAAO,MAAM,cAAc,EAAE,EAoT5B,CAAC"}