import { Form, Link } from "react-router"; import type { Route } from "./+types/admin.sports-seasons.$id.events.$eventId"; import { loader, action } from "./admin.sports-seasons.$id.events.$eventId.server"; 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "~/components/ui/select"; import { Badge } from "~/components/ui/badge"; import { ArrowLeft, Trophy, CheckCircle2, Pencil, Trash2, Brackets, Save } from "lucide-react"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "~/components/ui/table"; import { useState } from "react"; export { loader, action }; export default function EventResults({ loaderData, actionData, }: Route.ComponentProps) { const { sportsSeason, event, participants, results, participantResults, seasonResults } = loaderData; const [hasChanges, setHasChanges] = useState(false); // Create a map of participants with results for easy lookup const participantResultsMap = new Map( results.map((r: { participant: { id: string } }) => [r.participant.id, r]) ); // Get participants without results const participantsWithoutResults = participants.filter( (p: { id: string }) => !participantResultsMap.has(p.id) ); // Sort results by placement const sortedResults = [...results].sort((a, b) => (a.placement || 999) - (b.placement || 999)); // Create a map of season results for easy lookup const seasonResultsMap = seasonResults ? new Map( seasonResults.map((r: { participantId: string }) => [r.participantId, r]) ) : new Map(); const getEventTypeLabel = (type: string) => { switch (type) { case "playoff_game": return "Bracket"; case "major_tournament": return "Major Tournament"; case "final_standings": return "Final Standings"; default: return type; } }; return (

{event.name}

{sportsSeason.sport.name} - {sportsSeason.name} •{" "} {getEventTypeLabel(event.eventType)} {event.playoffRound && ` • ${event.playoffRound}`}

{event.eventType === "playoff_game" && ( )} {event.isComplete ? ( Completed ) : ( In Progress )}
{actionData?.error && (
{actionData.error}
)} {actionData?.success && (
{actionData.success}
)} {/* Season Standings Table for final_standings events */} {event.eventType === "final_standings" && !event.isComplete && ( <> Season Standings Tracker Enter championship points for each participant. Positions are automatically calculated based on points (highest = 1st). When the season ends, mark this event as complete to assign fantasy points to the top 8.
Participant Championship Points {participants.map((participant: { id: string; name: string }) => { const result = seasonResultsMap.get(participant.id); const currentPoints = result?.currentPoints || ""; return ( {participant.name} setHasChanges(true)} /> ); })}

{hasChanges ? "You have unsaved changes" : "Update standings after each race/event during the season"}

{/* Complete Season Button */} Finalize Season When the season is complete, mark this event as complete to:
  • Convert the top 8 participants (by position) to fantasy placements 1-8
  • Award fantasy points based on league scoring rules
  • Update all league standings

⚠️ Make sure all standings are saved before completing

)} {/* Regular Result Entry for other event types */} {event.eventType !== "final_standings" && !event.isComplete && ( Add Result Enter the placement for a participant in this event
)} {/* Current Results */}
Results {results.length} of {participants.length} participants have results
{!event.isComplete && results.length > 0 && event.eventType !== "final_standings" && (
)}
{sortedResults.length === 0 ? (

No results added yet. Add results using the form above.

) : ( Placement Participant {!event.isComplete && Actions} {sortedResults.map((result) => (
{result.placement === 1 && ( 🥇 )} {result.placement === 2 && ( 🥈 )} {result.placement === 3 && ( 🥉 )} {result.placement}
{result.participant.name} {!event.isComplete && (
{ if (e.key === 'Enter') { e.currentTarget.form?.requestSubmit(); } }} />
)}
))}
)}
{/* Participant Results with Fantasy Points */} {participantResults && participantResults.length > 0 && ( Fantasy Points Awarded Points calculated from bracket placements (sorted by position) Final Position Participant Fantasy Points {[...participantResults] .sort((a: any, b: any) => { const posA = a.finalPosition ?? 999; const posB = b.finalPosition ?? 999; return posA - posB; }) .map((result: any) => (
{result.finalPosition === 1 && ( 🥇 )} {result.finalPosition === 2 && ( 🥈 )} {result.finalPosition === 3 && ( 🥉 )} {result.finalPosition === 0 ? ( Early Elimination ) : ( `${result.finalPosition}${ result.finalPosition === 1 ? "st" : result.finalPosition === 2 ? "nd" : result.finalPosition === 3 ? "rd" : "th" }` )}
{result.participant.name} {result.qualifyingPoints ? ( {parseFloat(result.qualifyingPoints).toFixed(0)} pts ) : ( - )}
))}
)}
); }