From edf01e1c2cdd0d3a5ad93c21ea695f7d18cabbd6 Mon Sep 17 00:00:00 2001 From: Emily Przykucki Date: Fri, 29 May 2026 16:45:29 -0400 Subject: [PATCH 1/2] attempted bug fixes --- .../tournament/TournamentAnswers.jsx | 14 +++++----- .../tournament/TournamentChallengeCard.jsx | 2 +- .../components/tournament/TournamentGame.jsx | 18 ++++++------- .../tournament/TournamentLeaderboard.jsx | 4 +-- app/src/config/tournament.js | 26 +++++++++---------- 5 files changed, 33 insertions(+), 31 deletions(-) diff --git a/app/src/components/tournament/TournamentAnswers.jsx b/app/src/components/tournament/TournamentAnswers.jsx index c85d5d5f..ae4f67d4 100644 --- a/app/src/components/tournament/TournamentAnswers.jsx +++ b/app/src/components/tournament/TournamentAnswers.jsx @@ -13,7 +13,7 @@ import { } from "@mantine/core"; import { IconAlertCircle, IconTarget } from "@tabler/icons-react"; import { TOURNAMENT_CONFIG, getMaskedForecastDate } from "../../config"; -import { getLeaderboard } from "../../utils/tournamentAPI"; +import { getParticipant } from "../../utils/tournamentAPI"; import ForecastleChartCanvas from "../forecastle/ForecastleChartCanvas"; const addWeeksToDate = (dateString, weeks) => { @@ -111,10 +111,12 @@ const TournamentAnswers = ({ setError(null); try { - const leaderboard = await getLeaderboard(tournamentConfig); - const participantEntry = - leaderboard.find((entry) => entry.participantId === participantId) || - null; + const participantData = await getParticipant( + participantId, + tournamentConfig, + ); + const participantEntry = participantData?.participant || null; + const participantSubmissions = participantData?.submissions || []; if (!participantEntry) { setParticipantFound(false); @@ -128,7 +130,7 @@ const TournamentAnswers = ({ const nextSubmissionsByChallenge = {}; tournamentConfig.challenges.forEach((challenge) => { const submission = getSubmissionByChallenge( - participantEntry.submissions || [], + participantSubmissions, challenge, ); const forecasts = getSubmissionForecasts(submission); diff --git a/app/src/components/tournament/TournamentChallengeCard.jsx b/app/src/components/tournament/TournamentChallengeCard.jsx index f55a4169..f51273c3 100644 --- a/app/src/components/tournament/TournamentChallengeCard.jsx +++ b/app/src/components/tournament/TournamentChallengeCard.jsx @@ -56,7 +56,7 @@ const TournamentChallengeCard = ({ const [error, setError] = useState(null); const [inputMode, setInputMode] = useState("median"); // 'median' or 'intervals' const [existingSubmission, setExistingSubmission] = useState(null); - const [zoomedView, setZoomedView] = useState(true); // Start with zoomed view + const [zoomedView, setZoomedView] = useState(false); // Start with full history visible const isSubmissionLocked = tournamentConfig.features?.allowResubmit === false && isCompleted; diff --git a/app/src/components/tournament/TournamentGame.jsx b/app/src/components/tournament/TournamentGame.jsx index ccdfc6f8..ed1a873d 100644 --- a/app/src/components/tournament/TournamentGame.jsx +++ b/app/src/components/tournament/TournamentGame.jsx @@ -115,7 +115,7 @@ const TournamentGame = ({ const [submissionErrors, setSubmissionErrors] = useState({}); const [scores, setScores] = useState(null); const [inputMode, setInputMode] = useState("median"); // 'median', 'intervals', or 'scoring' - const [zoomedView, setZoomedView] = useState(true); + const [zoomedView, setZoomedView] = useState(false); const [visibleRankings, setVisibleRankings] = useState(0); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); @@ -158,7 +158,7 @@ const TournamentGame = ({ if (!response.ok) continue; const locationData = await response.json(); - scData[ch.number] = locationData; + scData[ch.id] = locationData; const groundTruthDates = locationData.ground_truth?.dates || []; const groundTruthValues = @@ -176,7 +176,7 @@ const TournamentGame = ({ return null; }); - gtData[ch.number] = { + gtData[ch.id] = { values: groundTruthForHorizons, dates: horizonDates, fullSeries: locationData.ground_truth, @@ -269,9 +269,9 @@ const TournamentGame = ({ ]); const latestObservationValue = useMemo(() => { - if (!challenge || !scenarioData[challenge.number]) return 1000; + if (!challenge || !scenarioData[challenge.id]) return 1000; - const locationData = scenarioData[challenge.number]; + const locationData = scenarioData[challenge.id]; const groundTruthDates = locationData.ground_truth?.dates || []; const groundTruthValues = locationData.ground_truth?.[challenge.target] || []; @@ -335,9 +335,9 @@ const TournamentGame = ({ }, [challengeId, initialInputs, savedSubmissions, inputMode]); const groundTruthSeries = useMemo(() => { - if (!challenge || !scenarioData[challenge.number]) return []; + if (!challenge || !scenarioData[challenge.id]) return []; - const locationData = scenarioData[challenge.number]; + const locationData = scenarioData[challenge.id]; const groundTruthDates = locationData.ground_truth?.dates || []; const groundTruthValues = locationData.ground_truth?.[challenge.target] || []; @@ -470,14 +470,14 @@ const TournamentGame = ({ ); // Calculate scores - const gtData = groundTruthData[challenge.number]; + const gtData = groundTruthData[challenge.id]; if (!gtData) { throw new Error("Ground truth data not available"); } const userScore = scoreUserForecast(forecastEntries, gtData.values); - const locationData = scenarioData[challenge.number]; + const locationData = scenarioData[challenge.id]; const modelScores = scoreModels( locationData.forecasts?.[challenge.forecastDate]?.[challenge.target] || {}, diff --git a/app/src/components/tournament/TournamentLeaderboard.jsx b/app/src/components/tournament/TournamentLeaderboard.jsx index e49224ee..a4114840 100644 --- a/app/src/components/tournament/TournamentLeaderboard.jsx +++ b/app/src/components/tournament/TournamentLeaderboard.jsx @@ -310,7 +310,7 @@ const TournamentLeaderboard = ({ Participant Avg rWIS {tournamentConfig.challenges.map((ch) => ( - + Ch {ch.number} ))} @@ -420,7 +420,7 @@ const TournamentLeaderboard = ({ {tournamentConfig.challenges.map((ch) => ( - + Date: Fri, 29 May 2026 16:59:48 -0400 Subject: [PATCH 2/2] further bug fixes (URGENT) --- .../tournament/TournamentAnswers.jsx | 21 ++++++++++++++++- .../tournament/TournamentChallengeCard.jsx | 2 +- .../tournament/TournamentDashboard.jsx | 5 ++++ .../components/tournament/TournamentGame.jsx | 23 +++++++++++-------- .../tournament/TournamentLeaderboard.jsx | 4 ++-- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/app/src/components/tournament/TournamentAnswers.jsx b/app/src/components/tournament/TournamentAnswers.jsx index ae4f67d4..f2ecaffc 100644 --- a/app/src/components/tournament/TournamentAnswers.jsx +++ b/app/src/components/tournament/TournamentAnswers.jsx @@ -93,6 +93,8 @@ const getSubmissionByChallenge = (submissions, challenge) => { const TournamentAnswers = ({ tournamentConfig = TOURNAMENT_CONFIG, participantId, + completedCount: completedCountProp = null, + isActive = false, }) => { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -107,6 +109,23 @@ const TournamentAnswers = ({ return; } + if (!isActive && completedCountProp !== null) { + setLoading(false); + return; + } + + if ( + Number.isFinite(completedCountProp) && + completedCountProp < tournamentConfig.numChallenges + ) { + setSubmissionsByChallenge({}); + setChallengeData({}); + setParticipantFound(true); + setError(null); + setLoading(false); + return; + } + setLoading(true); setError(null); @@ -212,7 +231,7 @@ const TournamentAnswers = ({ }; loadAnswers(); - }, [participantId, tournamentConfig]); + }, [participantId, tournamentConfig, completedCountProp, isActive]); const completedCount = useMemo( () => Object.keys(submissionsByChallenge).length, diff --git a/app/src/components/tournament/TournamentChallengeCard.jsx b/app/src/components/tournament/TournamentChallengeCard.jsx index f51273c3..f55a4169 100644 --- a/app/src/components/tournament/TournamentChallengeCard.jsx +++ b/app/src/components/tournament/TournamentChallengeCard.jsx @@ -56,7 +56,7 @@ const TournamentChallengeCard = ({ const [error, setError] = useState(null); const [inputMode, setInputMode] = useState("median"); // 'median' or 'intervals' const [existingSubmission, setExistingSubmission] = useState(null); - const [zoomedView, setZoomedView] = useState(false); // Start with full history visible + const [zoomedView, setZoomedView] = useState(true); // Start with zoomed view const isSubmissionLocked = tournamentConfig.features?.allowResubmit === false && isCompleted; diff --git a/app/src/components/tournament/TournamentDashboard.jsx b/app/src/components/tournament/TournamentDashboard.jsx index b8bb9ba4..18d7e322 100644 --- a/app/src/components/tournament/TournamentDashboard.jsx +++ b/app/src/components/tournament/TournamentDashboard.jsx @@ -16,6 +16,7 @@ const TournamentDashboard = ({ tournamentConfig = TOURNAMENT_CONFIG }) => { const [participantName, setParticipantName] = useState(null); const [loading, setLoading] = useState(true); const [activeTab, setActiveTab] = useState("challenges"); + const [completedCount, setCompletedCount] = useState(null); // Load participant data on mount useEffect(() => { @@ -32,6 +33,7 @@ const TournamentDashboard = ({ tournamentConfig = TOURNAMENT_CONFIG }) => { const handleRegistration = (id, name) => { setParticipantId(id); setParticipantName(name); + setCompletedCount(0); }; // Navigate to leaderboard @@ -87,6 +89,7 @@ const TournamentDashboard = ({ tournamentConfig = TOURNAMENT_CONFIG }) => { participantId={participantId} participantName={participantName} onAllCompleted={goToLeaderboard} + onProgressChange={setCompletedCount} /> @@ -101,6 +104,8 @@ const TournamentDashboard = ({ tournamentConfig = TOURNAMENT_CONFIG }) => { diff --git a/app/src/components/tournament/TournamentGame.jsx b/app/src/components/tournament/TournamentGame.jsx index ed1a873d..85c6162d 100644 --- a/app/src/components/tournament/TournamentGame.jsx +++ b/app/src/components/tournament/TournamentGame.jsx @@ -109,13 +109,14 @@ const TournamentGame = ({ participantId, participantName, onAllCompleted, + onProgressChange, }) => { const [currentChallengeIndex, setCurrentChallengeIndex] = useState(0); const [completedChallenges, setCompletedChallenges] = useState(new Set()); const [submissionErrors, setSubmissionErrors] = useState({}); const [scores, setScores] = useState(null); const [inputMode, setInputMode] = useState("median"); // 'median', 'intervals', or 'scoring' - const [zoomedView, setZoomedView] = useState(false); + const [zoomedView, setZoomedView] = useState(true); const [visibleRankings, setVisibleRankings] = useState(0); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); @@ -158,7 +159,7 @@ const TournamentGame = ({ if (!response.ok) continue; const locationData = await response.json(); - scData[ch.id] = locationData; + scData[ch.number] = locationData; const groundTruthDates = locationData.ground_truth?.dates || []; const groundTruthValues = @@ -176,7 +177,7 @@ const TournamentGame = ({ return null; }); - gtData[ch.id] = { + gtData[ch.number] = { values: groundTruthForHorizons, dates: horizonDates, fullSeries: locationData.ground_truth, @@ -236,6 +237,10 @@ const TournamentGame = ({ tournamentConfig, ]); + useEffect(() => { + onProgressChange?.(completedChallenges.size); + }, [completedChallenges, onProgressChange]); + useEffect(() => { if (inputMode === "scoring") { return; @@ -269,9 +274,9 @@ const TournamentGame = ({ ]); const latestObservationValue = useMemo(() => { - if (!challenge || !scenarioData[challenge.id]) return 1000; + if (!challenge || !scenarioData[challenge.number]) return 1000; - const locationData = scenarioData[challenge.id]; + const locationData = scenarioData[challenge.number]; const groundTruthDates = locationData.ground_truth?.dates || []; const groundTruthValues = locationData.ground_truth?.[challenge.target] || []; @@ -335,9 +340,9 @@ const TournamentGame = ({ }, [challengeId, initialInputs, savedSubmissions, inputMode]); const groundTruthSeries = useMemo(() => { - if (!challenge || !scenarioData[challenge.id]) return []; + if (!challenge || !scenarioData[challenge.number]) return []; - const locationData = scenarioData[challenge.id]; + const locationData = scenarioData[challenge.number]; const groundTruthDates = locationData.ground_truth?.dates || []; const groundTruthValues = locationData.ground_truth?.[challenge.target] || []; @@ -470,14 +475,14 @@ const TournamentGame = ({ ); // Calculate scores - const gtData = groundTruthData[challenge.id]; + const gtData = groundTruthData[challenge.number]; if (!gtData) { throw new Error("Ground truth data not available"); } const userScore = scoreUserForecast(forecastEntries, gtData.values); - const locationData = scenarioData[challenge.id]; + const locationData = scenarioData[challenge.number]; const modelScores = scoreModels( locationData.forecasts?.[challenge.forecastDate]?.[challenge.target] || {}, diff --git a/app/src/components/tournament/TournamentLeaderboard.jsx b/app/src/components/tournament/TournamentLeaderboard.jsx index a4114840..e49224ee 100644 --- a/app/src/components/tournament/TournamentLeaderboard.jsx +++ b/app/src/components/tournament/TournamentLeaderboard.jsx @@ -310,7 +310,7 @@ const TournamentLeaderboard = ({ Participant Avg rWIS {tournamentConfig.challenges.map((ch) => ( - + Ch {ch.number} ))} @@ -420,7 +420,7 @@ const TournamentLeaderboard = ({ {tournamentConfig.challenges.map((ch) => ( - +