Add marathon finish button and system

This commit is contained in:
2025-12-16 02:22:12 +07:00
parent d96f8de568
commit f57a2ba9ea
5 changed files with 89 additions and 8 deletions

View File

@@ -1,7 +1,7 @@
import { useState, useEffect, useRef } from 'react'
import { useParams, Link } from 'react-router-dom'
import { marathonsApi, wheelApi, gamesApi, eventsApi, assignmentsApi } from '@/api'
import type { Marathon, Assignment, SpinResult, Game, ActiveEvent, SwapCandidate, MySwapRequests, CommonEnemyLeaderboardEntry, EventAssignment, GameChoiceChallenges, ReturnedAssignment } from '@/types'
import type { Marathon, Assignment, Game, ActiveEvent, SwapCandidate, MySwapRequests, CommonEnemyLeaderboardEntry, EventAssignment, GameChoiceChallenges, ReturnedAssignment } from '@/types'
import { Button, Card, CardContent } from '@/components/ui'
import { SpinWheel } from '@/components/SpinWheel'
import { EventBanner } from '@/components/EventBanner'
@@ -22,7 +22,6 @@ export function PlayPage() {
const [marathon, setMarathon] = useState<Marathon | null>(null)
const [currentAssignment, setCurrentAssignment] = useState<Assignment | null>(null)
const [spinResult, setSpinResult] = useState<SpinResult | null>(null)
const [games, setGames] = useState<Game[]>([])
const [activeEvent, setActiveEvent] = useState<ActiveEvent | null>(null)
const [isLoading, setIsLoading] = useState(true)
@@ -219,7 +218,6 @@ export function PlayPage() {
try {
const result = await wheelApi.spin(parseInt(id))
setSpinResult(result)
return result.game
} catch (err: unknown) {
const error = err as { response?: { data?: { detail?: string } } }
@@ -256,7 +254,6 @@ export function PlayPage() {
setProofFile(null)
setProofUrl('')
setComment('')
setSpinResult(null)
await loadData()
} catch (err: unknown) {
@@ -270,7 +267,7 @@ export function PlayPage() {
const handleDrop = async () => {
if (!currentAssignment) return
const penalty = spinResult?.drop_penalty || 0
const penalty = currentAssignment.drop_penalty
const confirmed = await confirm({
title: 'Пропустить задание?',
message: `Вы потеряете ${penalty} очков.`,
@@ -285,7 +282,6 @@ export function PlayPage() {
const result = await wheelApi.drop(currentAssignment.id)
toast.info(`Пропущено. Штраф: -${result.penalty} очков`)
setSpinResult(null)
await loadData()
} catch (err: unknown) {
const error = err as { response?: { data?: { detail?: string } } }
@@ -455,6 +451,42 @@ export function PlayPage() {
return <div>Марафон не найден</div>
}
// Check if marathon has ended by status or by date
const marathonEndDate = marathon.end_date ? new Date(marathon.end_date) : null
const isMarathonExpired = marathonEndDate && new Date() > marathonEndDate
const isMarathonEnded = marathon.status === 'finished' || isMarathonExpired
if (isMarathonEnded) {
return (
<div className="max-w-2xl mx-auto">
<Link to={`/marathons/${id}`} className="inline-flex items-center gap-2 text-gray-400 hover:text-white mb-4 transition-colors">
<ArrowLeft className="w-4 h-4" />
К марафону
</Link>
<Card>
<CardContent className="text-center py-12">
<div className="w-16 h-16 bg-gray-700 rounded-full flex items-center justify-center mx-auto mb-4">
<Trophy className="w-8 h-8 text-yellow-500" />
</div>
<h2 className="text-2xl font-bold text-white mb-2">Марафон завершён</h2>
<p className="text-gray-400 mb-6">
{marathon.status === 'finished'
? 'Этот марафон был завершён организатором.'
: 'Этот марафон завершился по истечении срока.'}
</p>
<Link to={`/marathons/${id}/leaderboard`}>
<Button>
<Trophy className="w-4 h-4 mr-2" />
Посмотреть итоговый рейтинг
</Button>
</Link>
</CardContent>
</Card>
</div>
)
}
const participation = marathon.my_participation
return (
@@ -1092,7 +1124,7 @@ export function PlayPage() {
onClick={handleDrop}
isLoading={isDropping}
>
Пропустить (-{spinResult?.drop_penalty || 0})
Пропустить (-{currentAssignment.drop_penalty})
</Button>
</div>
</CardContent>