fix: show project title, team & country in ranking rows instead of truncated IDs
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
Adds getProjectStates query to build a projectInfoMap lookup. Each row now shows the project title, team name, and country. Also renames "Pass" label to "Yes" to match the binary yes/no vote semantics. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -59,10 +59,17 @@ type RankingDashboardProps = {
|
||||
roundId: string
|
||||
}
|
||||
|
||||
type ProjectInfo = {
|
||||
title: string
|
||||
teamName: string | null
|
||||
country: string | null
|
||||
}
|
||||
|
||||
type SortableProjectRowProps = {
|
||||
projectId: string
|
||||
currentRank: number
|
||||
entry: RankedProjectEntry | undefined
|
||||
projectInfo: ProjectInfo | undefined
|
||||
onSelect: () => void
|
||||
isSelected: boolean
|
||||
}
|
||||
@@ -73,6 +80,7 @@ function SortableProjectRow({
|
||||
projectId,
|
||||
currentRank,
|
||||
entry,
|
||||
projectInfo,
|
||||
onSelect,
|
||||
isSelected,
|
||||
}: SortableProjectRowProps) {
|
||||
@@ -128,11 +136,17 @@ function SortableProjectRow({
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{/* Project identifier */}
|
||||
{/* Project info */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium truncate">
|
||||
Project …{projectId.slice(-6)}
|
||||
{projectInfo?.title ?? `Project …${projectId.slice(-6)}`}
|
||||
</p>
|
||||
{projectInfo?.teamName && (
|
||||
<p className="text-xs text-muted-foreground truncate">
|
||||
{projectInfo.teamName}
|
||||
{projectInfo.country ? ` · ${projectInfo.country}` : ''}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
@@ -147,8 +161,8 @@ function SortableProjectRow({
|
||||
Avg {entry.avgGlobalScore.toFixed(1)}
|
||||
</span>
|
||||
)}
|
||||
<span title="Pass rate">
|
||||
Pass {Math.round(entry.passRate * 100)}%
|
||||
<span title="Yes/No vote rate">
|
||||
Yes {Math.round(entry.passRate * 100)}%
|
||||
</span>
|
||||
<span title="Evaluator count">
|
||||
{entry.evaluatorCount} juror{entry.evaluatorCount !== 1 ? 's' : ''}
|
||||
@@ -197,6 +211,10 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
||||
{ enabled: !!latestSnapshotId },
|
||||
)
|
||||
|
||||
const { data: projectStates } = trpc.roundEngine.getProjectStates.useQuery(
|
||||
{ roundId },
|
||||
)
|
||||
|
||||
const { data: projectDetail, isLoading: detailLoading } = trpc.project.getFullDetail.useQuery(
|
||||
{ id: selectedProjectId! },
|
||||
{ enabled: !!selectedProjectId },
|
||||
@@ -253,6 +271,20 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
||||
return map
|
||||
}, [snapshot])
|
||||
|
||||
// ─── projectInfoMap (O(1) lookup by projectId) ────────────────────────────
|
||||
const projectInfoMap = useMemo(() => {
|
||||
const map = new Map<string, ProjectInfo>()
|
||||
if (!projectStates) return map
|
||||
for (const ps of projectStates) {
|
||||
map.set(ps.project.id, {
|
||||
title: ps.project.title,
|
||||
teamName: ps.project.teamName,
|
||||
country: ps.project.country,
|
||||
})
|
||||
}
|
||||
return map
|
||||
}, [projectStates])
|
||||
|
||||
// ─── localOrder init (once, with useRef guard) ────────────────────────────
|
||||
useEffect(() => {
|
||||
if (!initialized.current && snapshot) {
|
||||
@@ -448,6 +480,7 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
||||
projectId={projectId}
|
||||
currentRank={index + 1}
|
||||
entry={rankingMap.get(projectId)}
|
||||
projectInfo={projectInfoMap.get(projectId)}
|
||||
onSelect={() => setSelectedProjectId(projectId)}
|
||||
isSelected={selectedProjectId === projectId}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user