2026-01-30 13:41:32 +01:00
|
|
|
'use client'
|
|
|
|
|
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
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>
2026-02-19 21:44:38 +01:00
|
|
|
import { ResponsiveLine } from '@nivo/line'
|
2026-01-30 13:41:32 +01:00
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
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>
2026-02-19 21:44:38 +01:00
|
|
|
import { nivoTheme, BRAND_DARK_BLUE } from './chart-theme'
|
2026-01-30 13:41:32 +01:00
|
|
|
|
|
|
|
|
interface TimelineDataPoint {
|
|
|
|
|
date: string
|
|
|
|
|
daily: number
|
|
|
|
|
cumulative: number
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface EvaluationTimelineProps {
|
|
|
|
|
data: TimelineDataPoint[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function EvaluationTimelineChart({ data }: EvaluationTimelineProps) {
|
2026-02-20 13:42:31 +01:00
|
|
|
if (!data?.length) return null
|
|
|
|
|
|
2026-01-30 13:41:32 +01:00
|
|
|
const formattedData = data.map((d) => ({
|
|
|
|
|
...d,
|
|
|
|
|
dateFormatted: new Date(d.date).toLocaleDateString('en-US', {
|
|
|
|
|
month: 'short',
|
|
|
|
|
day: 'numeric',
|
|
|
|
|
}),
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
const totalEvaluations =
|
|
|
|
|
data.length > 0 ? data[data.length - 1].cumulative : 0
|
|
|
|
|
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
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>
2026-02-19 21:44:38 +01:00
|
|
|
const lineData = [
|
|
|
|
|
{
|
|
|
|
|
id: 'Cumulative Evaluations',
|
|
|
|
|
data: formattedData.map((d) => ({
|
|
|
|
|
x: d.dateFormatted,
|
|
|
|
|
y: d.cumulative,
|
|
|
|
|
})),
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
|
2026-01-30 13:41:32 +01:00
|
|
|
return (
|
|
|
|
|
<Card>
|
|
|
|
|
<CardHeader>
|
|
|
|
|
<CardTitle className="flex items-center justify-between">
|
|
|
|
|
<span>Evaluation Progress Over Time</span>
|
|
|
|
|
<span className="text-sm font-normal text-muted-foreground">
|
|
|
|
|
Total: {totalEvaluations} evaluations
|
|
|
|
|
</span>
|
|
|
|
|
</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent>
|
Observer platform overhaul: Nivo charts, round-type stats, UX improvements
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>
2026-02-19 21:44:38 +01:00
|
|
|
<div style={{ height: '300px' }}>
|
|
|
|
|
<ResponsiveLine
|
|
|
|
|
data={lineData}
|
|
|
|
|
theme={nivoTheme}
|
|
|
|
|
colors={[BRAND_DARK_BLUE]}
|
|
|
|
|
enableArea={true}
|
|
|
|
|
areaOpacity={0.1}
|
|
|
|
|
areaBaselineValue={0}
|
|
|
|
|
curve="monotoneX"
|
|
|
|
|
pointSize={6}
|
|
|
|
|
pointColor={BRAND_DARK_BLUE}
|
|
|
|
|
pointBorderWidth={2}
|
|
|
|
|
pointBorderColor="#ffffff"
|
|
|
|
|
useMesh={true}
|
|
|
|
|
enableSlices="x"
|
|
|
|
|
sliceTooltip={({ slice }) => {
|
|
|
|
|
const point = slice.points[0]
|
|
|
|
|
const dataItem = formattedData.find(
|
|
|
|
|
(d) => d.dateFormatted === point.data.xFormatted
|
|
|
|
|
)
|
|
|
|
|
return (
|
|
|
|
|
<div
|
|
|
|
|
style={{
|
|
|
|
|
background: '#fff',
|
|
|
|
|
padding: '8px 12px',
|
|
|
|
|
border: '1px solid #e5e7eb',
|
|
|
|
|
borderRadius: '8px',
|
|
|
|
|
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<strong>{point.data.xFormatted}</strong>
|
|
|
|
|
<div>Cumulative: {point.data.yFormatted}</div>
|
|
|
|
|
{dataItem && <div>Daily: {dataItem.daily}</div>}
|
|
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}}
|
|
|
|
|
margin={{ top: 20, right: 20, bottom: 50, left: 60 }}
|
|
|
|
|
axisBottom={{
|
|
|
|
|
tickRotation: -45,
|
|
|
|
|
legend: '',
|
|
|
|
|
legendOffset: 36,
|
|
|
|
|
}}
|
|
|
|
|
axisLeft={{
|
|
|
|
|
legend: 'Evaluations',
|
|
|
|
|
legendOffset: -50,
|
|
|
|
|
legendPosition: 'middle',
|
|
|
|
|
}}
|
|
|
|
|
yScale={{ type: 'linear', min: 0, max: 'auto' }}
|
|
|
|
|
/>
|
2026-01-30 13:41:32 +01:00
|
|
|
</div>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
)
|
|
|
|
|
}
|