@burdenoff/microfe-atheletebridge 2026.720.1 → 2026.731.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.
- package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
- package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
- package/dist/atheletebridge/admin/AdminDashboardPage.js.map +1 -1
- package/dist/atheletebridge/admin/AdminRoot.js.map +1 -1
- package/dist/atheletebridge/components/AthleteSelect.js.map +1 -1
- package/dist/atheletebridge/components/Crest.js.map +1 -1
- package/dist/atheletebridge/components/CursorPager.js.map +1 -1
- package/dist/atheletebridge/components/DrillVideoLink.js.map +1 -1
- package/dist/atheletebridge/components/EmptyState.js.map +1 -1
- package/dist/atheletebridge/components/FilterSelect.js.map +1 -1
- package/dist/atheletebridge/components/FixtureCard.js.map +1 -1
- package/dist/atheletebridge/components/LoadingState.js.map +1 -1
- package/dist/atheletebridge/components/MatchupRow.js.map +1 -1
- package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
- package/dist/atheletebridge/components/PageLayout.js.map +1 -1
- package/dist/atheletebridge/components/ProgramCard.js.map +1 -1
- package/dist/atheletebridge/components/RouteAnalytics.js.map +1 -1
- package/dist/atheletebridge/components/Scoreboard.js.map +1 -1
- package/dist/atheletebridge/components/SessionCard.js.map +1 -1
- package/dist/atheletebridge/components/SessionStatusTimeline.js.map +1 -1
- package/dist/atheletebridge/components/StatusBadge.js.map +1 -1
- package/dist/atheletebridge/components/TeamCard.js.map +1 -1
- package/dist/atheletebridge/components/UserAvatar.js.map +1 -1
- package/dist/atheletebridge/components/UserSearchSelect.js.map +1 -1
- package/dist/atheletebridge/components/availability/AvailabilityRosterPanel.d.ts +9 -0
- package/dist/atheletebridge/components/availability/AvailabilityRosterPanel.d.ts.map +1 -0
- package/dist/atheletebridge/components/availability/AvailabilityRosterPanel.js +118 -0
- package/dist/atheletebridge/components/availability/AvailabilityRosterPanel.js.map +1 -0
- package/dist/atheletebridge/components/availability/AvailabilityRsvpControl.d.ts +9 -0
- package/dist/atheletebridge/components/availability/AvailabilityRsvpControl.d.ts.map +1 -0
- package/dist/atheletebridge/components/availability/AvailabilityRsvpControl.js +88 -0
- package/dist/atheletebridge/components/availability/AvailabilityRsvpControl.js.map +1 -0
- package/dist/atheletebridge/components/domain.js.map +1 -1
- package/dist/atheletebridge/components/form.js.map +1 -1
- package/dist/atheletebridge/components/viz/BarChart.js.map +1 -1
- package/dist/atheletebridge/components/viz/DonutChart.js +1 -1
- package/dist/atheletebridge/components/viz/DonutChart.js.map +1 -1
- package/dist/atheletebridge/components/viz/LineChart.js.map +1 -1
- package/dist/atheletebridge/components/viz/RatingStars.js.map +1 -1
- package/dist/atheletebridge/components/viz/Sparkline.js.map +1 -1
- package/dist/atheletebridge/components/viz/StatCard.js.map +1 -1
- package/dist/atheletebridge/components/viz/Timeline.js.map +1 -1
- package/dist/atheletebridge/components/viz/lib/CartesianFrame.js.map +1 -1
- package/dist/atheletebridge/components/viz/lib/ResponsiveSvg.js.map +1 -1
- package/dist/atheletebridge/components/viz/lib/format.js.map +1 -1
- package/dist/atheletebridge/components/viz/lib/geometry.js.map +1 -1
- package/dist/atheletebridge/components/viz/lib/hooks.js.map +1 -1
- package/dist/atheletebridge/components/viz/lib/palette.js.map +1 -1
- package/dist/atheletebridge/context/AthleteBridgeContext.js.map +1 -1
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts +18 -1
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts.map +1 -1
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +71 -33
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
- package/dist/atheletebridge/i18n.js.map +1 -1
- package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
- package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
- package/dist/atheletebridge/pages/analytics/CoachAnalyticsPage.js.map +1 -1
- package/dist/atheletebridge/pages/athletes/AthleteProfilePage.js.map +1 -1
- package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.d.ts.map +1 -1
- package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js +87 -75
- package/dist/atheletebridge/pages/fixtures/FixtureDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/fixtures/FixtureFormPage.js.map +1 -1
- package/dist/atheletebridge/pages/fixtures/FixturesListPage.js.map +1 -1
- package/dist/atheletebridge/pages/onboarding/OnboardingPage.js.map +1 -1
- package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -1
- package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/programs/ProgramFormPage.js.map +1 -1
- package/dist/atheletebridge/pages/programs/ProgramsListPage.js.map +1 -1
- package/dist/atheletebridge/pages/sessions/SessionDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -1
- package/dist/atheletebridge/pages/sessions/SessionsListPage.js.map +1 -1
- package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
- package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
- package/dist/atheletebridge/pages/tournaments/TournamentBracketPage.js.map +1 -1
- package/dist/atheletebridge/store/atheletebridgeStore.js.map +1 -1
- package/dist/atheletebridge/types/index.d.ts +27 -0
- package/dist/atheletebridge/types/index.d.ts.map +1 -1
- package/dist/atheletebridge/utils/cn.js.map +1 -1
- package/dist/atheletebridge/utils/datetime.js.map +1 -1
- package/dist/atheletebridge/utils/formatters.js.map +1 -1
- package/dist/atheletebridge/utils/identity.js.map +1 -1
- package/dist/atheletebridge/utils/navigation.js.map +1 -1
- package/dist/atheletebridge/utils/pageContext.js.map +1 -1
- package/dist/atheletebridge/utils/timeAgo.js.map +1 -1
- package/dist/atheletebridge/utils/url.js.map +1 -1
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +1 -1
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -1
- package/dist/services/createSandboxAssistantTransport.js.map +1 -1
- package/package.json +5 -5
|
@@ -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-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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamsListPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/teams/TeamsListPage.tsx"],"sourcesContent":["/**\n * Teams List\n * @module atheletebridge/pages/teams\n */\n\nimport { useState } from 'react';\nimport { Plus, Users } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { TeamCard } from '../../components/TeamCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FilterSelect } from '../../components/FilterSelect';\nimport { CursorPager } from '../../components/CursorPager';\nimport { SPORT_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useTeams } from '../../hooks/useAthleteBridgeApi';\nimport type { AthSport, AthTeamStatus } from '../../types';\n\nconst PAGE_SIZE = 12;\n\nconst SPORT_OPTS = (Object.keys(SPORT_LABELS) as AthSport[]).map((value) => ({\n value,\n label: SPORT_LABELS[value],\n}));\n\nconst STATUS_OPTS: ReadonlyArray<{ value: AthTeamStatus; label: string }> = [\n { value: 'FORMING', label: 'Forming' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'INACTIVE', label: 'Inactive' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nexport function TeamsListPage() {\n const { navigateTo } = useAthleteBridge();\n const [sport, setSport] = useState<AthSport | ''>('');\n const [status, setStatus] = useState<AthTeamStatus | ''>('');\n const [page, setPage] = useState(0);\n\n const teams = useTeams({\n sport: sport || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset: page * PAGE_SIZE },\n });\n\n const items = teams.data?.items ?? [];\n const hasMore = teams.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Teams\"\n description=\"Squads, club sides, academy groups and esports rosters.\"\n hero\n gradientTitle\n actions={\n <button\n type=\"button\"\n data-tour=\"teams-create\"\n onClick={() => navigateTo('/teams/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Plus className=\"h-4 w-4\" /> New team\n </button>\n }\n >\n <div data-tour=\"teams-filters\" className=\"mb-6 flex flex-wrap items-center gap-3\">\n <FilterSelect\n ariaLabel=\"Filter by sport\"\n allLabel=\"All sports\"\n value={sport}\n onChange={(v) => {\n setSport(v);\n setPage(0);\n }}\n options={SPORT_OPTS}\n />\n <FilterSelect\n ariaLabel=\"Filter by status\"\n allLabel=\"All statuses\"\n value={status}\n onChange={(v) => {\n setStatus(v);\n setPage(0);\n }}\n options={STATUS_OPTS}\n />\n </div>\n\n {teams.isLoading ? (\n <LoadingState label=\"Loading teams…\" />\n ) : teams.isError ? (\n <ErrorState onRetry={() => void teams.refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Users className=\"h-10 w-10\" />}\n title=\"No teams found\"\n description={\n sport || status\n ? 'Try clearing your filters to see all teams.'\n : 'Create your first team to build a roster and start scheduling fixtures.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/teams/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n Create team\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {items.map((team) => (\n <TeamCard\n key={team.id}\n team={team}\n memberCount={team.members?.items.length}\n onClick={() => navigateTo(`/teams/${team.id}`)}\n />\n ))}\n </div>\n <CursorPager\n className=\"mt-6\"\n page={page}\n hasMore={hasMore}\n onPrev={() => setPage((p) => Math.max(0, p - 1))}\n onNext={() => setPage((p) => p + 1)}\n />\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAkBA,IAAM,IAAY,IAEZ,IAAc,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"TeamsListPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/teams/TeamsListPage.tsx"],"sourcesContent":["/**\n * Teams List\n * @module atheletebridge/pages/teams\n */\n\nimport { useState } from 'react';\nimport { Plus, Users } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { TeamCard } from '../../components/TeamCard';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FilterSelect } from '../../components/FilterSelect';\nimport { CursorPager } from '../../components/CursorPager';\nimport { SPORT_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useTeams } from '../../hooks/useAthleteBridgeApi';\nimport type { AthSport, AthTeamStatus } from '../../types';\n\nconst PAGE_SIZE = 12;\n\nconst SPORT_OPTS = (Object.keys(SPORT_LABELS) as AthSport[]).map((value) => ({\n value,\n label: SPORT_LABELS[value],\n}));\n\nconst STATUS_OPTS: ReadonlyArray<{ value: AthTeamStatus; label: string }> = [\n { value: 'FORMING', label: 'Forming' },\n { value: 'ACTIVE', label: 'Active' },\n { value: 'INACTIVE', label: 'Inactive' },\n { value: 'ARCHIVED', label: 'Archived' },\n];\n\nexport function TeamsListPage() {\n const { navigateTo } = useAthleteBridge();\n const [sport, setSport] = useState<AthSport | ''>('');\n const [status, setStatus] = useState<AthTeamStatus | ''>('');\n const [page, setPage] = useState(0);\n\n const teams = useTeams({\n sport: sport || undefined,\n status: status || undefined,\n pagination: { limit: PAGE_SIZE, offset: page * PAGE_SIZE },\n });\n\n const items = teams.data?.items ?? [];\n const hasMore = teams.data?.pageInfo.hasMore ?? false;\n\n return (\n <PageLayout\n title=\"Teams\"\n description=\"Squads, club sides, academy groups and esports rosters.\"\n hero\n gradientTitle\n actions={\n <button\n type=\"button\"\n data-tour=\"teams-create\"\n onClick={() => navigateTo('/teams/new')}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n <Plus className=\"h-4 w-4\" /> New team\n </button>\n }\n >\n <div data-tour=\"teams-filters\" className=\"mb-6 flex flex-wrap items-center gap-3\">\n <FilterSelect\n ariaLabel=\"Filter by sport\"\n allLabel=\"All sports\"\n value={sport}\n onChange={(v) => {\n setSport(v);\n setPage(0);\n }}\n options={SPORT_OPTS}\n />\n <FilterSelect\n ariaLabel=\"Filter by status\"\n allLabel=\"All statuses\"\n value={status}\n onChange={(v) => {\n setStatus(v);\n setPage(0);\n }}\n options={STATUS_OPTS}\n />\n </div>\n\n {teams.isLoading ? (\n <LoadingState label=\"Loading teams…\" />\n ) : teams.isError ? (\n <ErrorState onRetry={() => void teams.refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n icon={<Users className=\"h-10 w-10\" />}\n title=\"No teams found\"\n description={\n sport || status\n ? 'Try clearing your filters to see all teams.'\n : 'Create your first team to build a roster and start scheduling fixtures.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/teams/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n Create team\n </button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {items.map((team) => (\n <TeamCard\n key={team.id}\n team={team}\n memberCount={team.members?.items.length}\n onClick={() => navigateTo(`/teams/${team.id}`)}\n />\n ))}\n </div>\n <CursorPager\n className=\"mt-6\"\n page={page}\n hasMore={hasMore}\n onPrev={() => setPage((p) => Math.max(0, p - 1))}\n onNext={() => setPage((p) => p + 1)}\n />\n </>\n )}\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAkBA,IAAM,IAAY,IAEZ,IAAc,OAAO,KAAK,CAAY,EAAiB,KAAK,OAAW;CAC3E;CACA,OAAO,EAAa;AACtB,EAAE,GAEI,IAAsE;CAC1E;EAAE,OAAO;EAAW,OAAO;CAAU;CACrC;EAAE,OAAO;EAAU,OAAO;CAAS;CACnC;EAAE,OAAO;EAAY,OAAO;CAAW;CACvC;EAAE,OAAO;EAAY,OAAO;CAAW;AACzC;AAEA,SAAgB,IAAgB;CAC9B,IAAM,EAAE,kBAAe,EAAiB,GAClC,CAAC,GAAO,KAAY,EAAwB,EAAE,GAC9C,CAAC,GAAQ,KAAa,EAA6B,EAAE,GACrD,CAAC,GAAM,KAAW,EAAS,CAAC,GAE5B,IAAQ,EAAS;EACrB,OAAO,KAAS,KAAA;EAChB,QAAQ,KAAU,KAAA;EAClB,YAAY;GAAE,OAAO;GAAW,QAAQ,IAAO;EAAU;CAC3D,CAAC,GAEK,IAAQ,EAAM,MAAM,SAAS,CAAC,GAC9B,IAAU,EAAM,MAAM,SAAS,WAAW;CAEhD,OACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,MAAA;EACA,eAAA;EACA,SACE,kBAAC,UAAD;GACE,MAAK;GACL,aAAU;GACV,eAAe,EAAW,YAAY;GACtC,WAAU;aAJZ,CAME,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA,GAAC,WACtB;;YAbZ,CAgBE,kBAAC,OAAD;GAAK,aAAU;GAAgB,WAAU;aAAzC,CACE,kBAAC,GAAD;IACE,WAAU;IACV,UAAS;IACT,OAAO;IACP,WAAW,MAAM;KAEf,AADA,EAAS,CAAC,GACV,EAAQ,CAAC;IACX;IACA,SAAS;GACV,CAAA,GACD,kBAAC,GAAD;IACE,WAAU;IACV,UAAS;IACT,OAAO;IACP,WAAW,MAAM;KAEf,AADA,EAAU,CAAC,GACX,EAAQ,CAAC;IACX;IACA,SAAS;GACV,CAAA,CACE;MAEJ,EAAM,YACL,kBAAC,GAAD,EAAc,OAAM,iBAAkB,CAAA,IACpC,EAAM,UACR,kBAAC,GAAD,EAAY,eAAe,KAAK,EAAM,QAAQ,EAAI,CAAA,IAChD,EAAM,WAAW,IACnB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAO,WAAU,YAAa,CAAA;GACpC,OAAM;GACN,aACE,KAAS,IACL,gDACA;GAEN,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,YAAY;IACtC,WAAU;cACX;GAEO,CAAA;EAEX,CAAA,IAED,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,GAAD;IAEQ;IACN,aAAa,EAAK,SAAS,MAAM;IACjC,eAAe,EAAW,UAAU,EAAK,IAAI;GAC9C,GAJM,EAAK,EAIX,CACF;EACE,CAAA,GACL,kBAAC,GAAD;GACE,WAAU;GACJ;GACG;GACT,cAAc,GAAS,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC,CAAC;GAC/C,cAAc,GAAS,MAAM,IAAI,CAAC;EACnC,CAAA,CACD,EAAA,CAAA,CAEM;;AAEhB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TournamentBracketPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/tournaments/TournamentBracketPage.tsx"],"sourcesContent":["/**\n * Tournament Bracket\n * @module atheletebridge/pages/tournaments\n *\n * A round-grouped bracket view for real TOURNAMENT-type fixtures. It lists every\n * competition that has TOURNAMENT fixtures, and for the selected competition\n * groups those fixtures by their `round` string into ordered columns\n * (Round of N → Quarter Finals → Semi Finals → Finals), each match showing crest\n * + score + status straight from the fixture row.\n *\n * Honesty: the backend stores fixtures FLAT (a round label, no parent/child\n * linkage), so columns are laid out as visual grouping only — there are NO\n * fabricated connector edges asserting stored progression, and no \"global rank\".\n * The champion card is driven solely by a real COMPLETED final with a decided\n * winner. Horizontally scrollable so it never breaks layout on mobile.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Gamepad2, Trophy } from 'lucide-react';\nimport { Badge, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Crest } from '../../components/Crest';\nimport { FilterSelect } from '../../components/FilterSelect';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { resolveMatchup } from '../../components/Scoreboard';\nimport { STATUS } from '../../components/viz';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useFixtures } from '../../hooks/useAthleteBridgeApi';\nimport { formatDate } from '../../utils/formatters';\nimport type { AthFixture, AthFixtureStatus, AthSport } from '../../types';\n\n/** Tokenized status dot color for a fixture. */\nconst STATUS_DOT: Record<AthFixtureStatus, string> = {\n COMPLETED: STATUS.success,\n LIVE: 'var(--color-accent-primary)',\n SCHEDULED: STATUS.warning,\n POSTPONED: 'var(--color-text-muted)',\n CANCELLED: 'var(--color-text-muted)',\n};\n\n/**\n * Order a round label within a single-elimination progression. Recognized\n * labels sort in bracket order; unrecognized labels fall to the end (tie-broken\n * by earliest kickoff) rather than being invented into the sequence.\n */\nfunction roundRank(round: string | null): number {\n if (!round) {\n return 9999;\n }\n const r = round.toLowerCase();\n const roundOf = r.match(/round of\\s*(\\d+)/);\n if (roundOf) {\n return 1000 - Number(roundOf[1]); // larger field ⇒ earlier column\n }\n if (/third|3rd/.test(r)) {\n return 1095;\n }\n if (/(grand\\s*)?final/.test(r) && !/semi|quarter/.test(r)) {\n return 1100;\n }\n if (/semi/.test(r)) {\n return 1050;\n }\n if (/quarter/.test(r)) {\n return 1020;\n }\n return 9999;\n}\n\ninterface RoundColumn {\n key: string;\n label: string;\n rank: number;\n earliest: number;\n fixtures: AthFixture[];\n}\n\n/** Group a competition's tournament fixtures into ordered round columns. */\nfunction buildRounds(fixtures: AthFixture[]): RoundColumn[] {\n const byRound = new Map<string, AthFixture[]>();\n for (const f of fixtures) {\n const key = f.round?.trim() || 'Unscheduled round';\n const list = byRound.get(key) ?? [];\n list.push(f);\n byRound.set(key, list);\n }\n return Array.from(byRound.entries())\n .map(([label, list]) => {\n const sorted = [...list].sort(\n (a, b) => new Date(a.scheduledAt).getTime() - new Date(b.scheduledAt).getTime()\n );\n const earliest = sorted.reduce(\n (acc, f) => Math.min(acc, new Date(f.scheduledAt).getTime() || acc),\n Number.POSITIVE_INFINITY\n );\n return {\n key: label,\n label,\n rank: roundRank(list[0]?.round ?? null),\n earliest: Number.isFinite(earliest) ? earliest : 0,\n fixtures: sorted,\n };\n })\n .sort((a, b) => (a.rank !== b.rank ? a.rank - b.rank : a.earliest - b.earliest));\n}\n\nexport function TournamentBracketPage() {\n const { navigateTo } = useAthleteBridge();\n const fixturesQuery = useFixtures({ pagination: { limit: 200 } });\n\n const tournamentFixtures = useMemo(\n () => (fixturesQuery.data?.items ?? []).filter((f) => f.type === 'TOURNAMENT'),\n [fixturesQuery.data]\n );\n\n const competitions = useMemo(() => {\n const set = new Set<string>();\n for (const f of tournamentFixtures) {\n set.add(f.competition?.trim() || 'Tournament');\n }\n return Array.from(set).sort();\n }, [tournamentFixtures]);\n\n const [selected, setSelected] = useState<string>('');\n const activeCompetition = selected || competitions[0] || '';\n\n const rounds = useMemo(() => {\n const forComp = tournamentFixtures.filter(\n (f) => (f.competition?.trim() || 'Tournament') === activeCompetition\n );\n return buildRounds(forComp);\n }, [tournamentFixtures, activeCompetition]);\n\n const matchCount = rounds.reduce((acc, r) => acc + r.fixtures.length, 0);\n\n // Champion: a COMPLETED final (last round) with a decided winner. No fabrication.\n const champion = useMemo(() => {\n const finalColumn = rounds[rounds.length - 1];\n if (!finalColumn) {\n return null;\n }\n for (const f of finalColumn.fixtures) {\n if (f.status !== 'COMPLETED') {\n continue;\n }\n const m = resolveMatchup(f);\n if (m.homeWon) {\n return { name: m.homeName, sport: m.homeSport, score: `${f.homeScore}–${f.awayScore}` };\n }\n if (m.awayWon) {\n return { name: m.awayName, sport: m.awaySport, score: `${f.awayScore}–${f.homeScore}` };\n }\n }\n return null;\n }, [rounds]);\n\n if (fixturesQuery.isLoading) {\n return (\n <PageLayout title=\"Tournaments\">\n <LoadingState label=\"Loading tournament fixtures…\" />\n </PageLayout>\n );\n }\n\n if (fixturesQuery.isError) {\n return (\n <PageLayout title=\"Tournaments\">\n <ErrorState onRetry={() => void fixturesQuery.refetch()} />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Tournaments\"\n description=\"Round-grouped brackets for your knockout competitions — every match is a real fixture.\"\n actions={\n competitions.length > 1 ? (\n <FilterSelect\n value={activeCompetition}\n onChange={(value) => setSelected(value)}\n options={competitions.map((c) => ({ value: c, label: c }))}\n allLabel=\"All competitions\"\n ariaLabel=\"Select competition\"\n />\n ) : undefined\n }\n >\n {tournamentFixtures.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<Trophy className=\"h-10 w-10\" />}\n title=\"No tournament fixtures yet\"\n description=\"Schedule fixtures with the Tournament type and a round label (e.g. “Quarter Finals”) to build a bracket.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n Schedule a fixture\n </button>\n }\n />\n ) : (\n <div className=\"space-y-6\">\n {/* Meta strip */}\n <GlassCard\n treatment=\"insight\"\n className=\"flex flex-wrap items-center gap-x-6 gap-y-3 p-5\"\n >\n <span className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Trophy className=\"h-5 w-5 text-[var(--color-accent-teal)]\" />\n {activeCompetition}\n </span>\n <span className=\"text-sm text-text-secondary\">\n <span className=\"font-semibold tabular-nums text-text-primary\">{rounds.length}</span>{' '}\n {rounds.length === 1 ? 'round' : 'rounds'}\n </span>\n <span className=\"text-sm text-text-secondary\">\n <span className=\"font-semibold tabular-nums text-text-primary\">{matchCount}</span>{' '}\n {matchCount === 1 ? 'match' : 'matches'}\n </span>\n <div className=\"ml-auto flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-text-secondary\">\n <StatusDot color={STATUS.success} label=\"Completed\" />\n <StatusDot color=\"var(--color-accent-primary)\" label=\"Live\" />\n <StatusDot color={STATUS.warning} label=\"Scheduled\" />\n </div>\n </GlassCard>\n\n {/* Bracket — horizontally scrollable columns */}\n <div className=\"overflow-x-auto pb-2\">\n <div className=\"flex min-w-max items-stretch gap-4\">\n {rounds.map((round) => (\n <div key={round.key} className=\"flex w-72 shrink-0 flex-col gap-3\">\n <div className=\"px-1\">\n <h2 className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n {round.label}\n </h2>\n {round.earliest > 0 ? (\n <p className=\"text-xs text-text-muted\">\n {formatDate(new Date(round.earliest).toISOString())}\n </p>\n ) : null}\n </div>\n <div className=\"flex flex-1 flex-col justify-around gap-3\">\n {round.fixtures.map((fixture) => (\n <MatchCard\n key={fixture.id}\n fixture={fixture}\n onClick={() => navigateTo(`/fixtures/${fixture.id}`)}\n />\n ))}\n </div>\n </div>\n ))}\n\n {/* Champion column (only when a real completed final exists) */}\n {champion ? (\n <div className=\"flex w-72 shrink-0 flex-col justify-center gap-3\">\n <div className=\"px-1\">\n <h2 className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Champion\n </h2>\n </div>\n <GlassCard\n treatment=\"glass\"\n className=\"flex flex-col items-center gap-3 p-6 text-center\"\n >\n <Trophy className=\"h-8 w-8 text-[var(--color-status-warning-text)]\" />\n <Crest name={champion.name} sport={champion.sport} size={56} />\n <div>\n <p className=\"text-lg font-semibold text-text-primary\">{champion.name}</p>\n <p className=\"mt-0.5 text-sm tabular-nums text-text-secondary\">\n Won {champion.score}\n </p>\n </div>\n <Badge variant=\"default\">Champions</Badge>\n </GlassCard>\n </div>\n ) : null}\n </div>\n </div>\n\n {rounds.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<Gamepad2 className=\"h-10 w-10\" />}\n title=\"No matches in this competition\"\n description=\"Add round labels to this competition's tournament fixtures to populate the bracket.\"\n />\n ) : null}\n </div>\n )}\n </PageLayout>\n );\n}\n\n// ── Match card ───────────────────────────────────────────────────────────────\n\ninterface MatchCardProps {\n fixture: AthFixture;\n onClick: () => void;\n}\n\nfunction MatchCard({ fixture, onClick }: MatchCardProps) {\n const m = resolveMatchup(fixture);\n const dot = STATUS_DOT[fixture.status];\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"group w-full rounded-[var(--radius-card)] border border-border-seam bg-bg-surface p-3 text-left transition-all duration-200 hover:-translate-y-0.5 hover:border-border-strong hover:shadow-elevation-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <MatchSide\n name={m.homeName}\n sport={m.homeSport}\n score={fixture.homeScore}\n won={m.homeWon}\n dimmed={m.awayWon}\n />\n <div className=\"my-1 h-px bg-border-seam\" aria-hidden=\"true\" />\n <MatchSide\n name={m.awayName}\n sport={m.awaySport}\n score={fixture.awayScore}\n won={m.awayWon}\n dimmed={m.homeWon}\n />\n <div className=\"mt-2 flex items-center gap-1.5 text-xs text-text-muted\">\n <span\n className=\"h-1.5 w-1.5 rounded-full\"\n style={{ backgroundColor: dot }}\n aria-hidden=\"true\"\n />\n <span className=\"capitalize\">{fixture.status.toLowerCase().replace(/_/g, ' ')}</span>\n {fixture.venue ? <span className=\"truncate\">· {fixture.venue}</span> : null}\n </div>\n </button>\n );\n}\n\ninterface MatchSideProps {\n name: string;\n sport?: AthSport;\n score: number | null;\n won: boolean;\n dimmed: boolean;\n}\n\nfunction MatchSide({ name, sport, score, won, dimmed }: MatchSideProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <Crest name={name} sport={sport} size={22} showSportGlyph={false} />\n <span\n className={\n won\n ? 'min-w-0 flex-1 truncate text-sm font-semibold text-status-success-text'\n : dimmed\n ? 'min-w-0 flex-1 truncate text-sm text-text-muted'\n : 'min-w-0 flex-1 truncate text-sm font-medium text-text-primary'\n }\n >\n {name}\n </span>\n <span\n className={\n won\n ? 'shrink-0 text-sm font-bold tabular-nums text-status-success-text'\n : 'shrink-0 text-sm font-semibold tabular-nums text-text-secondary'\n }\n >\n {score ?? '–'}\n </span>\n </div>\n );\n}\n\n// ── Legend dot ───────────────────────────────────────────────────────────────\n\nfunction StatusDot({ color, label }: { color: string; label: string }) {\n return (\n <span className=\"flex items-center gap-1.5\">\n <span\n className=\"h-2 w-2 rounded-full\"\n style={{ backgroundColor: color }}\n aria-hidden=\"true\"\n />\n {label}\n </span>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TournamentBracketPage.js","names":[],"sources":["../../../../src/atheletebridge/pages/tournaments/TournamentBracketPage.tsx"],"sourcesContent":["/**\n * Tournament Bracket\n * @module atheletebridge/pages/tournaments\n *\n * A round-grouped bracket view for real TOURNAMENT-type fixtures. It lists every\n * competition that has TOURNAMENT fixtures, and for the selected competition\n * groups those fixtures by their `round` string into ordered columns\n * (Round of N → Quarter Finals → Semi Finals → Finals), each match showing crest\n * + score + status straight from the fixture row.\n *\n * Honesty: the backend stores fixtures FLAT (a round label, no parent/child\n * linkage), so columns are laid out as visual grouping only — there are NO\n * fabricated connector edges asserting stored progression, and no \"global rank\".\n * The champion card is driven solely by a real COMPLETED final with a decided\n * winner. Horizontally scrollable so it never breaks layout on mobile.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Gamepad2, Trophy } from 'lucide-react';\nimport { Badge, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { Crest } from '../../components/Crest';\nimport { FilterSelect } from '../../components/FilterSelect';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { resolveMatchup } from '../../components/Scoreboard';\nimport { STATUS } from '../../components/viz';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useFixtures } from '../../hooks/useAthleteBridgeApi';\nimport { formatDate } from '../../utils/formatters';\nimport type { AthFixture, AthFixtureStatus, AthSport } from '../../types';\n\n/** Tokenized status dot color for a fixture. */\nconst STATUS_DOT: Record<AthFixtureStatus, string> = {\n COMPLETED: STATUS.success,\n LIVE: 'var(--color-accent-primary)',\n SCHEDULED: STATUS.warning,\n POSTPONED: 'var(--color-text-muted)',\n CANCELLED: 'var(--color-text-muted)',\n};\n\n/**\n * Order a round label within a single-elimination progression. Recognized\n * labels sort in bracket order; unrecognized labels fall to the end (tie-broken\n * by earliest kickoff) rather than being invented into the sequence.\n */\nfunction roundRank(round: string | null): number {\n if (!round) {\n return 9999;\n }\n const r = round.toLowerCase();\n const roundOf = r.match(/round of\\s*(\\d+)/);\n if (roundOf) {\n return 1000 - Number(roundOf[1]); // larger field ⇒ earlier column\n }\n if (/third|3rd/.test(r)) {\n return 1095;\n }\n if (/(grand\\s*)?final/.test(r) && !/semi|quarter/.test(r)) {\n return 1100;\n }\n if (/semi/.test(r)) {\n return 1050;\n }\n if (/quarter/.test(r)) {\n return 1020;\n }\n return 9999;\n}\n\ninterface RoundColumn {\n key: string;\n label: string;\n rank: number;\n earliest: number;\n fixtures: AthFixture[];\n}\n\n/** Group a competition's tournament fixtures into ordered round columns. */\nfunction buildRounds(fixtures: AthFixture[]): RoundColumn[] {\n const byRound = new Map<string, AthFixture[]>();\n for (const f of fixtures) {\n const key = f.round?.trim() || 'Unscheduled round';\n const list = byRound.get(key) ?? [];\n list.push(f);\n byRound.set(key, list);\n }\n return Array.from(byRound.entries())\n .map(([label, list]) => {\n const sorted = [...list].sort(\n (a, b) => new Date(a.scheduledAt).getTime() - new Date(b.scheduledAt).getTime()\n );\n const earliest = sorted.reduce(\n (acc, f) => Math.min(acc, new Date(f.scheduledAt).getTime() || acc),\n Number.POSITIVE_INFINITY\n );\n return {\n key: label,\n label,\n rank: roundRank(list[0]?.round ?? null),\n earliest: Number.isFinite(earliest) ? earliest : 0,\n fixtures: sorted,\n };\n })\n .sort((a, b) => (a.rank !== b.rank ? a.rank - b.rank : a.earliest - b.earliest));\n}\n\nexport function TournamentBracketPage() {\n const { navigateTo } = useAthleteBridge();\n const fixturesQuery = useFixtures({ pagination: { limit: 200 } });\n\n const tournamentFixtures = useMemo(\n () => (fixturesQuery.data?.items ?? []).filter((f) => f.type === 'TOURNAMENT'),\n [fixturesQuery.data]\n );\n\n const competitions = useMemo(() => {\n const set = new Set<string>();\n for (const f of tournamentFixtures) {\n set.add(f.competition?.trim() || 'Tournament');\n }\n return Array.from(set).sort();\n }, [tournamentFixtures]);\n\n const [selected, setSelected] = useState<string>('');\n const activeCompetition = selected || competitions[0] || '';\n\n const rounds = useMemo(() => {\n const forComp = tournamentFixtures.filter(\n (f) => (f.competition?.trim() || 'Tournament') === activeCompetition\n );\n return buildRounds(forComp);\n }, [tournamentFixtures, activeCompetition]);\n\n const matchCount = rounds.reduce((acc, r) => acc + r.fixtures.length, 0);\n\n // Champion: a COMPLETED final (last round) with a decided winner. No fabrication.\n const champion = useMemo(() => {\n const finalColumn = rounds[rounds.length - 1];\n if (!finalColumn) {\n return null;\n }\n for (const f of finalColumn.fixtures) {\n if (f.status !== 'COMPLETED') {\n continue;\n }\n const m = resolveMatchup(f);\n if (m.homeWon) {\n return { name: m.homeName, sport: m.homeSport, score: `${f.homeScore}–${f.awayScore}` };\n }\n if (m.awayWon) {\n return { name: m.awayName, sport: m.awaySport, score: `${f.awayScore}–${f.homeScore}` };\n }\n }\n return null;\n }, [rounds]);\n\n if (fixturesQuery.isLoading) {\n return (\n <PageLayout title=\"Tournaments\">\n <LoadingState label=\"Loading tournament fixtures…\" />\n </PageLayout>\n );\n }\n\n if (fixturesQuery.isError) {\n return (\n <PageLayout title=\"Tournaments\">\n <ErrorState onRetry={() => void fixturesQuery.refetch()} />\n </PageLayout>\n );\n }\n\n return (\n <PageLayout\n title=\"Tournaments\"\n description=\"Round-grouped brackets for your knockout competitions — every match is a real fixture.\"\n actions={\n competitions.length > 1 ? (\n <FilterSelect\n value={activeCompetition}\n onChange={(value) => setSelected(value)}\n options={competitions.map((c) => ({ value: c, label: c }))}\n allLabel=\"All competitions\"\n ariaLabel=\"Select competition\"\n />\n ) : undefined\n }\n >\n {tournamentFixtures.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<Trophy className=\"h-10 w-10\" />}\n title=\"No tournament fixtures yet\"\n description=\"Schedule fixtures with the Tournament type and a round label (e.g. “Quarter Finals”) to build a bracket.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/fixtures/new')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90\"\n >\n Schedule a fixture\n </button>\n }\n />\n ) : (\n <div className=\"space-y-6\">\n {/* Meta strip */}\n <GlassCard\n treatment=\"insight\"\n className=\"flex flex-wrap items-center gap-x-6 gap-y-3 p-5\"\n >\n <span className=\"flex items-center gap-2 text-lg font-semibold text-text-primary\">\n <Trophy className=\"h-5 w-5 text-[var(--color-accent-teal)]\" />\n {activeCompetition}\n </span>\n <span className=\"text-sm text-text-secondary\">\n <span className=\"font-semibold tabular-nums text-text-primary\">{rounds.length}</span>{' '}\n {rounds.length === 1 ? 'round' : 'rounds'}\n </span>\n <span className=\"text-sm text-text-secondary\">\n <span className=\"font-semibold tabular-nums text-text-primary\">{matchCount}</span>{' '}\n {matchCount === 1 ? 'match' : 'matches'}\n </span>\n <div className=\"ml-auto flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-text-secondary\">\n <StatusDot color={STATUS.success} label=\"Completed\" />\n <StatusDot color=\"var(--color-accent-primary)\" label=\"Live\" />\n <StatusDot color={STATUS.warning} label=\"Scheduled\" />\n </div>\n </GlassCard>\n\n {/* Bracket — horizontally scrollable columns */}\n <div className=\"overflow-x-auto pb-2\">\n <div className=\"flex min-w-max items-stretch gap-4\">\n {rounds.map((round) => (\n <div key={round.key} className=\"flex w-72 shrink-0 flex-col gap-3\">\n <div className=\"px-1\">\n <h2 className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n {round.label}\n </h2>\n {round.earliest > 0 ? (\n <p className=\"text-xs text-text-muted\">\n {formatDate(new Date(round.earliest).toISOString())}\n </p>\n ) : null}\n </div>\n <div className=\"flex flex-1 flex-col justify-around gap-3\">\n {round.fixtures.map((fixture) => (\n <MatchCard\n key={fixture.id}\n fixture={fixture}\n onClick={() => navigateTo(`/fixtures/${fixture.id}`)}\n />\n ))}\n </div>\n </div>\n ))}\n\n {/* Champion column (only when a real completed final exists) */}\n {champion ? (\n <div className=\"flex w-72 shrink-0 flex-col justify-center gap-3\">\n <div className=\"px-1\">\n <h2 className=\"text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n Champion\n </h2>\n </div>\n <GlassCard\n treatment=\"glass\"\n className=\"flex flex-col items-center gap-3 p-6 text-center\"\n >\n <Trophy className=\"h-8 w-8 text-[var(--color-status-warning-text)]\" />\n <Crest name={champion.name} sport={champion.sport} size={56} />\n <div>\n <p className=\"text-lg font-semibold text-text-primary\">{champion.name}</p>\n <p className=\"mt-0.5 text-sm tabular-nums text-text-secondary\">\n Won {champion.score}\n </p>\n </div>\n <Badge variant=\"default\">Champions</Badge>\n </GlassCard>\n </div>\n ) : null}\n </div>\n </div>\n\n {rounds.length === 0 ? (\n <EmptyState\n illustration=\"empty-calendar\"\n icon={<Gamepad2 className=\"h-10 w-10\" />}\n title=\"No matches in this competition\"\n description=\"Add round labels to this competition's tournament fixtures to populate the bracket.\"\n />\n ) : null}\n </div>\n )}\n </PageLayout>\n );\n}\n\n// ── Match card ───────────────────────────────────────────────────────────────\n\ninterface MatchCardProps {\n fixture: AthFixture;\n onClick: () => void;\n}\n\nfunction MatchCard({ fixture, onClick }: MatchCardProps) {\n const m = resolveMatchup(fixture);\n const dot = STATUS_DOT[fixture.status];\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"group w-full rounded-[var(--radius-card)] border border-border-seam bg-bg-surface p-3 text-left transition-all duration-200 hover:-translate-y-0.5 hover:border-border-strong hover:shadow-elevation-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <MatchSide\n name={m.homeName}\n sport={m.homeSport}\n score={fixture.homeScore}\n won={m.homeWon}\n dimmed={m.awayWon}\n />\n <div className=\"my-1 h-px bg-border-seam\" aria-hidden=\"true\" />\n <MatchSide\n name={m.awayName}\n sport={m.awaySport}\n score={fixture.awayScore}\n won={m.awayWon}\n dimmed={m.homeWon}\n />\n <div className=\"mt-2 flex items-center gap-1.5 text-xs text-text-muted\">\n <span\n className=\"h-1.5 w-1.5 rounded-full\"\n style={{ backgroundColor: dot }}\n aria-hidden=\"true\"\n />\n <span className=\"capitalize\">{fixture.status.toLowerCase().replace(/_/g, ' ')}</span>\n {fixture.venue ? <span className=\"truncate\">· {fixture.venue}</span> : null}\n </div>\n </button>\n );\n}\n\ninterface MatchSideProps {\n name: string;\n sport?: AthSport;\n score: number | null;\n won: boolean;\n dimmed: boolean;\n}\n\nfunction MatchSide({ name, sport, score, won, dimmed }: MatchSideProps) {\n return (\n <div className=\"flex items-center gap-2\">\n <Crest name={name} sport={sport} size={22} showSportGlyph={false} />\n <span\n className={\n won\n ? 'min-w-0 flex-1 truncate text-sm font-semibold text-status-success-text'\n : dimmed\n ? 'min-w-0 flex-1 truncate text-sm text-text-muted'\n : 'min-w-0 flex-1 truncate text-sm font-medium text-text-primary'\n }\n >\n {name}\n </span>\n <span\n className={\n won\n ? 'shrink-0 text-sm font-bold tabular-nums text-status-success-text'\n : 'shrink-0 text-sm font-semibold tabular-nums text-text-secondary'\n }\n >\n {score ?? '–'}\n </span>\n </div>\n );\n}\n\n// ── Legend dot ───────────────────────────────────────────────────────────────\n\nfunction StatusDot({ color, label }: { color: string; label: string }) {\n return (\n <span className=\"flex items-center gap-1.5\">\n <span\n className=\"h-2 w-2 rounded-full\"\n style={{ backgroundColor: color }}\n aria-hidden=\"true\"\n />\n {label}\n </span>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"atheletebridgeStore.js","names":[],"sources":["../../../src/atheletebridge/store/atheletebridgeStore.ts"],"sourcesContent":["/**\n * AthleteBridge Zustand Store\n * @module atheletebridge/store\n *\n * Local UI state only (view mode, sidebar). Server state lives in React Query.\n */\n\nimport { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\nimport { createProfileScopedStorage } from '@burdenoff/fe-libs/shared/utils';\nimport type { ViewMode } from '../types';\n\n// ============================================================================\n// State Interface\n// ============================================================================\n\ninterface AthleteBridgeState {\n viewMode: ViewMode;\n sidebarCollapsed: boolean;\n\n setViewMode: (mode: ViewMode) => void;\n toggleSidebar: () => void;\n reset: () => void;\n}\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst initialState = {\n viewMode: 'grid' as ViewMode,\n sidebarCollapsed: false,\n};\n\n// ============================================================================\n// Store\n// ============================================================================\n\nexport const useAthleteBridgeStore = create<AthleteBridgeState>()(\n devtools(\n persist(\n (set) => ({\n ...initialState,\n\n setViewMode: (mode) => set({ viewMode: mode }),\n toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),\n\n reset: () => set(initialState),\n }),\n {\n name: 'burdenoff-atheletebridge-storage',\n storage: createProfileScopedStorage(),\n partialize: (state) => ({\n viewMode: state.viewMode,\n sidebarCollapsed: state.sidebarCollapsed,\n }),\n }\n ),\n { name: 'AthleteBridge Store', enabled: import.meta.env.DEV }\n )\n);\n"],"mappings":";;;;AA6BA,IAAM,IAAe;CACnB,UAAU;CACV,kBAAkB;
|
|
1
|
+
{"version":3,"file":"atheletebridgeStore.js","names":[],"sources":["../../../src/atheletebridge/store/atheletebridgeStore.ts"],"sourcesContent":["/**\n * AthleteBridge Zustand Store\n * @module atheletebridge/store\n *\n * Local UI state only (view mode, sidebar). Server state lives in React Query.\n */\n\nimport { create } from 'zustand';\nimport { devtools, persist } from 'zustand/middleware';\nimport { createProfileScopedStorage } from '@burdenoff/fe-libs/shared/utils';\nimport type { ViewMode } from '../types';\n\n// ============================================================================\n// State Interface\n// ============================================================================\n\ninterface AthleteBridgeState {\n viewMode: ViewMode;\n sidebarCollapsed: boolean;\n\n setViewMode: (mode: ViewMode) => void;\n toggleSidebar: () => void;\n reset: () => void;\n}\n\n// ============================================================================\n// Initial State\n// ============================================================================\n\nconst initialState = {\n viewMode: 'grid' as ViewMode,\n sidebarCollapsed: false,\n};\n\n// ============================================================================\n// Store\n// ============================================================================\n\nexport const useAthleteBridgeStore = create<AthleteBridgeState>()(\n devtools(\n persist(\n (set) => ({\n ...initialState,\n\n setViewMode: (mode) => set({ viewMode: mode }),\n toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),\n\n reset: () => set(initialState),\n }),\n {\n name: 'burdenoff-atheletebridge-storage',\n storage: createProfileScopedStorage(),\n partialize: (state) => ({\n viewMode: state.viewMode,\n sidebarCollapsed: state.sidebarCollapsed,\n }),\n }\n ),\n { name: 'AthleteBridge Store', enabled: import.meta.env.DEV }\n )\n);\n"],"mappings":";;;;AA6BA,IAAM,IAAe;CACnB,UAAU;CACV,kBAAkB;AACpB,GAMa,IAAwB,EAA2B,EAC9D,EACE,GACG,OAAS;CACR,GAAG;CAEH,cAAc,MAAS,EAAI,EAAE,UAAU,EAAK,CAAC;CAC7C,qBAAqB,GAAK,OAAW,EAAE,kBAAkB,CAAC,EAAM,iBAAiB,EAAE;CAEnF,aAAa,EAAI,CAAY;AAC/B,IACA;CACE,MAAM;CACN,SAAS,EAA2B;CACpC,aAAa,OAAW;EACtB,UAAU,EAAM;EAChB,kBAAkB,EAAM;CAC1B;AACF,CACF,GACA;CAAE,MAAM;CAAuB,SAAA;AAA6B,CAC9D,CACF"}
|
|
@@ -296,6 +296,25 @@ export interface AthPerformanceMetricConnection {
|
|
|
296
296
|
items: AthPerformanceMetric[];
|
|
297
297
|
pageInfo: AthPageInfo;
|
|
298
298
|
}
|
|
299
|
+
export type AthAvailabilityResponse = 'YES' | 'NO' | 'MAYBE' | 'NO_RESPONSE';
|
|
300
|
+
/** Availability / RSVP for a fixture or session (BOFF-4134). */
|
|
301
|
+
export interface AthAvailability {
|
|
302
|
+
id: string;
|
|
303
|
+
workspaceId: string;
|
|
304
|
+
memberId: string;
|
|
305
|
+
fixtureId: string | null;
|
|
306
|
+
sessionId: string | null;
|
|
307
|
+
response: AthAvailabilityResponse;
|
|
308
|
+
respondedAt: string | null;
|
|
309
|
+
note: string | null;
|
|
310
|
+
createdAt: string;
|
|
311
|
+
updatedAt: string;
|
|
312
|
+
member?: Pick<AthMember, 'id' | 'displayName' | 'role'> | null;
|
|
313
|
+
}
|
|
314
|
+
export interface AthAvailabilityConnection {
|
|
315
|
+
items: AthAvailability[];
|
|
316
|
+
pageInfo: AthPageInfo;
|
|
317
|
+
}
|
|
299
318
|
export interface AthCreateTeamInput {
|
|
300
319
|
name: string;
|
|
301
320
|
sport?: AthSport;
|
|
@@ -424,4 +443,12 @@ export interface AthRecordMetricInput {
|
|
|
424
443
|
source?: string;
|
|
425
444
|
recordedAt: string;
|
|
426
445
|
}
|
|
446
|
+
/** Exactly one of fixtureId / sessionId must be supplied. */
|
|
447
|
+
export interface AthSetAvailabilityInput {
|
|
448
|
+
memberId: string;
|
|
449
|
+
fixtureId?: string;
|
|
450
|
+
sessionId?: string;
|
|
451
|
+
response: AthAvailabilityResponse;
|
|
452
|
+
note?: string;
|
|
453
|
+
}
|
|
427
454
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/types/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atheletebridge/types/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cn.js","names":[],"sources":["../../../src/atheletebridge/utils/cn.ts"],"sourcesContent":["/**\n * Class name utility\n * @module atheletebridge/utils\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";;;AAQA,SAAgB,EAAG,GAAG,GAA8B;
|
|
1
|
+
{"version":3,"file":"cn.js","names":[],"sources":["../../../src/atheletebridge/utils/cn.ts"],"sourcesContent":["/**\n * Class name utility\n * @module atheletebridge/utils\n */\n\nimport { clsx, type ClassValue } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";;;AAQA,SAAgB,EAAG,GAAG,GAA8B;CAClD,OAAO,EAAQ,EAAK,CAAM,CAAC;AAC7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"datetime.js","names":[],"sources":["../../../src/atheletebridge/utils/datetime.ts"],"sourcesContent":["/**\n * Datetime helpers for form inputs\n * @module atheletebridge/utils/datetime\n */\n\n/**\n * Convert a `datetime-local` input value to an ISO string, or undefined when\n * the value is empty. Returns undefined for unparseable values so callers never\n * send \"Invalid Date\" to the API.\n */\nexport function toIsoOrUndefined(value: string): string | undefined {\n if (!value) return undefined;\n const d = new Date(value);\n return Number.isNaN(d.getTime()) ? undefined : d.toISOString();\n}\n\n/**\n * Convert an ISO datetime string into the `datetime-local` input format\n * (`YYYY-MM-DDTHH:mm`) in the browser's local timezone.\n */\nexport function isoToLocalInput(iso: string | null | undefined): string {\n if (!iso) return '';\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return '';\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(\n d.getHours()\n )}:${pad(d.getMinutes())}`;\n}\n"],"mappings":";AAUA,SAAgB,EAAiB,GAAmC;
|
|
1
|
+
{"version":3,"file":"datetime.js","names":[],"sources":["../../../src/atheletebridge/utils/datetime.ts"],"sourcesContent":["/**\n * Datetime helpers for form inputs\n * @module atheletebridge/utils/datetime\n */\n\n/**\n * Convert a `datetime-local` input value to an ISO string, or undefined when\n * the value is empty. Returns undefined for unparseable values so callers never\n * send \"Invalid Date\" to the API.\n */\nexport function toIsoOrUndefined(value: string): string | undefined {\n if (!value) return undefined;\n const d = new Date(value);\n return Number.isNaN(d.getTime()) ? undefined : d.toISOString();\n}\n\n/**\n * Convert an ISO datetime string into the `datetime-local` input format\n * (`YYYY-MM-DDTHH:mm`) in the browser's local timezone.\n */\nexport function isoToLocalInput(iso: string | null | undefined): string {\n if (!iso) return '';\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return '';\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(\n d.getHours()\n )}:${pad(d.getMinutes())}`;\n}\n"],"mappings":";AAUA,SAAgB,EAAiB,GAAmC;CAClE,IAAI,CAAC,GAAO;CACZ,IAAM,IAAI,IAAI,KAAK,CAAK;CACxB,OAAO,OAAO,MAAM,EAAE,QAAQ,CAAC,IAAI,KAAA,IAAY,EAAE,YAAY;AAC/D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatters.js","names":[],"sources":["../../../src/atheletebridge/utils/formatters.ts"],"sourcesContent":["/**\n * Formatting utilities for the AthleteBridge microfrontend\n * @module atheletebridge/utils/formatters\n */\n\n/**\n * Format a date string or Date object into a human-readable format\n *\n * @param date - ISO date string or Date object\n * @param options - Optional Intl.DateTimeFormat options\n * @returns Formatted date string (e.g., \"15 Jan 2024, 4:00 PM\")\n *\n * @example\n * formatDate('2024-01-15T10:30:00Z')\n * // => \"15 Jan 2024, 4:00 PM\" (in IST)\n */\nexport function formatDate(\n date: string | Date,\n options?: Partial<Intl.DateTimeFormatOptions>\n): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n return new Intl.DateTimeFormat('en-IN', {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n ...options,\n }).format(d);\n}\n\n/**\n * Format a duration in minutes into a human-readable string\n *\n * @param minutes - Duration in minutes\n * @returns Formatted duration string\n *\n * @example\n * formatDuration(5) // => \"5 min\"\n * formatDuration(90) // => \"1h 30min\"\n * formatDuration(1440) // => \"1 day\"\n * formatDuration(4320) // => \"3 days\"\n */\nexport function formatDuration(minutes: number): string {\n if (minutes < 1) return 'instant';\n if (minutes < 60) return `${minutes} min`;\n\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n\n if (hours < 24) {\n if (remainingMinutes === 0) {\n return `${hours}h`;\n }\n return `${hours}h ${remainingMinutes}min`;\n }\n\n const days = Math.floor(hours / 24);\n const remainingHours = hours % 24;\n\n if (remainingHours === 0) {\n return `${days} day${days !== 1 ? 's' : ''}`;\n }\n return `${days} day${days !== 1 ? 's' : ''} ${remainingHours}h`;\n}\n"],"mappings":";AAgBA,SAAgB,EACd,GACA,GACQ;CACR,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"formatters.js","names":[],"sources":["../../../src/atheletebridge/utils/formatters.ts"],"sourcesContent":["/**\n * Formatting utilities for the AthleteBridge microfrontend\n * @module atheletebridge/utils/formatters\n */\n\n/**\n * Format a date string or Date object into a human-readable format\n *\n * @param date - ISO date string or Date object\n * @param options - Optional Intl.DateTimeFormat options\n * @returns Formatted date string (e.g., \"15 Jan 2024, 4:00 PM\")\n *\n * @example\n * formatDate('2024-01-15T10:30:00Z')\n * // => \"15 Jan 2024, 4:00 PM\" (in IST)\n */\nexport function formatDate(\n date: string | Date,\n options?: Partial<Intl.DateTimeFormatOptions>\n): string {\n const d = typeof date === 'string' ? new Date(date) : date;\n return new Intl.DateTimeFormat('en-IN', {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n ...options,\n }).format(d);\n}\n\n/**\n * Format a duration in minutes into a human-readable string\n *\n * @param minutes - Duration in minutes\n * @returns Formatted duration string\n *\n * @example\n * formatDuration(5) // => \"5 min\"\n * formatDuration(90) // => \"1h 30min\"\n * formatDuration(1440) // => \"1 day\"\n * formatDuration(4320) // => \"3 days\"\n */\nexport function formatDuration(minutes: number): string {\n if (minutes < 1) return 'instant';\n if (minutes < 60) return `${minutes} min`;\n\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n\n if (hours < 24) {\n if (remainingMinutes === 0) {\n return `${hours}h`;\n }\n return `${hours}h ${remainingMinutes}min`;\n }\n\n const days = Math.floor(hours / 24);\n const remainingHours = hours % 24;\n\n if (remainingHours === 0) {\n return `${days} day${days !== 1 ? 's' : ''}`;\n }\n return `${days} day${days !== 1 ? 's' : ''} ${remainingHours}h`;\n}\n"],"mappings":";AAgBA,SAAgB,EACd,GACA,GACQ;CACR,IAAM,IAAI,OAAO,KAAS,WAAW,IAAI,KAAK,CAAI,IAAI;CACtD,OAAO,IAAI,KAAK,eAAe,SAAS;EACtC,KAAK;EACL,OAAO;EACP,MAAM;EACN,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,GAAG;CACL,CAAC,EAAE,OAAO,CAAC;AACb;AAcA,SAAgB,EAAe,GAAyB;CACtD,IAAI,IAAU,GAAG,OAAO;CACxB,IAAI,IAAU,IAAI,OAAO,GAAG,EAAQ;CAEpC,IAAM,IAAQ,KAAK,MAAM,IAAU,EAAE,GAC/B,IAAmB,IAAU;CAEnC,IAAI,IAAQ,IAIV,OAHI,MAAqB,IAChB,GAAG,EAAM,KAEX,GAAG,EAAM,IAAI,EAAiB;CAGvC,IAAM,IAAO,KAAK,MAAM,IAAQ,EAAE,GAC5B,IAAiB,IAAQ;CAK/B,OAHI,MAAmB,IACd,GAAG,EAAK,MAAM,MAAS,IAAU,KAAN,QAE7B,GAAG,EAAK,MAAM,MAAS,IAAU,KAAN,IAAS,GAAG,EAAe;AAC/D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","names":[],"sources":["../../../src/atheletebridge/utils/identity.ts"],"sourcesContent":["/**\n * Deterministic identity helpers\n * @module atheletebridge/utils/identity\n *\n * Stable, seed-derived visuals for teams / athletes / coaches. The backend has\n * NO logo or photo field, so crests and avatars are honest monogram stand-ins:\n * initials over a gradient chosen deterministically from the entity's name/id.\n * Every color is a fe-libs semantic token — never a raw hex.\n */\n\n/** Small stable, order-independent-per-char string hash (djb2 xor variant). */\nexport function stableHash(input: string): number {\n let hash = 5381;\n for (let i = 0; i < input.length; i += 1) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n // Force to a positive 32-bit int.\n return hash >>> 0;\n}\n\n/** Up-to-`max`-letter initials from a display name (e.g. \"Riverside FC\" → \"RF\"). */\nexport function initials(name: string, max = 2): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) {\n return '?';\n }\n if (parts.length === 1) {\n return parts[0].slice(0, max).toUpperCase();\n }\n return parts\n .slice(0, max)\n .map((p) => p[0])\n .join('')\n .toUpperCase();\n}\n\n/**\n * Curated tokenized gradient stop pairs. Drawn from the categorical chart tokens\n * and product accents so crests read as distinct \"club colors\" while staying\n * theme-aware. Never emit a raw color.\n */\nexport const CREST_GRADIENTS: readonly [string, string][] = [\n ['var(--color-accent-primary)', 'var(--color-chart-2)'],\n ['var(--color-accent-blue)', 'var(--color-accent-indigo)'],\n ['var(--color-accent-teal)', 'var(--color-chart-3)'],\n ['var(--color-accent-purple)', 'var(--color-chart-11)'],\n ['var(--color-chart-4)', 'var(--color-chart-5)'],\n ['var(--color-chart-6)', 'var(--color-chart-7)'],\n ['var(--color-chart-8)', 'var(--color-chart-9)'],\n ['var(--color-chart-10)', 'var(--color-chart-12)'],\n];\n\n/** Deterministic gradient stop pair for a seed (name or id). */\nexport function gradientForSeed(seed: string): [string, string] {\n return CREST_GRADIENTS[stableHash(seed) % CREST_GRADIENTS.length];\n}\n\n/** A CSS `linear-gradient(...)` string for a seed, ready for a `background` style. */\nexport function gradientCss(seed: string, angle = 135): string {\n const [from, to] = gradientForSeed(seed);\n return `linear-gradient(${angle}deg, ${from}, ${to})`;\n}\n"],"mappings":";AAWA,SAAgB,EAAW,GAAuB;CAChD,IAAI,IAAO;
|
|
1
|
+
{"version":3,"file":"identity.js","names":[],"sources":["../../../src/atheletebridge/utils/identity.ts"],"sourcesContent":["/**\n * Deterministic identity helpers\n * @module atheletebridge/utils/identity\n *\n * Stable, seed-derived visuals for teams / athletes / coaches. The backend has\n * NO logo or photo field, so crests and avatars are honest monogram stand-ins:\n * initials over a gradient chosen deterministically from the entity's name/id.\n * Every color is a fe-libs semantic token — never a raw hex.\n */\n\n/** Small stable, order-independent-per-char string hash (djb2 xor variant). */\nexport function stableHash(input: string): number {\n let hash = 5381;\n for (let i = 0; i < input.length; i += 1) {\n hash = (hash * 33) ^ input.charCodeAt(i);\n }\n // Force to a positive 32-bit int.\n return hash >>> 0;\n}\n\n/** Up-to-`max`-letter initials from a display name (e.g. \"Riverside FC\" → \"RF\"). */\nexport function initials(name: string, max = 2): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) {\n return '?';\n }\n if (parts.length === 1) {\n return parts[0].slice(0, max).toUpperCase();\n }\n return parts\n .slice(0, max)\n .map((p) => p[0])\n .join('')\n .toUpperCase();\n}\n\n/**\n * Curated tokenized gradient stop pairs. Drawn from the categorical chart tokens\n * and product accents so crests read as distinct \"club colors\" while staying\n * theme-aware. Never emit a raw color.\n */\nexport const CREST_GRADIENTS: readonly [string, string][] = [\n ['var(--color-accent-primary)', 'var(--color-chart-2)'],\n ['var(--color-accent-blue)', 'var(--color-accent-indigo)'],\n ['var(--color-accent-teal)', 'var(--color-chart-3)'],\n ['var(--color-accent-purple)', 'var(--color-chart-11)'],\n ['var(--color-chart-4)', 'var(--color-chart-5)'],\n ['var(--color-chart-6)', 'var(--color-chart-7)'],\n ['var(--color-chart-8)', 'var(--color-chart-9)'],\n ['var(--color-chart-10)', 'var(--color-chart-12)'],\n];\n\n/** Deterministic gradient stop pair for a seed (name or id). */\nexport function gradientForSeed(seed: string): [string, string] {\n return CREST_GRADIENTS[stableHash(seed) % CREST_GRADIENTS.length];\n}\n\n/** A CSS `linear-gradient(...)` string for a seed, ready for a `background` style. */\nexport function gradientCss(seed: string, angle = 135): string {\n const [from, to] = gradientForSeed(seed);\n return `linear-gradient(${angle}deg, ${from}, ${to})`;\n}\n"],"mappings":";AAWA,SAAgB,EAAW,GAAuB;CAChD,IAAI,IAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAAK,GACrC,IAAQ,IAAO,KAAM,EAAM,WAAW,CAAC;CAGzC,OAAO,MAAS;AAClB;AAGA,SAAgB,EAAS,GAAc,IAAM,GAAW;CACtD,IAAM,IAAQ,EAAK,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;CAOrD,OANI,EAAM,WAAW,IACZ,MAEL,EAAM,WAAW,IACZ,EAAM,GAAG,MAAM,GAAG,CAAG,EAAE,YAAY,IAErC,EACJ,MAAM,GAAG,CAAG,EACZ,KAAK,MAAM,EAAE,EAAE,EACf,KAAK,EAAE,EACP,YAAY;AACjB;AAOA,IAAa,IAA+C;CAC1D,CAAC,+BAA+B,sBAAsB;CACtD,CAAC,4BAA4B,4BAA4B;CACzD,CAAC,4BAA4B,sBAAsB;CACnD,CAAC,8BAA8B,uBAAuB;CACtD,CAAC,wBAAwB,sBAAsB;CAC/C,CAAC,wBAAwB,sBAAsB;CAC/C,CAAC,wBAAwB,sBAAsB;CAC/C,CAAC,yBAAyB,uBAAuB;AACnD;AAGA,SAAgB,EAAgB,GAAgC;CAC9D,OAAO,EAAgB,EAAW,CAAI,IAAI,EAAgB;AAC5D;AAGA,SAAgB,EAAY,GAAc,IAAQ,KAAa;CAC7D,IAAM,CAAC,GAAM,KAAM,EAAgB,CAAI;CACvC,OAAO,mBAAmB,EAAM,OAAO,EAAK,IAAI,EAAG;AACrD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigation.js","names":[],"sources":["../../../src/atheletebridge/utils/navigation.ts"],"sourcesContent":["/**\n * Navigation utilities for the AthleteBridge microfrontend\n * @module atheletebridge/utils\n */\n\n/**\n * Join basePath with a relative path, correctly handling slashes\n *\n * @param basePath - The base path (e.g., '/' or '/atheletebridge')\n * @param relativePath - The relative path (e.g., 'carts/new' or '/carts/new')\n * @returns The joined path (e.g., '/atheletebridge/carts/new')\n *\n * @example\n * joinPath('/', 'carts/new') // => '/carts/new'\n * joinPath('/', '/carts/new') // => '/carts/new'\n * joinPath('/atheletebridge', 'orders') // => '/atheletebridge/orders'\n * joinPath('/atheletebridge/', 'orders') // => '/atheletebridge/orders'\n * joinPath('/atheletebridge', '') // => '/atheletebridge'\n */\nexport function joinPath(basePath: string, relativePath: string): string {\n // Remove trailing slash from base\n const cleanBase = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;\n\n // Handle empty relative path (go to base)\n if (!relativePath || relativePath === '') {\n return cleanBase || '/';\n }\n\n // Ensure relative path starts with /\n const cleanPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}`;\n\n // Join them\n return cleanBase + cleanPath;\n}\n"],"mappings":";AAmBA,SAAgB,EAAS,GAAkB,GAA8B;CAEvE,IAAM,IAAY,EAAS,SAAS,IAAI,
|
|
1
|
+
{"version":3,"file":"navigation.js","names":[],"sources":["../../../src/atheletebridge/utils/navigation.ts"],"sourcesContent":["/**\n * Navigation utilities for the AthleteBridge microfrontend\n * @module atheletebridge/utils\n */\n\n/**\n * Join basePath with a relative path, correctly handling slashes\n *\n * @param basePath - The base path (e.g., '/' or '/atheletebridge')\n * @param relativePath - The relative path (e.g., 'carts/new' or '/carts/new')\n * @returns The joined path (e.g., '/atheletebridge/carts/new')\n *\n * @example\n * joinPath('/', 'carts/new') // => '/carts/new'\n * joinPath('/', '/carts/new') // => '/carts/new'\n * joinPath('/atheletebridge', 'orders') // => '/atheletebridge/orders'\n * joinPath('/atheletebridge/', 'orders') // => '/atheletebridge/orders'\n * joinPath('/atheletebridge', '') // => '/atheletebridge'\n */\nexport function joinPath(basePath: string, relativePath: string): string {\n // Remove trailing slash from base\n const cleanBase = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;\n\n // Handle empty relative path (go to base)\n if (!relativePath || relativePath === '') {\n return cleanBase || '/';\n }\n\n // Ensure relative path starts with /\n const cleanPath = relativePath.startsWith('/') ? relativePath : `/${relativePath}`;\n\n // Join them\n return cleanBase + cleanPath;\n}\n"],"mappings":";AAmBA,SAAgB,EAAS,GAAkB,GAA8B;CAEvE,IAAM,IAAY,EAAS,SAAS,GAAG,IAAI,EAAS,MAAM,GAAG,EAAE,IAAI;CAWnE,OARI,CAAC,KAAgB,MAAiB,KAC7B,KAAa,MAOf,KAHW,EAAa,WAAW,GAAG,IAAI,IAAe,IAAI;AAItE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pageContext.js","names":[],"sources":["../../../src/atheletebridge/utils/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering — captures the user's current route context so the\n * assistant can resolve \"this / current / here\" without asking for an id.\n *\n * Two rules govern this file:\n *\n * 1. The capture index is declared PER ROUTE (`idGroup`), never assumed to be\n * `match[1]`. The athlete route (`/teams/:teamId/athletes/:memberId`) has two\n * captures, and a shared `match[1]` read handed the assistant an\n * `ATHLETEBRIDGE_ATHLETE` entityType paired with a TEAM id — a\n * confidently-wrong context. Declaring the group per row makes that class of\n * bug unrepresentable.\n * 2. Only ids and types cross the wire. No athlete names, emails or metric\n * values are ever forwarded, and only keys the agent actually accepts\n * (`ALLOWED_CONTEXT_KEYS` in wspace/sandbox/ai-assistant/src/context-loader.ts)\n * are emitted — `userAgent`/`timestamp` used to be sent and silently dropped.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n // The entity the user is currently looking at, resolved from the route.\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n}\n\n/**\n * Route segments that are literals in the router, not entity ids. Without this\n * guard `/atheletebridge/teams/new` resolves to `entityId: 'new'`.\n */\nconst RESERVED_ID_SEGMENTS = new Set(['new', 'edit']);\n\ninterface RouteDescriptor {\n pattern: RegExp;\n entityType: string;\n /**\n * 1-based capture group holding the entity id, or 0 for index routes that\n * name a surface rather than a single record.\n */\n idGroup: number;\n /** Extra ids/flags derived from the match. Ids and types only — never names. */\n metadata?: (match: RegExpMatchArray) => Record<string, unknown>;\n}\n\n/**\n * Mirrors the routes registered in AthleteBridgeRoutes.tsx. Every shipped route\n * that names something the assistant can act on has a row here; anything absent\n * falls through to the generic `activeTab` branch and binds to nothing.\n */\nconst ROUTE_DESCRIPTORS: RouteDescriptor[] = [\n // Athlete detail is matched BEFORE team detail: its path is a strict\n // extension of the team path and the more specific pattern must win.\n {\n pattern: /^\\/atheletebridge\\/teams\\/([^/]+)\\/athletes\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_ATHLETE',\n idGroup: 2,\n metadata: (match) => ({ teamId: match[1] }),\n },\n {\n pattern: /^\\/atheletebridge\\/teams\\/([^/]+)\\/edit$/,\n entityType: 'ATHLETEBRIDGE_TEAM',\n idGroup: 1,\n metadata: () => ({ mode: 'edit' }),\n },\n {\n pattern: /^\\/atheletebridge\\/teams\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_TEAM',\n idGroup: 1,\n },\n { pattern: /^\\/atheletebridge\\/teams$/, entityType: 'ATHLETEBRIDGE_TEAMS', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/fixtures\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_FIXTURE',\n idGroup: 1,\n },\n { pattern: /^\\/atheletebridge\\/fixtures$/, entityType: 'ATHLETEBRIDGE_FIXTURES', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/programs\\/([^/]+)\\/edit$/,\n entityType: 'ATHLETEBRIDGE_PROGRAM',\n idGroup: 1,\n metadata: () => ({ mode: 'edit' }),\n },\n {\n pattern: /^\\/atheletebridge\\/programs\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_PROGRAM',\n idGroup: 1,\n },\n { pattern: /^\\/atheletebridge\\/programs$/, entityType: 'ATHLETEBRIDGE_PROGRAMS', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/sessions\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_SESSION',\n idGroup: 1,\n },\n { pattern: /^\\/atheletebridge\\/sessions$/, entityType: 'ATHLETEBRIDGE_SESSIONS', idGroup: 0 },\n // Index-only surfaces. AthleteBridgeRoutes.tsx registers no detail route for\n // these, so an id-capturing pattern here could never match anything real.\n { pattern: /^\\/atheletebridge\\/standings$/, entityType: 'ATHLETEBRIDGE_STANDINGS', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/performance$/,\n entityType: 'ATHLETEBRIDGE_PERFORMANCE',\n idGroup: 0,\n },\n { pattern: /^\\/atheletebridge\\/analytics$/, entityType: 'ATHLETEBRIDGE_ANALYTICS', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/tournaments$/,\n entityType: 'ATHLETEBRIDGE_TOURNAMENTS',\n idGroup: 0,\n },\n { pattern: /^\\/atheletebridge\\/onboarding$/, entityType: 'ATHLETEBRIDGE_ONBOARDING', idGroup: 0 },\n];\n\nexport function gatherPageContext(): PageContext {\n const pathSegments = window.location.pathname.split('/').filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join('/') || 'home';\n const entity = resolveAthleteBridgeConversationContext(\n window.location.pathname,\n window.location.search\n );\n\n return {\n currentUrl: window.location.href,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n activeTab: entity.activeTab,\n };\n}\n\nexport function resolveAthleteBridgeConversationContext(\n pathname: string,\n search: string\n): ConversationContextShape {\n const params = new URLSearchParams(search);\n\n for (const descriptor of ROUTE_DESCRIPTORS) {\n const match = pathname.match(descriptor.pattern);\n if (!match) continue;\n\n const entityId = descriptor.idGroup > 0 ? match[descriptor.idGroup] : undefined;\n // `/teams/new` shape-matches `/teams/:id` — a router literal is not an id.\n if (entityId !== undefined && RESERVED_ID_SEGMENTS.has(entityId)) continue;\n\n return {\n entityType: descriptor.entityType,\n ...(entityId ? { entityId } : {}),\n metadata: {\n routePattern: descriptor.pattern.source,\n ...(descriptor.metadata ? descriptor.metadata(match) : {}),\n },\n };\n }\n\n const activeTab =\n params.get('tab') ??\n (() => {\n const segments = pathname.split('/').filter(Boolean);\n return segments.length > 2 ? segments[segments.length - 1] : undefined;\n })();\n\n return {\n activeTab: activeTab ?? undefined,\n metadata: {\n ...(activeTab ? { activeTab } : {}),\n },\n };\n}\n"],"mappings":";AAwCA,IAAM,IAAuB,IAAI,IAAI,CAAC,OAAO,
|
|
1
|
+
{"version":3,"file":"pageContext.js","names":[],"sources":["../../../src/atheletebridge/utils/pageContext.ts"],"sourcesContent":["/**\n * Page context gathering — captures the user's current route context so the\n * assistant can resolve \"this / current / here\" without asking for an id.\n *\n * Two rules govern this file:\n *\n * 1. The capture index is declared PER ROUTE (`idGroup`), never assumed to be\n * `match[1]`. The athlete route (`/teams/:teamId/athletes/:memberId`) has two\n * captures, and a shared `match[1]` read handed the assistant an\n * `ATHLETEBRIDGE_ATHLETE` entityType paired with a TEAM id — a\n * confidently-wrong context. Declaring the group per row makes that class of\n * bug unrepresentable.\n * 2. Only ids and types cross the wire. No athlete names, emails or metric\n * values are ever forwarded, and only keys the agent actually accepts\n * (`ALLOWED_CONTEXT_KEYS` in wspace/sandbox/ai-assistant/src/context-loader.ts)\n * are emitted — `userAgent`/`timestamp` used to be sent and silently dropped.\n */\n\ninterface ConversationContextShape {\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PageContext {\n // `currentUrl` (NOT `activeUrl`) — must match the agent's allowed-context-key\n // contract, otherwise the agent filters it out.\n currentUrl: string;\n currentPage: string;\n // The entity the user is currently looking at, resolved from the route.\n entityType?: string;\n entityId?: string;\n activeTab?: string;\n}\n\n/**\n * Route segments that are literals in the router, not entity ids. Without this\n * guard `/atheletebridge/teams/new` resolves to `entityId: 'new'`.\n */\nconst RESERVED_ID_SEGMENTS = new Set(['new', 'edit']);\n\ninterface RouteDescriptor {\n pattern: RegExp;\n entityType: string;\n /**\n * 1-based capture group holding the entity id, or 0 for index routes that\n * name a surface rather than a single record.\n */\n idGroup: number;\n /** Extra ids/flags derived from the match. Ids and types only — never names. */\n metadata?: (match: RegExpMatchArray) => Record<string, unknown>;\n}\n\n/**\n * Mirrors the routes registered in AthleteBridgeRoutes.tsx. Every shipped route\n * that names something the assistant can act on has a row here; anything absent\n * falls through to the generic `activeTab` branch and binds to nothing.\n */\nconst ROUTE_DESCRIPTORS: RouteDescriptor[] = [\n // Athlete detail is matched BEFORE team detail: its path is a strict\n // extension of the team path and the more specific pattern must win.\n {\n pattern: /^\\/atheletebridge\\/teams\\/([^/]+)\\/athletes\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_ATHLETE',\n idGroup: 2,\n metadata: (match) => ({ teamId: match[1] }),\n },\n {\n pattern: /^\\/atheletebridge\\/teams\\/([^/]+)\\/edit$/,\n entityType: 'ATHLETEBRIDGE_TEAM',\n idGroup: 1,\n metadata: () => ({ mode: 'edit' }),\n },\n {\n pattern: /^\\/atheletebridge\\/teams\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_TEAM',\n idGroup: 1,\n },\n { pattern: /^\\/atheletebridge\\/teams$/, entityType: 'ATHLETEBRIDGE_TEAMS', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/fixtures\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_FIXTURE',\n idGroup: 1,\n },\n { pattern: /^\\/atheletebridge\\/fixtures$/, entityType: 'ATHLETEBRIDGE_FIXTURES', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/programs\\/([^/]+)\\/edit$/,\n entityType: 'ATHLETEBRIDGE_PROGRAM',\n idGroup: 1,\n metadata: () => ({ mode: 'edit' }),\n },\n {\n pattern: /^\\/atheletebridge\\/programs\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_PROGRAM',\n idGroup: 1,\n },\n { pattern: /^\\/atheletebridge\\/programs$/, entityType: 'ATHLETEBRIDGE_PROGRAMS', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/sessions\\/([^/]+)$/,\n entityType: 'ATHLETEBRIDGE_SESSION',\n idGroup: 1,\n },\n { pattern: /^\\/atheletebridge\\/sessions$/, entityType: 'ATHLETEBRIDGE_SESSIONS', idGroup: 0 },\n // Index-only surfaces. AthleteBridgeRoutes.tsx registers no detail route for\n // these, so an id-capturing pattern here could never match anything real.\n { pattern: /^\\/atheletebridge\\/standings$/, entityType: 'ATHLETEBRIDGE_STANDINGS', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/performance$/,\n entityType: 'ATHLETEBRIDGE_PERFORMANCE',\n idGroup: 0,\n },\n { pattern: /^\\/atheletebridge\\/analytics$/, entityType: 'ATHLETEBRIDGE_ANALYTICS', idGroup: 0 },\n {\n pattern: /^\\/atheletebridge\\/tournaments$/,\n entityType: 'ATHLETEBRIDGE_TOURNAMENTS',\n idGroup: 0,\n },\n { pattern: /^\\/atheletebridge\\/onboarding$/, entityType: 'ATHLETEBRIDGE_ONBOARDING', idGroup: 0 },\n];\n\nexport function gatherPageContext(): PageContext {\n const pathSegments = window.location.pathname.split('/').filter(Boolean);\n const currentPage = pathSegments.slice(0, 3).join('/') || 'home';\n const entity = resolveAthleteBridgeConversationContext(\n window.location.pathname,\n window.location.search\n );\n\n return {\n currentUrl: window.location.href,\n currentPage,\n entityType: entity.entityType,\n entityId: entity.entityId,\n activeTab: entity.activeTab,\n };\n}\n\nexport function resolveAthleteBridgeConversationContext(\n pathname: string,\n search: string\n): ConversationContextShape {\n const params = new URLSearchParams(search);\n\n for (const descriptor of ROUTE_DESCRIPTORS) {\n const match = pathname.match(descriptor.pattern);\n if (!match) continue;\n\n const entityId = descriptor.idGroup > 0 ? match[descriptor.idGroup] : undefined;\n // `/teams/new` shape-matches `/teams/:id` — a router literal is not an id.\n if (entityId !== undefined && RESERVED_ID_SEGMENTS.has(entityId)) continue;\n\n return {\n entityType: descriptor.entityType,\n ...(entityId ? { entityId } : {}),\n metadata: {\n routePattern: descriptor.pattern.source,\n ...(descriptor.metadata ? descriptor.metadata(match) : {}),\n },\n };\n }\n\n const activeTab =\n params.get('tab') ??\n (() => {\n const segments = pathname.split('/').filter(Boolean);\n return segments.length > 2 ? segments[segments.length - 1] : undefined;\n })();\n\n return {\n activeTab: activeTab ?? undefined,\n metadata: {\n ...(activeTab ? { activeTab } : {}),\n },\n };\n}\n"],"mappings":";AAwCA,IAAM,IAAuB,IAAI,IAAI,CAAC,OAAO,MAAM,CAAC,GAmB9C,IAAuC;CAG3C;EACE,SAAS;EACT,YAAY;EACZ,SAAS;EACT,WAAW,OAAW,EAAE,QAAQ,EAAM,GAAG;CAC3C;CACA;EACE,SAAS;EACT,YAAY;EACZ,SAAS;EACT,iBAAiB,EAAE,MAAM,OAAO;CAClC;CACA;EACE,SAAS;EACT,YAAY;EACZ,SAAS;CACX;CACA;EAAE,SAAS;EAA6B,YAAY;EAAuB,SAAS;CAAE;CACtF;EACE,SAAS;EACT,YAAY;EACZ,SAAS;CACX;CACA;EAAE,SAAS;EAAgC,YAAY;EAA0B,SAAS;CAAE;CAC5F;EACE,SAAS;EACT,YAAY;EACZ,SAAS;EACT,iBAAiB,EAAE,MAAM,OAAO;CAClC;CACA;EACE,SAAS;EACT,YAAY;EACZ,SAAS;CACX;CACA;EAAE,SAAS;EAAgC,YAAY;EAA0B,SAAS;CAAE;CAC5F;EACE,SAAS;EACT,YAAY;EACZ,SAAS;CACX;CACA;EAAE,SAAS;EAAgC,YAAY;EAA0B,SAAS;CAAE;CAG5F;EAAE,SAAS;EAAiC,YAAY;EAA2B,SAAS;CAAE;CAC9F;EACE,SAAS;EACT,YAAY;EACZ,SAAS;CACX;CACA;EAAE,SAAS;EAAiC,YAAY;EAA2B,SAAS;CAAE;CAC9F;EACE,SAAS;EACT,YAAY;EACZ,SAAS;CACX;CACA;EAAE,SAAS;EAAkC,YAAY;EAA4B,SAAS;CAAE;AAClG;AAEA,SAAgB,IAAiC;CAE/C,IAAM,IADe,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,OAAO,OAC5C,EAAa,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,QACpD,IAAS,EACb,OAAO,SAAS,UAChB,OAAO,SAAS,MAClB;CAEA,OAAO;EACL,YAAY,OAAO,SAAS;EAC5B;EACA,YAAY,EAAO;EACnB,UAAU,EAAO;EACjB,WAAW,EAAO;CACpB;AACF;AAEA,SAAgB,EACd,GACA,GAC0B;CAC1B,IAAM,IAAS,IAAI,gBAAgB,CAAM;CAEzC,KAAK,IAAM,KAAc,GAAmB;EAC1C,IAAM,IAAQ,EAAS,MAAM,EAAW,OAAO;EAC/C,IAAI,CAAC,GAAO;EAEZ,IAAM,IAAW,EAAW,UAAU,IAAI,EAAM,EAAW,WAAW,KAAA;EAElE,YAAa,KAAA,KAAa,EAAqB,IAAI,CAAQ,IAE/D,OAAO;GACL,YAAY,EAAW;GACvB,GAAI,IAAW,EAAE,YAAS,IAAI,CAAC;GAC/B,UAAU;IACR,cAAc,EAAW,QAAQ;IACjC,GAAI,EAAW,WAAW,EAAW,SAAS,CAAK,IAAI,CAAC;GAC1D;EACF;CACF;CAEA,IAAM,IACJ,EAAO,IAAI,KAAK,YACT;EACL,IAAM,IAAW,EAAS,MAAM,GAAG,EAAE,OAAO,OAAO;EACnD,OAAO,EAAS,SAAS,IAAI,EAAS,EAAS,SAAS,KAAK,KAAA;CAC/D,GAAG;CAEL,OAAO;EACL,WAAW,KAAa,KAAA;EACxB,UAAU,EACR,GAAI,IAAY,EAAE,aAAU,IAAI,CAAC,EACnC;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeAgo.js","names":[],"sources":["../../../src/atheletebridge/utils/timeAgo.ts"],"sourcesContent":["/**\n * Relative-time formatter\n * @module atheletebridge/utils/timeAgo\n *\n * Compact \"2h ago\" / \"3d ago\" strings for the activity feed and record\n * timestamps. Falls back to an absolute short date beyond ~4 weeks so old items\n * stay legible.\n */\n\nconst MINUTE = 60;\nconst HOUR = MINUTE * 60;\nconst DAY = HOUR * 24;\nconst WEEK = DAY * 7;\n\n/**\n * Format an ISO timestamp (or Date) as a short relative string from `now`.\n *\n * @example\n * timeAgo('2026-07-06T10:00:00Z') // => \"2h ago\" (2h earlier)\n */\nexport function timeAgo(input: string | Date | null | undefined, now: Date = new Date()): string {\n if (!input) {\n return '';\n }\n const then = typeof input === 'string' ? new Date(input) : input;\n if (Number.isNaN(then.getTime())) {\n return '';\n }\n const diffSec = Math.round((now.getTime() - then.getTime()) / 1000);\n\n if (diffSec < 0) {\n // Future timestamp — mirror the past phrasing (\"in 2h\").\n return `in ${relativeUnit(-diffSec)}`;\n }\n if (diffSec < 45) {\n return 'just now';\n }\n if (diffSec >= WEEK * 4) {\n return new Intl.DateTimeFormat('en-IN', {\n day: 'numeric',\n month: 'short',\n year: then.getFullYear() === now.getFullYear() ? undefined : 'numeric',\n }).format(then);\n }\n return `${relativeUnit(diffSec)} ago`;\n}\n\nfunction relativeUnit(seconds: number): string {\n if (seconds < MINUTE) {\n return `${Math.max(1, Math.round(seconds))}s`;\n }\n if (seconds < HOUR) {\n return `${Math.round(seconds / MINUTE)}m`;\n }\n if (seconds < DAY) {\n return `${Math.round(seconds / HOUR)}h`;\n }\n if (seconds < WEEK) {\n return `${Math.round(seconds / DAY)}d`;\n }\n return `${Math.round(seconds / WEEK)}w`;\n}\n"],"mappings":";AASA,IAAM,IAAS,IACT,IAAO,IAAS,IAChB,IAAM,IAAO,IACb,IAAO,IAAM;AAQnB,SAAgB,EAAQ,GAAyC,oBAAY,IAAI,
|
|
1
|
+
{"version":3,"file":"timeAgo.js","names":[],"sources":["../../../src/atheletebridge/utils/timeAgo.ts"],"sourcesContent":["/**\n * Relative-time formatter\n * @module atheletebridge/utils/timeAgo\n *\n * Compact \"2h ago\" / \"3d ago\" strings for the activity feed and record\n * timestamps. Falls back to an absolute short date beyond ~4 weeks so old items\n * stay legible.\n */\n\nconst MINUTE = 60;\nconst HOUR = MINUTE * 60;\nconst DAY = HOUR * 24;\nconst WEEK = DAY * 7;\n\n/**\n * Format an ISO timestamp (or Date) as a short relative string from `now`.\n *\n * @example\n * timeAgo('2026-07-06T10:00:00Z') // => \"2h ago\" (2h earlier)\n */\nexport function timeAgo(input: string | Date | null | undefined, now: Date = new Date()): string {\n if (!input) {\n return '';\n }\n const then = typeof input === 'string' ? new Date(input) : input;\n if (Number.isNaN(then.getTime())) {\n return '';\n }\n const diffSec = Math.round((now.getTime() - then.getTime()) / 1000);\n\n if (diffSec < 0) {\n // Future timestamp — mirror the past phrasing (\"in 2h\").\n return `in ${relativeUnit(-diffSec)}`;\n }\n if (diffSec < 45) {\n return 'just now';\n }\n if (diffSec >= WEEK * 4) {\n return new Intl.DateTimeFormat('en-IN', {\n day: 'numeric',\n month: 'short',\n year: then.getFullYear() === now.getFullYear() ? undefined : 'numeric',\n }).format(then);\n }\n return `${relativeUnit(diffSec)} ago`;\n}\n\nfunction relativeUnit(seconds: number): string {\n if (seconds < MINUTE) {\n return `${Math.max(1, Math.round(seconds))}s`;\n }\n if (seconds < HOUR) {\n return `${Math.round(seconds / MINUTE)}m`;\n }\n if (seconds < DAY) {\n return `${Math.round(seconds / HOUR)}h`;\n }\n if (seconds < WEEK) {\n return `${Math.round(seconds / DAY)}d`;\n }\n return `${Math.round(seconds / WEEK)}w`;\n}\n"],"mappings":";AASA,IAAM,IAAS,IACT,IAAO,IAAS,IAChB,IAAM,IAAO,IACb,IAAO,IAAM;AAQnB,SAAgB,EAAQ,GAAyC,oBAAY,IAAI,KAAK,GAAW;CAC/F,IAAI,CAAC,GACH,OAAO;CAET,IAAM,IAAO,OAAO,KAAU,WAAW,IAAI,KAAK,CAAK,IAAI;CAC3D,IAAI,OAAO,MAAM,EAAK,QAAQ,CAAC,GAC7B,OAAO;CAET,IAAM,IAAU,KAAK,OAAO,EAAI,QAAQ,IAAI,EAAK,QAAQ,KAAK,GAAI;CAgBlE,OAdI,IAAU,IAEL,MAAM,EAAa,CAAC,CAAO,MAEhC,IAAU,KACL,aAEL,KAAW,IAAO,IACb,IAAI,KAAK,eAAe,SAAS;EACtC,KAAK;EACL,OAAO;EACP,MAAM,EAAK,YAAY,MAAM,EAAI,YAAY,IAAI,KAAA,IAAY;CAC/D,CAAC,EAAE,OAAO,CAAI,IAET,GAAG,EAAa,CAAO,EAAE;AAClC;AAEA,SAAS,EAAa,GAAyB;CAa7C,OAZI,IAAU,IACL,GAAG,KAAK,IAAI,GAAG,KAAK,MAAM,CAAO,CAAC,EAAE,KAEzC,IAAU,IACL,GAAG,KAAK,MAAM,IAAU,CAAM,EAAE,KAErC,IAAU,IACL,GAAG,KAAK,MAAM,IAAU,CAAI,EAAE,KAEnC,IAAU,IACL,GAAG,KAAK,MAAM,IAAU,CAAG,EAAE,KAE/B,GAAG,KAAK,MAAM,IAAU,CAAI,EAAE;AACvC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url.js","names":[],"sources":["../../../src/atheletebridge/utils/url.ts"],"sourcesContent":["/**\n * URL safety helpers\n * @module atheletebridge/utils/url\n *\n * `safeExternalHref` is defense-in-depth against DOM-XSS from user-controlled\n * URLs (e.g. a session `meetingUrl`) that get rendered as clickable anchors.\n * A stored `javascript:` / `data:` / `vbscript:` URL in an `<a href>` executes\n * on click, so we only ever hand back a URL that parses as an absolute URL and\n * uses an `http:` or `https:` scheme. Anything else (bad scheme, relative,\n * unparseable) returns `null` and the caller must decline to render a link.\n */\n\n/**\n * Returns the URL only if it is a safe, absolute http(s) link; otherwise `null`.\n *\n * @example\n * safeExternalHref('https://meet.example.com/x') // => 'https://meet.example.com/x'\n * safeExternalHref('javascript:alert(1)') // => null\n * safeExternalHref('data:text/html,<script>') // => null\n * safeExternalHref('meet.example.com') // => null (not absolute)\n */\nexport function safeExternalHref(url: string | null | undefined): string | null {\n if (!url) return null;\n const trimmed = url.trim();\n if (!trimmed) return null;\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n return null;\n }\n\n if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {\n return parsed.href;\n }\n return null;\n}\n"],"mappings":";AAqBA,SAAgB,EAAiB,GAA+C;
|
|
1
|
+
{"version":3,"file":"url.js","names":[],"sources":["../../../src/atheletebridge/utils/url.ts"],"sourcesContent":["/**\n * URL safety helpers\n * @module atheletebridge/utils/url\n *\n * `safeExternalHref` is defense-in-depth against DOM-XSS from user-controlled\n * URLs (e.g. a session `meetingUrl`) that get rendered as clickable anchors.\n * A stored `javascript:` / `data:` / `vbscript:` URL in an `<a href>` executes\n * on click, so we only ever hand back a URL that parses as an absolute URL and\n * uses an `http:` or `https:` scheme. Anything else (bad scheme, relative,\n * unparseable) returns `null` and the caller must decline to render a link.\n */\n\n/**\n * Returns the URL only if it is a safe, absolute http(s) link; otherwise `null`.\n *\n * @example\n * safeExternalHref('https://meet.example.com/x') // => 'https://meet.example.com/x'\n * safeExternalHref('javascript:alert(1)') // => null\n * safeExternalHref('data:text/html,<script>') // => null\n * safeExternalHref('meet.example.com') // => null (not absolute)\n */\nexport function safeExternalHref(url: string | null | undefined): string | null {\n if (!url) return null;\n const trimmed = url.trim();\n if (!trimmed) return null;\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n return null;\n }\n\n if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {\n return parsed.href;\n }\n return null;\n}\n"],"mappings":";AAqBA,SAAgB,EAAiB,GAA+C;CAC9E,IAAI,CAAC,GAAK,OAAO;CACjB,IAAM,IAAU,EAAI,KAAK;CACzB,IAAI,CAAC,GAAS,OAAO;CAErB,IAAI;CACJ,IAAI;EACF,IAAS,IAAI,IAAI,CAAO;CAC1B,QAAQ;EACN,OAAO;CACT;CAKA,OAHI,EAAO,aAAa,WAAW,EAAO,aAAa,WAC9C,EAAO,OAET;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clsx.js","names":[],"sources":["../../../../node_modules/clsx/dist/clsx.mjs"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;"],"x_google_ignoreList":[0],"mappings":";AAAA,SAAS,EAAE,GAAE;CAAC,IAAI,GAAE,GAAE,IAAE;
|
|
1
|
+
{"version":3,"file":"clsx.js","names":[],"sources":["../../../../node_modules/clsx/dist/clsx.mjs"],"sourcesContent":["function r(e){var t,f,n=\"\";if(\"string\"==typeof e||\"number\"==typeof e)n+=e;else if(\"object\"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=\" \"),n+=f)}else for(f in e)e[f]&&(n&&(n+=\" \"),n+=f);return n}export function clsx(){for(var e,t,f=0,n=\"\",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=\" \"),n+=t);return n}export default clsx;"],"x_google_ignoreList":[0],"mappings":";AAAA,SAAS,EAAE,GAAE;CAAC,IAAI,GAAE,GAAE,IAAE;CAAG,IAAa,OAAO,KAAjB,YAA8B,OAAO,KAAjB,UAAmB,KAAG;MAAO,IAAa,OAAO,KAAjB,UAAmB,IAAG,MAAM,QAAQ,CAAC,GAAE;EAAC,IAAI,IAAE,EAAE;EAAO,KAAI,IAAE,GAAE,IAAE,GAAE,KAAI,EAAE,OAAK,IAAE,EAAE,EAAE,EAAE,OAAK,MAAI,KAAG,MAAK,KAAG;CAAE,OAAM,KAAI,KAAK,GAAE,EAAE,OAAK,MAAI,KAAG,MAAK,KAAG;CAAG,OAAO;AAAC;AAAC,SAAgB,IAAM;CAAC,KAAI,IAAI,GAAE,GAAE,IAAE,GAAE,IAAE,IAAG,IAAE,UAAU,QAAO,IAAE,GAAE,KAAI,CAAC,IAAE,UAAU,QAAM,IAAE,EAAE,CAAC,OAAK,MAAI,KAAG,MAAK,KAAG;CAAG,OAAO;AAAC"}
|
|
@@ -234,7 +234,7 @@ var e = (e, t) => {
|
|
|
234
234
|
}, Y = (e, t, n = !1) => {
|
|
235
235
|
let r = j.exec(e);
|
|
236
236
|
return r ? r[1] ? t(r[1]) : n : !1;
|
|
237
|
-
}, X = (e) => e === "position" || e === "percentage", Z = (e) => e === "image" || e === "url", Q = (e) => e === "length" || e === "size" || e === "bg-size", $ = (e) => e === "length", Ce = (e) => e === "number", we = (e) => e === "family-name", Te = (e) => e === "number" || e === "weight", Ee = (e) => e === "shadow", De =
|
|
237
|
+
}, X = (e) => e === "position" || e === "percentage", Z = (e) => e === "image" || e === "url", Q = (e) => e === "length" || e === "size" || e === "bg-size", $ = (e) => e === "length", Ce = (e) => e === "number", we = (e) => e === "family-name", Te = (e) => e === "number" || e === "weight", Ee = (e) => e === "shadow", De = /*#__PURE__*/ D(() => {
|
|
238
238
|
let e = k("color"), t = k("font"), n = k("text"), r = k("font-weight"), i = k("tracking"), a = k("leading"), o = k("breakpoint"), s = k("container"), c = k("spacing"), l = k("radius"), u = k("shadow"), d = k("inset-shadow"), ee = k("text-shadow"), f = k("drop-shadow"), p = k("blur"), m = k("perspective"), h = k("aspect"), g = k("ease"), _ = k("animate"), v = () => [
|
|
239
239
|
"auto",
|
|
240
240
|
"avoid",
|