'use client' import { use, useState } from 'react' import { useRouter } from 'next/navigation' 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 { toast } from 'sonner' import { ArrowLeft, Trophy, CheckCircle2, Loader2, GripVertical, } from 'lucide-react' import { cn } from '@/lib/utils' import { CountryDisplay } from '@/components/shared/country-display' export default function JuryAwardVotingPage({ params, }: { params: Promise<{ id: string }> }) { const { id: awardId } = use(params) const router = useRouter() const utils = trpc.useUtils() const { data, isLoading, refetch } = trpc.specialAward.getMyAwardDetail.useQuery({ awardId }) const submitVote = trpc.specialAward.submitVote.useMutation({ onSuccess: () => { utils.specialAward.getMyAwardDetail.invalidate({ awardId }) }, }) const [selectedProjectId, setSelectedProjectId] = useState( null ) const [rankedIds, setRankedIds] = useState([]) // Initialize from existing votes if (data && !selectedProjectId && !rankedIds.length && data.myVotes.length > 0) { if (data.award.scoringMode === 'PICK_WINNER') { setSelectedProjectId(data.myVotes[0]?.projectId || null) } else if (data.award.scoringMode === 'RANKED') { const sorted = [...data.myVotes] .sort((a, b) => (a.rank || 0) - (b.rank || 0)) .map((v) => v.projectId) setRankedIds(sorted) } } const handleSubmitPickWinner = async () => { if (!selectedProjectId) return try { await submitVote.mutateAsync({ awardId, votes: [{ projectId: selectedProjectId }], }) toast.success('Vote submitted') refetch() } catch (error) { toast.error( error instanceof Error ? error.message : 'Failed to submit vote' ) } } const handleSubmitRanked = async () => { if (rankedIds.length === 0) return try { await submitVote.mutateAsync({ awardId, votes: rankedIds.map((projectId, index) => ({ projectId, rank: index + 1, })), }) toast.success('Rankings submitted') refetch() } catch (error) { toast.error( error instanceof Error ? error.message : 'Failed to submit rankings' ) } } const toggleRanked = (projectId: string) => { if (rankedIds.includes(projectId)) { setRankedIds(rankedIds.filter((id) => id !== projectId)) } else { const maxPicks = data?.award.maxRankedPicks || 5 if (rankedIds.length < maxPicks) { setRankedIds([...rankedIds, projectId]) } } } if (isLoading) { return (
) } if (!data) return null const { award, projects, myVotes } = data const hasVoted = myVotes.length > 0 const isVotingOpen = award.status === 'VOTING_OPEN' return (

{award.name}

{award.status.replace('_', ' ')} {hasVoted && ( Voted )}
{award.criteriaText && (

{award.criteriaText}

)}
{!isVotingOpen ? (

Voting is not open

Check back when voting opens for this award

) : award.scoringMode === 'PICK_WINNER' ? ( /* PICK_WINNER Mode */

Select one project as the winner

{projects.map((project) => ( setSelectedProjectId(project.id)} > {project.title} {project.teamName}
{project.competitionCategory && ( {project.competitionCategory.replace('_', ' ')} )} {project.country && ( )}
))}
) : award.scoringMode === 'RANKED' ? ( /* RANKED Mode */

Select and rank your top {award.maxRankedPicks || 5} projects. Click to add/remove, drag to reorder.

{/* Selected rankings */} {rankedIds.length > 0 && ( Your Rankings {rankedIds.map((id, index) => { const project = projects.find((p) => p.id === id) if (!project) return null return (
{index + 1}

{project.title}

{project.teamName}

) })}
)} {/* Available projects */}
{projects .filter((p) => !rankedIds.includes(p.id)) .map((project) => ( toggleRanked(project.id)} > {project.title} {project.teamName}
{project.competitionCategory && ( {project.competitionCategory.replace('_', ' ')} )} {project.country && ( )}
))}
) : ( /* SCORED Mode — redirect to evaluation */

Scored Award

This award uses the evaluation system. Check your evaluation assignments.

)}
) }