formatting

This commit is contained in:
Виталий Лавшонок
2025-11-04 15:04:59 +03:00
parent 3cd8e14288
commit 4972836164
60 changed files with 3604 additions and 2916 deletions

View File

@@ -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;