Admin dashboard & round management UX overhaul
All checks were successful
Build and Push Docker Image / build (push) Successful in 8m43s

- Extract round detail monolith (2900→600 lines) into 13 standalone components
- Add shared round/status config (round-config.ts) replacing 4 local copies
- Delete 12 legacy competition-scoped pages, merge project pool into projects page
- Add round-type-specific dashboard stat panels (submission, mentoring, live final, deliberation, summary)
- Add contextual header quick actions based on active round type
- Improve pipeline visualization: progress bars, checkmarks, chevron connectors, overflow fix
- Add config tab completion dots (green/amber/red) and inline validation warnings
- Enhance juries page with round assignments, member avatars, and cap mode badges
- Add context-aware project list (recent submissions vs active evaluations)
- Move competition settings into Manage Editions page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-22 17:14:00 +01:00
parent f7bc3b4dd2
commit f26ee3f076
51 changed files with 4530 additions and 6276 deletions

View File

@@ -109,6 +109,8 @@ export const dashboardRouter = router({
categoryBreakdown,
oceanIssueBreakdown,
recentActivity,
// Recently active
recentlyActiveEvals,
// Action signals
pendingCOIs,
] = await Promise.all([
@@ -257,7 +259,43 @@ export const dashboardRouter = router({
},
}),
// 17. Pending COIs
// 17. Recently active projects (with recent evaluations)
ctx.prisma.evaluation.findMany({
where: {
status: 'SUBMITTED',
assignment: {
round: { competition: { programId: editionId } },
},
},
orderBy: { submittedAt: 'desc' },
take: 8,
select: {
id: true,
globalScore: true,
submittedAt: true,
assignment: {
select: {
user: { select: { name: true } },
project: {
select: {
id: true,
title: true,
teamName: true,
country: true,
competitionCategory: true,
oceanIssue: true,
logoKey: true,
createdAt: true,
submittedAt: true,
status: true,
},
},
},
},
},
}),
// 18. Pending COIs
ctx.prisma.conflictOfInterest.count({
where: {
hasConflict: true,
@@ -443,6 +481,22 @@ export const dashboardRouter = router({
// ── Return ──────────────────────────────────────────────────────
// Deduplicate recently active projects (same project may have multiple evals)
const seenProjectIds = new Set<string>()
const recentlyActiveProjects = recentlyActiveEvals
.filter((e) => {
const pid = e.assignment.project.id
if (seenProjectIds.has(pid)) return false
seenProjectIds.add(pid)
return true
})
.map((e) => ({
...e.assignment.project,
latestEvaluator: e.assignment.user.name,
latestScore: e.globalScore,
evaluatedAt: e.submittedAt,
}))
return {
edition,
// Pipeline
@@ -460,6 +514,7 @@ export const dashboardRouter = router({
pendingCOIs,
// Lists
latestProjects,
recentlyActiveProjects,
categoryBreakdown,
oceanIssueBreakdown,
recentActivity,