150 lines
4.6 KiB
TypeScript
150 lines
4.6 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { use } from 'react';
|
||
|
|
import { trpc } from '@/lib/trpc/client';
|
||
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||
|
|
import { Badge } from '@/components/ui/badge';
|
||
|
|
import { DeliberationRankingForm } from '@/components/jury/deliberation-ranking-form';
|
||
|
|
import { CheckCircle2 } from 'lucide-react';
|
||
|
|
import { toast } from 'sonner';
|
||
|
|
|
||
|
|
export default function JuryDeliberationPage({ params: paramsPromise }: { params: Promise<{ sessionId: string }> }) {
|
||
|
|
const params = use(paramsPromise);
|
||
|
|
const utils = trpc.useUtils();
|
||
|
|
|
||
|
|
const { data: session, isLoading } = trpc.deliberation.getSession.useQuery({
|
||
|
|
sessionId: params.sessionId
|
||
|
|
});
|
||
|
|
|
||
|
|
const submitVoteMutation = trpc.deliberation.submitVote.useMutation({
|
||
|
|
onSuccess: () => {
|
||
|
|
utils.deliberation.getSession.invalidate();
|
||
|
|
toast.success('Vote submitted successfully');
|
||
|
|
},
|
||
|
|
onError: (err) => {
|
||
|
|
toast.error(err.message);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
const handleSubmitVote = (votes: Array<{ projectId: string; rank?: number; isWinnerPick?: boolean }>) => {
|
||
|
|
votes.forEach((vote) => {
|
||
|
|
submitVoteMutation.mutate({
|
||
|
|
sessionId: params.sessionId,
|
||
|
|
juryMemberId: session?.currentUser?.id || '',
|
||
|
|
projectId: vote.projectId,
|
||
|
|
rank: vote.rank,
|
||
|
|
isWinnerPick: vote.isWinnerPick
|
||
|
|
});
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
if (isLoading) {
|
||
|
|
return (
|
||
|
|
<div className="space-y-6">
|
||
|
|
<Card>
|
||
|
|
<CardContent className="flex items-center justify-center py-12">
|
||
|
|
<p className="text-muted-foreground">Loading session...</p>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!session) {
|
||
|
|
return (
|
||
|
|
<div className="space-y-6">
|
||
|
|
<Card>
|
||
|
|
<CardContent className="flex items-center justify-center py-12">
|
||
|
|
<p className="text-muted-foreground">Session not found</p>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const hasVoted = session.currentUser?.hasVoted;
|
||
|
|
|
||
|
|
if (session.status !== 'DELIB_VOTING') {
|
||
|
|
return (
|
||
|
|
<div className="space-y-6">
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<CardTitle>Deliberation Session</CardTitle>
|
||
|
|
<CardDescription>
|
||
|
|
{session.round?.name} - {session.category}
|
||
|
|
</CardDescription>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent className="flex flex-col items-center justify-center py-12">
|
||
|
|
<p className="text-muted-foreground">
|
||
|
|
{session.status === 'DELIB_OPEN'
|
||
|
|
? 'Voting has not started yet. Please wait for the admin to open voting.'
|
||
|
|
: session.status === 'DELIB_TALLYING'
|
||
|
|
? 'Voting is closed. Results are being tallied.'
|
||
|
|
: 'This session is locked.'}
|
||
|
|
</p>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (hasVoted) {
|
||
|
|
return (
|
||
|
|
<div className="space-y-6">
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<div className="flex items-start justify-between">
|
||
|
|
<div>
|
||
|
|
<CardTitle>Deliberation Session</CardTitle>
|
||
|
|
<CardDescription className="mt-1">
|
||
|
|
{session.round?.name} - {session.category}
|
||
|
|
</CardDescription>
|
||
|
|
</div>
|
||
|
|
<Badge>{session.status}</Badge>
|
||
|
|
</div>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent className="flex flex-col items-center justify-center py-12">
|
||
|
|
<CheckCircle2 className="mb-4 h-12 w-12 text-green-600" />
|
||
|
|
<p className="font-medium">Vote Submitted</p>
|
||
|
|
<p className="mt-1 text-sm text-muted-foreground">
|
||
|
|
Thank you for your participation in this deliberation
|
||
|
|
</p>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="space-y-6">
|
||
|
|
<Card>
|
||
|
|
<CardHeader>
|
||
|
|
<div className="flex items-start justify-between">
|
||
|
|
<div>
|
||
|
|
<CardTitle>Deliberation Session</CardTitle>
|
||
|
|
<CardDescription className="mt-1">
|
||
|
|
{session.round?.name} - {session.category}
|
||
|
|
</CardDescription>
|
||
|
|
</div>
|
||
|
|
<Badge>{session.status}</Badge>
|
||
|
|
</div>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent>
|
||
|
|
<p className="text-muted-foreground">
|
||
|
|
{session.mode === 'SINGLE_WINNER_VOTE'
|
||
|
|
? 'Select your top choice for this category.'
|
||
|
|
: 'Rank all projects from best to least preferred.'}
|
||
|
|
</p>
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
|
||
|
|
<DeliberationRankingForm
|
||
|
|
projects={session.projects || []}
|
||
|
|
mode={session.mode}
|
||
|
|
onSubmit={handleSubmitVote}
|
||
|
|
disabled={submitVoteMutation.isPending}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|