diff --git a/app/models/season-sport.ts b/app/models/season-sport.ts index 77dd1bf..d73b9e2 100644 --- a/app/models/season-sport.ts +++ b/app/models/season-sport.ts @@ -1,6 +1,8 @@ import { eq, and } from "drizzle-orm"; import { database } from "~/database/context"; import * as schema from "~/database/schema"; +import { findDraftableSportsSeasonBySportId } from "~/models/sports-season"; +import { logger } from "~/lib/logger"; export type SeasonSport = typeof schema.seasonSports.$inferSelect; export type NewSeasonSport = typeof schema.seasonSports.$inferInsert; @@ -89,7 +91,6 @@ export async function applySportsFromTemplate( ): Promise { const db = database(); - // Get all sports from the template const templateSports = await db.query.seasonTemplateSports.findMany({ where: eq(schema.seasonTemplateSports.templateId, templateId), }); @@ -98,12 +99,26 @@ export async function applySportsFromTemplate( return []; } - // Link them to the season + const resolved = await Promise.all( + templateSports.map(async (ts) => { + const season = await findDraftableSportsSeasonBySportId(ts.sportId); + if (!season) { + logger.warn(`No draftable season found for sport ${ts.sportId} in template ${templateId}`); + } + return season ?? null; + }) + ); + + const sportsSeasonIds = resolved + .filter((s): s is NonNullable => s !== null) + .map((s) => s.id); + + if (sportsSeasonIds.length === 0) { + return []; + } + return await linkMultipleSportsToSeason( - templateSports.map((ts) => ({ - seasonId, - sportsSeasonId: ts.sportsSeasonId, - })) + sportsSeasonIds.map((sportsSeasonId) => ({ seasonId, sportsSeasonId })) ); } diff --git a/app/models/season-template-sport.ts b/app/models/season-template-sport.ts index 2739191..8ac91ef 100644 --- a/app/models/season-template-sport.ts +++ b/app/models/season-template-sport.ts @@ -7,14 +7,14 @@ export type NewSeasonTemplateSport = typeof schema.seasonTemplateSports.$inferIn export async function addSportToTemplate( templateId: string, - sportsSeasonId: string + sportId: string ): Promise { const db = database(); const [link] = await db .insert(schema.seasonTemplateSports) .values({ templateId, - sportsSeasonId, + sportId, }) .returning(); return link; @@ -32,7 +32,7 @@ export async function addMultipleSportsToTemplate( export async function removeSportFromTemplate( templateId: string, - sportsSeasonId: string + sportId: string ): Promise { const db = database(); await db @@ -40,7 +40,7 @@ export async function removeSportFromTemplate( .where( and( eq(schema.seasonTemplateSports.templateId, templateId), - eq(schema.seasonTemplateSports.sportsSeasonId, sportsSeasonId) + eq(schema.seasonTemplateSports.sportId, sportId) ) ); } @@ -52,28 +52,23 @@ export async function findSeasonTemplateSportsByTemplateId( return await db.query.seasonTemplateSports.findMany({ where: eq(schema.seasonTemplateSports.templateId, templateId), with: { - sportsSeason: { - with: { - sport: true, - }, - }, + sport: true, }, }); } -export async function findSeasonTemplateSportsBySportsSeasonId( - sportsSeasonId: string +export async function findSeasonTemplateSportsBySportId( + sportId: string ): Promise { const db = database(); return await db.query.seasonTemplateSports.findMany({ - where: eq(schema.seasonTemplateSports.sportsSeasonId, sportsSeasonId), + where: eq(schema.seasonTemplateSports.sportId, sportId), with: { template: true, }, }); } - export async function deleteSeasonTemplateSport(id: string): Promise { const db = database(); await db.delete(schema.seasonTemplateSports).where(eq(schema.seasonTemplateSports.id, id)); diff --git a/app/models/season-template.ts b/app/models/season-template.ts index dd7cf1d..be3118e 100644 --- a/app/models/season-template.ts +++ b/app/models/season-template.ts @@ -29,18 +29,14 @@ export async function findSeasonTemplateById(id: string): Promise { const db = database(); return await db.query.seasonTemplates.findMany({ where: eq(schema.seasonTemplates.isActive, true), - orderBy: (templates, { desc }) => [desc(templates.year)], - }); -} - -export async function findSeasonTemplatesByYear(year: number): Promise { - const db = database(); - return await db.query.seasonTemplates.findMany({ - where: eq(schema.seasonTemplates.year, year), orderBy: (templates, { asc }) => [asc(templates.name)], }); } @@ -66,7 +54,7 @@ export async function findSeasonTemplatesByYear(year: number): Promise { const db = database(); return await db.query.seasonTemplates.findMany({ - orderBy: (templates, { desc }) => [desc(templates.year)], + orderBy: (templates, { asc }) => [asc(templates.name)], }); } diff --git a/app/models/sports-season.ts b/app/models/sports-season.ts index eb53760..72acfe7 100644 --- a/app/models/sports-season.ts +++ b/app/models/sports-season.ts @@ -151,6 +151,24 @@ export async function findDraftableSportsSeasons() { })); } +export async function findDraftableSportsSeasonBySportId(sportId: string) { + const db = database(); + const today = sql`CURRENT_DATE`; + return await db.query.sportsSeasons.findFirst({ + where: (ss, ops) => + ops.and( + ops.eq(ss.sportId, sportId), + lte(ss.draftOn, today), + gte(ss.draftOff, today), + isNull(ss.fantasySeasonId) + ), + orderBy: (ss, { desc }) => [desc(ss.year), desc(ss.draftOn)], + with: { + sport: true, + }, + }); +} + export async function updateSportsSeason( id: string, data: Partial diff --git a/app/routes/admin.templates.$id.tsx b/app/routes/admin.templates.$id.tsx index 1c091ad..bfca6c5 100644 --- a/app/routes/admin.templates.$id.tsx +++ b/app/routes/admin.templates.$id.tsx @@ -4,7 +4,7 @@ import type { Route } from "./+types/admin.templates.$id"; import { logger } from "~/lib/logger"; import { - findSeasonTemplateWithSportsSeasons, + findSeasonTemplateWithSports, updateSeasonTemplate, deleteSeasonTemplate, setSeasonTemplateActive @@ -13,7 +13,7 @@ import { addSportToTemplate, removeSportFromTemplate } from "~/models/season-template-sport"; -import { findAllSportsSeasons } from "~/models/sports-season"; +import { findAllSports } from "~/models/sport"; import { Button } from "~/components/ui/button"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; @@ -51,19 +51,15 @@ export function meta({ data }: Route.MetaArgs): Route.MetaDescriptors { } export async function loader({ params }: Route.LoaderArgs) { - const template = await findSeasonTemplateWithSportsSeasons(params.id); - + const template = await findSeasonTemplateWithSports(params.id); + if (!template) { throw new Response("Template not found", { status: 404 }); } - const allSportsSeasons = await findAllSportsSeasons(); + const allSports = await findAllSports(); - // Type assertion since we know the sport relation is included - return { - template, - allSportsSeasons: allSportsSeasons as Array - }; + return { template, allSports }; } export async function action({ request, params }: Route.ActionArgs) { @@ -82,45 +78,34 @@ export async function action({ request, params }: Route.ActionArgs) { } if (intent === "add-sport") { - const sportsSeasonId = formData.get("sportsSeasonId"); - - if (typeof sportsSeasonId === "string") { - await addSportToTemplate(params.id, sportsSeasonId); + const sportId = formData.get("sportId"); + + if (typeof sportId === "string") { + await addSportToTemplate(params.id, sportId); } return { success: true }; } if (intent === "remove-sport") { - const sportsSeasonId = formData.get("sportsSeasonId"); - - if (typeof sportsSeasonId === "string") { - await removeSportFromTemplate(params.id, sportsSeasonId); + const sportId = formData.get("sportId"); + + if (typeof sportId === "string") { + await removeSportFromTemplate(params.id, sportId); } return { success: true }; } // Update template const name = formData.get("name"); - const year = formData.get("year"); const description = formData.get("description"); if (typeof name !== "string" || !name.trim()) { return { error: "Template name is required" }; } - if (typeof year !== "string") { - return { error: "Year is required" }; - } - - const yearNum = parseInt(year, 10); - if (isNaN(yearNum) || yearNum < 2000 || yearNum > 2100) { - return { error: "Year must be between 2000 and 2100" }; - } - try { await updateSeasonTemplate(params.id, { name: name.trim(), - year: yearNum, description: typeof description === "string" && description.trim() ? description.trim() : null, }); @@ -132,15 +117,15 @@ export async function action({ request, params }: Route.ActionArgs) { } export default function EditTemplate({ loaderData, actionData }: Route.ComponentProps) { - const { template, allSportsSeasons } = loaderData; + const { template, allSports } = loaderData; const [selectedSportId, setSelectedSportId] = useState(""); - const includedSeasonIds = new Set( - template.seasonTemplateSports.map((s) => s.sportsSeasonId) + const includedSportIds = new Set( + template.seasonTemplateSports.map((s) => s.sportId) ); - const availableSportsSeasons = allSportsSeasons.filter( - (s) => !includedSeasonIds.has(s.id) + const availableSports = allSports.filter( + (s) => !includedSportIds.has(s.id) ); return ( @@ -170,19 +155,6 @@ export default function EditTemplate({ loaderData, actionData }: Route.Component /> -
- - -
-