175 lines
5.3 KiB
TypeScript
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 });
|
|
}
|
|
}
|