From d053d20825753e0b98eeefa7597ea7d07a8252ae Mon Sep 17 00:00:00 2001 From: rngsurrounded Date: Mon, 3 Mar 2025 22:23:15 +0900 Subject: [PATCH] competition timer test --- .../components/CompetitionHeader/index.tsx | 92 +++++++++++++++++-- .../src/pages/CompetitionSession/index.tsx | 5 + 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/services/frontend/src/pages/CompetitionSession/components/CompetitionHeader/index.tsx b/services/frontend/src/pages/CompetitionSession/components/CompetitionHeader/index.tsx index 086abb1..ba486e4 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/task'; 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,16 +20,66 @@ 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); 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 time is up, redirect to competition page + if (diff <= 0) { + navigate(`/competition/${competitionId}`); + return; + } + + // Calculate hours, minutes, seconds + 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); + + // Format time left + setTimeLeft(`${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`); + }; + + // Update timer every second + updateTimer(); + const timerInterval = setInterval(updateTimer, 1000); + + return () => clearInterval(timerInterval); + }, [endDate, competitionId, navigate, competitionType]); + + const showTimeSection = competitionType === CompetitionType.COMPETITIVE && (startDate || endDate); + return (
@@ -42,7 +95,30 @@ const CompetitionHeader: React.FC = ({ {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} />
) : (