diff --git a/services/frontend/src/App.tsx b/services/frontend/src/App.tsx index e6af9eb..820d663 100644 --- a/services/frontend/src/App.tsx +++ b/services/frontend/src/App.tsx @@ -1,13 +1,16 @@ import { Routes, Route } from "react-router"; import "./styles/globals.css"; import CompetitionsPage from "./pages/CompetitionsPage"; -import CompetitionPreview from "./pages/CompetitionPreview"; +import CompetitionPreviewPage from "./pages/CompetitionPreviewPage"; +import CompetitionRunnerPage from "./pages/CompetitionRunnerPage"; + const App = () => { return ( } /> - } /> + } /> + } /> ); diff --git a/services/frontend/src/pages/CompetitionPreview/index.tsx b/services/frontend/src/pages/CompetitionPreviewPage/index.tsx similarity index 65% rename from services/frontend/src/pages/CompetitionPreview/index.tsx rename to services/frontend/src/pages/CompetitionPreviewPage/index.tsx index 670723c..7feea79 100644 --- a/services/frontend/src/pages/CompetitionPreview/index.tsx +++ b/services/frontend/src/pages/CompetitionPreviewPage/index.tsx @@ -3,26 +3,9 @@ import { useParams, useNavigate } from "react-router-dom"; import Navbar from "@/modules/Navbar"; import { Button } from "@/components/ui/button"; import { ArrowLeft } from "lucide-react"; -import { Competition, Status } from "@/shared/types/types"; +import { Competition } from "@/shared/types/types"; +import { mockCompetitions, mockTasks } from "@/shared/mocks/mocks"; -const mockCompetitions: Competition[] = [ - { - id: '1', - name: 'Олимпиада DANO 2025. Индивидуальный этап', - imageUrl: '/DANO.png', - isOlympics: true, - status: Status.InProgress, - description: 'Проверка глубоких знаний и навыков в анализе данных. Будет несколько творческих заданий со свободным ответом. Задания выполняются индивидуально, вес тура в итоговом результате – 0,5. Этап пройдет онлайн в заданное время, с применением системы прокторинга. На работу дается 240 минут.' - }, - { - id: '2', - name: 'Олимпиада DANO 2025. Индивидуальный этап', - imageUrl: '/DANO.png', - isOlympics: false, - status: Status.NotParticipating, - description: 'Индивидуальный этап олимпиады DANO 2025 – это уникальная возможность для студентов продемонстрировать свои навыки анализа данных и решения сложных задач. Участники будут работать с реальными наборами данных и применять современные методы машинного обучения и статистического анализа.' - }, -]; const CompetitionPreview = () => { const { id } = useParams<{ id: string }>(); @@ -52,7 +35,16 @@ const CompetitionPreview = () => { }; const handleContinue = () => { - console.log("Continue to competition:", competition?.id); + if (competition?.id) { + const competitionTasks = mockTasks[competition.id]; + + if (competitionTasks && competitionTasks.length > 0) { + const firstTaskId = competitionTasks[0].id; + navigate(`/competition/${competition.id}/tasks/${firstTaskId}`); + } else { + navigate(`/competition/${competition.id}/tasks`); + } + } }; return ( diff --git a/services/frontend/src/pages/CompetitionRunnerPage/index.tsx b/services/frontend/src/pages/CompetitionRunnerPage/index.tsx new file mode 100644 index 0000000..fe030dd --- /dev/null +++ b/services/frontend/src/pages/CompetitionRunnerPage/index.tsx @@ -0,0 +1,98 @@ +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" }, +]; + +const CompetitionRunnerPage = () => { + const { id } = useParams<{ id: string }>(); + const [competitionTitle, setCompetitionTitle] = useState("Олимпиада DANO 2025. Индивидуальный этап"); + const [tasks, setTasks] = useState(sampleTasks); + const [selectedTaskId, setSelectedTaskId] = useState(null); + + 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)]"; + } + }; + + 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"; + } + }; + + const handleTaskClick = (taskId: string) => { + setSelectedTaskId(taskId); + }; + + return ( + <> + + + + + + {competitionTitle} + + + + {tasks.map((task) => ( + handleTaskClick(task.id)} + > + {task.number} + + ))} + + + + + + + {selectedTaskId ? ( + + + Задание {tasks.find(t => t.id === selectedTaskId)?.number} + + + Содержание задания будет отображаться здесь. + + + ) : ( + + Выберите задание для просмотра + + )} + + + > + ); +}; + +export default CompetitionRunnerPage; \ No newline at end of file diff --git a/services/frontend/src/pages/CompetitionsPage/index.tsx b/services/frontend/src/pages/CompetitionsPage/index.tsx index 0abcd4f..3996b7b 100644 --- a/services/frontend/src/pages/CompetitionsPage/index.tsx +++ b/services/frontend/src/pages/CompetitionsPage/index.tsx @@ -5,52 +5,7 @@ import { Alert, AlertDescription } from "@/components/ui/alert"; import { AlertCircle } from "lucide-react"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import Navbar from '@/modules/Navbar'; - -const mockCompetitions: Competition[] = [ - { - id: '1', - name: 'Олимпиада DANO 2025. Индивидуальный этап', - imageUrl: '/DANO.png', - isOlympics: true, - status: Status.InProgress - }, - { - id: '2', - name: 'Олимпиада DANO 2025. Индивидуальный этап', - imageUrl: '/DANO.png', - isOlympics: false, - status: Status.NotParticipating - }, - { - id: '3', - name: 'Олимпиада DANO 2025. Индивидуальный этап', - imageUrl: '/DANO.png', - isOlympics: false, - status: Status.InProgress - }, - { - id: '4', - name: 'Олимпиада DANO 2025. Индивидуальный этап', - imageUrl: '/DANO.png', - isOlympics: true, - status: Status.Completed - }, - { - id: '5', - name: 'Олимпиада DANO 2025. Индивидуальный этап', - imageUrl: '/DANO.png', - isOlympics: false, - status: Status.Completed - }, - { - id: '6', - name: 'Олимпиада DANO 2025. Индивидуальный этап', - imageUrl: '/DANO.png', - isOlympics: true, - status: Status.NotParticipating - } -]; - +import { mockCompetitions } from '@/shared/mocks/mocks'; const CompetitionsPage = () => { const [competitions, setCompetitions] = useState([]); diff --git a/services/frontend/src/shared/mocks/mocks.ts b/services/frontend/src/shared/mocks/mocks.ts new file mode 100644 index 0000000..ac54fe8 --- /dev/null +++ b/services/frontend/src/shared/mocks/mocks.ts @@ -0,0 +1,62 @@ +import { Competition, Status } from "../types/types"; + +const mockCompetitions: Competition[] = [ + { + id: '1', + name: 'Олимпиада DANO 2025. Индивидуальный этап', + imageUrl: '/DANO.png', + isOlympics: true, + status: Status.InProgress, + description: 'Проверка глубоких знаний и навыков в анализе данных. Будет несколько творческих заданий со свободным ответом. Задания выполняются индивидуально, вес тура в итоговом результате – 0,5. Этап пройдет онлайн в заданное время, с применением системы прокторинга. На работу дается 240 минут.' + }, + { + id: '2', + name: 'Олимпиада DANO 2025. Индивидуальный этап', + imageUrl: '/DANO.png', + isOlympics: false, + status: Status.NotParticipating, + description: 'Индивидуальный этап олимпиады DANO 2025 – это уникальная возможность для студентов продемонстрировать свои навыки анализа данных и решения сложных задач. Участники будут работать с реальными наборами данных и применять современные методы машинного обучения и статистического анализа.' + }, + { + id: '3', + name: 'Олимпиада DANO 2025. Индивидуальный этап', + imageUrl: '/DANO.png', + isOlympics: false, + status: Status.InProgress + }, + { + id: '4', + name: 'Олимпиада DANO 2025. Индивидуальный этап', + imageUrl: '/DANO.png', + isOlympics: true, + status: Status.Completed + }, + { + id: '5', + name: 'Олимпиада DANO 2025. Индивидуальный этап', + imageUrl: '/DANO.png', + isOlympics: false, + status: Status.Completed + }, + { + id: '6', + name: 'Олимпиада DANO 2025. Индивидуальный этап', + imageUrl: '/DANO.png', + isOlympics: true, + status: Status.NotParticipating + } +]; + +const mockTasks = { + '1': [ + { id: "1.1", number: "1.1", status: "uncleared" }, + { id: "1.2", number: "1.2", status: "checking" }, + { id: "1.3", number: "1.3", status: "correct" }, + ], + '2': [ + { id: "2.1", number: "1.1", status: "uncleared" }, + { id: "2.2", number: "1.2", status: "uncleared" }, + ] +}; + +export { mockCompetitions, mockTasks } \ No newline at end of file diff --git a/services/frontend/src/shared/types/types.ts b/services/frontend/src/shared/types/types.ts index 6fd3a3e..d670376 100644 --- a/services/frontend/src/shared/types/types.ts +++ b/services/frontend/src/shared/types/types.ts @@ -13,5 +13,13 @@ interface Competition { description?: string; } +type TaskStatus = "uncleared" | "checking" | "correct" | "partial" | "wrong"; + +interface Task { + id: string; + number: string; + status: TaskStatus; +} + export {Status} -export type {Competition} \ No newline at end of file +export type {Competition, TaskStatus, Task} \ No newline at end of file diff --git a/services/frontend/src/styles/globals.css b/services/frontend/src/styles/globals.css index 9df6fec..bcfe1c4 100644 --- a/services/frontend/src/styles/globals.css +++ b/services/frontend/src/styles/globals.css @@ -76,6 +76,12 @@ --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(0.269 0 0); --sidebar-ring: oklch(0.439 0 0); + + --task-uncleared: oklch(0.955 0 0); + --task-checking: oklch(0.899 0.1763 97.07); + --task-correct: oklch(0.962 0.0561 158.62); + --task-partial: oklch(0.971 0.0616 131.35); + --task-wrong: oklch(0.906 0.0484 18.08); } @theme inline { @@ -115,6 +121,13 @@ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); + + --color-task-uncleared: var(--task-uncleared); + --color-task-checking: var(--task-checking); + --color-task-correct: var(--task-correct); + --color-task-partial: var(--task-partial); + --color-task-wrong: var(--task-wrong); + } @layer base {
+ Содержание задания будет отображаться здесь. +
+ Выберите задание для просмотра +