formatting
This commit is contained in:
@@ -10,187 +10,191 @@ import Header from '../views/mission/statement/Header';
|
||||
import MissionSubmissions from '../views/mission/statement/MissionSubmissions';
|
||||
|
||||
const Mission = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// Получаем параметры из URL
|
||||
const { missionId } = useParams<{ missionId: string }>();
|
||||
const mission = useAppSelector((state) => state.missions.currentMission);
|
||||
const missionIdNumber = Number(missionId);
|
||||
if (!missionId || isNaN(missionIdNumber)) {
|
||||
return <Navigate to="/home" replace />;
|
||||
}
|
||||
|
||||
const [code, setCode] = useState<string>("");
|
||||
const [language, setLanguage] = useState<string>("");
|
||||
|
||||
const pollingRef = useRef<number | null>(null);
|
||||
const submissions = useAppSelector((state) => state.submin.submitsById[missionIdNumber] || []);
|
||||
const submissionsRef = useRef(submissions);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const startPolling = () => {
|
||||
if (pollingRef.current)
|
||||
return;
|
||||
|
||||
pollingRef.current = setInterval(async () => {
|
||||
dispatch(fetchMySubmitsByMission(missionIdNumber));
|
||||
|
||||
const hasWaiting = submissionsRef.current.some(
|
||||
(s: any) => s.solution.status == "Waiting" || s.solution.testerState === "Waiting"
|
||||
);
|
||||
if (!hasWaiting) {
|
||||
// Всё проверено — стоп
|
||||
if (pollingRef.current) {
|
||||
clearInterval(pollingRef.current);
|
||||
pollingRef.current = null;
|
||||
}
|
||||
}
|
||||
}, 5000); // 10 секунд
|
||||
};
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchMissionById(missionIdNumber));
|
||||
dispatch(fetchMySubmitsByMission(missionIdNumber));
|
||||
}, [missionIdNumber]);
|
||||
|
||||
useEffect(() => {
|
||||
}, [submissions]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (pollingRef.current) {
|
||||
clearInterval(pollingRef.current);
|
||||
pollingRef.current = null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
submissionsRef.current = submissions;
|
||||
|
||||
if (submissions.length) {
|
||||
const hasWaiting = submissions.some(
|
||||
s => s.solution.status === "Waiting" || s.solution.testerState === "Waiting"
|
||||
);
|
||||
|
||||
if (hasWaiting) {
|
||||
startPolling();
|
||||
}
|
||||
// Получаем параметры из URL
|
||||
const { missionId } = useParams<{ missionId: string }>();
|
||||
const mission = useAppSelector((state) => state.missions.currentMission);
|
||||
const missionIdNumber = Number(missionId);
|
||||
if (!missionId || isNaN(missionIdNumber)) {
|
||||
return <Navigate to="/home" replace />;
|
||||
}
|
||||
}, [submissions]);
|
||||
|
||||
const [code, setCode] = useState<string>('');
|
||||
const [language, setLanguage] = useState<string>('');
|
||||
|
||||
if (!mission || !mission.statements || mission.statements.length === 0) {
|
||||
return <div>Загрузка...</div>;
|
||||
}
|
||||
|
||||
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"
|
||||
const pollingRef = useRef<number | null>(null);
|
||||
const submissions = useAppSelector(
|
||||
(state) => state.submin.submitsById[missionIdNumber] || [],
|
||||
);
|
||||
const submissionsRef = useRef(submissions);
|
||||
|
||||
// 2. Берём первый statement с форматом Html и языком russian
|
||||
const htmlStatement = mission.statements.find(
|
||||
(stmt: any) => stmt && stmt.language === "russian" && stmt.format === "Html"
|
||||
);
|
||||
const startPolling = () => {
|
||||
if (pollingRef.current) return;
|
||||
|
||||
if (!latexStatement) throw new Error("Не найден блок Latex на русском");
|
||||
if (!htmlStatement) throw new Error("Не найден блок Html на русском");
|
||||
pollingRef.current = setInterval(async () => {
|
||||
dispatch(fetchMySubmitsByMission(missionIdNumber));
|
||||
|
||||
// 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
|
||||
const hasWaiting = submissionsRef.current.some(
|
||||
(s: any) =>
|
||||
s.solution.status == 'Waiting' ||
|
||||
s.solution.testerState === 'Waiting',
|
||||
);
|
||||
if (!hasWaiting) {
|
||||
// Всё проверено — стоп
|
||||
if (pollingRef.current) {
|
||||
clearInterval(pollingRef.current);
|
||||
pollingRef.current = null;
|
||||
}
|
||||
}
|
||||
}, 5000); // 10 секунд
|
||||
};
|
||||
} catch (err) {
|
||||
console.error("Ошибка парсинга statementTexts:", err);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchMissionById(missionIdNumber));
|
||||
dispatch(fetchMySubmitsByMission(missionIdNumber));
|
||||
}, [missionIdNumber]);
|
||||
|
||||
useEffect(() => {}, [submissions]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (pollingRef.current) {
|
||||
clearInterval(pollingRef.current);
|
||||
pollingRef.current = null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
useEffect(() => {
|
||||
submissionsRef.current = submissions;
|
||||
|
||||
<div className="h-screen grid grid-rows-[60px,1fr]">
|
||||
<div className="">
|
||||
<Header missionId={missionIdNumber} />
|
||||
</div>
|
||||
if (submissions.length) {
|
||||
const hasWaiting = submissions.some(
|
||||
(s) =>
|
||||
s.solution.status === 'Waiting' ||
|
||||
s.solution.testerState === 'Waiting',
|
||||
);
|
||||
|
||||
<div className="grid grid-cols-2 h-full min-h-0 gap-[20px]">
|
||||
<div className="overflow-y-auto min-h-0 overflow-hidden">
|
||||
<Statement
|
||||
{...statementData}
|
||||
if (hasWaiting) {
|
||||
startPolling();
|
||||
}
|
||||
}
|
||||
}, [submissions]);
|
||||
|
||||
/>
|
||||
if (!mission || !mission.statements || mission.statements.length === 0) {
|
||||
return <div>Загрузка...</div>;
|
||||
}
|
||||
|
||||
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) {
|
||||
console.error('Ошибка парсинга statementTexts:', err);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-screen grid grid-rows-[60px,1fr]">
|
||||
<div className="">
|
||||
<Header missionId={missionIdNumber} />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 h-full min-h-0 gap-[20px]">
|
||||
<div className="overflow-y-auto min-h-0 overflow-hidden">
|
||||
<Statement {...statementData} />
|
||||
</div>
|
||||
|
||||
<div className="overflow-y-auto min-h-0 overflow-hidden pb-[20px]">
|
||||
<div className=" grid grid-rows-[1fr,45px,230px] grid-flow-row h-full w-full gap-[20px] ">
|
||||
<div className="w-full relative ">
|
||||
<CodeEditor
|
||||
onChange={(value: string) => {
|
||||
setCode(value);
|
||||
}}
|
||||
onChangeLanguage={(value: string) => {
|
||||
setLanguage(value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<PrimaryButton
|
||||
text="Отправить"
|
||||
onClick={async () => {
|
||||
await dispatch(
|
||||
submitMission({
|
||||
missionId: missionIdNumber,
|
||||
language: language,
|
||||
languageVersion: 'latest',
|
||||
sourceCode: code,
|
||||
contestId: null,
|
||||
}),
|
||||
).unwrap();
|
||||
dispatch(
|
||||
fetchMySubmitsByMission(
|
||||
missionIdNumber,
|
||||
),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="h-full w-full ">
|
||||
<MissionSubmissions missionId={missionIdNumber} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="overflow-y-auto min-h-0 overflow-hidden pb-[20px]">
|
||||
<div className=' grid grid-rows-[1fr,45px,230px] grid-flow-row h-full w-full gap-[20px] '>
|
||||
<div className='w-full relative '>
|
||||
<CodeEditor
|
||||
onChange={(value: string) => { setCode(value); }}
|
||||
onChangeLanguage={((value: string) => { setLanguage(value); })}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<PrimaryButton text='Отправить' onClick={async () => {
|
||||
await dispatch(submitMission({
|
||||
missionId: missionIdNumber,
|
||||
language: language,
|
||||
languageVersion: "latest",
|
||||
sourceCode: code,
|
||||
contestId: null,
|
||||
|
||||
})).unwrap();
|
||||
dispatch(fetchMySubmitsByMission(missionIdNumber));
|
||||
}} />
|
||||
</div>
|
||||
|
||||
<div className='h-full w-full '>
|
||||
<MissionSubmissions missionId={missionIdNumber} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default Mission;
|
||||
|
||||
Reference in New Issue
Block a user