diff --git a/services/frontend/src/pages/CompetitionSession/components/CompetitionHeader/index.tsx b/services/frontend/src/pages/CompetitionSession/components/CompetitionHeader/index.tsx index d4bab74..d912f1a 100644 --- a/services/frontend/src/pages/CompetitionSession/components/CompetitionHeader/index.tsx +++ b/services/frontend/src/pages/CompetitionSession/components/CompetitionHeader/index.tsx @@ -1,8 +1,8 @@ -import React from 'react'; -import { Link } from 'react-router-dom'; +import React, { useState, useEffect } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; import { Task } from '@/shared/types/task'; -import { ArrowLeft } from 'lucide-react'; -import { useNavigate } from 'react-router-dom'; +import { ArrowLeft, Clock } from 'lucide-react'; +import { CompetitionType } from '@/shared/types/competition'; interface CompetitionHeaderProps { title: string; @@ -10,6 +10,9 @@ interface CompetitionHeaderProps { competitionId: string; setAnswer: (value: string) => void; setSelectedFile: (file: File | null) => void; + competitionType?: CompetitionType; + startDate?: Date; + endDate?: Date; } const CompetitionHeader: React.FC = ({ @@ -17,33 +20,103 @@ const CompetitionHeader: React.FC = ({ tasks, competitionId, setAnswer, - setSelectedFile + setSelectedFile, + competitionType, + startDate, + endDate }) => { const navigate = useNavigate(); - + const [timeLeft, setTimeLeft] = useState(''); + const handleTaskSelect = (taskId: string) => { setAnswer(""); setSelectedFile(null); - console.log("SETTER ERROR") navigate(`/competition/${competitionId}/tasks/${taskId}`); } - + + const formatDate = (date?: Date) => { + if (!date) return ''; + + const dateObj = typeof date === 'string' ? new Date(date) : date; + return dateObj.toLocaleString('ru-RU', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + }; + + useEffect(() => { + if (!endDate || competitionType !== CompetitionType.COMPETITIVE) return; + + const endDateObj = typeof endDate === 'string' ? new Date(endDate) : endDate; + + const updateTimer = () => { + const now = new Date(); + const diff = endDateObj.getTime() - now.getTime(); + + if (diff <= 0) { + navigate(`/competition/${competitionId}`); + return; + } + + const hours = Math.floor(diff / (1000 * 60 * 60)); + const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((diff % (1000 * 60)) / 1000); + + setTimeLeft(`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`); + }; + + updateTimer(); + const timerInterval = setInterval(updateTimer, 1000); + + return () => clearInterval(timerInterval); + }, [endDate, competitionId, navigate, competitionType]); + + const showTimeSection = competitionType === CompetitionType.COMPETITIVE && (startDate || endDate); + return (
- - - +
+ + + + +

+ {title} +

+
+ -

- {title} -

- -
+ {showTimeSection ? ( +
+
+ {startDate && ( + + Начало: {formatDate(startDate)} + + )} + {endDate && ( + + Конец: {formatDate(endDate)} + + )} + {timeLeft && ( + + Осталось: {timeLeft} + + )} +
+
+ ) : ( +
+ )}
diff --git a/services/frontend/src/pages/CompetitionSession/index.tsx b/services/frontend/src/pages/CompetitionSession/index.tsx index eb80913..4297e8e 100644 --- a/services/frontend/src/pages/CompetitionSession/index.tsx +++ b/services/frontend/src/pages/CompetitionSession/index.tsx @@ -8,6 +8,7 @@ import { getCompetition } from "@/shared/api/competitions"; import { Loader2 } from "lucide-react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { TaskType } from "@/shared/types/task"; +import { CompetitionType } from "@/shared/types/task"; const CompetitionSession = () => { const { id, taskId } = useParams<{ id: string; taskId?: string }>(); @@ -97,6 +98,9 @@ const CompetitionSession = () => { competitionId={competitionId} setAnswer={setAnswer} setSelectedFile={setSelectedFile} + competitionType={competition?.type} + startDate={competition?.start_date} + endDate={competition?.end_date} />
@@ -120,6 +124,7 @@ const CompetitionSession = () => { selectedFile={selectedFile} setSelectedFile={setSelectedFile} onSubmit={handleSubmit} + isSubmitting={submitMutation.isPending} />
) : ( diff --git a/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/index.tsx b/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/index.tsx index 5267dbb..5441408 100644 --- a/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/index.tsx +++ b/services/frontend/src/pages/CompetitionSession/modules/TaskSolution/index.tsx @@ -82,26 +82,31 @@ const TaskSolution: React.FC = ({ useEffect(() => { const loadSolutionContent = async () => { if (!displayedSolution || !displayedSolution.content) return; - + console.log(displayedSolution, solutionHistory, "CHECK") try { if (task.type === TaskType.FILE) { + setAnswer(""); setSelectedFile(null); setSelectedSolutionUrl(displayedSolution.content); - } else { + } + else { + setSelectedFile(null); + setSelectedSolutionUrl(null); const response = await fetch(displayedSolution.content); if (!response.ok) { throw new Error(`Failed to fetch solution content: ${response.status}`); } const text = await response.text(); + setAnswer(text); } } catch (error) { console.error('Error loading solution content:', error); } }; - + loadSolutionContent(); - }, [displayedSolution, task.type, setAnswer, setSelectedFile]); + }, [displayedSolution, setAnswer, setSelectedFile]); const handleOpenHistory = () => { setIsHistoryOpen(true);