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

175 lines
5.3 KiB
TypeScript

import { data, type ActionFunctionArgs } from "react-router";
import { getAuth } from "@clerk/react-router/server";
import {
findSeasonById,
updateSeason,
updateSeasonStatus,
findTeamsBySeasonId,
isCommissioner,
createDraftPick,
isParticipantDrafted,
updateTeamTimer,
getSeasonTimers,
calculatePickInfo,
getTeamForPick,
findDraftSlotsBySeasonId,
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 seasonId = formData.get("seasonId");
const teamId = formData.get("teamId");
const participantId = formData.get("participantId");
if (!seasonId || typeof seasonId !== "string") {
return data({ error: "Season ID is required" }, { status: 400 });
}
if (!teamId || typeof teamId !== "string") {
return data({ error: "Team ID is required" }, { status: 400 });
}
if (!participantId || typeof participantId !== "string") {
return data({ error: "Participant ID is required" }, { status: 400 });
}
try {
// Get season
const season = await findSeasonById(seasonId);
if (!season) {
return data({ error: "Season not found" }, { status: 404 });
}
// Check if draft has started
if (!season.draftStartedAt) {
return data({ error: "Draft has not started" }, { status: 400 });
}
// Check if draft is paused
if (season.draftPaused) {
return data({ error: "Draft is currently paused" }, { 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 });
}
// Get draft slots to determine current team
const draftSlots = await findDraftSlotsBySeasonId(seasonId);
const draftOrder = draftSlots.map((slot: any) => ({
teamId: slot.teamId,
draftOrder: slot.draftOrder,
}));
const currentTeamId = getTeamForPick(currentPickNumber, draftOrder);
if (!currentTeamId) {
return data({ error: "Could not determine current team" }, { status: 400 });
}
// Verify it's the correct team's turn
if (teamId !== currentTeamId) {
return data({ error: "It is not this team's turn" }, { status: 400 });
}
// Verify user has permission (team owner or commissioner)
const team = teams.find((t: any) => t.id === teamId);
const isTeamOwner = team?.ownerId === userId;
const isUserCommissioner = await isCommissioner(season.leagueId, userId);
if (!isTeamOwner && !isUserCommissioner) {
return data({ error: "You do not have permission to make this pick" }, { status: 403 });
}
// Check if participant is already drafted
const isDrafted = await isParticipantDrafted(seasonId, participantId);
if (isDrafted) {
return data({ error: "This participant has already been drafted" }, { status: 400 });
}
// Calculate pick info
const { round, pickInRound } = calculatePickInfo(currentPickNumber, teams.length);
// Determine picked by type
const pickedByType = isUserCommissioner && !isTeamOwner ? "commissioner" : "owner";
// Create the draft pick
const pick = await createDraftPick({
seasonId,
teamId,
participantId,
pickNumber: currentPickNumber,
round,
pickInRound,
pickedByUserId: userId,
pickedByType,
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
const io = getSocketIO();
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 });
} catch (error) {
console.error("Error making pick:", error);
return data({
error: error instanceof Error ? error.message : "Failed to make pick",
}, { status: 500 });
}
}