import { Form, Link, useActionData } from "react-router"; import type { Route } from "./+types/admin.sports-seasons.$id.expected-values"; import { findSportsSeasonById } from "~/models/sports-season"; import { findParticipantsBySportsSeasonId } from "~/models/participant"; import { upsertParticipantEV, getParticipantEV, getAllParticipantEVsForSeason } from "~/models/participant-expected-value"; import { Button } from "~/components/ui/button"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "~/components/ui/card"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "~/components/ui/table"; import { ArrowLeft, Save, Calculator } from "lucide-react"; import type { ProbabilitySource } from "~/models/participant-expected-value"; export async function loader({ params }: Route.LoaderArgs) { const sportsSeason = await findSportsSeasonById(params.id); if (!sportsSeason) { throw new Response("Sports season not found", { status: 404 }); } const participants = await findParticipantsBySportsSeasonId(params.id); const existingEVs = await getAllParticipantEVsForSeason(params.id); // Create a map of participant ID to EV data const evMap = new Map(existingEVs.map(ev => [ev.participantId, ev])); return { sportsSeason: sportsSeason as typeof sportsSeason & { sport: { id: string; name: string; type: string; slug: string } }, participants, existingEVs: evMap, }; } export async function action({ request, params }: Route.ActionArgs) { const formData = await request.formData(); const participantId = formData.get("participantId"); const source = (formData.get("source") || "manual") as ProbabilitySource; if (typeof participantId !== "string") { return { error: "Participant ID is required" }; } // Get probability values const probFirst = parseFloat(formData.get("probFirst") as string || "0"); const probSecond = parseFloat(formData.get("probSecond") as string || "0"); const probThird = parseFloat(formData.get("probThird") as string || "0"); const probFourth = parseFloat(formData.get("probFourth") as string || "0"); const probFifth = parseFloat(formData.get("probFifth") as string || "0"); const probSixth = parseFloat(formData.get("probSixth") as string || "0"); const probSeventh = parseFloat(formData.get("probSeventh") as string || "0"); const probEighth = parseFloat(formData.get("probEighth") as string || "0"); // Use default scoring rules // Note: Actual league seasons may have different scoring rules // EVs will be recalculated when used in a specific league const scoringRules = { pointsFor1st: 100, pointsFor2nd: 70, pointsFor3rd: 50, pointsFor4th: 40, pointsFor5th: 25, pointsFor6th: 25, pointsFor7th: 15, pointsFor8th: 15, }; try { const result = await upsertParticipantEV({ participantId, sportsSeasonId: params.id, probabilities: { probFirst, probSecond, probThird, probFourth, probFifth, probSixth, probSeventh, probEighth, }, scoringRules, source, }); return { success: true, participantId, expectedValue: parseFloat(result.expectedValue), }; } catch (error) { console.error("Error saving probabilities:", error); return { error: error instanceof Error ? error.message : "Failed to save probabilities" }; } } export default function ExpectedValuesPage({ loaderData, actionData }: Route.ComponentProps) { const { sportsSeason, participants, existingEVs } = loaderData; return (
Expected Values: {sportsSeason.sport.name} {sportsSeason.year} Manage probability distributions and expected values for participants {actionData?.error && (
{actionData.error}
)} {actionData?.success && (
Successfully saved! Expected Value: {actionData.expectedValue?.toFixed(2)} points
)}

Default Scoring Rules (for EV calculation):

1st: 100 pts 2nd: 70 pts 3rd: 50 pts 4th: 40 pts 5th: 25 pts 6th: 25 pts 7th: 15 pts 8th: 15 pts

Note: EVs will be recalculated with actual league scoring rules when used in fantasy leagues.

Participant 1st % 2nd % 3rd % 4th % 5th % 6th % 7th % 8th % EV {participants.map((participant: { id: string; name: string }) => { const existingEV = existingEVs.get(participant.id); const formId = `form-${participant.id}`; return ( {participant.name} {existingEV ? parseFloat(existingEV.expectedValue).toFixed(2) : "-"}
); })}
{participants.length === 0 && (

No participants found. Please add participants to this sports season first.

)}
); }