Bug fixes
This commit is contained in:
@@ -4,7 +4,7 @@ import type { AdminMarathon } from '@/types'
|
||||
import { useToast } from '@/store/toast'
|
||||
import { useConfirm } from '@/store/confirm'
|
||||
import { NeonButton } from '@/components/ui'
|
||||
import { Search, Trash2, StopCircle, ChevronLeft, ChevronRight, Trophy, Clock, CheckCircle, Loader2 } from 'lucide-react'
|
||||
import { Search, Trash2, StopCircle, ChevronLeft, ChevronRight, Trophy, Clock, CheckCircle, Loader2, BadgeCheck, BadgeX } from 'lucide-react'
|
||||
|
||||
const STATUS_CONFIG: Record<string, { label: string; icon: typeof Clock; className: string }> = {
|
||||
preparing: {
|
||||
@@ -108,6 +108,47 @@ export function AdminMarathonsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleCertify = async (marathon: AdminMarathon) => {
|
||||
const confirmed = await confirm({
|
||||
title: 'Верифицировать марафон',
|
||||
message: `Верифицировать марафон "${marathon.title}"? Участники смогут зарабатывать монетки.`,
|
||||
confirmText: 'Верифицировать',
|
||||
})
|
||||
if (!confirmed) return
|
||||
|
||||
try {
|
||||
await adminApi.certifyMarathon(marathon.id)
|
||||
setMarathons(marathons.map(m =>
|
||||
m.id === marathon.id ? { ...m, is_certified: true, certification_status: 'certified' } : m
|
||||
))
|
||||
toast.success('Марафон верифицирован')
|
||||
} catch (err) {
|
||||
console.error('Failed to certify marathon:', err)
|
||||
toast.error('Ошибка верификации')
|
||||
}
|
||||
}
|
||||
|
||||
const handleRevokeCertification = async (marathon: AdminMarathon) => {
|
||||
const confirmed = await confirm({
|
||||
title: 'Отозвать верификацию',
|
||||
message: `Отозвать верификацию марафона "${marathon.title}"? Участники больше не смогут зарабатывать монетки.`,
|
||||
confirmText: 'Отозвать',
|
||||
variant: 'warning',
|
||||
})
|
||||
if (!confirmed) return
|
||||
|
||||
try {
|
||||
await adminApi.revokeCertification(marathon.id)
|
||||
setMarathons(marathons.map(m =>
|
||||
m.id === marathon.id ? { ...m, is_certified: false, certification_status: 'none' } : m
|
||||
))
|
||||
toast.success('Верификация отозвана')
|
||||
} catch (err) {
|
||||
console.error('Failed to revoke certification:', err)
|
||||
toast.error('Ошибка отзыва верификации')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Header */}
|
||||
@@ -145,6 +186,7 @@ export function AdminMarathonsPage() {
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-400">Название</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-400">Создатель</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-400">Статус</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-400">Верификация</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-400">Участники</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-400">Игры</th>
|
||||
<th className="px-4 py-3 text-left text-sm font-medium text-gray-400">Даты</th>
|
||||
@@ -154,13 +196,13 @@ export function AdminMarathonsPage() {
|
||||
<tbody className="divide-y divide-dark-600">
|
||||
{loading ? (
|
||||
<tr>
|
||||
<td colSpan={8} className="px-4 py-8 text-center">
|
||||
<td colSpan={9} className="px-4 py-8 text-center">
|
||||
<div className="animate-spin rounded-full h-6 w-6 border-2 border-accent-500 border-t-transparent mx-auto" />
|
||||
</td>
|
||||
</tr>
|
||||
) : marathons.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={8} className="px-4 py-8 text-center text-gray-400">
|
||||
<td colSpan={9} className="px-4 py-8 text-center text-gray-400">
|
||||
Марафоны не найдены
|
||||
</td>
|
||||
</tr>
|
||||
@@ -179,6 +221,19 @@ export function AdminMarathonsPage() {
|
||||
{statusConfig.label}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
{marathon.is_certified ? (
|
||||
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg bg-green-500/20 text-green-400 border border-green-500/30">
|
||||
<BadgeCheck className="w-3 h-3" />
|
||||
Верифицирован
|
||||
</span>
|
||||
) : (
|
||||
<span className="inline-flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-lg bg-dark-600/50 text-gray-400 border border-dark-500">
|
||||
<BadgeX className="w-3 h-3" />
|
||||
Нет
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-4 py-3 text-sm text-gray-400">{marathon.participants_count}</td>
|
||||
<td className="px-4 py-3 text-sm text-gray-400">{marathon.games_count}</td>
|
||||
<td className="px-4 py-3 text-sm text-gray-400">
|
||||
@@ -188,6 +243,23 @@ export function AdminMarathonsPage() {
|
||||
</td>
|
||||
<td className="px-4 py-3">
|
||||
<div className="flex items-center gap-1">
|
||||
{marathon.is_certified ? (
|
||||
<button
|
||||
onClick={() => handleRevokeCertification(marathon)}
|
||||
className="p-2 text-yellow-400 hover:bg-yellow-500/20 rounded-lg transition-colors"
|
||||
title="Отозвать верификацию"
|
||||
>
|
||||
<BadgeX className="w-4 h-4" />
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => handleCertify(marathon)}
|
||||
className="p-2 text-green-400 hover:bg-green-500/20 rounded-lg transition-colors"
|
||||
title="Верифицировать"
|
||||
>
|
||||
<BadgeCheck className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
{marathon.status !== 'finished' && (
|
||||
<button
|
||||
onClick={() => handleForceFinish(marathon)}
|
||||
|
||||
Reference in New Issue
Block a user