diff --git a/src/components/admin/round/ranking-dashboard.tsx b/src/components/admin/round/ranking-dashboard.tsx index f379afa..2528bab 100644 --- a/src/components/admin/round/ranking-dashboard.tsx +++ b/src/components/admin/round/ranking-dashboard.tsx @@ -169,10 +169,11 @@ function SortableProjectRow({

{projectInfo?.title ?? `Project …${projectId.slice(-6)}`}

- {projectInfo?.teamName && ( + {(projectInfo?.teamName || projectInfo?.country) && (

{projectInfo.teamName} - {projectInfo.country ? <> · : ''} + {projectInfo.teamName && projectInfo.country ? ' · ' : ''} + {projectInfo.country && }

)} @@ -1153,12 +1154,12 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
{a.user?.name ?? a.user?.email ?? 'Unknown'}
- {a.evaluation?.binaryDecision != null && ( + {a.evaluation?.decision != null && ( - {a.evaluation.binaryDecision ? 'Yes' : 'No'} + {a.evaluation.decision ? 'Yes' : 'No'} )} Score: {a.evaluation?.globalScore?.toFixed(1) ?? '—'} diff --git a/src/server/routers/project.ts b/src/server/routers/project.ts index a8c2339..7e48465 100644 --- a/src/server/routers/project.ts +++ b/src/server/routers/project.ts @@ -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() + 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 let stats = null if (submittedEvaluations.length > 0) { @@ -1355,13 +1376,30 @@ export const projectRouter = router({ })) ), Promise.all( - assignments.map(async (a) => ({ - ...a, - user: { - ...a.user, - avatarUrl: await getUserAvatarUrl(a.user.profileImageKey, a.user.profileImageProvider), - }, - })) + assignments.map(async (a) => { + // Resolve decision: column first, criterion fallback second. + let decision: boolean | null = a.evaluation?.binaryDecision ?? null + if (decision == null && a.evaluation) { + const advCritId = advanceCriterionByRound.get(a.round.id) ?? null + if (advCritId) { + const scores = a.evaluation.criterionScoresJson as Record | 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 ? (async () => ({