@burdenoff/microfe-atheletebridge 2026.628.1 → 2026.705.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 +45 -37
- package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
- package/dist/atheletebridge/AthleteBridgeRoutes.js +10 -6
- package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
- package/dist/atheletebridge/components/AthleteSelect.js +66 -0
- package/dist/atheletebridge/components/AthleteSelect.js.map +1 -0
- package/dist/atheletebridge/components/DrillVideoLink.js +28 -0
- package/dist/atheletebridge/components/DrillVideoLink.js.map +1 -0
- package/dist/atheletebridge/components/FixtureCard.js.map +1 -1
- package/dist/atheletebridge/components/LoadingState.js.map +1 -1
- package/dist/atheletebridge/components/MetricsCard.js +20 -46
- package/dist/atheletebridge/components/MetricsCard.js.map +1 -1
- package/dist/atheletebridge/components/UserSearchSelect.js +129 -0
- package/dist/atheletebridge/components/UserSearchSelect.js.map +1 -0
- package/dist/atheletebridge/components/domain.js +10 -1
- package/dist/atheletebridge/components/domain.js.map +1 -1
- package/dist/atheletebridge/context/AthleteBridgeContext.js.map +1 -1
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +313 -180
- package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
- package/dist/atheletebridge/pages/DashboardPage.js +77 -69
- package/dist/atheletebridge/pages/DashboardPage.js.map +1 -1
- package/dist/atheletebridge/pages/StandingsPage.js.map +1 -1
- package/dist/atheletebridge/pages/performance/PerformancePage.js +496 -0
- package/dist/atheletebridge/pages/performance/PerformancePage.js.map +1 -0
- package/dist/atheletebridge/pages/programs/ProgramDetailPage.js +175 -141
- package/dist/atheletebridge/pages/programs/ProgramDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/programs/ProgramFormPage.js.map +1 -1
- package/dist/atheletebridge/pages/sessions/SessionFormPage.js +91 -98
- package/dist/atheletebridge/pages/sessions/SessionFormPage.js.map +1 -1
- package/dist/atheletebridge/pages/teams/TeamDetailPage.js +132 -137
- package/dist/atheletebridge/pages/teams/TeamDetailPage.js.map +1 -1
- package/dist/atheletebridge/pages/teams/TeamFormPage.js.map +1 -1
- package/dist/atheletebridge/pages/teams/TeamsListPage.js.map +1 -1
- package/dist/atheletebridge/utils/formatters.js +2 -25
- package/dist/atheletebridge/utils/formatters.js.map +1 -1
- package/dist/index.js +4 -4
- 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, Loader2, Save } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { SPORT_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport {\n useTeam,\n useCreateTeam,\n useUpdateTeam,\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'];\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 tagsText: string;\n}\n\nconst EMPTY_FORM: TeamFormState = {\n name: '',\n sport: 'OTHER',\n status: 'FORMING',\n description: '',\n ageGroup: '',\n season: '',\n homeVenue: '',\n tagsText: '',\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 [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const team = existing.data;\n if (isEdit && team) {\n setForm({\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 tagsText: team.tags.join(', '),\n });\n }\n }, [isEdit, existing.data]);\n\n const set = <K extends keyof TeamFormState>(key: K, value: TeamFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n const parseTags = (text: string): string[] =>\n text\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\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 const tags = parseTags(form.tagsText);\n\n try {\n if (isEdit && id) {\n await updateTeam.mutateAsync({\n id,\n input: {\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 tags,\n },\n });\n navigateTo(`/teams/${id}`);\n } else {\n const created = await createTeam.mutateAsync({\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 tags,\n });\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=\"max-w-2xl space-y-5\">\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 <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Sport\" htmlFor=\"sport\">\n <select\n id=\"sport\"\n className={fieldInputClass}\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 </FormField>\n\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 </div>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\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\n <FormField label=\"Season\" htmlFor=\"season\">\n <input\n id=\"season\"\n className={fieldInputClass}\n value={form.season}\n onChange={(e) => set('season', e.target.value)}\n placeholder=\"e.g. 2025/26\"\n />\n </FormField>\n </div>\n\n <FormField label=\"Home venue\" htmlFor=\"homeVenue\">\n <input\n id=\"homeVenue\"\n className={fieldInputClass}\n value={form.homeVenue}\n onChange={(e) => set('homeVenue', e.target.value)}\n placeholder=\"e.g. Riverside Stadium\"\n />\n </FormField>\n\n <FormField label=\"Description\" htmlFor=\"description\">\n <textarea\n id=\"description\"\n className={fieldInputClass}\n rows={3}\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"A short description of the team.\"\n />\n </FormField>\n\n <FormField\n label=\"Tags\"\n htmlFor=\"tags\"\n hint=\"Comma-separated, e.g. youth, development, first-team.\"\n >\n <input\n id=\"tags\"\n className={fieldInputClass}\n value={form.tagsText}\n onChange={(e) => set('tagsText', e.target.value)}\n placeholder=\"youth, development\"\n />\n </FormField>\n\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n\n <div className=\"flex items-center gap-3 pt-2\">\n <button\n type=\"submit\"\n disabled={saving}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60\"\n >\n {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 </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, Loader2, Save } from 'lucide-react';\nimport { PageLayout } from '../../components/PageLayout';\nimport { LoadingState, ErrorState } from '../../components/LoadingState';\nimport { FormField, fieldInputClass } from '../../components/form';\nimport { SPORT_LABELS } from '../../components/domain';\nimport { useAthleteBridge } from '../../context/AthleteBridgeContext';\nimport { useTeam, useCreateTeam, useUpdateTeam } 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'];\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 tagsText: string;\n}\n\nconst EMPTY_FORM: TeamFormState = {\n name: '',\n sport: 'OTHER',\n status: 'FORMING',\n description: '',\n ageGroup: '',\n season: '',\n homeVenue: '',\n tagsText: '',\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 [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n const team = existing.data;\n if (isEdit && team) {\n setForm({\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 tagsText: team.tags.join(', '),\n });\n }\n }, [isEdit, existing.data]);\n\n const set = <K extends keyof TeamFormState>(key: K, value: TeamFormState[K]) =>\n setForm((prev) => ({ ...prev, [key]: value }));\n\n const parseTags = (text: string): string[] =>\n text\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\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 const tags = parseTags(form.tagsText);\n\n try {\n if (isEdit && id) {\n await updateTeam.mutateAsync({\n id,\n input: {\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 tags,\n },\n });\n navigateTo(`/teams/${id}`);\n } else {\n const created = await createTeam.mutateAsync({\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 tags,\n });\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=\"max-w-2xl space-y-5\">\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 <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\n <FormField label=\"Sport\" htmlFor=\"sport\">\n <select\n id=\"sport\"\n className={fieldInputClass}\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 </FormField>\n\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 </div>\n\n <div className=\"grid grid-cols-1 gap-5 sm:grid-cols-2\">\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\n <FormField label=\"Season\" htmlFor=\"season\">\n <input\n id=\"season\"\n className={fieldInputClass}\n value={form.season}\n onChange={(e) => set('season', e.target.value)}\n placeholder=\"e.g. 2025/26\"\n />\n </FormField>\n </div>\n\n <FormField label=\"Home venue\" htmlFor=\"homeVenue\">\n <input\n id=\"homeVenue\"\n className={fieldInputClass}\n value={form.homeVenue}\n onChange={(e) => set('homeVenue', e.target.value)}\n placeholder=\"e.g. Riverside Stadium\"\n />\n </FormField>\n\n <FormField label=\"Description\" htmlFor=\"description\">\n <textarea\n id=\"description\"\n className={fieldInputClass}\n rows={3}\n value={form.description}\n onChange={(e) => set('description', e.target.value)}\n placeholder=\"A short description of the team.\"\n />\n </FormField>\n\n <FormField\n label=\"Tags\"\n htmlFor=\"tags\"\n hint=\"Comma-separated, e.g. youth, development, first-team.\"\n >\n <input\n id=\"tags\"\n className={fieldInputClass}\n value={form.tagsText}\n onChange={(e) => set('tagsText', e.target.value)}\n placeholder=\"youth, development\"\n />\n </FormField>\n\n {error && <p className=\"text-sm text-status-error-text\">{error}</p>}\n\n <div className=\"flex items-center gap-3 pt-2\">\n <button\n type=\"submit\"\n disabled={saving}\n className=\"inline-flex items-center gap-1.5 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:opacity-60\"\n >\n {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 </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 actions={\n <button\n type=\"button\"\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 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
|
|
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 actions={\n <button\n type=\"button\"\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 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 key={team.id} team={team} onClick={() => navigateTo(`/teams/${team.id}`)} />\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,EAAa,CAAgB,KAAK,OAAW;CAC3E;CACA,OAAO,EAAa;CACrB,EAAE,EAEG,IAAsE;CAC1E;EAAE,OAAO;EAAW,OAAO;EAAW;CACtC;EAAE,OAAO;EAAU,OAAO;EAAU;CACpC;EAAE,OAAO;EAAY,OAAO;EAAY;CACxC;EAAE,OAAO;EAAY,OAAO;EAAY;CACzC;AAED,SAAgB,IAAgB;CAC9B,IAAM,EAAE,kBAAe,GAAkB,EACnC,CAAC,GAAO,KAAY,EAAwB,GAAG,EAC/C,CAAC,GAAQ,KAAa,EAA6B,GAAG,EACtD,CAAC,GAAM,KAAW,EAAS,EAAE,EAE7B,IAAQ,EAAS;EACrB,OAAO,KAAS,KAAA;EAChB,QAAQ,KAAU,KAAA;EAClB,YAAY;GAAE,OAAO;GAAW,QAAQ,IAAO;GAAW;EAC3D,CAAC,EAEI,IAAQ,EAAM,MAAM,SAAS,EAAE,EAC/B,IAAU,EAAM,MAAM,SAAS,WAAW;AAEhD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,EAAW,aAAa;GACvC,WAAU;aAHZ,CAKE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAAA,YACrB;;YAVb,CAaE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD;IACE,WAAU;IACV,UAAS;IACT,OAAO;IACP,WAAW,MAAM;AAEf,KADA,EAAS,EAAE,EACX,EAAQ,EAAE;;IAEZ,SAAS;IACT,CAAA,EACF,kBAAC,GAAD;IACE,WAAU;IACV,UAAS;IACT,OAAO;IACP,WAAW,MAAM;AAEf,KADA,EAAU,EAAE,EACZ,EAAQ,EAAE;;IAEZ,SAAS;IACT,CAAA,CACE;MAEL,EAAM,YACL,kBAAC,GAAD,EAAc,OAAM,kBAAmB,CAAA,GACrC,EAAM,UACR,kBAAC,GAAD,EAAY,eAAe,KAAK,EAAM,SAAS,EAAI,CAAA,GACjD,EAAM,WAAW,IACnB,kBAAC,GAAD;GACE,cAAa;GACb,MAAM,kBAAC,GAAD,EAAO,WAAU,aAAc,CAAA;GACrC,OAAM;GACN,aACE,KAAS,IACL,gDACA;GAEN,QACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,aAAa;IACvC,WAAU;cACX;IAEQ,CAAA;GAEX,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,MACV,kBAAC,GAAD;IAA8B;IAAM,eAAe,EAAW,UAAU,EAAK,KAAK;IAAI,EAAvE,EAAK,GAAkE,CACtF;GACE,CAAA,EACN,kBAAC,GAAD;GACE,WAAU;GACJ;GACG;GACT,cAAc,GAAS,MAAM,KAAK,IAAI,GAAG,IAAI,EAAE,CAAC;GAChD,cAAc,GAAS,MAAM,IAAI,EAAE;GACnC,CAAA,CACD,EAAA,CAAA,CAEM"}
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
//#region src/atheletebridge/utils/formatters.ts
|
|
2
2
|
function e(e, t) {
|
|
3
|
-
return new Intl.NumberFormat("en-IN", {
|
|
4
|
-
style: "currency",
|
|
5
|
-
currency: "INR",
|
|
6
|
-
minimumFractionDigits: 2,
|
|
7
|
-
maximumFractionDigits: 2,
|
|
8
|
-
...t
|
|
9
|
-
}).format(e);
|
|
10
|
-
}
|
|
11
|
-
function t(e, t) {
|
|
12
3
|
let n = typeof e == "string" ? new Date(e) : e;
|
|
13
4
|
return new Intl.DateTimeFormat("en-IN", {
|
|
14
5
|
day: "numeric",
|
|
@@ -20,21 +11,7 @@ function t(e, t) {
|
|
|
20
11
|
...t
|
|
21
12
|
}).format(n);
|
|
22
13
|
}
|
|
23
|
-
function
|
|
24
|
-
let t = typeof e == "string" ? new Date(e) : e, n = (/* @__PURE__ */ new Date()).getTime() - t.getTime(), r = Math.floor(n / 1e3), i = Math.floor(r / 60), a = Math.floor(i / 60), o = Math.floor(a / 24), s = Math.floor(o / 7), c = Math.floor(o / 30);
|
|
25
|
-
if (r < 60) return "just now";
|
|
26
|
-
if (i < 60) return `${i} min${i === 1 ? "" : "s"} ago`;
|
|
27
|
-
if (a < 24) return `${a} hour${a === 1 ? "" : "s"} ago`;
|
|
28
|
-
if (o < 7) return `${o} day${o === 1 ? "" : "s"} ago`;
|
|
29
|
-
if (s < 4) return `${s} week${s === 1 ? "" : "s"} ago`;
|
|
30
|
-
if (c < 12) return `${c} month${c === 1 ? "" : "s"} ago`;
|
|
31
|
-
let l = Math.floor(o / 365);
|
|
32
|
-
return `${l} year${l === 1 ? "" : "s"} ago`;
|
|
33
|
-
}
|
|
34
|
-
function r(e, t) {
|
|
35
|
-
return new Intl.NumberFormat("en-IN", t).format(e);
|
|
36
|
-
}
|
|
37
|
-
function i(e) {
|
|
14
|
+
function t(e) {
|
|
38
15
|
if (e < 1) return "instant";
|
|
39
16
|
if (e < 60) return `${e} min`;
|
|
40
17
|
let t = Math.floor(e / 60), n = e % 60;
|
|
@@ -43,6 +20,6 @@ function i(e) {
|
|
|
43
20
|
return i === 0 ? `${r} day${r === 1 ? "" : "s"}` : `${r} day${r === 1 ? "" : "s"} ${i}h`;
|
|
44
21
|
}
|
|
45
22
|
//#endregion
|
|
46
|
-
export { e as
|
|
23
|
+
export { e as formatDate, t as formatDuration };
|
|
47
24
|
|
|
48
25
|
//# sourceMappingURL=formatters.js.map
|
|
@@ -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
|
|
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,EAAK,GAAG;AACtD,QAAO,IAAI,KAAK,eAAe,SAAS;EACtC,KAAK;EACL,OAAO;EACP,MAAM;EACN,MAAM;EACN,QAAQ;EACR,QAAQ;EACR,GAAG;EACJ,CAAC,CAAC,OAAO,EAAE;;AAed,SAAgB,EAAe,GAAyB;AACtD,KAAI,IAAU,EAAG,QAAO;AACxB,KAAI,IAAU,GAAI,QAAO,GAAG,EAAQ;CAEpC,IAAM,IAAQ,KAAK,MAAM,IAAU,GAAG,EAChC,IAAmB,IAAU;AAEnC,KAAI,IAAQ,GAIV,QAHI,MAAqB,IAChB,GAAG,EAAM,KAEX,GAAG,EAAM,IAAI,EAAiB;CAGvC,IAAM,IAAO,KAAK,MAAM,IAAQ,GAAG,EAC7B,IAAiB,IAAQ;AAK/B,QAHI,MAAmB,IACd,GAAG,EAAK,MAAM,MAAS,IAAU,KAAN,QAE7B,GAAG,EAAK,MAAM,MAAS,IAAU,KAAN,IAAS,GAAG,EAAe"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AthleteBridgeProvider as e, useAthleteBridge as t } from "./atheletebridge/context/AthleteBridgeContext.js";
|
|
2
2
|
import { cn as n } from "./atheletebridge/utils/cn.js";
|
|
3
|
-
import {
|
|
4
|
-
import { AthleteBridgeRoot as
|
|
5
|
-
import { useAthleteBridgeStore as
|
|
3
|
+
import { formatDate as r, formatDuration as i } from "./atheletebridge/utils/formatters.js";
|
|
4
|
+
import { AthleteBridgeRoot as a } from "./atheletebridge/AthleteBridgeRoot.js";
|
|
5
|
+
import { useAthleteBridgeStore as o } from "./atheletebridge/store/atheletebridgeStore.js";
|
|
6
6
|
import "./atheletebridge/index.js";
|
|
7
|
-
export { e as AthleteBridgeProvider,
|
|
7
|
+
export { e as AthleteBridgeProvider, a as AthleteBridgeRoot, n as cn, r as formatDate, i as formatDuration, t as useAthleteBridge, o as useAthleteBridgeStore };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-atheletebridge",
|
|
3
|
-
"version": "2026.
|
|
4
|
-
"description": "Burdenoff
|
|
3
|
+
"version": "2026.705.1",
|
|
4
|
+
"description": "Burdenoff AthleteBridge Microfrontend - Sports, coaching & training platform for teams, fixtures, programs, sessions and athlete performance",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
],
|
|
11
11
|
"imports": {
|
|
12
12
|
"#src/*": "./src/*",
|
|
13
|
-
"#
|
|
13
|
+
"#atheletebridge/*": "./src/atheletebridge/*"
|
|
14
14
|
},
|
|
15
15
|
"exports": {
|
|
16
16
|
".": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@apollo/client": "^4.0.11",
|
|
43
|
-
"@burdenoff/fe-libs": "2026.
|
|
43
|
+
"@burdenoff/fe-libs": "2026.705.2",
|
|
44
44
|
"@tanstack/react-query": "^5.90.16",
|
|
45
45
|
"clsx": "^2.1.1",
|
|
46
46
|
"graphql": "^16.12.0",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"access": "restricted"
|
|
87
87
|
},
|
|
88
88
|
"overrides": {
|
|
89
|
-
"@burdenoff/fe-libs": "2026.
|
|
89
|
+
"@burdenoff/fe-libs": "2026.705.2",
|
|
90
90
|
"lodash": ">=4.17.21",
|
|
91
91
|
"lodash-es": ">=4.17.21",
|
|
92
92
|
"dompurify": ">=3.3.4",
|