From 813db84d928b986bbac382d3e9f49600a192a2ea Mon Sep 17 00:00:00 2001 From: rngsurrounded Date: Sat, 1 Mar 2025 19:20:58 +0900 Subject: [PATCH 1/5] feat: continued working on competition runner page --- .../pages/CompetitionPreviewPage/index.tsx | 8 +- .../src/pages/CompetitionRunnerPage/index.tsx | 178 +++++++++++------- .../CompetitionRunnerPage/utils/utils.ts | 23 +++ services/frontend/src/shared/mocks/mocks.ts | 23 ++- services/frontend/src/styles/globals.css | 26 ++- 5 files changed, 171 insertions(+), 87 deletions(-) create mode 100644 services/frontend/src/pages/CompetitionRunnerPage/utils/utils.ts diff --git a/services/frontend/src/pages/CompetitionPreviewPage/index.tsx b/services/frontend/src/pages/CompetitionPreviewPage/index.tsx index 7feea79..093b724 100644 --- a/services/frontend/src/pages/CompetitionPreviewPage/index.tsx +++ b/services/frontend/src/pages/CompetitionPreviewPage/index.tsx @@ -35,11 +35,9 @@ const CompetitionPreview = () => { }; const handleContinue = () => { - if (competition?.id) { - const competitionTasks = mockTasks[competition.id]; - - if (competitionTasks && competitionTasks.length > 0) { - const firstTaskId = competitionTasks[0].id; + if (competition?.id) { + if (mockTasks && mockTasks.length > 0) { + const firstTaskId = mockTasks[0].id; navigate(`/competition/${competition.id}/tasks/${firstTaskId}`); } else { navigate(`/competition/${competition.id}/tasks`); diff --git a/services/frontend/src/pages/CompetitionRunnerPage/index.tsx b/services/frontend/src/pages/CompetitionRunnerPage/index.tsx index fe030dd..437f6b2 100644 --- a/services/frontend/src/pages/CompetitionRunnerPage/index.tsx +++ b/services/frontend/src/pages/CompetitionRunnerPage/index.tsx @@ -1,69 +1,61 @@ -import { useState } from "react"; -import { useParams } from "react-router-dom"; -import Navbar from "@/modules/Navbar"; -import { Task, TaskStatus } from "@/shared/types/types"; - - - -const sampleTasks: Task[] = [ - { id: "1", number: "1.1", status: "uncleared" }, - { id: "2", number: "1.2", status: "checking" }, - { id: "3", number: "1.3", status: "correct" }, - { id: "4", number: "2.1", status: "partial" }, - { id: "5", number: "2.2", status: "wrong" }, - { id: "6", number: "2.3", status: "uncleared" }, - { id: "7", number: "3.1", status: "checking" }, - { id: "8", number: "3.2", status: "correct" }, -]; +import { useState, useEffect } from "react"; +import { useParams, useNavigate } from "react-router-dom"; +import { Task } from "@/shared/types/types"; +import { getTaskBgColor, getTaskTextColor } from "./utils/utils"; +import { mockTasks } from "@/shared/mocks/mocks"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "lucide-react"; const CompetitionRunnerPage = () => { - const { id } = useParams<{ id: string }>(); + const { id, taskId } = useParams<{ id: string; taskId?: string }>(); + const navigate = useNavigate(); const [competitionTitle, setCompetitionTitle] = useState("Олимпиада DANO 2025. Индивидуальный этап"); - const [tasks, setTasks] = useState(sampleTasks); - const [selectedTaskId, setSelectedTaskId] = useState(null); + const [tasks] = useState(mockTasks); + const [selectedTaskId, setSelectedTaskId] = useState(taskId || null); + const [answer, setAnswer] = useState(""); - const getTaskBgColor = (status: TaskStatus): string => { - switch (status) { - case "uncleared": return "bg-[var(--color-task-uncleared)]"; - case "checking": return "bg-[var(--color-task-checking)]"; - case "correct": return "bg-[var(--color-task-correct)]"; - case "partial": return "bg-[var(--color-task-partial)]"; - case "wrong": return "bg-[var(--color-task-wrong)]"; + useEffect(() => { + if (taskId) { + setSelectedTaskId(taskId); + } else if (tasks.length > 0) { + navigate(`/competition/${id}/tasks/${tasks[0].id}`, { replace: true }); } - }; - - const getTaskTextColor = (status: TaskStatus): string => { - switch (status) { - case "uncleared": return "text-gray-600"; - case "checking": return "text-gray-800"; - case "correct": return "text-green-800"; - case "partial": return "text-green-700"; - case "wrong": return "text-red-800"; - } - }; + }, [taskId, tasks, id, navigate]); const handleTaskClick = (taskId: string) => { - setSelectedTaskId(taskId); + if (selectedTaskId !== taskId) { + setSelectedTaskId(taskId); + navigate(`/competition/${id}/tasks/${taskId}`); + } + }; + + const currentTask = tasks.find(t => t.id === selectedTaskId); + + const handleSubmit = () => { + console.log("Submitting answer:", answer); + // Submit logic here + }; + + const handleHistoryClick = () => { + console.log("View history"); }; return ( - <> - - -
-
-
-

{competitionTitle}

+ <> +
+
+
+

{competitionTitle}

-
+
{tasks.map((task) => (
handleTaskClick(task.id)} > {task.number} @@ -73,21 +65,81 @@ const CompetitionRunnerPage = () => {
-
-
- {selectedTaskId ? ( -
-

- Задание {tasks.find(t => t.id === selectedTaskId)?.number} -

-

- Содержание задания будет отображаться здесь. -

+
+
+ {currentTask ? ( +
+ {/* Left Container - Task Description */} +
+

+ Задача {currentTask.number} +

+ +
+

+ Рассмотрим последовательность чисел 2, 3, 5, 9, 17, 33, 65, 129, ... + Каждый член этой последовательности, начиная с третьего, равен сумме двух предыдущих членов. +

+

+ Найдите сумму первых 15 членов этой последовательности. +

+

+ В ответе укажите целое число. +

+
+
+ + {/* Right Container - Solution Area */} +
+ {/* Solution Status Card */} +
+
+ + Решение 12345 + + + Зачтено 5/10 баллов + +
+
+ 1 марта, 08:41 +
+
+ + {/* Answer Input */} +
+