import { Fragment } from "react"; import { Form } from "react-router"; import { Button } from "~/components/ui/button"; import { TeamOwnerBadge } from "~/components/ui/team-owner-badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "~/components/ui/card"; import { Trophy, CheckCircle2 } from "lucide-react"; interface TeamOwnership { participantId: string; teamName: string; teamId: string; ownerName?: string; } interface QPStanding { id: string; totalQualifyingPoints: string; eventsScored: number; finalRanking: number | null; globalRank: number; participant: { id: string; name: string; }; } interface ScoringRules { pointsFor1st: number; pointsFor2nd: number; pointsFor3rd: number; pointsFor4th: number; pointsFor5th: number; pointsFor6th: number; pointsFor7th: number; pointsFor8th: number; } interface QualifyingPointsStandingsProps { standings: QPStanding[]; scoringRules: ScoringRules | null; isFinalized: boolean; totalMajors?: number | null; majorsCompleted?: number; canFinalize: boolean; teamOwnerships?: TeamOwnership[]; userParticipantIds?: string[]; } function formatQP(raw: string): string { const n = parseFloat(raw); if (isNaN(n)) return "—"; // At most 2 decimals, trailing zeros trimmed (1.50→1.5). Mirrors the Discord // embed's formatQPValue (app/services/discord.ts) so the site and Discord agree. return parseFloat(n.toFixed(2)).toString(); } export function QualifyingPointsStandings({ standings, scoringRules, isFinalized, totalMajors, majorsCompleted = 0, canFinalize, teamOwnerships = [], userParticipantIds = [], }: QualifyingPointsStandingsProps) { const ownershipMap = new Map(teamOwnerships.map((o) => [o.participantId, o])); const userParticipantSet = new Set(userParticipantIds); // Use the pre-computed global rank from the loader so displayed ranks reflect the full // participant field even when the array has been filtered down to drafted/points-earning rows. const rankedStandings: Array = standings.map( (standing) => ({ ...standing, currentRank: standing.globalRank }) ); const tiedCountByRank = new Map(); for (const s of rankedStandings) { tiedCountByRank.set(s.currentRank, (tiedCountByRank.get(s.currentRank) ?? 0) + 1); } const showOwnership = teamOwnerships.length > 0; // Index of first row with rank > 8; -1 when there is no cutoff. const firstOver8Idx = rankedStandings.findIndex((s) => s.currentRank > 8); return ( Qualifying Points Standings {isFinalized ? ( Finalized — fantasy points have been assigned ) : ( <> Current standings based on {majorsCompleted} of {totalMajors || "?"} major tournaments completed. )} {standings.length === 0 ? (

No qualifying points awarded yet. Complete a qualifying event to see standings.

) : ( <>
{showOwnership && ( )} {rankedStandings.map((standing, idx) => { const ownership = showOwnership ? ownershipMap.get(standing.participant.id) : undefined; const isTop8 = standing.currentRank <= 8; const isTied = (tiedCountByRank.get(standing.currentRank) ?? 1) > 1; const isOwned = userParticipantSet.has(standing.participant.id); const showPointsLineBefore = firstOver8Idx !== -1 && idx === firstOver8Idx; const isLastBeforePointsLine = firstOver8Idx !== -1 && idx === firstOver8Idx - 1; return ( {showPointsLineBefore && ( )} {showOwnership && ( )} ); })}
# Participant Total QPDrafted By
Points Line
{isTied ? `T${standing.currentRank}` : standing.currentRank} {standing.participant.name} {ownership && (
)}
{formatQP(standing.totalQualifyingPoints)} QP {ownership ? (
) : ( )}
{/* canFinalize is controlled by the route loader; this section is only shown to league admins */} {!isFinalized && canFinalize && (

Ready to finalize?

All {totalMajors} major tournaments are complete. Finalizing will:

  • Convert the top 8 participants to fantasy placements 1–8
  • Award fantasy points based on league scoring rules
  • Update all league standings
  • Lock the qualifying points (no further changes)
)} {!isFinalized && !canFinalize && scoringRules && (

Not ready to finalize yet. Complete all{" "} {totalMajors} major tournaments before finalizing qualifying points. ( {majorsCompleted} of {totalMajors} completed)

)} )}
); }