All checks were successful
Build and Push Docker Image / build (push) Successful in 12m29s
Phase 1: Fix 6 backend data bugs in analytics.ts (roundName filtering, unscored projects, criteria scores, activeRoundCount scoping, email privacy leaks in juror consistency + workload) Phase 2-3: Migrate all 9 chart components from Recharts to Nivo (@nivo/bar, @nivo/line, @nivo/pie, @nivo/scatterplot) with shared brand theme, scoreGradient colors, and STATUS_COLORS map. Fixes scatter plot outlier coloring and pie chart label visibility bugs. Phase 4: Add round-type-aware stats (getRoundTypeStats backend + RoundTypeStatsCards component) showing appropriate metrics per round type (intake/filtering/evaluation/submission/mentoring/live/deliberation). Phase 5: UX improvements — Stage→Round terminology, clickable dashboard round links, URL-based round selection (?round=), round type indicators in selectors, accessible Toggle-based cross-round comparison, sortable project table columns (title/score/evaluations), brand score colors on dashboard bar chart with aria labels. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
'use client'
|
|
|
|
import { ResponsiveBar } from '@nivo/bar'
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
import { nivoTheme, scoreGradient } from './chart-theme'
|
|
|
|
interface ScoreDistributionProps {
|
|
data: { score: number; count: number }[]
|
|
averageScore: number
|
|
totalScores: number
|
|
}
|
|
|
|
export function ScoreDistributionChart({
|
|
data,
|
|
averageScore,
|
|
totalScores,
|
|
}: ScoreDistributionProps) {
|
|
const chartData = data.map((d) => ({
|
|
score: String(d.score),
|
|
count: d.count,
|
|
}))
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="flex items-center justify-between">
|
|
<span>Score Distribution</span>
|
|
<span className="text-sm font-normal text-muted-foreground">
|
|
Avg: {averageScore.toFixed(2)} ({totalScores} scores)
|
|
</span>
|
|
</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div style={{ height: '300px' }}>
|
|
<ResponsiveBar
|
|
data={chartData}
|
|
keys={['count']}
|
|
indexBy="score"
|
|
theme={nivoTheme}
|
|
colors={(bar) => scoreGradient(Number(bar.indexValue))}
|
|
borderRadius={4}
|
|
enableLabel={true}
|
|
labelSkipHeight={12}
|
|
labelTextColor="#ffffff"
|
|
axisBottom={{
|
|
legend: 'Score',
|
|
legendPosition: 'middle',
|
|
legendOffset: 36,
|
|
}}
|
|
axisLeft={{
|
|
legend: 'Count',
|
|
legendPosition: 'middle',
|
|
legendOffset: -40,
|
|
}}
|
|
margin={{ top: 20, right: 20, bottom: 50, left: 50 }}
|
|
padding={0.2}
|
|
animate={true}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)
|
|
}
|