Show award-routed projects in filtering stats and results table
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
- Stats cards show new 'Award Track' card with count of confirmed SEPARATE_POOL shortlisted projects - Passed card shows breakdown (main + award) when awards are routed - Results table shows award badge on projects routed to award tracks - getResults query includes confirmed award eligibility data per project Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -686,7 +686,7 @@ export function FilteringDashboard({ competitionId, roundId }: FilteringDashboar
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : stats && stats.total > 0 ? (
|
) : stats && stats.total > 0 ? (
|
||||||
<div className="grid gap-4 grid-cols-2 lg:grid-cols-5">
|
<div className="grid gap-4 grid-cols-2 lg:grid-cols-6">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<CardTitle className="text-sm font-medium">Total</CardTitle>
|
<CardTitle className="text-sm font-medium">Total</CardTitle>
|
||||||
@@ -706,6 +706,11 @@ export function FilteringDashboard({ competitionId, roundId }: FilteringDashboar
|
|||||||
<div className="text-2xl font-bold text-green-700">{stats.passed}</div>
|
<div className="text-2xl font-bold text-green-700">{stats.passed}</div>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
{stats.total > 0 ? `${((stats.passed / stats.total) * 100).toFixed(0)}%` : '0%'}
|
{stats.total > 0 ? `${((stats.passed / stats.total) * 100).toFixed(0)}%` : '0%'}
|
||||||
|
{stats.routedToAwards > 0 && (
|
||||||
|
<span className="block text-amber-600 mt-0.5">
|
||||||
|
{stats.passed - stats.routedToAwards} main + {stats.routedToAwards} award
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -741,6 +746,18 @@ export function FilteringDashboard({ competitionId, roundId }: FilteringDashboar
|
|||||||
<p className="text-xs text-muted-foreground">Manual changes</p>
|
<p className="text-xs text-muted-foreground">Manual changes</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
{stats.routedToAwards > 0 && (
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
|
<CardTitle className="text-sm font-medium">Award Track</CardTitle>
|
||||||
|
<Award className="h-4 w-4 text-amber-600" />
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold text-amber-700">{stats.routedToAwards}</div>
|
||||||
|
<p className="text-xs text-muted-foreground">Routed to awards</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
@@ -878,13 +895,21 @@ export function FilteringDashboard({ competitionId, roundId }: FilteringDashboar
|
|||||||
<ChevronDown className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
<ChevronDown className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
||||||
)}
|
)}
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
<Link
|
<Link
|
||||||
href={`/admin/projects/${result.projectId}` as Route}
|
href={`/admin/projects/${result.projectId}` as Route}
|
||||||
className="font-medium truncate block hover:underline text-foreground"
|
className="font-medium truncate hover:underline text-foreground"
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{result.project?.title || 'Unknown'}
|
{result.project?.title || 'Unknown'}
|
||||||
</Link>
|
</Link>
|
||||||
|
{result.project?.awardEligibilities?.length > 0 && (
|
||||||
|
<Badge variant="outline" className="text-[10px] px-1.5 py-0 bg-amber-50 text-amber-700 border-amber-200 shrink-0">
|
||||||
|
<Award className="h-2.5 w-2.5 mr-0.5" />
|
||||||
|
{result.project.awardEligibilities[0].award.name}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<p className="text-xs text-muted-foreground truncate">
|
<p className="text-xs text-muted-foreground truncate">
|
||||||
{result.project?.teamName}
|
{result.project?.teamName}
|
||||||
{result.project?.country && ` \u00b7 ${result.project.country}`}
|
{result.project?.country && ` \u00b7 ${result.project.country}`}
|
||||||
|
|||||||
@@ -877,6 +877,16 @@ export const filteringRouter = router({
|
|||||||
teamName: true,
|
teamName: true,
|
||||||
competitionCategory: true,
|
competitionCategory: true,
|
||||||
country: true,
|
country: true,
|
||||||
|
awardEligibilities: {
|
||||||
|
where: {
|
||||||
|
shortlisted: true,
|
||||||
|
confirmedAt: { not: null },
|
||||||
|
award: { eligibilityMode: 'SEPARATE_POOL' },
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
award: { select: { name: true } },
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
overriddenByUser: {
|
overriddenByUser: {
|
||||||
@@ -936,7 +946,27 @@ export const filteringRouter = router({
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
return { passed, filteredOut, flagged, overridden, total: passed + filteredOut + flagged }
|
// Count projects routed to SEPARATE_POOL award tracks (confirmed shortlist)
|
||||||
|
const round = await ctx.prisma.round.findUnique({
|
||||||
|
where: { id: input.roundId },
|
||||||
|
select: { competitionId: true },
|
||||||
|
})
|
||||||
|
|
||||||
|
let routedToAwards = 0
|
||||||
|
if (round?.competitionId) {
|
||||||
|
routedToAwards = await ctx.prisma.awardEligibility.count({
|
||||||
|
where: {
|
||||||
|
award: {
|
||||||
|
competitionId: round.competitionId,
|
||||||
|
eligibilityMode: 'SEPARATE_POOL',
|
||||||
|
},
|
||||||
|
shortlisted: true,
|
||||||
|
confirmedAt: { not: null },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { passed, filteredOut, flagged, overridden, routedToAwards, total: passed + filteredOut + flagged }
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user