Add dispute system

This commit is contained in:
2025-12-16 00:33:50 +07:00
parent 339a212e57
commit c7966656d8
22 changed files with 1584 additions and 8 deletions

View File

@@ -1,11 +1,11 @@
import { useState, useEffect, useRef } from 'react'
import { useParams, Link } from 'react-router-dom'
import { marathonsApi, wheelApi, gamesApi, eventsApi } from '@/api'
import type { Marathon, Assignment, SpinResult, Game, ActiveEvent, SwapCandidate, MySwapRequests, CommonEnemyLeaderboardEntry, EventAssignment, GameChoiceChallenges } from '@/types'
import { marathonsApi, wheelApi, gamesApi, eventsApi, assignmentsApi } from '@/api'
import type { Marathon, Assignment, SpinResult, 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'
import { Loader2, Upload, X, Gamepad2, ArrowLeftRight, Check, XCircle, Clock, Send, Trophy, Users, ArrowLeft } from 'lucide-react'
import { Loader2, Upload, X, Gamepad2, ArrowLeftRight, Check, XCircle, Clock, Send, Trophy, Users, ArrowLeft, AlertTriangle } from 'lucide-react'
export function PlayPage() {
const { id } = useParams<{ id: string }>()
@@ -53,6 +53,9 @@ export function PlayPage() {
const [eventComment, setEventComment] = useState('')
const [isEventCompleting, setIsEventCompleting] = useState(false)
// Returned assignments state
const [returnedAssignments, setReturnedAssignments] = useState<ReturnedAssignment[]>([])
const fileInputRef = useRef<HTMLInputElement>(null)
const eventFileInputRef = useRef<HTMLInputElement>(null)
@@ -138,18 +141,20 @@ export function PlayPage() {
const loadData = async () => {
if (!id) return
try {
const [marathonData, assignment, gamesData, eventData, eventAssignmentData] = await Promise.all([
const [marathonData, assignment, gamesData, eventData, eventAssignmentData, returnedData] = await Promise.all([
marathonsApi.get(parseInt(id)),
wheelApi.getCurrentAssignment(parseInt(id)),
gamesApi.list(parseInt(id), 'approved'),
eventsApi.getActive(parseInt(id)),
eventsApi.getEventAssignment(parseInt(id)),
assignmentsApi.getReturnedAssignments(parseInt(id)),
])
setMarathon(marathonData)
setCurrentAssignment(assignment)
setGames(gamesData)
setActiveEvent(eventData)
setEventAssignment(eventAssignmentData)
setReturnedAssignments(returnedData)
} catch (error) {
console.error('Failed to load data:', error)
} finally {
@@ -427,6 +432,45 @@ export function PlayPage() {
</div>
)}
{/* Returned assignments warning */}
{returnedAssignments.length > 0 && (
<Card className="mb-6 border-orange-500/50">
<CardContent>
<div className="flex items-center gap-2 mb-3">
<AlertTriangle className="w-5 h-5 text-orange-500" />
<h3 className="text-lg font-bold text-orange-400">Возвращённые задания</h3>
<span className="ml-auto px-2 py-0.5 bg-orange-500/20 text-orange-400 text-sm rounded">
{returnedAssignments.length}
</span>
</div>
<p className="text-gray-400 text-sm mb-4">
Эти задания были оспорены. После текущего задания вам нужно будет их переделать.
</p>
<div className="space-y-2">
{returnedAssignments.map((ra) => (
<div
key={ra.id}
className="p-3 bg-orange-500/10 border border-orange-500/20 rounded-lg"
>
<div className="flex items-start justify-between">
<div>
<p className="text-white font-medium">{ra.challenge.title}</p>
<p className="text-gray-400 text-sm">{ra.challenge.game.title}</p>
</div>
<span className="px-2 py-0.5 bg-green-500/20 text-green-400 text-xs rounded">
+{ra.challenge.points}
</span>
</div>
<p className="text-orange-300 text-xs mt-2">
Причина: {ra.dispute_reason}
</p>
</div>
))}
</div>
</CardContent>
</Card>
)}
{/* Tabs for Common Enemy event */}
{activeEvent?.event?.type === 'common_enemy' && (
<div className="flex gap-2 mb-6">