fix: resolve advance decision and surface country on rankings list
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m35s
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m35s
The side panel only read Evaluation.binaryDecision, which is null when the round's evaluation form stores the 'proceed to next round' answer as a boolean criterion in criterionScoresJson (the current round's shape). project.getFullDetail now resolves a unified `decision` field per assignment using the same fallback pattern as the ranking router: prefer the column, fall back to a type='advance' (or legacy 'move to the next stage' boolean) criterion looked up by id in the active form. Also: project country in the rankings list now renders whenever it's present, not only when teamName is also set. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -169,10 +169,11 @@ function SortableProjectRow({
|
|||||||
<p className="text-sm font-medium truncate">
|
<p className="text-sm font-medium truncate">
|
||||||
{projectInfo?.title ?? `Project …${projectId.slice(-6)}`}
|
{projectInfo?.title ?? `Project …${projectId.slice(-6)}`}
|
||||||
</p>
|
</p>
|
||||||
{projectInfo?.teamName && (
|
{(projectInfo?.teamName || projectInfo?.country) && (
|
||||||
<p className="text-xs text-muted-foreground truncate">
|
<p className="text-xs text-muted-foreground truncate">
|
||||||
{projectInfo.teamName}
|
{projectInfo.teamName}
|
||||||
{projectInfo.country ? <> · <CountryDisplay country={projectInfo.country} /></> : ''}
|
{projectInfo.teamName && projectInfo.country ? ' · ' : ''}
|
||||||
|
{projectInfo.country && <CountryDisplay country={projectInfo.country} />}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1153,12 +1154,12 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<span className="font-medium text-sm">{a.user?.name ?? a.user?.email ?? 'Unknown'}</span>
|
<span className="font-medium text-sm">{a.user?.name ?? a.user?.email ?? 'Unknown'}</span>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{a.evaluation?.binaryDecision != null && (
|
{a.evaluation?.decision != null && (
|
||||||
<Badge
|
<Badge
|
||||||
variant={a.evaluation.binaryDecision ? 'default' : 'destructive'}
|
variant={a.evaluation.decision ? 'default' : 'destructive'}
|
||||||
className={a.evaluation.binaryDecision ? 'bg-emerald-100 text-emerald-700 hover:bg-emerald-100' : ''}
|
className={a.evaluation.decision ? 'bg-emerald-100 text-emerald-700 hover:bg-emerald-100' : ''}
|
||||||
>
|
>
|
||||||
{a.evaluation.binaryDecision ? 'Yes' : 'No'}
|
{a.evaluation.decision ? 'Yes' : 'No'}
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
<Badge variant="outline">Score: {a.evaluation?.globalScore?.toFixed(1) ?? '—'}</Badge>
|
<Badge variant="outline">Score: {a.evaluation?.globalScore?.toFixed(1) ?? '—'}</Badge>
|
||||||
|
|||||||
@@ -1305,6 +1305,27 @@ export const projectRouter = router({
|
|||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// Resolve the boolean "advance to next round" criterion id for each round
|
||||||
|
// so we can fall back to criterionScoresJson when binaryDecision is null.
|
||||||
|
// Mirrors ranking.ts logic: prefer type='advance', else legacy boolean
|
||||||
|
// criterion labeled "move to the next stage".
|
||||||
|
const roundIdsInUse = Array.from(new Set(assignments.map((a) => a.round.id)))
|
||||||
|
const advanceCriterionByRound = new Map<string, string | null>()
|
||||||
|
if (roundIdsInUse.length > 0) {
|
||||||
|
const forms = await ctx.prisma.evaluationForm.findMany({
|
||||||
|
where: { roundId: { in: roundIdsInUse }, isActive: true },
|
||||||
|
select: { roundId: true, criteriaJson: true },
|
||||||
|
})
|
||||||
|
for (const form of forms) {
|
||||||
|
if (advanceCriterionByRound.has(form.roundId)) continue
|
||||||
|
const criteria = (form.criteriaJson as Array<{ id: string; type?: string; label?: string }> | null) ?? []
|
||||||
|
const found =
|
||||||
|
criteria.find((c) => c.type === 'advance') ??
|
||||||
|
criteria.find((c) => c.type === 'boolean' && c.label?.toLowerCase().includes('move to the next stage'))
|
||||||
|
advanceCriterionByRound.set(form.roundId, found?.id ?? null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compute evaluation stats
|
// Compute evaluation stats
|
||||||
let stats = null
|
let stats = null
|
||||||
if (submittedEvaluations.length > 0) {
|
if (submittedEvaluations.length > 0) {
|
||||||
@@ -1355,13 +1376,30 @@ export const projectRouter = router({
|
|||||||
}))
|
}))
|
||||||
),
|
),
|
||||||
Promise.all(
|
Promise.all(
|
||||||
assignments.map(async (a) => ({
|
assignments.map(async (a) => {
|
||||||
...a,
|
// Resolve decision: column first, criterion fallback second.
|
||||||
user: {
|
let decision: boolean | null = a.evaluation?.binaryDecision ?? null
|
||||||
...a.user,
|
if (decision == null && a.evaluation) {
|
||||||
avatarUrl: await getUserAvatarUrl(a.user.profileImageKey, a.user.profileImageProvider),
|
const advCritId = advanceCriterionByRound.get(a.round.id) ?? null
|
||||||
},
|
if (advCritId) {
|
||||||
}))
|
const scores = a.evaluation.criterionScoresJson as Record<string, unknown> | null
|
||||||
|
if (scores) {
|
||||||
|
const val = scores[advCritId]
|
||||||
|
if (typeof val === 'boolean') decision = val
|
||||||
|
else if (val === 'true') decision = true
|
||||||
|
else if (val === 'false') decision = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...a,
|
||||||
|
user: {
|
||||||
|
...a.user,
|
||||||
|
avatarUrl: await getUserAvatarUrl(a.user.profileImageKey, a.user.profileImageProvider),
|
||||||
|
},
|
||||||
|
evaluation: a.evaluation ? { ...a.evaluation, decision } : null,
|
||||||
|
}
|
||||||
|
})
|
||||||
),
|
),
|
||||||
projectRaw.mentorAssignment
|
projectRaw.mentorAssignment
|
||||||
? (async () => ({
|
? (async () => ({
|
||||||
|
|||||||
Reference in New Issue
Block a user