Implement the Organization management page under /organization, covering both Sports and Teams.
Priority: P1
API endpoints used
Sports
| Method |
Endpoint |
Description |
| GET |
/organization/sports |
List all sports (Sport[]) |
| POST |
/organization/sports |
Create a sport (SportCreate) |
| GET |
/organization/sports/{sport_name} |
Get sport details |
| PATCH |
/organization/sports/{sport_name} |
Update sport (SportPartialUpdate) |
| DELETE |
/organization/sports/{sport_name} |
Delete a sport |
Teams
| Method |
Endpoint |
Description |
| GET |
/organization/teams |
List all teams (Team[]) |
| POST |
/organization/teams |
Create a team (TeamCreate) |
| GET |
/organization/teams/{team_id} |
Get team details |
| PATCH |
/organization/teams/{team_id} |
Update team (TeamPartialUpdate) |
| DELETE |
/organization/teams/{team_id} |
Delete a team |
Tasks
- Add
src/features/organization/api/queries.ts with useListSports, useGetSport, useListTeams, and useGetTeam hooks using TanStack Query; expose query options for route loaders
- Add
src/features/organization/api/mutations.ts with create/update/delete hooks for both sports and teams; invalidate respective list query on success
- Add
src/features/organization/api/query-keys.ts for structured query keys
- Wire a React Router v7 loader on the
/organization route that prefetches both sports and teams
- Add Zod schemas for
SportCreate, SportPartialUpdate, TeamCreate, and TeamPartialUpdate derived from the generated types in src/api.ts
- Add Zustand slice for UI state only: active tab (Sports / Teams), selected item ID, dialog open/closed
- Build a two-tab layout (shadcn/ui Tabs): Sports tab and Teams tab
- Sports: Table with
name, description, directors; create/edit/delete via Dialog
- Teams: Table with
name, sport, address; create/edit/delete via Dialog; sport field populated from the sports list
Acceptance criteria
- Both sports and teams lists load before the page renders (via loader prefetch)
- Full CRUD works for both sports and teams
- The
sport field in the team creation form is a dropdown populated from GET /organization/sports
- Form validates required fields (
name for sports; name + sport for teams) before submitting and shows inline errors
- Conflict responses (e.g. duplicates) are shown as actionable user-facing errors
Implement the Organization management page under
/organization, covering both Sports and Teams.Priority: P1
API endpoints used
Sports
Sport[])SportCreate)SportPartialUpdate)Teams
Team[])TeamCreate)TeamPartialUpdate)Tasks
src/features/organization/api/queries.tswithuseListSports,useGetSport,useListTeams, anduseGetTeamhooks using TanStack Query; expose query options for route loaderssrc/features/organization/api/mutations.tswith create/update/delete hooks for both sports and teams; invalidate respective list query on successsrc/features/organization/api/query-keys.tsfor structured query keys/organizationroute that prefetches both sports and teamsSportCreate,SportPartialUpdate,TeamCreate, andTeamPartialUpdatederived from the generated types insrc/api.tsname,description,directors; create/edit/delete via Dialogname,sport,address; create/edit/delete via Dialog;sportfield populated from the sports listAcceptance criteria
sportfield in the team creation form is a dropdown populated fromGET /organization/sportsnamefor sports;name+sportfor teams) before submitting and shows inline errors