import { useParams, Navigate, useNavigate } from 'react-router-dom'; import CodeEditor from '../views/mission/codeeditor/CodeEditor'; import Statement from '../views/mission/statement/Statement'; import { PrimaryButton } from '../components/button/PrimaryButton'; import { useEffect, useRef, useState } from 'react'; import { useAppDispatch, useAppSelector } from '../redux/hooks'; import { fetchMySubmitsByMission, submitMission } from '../redux/slices/submit'; import { fetchMissionById, setMissionsStatus } from '../redux/slices/missions'; import Header from '../views/mission/statement/Header'; import MissionSubmissions from '../views/mission/statement/MissionSubmissions'; import { useQuery } from '../hooks/useQuery'; import { fetchMyAttemptsInContest } from '../redux/slices/contests'; const Mission = () => { const dispatch = useAppDispatch(); const navigate = useNavigate(); // Получаем параметры из URL const { missionId } = useParams<{ missionId: string }>(); const mission = useAppSelector((state) => state.missions.currentMission); const missionStatus = useAppSelector( (state) => state.missions.statuses.fetchById, ); const attempt = useAppSelector( (state) => state.contests.fetchMyAttemptsInContest.attempts[0], ); const missionIdNumber = Number(missionId); const query = useQuery(); const back = query.get('back') ?? undefined; const contestId = Number(query.get('contestId') ?? undefined); if (!missionId || isNaN(missionIdNumber)) { if (back) return ; return ; } const [code, setCode] = useState(''); const [language, setLanguage] = useState(''); const pollingRef = useRef(null); const submissions = useAppSelector( (state) => state.submin.submitsById[missionIdNumber] || [], ); const submissionsRef = useRef(submissions); const startPolling = () => { if (pollingRef.current) return; pollingRef.current = setInterval(async () => { if (contestId) { dispatch(fetchMyAttemptsInContest(contestId)); } dispatch(fetchMySubmitsByMission(missionIdNumber)); const hasWaiting = submissionsRef.current.some( (s: any) => s.solution.status == 'Waiting' || s.solution.testerState === 'Waiting' || s.solution.status === 'Compiling' || s.solution.testerState === 'Compiling', ); if (!hasWaiting) { // Всё проверено — стоп if (pollingRef.current) { clearInterval(pollingRef.current); pollingRef.current = null; } } }, 5000); // 10 секунд }; useEffect(() => { if (contestId) { dispatch(fetchMyAttemptsInContest(contestId)); } }, [contestId]); useEffect(() => { dispatch(fetchMissionById(missionIdNumber)); dispatch(fetchMySubmitsByMission(missionIdNumber)); }, [missionIdNumber]); useEffect(() => {}, [submissions]); useEffect(() => { return () => { if (pollingRef.current) { clearInterval(pollingRef.current); pollingRef.current = null; } }; }, []); useEffect(() => { if (missionStatus == 'failed') { setMissionsStatus({ key: 'fetchById', status: 'idle' }); navigate(back ?? '/home/missions'); } }, [missionStatus]); useEffect(() => { submissionsRef.current = submissions; if (submissions.length) { const hasWaiting = submissions.some( (s) => s.solution.status === 'Waiting' || s.solution.testerState === 'Waiting' || s.solution.status === 'Compiling' || s.solution.testerState === 'Compiling', ); if (hasWaiting) { startPolling(); } } }, [submissions]); if (!mission || !mission.statements || mission.statements.length === 0) { return
Загрузка...
; } interface StatementData { id: number; legend?: string; timeLimit?: number; output?: string; input?: string; sampleTests?: any[]; name?: string; memoryLimit?: number; tags?: string[]; notes?: string; html?: string; mediaFiles?: any[]; } let statementData: StatementData = { id: mission.id }; try { // 1. Берём первый statement с форматом Latex и языком russian const latexStatement = mission.statements.find( (stmt: any) => stmt && stmt.language === 'russian' && stmt.format === 'Latex', ); // 2. Берём первый statement с форматом Html и языком russian const htmlStatement = mission.statements.find( (stmt: any) => stmt && stmt.language === 'russian' && stmt.format === 'Html', ); if (!latexStatement) throw new Error('Не найден блок Latex на русском'); if (!htmlStatement) throw new Error('Не найден блок Html на русском'); // 3. Парсим данные из problem-properties.json const statementTexts = JSON.parse( latexStatement.statementTexts['problem-properties.json'], ); statementData = { id: missionIdNumber, legend: statementTexts.legend, timeLimit: statementTexts.timeLimit, output: statementTexts.output, input: statementTexts.input, sampleTests: statementTexts.sampleTests, name: statementTexts.name, memoryLimit: statementTexts.memoryLimit, tags: mission.tags, notes: statementTexts.notes, html: htmlStatement.statementTexts['problem.html'], mediaFiles: latexStatement.mediaFiles, }; } catch (err) {} return (
{ setCode(value); }} onChangeLanguage={(value: string) => { setLanguage(value); }} />
{ await dispatch( submitMission({ missionId: missionIdNumber, language: language, languageVersion: 'latest', sourceCode: code, contestAttemptId: attempt?.attemptId, }), ).unwrap(); dispatch( fetchMySubmitsByMission( missionIdNumber, ), ); }} />
); }; export default Mission;