import { useState, useEffect, useRef } from 'react' import { useParams } from 'react-router-dom' import { marathonsApi, wheelApi, gamesApi } from '@/api' import type { Marathon, Assignment, SpinResult, Game } from '@/types' import { Button, Card, CardContent } from '@/components/ui' import { SpinWheel } from '@/components/SpinWheel' import { Loader2, Upload, X } from 'lucide-react' export function PlayPage() { const { id } = useParams<{ id: string }>() const [marathon, setMarathon] = useState(null) const [currentAssignment, setCurrentAssignment] = useState(null) const [spinResult, setSpinResult] = useState(null) const [games, setGames] = useState([]) const [isLoading, setIsLoading] = useState(true) // Complete state const [proofFile, setProofFile] = useState(null) const [proofUrl, setProofUrl] = useState('') const [comment, setComment] = useState('') const [isCompleting, setIsCompleting] = useState(false) // Drop state const [isDropping, setIsDropping] = useState(false) const fileInputRef = useRef(null) useEffect(() => { loadData() }, [id]) const loadData = async () => { if (!id) return try { const [marathonData, assignment, gamesData] = await Promise.all([ marathonsApi.get(parseInt(id)), wheelApi.getCurrentAssignment(parseInt(id)), gamesApi.list(parseInt(id), 'approved'), ]) setMarathon(marathonData) setCurrentAssignment(assignment) setGames(gamesData) } catch (error) { console.error('Failed to load data:', error) } finally { setIsLoading(false) } } const handleSpin = async (): Promise => { if (!id) return null try { const result = await wheelApi.spin(parseInt(id)) setSpinResult(result) return result.game } catch (err: unknown) { const error = err as { response?: { data?: { detail?: string } } } alert(error.response?.data?.detail || 'Не удалось крутить') return null } } const handleSpinComplete = async () => { // Small delay then reload data to show the assignment setTimeout(async () => { await loadData() }, 500) } const handleComplete = async () => { if (!currentAssignment) return if (!proofFile && !proofUrl) { alert('Пожалуйста, предоставьте доказательство (файл или ссылку)') return } setIsCompleting(true) try { const result = await wheelApi.complete(currentAssignment.id, { proof_file: proofFile || undefined, proof_url: proofUrl || undefined, comment: comment || undefined, }) alert(`Выполнено! +${result.points_earned} очков (бонус серии: +${result.streak_bonus})`) // Reset form setProofFile(null) setProofUrl('') setComment('') setSpinResult(null) await loadData() } catch (err: unknown) { const error = err as { response?: { data?: { detail?: string } } } alert(error.response?.data?.detail || 'Не удалось выполнить') } finally { setIsCompleting(false) } } const handleDrop = async () => { if (!currentAssignment) return const penalty = spinResult?.drop_penalty || 0 if (!confirm(`Пропустить это задание? Вы потеряете ${penalty} очков.`)) return setIsDropping(true) try { const result = await wheelApi.drop(currentAssignment.id) alert(`Пропущено. Штраф: -${result.penalty} очков`) setSpinResult(null) await loadData() } catch (err: unknown) { const error = err as { response?: { data?: { detail?: string } } } alert(error.response?.data?.detail || 'Не удалось пропустить') } finally { setIsDropping(false) } } if (isLoading) { return (
) } if (!marathon) { return
Марафон не найден
} const participation = marathon.my_participation return (
{/* Header stats */}
{participation?.total_points || 0}
Очков
{participation?.current_streak || 0}
Серия
{participation?.drop_count || 0}
Пропусков
{/* No active assignment - show spin wheel */} {!currentAssignment && (

Крутите колесо!

Получите случайную игру и задание для выполнения

)} {/* Active assignment */} {currentAssignment && (
Активное задание
{/* Game */}

Игра

{currentAssignment.challenge.game.title}

{/* Challenge */}

Задание

{currentAssignment.challenge.title}

{currentAssignment.challenge.description}

{/* Points */}
+{currentAssignment.challenge.points} очков {currentAssignment.challenge.difficulty} {currentAssignment.challenge.estimated_time && ( ~{currentAssignment.challenge.estimated_time} мин )}
{/* Proof hint */} {currentAssignment.challenge.proof_hint && (

Нужно доказательство: {currentAssignment.challenge.proof_hint}

)} {/* Proof upload */}
{/* File upload */} setProofFile(e.target.files?.[0] || null)} /> {proofFile ? (
{proofFile.name}
) : ( )}
или
{/* URL input */} setProofUrl(e.target.value)} /> {/* Comment */}