diff --git a/backend/app/routers/submissions.py b/backend/app/routers/submissions.py index 13de25f..bfa315c 100644 --- a/backend/app/routers/submissions.py +++ b/backend/app/routers/submissions.py @@ -141,7 +141,11 @@ async def get_my_submissions( db: AsyncSession = Depends(get_db), current_user: User = Depends(get_current_user), ): - query = select(Submission).where(Submission.user_id == current_user.id) + query = ( + select(Submission) + .options(selectinload(Submission.problem)) + .where(Submission.user_id == current_user.id) + ) if problem_id: query = query.where(Submission.problem_id == problem_id) @@ -151,7 +155,25 @@ async def get_my_submissions( query = query.order_by(Submission.created_at.desc()) result = await db.execute(query) - return result.scalars().all() + submissions = result.scalars().all() + + # Add problem_title to each submission + return [ + SubmissionListResponse( + id=s.id, + problem_id=s.problem_id, + problem_title=s.problem.title if s.problem else None, + contest_id=s.contest_id, + language_name=s.language_name, + status=s.status, + score=s.score, + total_points=s.total_points, + tests_passed=s.tests_passed, + tests_total=s.tests_total, + created_at=s.created_at, + ) + for s in submissions + ] @router.get("/problem/{problem_id}", response_model=list[SubmissionListResponse]) diff --git a/backend/app/schemas/submission.py b/backend/app/schemas/submission.py index 675f02b..5fb3b41 100644 --- a/backend/app/schemas/submission.py +++ b/backend/app/schemas/submission.py @@ -33,6 +33,8 @@ class SubmissionResponse(BaseModel): class SubmissionListResponse(BaseModel): id: int problem_id: int + problem_title: str | None = None + contest_id: int | None = None language_name: str | None status: str score: int diff --git a/frontend/src/app/contests/[id]/problems/[problemId]/page.tsx b/frontend/src/app/contests/[id]/problems/[problemId]/page.tsx index 9323fd7..088a688 100644 --- a/frontend/src/app/contests/[id]/problems/[problemId]/page.tsx +++ b/frontend/src/app/contests/[id]/problems/[problemId]/page.tsx @@ -220,6 +220,39 @@ export default function ProblemPage() { const selectedLanguage = languages.find((l) => l.id.toString() === selectedLanguageId); const isJudging = lastSubmission?.status === "pending" || lastSubmission?.status === "judging"; + // localStorage key for this problem's draft + const draftKey = `code_draft_problem_${problemId}`; + + // Load saved draft from localStorage + useEffect(() => { + if (typeof window !== "undefined") { + try { + const saved = localStorage.getItem(draftKey); + if (saved) { + const draft = JSON.parse(saved); + if (draft.code) setCode(draft.code); + if (draft.languageId) setSelectedLanguageId(draft.languageId); + } + } catch (e) { + // Ignore parse errors + } + } + }, [draftKey]); + + // Save draft to localStorage when code or language changes + useEffect(() => { + if (typeof window !== "undefined" && (code || selectedLanguageId)) { + try { + localStorage.setItem( + draftKey, + JSON.stringify({ code, languageId: selectedLanguageId }) + ); + } catch (e) { + // Ignore storage errors + } + } + }, [code, selectedLanguageId, draftKey]); + useEffect(() => { Promise.all([ api.getProblem(problemId), @@ -230,7 +263,31 @@ export default function ProblemPage() { setProblem(problemData); setLanguages(languagesData); setSubmissions(submissionsData); - // Default to Python + + // Check if we have a saved language preference + const savedDraft = typeof window !== "undefined" + ? localStorage.getItem(draftKey) + : null; + + if (savedDraft) { + try { + const draft = JSON.parse(savedDraft); + if (draft.languageId) { + // Verify the saved language still exists + const savedLang = languagesData.find( + (l) => l.id.toString() === draft.languageId + ); + if (savedLang) { + setSelectedLanguageId(draft.languageId); + return; + } + } + } catch (e) { + // Fall through to default + } + } + + // Default to Python if no saved preference const python = languagesData.find((l) => l.name.toLowerCase().includes("python") ); @@ -241,7 +298,7 @@ export default function ProblemPage() { toast.error("Ошибка загрузки задачи"); }) .finally(() => setIsLoading(false)); - }, [problemId]); + }, [problemId, draftKey]); // Poll for submission status useEffect(() => { @@ -304,7 +361,11 @@ export default function ProblemPage() { }; const handleReset = () => { + if (!confirm("Очистить код? Черновик будет удалён.")) return; setCode(""); + if (typeof window !== "undefined") { + localStorage.removeItem(draftKey); + } toast.info("Код очищен"); }; diff --git a/frontend/src/app/submissions/page.tsx b/frontend/src/app/submissions/page.tsx index 152dcb8..18ba4d7 100644 --- a/frontend/src/app/submissions/page.tsx +++ b/frontend/src/app/submissions/page.tsx @@ -333,6 +333,7 @@ export default function SubmissionsPage() { ID + Задача Время Язык Статус @@ -362,6 +363,18 @@ export default function SubmissionsPage() { #{submission.id} + + {submission.problem_title ? ( + + {submission.problem_title} + + ) : ( + + )} +
diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index cec0f31..3b6d7b9 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -93,6 +93,8 @@ export interface Submission { export interface SubmissionListItem { id: number; problem_id: number; + problem_title: string | null; + contest_id: number | null; language_name: string | null; status: string; score: number;