brackt/app/routes/api/draft-commissioner.ts

203 lines
6 KiB
TypeScript

import { data, type ActionFunctionArgs } from "react-router";
import { getAuth } from "@clerk/react-router/server";
import {
findSeasonById,
updateSeason,
updateSeasonStatus,
findTeamsBySeasonId,
isCommissioner,
createDraftPick,
initializeDraftTimers,
updateTeamTimer,
getSeasonTimers,
autoPickForTeam,
calculatePickInfo,
removeFromQueue,
getTeamQueue,
} from "~/models";
import { getSocketIO } from "../../../server/socket.js";
export async function action(args: ActionFunctionArgs) {
const { userId } = await getAuth(args);
if (!userId) {
return data({ error: "Unauthorized" }, { status: 401 });
}
const { request } = args;
const formData = await request.formData();
const actionType = formData.get("action");
const seasonId = formData.get("seasonId");
if (!seasonId || typeof seasonId !== "string") {
return data({ error: "Season ID is required" }, { status: 400 });
}
// Get season
const season = await findSeasonById(seasonId);
if (!season) {
return data({ error: "Season not found" }, { status: 404 });
}
// Verify user is commissioner
const isUserCommissioner = await isCommissioner(season.leagueId, userId);
if (!isUserCommissioner) {
return data({ error: "Only commissioners can perform this action" }, { status: 403 });
}
try {
const io = getSocketIO();
switch (actionType) {
case "start-draft": {
// Check if draft already started
if (season.draftStartedAt) {
return data({ error: "Draft has already started" }, { status: 400 });
}
// Get teams
const teams = await findTeamsBySeasonId(seasonId);
// Initialize timers
await initializeDraftTimers(seasonId, teams, season.draftInitialTime || 120);
// Update season
await updateSeason(seasonId, {
draftStartedAt: new Date(),
currentPickNumber: 1,
draftPaused: false,
});
await updateSeasonStatus(seasonId, "draft");
// Get updated timers
const timers = await getSeasonTimers(seasonId);
// Broadcast to all clients
io.to(`draft-${seasonId}`).emit("draft-started", {
seasonId,
startedAt: new Date(),
timers,
});
return data({ success: true });
}
case "pause-draft": {
const pause = formData.get("pause") === "true";
// Check if draft has started
if (!season.draftStartedAt) {
return data({ error: "Draft has not started yet" }, { status: 400 });
}
// Update season
await updateSeason(seasonId, { draftPaused: pause });
// Broadcast to all clients
io.to(`draft-${seasonId}`).emit("draft-paused", {
seasonId,
isPaused: pause,
});
return data({ success: true });
}
case "force-pick": {
const teamId = formData.get("teamId");
if (!teamId || typeof teamId !== "string") {
return data({ error: "Team ID is required" }, { status: 400 });
}
// Check if draft has started
if (!season.draftStartedAt) {
return data({ error: "Draft has not started" }, { status: 400 });
}
// Check if draft is complete
const teams = await findTeamsBySeasonId(seasonId);
const totalPicks = season.draftRounds * teams.length;
const currentPickNumber = season.currentPickNumber || 1;
if (currentPickNumber > totalPicks) {
return data({ error: "Draft is already complete" }, { status: 400 });
}
// Auto-pick for the team
const participantId = await autoPickForTeam(seasonId, teamId);
if (!participantId) {
return data({ error: "No available participants to pick" }, { status: 400 });
}
// Calculate pick info
const { round, pickInRound } = calculatePickInfo(currentPickNumber, teams.length);
// Create the draft pick
const pick = await createDraftPick({
seasonId,
teamId,
participantId,
pickNumber: currentPickNumber,
round,
pickInRound,
pickedByUserId: userId,
pickedByType: "commissioner",
timeUsed: 0,
});
// Remove from queue if it was queued
const queue = await getTeamQueue(teamId);
const queueItem = queue.find((item: any) => item.participantId === participantId);
if (queueItem) {
await removeFromQueue(queueItem.id);
}
// Update season to next pick
const nextPickNumber = currentPickNumber + 1;
await updateSeason(seasonId, { currentPickNumber: nextPickNumber });
// Add increment time to current team's timer
if (season.draftIncrementTime) {
const timers = await getSeasonTimers(seasonId);
const currentTimer = timers.find((t: any) => t.teamId === teamId);
if (currentTimer) {
const newTime = currentTimer.timeRemaining + season.draftIncrementTime;
await updateTeamTimer(teamId, newTime);
}
}
// Check if draft is complete
if (nextPickNumber > totalPicks) {
await updateSeasonStatus(seasonId, "active");
io.to(`draft-${seasonId}`).emit("draft-completed", {
seasonId,
});
}
// Broadcast pick to all clients in the room
io.to(`draft-${seasonId}`).emit("pick-made", {
pick,
nextPickNumber,
isDraftComplete: nextPickNumber > totalPicks,
});
// Emit queue update to team owner
const updatedQueue = await getTeamQueue(teamId);
io.to(`draft-${seasonId}`).emit("queue-updated", {
teamId,
queue: updatedQueue,
});
return data({ success: true, pick });
}
default:
return data({ error: "Invalid action" }, { status: 400 });
}
} catch (error) {
console.error("Commissioner action error:", error);
return data({
error: error instanceof Error ? error.message : "Failed to perform action"
}, { status: 500 });
}
}