diff --git a/backend/src/infrastructure/database/migrations/0005_add_league_sport.ts b/backend/src/infrastructure/database/migrations/0005_add_league_sport.ts new file mode 100644 index 0000000..62ef36d --- /dev/null +++ b/backend/src/infrastructure/database/migrations/0005_add_league_sport.ts @@ -0,0 +1,77 @@ +import { Kysely, sql } from 'kysely'; + +const TABLE = 'league'; +const CHECK_NAME = 'ck_league_sport'; + +export async function up(db: Kysely): Promise { + const engine = process.env.DB_ENGINE ?? 'sqlite'; + + if (engine === 'sqlite') { + // 1) Create new table with sport + CHECK constraint + await sql` + CREATE TABLE league_new ( + league_id TEXT PRIMARY KEY, + name TEXT NOT NULL, + sport TEXT NOT NULL DEFAULT 'NFL' CHECK (sport IN ('NFL','GOLF')), + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + ) + `.execute(db); + + // 2) Copy existing data (sport will take DEFAULT 'NFL') + await sql` + INSERT INTO league_new (league_id, name, created_at) + SELECT league_id, name, created_at + FROM ${sql.table(TABLE)} + `.execute(db); + + // 3) Swap tables + await sql`DROP TABLE ${sql.table(TABLE)}`.execute(db); + await sql`ALTER TABLE league_new RENAME TO ${sql.table(TABLE)}`.execute(db); + } else if (engine === 'postgres') { + await db.schema + .alterTable(TABLE) + .addColumn('sport', 'text', (col) => col.notNull().defaultTo('NFL')) + .execute(); + + await sql` + ALTER TABLE ${sql.table(TABLE)} + ADD CONSTRAINT ${sql.raw(CHECK_NAME)} + CHECK (sport IN ('NFL','GOLF')) + `.execute(db); + } else { + throw new Error(`Unsupported DB_ENGINE: ${engine}`); + } +} + +export async function down(db: Kysely): Promise { + const engine = process.env.DB_ENGINE ?? 'sqlite'; + + if (engine === 'sqlite') { + // Recreate original schema without sport + await sql` + CREATE TABLE league_new ( + league_id TEXT PRIMARY KEY, + name TEXT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + ) + `.execute(db); + + await sql` + INSERT INTO league_new (league_id, name, created_at) + SELECT league_id, name, created_at + FROM ${sql.table(TABLE)} + `.execute(db); + + await sql`DROP TABLE ${sql.table(TABLE)}`.execute(db); + await sql`ALTER TABLE league_new RENAME TO ${sql.table(TABLE)}`.execute(db); + } else if (engine === 'postgres') { + await sql` + ALTER TABLE ${sql.table(TABLE)} + DROP CONSTRAINT IF EXISTS ${sql.raw(CHECK_NAME)} + `.execute(db); + + await db.schema.alterTable(TABLE).dropColumn('sport').execute(); + } else { + throw new Error(`Unsupported DB_ENGINE: ${engine}`); + } +} diff --git a/backend/src/leagues/entities/league.entity.ts b/backend/src/leagues/entities/league.entity.ts index 8711b1a..43af77e 100644 --- a/backend/src/leagues/entities/league.entity.ts +++ b/backend/src/leagues/entities/league.entity.ts @@ -4,6 +4,7 @@ import { Selectable } from 'kysely'; export interface ILeague { leagueId: string & tags.Format<'uuid'>; name: string; + sport: string; } export type League = Selectable; diff --git a/backend/src/leagues/leagues.repository.ts b/backend/src/leagues/leagues.repository.ts index 9aaac74..e3a3db7 100644 --- a/backend/src/leagues/leagues.repository.ts +++ b/backend/src/leagues/leagues.repository.ts @@ -49,6 +49,7 @@ export class DatabaseLeaguesRepository extends LeaguesRepository { .values({ leagueId: crypto.randomUUID(), name: league.name, + sport: league.sport, }) .returningAll() .executeTakeFirstOrThrow(); diff --git a/frontend/src/components/dashboard.js b/frontend/src/components/dashboard.js index 210e190..73b2cd1 100644 --- a/frontend/src/components/dashboard.js +++ b/frontend/src/components/dashboard.js @@ -11,6 +11,7 @@ const Dashboard = () => { const [user, setUser] = useState(null); const [leagues, setLeagues] = useState([]); const [newLeague, setNewLeague] = useState(""); + const [leagueSport, setLeagueSport] = useState("NFL"); const [joinCode, setJoinCode] = useState(""); const [showCreateForm, setShowCreateForm] = useState(false); const [showJoinForm, setShowJoinForm] = useState(false); @@ -90,6 +91,7 @@ const Dashboard = () => { // Wire create league to backend leagues endpoints. const addLeague = async () => { const name = newLeague.trim(); + const sport = leagueSport; if (!name) return; console.log(user); const userId = user && (user.id || user.userId); @@ -106,7 +108,7 @@ const Dashboard = () => { method: "POST", headers: {"Content-Type": "application/json"}, credentials: "include", - body: JSON.stringify({name}), + body: JSON.stringify({name: name, sport: sport}), }); if (!createRes.ok) { @@ -269,6 +271,7 @@ const Dashboard = () => {

{league.name || league.leagueName || "Unnamed League"}

+

{league.sport}

{role === "admin" ? "Admin" : role}

- {showCreateForm && ( -
- setNewLeague(e.target.value)} - /> - -
- )} + {showCreateForm && ( +
+ setNewLeague(e.target.value)} + /> + + + + +
+ )} {showJoinForm && (