@burdenoff/microfe-atheletebridge 2026.629.1 → 2026.705.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.
- package/dist/atheletebridge/AthleteBridgeRoot.js +45 -37
- package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
- package/dist/atheletebridge/AthleteBridgeRoutes.js +10 -6
- package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
- package/dist/atheletebridge/components/AthleteSelect.js +66 -0
- package/dist/atheletebridge/components/AthleteSelect.js.map +1 -0
- package/dist/atheletebridge/components/DrillVideoLink.js +28 -0
- package/dist/atheletebridge/components/DrillVideoLink.js.map +1 -0
- package/dist/atheletebridge/components/MetricsCard.js +20 -46
- package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
- package/dist/atheletebridge/components/UserSearchSelect.js +129 -0
- package/dist/atheletebridge/components/UserSearchSelect.js.map +1 -0
- package/dist/atheletebridge/components/domain.js +10 -1
- package/dist/atheletebridge/components/domain.js.map +1 -1
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +313 -180
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
- package/dist/atheletebridge/pages/DashboardPage.js +77 -69
- package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
- package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +4 -4
- package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/performance/PerformancePage.js +496 -0
- package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -0
- package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +176 -142
- package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +86 -85
- package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/sessions/SessionFormPage.js +92 -98
- package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -1
- package/dist/atheletebridge/pages/teams/TeamDetailPage.js +132 -137
- package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
- package/dist/atheletebridge/utils/formatters.js +2 -25
- package/dist/atheletebridge/utils/formatters.js.map +1 -1
- package/dist/atheletebridge/utils/url.js +17 -0
- package/dist/atheletebridge/utils/url.js.map +1 -0
- package/dist/index.js +4 -4
- package/package.json +5 -5
|
@@ -7,19 +7,20 @@ import { EmptyState as o } from "../../components/EmptyState.js";
|
|
|
7
7
|
import { ErrorState as s, LoadingState as c } from "../../components/LoadingState.js";
|
|
8
8
|
import { useAddMember as l, useArchiveTeam as u, useRemoveMember as d, useTeam as f } from "../../hooks/useAthleteBridgeApi.js";
|
|
9
9
|
import { FormField as p, fieldInputClass as m } from "../../components/form.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
10
|
+
import { UserSearchSelect as h } from "../../components/UserSearchSelect.js";
|
|
11
|
+
import { useState as g } from "react";
|
|
12
|
+
import { Archive as _, ArrowLeft as v, CalendarDays as y, Edit as b, Loader2 as x, MapPin as S, Plus as C, Trash2 as w, UserPlus as T } from "lucide-react";
|
|
13
|
+
import { useParams as E } from "react-router-dom";
|
|
14
|
+
import { jsx as D, jsxs as O } from "react/jsx-runtime";
|
|
15
|
+
import { EmphasisPanel as k, GlassCard as A, ResponsiveDialog as j, ResponsiveDialogContent as M, ResponsiveDialogFooter as N, ResponsiveDialogHeader as P, ResponsiveDialogTitle as F } from "@burdenoff/fe-libs/ui";
|
|
15
16
|
//#region src/atheletebridge/pages/teams/TeamDetailPage.tsx
|
|
16
|
-
var
|
|
17
|
+
var I = Object.keys(r), L = [
|
|
17
18
|
"TRIAL",
|
|
18
19
|
"ACTIVE",
|
|
19
20
|
"INJURED",
|
|
20
21
|
"SUSPENDED",
|
|
21
22
|
"RELEASED"
|
|
22
|
-
],
|
|
23
|
+
], R = {
|
|
23
24
|
userId: "",
|
|
24
25
|
displayName: "",
|
|
25
26
|
role: "PLAYER",
|
|
@@ -27,48 +28,48 @@ var F = Object.keys(r), I = [
|
|
|
27
28
|
position: "",
|
|
28
29
|
jerseyNumber: ""
|
|
29
30
|
};
|
|
30
|
-
function
|
|
31
|
-
let { id:
|
|
32
|
-
if (
|
|
31
|
+
function z() {
|
|
32
|
+
let { id: z } = E(), { navigateTo: B } = e(), V = f(z), H = u(), U = l(), W = d(z), [G, K] = g(!1), [q, J] = g(R), [Y, X] = g(null);
|
|
33
|
+
if (V.isLoading) return /* @__PURE__ */ D(t, {
|
|
33
34
|
title: "Team",
|
|
34
|
-
children: /* @__PURE__ */
|
|
35
|
+
children: /* @__PURE__ */ D(c, { label: "Loading team…" })
|
|
35
36
|
});
|
|
36
|
-
if (
|
|
37
|
+
if (V.isError || !V.data) return /* @__PURE__ */ D(t, {
|
|
37
38
|
title: "Team",
|
|
38
|
-
children: /* @__PURE__ */
|
|
39
|
+
children: /* @__PURE__ */ D(s, {
|
|
39
40
|
title: "Team not found",
|
|
40
41
|
message: "This team does not exist or you do not have access to it.",
|
|
41
|
-
onRetry: () =>
|
|
42
|
+
onRetry: () => B("/teams")
|
|
42
43
|
})
|
|
43
44
|
});
|
|
44
|
-
let
|
|
45
|
-
return /* @__PURE__ */
|
|
46
|
-
title:
|
|
47
|
-
description: `${i[
|
|
48
|
-
actions: /* @__PURE__ */
|
|
45
|
+
let Z = V.data, Q = Z.members ?? [], $ = Z.fixtures ?? [];
|
|
46
|
+
return /* @__PURE__ */ O(t, {
|
|
47
|
+
title: Z.name,
|
|
48
|
+
description: `${i[Z.sport]}${Z.season ? ` · ${Z.season}` : ""}`,
|
|
49
|
+
actions: /* @__PURE__ */ O("div", {
|
|
49
50
|
className: "flex flex-wrap items-center gap-2",
|
|
50
51
|
children: [
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ O("button", {
|
|
52
53
|
type: "button",
|
|
53
|
-
onClick: () =>
|
|
54
|
+
onClick: () => B("/teams"),
|
|
54
55
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
|
|
55
|
-
children: [/* @__PURE__ */
|
|
56
|
+
children: [/* @__PURE__ */ D(v, { className: "h-4 w-4" }), " Back"]
|
|
56
57
|
}),
|
|
57
|
-
/* @__PURE__ */
|
|
58
|
+
/* @__PURE__ */ O("button", {
|
|
58
59
|
type: "button",
|
|
59
|
-
onClick: () =>
|
|
60
|
+
onClick: () => B(`/teams/${Z.id}/edit`),
|
|
60
61
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
|
|
61
|
-
children: [/* @__PURE__ */
|
|
62
|
+
children: [/* @__PURE__ */ D(b, { className: "h-4 w-4" }), " Edit"]
|
|
62
63
|
}),
|
|
63
|
-
|
|
64
|
+
Z.status !== "ARCHIVED" && /* @__PURE__ */ O("button", {
|
|
64
65
|
type: "button",
|
|
65
66
|
onClick: async () => {
|
|
66
|
-
|
|
67
|
+
z && (await H.mutateAsync(z), B("/teams"));
|
|
67
68
|
},
|
|
68
|
-
disabled:
|
|
69
|
+
disabled: H.isPending,
|
|
69
70
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-60",
|
|
70
71
|
children: [
|
|
71
|
-
|
|
72
|
+
H.isPending ? /* @__PURE__ */ D(x, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ D(_, { className: "h-4 w-4" }),
|
|
72
73
|
" ",
|
|
73
74
|
"Archive"
|
|
74
75
|
]
|
|
@@ -76,246 +77,240 @@ function R() {
|
|
|
76
77
|
]
|
|
77
78
|
}),
|
|
78
79
|
children: [
|
|
79
|
-
/* @__PURE__ */
|
|
80
|
+
/* @__PURE__ */ O(A, {
|
|
80
81
|
treatment: "insight",
|
|
81
82
|
className: "mb-8 p-6",
|
|
82
83
|
children: [
|
|
83
|
-
/* @__PURE__ */
|
|
84
|
+
/* @__PURE__ */ O("div", {
|
|
84
85
|
className: "flex flex-wrap items-center gap-3",
|
|
85
86
|
children: [
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
-
|
|
87
|
+
/* @__PURE__ */ D(n, { status: Z.status }),
|
|
88
|
+
Z.ageGroup && /* @__PURE__ */ O("span", {
|
|
88
89
|
className: "text-sm text-text-secondary",
|
|
89
|
-
children: ["Age group: ",
|
|
90
|
+
children: ["Age group: ", Z.ageGroup]
|
|
90
91
|
}),
|
|
91
|
-
|
|
92
|
+
Z.homeVenue && /* @__PURE__ */ O("span", {
|
|
92
93
|
className: "flex items-center gap-1 text-sm text-text-secondary",
|
|
93
94
|
children: [
|
|
94
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ D(S, { className: "h-3.5 w-3.5" }),
|
|
95
96
|
" ",
|
|
96
|
-
|
|
97
|
+
Z.homeVenue
|
|
97
98
|
]
|
|
98
99
|
})
|
|
99
100
|
]
|
|
100
101
|
}),
|
|
101
|
-
|
|
102
|
+
Z.description && /* @__PURE__ */ D("p", {
|
|
102
103
|
className: "mt-4 text-sm text-text-secondary",
|
|
103
|
-
children:
|
|
104
|
+
children: Z.description
|
|
104
105
|
}),
|
|
105
|
-
|
|
106
|
+
Z.tags.length > 0 && /* @__PURE__ */ D("div", {
|
|
106
107
|
className: "mt-4 flex flex-wrap gap-1.5",
|
|
107
|
-
children:
|
|
108
|
+
children: Z.tags.map((e) => /* @__PURE__ */ D("span", {
|
|
108
109
|
className: "inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
|
|
109
110
|
children: e
|
|
110
111
|
}, e))
|
|
111
112
|
})
|
|
112
113
|
]
|
|
113
114
|
}),
|
|
114
|
-
/* @__PURE__ */
|
|
115
|
+
/* @__PURE__ */ O("section", {
|
|
115
116
|
className: "mb-8",
|
|
116
|
-
children: [/* @__PURE__ */
|
|
117
|
+
children: [/* @__PURE__ */ O("div", {
|
|
117
118
|
className: "mb-4 flex items-center justify-between",
|
|
118
|
-
children: [/* @__PURE__ */
|
|
119
|
+
children: [/* @__PURE__ */ O("h2", {
|
|
119
120
|
className: "text-lg font-semibold text-text-primary",
|
|
120
121
|
children: [
|
|
121
122
|
"Roster (",
|
|
122
|
-
|
|
123
|
+
Q.length,
|
|
123
124
|
")"
|
|
124
125
|
]
|
|
125
|
-
}), /* @__PURE__ */
|
|
126
|
+
}), /* @__PURE__ */ O("button", {
|
|
126
127
|
type: "button",
|
|
127
128
|
onClick: () => {
|
|
128
|
-
|
|
129
|
+
X(null), K(!0);
|
|
129
130
|
},
|
|
130
131
|
className: "inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90",
|
|
131
|
-
children: [/* @__PURE__ */
|
|
132
|
+
children: [/* @__PURE__ */ D(T, { className: "h-4 w-4" }), " Add member"]
|
|
132
133
|
})]
|
|
133
|
-
}),
|
|
134
|
+
}), Q.length === 0 ? /* @__PURE__ */ D(o, {
|
|
134
135
|
illustration: "empty-data",
|
|
135
|
-
icon: /* @__PURE__ */
|
|
136
|
+
icon: /* @__PURE__ */ D(T, { className: "h-10 w-10" }),
|
|
136
137
|
title: "No members yet",
|
|
137
138
|
description: "Add players, coaches and staff to build the roster."
|
|
138
|
-
}) : /* @__PURE__ */
|
|
139
|
+
}) : /* @__PURE__ */ D(k, { children: /* @__PURE__ */ D("div", {
|
|
139
140
|
className: "divide-y divide-border-seam",
|
|
140
|
-
children:
|
|
141
|
+
children: Q.map((e) => /* @__PURE__ */ O("div", {
|
|
141
142
|
className: "flex items-center gap-4 py-3",
|
|
142
143
|
children: [
|
|
143
|
-
/* @__PURE__ */
|
|
144
|
+
/* @__PURE__ */ D("div", {
|
|
144
145
|
className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold tabular-nums text-text-primary",
|
|
145
146
|
children: e.jerseyNumber ?? e.displayName.charAt(0).toUpperCase()
|
|
146
147
|
}),
|
|
147
|
-
/* @__PURE__ */
|
|
148
|
+
/* @__PURE__ */ O("div", {
|
|
148
149
|
className: "min-w-0 flex-1",
|
|
149
|
-
children: [/* @__PURE__ */
|
|
150
|
+
children: [/* @__PURE__ */ D("p", {
|
|
150
151
|
className: "truncate text-sm font-medium text-text-primary",
|
|
151
152
|
children: e.displayName
|
|
152
|
-
}), /* @__PURE__ */
|
|
153
|
+
}), /* @__PURE__ */ O("p", {
|
|
153
154
|
className: "text-xs text-text-secondary",
|
|
154
155
|
children: [r[e.role], e.position ? ` · ${e.position}` : ""]
|
|
155
156
|
})]
|
|
156
157
|
}),
|
|
157
|
-
/* @__PURE__ */
|
|
158
|
-
/* @__PURE__ */
|
|
158
|
+
/* @__PURE__ */ D(n, { status: e.status }),
|
|
159
|
+
/* @__PURE__ */ D("button", {
|
|
159
160
|
type: "button",
|
|
160
|
-
onClick: () => void
|
|
161
|
-
disabled:
|
|
161
|
+
onClick: () => void W.mutate(e.id),
|
|
162
|
+
disabled: W.isPending,
|
|
162
163
|
"aria-label": `Remove ${e.displayName}`,
|
|
163
164
|
className: "rounded-lg p-2 text-text-secondary transition-colors hover:bg-status-error-bg-subtle hover:text-status-error-text disabled:opacity-60",
|
|
164
|
-
children: /* @__PURE__ */
|
|
165
|
+
children: /* @__PURE__ */ D(w, { className: "h-4 w-4" })
|
|
165
166
|
})
|
|
166
167
|
]
|
|
167
168
|
}, e.id))
|
|
168
169
|
}) })]
|
|
169
170
|
}),
|
|
170
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ O("section", { children: [/* @__PURE__ */ O("div", {
|
|
171
172
|
className: "mb-4 flex items-center justify-between",
|
|
172
|
-
children: [/* @__PURE__ */
|
|
173
|
+
children: [/* @__PURE__ */ O("h2", {
|
|
173
174
|
className: "text-lg font-semibold text-text-primary",
|
|
174
175
|
children: [
|
|
175
176
|
"Fixtures (",
|
|
176
|
-
|
|
177
|
+
$.length,
|
|
177
178
|
")"
|
|
178
179
|
]
|
|
179
|
-
}), /* @__PURE__ */
|
|
180
|
+
}), /* @__PURE__ */ O("button", {
|
|
180
181
|
type: "button",
|
|
181
|
-
onClick: () =>
|
|
182
|
+
onClick: () => B(`/fixtures/new?homeTeamId=${Z.id}`),
|
|
182
183
|
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
|
|
183
|
-
children: [/* @__PURE__ */
|
|
184
|
+
children: [/* @__PURE__ */ D(C, { className: "h-4 w-4" }), " Schedule"]
|
|
184
185
|
})]
|
|
185
|
-
}),
|
|
186
|
+
}), $.length === 0 ? /* @__PURE__ */ D(o, {
|
|
186
187
|
illustration: "empty-calendar",
|
|
187
|
-
icon: /* @__PURE__ */
|
|
188
|
+
icon: /* @__PURE__ */ D(y, { className: "h-10 w-10" }),
|
|
188
189
|
title: "No fixtures scheduled",
|
|
189
190
|
description: "Schedule a match for this team to start tracking results."
|
|
190
|
-
}) : /* @__PURE__ */
|
|
191
|
+
}) : /* @__PURE__ */ D("div", {
|
|
191
192
|
className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3",
|
|
192
|
-
children:
|
|
193
|
+
children: $.map((e) => /* @__PURE__ */ D(a, {
|
|
193
194
|
fixture: e,
|
|
194
|
-
onClick: () =>
|
|
195
|
+
onClick: () => B(`/fixtures/${e.id}`)
|
|
195
196
|
}, e.id))
|
|
196
197
|
})] }),
|
|
197
|
-
/* @__PURE__ */
|
|
198
|
-
open:
|
|
199
|
-
onOpenChange:
|
|
200
|
-
children: /* @__PURE__ */
|
|
198
|
+
/* @__PURE__ */ D(j, {
|
|
199
|
+
open: G,
|
|
200
|
+
onOpenChange: K,
|
|
201
|
+
children: /* @__PURE__ */ O(M, { children: [/* @__PURE__ */ D(P, { children: /* @__PURE__ */ D(F, { children: "Add member" }) }), /* @__PURE__ */ O("form", {
|
|
201
202
|
onSubmit: async (e) => {
|
|
202
|
-
if (e.preventDefault(),
|
|
203
|
-
if (!
|
|
204
|
-
|
|
203
|
+
if (e.preventDefault(), X(null), !z) return;
|
|
204
|
+
if (!q.userId.trim() || !q.displayName.trim()) {
|
|
205
|
+
X("User ID and display name are required.");
|
|
205
206
|
return;
|
|
206
207
|
}
|
|
207
|
-
let t =
|
|
208
|
+
let t = q.jerseyNumber.trim() ? Number.parseInt(q.jerseyNumber, 10) : void 0;
|
|
208
209
|
if (t !== void 0 && Number.isNaN(t)) {
|
|
209
|
-
|
|
210
|
+
X("Jersey number must be a number.");
|
|
210
211
|
return;
|
|
211
212
|
}
|
|
212
213
|
try {
|
|
213
|
-
await
|
|
214
|
-
teamId:
|
|
215
|
-
userId:
|
|
216
|
-
displayName:
|
|
217
|
-
role:
|
|
218
|
-
status:
|
|
219
|
-
position:
|
|
214
|
+
await U.mutateAsync({
|
|
215
|
+
teamId: z,
|
|
216
|
+
userId: q.userId.trim(),
|
|
217
|
+
displayName: q.displayName.trim(),
|
|
218
|
+
role: q.role,
|
|
219
|
+
status: q.status,
|
|
220
|
+
position: q.position.trim() || void 0,
|
|
220
221
|
jerseyNumber: t
|
|
221
|
-
}),
|
|
222
|
+
}), J(R), K(!1);
|
|
222
223
|
} catch (e) {
|
|
223
|
-
|
|
224
|
+
X(e instanceof Error ? e.message : "Failed to add member.");
|
|
224
225
|
}
|
|
225
226
|
},
|
|
226
227
|
className: "space-y-4 px-1",
|
|
227
228
|
children: [
|
|
228
|
-
/* @__PURE__ */
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
onChange: (e) => q((t) => ({
|
|
238
|
-
...t,
|
|
239
|
-
userId: e.target.value
|
|
240
|
-
})),
|
|
241
|
-
placeholder: "user-uuid"
|
|
242
|
-
})
|
|
229
|
+
/* @__PURE__ */ D(h, {
|
|
230
|
+
userId: q.userId,
|
|
231
|
+
displayName: q.displayName,
|
|
232
|
+
onSelect: ({ userId: e, displayName: t }) => J((n) => ({
|
|
233
|
+
...n,
|
|
234
|
+
userId: e,
|
|
235
|
+
displayName: t || n.displayName
|
|
236
|
+
})),
|
|
237
|
+
required: !0
|
|
243
238
|
}),
|
|
244
|
-
/* @__PURE__ */
|
|
239
|
+
/* @__PURE__ */ D(p, {
|
|
245
240
|
label: "Display name",
|
|
246
241
|
htmlFor: "displayName",
|
|
247
242
|
required: !0,
|
|
248
|
-
children: /* @__PURE__ */
|
|
243
|
+
children: /* @__PURE__ */ D("input", {
|
|
249
244
|
id: "displayName",
|
|
250
245
|
className: m,
|
|
251
|
-
value:
|
|
252
|
-
onChange: (e) =>
|
|
246
|
+
value: q.displayName,
|
|
247
|
+
onChange: (e) => J((t) => ({
|
|
253
248
|
...t,
|
|
254
249
|
displayName: e.target.value
|
|
255
250
|
})),
|
|
256
251
|
placeholder: "e.g. Alex Morgan"
|
|
257
252
|
})
|
|
258
253
|
}),
|
|
259
|
-
/* @__PURE__ */
|
|
254
|
+
/* @__PURE__ */ O("div", {
|
|
260
255
|
className: "grid grid-cols-2 gap-4",
|
|
261
|
-
children: [/* @__PURE__ */
|
|
256
|
+
children: [/* @__PURE__ */ D(p, {
|
|
262
257
|
label: "Role",
|
|
263
258
|
htmlFor: "role",
|
|
264
|
-
children: /* @__PURE__ */
|
|
259
|
+
children: /* @__PURE__ */ D("select", {
|
|
265
260
|
id: "role",
|
|
266
261
|
className: m,
|
|
267
|
-
value:
|
|
268
|
-
onChange: (e) =>
|
|
262
|
+
value: q.role,
|
|
263
|
+
onChange: (e) => J((t) => ({
|
|
269
264
|
...t,
|
|
270
265
|
role: e.target.value
|
|
271
266
|
})),
|
|
272
|
-
children:
|
|
267
|
+
children: I.map((e) => /* @__PURE__ */ D("option", {
|
|
273
268
|
value: e,
|
|
274
269
|
children: r[e]
|
|
275
270
|
}, e))
|
|
276
271
|
})
|
|
277
|
-
}), /* @__PURE__ */
|
|
272
|
+
}), /* @__PURE__ */ D(p, {
|
|
278
273
|
label: "Status",
|
|
279
274
|
htmlFor: "memberStatus",
|
|
280
|
-
children: /* @__PURE__ */
|
|
275
|
+
children: /* @__PURE__ */ D("select", {
|
|
281
276
|
id: "memberStatus",
|
|
282
277
|
className: m,
|
|
283
|
-
value:
|
|
284
|
-
onChange: (e) =>
|
|
278
|
+
value: q.status,
|
|
279
|
+
onChange: (e) => J((t) => ({
|
|
285
280
|
...t,
|
|
286
281
|
status: e.target.value
|
|
287
282
|
})),
|
|
288
|
-
children:
|
|
283
|
+
children: L.map((e) => /* @__PURE__ */ D("option", {
|
|
289
284
|
value: e,
|
|
290
285
|
children: e.charAt(0) + e.slice(1).toLowerCase()
|
|
291
286
|
}, e))
|
|
292
287
|
})
|
|
293
288
|
})]
|
|
294
289
|
}),
|
|
295
|
-
/* @__PURE__ */
|
|
290
|
+
/* @__PURE__ */ O("div", {
|
|
296
291
|
className: "grid grid-cols-2 gap-4",
|
|
297
|
-
children: [/* @__PURE__ */
|
|
292
|
+
children: [/* @__PURE__ */ D(p, {
|
|
298
293
|
label: "Position",
|
|
299
294
|
htmlFor: "position",
|
|
300
|
-
children: /* @__PURE__ */
|
|
295
|
+
children: /* @__PURE__ */ D("input", {
|
|
301
296
|
id: "position",
|
|
302
297
|
className: m,
|
|
303
|
-
value:
|
|
304
|
-
onChange: (e) =>
|
|
298
|
+
value: q.position,
|
|
299
|
+
onChange: (e) => J((t) => ({
|
|
305
300
|
...t,
|
|
306
301
|
position: e.target.value
|
|
307
302
|
})),
|
|
308
303
|
placeholder: "e.g. Striker"
|
|
309
304
|
})
|
|
310
|
-
}), /* @__PURE__ */
|
|
305
|
+
}), /* @__PURE__ */ D(p, {
|
|
311
306
|
label: "Jersey #",
|
|
312
307
|
htmlFor: "jersey",
|
|
313
|
-
children: /* @__PURE__ */
|
|
308
|
+
children: /* @__PURE__ */ D("input", {
|
|
314
309
|
id: "jersey",
|
|
315
310
|
className: m,
|
|
316
311
|
inputMode: "numeric",
|
|
317
|
-
value:
|
|
318
|
-
onChange: (e) =>
|
|
312
|
+
value: q.jerseyNumber,
|
|
313
|
+
onChange: (e) => J((t) => ({
|
|
319
314
|
...t,
|
|
320
315
|
jerseyNumber: e.target.value
|
|
321
316
|
})),
|
|
@@ -323,20 +318,20 @@ function R() {
|
|
|
323
318
|
})
|
|
324
319
|
})]
|
|
325
320
|
}),
|
|
326
|
-
|
|
321
|
+
Y && /* @__PURE__ */ D("p", {
|
|
327
322
|
className: "text-sm text-status-error-text",
|
|
328
|
-
children:
|
|
323
|
+
children: Y
|
|
329
324
|
}),
|
|
330
|
-
/* @__PURE__ */
|
|
325
|
+
/* @__PURE__ */ O(N, { children: [/* @__PURE__ */ D("button", {
|
|
331
326
|
type: "button",
|
|
332
|
-
onClick: () =>
|
|
327
|
+
onClick: () => K(!1),
|
|
333
328
|
className: "rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
|
|
334
329
|
children: "Cancel"
|
|
335
|
-
}), /* @__PURE__ */
|
|
330
|
+
}), /* @__PURE__ */ O("button", {
|
|
336
331
|
type: "submit",
|
|
337
|
-
disabled:
|
|
332
|
+
disabled: U.isPending,
|
|
338
333
|
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",
|
|
339
|
-
children: [
|
|
334
|
+
children: [U.isPending && /* @__PURE__ */ D(x, { className: "h-4 w-4 animate-spin" }), "Add member"]
|
|
340
335
|
})] })
|
|
341
336
|
]
|
|
342
337
|
})] })
|
|
@@ -345,6 +340,6 @@ function R() {
|
|
|
345
340
|
});
|
|
346
341
|
}
|
|
347
342
|
//#endregion
|
|
348
|
-
export {
|
|
343
|
+
export { z as TeamDetailPage };
|
|
349
344
|
|
|
350
345
|
//# sourceMappingURL=TeamDetailPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamDetailPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/teams/TeamDetailPage.tsx"],"sourcesContent":["/**\n * Team Detail\n * @module atheletebridge/pages/teams\n *\n * Reads a single team (with members + fixtures) from `athTeam`, supports adding\n * and removing members (athAddMember / athRemoveMember), editing and archiving\n * the team (athUpdateTeam via the form / athArchiveTeam), and links into the\n * team's fixtures.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n CalendarDays,\n Edit,\n Archive,\n MapPin,\n Plus,\n Trash2,\n UserPlus,\n Loader2,\n} from 'lucide-react';\nimport {\n GlassCard,\n EmphasisPanel,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { FixtureCard } from '../../components/FixtureCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { SPORT_LABELS, MEMBER_ROLE_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport {\n useTeam,\n useArchiveTeam,\n useAddMember,\n useRemoveMember,\n} from '../../hooks/useAthleteBridgeApi';\nimport type { AthMemberRole, AthMemberStatus } from '../../types';\n\nconst ROLES = Object.keys(MEMBER_ROLE_LABELS) as AthMemberRole[];\nconst MEMBER_STATUSES: AthMemberStatus[] = ['TRIAL', 'ACTIVE', 'INJURED', 'SUSPENDED', 'RELEASED'];\n\ninterface AddMemberForm {\n userId: string;\n displayName: string;\n role: AthMemberRole;\n status: AthMemberStatus;\n position: string;\n jerseyNumber: string;\n}\n\nconst EMPTY_MEMBER: AddMemberForm = {\n userId: '',\n displayName: '',\n role: 'PLAYER',\n status: 'ACTIVE',\n position: '',\n jerseyNumber: '',\n};\n\nexport function TeamDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useAthleteBridge();\n\n const team = useTeam(id);\n const archiveTeam = useArchiveTeam();\n const addMember = useAddMember();\n const removeMember = useRemoveMember(id);\n\n const [addOpen, setAddOpen] = useState(false);\n const [memberForm, setMemberForm] = useState<AddMemberForm>(EMPTY_MEMBER);\n const [memberError, setMemberError] = useState<string | null>(null);\n\n if (team.isLoading) {\n return (\n <PageLayout title=\"Team\">\n <LoadingState label=\"Loading team…\" />\n </PageLayout>\n );\n }\n\n if (team.isError || !team.data) {\n return (\n <PageLayout title=\"Team\">\n <ErrorState\n title=\"Team not found\"\n message=\"This team does not exist or you do not have access to it.\"\n onRetry={() => navigateTo('/teams')}\n />\n </PageLayout>\n );\n }\n\n const t = team.data;\n const members = t.members ?? [];\n const fixtures = t.fixtures ?? [];\n\n const handleArchive = async () => {\n if (!id) return;\n await archiveTeam.mutateAsync(id);\n navigateTo('/teams');\n };\n\n const handleAddMember = async (e: React.FormEvent) => {\n e.preventDefault();\n setMemberError(null);\n if (!id) return;\n if (!memberForm.userId.trim() || !memberForm.displayName.trim()) {\n setMemberError('User ID and display name are required.');\n return;\n }\n const jersey = memberForm.jerseyNumber.trim()\n ? Number.parseInt(memberForm.jerseyNumber, 10)\n : undefined;\n if (jersey !== undefined && Number.isNaN(jersey)) {\n setMemberError('Jersey number must be a number.');\n return;\n }\n try {\n await addMember.mutateAsync({\n teamId: id,\n userId: memberForm.userId.trim(),\n displayName: memberForm.displayName.trim(),\n role: memberForm.role,\n status: memberForm.status,\n position: memberForm.position.trim() || undefined,\n jerseyNumber: jersey,\n });\n setMemberForm(EMPTY_MEMBER);\n setAddOpen(false);\n } catch (err) {\n setMemberError(err instanceof Error ? err.message : 'Failed to add member.');\n }\n };\n\n return (\n <PageLayout\n title={t.name}\n description={`${SPORT_LABELS[t.sport]}${t.season ? ` · ${t.season}` : ''}`}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/teams')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 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 <button\n type=\"button\"\n onClick={() => navigateTo(`/teams/${t.id}/edit`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Edit className=\"h-4 w-4\" /> Edit\n </button>\n {t.status !== 'ARCHIVED' && (\n <button\n type=\"button\"\n onClick={handleArchive}\n disabled={archiveTeam.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-60\"\n >\n {archiveTeam.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Archive className=\"h-4 w-4\" />\n )}{' '}\n Archive\n </button>\n )}\n </div>\n }\n >\n {/* Summary */}\n <GlassCard treatment=\"insight\" className=\"mb-8 p-6\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <StatusBadge status={t.status} />\n {t.ageGroup && (\n <span className=\"text-sm text-text-secondary\">Age group: {t.ageGroup}</span>\n )}\n {t.homeVenue && (\n <span className=\"flex items-center gap-1 text-sm text-text-secondary\">\n <MapPin className=\"h-3.5 w-3.5\" /> {t.homeVenue}\n </span>\n )}\n </div>\n {t.description && <p className=\"mt-4 text-sm text-text-secondary\">{t.description}</p>}\n {t.tags.length > 0 && (\n <div className=\"mt-4 flex flex-wrap gap-1.5\">\n {t.tags.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n </span>\n ))}\n </div>\n )}\n </GlassCard>\n\n {/* Roster */}\n <section className=\"mb-8\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Roster ({members.length})</h2>\n <button\n type=\"button\"\n onClick={() => {\n setMemberError(null);\n setAddOpen(true);\n }}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <UserPlus className=\"h-4 w-4\" /> Add member\n </button>\n </div>\n\n {members.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<UserPlus className=\"h-10 w-10\" />}\n title=\"No members yet\"\n description=\"Add players, coaches and staff to build the roster.\"\n />\n ) : (\n <EmphasisPanel>\n <div className=\"divide-y divide-border-seam\">\n {members.map((m) => (\n <div key={m.id} className=\"flex items-center gap-4 py-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold tabular-nums text-text-primary\">\n {m.jerseyNumber ?? m.displayName.charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {m.displayName}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {MEMBER_ROLE_LABELS[m.role]}\n {m.position ? ` · ${m.position}` : ''}\n </p>\n </div>\n <StatusBadge status={m.status} />\n <button\n type=\"button\"\n onClick={() => void removeMember.mutate(m.id)}\n disabled={removeMember.isPending}\n aria-label={`Remove ${m.displayName}`}\n className=\"rounded-lg p-2 text-text-secondary transition-colors hover:bg-status-error-bg-subtle hover:text-status-error-text disabled:opacity-60\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n )}\n </section>\n\n {/* Fixtures */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Fixtures ({fixtures.length})</h2>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/fixtures/new?homeTeamId=${t.id}`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" /> Schedule\n </button>\n </div>\n {fixtures.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<CalendarDays className=\"h-10 w-10\" />}\n title=\"No fixtures scheduled\"\n description=\"Schedule a match for this team to start tracking results.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {fixtures.map((f) => (\n <FixtureCard key={f.id} fixture={f} onClick={() => navigateTo(`/fixtures/${f.id}`)} />\n ))}\n </div>\n )}\n </section>\n\n {/* Add member dialog */}\n <ResponsiveDialog open={addOpen} onOpenChange={setAddOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Add member</ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <form onSubmit={handleAddMember} className=\"space-y-4 px-1\">\n <FormField label=\"User ID\" htmlFor=\"userId\" required hint=\"The auth-svc user id.\">\n <input\n id=\"userId\"\n className={fieldInputClass}\n value={memberForm.userId}\n onChange={(e) => setMemberForm((p) => ({ ...p, userId: e.target.value }))}\n placeholder=\"user-uuid\"\n />\n </FormField>\n <FormField label=\"Display name\" htmlFor=\"displayName\" required>\n <input\n id=\"displayName\"\n className={fieldInputClass}\n value={memberForm.displayName}\n onChange={(e) => setMemberForm((p) => ({ ...p, displayName: e.target.value }))}\n placeholder=\"e.g. Alex Morgan\"\n />\n </FormField>\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Role\" htmlFor=\"role\">\n <select\n id=\"role\"\n className={fieldInputClass}\n value={memberForm.role}\n onChange={(e) =>\n setMemberForm((p) => ({ ...p, role: e.target.value as AthMemberRole }))\n }\n >\n {ROLES.map((r) => (\n <option key={r} value={r}>\n {MEMBER_ROLE_LABELS[r]}\n </option>\n ))}\n </select>\n </FormField>\n <FormField label=\"Status\" htmlFor=\"memberStatus\">\n <select\n id=\"memberStatus\"\n className={fieldInputClass}\n value={memberForm.status}\n onChange={(e) =>\n setMemberForm((p) => ({ ...p, status: e.target.value as AthMemberStatus }))\n }\n >\n {MEMBER_STATUSES.map((s) => (\n <option key={s} value={s}>\n {s.charAt(0) + s.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </FormField>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Position\" htmlFor=\"position\">\n <input\n id=\"position\"\n className={fieldInputClass}\n value={memberForm.position}\n onChange={(e) => setMemberForm((p) => ({ ...p, position: e.target.value }))}\n placeholder=\"e.g. Striker\"\n />\n </FormField>\n <FormField label=\"Jersey #\" htmlFor=\"jersey\">\n <input\n id=\"jersey\"\n className={fieldInputClass}\n inputMode=\"numeric\"\n value={memberForm.jerseyNumber}\n onChange={(e) => setMemberForm((p) => ({ ...p, jerseyNumber: e.target.value }))}\n placeholder=\"9\"\n />\n </FormField>\n </div>\n {memberError && <p className=\"text-sm text-status-error-text\">{memberError}</p>}\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={() => setAddOpen(false)}\n className=\"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 Cancel\n </button>\n <button\n type=\"submit\"\n disabled={addMember.isPending}\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 disabled:opacity-60\"\n >\n {addMember.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n Add member\n </button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TeamDetailPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/teams/TeamDetailPage.tsx"],"sourcesContent":["/**\n * Team Detail\n * @module atheletebridge/pages/teams\n *\n * Reads a single team (with members + fixtures) from `athTeam`, supports adding\n * and removing members (athAddMember / athRemoveMember), editing and archiving\n * the team (athUpdateTeam via the form / athArchiveTeam), and links into the\n * team's fixtures.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n CalendarDays,\n Edit,\n Archive,\n MapPin,\n Plus,\n Trash2,\n UserPlus,\n Loader2,\n} from 'lucide-react';\nimport {\n GlassCard,\n EmphasisPanel,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { FixtureCard } from '../../components/FixtureCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { UserSearchSelect } from '../../components/UserSearchSelect';\nimport { SPORT_LABELS, MEMBER_ROLE_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport {\n useTeam,\n useArchiveTeam,\n useAddMember,\n useRemoveMember,\n} from '../../hooks/useAthleteBridgeApi';\nimport type { AthMemberRole, AthMemberStatus } from '../../types';\n\nconst ROLES = Object.keys(MEMBER_ROLE_LABELS) as AthMemberRole[];\nconst MEMBER_STATUSES: AthMemberStatus[] = ['TRIAL', 'ACTIVE', 'INJURED', 'SUSPENDED', 'RELEASED'];\n\ninterface AddMemberForm {\n userId: string;\n displayName: string;\n role: AthMemberRole;\n status: AthMemberStatus;\n position: string;\n jerseyNumber: string;\n}\n\nconst EMPTY_MEMBER: AddMemberForm = {\n userId: '',\n displayName: '',\n role: 'PLAYER',\n status: 'ACTIVE',\n position: '',\n jerseyNumber: '',\n};\n\nexport function TeamDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useAthleteBridge();\n\n const team = useTeam(id);\n const archiveTeam = useArchiveTeam();\n const addMember = useAddMember();\n const removeMember = useRemoveMember(id);\n\n const [addOpen, setAddOpen] = useState(false);\n const [memberForm, setMemberForm] = useState<AddMemberForm>(EMPTY_MEMBER);\n const [memberError, setMemberError] = useState<string | null>(null);\n\n if (team.isLoading) {\n return (\n <PageLayout title=\"Team\">\n <LoadingState label=\"Loading team…\" />\n </PageLayout>\n );\n }\n\n if (team.isError || !team.data) {\n return (\n <PageLayout title=\"Team\">\n <ErrorState\n title=\"Team not found\"\n message=\"This team does not exist or you do not have access to it.\"\n onRetry={() => navigateTo('/teams')}\n />\n </PageLayout>\n );\n }\n\n const t = team.data;\n const members = t.members ?? [];\n const fixtures = t.fixtures ?? [];\n\n const handleArchive = async () => {\n if (!id) return;\n await archiveTeam.mutateAsync(id);\n navigateTo('/teams');\n };\n\n const handleAddMember = async (e: React.FormEvent) => {\n e.preventDefault();\n setMemberError(null);\n if (!id) return;\n if (!memberForm.userId.trim() || !memberForm.displayName.trim()) {\n setMemberError('User ID and display name are required.');\n return;\n }\n const jersey = memberForm.jerseyNumber.trim()\n ? Number.parseInt(memberForm.jerseyNumber, 10)\n : undefined;\n if (jersey !== undefined && Number.isNaN(jersey)) {\n setMemberError('Jersey number must be a number.');\n return;\n }\n try {\n await addMember.mutateAsync({\n teamId: id,\n userId: memberForm.userId.trim(),\n displayName: memberForm.displayName.trim(),\n role: memberForm.role,\n status: memberForm.status,\n position: memberForm.position.trim() || undefined,\n jerseyNumber: jersey,\n });\n setMemberForm(EMPTY_MEMBER);\n setAddOpen(false);\n } catch (err) {\n setMemberError(err instanceof Error ? err.message : 'Failed to add member.');\n }\n };\n\n return (\n <PageLayout\n title={t.name}\n description={`${SPORT_LABELS[t.sport]}${t.season ? ` · ${t.season}` : ''}`}\n actions={\n <div className=\"flex flex-wrap items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => navigateTo('/teams')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 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 <button\n type=\"button\"\n onClick={() => navigateTo(`/teams/${t.id}/edit`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Edit className=\"h-4 w-4\" /> Edit\n </button>\n {t.status !== 'ARCHIVED' && (\n <button\n type=\"button\"\n onClick={handleArchive}\n disabled={archiveTeam.isPending}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-2 text-sm font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle disabled:opacity-60\"\n >\n {archiveTeam.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Archive className=\"h-4 w-4\" />\n )}{' '}\n Archive\n </button>\n )}\n </div>\n }\n >\n {/* Summary */}\n <GlassCard treatment=\"insight\" className=\"mb-8 p-6\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <StatusBadge status={t.status} />\n {t.ageGroup && (\n <span className=\"text-sm text-text-secondary\">Age group: {t.ageGroup}</span>\n )}\n {t.homeVenue && (\n <span className=\"flex items-center gap-1 text-sm text-text-secondary\">\n <MapPin className=\"h-3.5 w-3.5\" /> {t.homeVenue}\n </span>\n )}\n </div>\n {t.description && <p className=\"mt-4 text-sm text-text-secondary\">{t.description}</p>}\n {t.tags.length > 0 && (\n <div className=\"mt-4 flex flex-wrap gap-1.5\">\n {t.tags.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n </span>\n ))}\n </div>\n )}\n </GlassCard>\n\n {/* Roster */}\n <section className=\"mb-8\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Roster ({members.length})</h2>\n <button\n type=\"button\"\n onClick={() => {\n setMemberError(null);\n setAddOpen(true);\n }}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-3 py-1.5 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <UserPlus className=\"h-4 w-4\" /> Add member\n </button>\n </div>\n\n {members.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<UserPlus className=\"h-10 w-10\" />}\n title=\"No members yet\"\n description=\"Add players, coaches and staff to build the roster.\"\n />\n ) : (\n <EmphasisPanel>\n <div className=\"divide-y divide-border-seam\">\n {members.map((m) => (\n <div key={m.id} className=\"flex items-center gap-4 py-3\">\n <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold tabular-nums text-text-primary\">\n {m.jerseyNumber ?? m.displayName.charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {m.displayName}\n </p>\n <p className=\"text-xs text-text-secondary\">\n {MEMBER_ROLE_LABELS[m.role]}\n {m.position ? ` · ${m.position}` : ''}\n </p>\n </div>\n <StatusBadge status={m.status} />\n <button\n type=\"button\"\n onClick={() => void removeMember.mutate(m.id)}\n disabled={removeMember.isPending}\n aria-label={`Remove ${m.displayName}`}\n className=\"rounded-lg p-2 text-text-secondary transition-colors hover:bg-status-error-bg-subtle hover:text-status-error-text disabled:opacity-60\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n )}\n </section>\n\n {/* Fixtures */}\n <section>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Fixtures ({fixtures.length})</h2>\n <button\n type=\"button\"\n onClick={() => navigateTo(`/fixtures/new?homeTeamId=${t.id}`)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Plus className=\"h-4 w-4\" /> Schedule\n </button>\n </div>\n {fixtures.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<CalendarDays className=\"h-10 w-10\" />}\n title=\"No fixtures scheduled\"\n description=\"Schedule a match for this team to start tracking results.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {fixtures.map((f) => (\n <FixtureCard key={f.id} fixture={f} onClick={() => navigateTo(`/fixtures/${f.id}`)} />\n ))}\n </div>\n )}\n </section>\n\n {/* Add member dialog */}\n <ResponsiveDialog open={addOpen} onOpenChange={setAddOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Add member</ResponsiveDialogTitle>\n </ResponsiveDialogHeader>\n <form onSubmit={handleAddMember} className=\"space-y-4 px-1\">\n <UserSearchSelect\n userId={memberForm.userId}\n displayName={memberForm.displayName}\n onSelect={({ userId, displayName }) =>\n setMemberForm((p) => ({ ...p, userId, displayName: displayName || p.displayName }))\n }\n required\n />\n <FormField label=\"Display name\" htmlFor=\"displayName\" required>\n <input\n id=\"displayName\"\n className={fieldInputClass}\n value={memberForm.displayName}\n onChange={(e) => setMemberForm((p) => ({ ...p, displayName: e.target.value }))}\n placeholder=\"e.g. Alex Morgan\"\n />\n </FormField>\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Role\" htmlFor=\"role\">\n <select\n id=\"role\"\n className={fieldInputClass}\n value={memberForm.role}\n onChange={(e) =>\n setMemberForm((p) => ({ ...p, role: e.target.value as AthMemberRole }))\n }\n >\n {ROLES.map((r) => (\n <option key={r} value={r}>\n {MEMBER_ROLE_LABELS[r]}\n </option>\n ))}\n </select>\n </FormField>\n <FormField label=\"Status\" htmlFor=\"memberStatus\">\n <select\n id=\"memberStatus\"\n className={fieldInputClass}\n value={memberForm.status}\n onChange={(e) =>\n setMemberForm((p) => ({ ...p, status: e.target.value as AthMemberStatus }))\n }\n >\n {MEMBER_STATUSES.map((s) => (\n <option key={s} value={s}>\n {s.charAt(0) + s.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </FormField>\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <FormField label=\"Position\" htmlFor=\"position\">\n <input\n id=\"position\"\n className={fieldInputClass}\n value={memberForm.position}\n onChange={(e) => setMemberForm((p) => ({ ...p, position: e.target.value }))}\n placeholder=\"e.g. Striker\"\n />\n </FormField>\n <FormField label=\"Jersey #\" htmlFor=\"jersey\">\n <input\n id=\"jersey\"\n className={fieldInputClass}\n inputMode=\"numeric\"\n value={memberForm.jerseyNumber}\n onChange={(e) => setMemberForm((p) => ({ ...p, jerseyNumber: e.target.value }))}\n placeholder=\"9\"\n />\n </FormField>\n </div>\n {memberError && <p className=\"text-sm text-status-error-text\">{memberError}</p>}\n <ResponsiveDialogFooter>\n <button\n type=\"button\"\n onClick={() => setAddOpen(false)}\n className=\"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 Cancel\n </button>\n <button\n type=\"submit\"\n disabled={addMember.isPending}\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 disabled:opacity-60\"\n >\n {addMember.isPending && <Loader2 className=\"h-4 w-4 animate-spin\" />}\n Add member\n </button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
//#region src/atheletebridge/utils/formatters.ts
|
|
2
2
|
function e(e, t) {
|
|
3
|
-
return new Intl.NumberFormat("en-IN", {
|
|
4
|
-
style: "currency",
|
|
5
|
-
currency: "INR",
|
|
6
|
-
minimumFractionDigits: 2,
|
|
7
|
-
maximumFractionDigits: 2,
|
|
8
|
-
...t
|
|
9
|
-
}).format(e);
|
|
10
|
-
}
|
|
11
|
-
function t(e, t) {
|
|
12
3
|
let n = typeof e == "string" ? new Date(e) : e;
|
|
13
4
|
return new Intl.DateTimeFormat("en-IN", {
|
|
14
5
|
day: "numeric",
|
|
@@ -20,21 +11,7 @@ function t(e, t) {
|
|
|
20
11
|
...t
|
|
21
12
|
}).format(n);
|
|
22
13
|
}
|
|
23
|
-
function
|
|
24
|
-
let t = typeof e == "string" ? new Date(e) : e, n = (/* @__PURE__ */ new Date()).getTime() - t.getTime(), r = Math.floor(n / 1e3), i = Math.floor(r / 60), a = Math.floor(i / 60), o = Math.floor(a / 24), s = Math.floor(o / 7), c = Math.floor(o / 30);
|
|
25
|
-
if (r < 60) return "just now";
|
|
26
|
-
if (i < 60) return `${i} min${i === 1 ? "" : "s"} ago`;
|
|
27
|
-
if (a < 24) return `${a} hour${a === 1 ? "" : "s"} ago`;
|
|
28
|
-
if (o < 7) return `${o} day${o === 1 ? "" : "s"} ago`;
|
|
29
|
-
if (s < 4) return `${s} week${s === 1 ? "" : "s"} ago`;
|
|
30
|
-
if (c < 12) return `${c} month${c === 1 ? "" : "s"} ago`;
|
|
31
|
-
let l = Math.floor(o / 365);
|
|
32
|
-
return `${l} year${l === 1 ? "" : "s"} ago`;
|
|
33
|
-
}
|
|
34
|
-
function r(e, t) {
|
|
35
|
-
return new Intl.NumberFormat("en-IN", t).format(e);
|
|
36
|
-
}
|
|
37
|
-
function i(e) {
|
|
14
|
+
function t(e) {
|
|
38
15
|
if (e < 1) return "instant";
|
|
39
16
|
if (e < 60) return `${e} min`;
|
|
40
17
|
let t = Math.floor(e / 60), n = e % 60;
|
|
@@ -43,6 +20,6 @@ function i(e) {
|
|
|
43
20
|
return i === 0 ? `${r} day${r === 1 ? "" : "s"}` : `${r} day${r === 1 ? "" : "s"} ${i}h`;
|
|
44
21
|
}
|
|
45
22
|
//#endregion
|
|
46
|
-
export { e as
|
|
23
|
+
export { e as formatDate, t as formatDuration };
|
|
47
24
|
|
|
48
25
|
//# sourceMappingURL=formatters.js.map
|