From 63ca9599581755c448b5d7ff61748b7597ee9a00 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 23 Feb 2026 01:23:54 +0000 Subject: [PATCH] Fix silent timer failures and missing seasonId filter in timer model - draft.make-pick.ts: create a timer with the increment amount instead of logging a warning and silently skipping when no timer exists for the picking team - draft.force-manual-pick.ts: same fix for the commissioner force-pick path; also unconditionally emit the timer-update socket event so clients always see the updated time - models/draft-timer.ts: add seasonId parameter to getTeamTimer and updateTeamTimer so they cannot match the wrong season's timer when a team participates in multiple seasons https://claude.ai/code/session_016VpJKZZFNQQqzfmLu8pHoc --- app/models/draft-timer.ts | 12 ++++----- app/routes/api/draft.force-manual-pick.ts | 32 ++++++++++++++--------- app/routes/api/draft.make-pick.ts | 32 +++++++++++++---------- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/app/models/draft-timer.ts b/app/models/draft-timer.ts index a267474..f41260f 100644 --- a/app/models/draft-timer.ts +++ b/app/models/draft-timer.ts @@ -1,6 +1,6 @@ import { database } from "~/database/context"; import * as schema from "~/database/schema"; -import { eq } from "drizzle-orm"; +import { eq, and } from "drizzle-orm"; export async function initializeDraftTimers(seasonId: string, teams: { id: string }[], initialTime: number) { const timerData = teams.map((team) => ({ @@ -8,17 +8,17 @@ export async function initializeDraftTimers(seasonId: string, teams: { id: strin teamId: team.id, timeRemaining: initialTime, })); - + const db = database(); await db.insert(schema.draftTimers).values(timerData); } -export async function getTeamTimer(teamId: string) { +export async function getTeamTimer(seasonId: string, teamId: string) { const db = database(); const [timer] = await db .select() .from(schema.draftTimers) - .where(eq(schema.draftTimers.teamId, teamId)); + .where(and(eq(schema.draftTimers.seasonId, seasonId), eq(schema.draftTimers.teamId, teamId))); return timer; } @@ -30,12 +30,12 @@ export async function getSeasonTimers(seasonId: string) { .where(eq(schema.draftTimers.seasonId, seasonId)); } -export async function updateTeamTimer(teamId: string, timeRemaining: number) { +export async function updateTeamTimer(seasonId: string, teamId: string, timeRemaining: number) { const db = database(); const [timer] = await db .update(schema.draftTimers) .set({ timeRemaining, updatedAt: new Date() }) - .where(eq(schema.draftTimers.teamId, teamId)) + .where(and(eq(schema.draftTimers.seasonId, seasonId), eq(schema.draftTimers.teamId, teamId))) .returning(); return timer; } diff --git a/app/routes/api/draft.force-manual-pick.ts b/app/routes/api/draft.force-manual-pick.ts index 7566923..03176be 100644 --- a/app/routes/api/draft.force-manual-pick.ts +++ b/app/routes/api/draft.force-manual-pick.ts @@ -148,9 +148,9 @@ export async function action(args: any) { ), }); + const incrementTime = season.draftIncrementTime || 30; + const newTimeRemaining = (currentTimer?.timeRemaining ?? 0) + incrementTime; if (currentTimer) { - const incrementTime = season.draftIncrementTime || 30; - const newTimeRemaining = currentTimer.timeRemaining + incrementTime; await db .update(schema.draftTimers) .set({ @@ -158,18 +158,24 @@ export async function action(args: any) { updatedAt: new Date(), }) .where(eq(schema.draftTimers.id, currentTimer.id)); + } else { + await db.insert(schema.draftTimers).values({ + seasonId, + teamId, + timeRemaining: newTimeRemaining, + }); + } - // Emit timer update to all clients - try { - getSocketIO().to(`draft-${seasonId}`).emit("timer-update", { - seasonId, - teamId, - timeRemaining: newTimeRemaining, - currentPickNumber: pickNumber, - }); - } catch (error) { - console.error("Socket.IO timer-update error:", error); - } + // Emit timer update to all clients + try { + getSocketIO().to(`draft-${seasonId}`).emit("timer-update", { + seasonId, + teamId, + timeRemaining: newTimeRemaining, + currentPickNumber: pickNumber, + }); + } catch (error) { + console.error("Socket.IO timer-update error:", error); } // Initialize timer for the next team BEFORE updating pick number (prevents race condition) diff --git a/app/routes/api/draft.make-pick.ts b/app/routes/api/draft.make-pick.ts index fbe1cdd..9d2bdf8 100644 --- a/app/routes/api/draft.make-pick.ts +++ b/app/routes/api/draft.make-pick.ts @@ -186,25 +186,29 @@ export async function action(args: any) { ), }); - if (!currentTimer) { - console.warn(`[Pick] No timer found for team ${currentDraftSlot.teamId} in season ${seasonId}`); - } else { - const newTimeRemaining = currentTimer.timeRemaining + incrementTime; + const newTimeRemaining = (currentTimer?.timeRemaining ?? 0) + incrementTime; + if (currentTimer) { await db .update(schema.draftTimers) .set({ timeRemaining: newTimeRemaining, updatedAt: new Date() }) .where(eq(schema.draftTimers.id, currentTimer.id)); + } else { + await db.insert(schema.draftTimers).values({ + seasonId, + teamId: currentDraftSlot.teamId, + timeRemaining: newTimeRemaining, + }); + } - try { - getSocketIO().to(`draft-${seasonId}`).emit("timer-update", { - seasonId, - teamId: currentDraftSlot.teamId, - timeRemaining: newTimeRemaining, - currentPickNumber, - }); - } catch (error) { - console.error("Socket.IO timer-update error:", error); - } + try { + getSocketIO().to(`draft-${seasonId}`).emit("timer-update", { + seasonId, + teamId: currentDraftSlot.teamId, + timeRemaining: newTimeRemaining, + currentPickNumber, + }); + } catch (error) { + console.error("Socket.IO timer-update error:", error); } // Next team's timer is unchanged — their bank carries forward as-is