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
|
roundId: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProjectInfo = {
|
||||||
|
title: string
|
||||||
|
teamName: string | null
|
||||||
|
country: string | null
|
||||||
|
}
|
||||||
|
|
||||||
type SortableProjectRowProps = {
|
type SortableProjectRowProps = {
|
||||||
projectId: string
|
projectId: string
|
||||||
currentRank: number
|
currentRank: number
|
||||||
entry: RankedProjectEntry | undefined
|
entry: RankedProjectEntry | undefined
|
||||||
|
projectInfo: ProjectInfo | undefined
|
||||||
onSelect: () => void
|
onSelect: () => void
|
||||||
isSelected: boolean
|
isSelected: boolean
|
||||||
}
|
}
|
||||||
@@ -73,6 +80,7 @@ function SortableProjectRow({
|
|||||||
projectId,
|
projectId,
|
||||||
currentRank,
|
currentRank,
|
||||||
entry,
|
entry,
|
||||||
|
projectInfo,
|
||||||
onSelect,
|
onSelect,
|
||||||
isSelected,
|
isSelected,
|
||||||
}: SortableProjectRowProps) {
|
}: SortableProjectRowProps) {
|
||||||
@@ -128,11 +136,17 @@ function SortableProjectRow({
|
|||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Project identifier */}
|
{/* Project info */}
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<p className="text-sm font-medium truncate">
|
<p className="text-sm font-medium truncate">
|
||||||
Project …{projectId.slice(-6)}
|
{projectInfo?.title ?? `Project …${projectId.slice(-6)}`}
|
||||||
</p>
|
</p>
|
||||||
|
{projectInfo?.teamName && (
|
||||||
|
<p className="text-xs text-muted-foreground truncate">
|
||||||
|
{projectInfo.teamName}
|
||||||
|
{projectInfo.country ? ` · ${projectInfo.country}` : ''}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Stats */}
|
{/* Stats */}
|
||||||
@@ -147,8 +161,8 @@ function SortableProjectRow({
|
|||||||
Avg {entry.avgGlobalScore.toFixed(1)}
|
Avg {entry.avgGlobalScore.toFixed(1)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<span title="Pass rate">
|
<span title="Yes/No vote rate">
|
||||||
Pass {Math.round(entry.passRate * 100)}%
|
Yes {Math.round(entry.passRate * 100)}%
|
||||||
</span>
|
</span>
|
||||||
<span title="Evaluator count">
|
<span title="Evaluator count">
|
||||||
{entry.evaluatorCount} juror{entry.evaluatorCount !== 1 ? 's' : ''}
|
{entry.evaluatorCount} juror{entry.evaluatorCount !== 1 ? 's' : ''}
|
||||||
@@ -197,6 +211,10 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
|||||||
{ enabled: !!latestSnapshotId },
|
{ enabled: !!latestSnapshotId },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const { data: projectStates } = trpc.roundEngine.getProjectStates.useQuery(
|
||||||
|
{ roundId },
|
||||||
|
)
|
||||||
|
|
||||||
const { data: projectDetail, isLoading: detailLoading } = trpc.project.getFullDetail.useQuery(
|
const { data: projectDetail, isLoading: detailLoading } = trpc.project.getFullDetail.useQuery(
|
||||||
{ id: selectedProjectId! },
|
{ id: selectedProjectId! },
|
||||||
{ enabled: !!selectedProjectId },
|
{ enabled: !!selectedProjectId },
|
||||||
@@ -253,6 +271,20 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
|||||||
return map
|
return map
|
||||||
}, [snapshot])
|
}, [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) ────────────────────────────
|
// ─── localOrder init (once, with useRef guard) ────────────────────────────
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!initialized.current && snapshot) {
|
if (!initialized.current && snapshot) {
|
||||||
@@ -448,6 +480,7 @@ export function RankingDashboard({ competitionId: _competitionId, roundId }: Ran
|
|||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
currentRank={index + 1}
|
currentRank={index + 1}
|
||||||
entry={rankingMap.get(projectId)}
|
entry={rankingMap.get(projectId)}
|
||||||
|
projectInfo={projectInfoMap.get(projectId)}
|
||||||
onSelect={() => setSelectedProjectId(projectId)}
|
onSelect={() => setSelectedProjectId(projectId)}
|
||||||
isSelected={selectedProjectId === projectId}
|
isSelected={selectedProjectId === projectId}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user