@burdenoff/microfe-atheletebridge 2026.705.2 → 2026.706.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.js +55 -39
  2. package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
  3. package/dist/atheletebridge/AthleteBridgeRoutes.js +18 -6
  4. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  5. package/dist/atheletebridge/components/Crest.js +70 -0
  6. package/dist/atheletebridge/components/Crest.js.map +1 -0
  7. package/dist/atheletebridge/components/FixtureCard.js +8 -72
  8. package/dist/atheletebridge/components/FixtureCard.js.map +1 -1
  9. package/dist/atheletebridge/components/MatchupRow.js +74 -0
  10. package/dist/atheletebridge/components/MatchupRow.js.map +1 -0
  11. package/dist/atheletebridge/components/MetricsCard.js +61 -21
  12. package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
  13. package/dist/atheletebridge/components/ProgramCard.js +75 -43
  14. package/dist/atheletebridge/components/ProgramCard.js.map +1 -1
  15. package/dist/atheletebridge/components/Scoreboard.js +163 -0
  16. package/dist/atheletebridge/components/Scoreboard.js.map +1 -0
  17. package/dist/atheletebridge/components/SessionCard.js +64 -41
  18. package/dist/atheletebridge/components/SessionCard.js.map +1 -1
  19. package/dist/atheletebridge/components/SessionStatusTimeline.js +80 -0
  20. package/dist/atheletebridge/components/SessionStatusTimeline.js.map +1 -0
  21. package/dist/atheletebridge/components/StatusBadge.js +5 -5
  22. package/dist/atheletebridge/components/StatusBadge.js.map +1 -1
  23. package/dist/atheletebridge/components/TeamCard.js +65 -35
  24. package/dist/atheletebridge/components/TeamCard.js.map +1 -1
  25. package/dist/atheletebridge/components/UserAvatar.js +33 -0
  26. package/dist/atheletebridge/components/UserAvatar.js.map +1 -0
  27. package/dist/atheletebridge/components/domain.js +5 -2
  28. package/dist/atheletebridge/components/domain.js.map +1 -1
  29. package/dist/atheletebridge/components/viz/AvatarStack.js +2 -0
  30. package/dist/atheletebridge/components/viz/BarChart.js +83 -0
  31. package/dist/atheletebridge/components/viz/BarChart.js.map +1 -0
  32. package/dist/atheletebridge/components/viz/DonutChart.js +109 -0
  33. package/dist/atheletebridge/components/viz/DonutChart.js.map +1 -0
  34. package/dist/atheletebridge/components/viz/LineChart.js +123 -0
  35. package/dist/atheletebridge/components/viz/LineChart.js.map +1 -0
  36. package/dist/atheletebridge/components/viz/ProgressRing.js +6 -0
  37. package/dist/atheletebridge/components/viz/ProgressRing.js.map +1 -0
  38. package/dist/atheletebridge/components/viz/RatingStars.js +92 -0
  39. package/dist/atheletebridge/components/viz/RatingStars.js.map +1 -0
  40. package/dist/atheletebridge/components/viz/Sparkline.js +74 -0
  41. package/dist/atheletebridge/components/viz/Sparkline.js.map +1 -0
  42. package/dist/atheletebridge/components/viz/StatCard.js +60 -0
  43. package/dist/atheletebridge/components/viz/StatCard.js.map +1 -0
  44. package/dist/atheletebridge/components/viz/StepProgress.js +3 -0
  45. package/dist/atheletebridge/components/viz/Timeline.js +66 -0
  46. package/dist/atheletebridge/components/viz/Timeline.js.map +1 -0
  47. package/dist/atheletebridge/components/viz/index.js +13 -0
  48. package/dist/atheletebridge/components/viz/lib/Avatar.js +1 -0
  49. package/dist/atheletebridge/components/viz/lib/CartesianFrame.js +119 -0
  50. package/dist/atheletebridge/components/viz/lib/CartesianFrame.js.map +1 -0
  51. package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.js +35 -0
  52. package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.js.map +1 -0
  53. package/dist/atheletebridge/components/viz/lib/format.js +17 -0
  54. package/dist/atheletebridge/components/viz/lib/format.js.map +1 -0
  55. package/dist/atheletebridge/components/viz/lib/geometry.js +61 -0
  56. package/dist/atheletebridge/components/viz/lib/geometry.js.map +1 -0
  57. package/dist/atheletebridge/components/viz/lib/hooks.js +39 -0
  58. package/dist/atheletebridge/components/viz/lib/hooks.js.map +1 -0
  59. package/dist/atheletebridge/components/viz/lib/palette.js +27 -0
  60. package/dist/atheletebridge/components/viz/lib/palette.js.map +1 -0
  61. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +369 -163
  62. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  63. package/dist/atheletebridge/pages/DashboardPage.js +182 -117
  64. package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
  65. package/dist/atheletebridge/pages/StandingsPage.js +119 -95
  66. package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
  67. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js +372 -0
  68. package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js.map +1 -0
  69. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js +511 -0
  70. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js.map +1 -0
  71. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +120 -131
  72. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -1
  73. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js +264 -176
  74. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js.map +1 -1
  75. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js +84 -47
  76. package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -1
  77. package/dist/atheletebridge/pages/performance/PerformancePage.js +432 -281
  78. package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -1
  79. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +187 -123
  80. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  81. package/dist/atheletebridge/pages/programs/ProgramsListPage.js +56 -39
  82. package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -1
  83. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +267 -139
  84. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
  85. package/dist/atheletebridge/pages/sessions/SessionFormPage.js +253 -162
  86. package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -1
  87. package/dist/atheletebridge/pages/sessions/SessionsListPage.js +38 -36
  88. package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -1
  89. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +437 -189
  90. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  91. package/dist/atheletebridge/pages/teams/TeamFormPage.js +368 -177
  92. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
  93. package/dist/atheletebridge/pages/teams/TeamsListPage.js +3 -0
  94. package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
  95. package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.js +298 -0
  96. package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.js.map +1 -0
  97. package/dist/atheletebridge/utils/identity.js +31 -0
  98. package/dist/atheletebridge/utils/identity.js.map +1 -0
  99. package/dist/atheletebridge/utils/timeAgo.js +20 -0
  100. package/dist/atheletebridge/utils/timeAgo.js.map +1 -0
  101. package/package.json +1 -1
@@ -1,20 +1,141 @@
1
1
  import { useAthleteBridge as e } from "../../context/AthleteBridgeContext.js";
2
2
  import { PageLayout as t } from "../../components/PageLayout.js";
3
- import { SPORT_LABELS as n } from "../../components/domain.js";
4
- import { ErrorState as r, LoadingState as i } from "../../components/LoadingState.js";
5
- import { useCreateTeam as a, useTeam as o, useUpdateTeam as s } from "../../hooks/useAthleteBridgeApi.js";
6
- import { FormField as c, fieldInputClass as l } from "../../components/form.js";
7
- import { useEffect as u, useState as d } from "react";
8
- import { ArrowLeft as f, Loader2 as p, Save as m } from "lucide-react";
9
- import { useParams as h } from "react-router-dom";
10
- import { jsx as g, jsxs as _ } from "react/jsx-runtime";
3
+ import { SPORT_ICONS as n, SPORT_LABELS as r } from "../../components/domain.js";
4
+ import { UserAvatar as i } from "../../components/UserAvatar.js";
5
+ import { ErrorState as a, LoadingState as o } from "../../components/LoadingState.js";
6
+ import { directoryUserName as s, useCreateTeam as c, useTeam as l, useUpdateTeam as u, useUserDirectory as d, useUserSearch as f } from "../../hooks/useAthleteBridgeApi.js";
7
+ import { FormField as p, fieldInputClass as m } from "../../components/form.js";
8
+ import { useEffect as h, useState as g } from "react";
9
+ import { ArrowLeft as _, CalendarDays as v, Loader2 as y, MapPin as b, Save as x, Search as S, X as C } from "lucide-react";
10
+ import { useParams as w } from "react-router-dom";
11
+ import { jsx as T, jsxs as E } from "react/jsx-runtime";
12
+ import { GlassCard as D } from "@burdenoff/fe-libs/ui";
11
13
  //#region src/atheletebridge/pages/teams/TeamFormPage.tsx
12
- var v = Object.keys(n), y = [
14
+ var O = Object.keys(r), k = [
13
15
  "FORMING",
14
16
  "ACTIVE",
15
17
  "INACTIVE",
16
18
  "ARCHIVED"
17
- ], b = {
19
+ ], A = 300;
20
+ function j({ sport: e }) {
21
+ let t = n[e];
22
+ return /* @__PURE__ */ T(t, {
23
+ className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted",
24
+ "aria-hidden": "true"
25
+ });
26
+ }
27
+ function M({ userId: e, displayName: t, onSelect: n }) {
28
+ let [r, a] = g(""), o = f(r), c = o.data ?? [], l = r.trim().length >= 2, u = o.isError;
29
+ return e ? /* @__PURE__ */ T(p, {
30
+ label: "Head coach",
31
+ hint: "Optional — the coach who leads this squad.",
32
+ children: /* @__PURE__ */ E("div", {
33
+ className: "flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-surface px-3 py-2",
34
+ children: [
35
+ /* @__PURE__ */ T(i, {
36
+ name: t,
37
+ id: e,
38
+ size: "sm"
39
+ }),
40
+ /* @__PURE__ */ E("div", {
41
+ className: "min-w-0 flex-1",
42
+ children: [/* @__PURE__ */ T("p", {
43
+ className: "truncate text-sm font-medium text-text-primary",
44
+ children: t || "Selected coach"
45
+ }), /* @__PURE__ */ T("p", {
46
+ className: "truncate text-xs text-text-secondary",
47
+ children: e
48
+ })]
49
+ }),
50
+ /* @__PURE__ */ T("button", {
51
+ type: "button",
52
+ "aria-label": "Clear head coach",
53
+ onClick: () => n({
54
+ userId: "",
55
+ displayName: ""
56
+ }),
57
+ className: "rounded-md p-1 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary",
58
+ children: /* @__PURE__ */ T(C, { className: "h-4 w-4" })
59
+ })
60
+ ]
61
+ })
62
+ }) : u ? /* @__PURE__ */ T(p, {
63
+ label: "Head coach",
64
+ htmlFor: "headCoachId",
65
+ hint: "Optional — directory unavailable here; paste the auth-svc user id.",
66
+ children: /* @__PURE__ */ T("input", {
67
+ id: "headCoachId",
68
+ className: m,
69
+ value: e,
70
+ onChange: (e) => n({
71
+ userId: e.target.value,
72
+ displayName: t
73
+ }),
74
+ placeholder: "user-uuid"
75
+ })
76
+ }) : /* @__PURE__ */ T(p, {
77
+ label: "Head coach",
78
+ hint: "Optional — the coach who leads this squad.",
79
+ children: /* @__PURE__ */ E("div", {
80
+ className: "space-y-2",
81
+ children: [
82
+ /* @__PURE__ */ E("div", {
83
+ className: "relative",
84
+ children: [
85
+ /* @__PURE__ */ T(S, {
86
+ className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted",
87
+ "aria-hidden": "true"
88
+ }),
89
+ /* @__PURE__ */ T("input", {
90
+ className: `${m} pl-9`,
91
+ value: r,
92
+ onChange: (e) => a(e.target.value),
93
+ placeholder: "Search coaches by name or email…",
94
+ "aria-label": "Search for a head coach"
95
+ }),
96
+ o.isFetching && /* @__PURE__ */ T(y, { className: "absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-text-muted" })
97
+ ]
98
+ }),
99
+ l && !o.isFetching && c.length === 0 && /* @__PURE__ */ E("p", {
100
+ className: "text-xs text-text-secondary",
101
+ children: [
102
+ "No users match “",
103
+ r.trim(),
104
+ "”."
105
+ ]
106
+ }),
107
+ c.length > 0 && /* @__PURE__ */ T("ul", {
108
+ className: "max-h-56 divide-y divide-border-seam overflow-auto rounded-lg border border-border-seam bg-bg-surface",
109
+ children: c.map((e) => /* @__PURE__ */ T("li", { children: /* @__PURE__ */ E("button", {
110
+ type: "button",
111
+ onClick: () => {
112
+ n({
113
+ userId: e.id,
114
+ displayName: s(e)
115
+ }), a("");
116
+ },
117
+ className: "flex w-full items-center gap-2.5 px-3 py-2 text-left transition-colors hover:bg-bg-sunken",
118
+ children: [/* @__PURE__ */ T(i, {
119
+ name: s(e),
120
+ id: e.id,
121
+ size: "sm"
122
+ }), /* @__PURE__ */ E("span", {
123
+ className: "min-w-0 flex-1",
124
+ children: [/* @__PURE__ */ T("span", {
125
+ className: "block truncate text-sm font-medium text-text-primary",
126
+ children: s(e)
127
+ }), /* @__PURE__ */ T("span", {
128
+ className: "block truncate text-xs text-text-secondary",
129
+ children: e.email
130
+ })]
131
+ })]
132
+ }) }, e.id))
133
+ })
134
+ ]
135
+ })
136
+ });
137
+ }
138
+ var N = {
18
139
  name: "",
19
140
  sport: "OTHER",
20
141
  status: "FORMING",
@@ -22,13 +143,15 @@ var v = Object.keys(n), y = [
22
143
  ageGroup: "",
23
144
  season: "",
24
145
  homeVenue: "",
25
- tagsText: ""
146
+ headCoachId: "",
147
+ headCoachName: "",
148
+ tags: []
26
149
  };
27
- function x() {
28
- let { id: x } = h(), S = !!x, { navigateTo: C } = e(), w = o(x), T = a(), E = s(), [D, O] = d(b), [k, A] = d(null);
29
- u(() => {
30
- let e = w.data;
31
- S && e && O({
150
+ function P() {
151
+ let { id: n } = w(), i = !!n, { navigateTo: s } = e(), f = l(n), S = c(), P = u(), [F, I] = g(N), [L, R] = g(""), [z, B] = g(null), V = d(i ? [f.data?.headCoachId] : []).nameOf(f.data?.headCoachId ?? void 0);
152
+ h(() => {
153
+ let e = f.data;
154
+ i && e && I((t) => ({
32
155
  name: e.name,
33
156
  sport: e.sport,
34
157
  status: e.status,
@@ -36,187 +159,255 @@ function x() {
36
159
  ageGroup: e.ageGroup ?? "",
37
160
  season: e.season ?? "",
38
161
  homeVenue: e.homeVenue ?? "",
39
- tagsText: e.tags.join(", ")
40
- });
41
- }, [S, w.data]);
42
- let j = (e, t) => O((n) => ({
162
+ headCoachId: e.headCoachId ?? "",
163
+ headCoachName: V ?? t.headCoachName,
164
+ tags: e.tags
165
+ }));
166
+ }, [
167
+ i,
168
+ f.data,
169
+ V
170
+ ]);
171
+ let H = (e, t) => I((n) => ({
43
172
  ...n,
44
173
  [e]: t
45
- })), M = (e) => e.split(",").map((e) => e.trim()).filter(Boolean), N = async (e) => {
46
- if (e.preventDefault(), A(null), !D.name.trim()) {
47
- A("Team name is required.");
174
+ })), U = (e) => {
175
+ let t = e.trim();
176
+ t && (I((e) => e.tags.some((e) => e.toLowerCase() === t.toLowerCase()) ? e : {
177
+ ...e,
178
+ tags: [...e.tags, t]
179
+ }), R(""));
180
+ }, W = (e) => I((t) => ({
181
+ ...t,
182
+ tags: t.tags.filter((t) => t !== e)
183
+ })), G = (e) => {
184
+ e.key === "Enter" || e.key === "," ? (e.preventDefault(), U(L)) : e.key === "Backspace" && !L && F.tags.length && W(F.tags[F.tags.length - 1]);
185
+ }, K = async (e) => {
186
+ if (e.preventDefault(), B(null), !F.name.trim()) {
187
+ B("Team name is required.");
48
188
  return;
49
189
  }
50
- let t = M(D.tagsText);
190
+ let t = L.trim(), r = t && !F.tags.some((e) => e.toLowerCase() === t.toLowerCase()) ? [...F.tags, t] : F.tags, a = {
191
+ name: F.name.trim(),
192
+ sport: F.sport,
193
+ status: F.status,
194
+ description: F.description.trim() || void 0,
195
+ ageGroup: F.ageGroup.trim() || void 0,
196
+ season: F.season.trim() || void 0,
197
+ homeVenue: F.homeVenue.trim() || void 0,
198
+ headCoachId: F.headCoachId.trim() || void 0,
199
+ tags: r
200
+ };
51
201
  try {
52
- S && x ? (await E.mutateAsync({
53
- id: x,
54
- input: {
55
- name: D.name.trim(),
56
- sport: D.sport,
57
- status: D.status,
58
- description: D.description.trim() || void 0,
59
- ageGroup: D.ageGroup.trim() || void 0,
60
- season: D.season.trim() || void 0,
61
- homeVenue: D.homeVenue.trim() || void 0,
62
- tags: t
63
- }
64
- }), C(`/teams/${x}`)) : C(`/teams/${(await T.mutateAsync({
65
- name: D.name.trim(),
66
- sport: D.sport,
67
- status: D.status,
68
- description: D.description.trim() || void 0,
69
- ageGroup: D.ageGroup.trim() || void 0,
70
- season: D.season.trim() || void 0,
71
- homeVenue: D.homeVenue.trim() || void 0,
72
- tags: t
73
- })).id}`);
202
+ i && n ? (await P.mutateAsync({
203
+ id: n,
204
+ input: a
205
+ }), s(`/teams/${n}`)) : s(`/teams/${(await S.mutateAsync(a)).id}`);
74
206
  } catch (e) {
75
- A(e instanceof Error ? e.message : "Failed to save team.");
207
+ B(e instanceof Error ? e.message : "Failed to save team.");
76
208
  }
77
- }, P = T.isPending || E.isPending;
78
- return S && w.isLoading ? /* @__PURE__ */ g(t, {
209
+ }, q = S.isPending || P.isPending;
210
+ return i && f.isLoading ? /* @__PURE__ */ T(t, {
79
211
  title: "Edit team",
80
- children: /* @__PURE__ */ g(i, { label: "Loading team…" })
81
- }) : S && (w.isError || !w.isLoading && !w.data) ? /* @__PURE__ */ g(t, {
212
+ children: /* @__PURE__ */ T(o, { label: "Loading team…" })
213
+ }) : i && (f.isError || !f.isLoading && !f.data) ? /* @__PURE__ */ T(t, {
82
214
  title: "Edit team",
83
- children: /* @__PURE__ */ g(r, {
215
+ children: /* @__PURE__ */ T(a, {
84
216
  title: "Team not found",
85
217
  message: "This team does not exist or you do not have access to it.",
86
- onRetry: () => C("/teams")
218
+ onRetry: () => s("/teams")
87
219
  })
88
- }) : /* @__PURE__ */ g(t, {
89
- title: S ? "Edit team" : "New team",
90
- description: S ? "Update the squad details." : "Create a new squad to build a roster.",
91
- actions: /* @__PURE__ */ _("button", {
220
+ }) : /* @__PURE__ */ T(t, {
221
+ title: i ? "Edit team" : "New team",
222
+ description: i ? "Update the squad details." : "Create a new squad to build a roster.",
223
+ actions: /* @__PURE__ */ E("button", {
92
224
  type: "button",
93
- onClick: () => C(S && x ? `/teams/${x}` : "/teams"),
225
+ onClick: () => s(i && n ? `/teams/${n}` : "/teams"),
94
226
  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",
95
- children: [/* @__PURE__ */ g(f, { className: "h-4 w-4" }), " Cancel"]
227
+ children: [/* @__PURE__ */ T(_, { className: "h-4 w-4" }), " Cancel"]
96
228
  }),
97
- children: /* @__PURE__ */ _("form", {
98
- onSubmit: N,
99
- className: "max-w-2xl space-y-5",
100
- children: [
101
- /* @__PURE__ */ g(c, {
102
- label: "Team name",
103
- htmlFor: "name",
104
- required: !0,
105
- children: /* @__PURE__ */ g("input", {
106
- id: "name",
107
- className: l,
108
- value: D.name,
109
- onChange: (e) => j("name", e.target.value),
110
- placeholder: "e.g. Riverside United U18"
111
- })
112
- }),
113
- /* @__PURE__ */ _("div", {
114
- className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
115
- children: [/* @__PURE__ */ g(c, {
116
- label: "Sport",
117
- htmlFor: "sport",
118
- children: /* @__PURE__ */ g("select", {
119
- id: "sport",
120
- className: l,
121
- value: D.sport,
122
- onChange: (e) => j("sport", e.target.value),
123
- children: v.map((e) => /* @__PURE__ */ g("option", {
124
- value: e,
125
- children: n[e]
126
- }, e))
229
+ children: /* @__PURE__ */ T("form", {
230
+ onSubmit: K,
231
+ className: "mx-auto max-w-3xl",
232
+ children: /* @__PURE__ */ E(D, {
233
+ treatment: "insight",
234
+ className: "p-6 sm:p-8",
235
+ children: [/* @__PURE__ */ E("div", {
236
+ className: "space-y-5",
237
+ children: [
238
+ /* @__PURE__ */ E("div", {
239
+ className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
240
+ children: [/* @__PURE__ */ T(p, {
241
+ label: "Team name",
242
+ htmlFor: "name",
243
+ required: !0,
244
+ children: /* @__PURE__ */ T("input", {
245
+ id: "name",
246
+ className: m,
247
+ value: F.name,
248
+ onChange: (e) => H("name", e.target.value),
249
+ placeholder: "e.g. Riverside United U18"
250
+ })
251
+ }), /* @__PURE__ */ T(p, {
252
+ label: "Sport",
253
+ htmlFor: "sport",
254
+ children: /* @__PURE__ */ E("div", {
255
+ className: "relative",
256
+ children: [/* @__PURE__ */ T(j, { sport: F.sport }), /* @__PURE__ */ T("select", {
257
+ id: "sport",
258
+ className: `${m} pl-9`,
259
+ value: F.sport,
260
+ onChange: (e) => H("sport", e.target.value),
261
+ children: O.map((e) => /* @__PURE__ */ T("option", {
262
+ value: e,
263
+ children: r[e]
264
+ }, e))
265
+ })]
266
+ })
267
+ })]
268
+ }),
269
+ /* @__PURE__ */ E("div", {
270
+ className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
271
+ children: [/* @__PURE__ */ T(p, {
272
+ label: "Status",
273
+ htmlFor: "status",
274
+ children: /* @__PURE__ */ T("select", {
275
+ id: "status",
276
+ className: m,
277
+ value: F.status,
278
+ onChange: (e) => H("status", e.target.value),
279
+ children: k.map((e) => /* @__PURE__ */ T("option", {
280
+ value: e,
281
+ children: e.charAt(0) + e.slice(1).toLowerCase()
282
+ }, e))
283
+ })
284
+ }), /* @__PURE__ */ T(p, {
285
+ label: "Age group",
286
+ htmlFor: "ageGroup",
287
+ children: /* @__PURE__ */ T("input", {
288
+ id: "ageGroup",
289
+ className: m,
290
+ value: F.ageGroup,
291
+ onChange: (e) => H("ageGroup", e.target.value),
292
+ placeholder: "e.g. U18"
293
+ })
294
+ })]
295
+ }),
296
+ /* @__PURE__ */ E("div", {
297
+ className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
298
+ children: [/* @__PURE__ */ T(p, {
299
+ label: "Season",
300
+ htmlFor: "season",
301
+ children: /* @__PURE__ */ E("div", {
302
+ className: "relative",
303
+ children: [/* @__PURE__ */ T(v, {
304
+ className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted",
305
+ "aria-hidden": "true"
306
+ }), /* @__PURE__ */ T("input", {
307
+ id: "season",
308
+ className: `${m} pl-9`,
309
+ value: F.season,
310
+ onChange: (e) => H("season", e.target.value),
311
+ placeholder: "e.g. 2025/26"
312
+ })]
313
+ })
314
+ }), /* @__PURE__ */ T(p, {
315
+ label: "Home venue",
316
+ htmlFor: "homeVenue",
317
+ children: /* @__PURE__ */ E("div", {
318
+ className: "relative",
319
+ children: [/* @__PURE__ */ T(b, {
320
+ className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted",
321
+ "aria-hidden": "true"
322
+ }), /* @__PURE__ */ T("input", {
323
+ id: "homeVenue",
324
+ className: `${m} pl-9`,
325
+ value: F.homeVenue,
326
+ onChange: (e) => H("homeVenue", e.target.value),
327
+ placeholder: "e.g. Riverside Stadium"
328
+ })]
329
+ })
330
+ })]
331
+ }),
332
+ /* @__PURE__ */ T(M, {
333
+ userId: F.headCoachId,
334
+ displayName: F.headCoachName,
335
+ onSelect: ({ userId: e, displayName: t }) => I((n) => ({
336
+ ...n,
337
+ headCoachId: e,
338
+ headCoachName: t
339
+ }))
340
+ }),
341
+ /* @__PURE__ */ E(p, {
342
+ label: "Description",
343
+ htmlFor: "description",
344
+ children: [/* @__PURE__ */ T("textarea", {
345
+ id: "description",
346
+ className: m,
347
+ rows: 3,
348
+ maxLength: A,
349
+ value: F.description,
350
+ onChange: (e) => H("description", e.target.value),
351
+ placeholder: "A short description of the team."
352
+ }), /* @__PURE__ */ E("div", {
353
+ className: "mt-1 text-right text-xs tabular-nums text-text-muted",
354
+ children: [
355
+ F.description.length,
356
+ "/",
357
+ A
358
+ ]
359
+ })]
360
+ }),
361
+ /* @__PURE__ */ T(p, {
362
+ label: "Tags",
363
+ htmlFor: "tags",
364
+ hint: "Type a tag and press Enter to add it; click × to remove.",
365
+ children: /* @__PURE__ */ E("div", {
366
+ className: "flex flex-wrap items-center gap-1.5 rounded-lg border border-border-seam bg-bg-surface px-2 py-1.5 focus-within:ring-2 focus-within:ring-[var(--color-focus-ring)]",
367
+ children: [F.tags.map((e) => /* @__PURE__ */ E("span", {
368
+ className: "inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
369
+ children: [e, /* @__PURE__ */ T("button", {
370
+ type: "button",
371
+ onClick: () => W(e),
372
+ "aria-label": `Remove tag ${e}`,
373
+ className: "rounded-full text-text-muted transition-colors hover:text-status-error-text",
374
+ children: /* @__PURE__ */ T(C, { className: "h-3 w-3" })
375
+ })]
376
+ }, e)), /* @__PURE__ */ T("input", {
377
+ id: "tags",
378
+ className: "min-w-[8rem] flex-1 bg-transparent px-1 py-0.5 text-sm text-text-primary placeholder:text-text-muted focus:outline-none",
379
+ value: L,
380
+ onChange: (e) => R(e.target.value),
381
+ onKeyDown: G,
382
+ onBlur: () => U(L),
383
+ placeholder: F.tags.length ? "Add tag and press Enter…" : "youth, development"
384
+ })]
385
+ })
386
+ }),
387
+ z && /* @__PURE__ */ T("p", {
388
+ className: "text-sm text-status-error-text",
389
+ children: z
127
390
  })
128
- }), /* @__PURE__ */ g(c, {
129
- label: "Status",
130
- htmlFor: "status",
131
- children: /* @__PURE__ */ g("select", {
132
- id: "status",
133
- className: l,
134
- value: D.status,
135
- onChange: (e) => j("status", e.target.value),
136
- children: y.map((e) => /* @__PURE__ */ g("option", {
137
- value: e,
138
- children: e.charAt(0) + e.slice(1).toLowerCase()
139
- }, e))
140
- })
141
- })]
142
- }),
143
- /* @__PURE__ */ _("div", {
144
- className: "grid grid-cols-1 gap-5 sm:grid-cols-2",
145
- children: [/* @__PURE__ */ g(c, {
146
- label: "Age group",
147
- htmlFor: "ageGroup",
148
- children: /* @__PURE__ */ g("input", {
149
- id: "ageGroup",
150
- className: l,
151
- value: D.ageGroup,
152
- onChange: (e) => j("ageGroup", e.target.value),
153
- placeholder: "e.g. U18"
154
- })
155
- }), /* @__PURE__ */ g(c, {
156
- label: "Season",
157
- htmlFor: "season",
158
- children: /* @__PURE__ */ g("input", {
159
- id: "season",
160
- className: l,
161
- value: D.season,
162
- onChange: (e) => j("season", e.target.value),
163
- placeholder: "e.g. 2025/26"
164
- })
165
- })]
166
- }),
167
- /* @__PURE__ */ g(c, {
168
- label: "Home venue",
169
- htmlFor: "homeVenue",
170
- children: /* @__PURE__ */ g("input", {
171
- id: "homeVenue",
172
- className: l,
173
- value: D.homeVenue,
174
- onChange: (e) => j("homeVenue", e.target.value),
175
- placeholder: "e.g. Riverside Stadium"
176
- })
177
- }),
178
- /* @__PURE__ */ g(c, {
179
- label: "Description",
180
- htmlFor: "description",
181
- children: /* @__PURE__ */ g("textarea", {
182
- id: "description",
183
- className: l,
184
- rows: 3,
185
- value: D.description,
186
- onChange: (e) => j("description", e.target.value),
187
- placeholder: "A short description of the team."
188
- })
189
- }),
190
- /* @__PURE__ */ g(c, {
191
- label: "Tags",
192
- htmlFor: "tags",
193
- hint: "Comma-separated, e.g. youth, development, first-team.",
194
- children: /* @__PURE__ */ g("input", {
195
- id: "tags",
196
- className: l,
197
- value: D.tagsText,
198
- onChange: (e) => j("tagsText", e.target.value),
199
- placeholder: "youth, development"
200
- })
201
- }),
202
- k && /* @__PURE__ */ g("p", {
203
- className: "text-sm text-status-error-text",
204
- children: k
205
- }),
206
- /* @__PURE__ */ g("div", {
207
- className: "flex items-center gap-3 pt-2",
208
- children: /* @__PURE__ */ _("button", {
391
+ ]
392
+ }), /* @__PURE__ */ E("div", {
393
+ className: "mt-6 flex items-center justify-end gap-3 border-t border-border-seam pt-5",
394
+ children: [/* @__PURE__ */ T("button", {
395
+ type: "button",
396
+ onClick: () => s(i && n ? `/teams/${n}` : "/teams"),
397
+ className: "rounded-lg px-4 py-2 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary",
398
+ children: "Cancel"
399
+ }), /* @__PURE__ */ E("button", {
209
400
  type: "submit",
210
- disabled: P,
211
- 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 disabled:opacity-60",
212
- children: [P ? /* @__PURE__ */ g(p, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ g(m, { className: "h-4 w-4" }), S ? "Save changes" : "Create team"]
213
- })
214
- })
215
- ]
401
+ disabled: q,
402
+ className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-5 py-2 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60",
403
+ children: [q ? /* @__PURE__ */ T(y, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ T(x, { className: "h-4 w-4" }), i ? "Save changes" : "Create team"]
404
+ })]
405
+ })]
406
+ })
216
407
  })
217
408
  });
218
409
  }
219
410
  //#endregion
220
- export { x as TeamFormPage };
411
+ export { P as TeamFormPage };
221
412
 
222
413
  //# sourceMappingURL=TeamFormPage.js.map