import { useParams, useSearchParams } from "react-router-dom"; import RoundDetail from "@/components/RoundDetail"; import RoundFileUpload from "@/components/RoundFileUpload"; import LogsTable from "@/components/LogsTable"; import ResultsTables from "@/components/ResultsTables"; import RoundEvaluationPanel from "@/components/RoundEvaluationPanel"; import { Button, Card, CardHeader, CardBody, Divider, Tabs, Tab } from "@heroui/react"; import { useContestStore } from "@/stores/contestStore"; import { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { useUserStore } from "@/stores/userStore"; import axios from "axios"; import useRoundEvaluationRun from "@/hooks/useRoundEvaluationRun"; export default function RoundDetailPage() { const { contestId, roundId } = useParams(); const [searchParams, setSearchParams] = useSearchParams(); const cId = contestId ? Number(contestId) : null; const rId = roundId ? Number(roundId) : null; const selectedRound = useContestStore((s) => s.selectedRound); const user = useUserStore((s) => s.user); const [logsRefreshKey, setLogsRefreshKey] = useState(0); const selectedTab = searchParams.get("tab") ?? "verified"; const [declaredFilter, setDeclaredFilter] = useState<"ALL" | "OK">("OK"); const [finalFilter, setFinalFilter] = useState<"ALL" | "OK">("ALL"); const [finalResultLabel, setFinalResultLabel] = useState(null); const [finalResultClass, setFinalResultClass] = useState(""); const [finalResultType, setFinalResultType] = useState(null); const [recalcLoading, setRecalcLoading] = useState(false); const [recalcMessage, setRecalcMessage] = useState(null); const [recalcError, setRecalcError] = useState(null); const [finalPublished, setFinalPublished] = useState(false); const { run } = useRoundEvaluationRun(rId); const { t } = useTranslation("common"); const isAdmin = !!user?.is_admin; const roundDeadline = selectedRound?.id === rId ? selectedRound?.logs_deadline ?? null : null; const anonymousUploadClosed = () => { if (user) return false; if (!roundDeadline) return false; const deadline = new Date(roundDeadline); if (Number.isNaN(deadline.getTime())) return false; return new Date() > deadline; }; const publicResultType = finalResultType ?? run?.result_type ?? null; const shouldShowEvaluatingMessage = !user && ((run && run.status !== "SUCCEEDED") || publicResultType === "TEST"); const evaluatingLabel = t("results_evaluating") ?? "Vyhodnocuje se"; const filterAllLabel = t("results_filter_all") ?? "Všechny výsledky"; const filterOkLabel = t("results_filter_ok_ol") ?? "OK/OL závodníci"; const handleTabChange = (key: any) => { const params = new URLSearchParams(searchParams); params.set("tab", String(key)); setSearchParams(params, { replace: true }); }; const handleRecalculate = async () => { if (!rId) return; try { setRecalcLoading(true); setRecalcMessage(null); setRecalcError(null); await axios.post(`/api/rounds/${rId}/recalculate-claimed`, null, { headers: { Accept: "application/json" }, withCredentials: true, }); setRecalcMessage( (t("declared_recalculate_started") as string) || "Přepočet byl spuštěn." ); } catch (e: any) { const fallback = (t("declared_recalculate_failed") as string) || "Nepodařilo se spustit přepočet."; const msg = e?.response?.data?.message || fallback; setRecalcError(msg); } finally { setRecalcLoading(false); } }; useEffect(() => { if (isAdmin) { setFinalPublished(true); return; } if (!rId) { setFinalPublished(false); return; } const officialRunId = selectedRound?.id === rId ? selectedRound?.official_evaluation_run_id ?? null : null; if (!officialRunId) { setFinalPublished(false); return; } let active = true; (async () => { try { const res = await axios.get<{ status?: string | null; result_type?: string | null }>( `/api/evaluation-runs/${officialRunId}`, { headers: { Accept: "application/json" }, withCredentials: true, } ); if (!active) return; const isFinal = res.data?.status === "SUCCEEDED" && res.data?.result_type === "FINAL"; setFinalPublished(isFinal); } catch { if (!active) return; setFinalPublished(false); } })(); return () => { active = false; }; }, [rId, selectedRound?.official_evaluation_run_id, isAdmin]); return ( <> {t("round_detail_title") ?? "Detail kola"} {user && } {anonymousUploadClosed && ( setLogsRefreshKey((k) => k + 1)} /> )} {shouldShowEvaluatingMessage ? (
{evaluatingLabel}
) : ( <> {finalResultLabel && (
{finalResultLabel}
)}
{ setFinalResultLabel(label); setFinalResultClass(className); setFinalResultType(resultType); }} refreshKey={run?.result_type ?? ""} evaluationRunId={run?.id ?? null} /> )}

{t("declared_note_line1") ?? "Deklarované výsledky jsou předběžné výsledky OK a OL stanic."}

{t("declared_note_line2") ?? "Zobrazené mezinárodní výsledky nejsou oficiální výsledky a slouží pouze pro porovnání."}

{t("declared_note_line3") ?? "Deklarované výsledky jsou uspořádány na základě údajů v hlavičce EDI souborů v řádce CQSOP=. Další sloupce rovněž zobrazují data z deníku, které jsou kontrolovány pouze na správnost formátu zápisu."}

{user && ( )}
{recalcMessage &&
{recalcMessage}
} {recalcError &&
{recalcError}
}
); }