'use client' import { use, useState } from 'react' import Link from 'next/link' import { trpc } from '@/lib/trpc/client' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Skeleton } from '@/components/ui/skeleton' import { Switch } from '@/components/ui/switch' import { Label } from '@/components/ui/label' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { UserAvatar } from '@/components/shared/user-avatar' import { Pagination } from '@/components/shared/pagination' import { toast } from 'sonner' import { ArrowLeft, Trophy, Users, CheckCircle2, Brain, BarChart3, Loader2, Crown, UserPlus, X, Play, Lock, Pencil, } from 'lucide-react' const STATUS_COLORS: Record = { DRAFT: 'secondary', NOMINATIONS_OPEN: 'default', VOTING_OPEN: 'default', CLOSED: 'outline', ARCHIVED: 'secondary', } export default function AwardDetailPage({ params, }: { params: Promise<{ id: string }> }) { const { id: awardId } = use(params) const { data: award, isLoading, refetch } = trpc.specialAward.get.useQuery({ id: awardId }) const { data: eligibilityData, refetch: refetchEligibility } = trpc.specialAward.listEligible.useQuery({ awardId, page: 1, perPage: 50, }) const { data: jurors, refetch: refetchJurors } = trpc.specialAward.listJurors.useQuery({ awardId }) const { data: voteResults } = trpc.specialAward.getVoteResults.useQuery({ awardId }) const { data: allUsers } = trpc.user.list.useQuery({ page: 1, perPage: 100 }) const updateStatus = trpc.specialAward.updateStatus.useMutation() const runEligibility = trpc.specialAward.runEligibility.useMutation() const setEligibility = trpc.specialAward.setEligibility.useMutation() const addJuror = trpc.specialAward.addJuror.useMutation() const removeJuror = trpc.specialAward.removeJuror.useMutation() const setWinner = trpc.specialAward.setWinner.useMutation() const [selectedJurorId, setSelectedJurorId] = useState('') const [includeSubmitted, setIncludeSubmitted] = useState(true) const handleStatusChange = async ( status: 'DRAFT' | 'NOMINATIONS_OPEN' | 'VOTING_OPEN' | 'CLOSED' | 'ARCHIVED' ) => { try { await updateStatus.mutateAsync({ id: awardId, status }) toast.success(`Status updated to ${status.replace('_', ' ')}`) refetch() } catch (error) { toast.error( error instanceof Error ? error.message : 'Failed to update status' ) } } const handleRunEligibility = async () => { try { const result = await runEligibility.mutateAsync({ awardId, includeSubmitted }) toast.success( `Eligibility run: ${result.eligible} eligible, ${result.ineligible} ineligible` ) refetchEligibility() refetch() } catch (error) { toast.error( error instanceof Error ? error.message : 'Failed to run eligibility' ) } } const handleToggleEligibility = async ( projectId: string, eligible: boolean ) => { try { await setEligibility.mutateAsync({ awardId, projectId, eligible }) refetchEligibility() } catch { toast.error('Failed to update eligibility') } } const handleAddJuror = async () => { if (!selectedJurorId) return try { await addJuror.mutateAsync({ awardId, userId: selectedJurorId }) toast.success('Juror added') setSelectedJurorId('') refetchJurors() } catch { toast.error('Failed to add juror') } } const handleRemoveJuror = async (userId: string) => { try { await removeJuror.mutateAsync({ awardId, userId }) refetchJurors() } catch { toast.error('Failed to remove juror') } } const handleSetWinner = async (projectId: string) => { try { await setWinner.mutateAsync({ awardId, projectId, overridden: true, }) toast.success('Winner set') refetch() } catch { toast.error('Failed to set winner') } } if (isLoading) { return (
) } if (!award) return null const jurorUserIds = new Set(jurors?.map((j) => j.userId) || []) const availableUsers = allUsers?.users.filter((u) => !jurorUserIds.has(u.id)) || [] return (
{/* Header */}

{award.name}

{award.status.replace('_', ' ')} {award.program.year} Edition
{award.status === 'DRAFT' && ( )} {award.status === 'NOMINATIONS_OPEN' && ( )} {award.status === 'VOTING_OPEN' && ( )}
{/* Description */} {award.description && (

{award.description}

)} {/* Tabs */} Eligibility ({award.eligibleCount}) Jurors ({award._count.jurors}) Results {/* Eligibility Tab */}

{award.eligibleCount} of {award._count.eligibilities} projects eligible

{award.useAiEligibility ? ( ) : ( )}
{!award.useAiEligibility && (

AI eligibility is off for this award. Projects are loaded for manual selection.

)} {eligibilityData && eligibilityData.eligibilities.length > 0 ? ( Project Category Country Eligible {eligibilityData.eligibilities.map((e) => (

{e.project.title}

{e.project.teamName}

{e.project.competitionCategory ? ( {e.project.competitionCategory.replace('_', ' ')} ) : ( '-' )} {e.project.country || '-'} handleToggleEligibility(e.projectId, checked) } />
))}
) : (

No eligibility data

Run AI eligibility to evaluate projects against criteria

)}
{/* Jurors Tab */}
{jurors && jurors.length > 0 ? ( Member Role Actions {jurors.map((j) => (

{j.user.name || 'Unnamed'}

{j.user.email}

{j.user.role.replace('_', ' ')}
))}
) : (

No jurors assigned

Add members as jurors for this award

)}
{/* Results Tab */} {voteResults && voteResults.results.length > 0 ? ( <>
{voteResults.votedJurorCount} of {voteResults.jurorCount}{' '} jurors voted {voteResults.scoringMode.replace('_', ' ')}
# Project Votes Points Actions {voteResults.results.map((r, i) => ( {i + 1}
{r.project.id === voteResults.winnerId && ( )}

{r.project.title}

{r.project.teamName}

{r.votes} {r.points} {r.project.id !== voteResults.winnerId && ( )}
))}
) : (

No votes yet

Votes will appear here once jurors submit their selections

)}
) }