feat: show vote status on jury dashboard and add logos to award-master
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m47s
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m47s
- Jury dashboard now shows "Submitted" badge (green) with "Edit Rankings" button when juror has already voted, instead of always showing "Vote Now" — prevents confusion about whether vote saved - Award-master page now shows project logos next to project names - Backend getMyAwardDetailEnhanced now returns logo URLs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
import { cn } from '@/lib/utils'
|
||||
import { CountryDisplay } from '@/components/shared/country-display'
|
||||
import { ProjectFilesSection } from '@/components/jury/project-files-section'
|
||||
import { ProjectLogo } from '@/components/shared/project-logo'
|
||||
|
||||
export default function AwardMasterVotingPage({
|
||||
params,
|
||||
@@ -254,7 +255,8 @@ export default function AwardMasterVotingPage({
|
||||
onClick={() => handleProjectClick(project.id)}
|
||||
>
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-start gap-3">
|
||||
<ProjectLogo project={project} logoUrl={project.logoUrl} size="sm" fallback="initials" className="mt-0.5" />
|
||||
<div className="flex-1 min-w-0">
|
||||
<CardTitle className="text-base">
|
||||
{project.title}
|
||||
|
||||
@@ -132,6 +132,17 @@ async function JuryDashboardContent() {
|
||||
|
||||
const juryCompareEnabled = compareFlag?.value === 'true'
|
||||
|
||||
// Check which awards the user has already voted on
|
||||
const awardIds = myAwardJurorRecords.map((r) => r.award.id)
|
||||
const myAwardVotes = awardIds.length > 0
|
||||
? await prisma.awardVote.groupBy({
|
||||
by: ['awardId'],
|
||||
where: { userId, awardId: { in: awardIds } },
|
||||
_count: { id: true },
|
||||
})
|
||||
: []
|
||||
const votedAwardIds = new Set(myAwardVotes.filter((v) => v._count.id > 0).map((v) => v.awardId))
|
||||
|
||||
// Awards where voting is open
|
||||
const activeAwards = myAwardJurorRecords.filter(
|
||||
(r) => r.award.status === 'VOTING_OPEN'
|
||||
@@ -314,35 +325,50 @@ async function JuryDashboardContent() {
|
||||
const award = record.award
|
||||
const deadline = award.votingEndAt ? new Date(award.votingEndAt) : null
|
||||
const isUrgent = deadline && (deadline.getTime() - now.getTime()) < 24 * 60 * 60 * 1000
|
||||
const hasVoted = votedAwardIds.has(award.id)
|
||||
|
||||
return (
|
||||
<div
|
||||
key={award.id}
|
||||
className={cn(
|
||||
'rounded-xl border p-4 space-y-3 transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md',
|
||||
isUrgent
|
||||
? 'border-red-200 bg-red-50/50 dark:border-red-900 dark:bg-red-950/20'
|
||||
: 'border-amber-200/60 bg-amber-50/30 dark:border-amber-800/40 dark:bg-amber-950/10'
|
||||
hasVoted
|
||||
? 'border-green-200/60 bg-green-50/30 dark:border-green-800/40 dark:bg-green-950/10'
|
||||
: isUrgent
|
||||
? 'border-red-200 bg-red-50/50 dark:border-red-900 dark:bg-red-950/20'
|
||||
: 'border-amber-200/60 bg-amber-50/30 dark:border-amber-800/40 dark:bg-amber-950/10'
|
||||
)}
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<h3 className="font-semibold text-amber-700 dark:text-amber-400">{award.name}</h3>
|
||||
<h3 className={cn('font-semibold', hasVoted ? 'text-green-700 dark:text-green-400' : 'text-amber-700 dark:text-amber-400')}>{award.name}</h3>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">
|
||||
{award._count.eligibilities} project{award._count.eligibilities !== 1 ? 's' : ''} to review
|
||||
{record.isChair && ' · You are the Chair'}
|
||||
</p>
|
||||
</div>
|
||||
<Badge className="bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-950 dark:text-amber-300 dark:border-amber-700">
|
||||
Vote Now
|
||||
</Badge>
|
||||
{hasVoted ? (
|
||||
<Badge className="bg-green-100 text-green-800 border-green-300 dark:bg-green-950 dark:text-green-300 dark:border-green-700">
|
||||
<CheckCircle2 className="mr-1 h-3 w-3" />
|
||||
Submitted
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge className="bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-950 dark:text-amber-300 dark:border-amber-700">
|
||||
Vote Now
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
{deadline && (
|
||||
<CountdownTimer deadline={deadline} label="Voting closes:" />
|
||||
)}
|
||||
<Button asChild size="sm" className="w-full bg-amber-600 hover:bg-amber-700 text-white shadow-sm">
|
||||
<Button asChild size="sm" className={cn(
|
||||
'w-full shadow-sm',
|
||||
hasVoted
|
||||
? 'bg-green-600 hover:bg-green-700 text-white'
|
||||
: 'bg-amber-600 hover:bg-amber-700 text-white'
|
||||
)}>
|
||||
<Link href={`/jury/awards/${award.id}`}>
|
||||
Review & Vote
|
||||
{hasVoted ? 'Edit Rankings' : 'Review & Vote'}
|
||||
<ArrowRight className="ml-2 h-4 w-4" />
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user