mirror of
https://gitlab.com/megazordpobeda/DataRush.git
synced 2026-05-23 21:27:10 +00:00
feat: started adding timers support for events
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
import { useParams, Link, useNavigate } from "react-router-dom";
|
import { useParams, Link, useNavigate } from "react-router-dom";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { ArrowLeft } from "lucide-react";
|
import { ArrowLeft, Clock, Trophy, BookOpen } from "lucide-react";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||||
import { getCompetition, startCompetition } from "@/shared/api/competitions";
|
import { getCompetition, startCompetition } from "@/shared/api/competitions";
|
||||||
import { getCompetitionTasks } from "@/shared/api/session";
|
import { getCompetitionTasks } from "@/shared/api/session";
|
||||||
import { Loading } from "@/components/ui/loading";
|
import { Loading } from "@/components/ui/loading";
|
||||||
|
import { CompetitionType } from "@/shared/types/competition";
|
||||||
|
|
||||||
const CompetitionPage = () => {
|
const CompetitionPage = () => {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
@@ -38,6 +39,19 @@ const CompetitionPage = () => {
|
|||||||
console.error("Failed to start competition:", error);
|
console.error("Failed to start competition:", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const formatDate = (date?: Date | string) => {
|
||||||
|
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',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleStart = () => {
|
const handleStart = () => {
|
||||||
startMutation.mutate();
|
startMutation.mutate();
|
||||||
@@ -74,13 +88,50 @@ const CompetitionPage = () => {
|
|||||||
|
|
||||||
<div className="flex flex-col-reverse gap-8 md:flex-row">
|
<div className="flex flex-col-reverse gap-8 md:flex-row">
|
||||||
<div className="flex flex-1 flex-col gap-5">
|
<div className="flex flex-1 flex-col gap-5">
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<div className="bg-gray-100 text-gray-700 px-3 py-1 rounded-full text-sm font-medium flex items-center">
|
||||||
|
{competition.type === CompetitionType.COMPETITIVE ? (
|
||||||
|
<>
|
||||||
|
<Trophy size={14} className="mr-1.5" />
|
||||||
|
Соревнование
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<BookOpen size={14} className="mr-1.5" />
|
||||||
|
Тренировка
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h1 className="text-[34px] leading-11 font-semibold text-balance">
|
<h1 className="text-[34px] leading-11 font-semibold text-balance">
|
||||||
{competition.title}
|
{competition.title}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
{competition.type === CompetitionType.COMPETITIVE && (
|
||||||
|
<div className="mt-3 text-gray-600 font-hse-sans">
|
||||||
|
{competition.start_date && (
|
||||||
|
<div className="flex items-center gap-2 mb-1">
|
||||||
|
<Clock size={16} className="text-gray-500" />
|
||||||
|
<span>Начало: {formatDate(competition.start_date)}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{competition.end_date && (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Clock size={16} className="text-gray-500" />
|
||||||
|
<span>Окончание: {formatDate(competition.end_date)}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="prose prose-lg max-w-none text-xl leading-10 font-normal">
|
<div className="prose prose-lg max-w-none text-xl leading-10 font-normal">
|
||||||
<ReactMarkdown>{competition.description || ""}</ReactMarkdown>
|
<ReactMarkdown>{competition.description || ""}</ReactMarkdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full *:w-full md:w-96">
|
<div className="w-full *:w-full md:w-96">
|
||||||
<Button
|
<Button
|
||||||
size={"lg"}
|
size={"lg"}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
CompetitionState,
|
CompetitionState,
|
||||||
CompetitionType,
|
CompetitionType,
|
||||||
} from "@/shared/types/competition";
|
} from "@/shared/types/competition";
|
||||||
|
import { Clock } from "lucide-react";
|
||||||
|
|
||||||
interface CompetitionCardProps {
|
interface CompetitionCardProps {
|
||||||
competition: Competition;
|
competition: Competition;
|
||||||
@@ -15,6 +16,20 @@ export function CompetitionCard({
|
|||||||
competition,
|
competition,
|
||||||
className,
|
className,
|
||||||
}: CompetitionCardProps) {
|
}: CompetitionCardProps) {
|
||||||
|
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',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={cn("aspect-square h-full w-auto overflow-hidden", className)}
|
className={cn("aspect-square h-full w-auto overflow-hidden", className)}
|
||||||
@@ -27,7 +42,7 @@ export function CompetitionCard({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CardContent>
|
<CardContent className="p-4">
|
||||||
<div className="flex flex-col gap-2.5">
|
<div className="flex flex-col gap-2.5">
|
||||||
<div className="text-muted-foreground flex items-center gap-2 *:text-sm *:font-semibold">
|
<div className="text-muted-foreground flex items-center gap-2 *:text-sm *:font-semibold">
|
||||||
<span>
|
<span>
|
||||||
@@ -46,9 +61,28 @@ export function CompetitionCard({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 className="line-clamp-2 text-xl font-semibold">
|
<h3 className="line-clamp-2 text-xl font-semibold">
|
||||||
{competition.title}
|
{competition.title}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
|
{competition.type === CompetitionType.COMPETITIVE && (
|
||||||
|
<div className="text-gray-500 text-sm mt-1">
|
||||||
|
{competition.start_date && (
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<Clock size={14} />
|
||||||
|
<span>Начало: {formatDate(competition.start_date)}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{competition.end_date && (
|
||||||
|
<div className="flex items-center gap-1.5 mt-1">
|
||||||
|
<Clock size={14} />
|
||||||
|
<span>Конец: {formatDate(competition.end_date)}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
Reference in New Issue
Block a user