Comprehensive admin UI stats audit: fix 16 display bugs
HIGH fixes: - H1: Competition detail project count no longer double-counts across rounds - H2: Rounds page header stats use unfiltered round set - H3: Rounds page "eval" label corrected to "asgn" (assignment count) - H4: Observer reports project count uses distinct analytics count - H5: Awards eligibility count filters to only eligible=true (backend) - H6: Round detail projectCount derived from projectStates for consistency - H7: Deliberation hasVoted derived from votes array (was always undefined) MEDIUM fixes: - M1: Reports page round status badges use correct ROUND_ACTIVE/ROUND_CLOSED enums - M2: Observer reports badges use ROUND_ prefix instead of stale STAGE_ prefix - M3: Deliberation list status badges use correct VOTING/TALLYING/RUNOFF enums - M4: Competition list/detail round count excludes special-award rounds (backend) - M5: Messages page shows actual recipient count instead of hardcoded "1 user" LOW fixes: - L2: Observer analytics jurorCount scoped to round when roundId provided - L3: Analytics round-scoped project count uses ProjectRoundState not assignments - L4: JuryGroup delete audit log reports member count (not assignment count) - L5: Project rankings include unevaluated projects at bottom instead of hiding Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -100,7 +100,8 @@ function OverviewTab({ selectedValue }: { selectedValue: string | null }) {
|
||||
)
|
||||
}
|
||||
|
||||
const totalProjects = stages.reduce((acc, s) => acc + (s._count?.projects || 0), 0)
|
||||
// Count distinct projects by collecting unique IDs, not summing per-round states
|
||||
const totalProjects = overviewStats?.projectCount ?? stages.reduce((acc, s) => acc + (s._count?.projects || 0), 0)
|
||||
const activeStages = stages.filter((s) => s.status === 'ROUND_ACTIVE').length
|
||||
const totalPrograms = programs?.length || 0
|
||||
|
||||
@@ -285,14 +286,14 @@ function OverviewTab({ selectedValue }: { selectedValue: string | null }) {
|
||||
<TableCell>
|
||||
<Badge
|
||||
variant={
|
||||
stage.status === 'STAGE_ACTIVE'
|
||||
stage.status === 'ROUND_ACTIVE'
|
||||
? 'default'
|
||||
: stage.status === 'STAGE_CLOSED'
|
||||
: stage.status === 'ROUND_CLOSED'
|
||||
? 'secondary'
|
||||
: 'outline'
|
||||
}
|
||||
>
|
||||
{stage.status === 'STAGE_ACTIVE' ? 'Active' : stage.status === 'STAGE_CLOSED' ? 'Closed' : stage.status}
|
||||
{stage.status === 'ROUND_ACTIVE' ? 'Active' : stage.status === 'ROUND_CLOSED' ? 'Closed' : stage.status}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -312,14 +313,14 @@ function OverviewTab({ selectedValue }: { selectedValue: string | null }) {
|
||||
<p className="font-medium">{stage.name}</p>
|
||||
<Badge
|
||||
variant={
|
||||
stage.status === 'STAGE_ACTIVE'
|
||||
stage.status === 'ROUND_ACTIVE'
|
||||
? 'default'
|
||||
: stage.status === 'STAGE_CLOSED'
|
||||
: stage.status === 'ROUND_CLOSED'
|
||||
? 'secondary'
|
||||
: 'outline'
|
||||
}
|
||||
>
|
||||
{stage.status === 'STAGE_ACTIVE' ? 'Active' : stage.status === 'STAGE_CLOSED' ? 'Closed' : stage.status}
|
||||
{stage.status === 'ROUND_ACTIVE' ? 'Active' : stage.status === 'ROUND_CLOSED' ? 'Closed' : stage.status}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">{stage.programName}</p>
|
||||
|
||||
Reference in New Issue
Block a user