Fix draft timer creation for teams without existing timers (#26)
* Create timer when adding time to a team with no existing timer When a commissioner tries to add time to a team that has no draft timer, instead of returning a 404 error, create a new timer record with the specified amount of time. Removing time still returns a 404 if no timer exists (nothing to remove from). https://claude.ai/code/session_016VpJKZZFNQQqzfmLu8pHoc * 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 --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
a3ec556ecc
commit
34da0594d1
4 changed files with 60 additions and 41 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
import { database } from "~/database/context";
|
import { database } from "~/database/context";
|
||||||
import * as schema from "~/database/schema";
|
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) {
|
export async function initializeDraftTimers(seasonId: string, teams: { id: string }[], initialTime: number) {
|
||||||
const timerData = teams.map((team) => ({
|
const timerData = teams.map((team) => ({
|
||||||
|
|
@ -8,17 +8,17 @@ export async function initializeDraftTimers(seasonId: string, teams: { id: strin
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
timeRemaining: initialTime,
|
timeRemaining: initialTime,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const db = database();
|
const db = database();
|
||||||
await db.insert(schema.draftTimers).values(timerData);
|
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 db = database();
|
||||||
const [timer] = await db
|
const [timer] = await db
|
||||||
.select()
|
.select()
|
||||||
.from(schema.draftTimers)
|
.from(schema.draftTimers)
|
||||||
.where(eq(schema.draftTimers.teamId, teamId));
|
.where(and(eq(schema.draftTimers.seasonId, seasonId), eq(schema.draftTimers.teamId, teamId)));
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -30,12 +30,12 @@ export async function getSeasonTimers(seasonId: string) {
|
||||||
.where(eq(schema.draftTimers.seasonId, seasonId));
|
.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 db = database();
|
||||||
const [timer] = await db
|
const [timer] = await db
|
||||||
.update(schema.draftTimers)
|
.update(schema.draftTimers)
|
||||||
.set({ timeRemaining, updatedAt: new Date() })
|
.set({ timeRemaining, updatedAt: new Date() })
|
||||||
.where(eq(schema.draftTimers.teamId, teamId))
|
.where(and(eq(schema.draftTimers.seasonId, seasonId), eq(schema.draftTimers.teamId, teamId)))
|
||||||
.returning();
|
.returning();
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,17 +61,26 @@ export async function action(args: any) {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let newTime: number;
|
||||||
|
|
||||||
if (!currentTimer) {
|
if (!currentTimer) {
|
||||||
return Response.json({ error: "Timer not found for this team" }, { status: 404 });
|
if (adjustment <= 0) {
|
||||||
|
return Response.json({ error: "Timer not found for this team" }, { status: 404 });
|
||||||
|
}
|
||||||
|
newTime = adjustment;
|
||||||
|
await db.insert(schema.draftTimers).values({
|
||||||
|
seasonId,
|
||||||
|
teamId,
|
||||||
|
timeRemaining: newTime,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
newTime = Math.max(0, currentTimer.timeRemaining + adjustment);
|
||||||
|
await db
|
||||||
|
.update(schema.draftTimers)
|
||||||
|
.set({ timeRemaining: newTime, updatedAt: new Date() })
|
||||||
|
.where(eq(schema.draftTimers.id, currentTimer.id));
|
||||||
}
|
}
|
||||||
|
|
||||||
const newTime = Math.max(0, currentTimer.timeRemaining + adjustment);
|
|
||||||
|
|
||||||
await db
|
|
||||||
.update(schema.draftTimers)
|
|
||||||
.set({ timeRemaining: newTime, updatedAt: new Date() })
|
|
||||||
.where(eq(schema.draftTimers.id, currentTimer.id));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getSocketIO()
|
getSocketIO()
|
||||||
.to(`draft-${seasonId}`)
|
.to(`draft-${seasonId}`)
|
||||||
|
|
|
||||||
|
|
@ -148,9 +148,9 @@ export async function action(args: any) {
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const incrementTime = season.draftIncrementTime || 30;
|
||||||
|
const newTimeRemaining = (currentTimer?.timeRemaining ?? 0) + incrementTime;
|
||||||
if (currentTimer) {
|
if (currentTimer) {
|
||||||
const incrementTime = season.draftIncrementTime || 30;
|
|
||||||
const newTimeRemaining = currentTimer.timeRemaining + incrementTime;
|
|
||||||
await db
|
await db
|
||||||
.update(schema.draftTimers)
|
.update(schema.draftTimers)
|
||||||
.set({
|
.set({
|
||||||
|
|
@ -158,18 +158,24 @@ export async function action(args: any) {
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
})
|
})
|
||||||
.where(eq(schema.draftTimers.id, currentTimer.id));
|
.where(eq(schema.draftTimers.id, currentTimer.id));
|
||||||
|
} else {
|
||||||
|
await db.insert(schema.draftTimers).values({
|
||||||
|
seasonId,
|
||||||
|
teamId,
|
||||||
|
timeRemaining: newTimeRemaining,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Emit timer update to all clients
|
// Emit timer update to all clients
|
||||||
try {
|
try {
|
||||||
getSocketIO().to(`draft-${seasonId}`).emit("timer-update", {
|
getSocketIO().to(`draft-${seasonId}`).emit("timer-update", {
|
||||||
seasonId,
|
seasonId,
|
||||||
teamId,
|
teamId,
|
||||||
timeRemaining: newTimeRemaining,
|
timeRemaining: newTimeRemaining,
|
||||||
currentPickNumber: pickNumber,
|
currentPickNumber: pickNumber,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Socket.IO timer-update error:", error);
|
console.error("Socket.IO timer-update error:", error);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize timer for the next team BEFORE updating pick number (prevents race condition)
|
// Initialize timer for the next team BEFORE updating pick number (prevents race condition)
|
||||||
|
|
|
||||||
|
|
@ -186,25 +186,29 @@ export async function action(args: any) {
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!currentTimer) {
|
const newTimeRemaining = (currentTimer?.timeRemaining ?? 0) + incrementTime;
|
||||||
console.warn(`[Pick] No timer found for team ${currentDraftSlot.teamId} in season ${seasonId}`);
|
if (currentTimer) {
|
||||||
} else {
|
|
||||||
const newTimeRemaining = currentTimer.timeRemaining + incrementTime;
|
|
||||||
await db
|
await db
|
||||||
.update(schema.draftTimers)
|
.update(schema.draftTimers)
|
||||||
.set({ timeRemaining: newTimeRemaining, updatedAt: new Date() })
|
.set({ timeRemaining: newTimeRemaining, updatedAt: new Date() })
|
||||||
.where(eq(schema.draftTimers.id, currentTimer.id));
|
.where(eq(schema.draftTimers.id, currentTimer.id));
|
||||||
|
} else {
|
||||||
|
await db.insert(schema.draftTimers).values({
|
||||||
|
seasonId,
|
||||||
|
teamId: currentDraftSlot.teamId,
|
||||||
|
timeRemaining: newTimeRemaining,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getSocketIO().to(`draft-${seasonId}`).emit("timer-update", {
|
getSocketIO().to(`draft-${seasonId}`).emit("timer-update", {
|
||||||
seasonId,
|
seasonId,
|
||||||
teamId: currentDraftSlot.teamId,
|
teamId: currentDraftSlot.teamId,
|
||||||
timeRemaining: newTimeRemaining,
|
timeRemaining: newTimeRemaining,
|
||||||
currentPickNumber,
|
currentPickNumber,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Socket.IO timer-update error:", error);
|
console.error("Socket.IO timer-update error:", error);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next team's timer is unchanged — their bank carries forward as-is
|
// Next team's timer is unchanged — their bank carries forward as-is
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue