@burdenoff/microfe-atheletebridge 2026.731.1 → 2026.801.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 (25) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoutes.js +1 -1
  2. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  3. package/dist/atheletebridge/components/RouteAnalytics.js +1 -1
  4. package/dist/atheletebridge/components/RouteAnalytics.js.map +1 -1
  5. package/dist/atheletebridge/context/AthleteBridgeContext.js +1 -1
  6. package/dist/atheletebridge/context/AthleteBridgeContext.js.map +1 -1
  7. package/dist/atheletebridge/pages/StandingsPage.js +1 -1
  8. package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
  9. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js +1 -1
  10. package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js.map +1 -1
  11. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +1 -1
  12. package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -1
  13. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js +1 -1
  14. package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js.map +1 -1
  15. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +1 -1
  16. package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
  17. package/dist/atheletebridge/pages/programs/ProgramFormPage.js +1 -1
  18. package/dist/atheletebridge/pages/programs/ProgramFormPage.js.map +1 -1
  19. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js +1 -1
  20. package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
  21. package/dist/atheletebridge/pages/teams/TeamDetailPage.js +1 -1
  22. package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
  23. package/dist/atheletebridge/pages/teams/TeamFormPage.js +1 -1
  24. package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
  25. package/package.json +4 -4
@@ -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 * editing (athUpdateMember — role/position/jersey/status inline per roster row)\n * and removing members (athAddMember / athRemoveMember), editing and archiving\n * the team (athUpdateTeam via the form / athArchiveTeam), links each roster row\n * to the athlete profile, and renders the team's fixtures as crest-vs-crest\n * matchup rows.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n CalendarDays,\n Check,\n Edit,\n Archive,\n MapPin,\n Pencil,\n Plus,\n Trash2,\n UserPlus,\n Loader2,\n X,\n} from 'lucide-react';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch, clearGraphqlFetchResponseCache } from '@burdenoff/fe-libs/shared/graphql';\nimport {\n GlassCard,\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 { Crest } from '../../components/Crest';\nimport { UserAvatar } from '../../components/UserAvatar';\nimport { MatchupRow } from '../../components/MatchupRow';\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 { AthMember, AthMemberRole, AthMemberStatus, AthUpdateMemberInput } from '../../types';\n\nconst ROLES = Object.keys(MEMBER_ROLE_LABELS) as AthMemberRole[];\nconst MEMBER_STATUSES: AthMemberStatus[] = ['TRIAL', 'ACTIVE', 'INJURED', 'SUSPENDED', 'RELEASED'];\n\nconst memberStatusLabel = (s: AthMemberStatus): string => s.charAt(0) + s.slice(1).toLowerCase();\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\ninterface RowDraft {\n role: AthMemberRole;\n status: AthMemberStatus;\n position: string;\n jerseyNumber: string;\n}\n\n/**\n * Inline roster-member update wired directly to the shipped `athUpdateMember`\n * mutation (the shared kit has add/remove hooks but no update hook). Uses the\n * same workspace-token graphqlFetch primitive as the rest of the MFE and clears\n * the short-lived read cache so the team refetch is fresh.\n */\nconst useUpdateMemberInline = (teamId: string | undefined) => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useAthleteBridge();\n return useMutation({\n mutationFn: async ({ id, input }: { id: string; input: AthUpdateMemberInput }) => {\n const res = await graphqlFetch<{ athUpdateMember: AthMember }>({\n gateway: 'workspace',\n baseUrl: apiGatewayUrl,\n query: `mutation AthUpdateMember($id: ID!, $input: AthUpdateMemberInput!) {\n athUpdateMember(id: $id, input: $input) {\n id teamId displayName role status position jerseyNumber\n }\n }`,\n variables: { id, input },\n workspaceToken: true,\n });\n if (res.errors?.length) {\n throw new Error(res.errors[0]?.message ?? 'Failed to update member.');\n }\n clearGraphqlFetchResponseCache();\n if (!res.data) throw new Error('Update did not return data.');\n return res.data.athUpdateMember;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: ['atheletebridge', 'team', teamId] });\n void queryClient.invalidateQueries({ queryKey: ['atheletebridge', 'members', teamId] });\n },\n });\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 const updateMember = useUpdateMemberInline(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 const [editingId, setEditingId] = useState<string | null>(null);\n const [draft, setDraft] = useState<RowDraft | null>(null);\n const [rowError, setRowError] = 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?.items ?? [];\n const fixtures = t.fixtures?.items ?? [];\n\n const metaParts = [\n SPORT_LABELS[t.sport],\n t.ageGroup ?? undefined,\n t.season ?? undefined,\n t.homeVenue ?? undefined,\n ].filter(Boolean) as string[];\n\n const handleArchive = async () => {\n if (!id) return;\n await archiveTeam.mutateAsync(id);\n navigateTo('/teams');\n };\n\n const startEdit = (m: AthMember) => {\n setRowError(null);\n setEditingId(m.id);\n setDraft({\n role: m.role,\n status: m.status,\n position: m.position ?? '',\n jerseyNumber: m.jerseyNumber != null ? String(m.jerseyNumber) : '',\n });\n };\n\n const cancelEdit = () => {\n setEditingId(null);\n setDraft(null);\n setRowError(null);\n };\n\n const saveEdit = async (memberId: string) => {\n if (!draft) return;\n setRowError(null);\n const trimmedJersey = draft.jerseyNumber.trim();\n let jersey: number | undefined;\n if (trimmedJersey) {\n jersey = Number.parseInt(trimmedJersey, 10);\n if (Number.isNaN(jersey)) {\n setRowError('Jersey number must be a number.');\n return;\n }\n }\n try {\n await updateMember.mutateAsync({\n id: memberId,\n input: {\n role: draft.role,\n status: draft.status,\n position: draft.position.trim() || undefined,\n jerseyNumber: jersey,\n },\n });\n cancelEdit();\n } catch (err) {\n setRowError(err instanceof Error ? err.message : 'Failed to update member.');\n }\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 const openProfile = (memberId: string) => navigateTo(`/teams/${t.id}/athletes/${memberId}`);\n\n return (\n <PageLayout\n title={t.name}\n gradientTitle\n description={metaParts.join(' · ')}\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 bg-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\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 {/* Hero: crest + meta strip */}\n <GlassCard treatment=\"insight\" className=\"mb-8 p-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\n <Crest name={t.name} sport={t.sport} size={64} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h2 className=\"text-xl font-semibold text-text-primary\">{t.name}</h2>\n <StatusBadge status={t.status} />\n </div>\n <div className=\"mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-sm text-text-secondary\">\n {metaParts.map((part, i) => (\n <span key={part} className=\"flex items-center gap-2\">\n {i > 0 && (\n <span aria-hidden=\"true\" className=\"text-text-muted\">\n ·\n </span>\n )}\n {part === t.homeVenue ? (\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> {part}\n </span>\n ) : (\n part\n )}\n </span>\n ))}\n </div>\n </div>\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-semibold 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 <GlassCard treatment=\"insight\" className=\"overflow-hidden p-0\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[720px] border-collapse 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-4 py-3 font-medium\">Player</th>\n <th className=\"px-4 py-3 font-medium\">Role</th>\n <th className=\"px-4 py-3 font-medium\">Position</th>\n <th className=\"px-4 py-3 font-medium\">Jersey #</th>\n <th className=\"px-4 py-3 font-medium\">Status</th>\n <th className=\"px-4 py-3 text-right font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-seam\">\n {members.map((m) => {\n const isEditing = editingId === m.id;\n const busy = updateMember.isPending && isEditing;\n return (\n <tr\n key={m.id}\n className=\"align-middle transition-colors hover:bg-bg-sunken/60\"\n >\n {/* Player */}\n <td className=\"px-4 py-3\">\n <button\n type=\"button\"\n onClick={() => openProfile(m.id)}\n className=\"group flex items-center gap-3 text-left focus-visible:outline-none\"\n title={`View ${m.displayName}'s profile`}\n >\n <UserAvatar\n name={m.displayName}\n id={m.userId}\n jersey={m.jerseyNumber}\n size=\"sm\"\n />\n <span className=\"min-w-0\">\n <span className=\"block truncate font-medium text-text-primary group-hover:text-text-link\">\n {m.displayName}\n </span>\n <span className=\"block truncate text-xs text-text-secondary group-hover:text-text-link\">\n View profile\n </span>\n </span>\n </button>\n </td>\n\n {/* Role */}\n <td className=\"px-4 py-3\">\n {isEditing && draft ? (\n <select\n aria-label=\"Role\"\n className={fieldInputClass}\n value={draft.role}\n onChange={(e) =>\n setDraft((d) =>\n d ? { ...d, role: e.target.value as AthMemberRole } : d\n )\n }\n >\n {ROLES.map((r) => (\n <option key={r} value={r}>\n {MEMBER_ROLE_LABELS[r]}\n </option>\n ))}\n </select>\n ) : (\n <span className=\"text-text-secondary\">\n {MEMBER_ROLE_LABELS[m.role]}\n </span>\n )}\n </td>\n\n {/* Position */}\n <td className=\"px-4 py-3\">\n {isEditing && draft ? (\n <input\n aria-label=\"Position\"\n className={fieldInputClass}\n value={draft.position}\n onChange={(e) =>\n setDraft((d) => (d ? { ...d, position: e.target.value } : d))\n }\n placeholder=\"e.g. Striker\"\n />\n ) : (\n <span className=\"text-text-secondary\">{m.position || '—'}</span>\n )}\n </td>\n\n {/* Jersey # */}\n <td className=\"px-4 py-3\">\n {isEditing && draft ? (\n <input\n aria-label=\"Jersey number\"\n inputMode=\"numeric\"\n className={`${fieldInputClass} w-20`}\n value={draft.jerseyNumber}\n onChange={(e) =>\n setDraft((d) => (d ? { ...d, jerseyNumber: e.target.value } : d))\n }\n placeholder=\"9\"\n />\n ) : (\n <span className=\"tabular-nums text-text-primary\">\n {m.jerseyNumber ?? '—'}\n </span>\n )}\n </td>\n\n {/* Status */}\n <td className=\"px-4 py-3\">\n {isEditing && draft ? (\n <select\n aria-label=\"Status\"\n className={fieldInputClass}\n value={draft.status}\n onChange={(e) =>\n setDraft((d) =>\n d ? { ...d, status: e.target.value as AthMemberStatus } : d\n )\n }\n >\n {MEMBER_STATUSES.map((s) => (\n <option key={s} value={s}>\n {memberStatusLabel(s)}\n </option>\n ))}\n </select>\n ) : (\n <StatusBadge status={m.status} />\n )}\n </td>\n\n {/* Actions */}\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center justify-end gap-1\">\n {isEditing ? (\n <>\n <button\n type=\"button\"\n onClick={() => void saveEdit(m.id)}\n disabled={busy}\n aria-label=\"Save changes\"\n className=\"rounded-lg p-2 text-status-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-60\"\n >\n {busy ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Check className=\"h-4 w-4\" />\n )}\n </button>\n <button\n type=\"button\"\n onClick={cancelEdit}\n disabled={busy}\n aria-label=\"Cancel editing\"\n className=\"rounded-lg p-2 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary disabled:opacity-60\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n onClick={() => startEdit(m)}\n aria-label={`Edit ${m.displayName}`}\n className=\"rounded-lg p-2 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <Pencil className=\"h-4 w-4\" />\n </button>\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 </>\n )}\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n {rowError && (\n <p className=\"border-t border-border-seam px-4 py-2 text-sm text-status-error-text\">\n {rowError}\n </p>\n )}\n </GlassCard>\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 <div className=\"flex items-center gap-2\">\n {fixtures.length > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures')}\n className=\"text-sm font-medium text-text-link transition-colors hover:underline\"\n >\n View all\n </button>\n )}\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 </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 <GlassCard treatment=\"insight\" className=\"px-4 py-1\">\n <div className=\"divide-y divide-border-seam\">\n {fixtures.map((f) => (\n <MatchupRow\n key={f.id}\n fixture={f}\n onClick={() => navigateTo(`/fixtures/${f.id}`)}\n />\n ))}\n </div>\n </GlassCard>\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 {memberStatusLabel(s)}\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-semibold 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 * editing (athUpdateMember — role/position/jersey/status inline per roster row)\n * and removing members (athAddMember / athRemoveMember), editing and archiving\n * the team (athUpdateTeam via the form / athArchiveTeam), links each roster row\n * to the athlete profile, and renders the team's fixtures as crest-vs-crest\n * matchup rows.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n CalendarDays,\n Check,\n Edit,\n Archive,\n MapPin,\n Pencil,\n Plus,\n Trash2,\n UserPlus,\n Loader2,\n X,\n} from 'lucide-react';\nimport { useMutation, useQueryClient } from '@tanstack/react-query';\nimport { graphqlFetch, clearGraphqlFetchResponseCache } from '@burdenoff/fe-libs/shared/graphql';\nimport {\n GlassCard,\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 { Crest } from '../../components/Crest';\nimport { UserAvatar } from '../../components/UserAvatar';\nimport { MatchupRow } from '../../components/MatchupRow';\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 { AthMember, AthMemberRole, AthMemberStatus, AthUpdateMemberInput } from '../../types';\n\nconst ROLES = Object.keys(MEMBER_ROLE_LABELS) as AthMemberRole[];\nconst MEMBER_STATUSES: AthMemberStatus[] = ['TRIAL', 'ACTIVE', 'INJURED', 'SUSPENDED', 'RELEASED'];\n\nconst memberStatusLabel = (s: AthMemberStatus): string => s.charAt(0) + s.slice(1).toLowerCase();\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\ninterface RowDraft {\n role: AthMemberRole;\n status: AthMemberStatus;\n position: string;\n jerseyNumber: string;\n}\n\n/**\n * Inline roster-member update wired directly to the shipped `athUpdateMember`\n * mutation (the shared kit has add/remove hooks but no update hook). Uses the\n * same workspace-token graphqlFetch primitive as the rest of the MFE and clears\n * the short-lived read cache so the team refetch is fresh.\n */\nconst useUpdateMemberInline = (teamId: string | undefined) => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useAthleteBridge();\n return useMutation({\n mutationFn: async ({ id, input }: { id: string; input: AthUpdateMemberInput }) => {\n const res = await graphqlFetch<{ athUpdateMember: AthMember }>({\n gateway: 'workspace',\n baseUrl: apiGatewayUrl,\n query: `mutation AthUpdateMember($id: ID!, $input: AthUpdateMemberInput!) {\n athUpdateMember(id: $id, input: $input) {\n id teamId displayName role status position jerseyNumber\n }\n }`,\n variables: { id, input },\n workspaceToken: true,\n });\n if (res.errors?.length) {\n throw new Error(res.errors[0]?.message ?? 'Failed to update member.');\n }\n clearGraphqlFetchResponseCache();\n if (!res.data) throw new Error('Update did not return data.');\n return res.data.athUpdateMember;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: ['atheletebridge', 'team', teamId] });\n void queryClient.invalidateQueries({ queryKey: ['atheletebridge', 'members', teamId] });\n },\n });\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 const updateMember = useUpdateMemberInline(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 const [editingId, setEditingId] = useState<string | null>(null);\n const [draft, setDraft] = useState<RowDraft | null>(null);\n const [rowError, setRowError] = 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?.items ?? [];\n const fixtures = t.fixtures?.items ?? [];\n\n const metaParts = [\n SPORT_LABELS[t.sport],\n t.ageGroup ?? undefined,\n t.season ?? undefined,\n t.homeVenue ?? undefined,\n ].filter(Boolean) as string[];\n\n const handleArchive = async () => {\n if (!id) return;\n await archiveTeam.mutateAsync(id);\n navigateTo('/teams');\n };\n\n const startEdit = (m: AthMember) => {\n setRowError(null);\n setEditingId(m.id);\n setDraft({\n role: m.role,\n status: m.status,\n position: m.position ?? '',\n jerseyNumber: m.jerseyNumber != null ? String(m.jerseyNumber) : '',\n });\n };\n\n const cancelEdit = () => {\n setEditingId(null);\n setDraft(null);\n setRowError(null);\n };\n\n const saveEdit = async (memberId: string) => {\n if (!draft) return;\n setRowError(null);\n const trimmedJersey = draft.jerseyNumber.trim();\n let jersey: number | undefined;\n if (trimmedJersey) {\n jersey = Number.parseInt(trimmedJersey, 10);\n if (Number.isNaN(jersey)) {\n setRowError('Jersey number must be a number.');\n return;\n }\n }\n try {\n await updateMember.mutateAsync({\n id: memberId,\n input: {\n role: draft.role,\n status: draft.status,\n position: draft.position.trim() || undefined,\n jerseyNumber: jersey,\n },\n });\n cancelEdit();\n } catch (err) {\n setRowError(err instanceof Error ? err.message : 'Failed to update member.');\n }\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 const openProfile = (memberId: string) => navigateTo(`/teams/${t.id}/athletes/${memberId}`);\n\n return (\n <PageLayout\n title={t.name}\n gradientTitle\n description={metaParts.join(' · ')}\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 bg-action-primary-bg px-4 py-2 text-sm font-semibold text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\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 {/* Hero: crest + meta strip */}\n <GlassCard treatment=\"insight\" className=\"mb-8 p-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\n <Crest name={t.name} sport={t.sport} size={64} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <h2 className=\"text-xl font-semibold text-text-primary\">{t.name}</h2>\n <StatusBadge status={t.status} />\n </div>\n <div className=\"mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-sm text-text-secondary\">\n {metaParts.map((part, i) => (\n <span key={part} className=\"flex items-center gap-2\">\n {i > 0 && (\n <span aria-hidden=\"true\" className=\"text-text-muted\">\n ·\n </span>\n )}\n {part === t.homeVenue ? (\n <span className=\"flex items-center gap-1\">\n <MapPin className=\"h-3.5 w-3.5\" aria-hidden=\"true\" /> {part}\n </span>\n ) : (\n part\n )}\n </span>\n ))}\n </div>\n </div>\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-semibold 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 <GlassCard treatment=\"insight\" className=\"overflow-hidden p-0\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full min-w-[720px] border-collapse 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-4 py-3 font-medium\">Player</th>\n <th className=\"px-4 py-3 font-medium\">Role</th>\n <th className=\"px-4 py-3 font-medium\">Position</th>\n <th className=\"px-4 py-3 font-medium\">Jersey #</th>\n <th className=\"px-4 py-3 font-medium\">Status</th>\n <th className=\"px-4 py-3 text-right font-medium\">Actions</th>\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border-seam\">\n {members.map((m) => {\n const isEditing = editingId === m.id;\n const busy = updateMember.isPending && isEditing;\n return (\n <tr\n key={m.id}\n className=\"align-middle transition-colors hover:bg-bg-sunken/60\"\n >\n {/* Player */}\n <td className=\"px-4 py-3\">\n <button\n type=\"button\"\n onClick={() => openProfile(m.id)}\n className=\"group flex items-center gap-3 text-left focus-visible:outline-none\"\n title={`View ${m.displayName}'s profile`}\n >\n <UserAvatar\n name={m.displayName}\n id={m.userId}\n jersey={m.jerseyNumber}\n size=\"sm\"\n />\n <span className=\"min-w-0\">\n <span className=\"block truncate font-medium text-text-primary group-hover:text-text-link\">\n {m.displayName}\n </span>\n <span className=\"block truncate text-xs text-text-secondary group-hover:text-text-link\">\n View profile\n </span>\n </span>\n </button>\n </td>\n\n {/* Role */}\n <td className=\"px-4 py-3\">\n {isEditing && draft ? (\n <select\n aria-label=\"Role\"\n className={fieldInputClass}\n value={draft.role}\n onChange={(e) =>\n setDraft((d) =>\n d ? { ...d, role: e.target.value as AthMemberRole } : d\n )\n }\n >\n {ROLES.map((r) => (\n <option key={r} value={r}>\n {MEMBER_ROLE_LABELS[r]}\n </option>\n ))}\n </select>\n ) : (\n <span className=\"text-text-secondary\">\n {MEMBER_ROLE_LABELS[m.role]}\n </span>\n )}\n </td>\n\n {/* Position */}\n <td className=\"px-4 py-3\">\n {isEditing && draft ? (\n <input\n aria-label=\"Position\"\n className={fieldInputClass}\n value={draft.position}\n onChange={(e) =>\n setDraft((d) => (d ? { ...d, position: e.target.value } : d))\n }\n placeholder=\"e.g. Striker\"\n />\n ) : (\n <span className=\"text-text-secondary\">{m.position || '—'}</span>\n )}\n </td>\n\n {/* Jersey # */}\n <td className=\"px-4 py-3\">\n {isEditing && draft ? (\n <input\n aria-label=\"Jersey number\"\n inputMode=\"numeric\"\n className={`${fieldInputClass} w-20`}\n value={draft.jerseyNumber}\n onChange={(e) =>\n setDraft((d) => (d ? { ...d, jerseyNumber: e.target.value } : d))\n }\n placeholder=\"9\"\n />\n ) : (\n <span className=\"tabular-nums text-text-primary\">\n {m.jerseyNumber ?? '—'}\n </span>\n )}\n </td>\n\n {/* Status */}\n <td className=\"px-4 py-3\">\n {isEditing && draft ? (\n <select\n aria-label=\"Status\"\n className={fieldInputClass}\n value={draft.status}\n onChange={(e) =>\n setDraft((d) =>\n d ? { ...d, status: e.target.value as AthMemberStatus } : d\n )\n }\n >\n {MEMBER_STATUSES.map((s) => (\n <option key={s} value={s}>\n {memberStatusLabel(s)}\n </option>\n ))}\n </select>\n ) : (\n <StatusBadge status={m.status} />\n )}\n </td>\n\n {/* Actions */}\n <td className=\"px-4 py-3\">\n <div className=\"flex items-center justify-end gap-1\">\n {isEditing ? (\n <>\n <button\n type=\"button\"\n onClick={() => void saveEdit(m.id)}\n disabled={busy}\n aria-label=\"Save changes\"\n className=\"rounded-lg p-2 text-status-success-text transition-colors hover:bg-status-success-bg-subtle disabled:opacity-60\"\n >\n {busy ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Check className=\"h-4 w-4\" />\n )}\n </button>\n <button\n type=\"button\"\n onClick={cancelEdit}\n disabled={busy}\n aria-label=\"Cancel editing\"\n className=\"rounded-lg p-2 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary disabled:opacity-60\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </>\n ) : (\n <>\n <button\n type=\"button\"\n onClick={() => startEdit(m)}\n aria-label={`Edit ${m.displayName}`}\n className=\"rounded-lg p-2 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <Pencil className=\"h-4 w-4\" />\n </button>\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 </>\n )}\n </div>\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n {rowError && (\n <p className=\"border-t border-border-seam px-4 py-2 text-sm text-status-error-text\">\n {rowError}\n </p>\n )}\n </GlassCard>\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 <div className=\"flex items-center gap-2\">\n {fixtures.length > 0 && (\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures')}\n className=\"text-sm font-medium text-text-link transition-colors hover:underline\"\n >\n View all\n </button>\n )}\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 </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 <GlassCard treatment=\"insight\" className=\"px-4 py-1\">\n <div className=\"divide-y divide-border-seam\">\n {fixtures.map((f) => (\n <MatchupRow\n key={f.id}\n fixture={f}\n onClick={() => navigateTo(`/fixtures/${f.id}`)}\n />\n ))}\n </div>\n </GlassCard>\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 {memberStatusLabel(s)}\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-semibold 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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"}
@@ -7,7 +7,7 @@ import { directoryUserName as s, useCreateTeam as c, useTeam as l, useUpdateTeam
7
7
  import { FormField as p, fieldInputClass as m } from "../../components/form.js";
8
8
  import { useEffect as h, useState as g } from "react";
9
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";
10
+ import { useParams as w } from "react-router";
11
11
  import { jsx as T, jsxs as E } from "react/jsx-runtime";
12
12
  import { GlassCard as D } from "@burdenoff/fe-libs/ui";
13
13
  //#region src/atheletebridge/pages/teams/TeamFormPage.tsx
@@ -1 +1 @@
1
- {"version":3,"file":"TeamFormPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/teams/TeamFormPage.tsx"],"sourcesContent":["/**\n * Team Create / Edit Form\n * @module atheletebridge/pages/teams\n */\n\nimport { useEffect, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, CalendarDays, Loader2, MapPin, Save, Search, X } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { UserAvatar } from '../../components/UserAvatar';\nimport { SPORT_ICONS, SPORT_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport {\n useTeam,\n useCreateTeam,\n useUpdateTeam,\n useUserDirectory,\n useUserSearch,\n directoryUserName,\n} from '../../hooks/useAthleteBridgeApi';\nimport type { AthSport, AthTeamStatus } from '../../types';\n\nconst SPORTS = Object.keys(SPORT_LABELS) as AthSport[];\nconst STATUSES: AthTeamStatus[] = ['FORMING', 'ACTIVE', 'INACTIVE', 'ARCHIVED'];\nconst DESCRIPTION_LIMIT = 300;\n\n/** Faint sport glyph rendered inside the Sport select trigger. */\nfunction SportGlyph({ sport }: { sport: AthSport }) {\n const Icon = SPORT_ICONS[sport];\n return (\n <Icon\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\"\n aria-hidden=\"true\"\n />\n );\n}\n\ninterface HeadCoachPickerProps {\n userId: string;\n displayName: string;\n onSelect: (value: { userId: string; displayName: string }) => void;\n}\n\n/**\n * Optional head-coach picker — a lightweight directory search wired to the real\n * `useUserSearch` hook, degrading to a paste-a-user-id field when the directory\n * is unavailable. Labelled correctly for the head-coach role.\n */\nfunction HeadCoachPicker({ userId, displayName, onSelect }: HeadCoachPickerProps) {\n const [term, setTerm] = useState('');\n const search = useUserSearch(term);\n const results = search.data ?? [];\n const active = term.trim().length >= 2;\n const unavailable = search.isError;\n\n if (userId) {\n return (\n <FormField label=\"Head coach\" hint=\"Optional — the coach who leads this squad.\">\n <div className=\"flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-surface px-3 py-2\">\n <UserAvatar name={displayName} id={userId} size=\"sm\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {displayName || 'Selected coach'}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">{userId}</p>\n </div>\n <button\n type=\"button\"\n aria-label=\"Clear head coach\"\n onClick={() => onSelect({ userId: '', displayName: '' })}\n className=\"rounded-md p-1 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n </FormField>\n );\n }\n\n if (unavailable) {\n return (\n <FormField\n label=\"Head coach\"\n htmlFor=\"headCoachId\"\n hint=\"Optional — directory unavailable here; paste the auth-svc user id.\"\n >\n <input\n id=\"headCoachId\"\n className={fieldInputClass}\n value={userId}\n onChange={(e) => onSelect({ userId: e.target.value, displayName })}\n placeholder=\"user-uuid\"\n />\n </FormField>\n );\n }\n\n return (\n <FormField label=\"Head coach\" hint=\"Optional — the coach who leads this squad.\">\n <div className=\"space-y-2\">\n <div className=\"relative\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\"\n aria-hidden=\"true\"\n />\n <input\n className={`${fieldInputClass} pl-9`}\n value={term}\n onChange={(e) => setTerm(e.target.value)}\n placeholder=\"Search coaches by name or email…\"\n aria-label=\"Search for a head coach\"\n />\n {search.isFetching && (\n <Loader2 className=\"absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-text-muted\" />\n )}\n </div>\n {active && !search.isFetching && results.length === 0 && (\n <p className=\"text-xs text-text-secondary\">No users match “{term.trim()}”.</p>\n )}\n {results.length > 0 && (\n <ul className=\"max-h-56 divide-y divide-border-seam overflow-auto rounded-lg border border-border-seam bg-bg-surface\">\n {results.map((user) => (\n <li key={user.id}>\n <button\n type=\"button\"\n onClick={() => {\n onSelect({ userId: user.id, displayName: directoryUserName(user) });\n setTerm('');\n }}\n className=\"flex w-full items-center gap-2.5 px-3 py-2 text-left transition-colors hover:bg-bg-sunken\"\n >\n <UserAvatar name={directoryUserName(user)} id={user.id} size=\"sm\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-text-primary\">\n {directoryUserName(user)}\n </span>\n <span className=\"block truncate text-xs text-text-secondary\">{user.email}</span>\n </span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n </FormField>\n );\n}\n\ninterface TeamFormState {\n name: string;\n sport: AthSport;\n status: AthTeamStatus;\n description: string;\n ageGroup: string;\n season: string;\n homeVenue: string;\n headCoachId: string;\n headCoachName: string;\n tags: string[];\n}\n\nconst EMPTY_FORM: TeamFormState = {\n name: '',\n sport: 'OTHER',\n status: 'FORMING',\n description: '',\n ageGroup: '',\n season: '',\n homeVenue: '',\n headCoachId: '',\n headCoachName: '',\n tags: [],\n};\n\nexport function TeamFormPage() {\n const { id } = useParams<{ id: string }>();\n const isEdit = Boolean(id);\n const { navigateTo } = useAthleteBridge();\n\n const existing = useTeam(id);\n const createTeam = useCreateTeam();\n const updateTeam = useUpdateTeam();\n\n const [form, setForm] = useState<TeamFormState>(EMPTY_FORM);\n const [tagInput, setTagInput] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n // Resolve the existing head coach's display name so the picker shows it on edit.\n const coachDir = useUserDirectory(isEdit ? [existing.data?.headCoachId] : []);\n const resolvedCoachName = coachDir.nameOf(existing.data?.headCoachId ?? undefined);\n\n useEffect(() => {\n const team = existing.data;\n if (isEdit && team) {\n setForm((prev) => ({\n name: team.name,\n sport: team.sport,\n status: team.status,\n description: team.description ?? '',\n ageGroup: team.ageGroup ?? '',\n season: team.season ?? '',\n homeVenue: team.homeVenue ?? '',\n headCoachId: team.headCoachId ?? '',\n headCoachName: resolvedCoachName ?? prev.headCoachName,\n tags: team.tags,\n }));\n }\n }, [isEdit, existing.data, resolvedCoachName]);\n\n const set = <K extends keyof TeamFormState>(key: K, value: TeamFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n const commitTag = (raw: string) => {\n const tag = raw.trim();\n if (!tag) return;\n setForm((prev) =>\n prev.tags.some((t) => t.toLowerCase() === tag.toLowerCase())\n ? prev\n : { ...prev, tags: [...prev.tags, tag] }\n );\n setTagInput('');\n };\n\n const removeTag = (tag: string) =>\n setForm((prev) => ({ ...prev, tags: prev.tags.filter((t) => t !== tag) }));\n\n const handleTagKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' || e.key === ',') {\n e.preventDefault();\n commitTag(tagInput);\n } else if (e.key === 'Backspace' && !tagInput && form.tags.length) {\n removeTag(form.tags[form.tags.length - 1]);\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (!form.name.trim()) {\n setError('Team name is required.');\n return;\n }\n\n // Fold any half-typed tag still in the input into the submission.\n const pending = tagInput.trim();\n const tags =\n pending && !form.tags.some((t) => t.toLowerCase() === pending.toLowerCase())\n ? [...form.tags, pending]\n : form.tags;\n\n const shared = {\n name: form.name.trim(),\n sport: form.sport,\n status: form.status,\n description: form.description.trim() || undefined,\n ageGroup: form.ageGroup.trim() || undefined,\n season: form.season.trim() || undefined,\n homeVenue: form.homeVenue.trim() || undefined,\n headCoachId: form.headCoachId.trim() || undefined,\n tags,\n };\n\n try {\n if (isEdit && id) {\n await updateTeam.mutateAsync({ id, input: shared });\n navigateTo(`/teams/${id}`);\n } else {\n const created = await createTeam.mutateAsync(shared);\n navigateTo(`/teams/${created.id}`);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to save team.');\n }\n };\n\n const saving = createTeam.isPending || updateTeam.isPending;\n\n if (isEdit && existing.isLoading) {\n return (\n <PageLayout title=\"Edit team\">\n <LoadingState label=\"Loading team…\" />\n </PageLayout>\n );\n }\n\n if (isEdit && (existing.isError || (!existing.isLoading && !existing.data))) {\n return (\n <PageLayout title=\"Edit 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 return (\n <PageLayout\n title={isEdit ? 'Edit team' : 'New team'}\n description={isEdit ? 'Update the squad details.' : 'Create a new squad to build a roster.'}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo(isEdit && id ? `/teams/${id}` : '/teams')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Cancel\n </button>\n }\n >\n <form onSubmit={handleSubmit} className=\"mx-auto max-w-3xl\">\n <GlassCard treatment=\"insight\" className=\"p-6 sm:p-8\">\n <div className=\"space-y-5\">\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Team name\" htmlFor=\"name\" required>\n <input\n id=\"name\"\n className={fieldInputClass}\n value={form.name}\n onChange={(e) => set('name', e.target.value)}\n placeholder=\"e.g. Riverside United U18\"\n />\n </FormField>\n\n <FormField label=\"Sport\" htmlFor=\"sport\">\n <div className=\"relative\">\n <SportGlyph sport={form.sport} />\n <select\n id=\"sport\"\n className={`${fieldInputClass} pl-9`}\n value={form.sport}\n onChange={(e) => set('sport', e.target.value as AthSport)}\n >\n {SPORTS.map((s) => (\n <option key={s} value={s}>\n {SPORT_LABELS[s]}\n </option>\n ))}\n </select>\n </div>\n </FormField>\n </div>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Status\" htmlFor=\"status\">\n <select\n id=\"status\"\n className={fieldInputClass}\n value={form.status}\n onChange={(e) => set('status', e.target.value as AthTeamStatus)}\n >\n {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\n <FormField label=\"Age group\" htmlFor=\"ageGroup\">\n <input\n id=\"ageGroup\"\n className={fieldInputClass}\n value={form.ageGroup}\n onChange={(e) => set('ageGroup', e.target.value)}\n placeholder=\"e.g. U18\"\n />\n </FormField>\n </div>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Season\" htmlFor=\"season\">\n <div className=\"relative\">\n <CalendarDays\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\"\n aria-hidden=\"true\"\n />\n <input\n id=\"season\"\n className={`${fieldInputClass} pl-9`}\n value={form.season}\n onChange={(e) => set('season', e.target.value)}\n placeholder=\"e.g. 2025/26\"\n />\n </div>\n </FormField>\n\n <FormField label=\"Home venue\" htmlFor=\"homeVenue\">\n <div className=\"relative\">\n <MapPin\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\"\n aria-hidden=\"true\"\n />\n <input\n id=\"homeVenue\"\n className={`${fieldInputClass} pl-9`}\n value={form.homeVenue}\n onChange={(e) => set('homeVenue', e.target.value)}\n placeholder=\"e.g. Riverside Stadium\"\n />\n </div>\n </FormField>\n </div>\n\n <HeadCoachPicker\n userId={form.headCoachId}\n displayName={form.headCoachName}\n onSelect={({ userId, displayName }) =>\n setForm((prev) => ({\n ...prev,\n headCoachId: userId,\n headCoachName: displayName,\n }))\n }\n />\n\n <FormField label=\"Description\" htmlFor=\"description\">\n <textarea\n id=\"description\"\n className={fieldInputClass}\n rows={3}\n maxLength={DESCRIPTION_LIMIT}\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"A short description of the team.\"\n />\n <div className=\"mt-1 text-right text-xs tabular-nums text-text-muted\">\n {form.description.length}/{DESCRIPTION_LIMIT}\n </div>\n </FormField>\n\n <FormField\n label=\"Tags\"\n htmlFor=\"tags\"\n hint=\"Type a tag and press Enter to add it; click × to remove.\"\n >\n <div 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)]\">\n {form.tags.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n <button\n type=\"button\"\n onClick={() => removeTag(tag)}\n aria-label={`Remove tag ${tag}`}\n className=\"rounded-full text-text-muted transition-colors hover:text-status-error-text\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n ))}\n <input\n id=\"tags\"\n 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\"\n value={tagInput}\n onChange={(e) => setTagInput(e.target.value)}\n onKeyDown={handleTagKeyDown}\n onBlur={() => commitTag(tagInput)}\n placeholder={form.tags.length ? 'Add tag and press Enter…' : 'youth, development'}\n />\n </div>\n </FormField>\n\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n </div>\n\n <div className=\"mt-6 flex items-center justify-end gap-3 border-t border-border-seam pt-5\">\n <button\n type=\"button\"\n onClick={() => navigateTo(isEdit && id ? `/teams/${id}` : '/teams')}\n className=\"rounded-lg px-4 py-2 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={saving}\n 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\"\n >\n {saving ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {isEdit ? 'Save changes' : 'Create team'}\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TeamFormPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/teams/TeamFormPage.tsx"],"sourcesContent":["/**\n * Team Create / Edit Form\n * @module atheletebridge/pages/teams\n */\n\nimport { useEffect, useState } from 'react';\nimport { useParams } from 'react-router';\nimport { ArrowLeft, CalendarDays, Loader2, MapPin, Save, Search, X } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { UserAvatar } from '../../components/UserAvatar';\nimport { SPORT_ICONS, SPORT_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport {\n useTeam,\n useCreateTeam,\n useUpdateTeam,\n useUserDirectory,\n useUserSearch,\n directoryUserName,\n} from '../../hooks/useAthleteBridgeApi';\nimport type { AthSport, AthTeamStatus } from '../../types';\n\nconst SPORTS = Object.keys(SPORT_LABELS) as AthSport[];\nconst STATUSES: AthTeamStatus[] = ['FORMING', 'ACTIVE', 'INACTIVE', 'ARCHIVED'];\nconst DESCRIPTION_LIMIT = 300;\n\n/** Faint sport glyph rendered inside the Sport select trigger. */\nfunction SportGlyph({ sport }: { sport: AthSport }) {\n const Icon = SPORT_ICONS[sport];\n return (\n <Icon\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\"\n aria-hidden=\"true\"\n />\n );\n}\n\ninterface HeadCoachPickerProps {\n userId: string;\n displayName: string;\n onSelect: (value: { userId: string; displayName: string }) => void;\n}\n\n/**\n * Optional head-coach picker — a lightweight directory search wired to the real\n * `useUserSearch` hook, degrading to a paste-a-user-id field when the directory\n * is unavailable. Labelled correctly for the head-coach role.\n */\nfunction HeadCoachPicker({ userId, displayName, onSelect }: HeadCoachPickerProps) {\n const [term, setTerm] = useState('');\n const search = useUserSearch(term);\n const results = search.data ?? [];\n const active = term.trim().length >= 2;\n const unavailable = search.isError;\n\n if (userId) {\n return (\n <FormField label=\"Head coach\" hint=\"Optional — the coach who leads this squad.\">\n <div className=\"flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-surface px-3 py-2\">\n <UserAvatar name={displayName} id={userId} size=\"sm\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {displayName || 'Selected coach'}\n </p>\n <p className=\"truncate text-xs text-text-secondary\">{userId}</p>\n </div>\n <button\n type=\"button\"\n aria-label=\"Clear head coach\"\n onClick={() => onSelect({ userId: '', displayName: '' })}\n className=\"rounded-md p-1 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n </FormField>\n );\n }\n\n if (unavailable) {\n return (\n <FormField\n label=\"Head coach\"\n htmlFor=\"headCoachId\"\n hint=\"Optional — directory unavailable here; paste the auth-svc user id.\"\n >\n <input\n id=\"headCoachId\"\n className={fieldInputClass}\n value={userId}\n onChange={(e) => onSelect({ userId: e.target.value, displayName })}\n placeholder=\"user-uuid\"\n />\n </FormField>\n );\n }\n\n return (\n <FormField label=\"Head coach\" hint=\"Optional — the coach who leads this squad.\">\n <div className=\"space-y-2\">\n <div className=\"relative\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\"\n aria-hidden=\"true\"\n />\n <input\n className={`${fieldInputClass} pl-9`}\n value={term}\n onChange={(e) => setTerm(e.target.value)}\n placeholder=\"Search coaches by name or email…\"\n aria-label=\"Search for a head coach\"\n />\n {search.isFetching && (\n <Loader2 className=\"absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-text-muted\" />\n )}\n </div>\n {active && !search.isFetching && results.length === 0 && (\n <p className=\"text-xs text-text-secondary\">No users match “{term.trim()}”.</p>\n )}\n {results.length > 0 && (\n <ul className=\"max-h-56 divide-y divide-border-seam overflow-auto rounded-lg border border-border-seam bg-bg-surface\">\n {results.map((user) => (\n <li key={user.id}>\n <button\n type=\"button\"\n onClick={() => {\n onSelect({ userId: user.id, displayName: directoryUserName(user) });\n setTerm('');\n }}\n className=\"flex w-full items-center gap-2.5 px-3 py-2 text-left transition-colors hover:bg-bg-sunken\"\n >\n <UserAvatar name={directoryUserName(user)} id={user.id} size=\"sm\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-text-primary\">\n {directoryUserName(user)}\n </span>\n <span className=\"block truncate text-xs text-text-secondary\">{user.email}</span>\n </span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n </FormField>\n );\n}\n\ninterface TeamFormState {\n name: string;\n sport: AthSport;\n status: AthTeamStatus;\n description: string;\n ageGroup: string;\n season: string;\n homeVenue: string;\n headCoachId: string;\n headCoachName: string;\n tags: string[];\n}\n\nconst EMPTY_FORM: TeamFormState = {\n name: '',\n sport: 'OTHER',\n status: 'FORMING',\n description: '',\n ageGroup: '',\n season: '',\n homeVenue: '',\n headCoachId: '',\n headCoachName: '',\n tags: [],\n};\n\nexport function TeamFormPage() {\n const { id } = useParams<{ id: string }>();\n const isEdit = Boolean(id);\n const { navigateTo } = useAthleteBridge();\n\n const existing = useTeam(id);\n const createTeam = useCreateTeam();\n const updateTeam = useUpdateTeam();\n\n const [form, setForm] = useState<TeamFormState>(EMPTY_FORM);\n const [tagInput, setTagInput] = useState('');\n const [error, setError] = useState<string | null>(null);\n\n // Resolve the existing head coach's display name so the picker shows it on edit.\n const coachDir = useUserDirectory(isEdit ? [existing.data?.headCoachId] : []);\n const resolvedCoachName = coachDir.nameOf(existing.data?.headCoachId ?? undefined);\n\n useEffect(() => {\n const team = existing.data;\n if (isEdit && team) {\n setForm((prev) => ({\n name: team.name,\n sport: team.sport,\n status: team.status,\n description: team.description ?? '',\n ageGroup: team.ageGroup ?? '',\n season: team.season ?? '',\n homeVenue: team.homeVenue ?? '',\n headCoachId: team.headCoachId ?? '',\n headCoachName: resolvedCoachName ?? prev.headCoachName,\n tags: team.tags,\n }));\n }\n }, [isEdit, existing.data, resolvedCoachName]);\n\n const set = <K extends keyof TeamFormState>(key: K, value: TeamFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n const commitTag = (raw: string) => {\n const tag = raw.trim();\n if (!tag) return;\n setForm((prev) =>\n prev.tags.some((t) => t.toLowerCase() === tag.toLowerCase())\n ? prev\n : { ...prev, tags: [...prev.tags, tag] }\n );\n setTagInput('');\n };\n\n const removeTag = (tag: string) =>\n setForm((prev) => ({ ...prev, tags: prev.tags.filter((t) => t !== tag) }));\n\n const handleTagKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' || e.key === ',') {\n e.preventDefault();\n commitTag(tagInput);\n } else if (e.key === 'Backspace' && !tagInput && form.tags.length) {\n removeTag(form.tags[form.tags.length - 1]);\n }\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (!form.name.trim()) {\n setError('Team name is required.');\n return;\n }\n\n // Fold any half-typed tag still in the input into the submission.\n const pending = tagInput.trim();\n const tags =\n pending && !form.tags.some((t) => t.toLowerCase() === pending.toLowerCase())\n ? [...form.tags, pending]\n : form.tags;\n\n const shared = {\n name: form.name.trim(),\n sport: form.sport,\n status: form.status,\n description: form.description.trim() || undefined,\n ageGroup: form.ageGroup.trim() || undefined,\n season: form.season.trim() || undefined,\n homeVenue: form.homeVenue.trim() || undefined,\n headCoachId: form.headCoachId.trim() || undefined,\n tags,\n };\n\n try {\n if (isEdit && id) {\n await updateTeam.mutateAsync({ id, input: shared });\n navigateTo(`/teams/${id}`);\n } else {\n const created = await createTeam.mutateAsync(shared);\n navigateTo(`/teams/${created.id}`);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to save team.');\n }\n };\n\n const saving = createTeam.isPending || updateTeam.isPending;\n\n if (isEdit && existing.isLoading) {\n return (\n <PageLayout title=\"Edit team\">\n <LoadingState label=\"Loading team…\" />\n </PageLayout>\n );\n }\n\n if (isEdit && (existing.isError || (!existing.isLoading && !existing.data))) {\n return (\n <PageLayout title=\"Edit 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 return (\n <PageLayout\n title={isEdit ? 'Edit team' : 'New team'}\n description={isEdit ? 'Update the squad details.' : 'Create a new squad to build a roster.'}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo(isEdit && id ? `/teams/${id}` : '/teams')}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Cancel\n </button>\n }\n >\n <form onSubmit={handleSubmit} className=\"mx-auto max-w-3xl\">\n <GlassCard treatment=\"insight\" className=\"p-6 sm:p-8\">\n <div className=\"space-y-5\">\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Team name\" htmlFor=\"name\" required>\n <input\n id=\"name\"\n className={fieldInputClass}\n value={form.name}\n onChange={(e) => set('name', e.target.value)}\n placeholder=\"e.g. Riverside United U18\"\n />\n </FormField>\n\n <FormField label=\"Sport\" htmlFor=\"sport\">\n <div className=\"relative\">\n <SportGlyph sport={form.sport} />\n <select\n id=\"sport\"\n className={`${fieldInputClass} pl-9`}\n value={form.sport}\n onChange={(e) => set('sport', e.target.value as AthSport)}\n >\n {SPORTS.map((s) => (\n <option key={s} value={s}>\n {SPORT_LABELS[s]}\n </option>\n ))}\n </select>\n </div>\n </FormField>\n </div>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Status\" htmlFor=\"status\">\n <select\n id=\"status\"\n className={fieldInputClass}\n value={form.status}\n onChange={(e) => set('status', e.target.value as AthTeamStatus)}\n >\n {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\n <FormField label=\"Age group\" htmlFor=\"ageGroup\">\n <input\n id=\"ageGroup\"\n className={fieldInputClass}\n value={form.ageGroup}\n onChange={(e) => set('ageGroup', e.target.value)}\n placeholder=\"e.g. U18\"\n />\n </FormField>\n </div>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Season\" htmlFor=\"season\">\n <div className=\"relative\">\n <CalendarDays\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\"\n aria-hidden=\"true\"\n />\n <input\n id=\"season\"\n className={`${fieldInputClass} pl-9`}\n value={form.season}\n onChange={(e) => set('season', e.target.value)}\n placeholder=\"e.g. 2025/26\"\n />\n </div>\n </FormField>\n\n <FormField label=\"Home venue\" htmlFor=\"homeVenue\">\n <div className=\"relative\">\n <MapPin\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted\"\n aria-hidden=\"true\"\n />\n <input\n id=\"homeVenue\"\n className={`${fieldInputClass} pl-9`}\n value={form.homeVenue}\n onChange={(e) => set('homeVenue', e.target.value)}\n placeholder=\"e.g. Riverside Stadium\"\n />\n </div>\n </FormField>\n </div>\n\n <HeadCoachPicker\n userId={form.headCoachId}\n displayName={form.headCoachName}\n onSelect={({ userId, displayName }) =>\n setForm((prev) => ({\n ...prev,\n headCoachId: userId,\n headCoachName: displayName,\n }))\n }\n />\n\n <FormField label=\"Description\" htmlFor=\"description\">\n <textarea\n id=\"description\"\n className={fieldInputClass}\n rows={3}\n maxLength={DESCRIPTION_LIMIT}\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"A short description of the team.\"\n />\n <div className=\"mt-1 text-right text-xs tabular-nums text-text-muted\">\n {form.description.length}/{DESCRIPTION_LIMIT}\n </div>\n </FormField>\n\n <FormField\n label=\"Tags\"\n htmlFor=\"tags\"\n hint=\"Type a tag and press Enter to add it; click × to remove.\"\n >\n <div 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)]\">\n {form.tags.map((tag) => (\n <span\n key={tag}\n className=\"inline-flex items-center gap-1 rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {tag}\n <button\n type=\"button\"\n onClick={() => removeTag(tag)}\n aria-label={`Remove tag ${tag}`}\n className=\"rounded-full text-text-muted transition-colors hover:text-status-error-text\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n </span>\n ))}\n <input\n id=\"tags\"\n 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\"\n value={tagInput}\n onChange={(e) => setTagInput(e.target.value)}\n onKeyDown={handleTagKeyDown}\n onBlur={() => commitTag(tagInput)}\n placeholder={form.tags.length ? 'Add tag and press Enter…' : 'youth, development'}\n />\n </div>\n </FormField>\n\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n </div>\n\n <div className=\"mt-6 flex items-center justify-end gap-3 border-t border-border-seam pt-5\">\n <button\n type=\"button\"\n onClick={() => navigateTo(isEdit && id ? `/teams/${id}` : '/teams')}\n className=\"rounded-lg px-4 py-2 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={saving}\n 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\"\n >\n {saving ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : <Save className=\"h-4 w-4\" />}\n {isEdit ? 'Save changes' : 'Create team'}\n </button>\n </div>\n </GlassCard>\n </form>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-atheletebridge",
3
- "version": "2026.731.1",
3
+ "version": "2026.801.1",
4
4
  "description": "Burdenoff AthleteBridge Microfrontend - Sports, coaching & training platform for teams, fixtures, programs, sessions and athlete performance",
5
5
  "type": "module",
6
6
  "files": [
@@ -48,14 +48,14 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@apollo/client": "^4.0.11",
51
- "@burdenoff/fe-libs": "2026.713.6",
51
+ "@burdenoff/fe-libs": "2026.801.1",
52
52
  "@tanstack/react-query": "^5.90.16",
53
53
  "clsx": "^2.1.1",
54
54
  "graphql": "^16.12.0",
55
55
  "lucide-react": "^0.468.0",
56
56
  "react": "^19.0.0",
57
57
  "react-dom": "^19.0.0",
58
- "react-router-dom": "^7.1.3",
58
+ "react-router": "^8.3.0",
59
59
  "tailwind-merge": "^3.4.0",
60
60
  "zustand": "^5.0.7"
61
61
  },
@@ -102,7 +102,7 @@
102
102
  "access": "restricted"
103
103
  },
104
104
  "overrides": {
105
- "@burdenoff/fe-libs": "2026.713.6",
105
+ "@burdenoff/fe-libs": "2026.801.1",
106
106
  "lodash": ">=4.17.21",
107
107
  "lodash-es": ">=4.17.21",
108
108
  "dompurify": ">=3.3.4",