'use client'; import { useEffect, useRef } from 'react'; import styles from './SatsChart.module.css'; interface SubjectData { name: string; expectedPct: number | null; exceedingPct: number | null; nationalExpectedPct: number | null; } interface SatsChartProps { subjects: SubjectData[]; } const RULER_TICKS = [0, 25, 50, 75, 100]; const GRIDLINE_POSITIONS = [25, 50, 75]; function SubjectColumn({ subject }: { subject: SubjectData }) { const expectedRef = useRef(null); const exceedingRef = useRef(null); const { name, expectedPct, exceedingPct, nationalExpectedPct } = subject; // Animate bars on mount useEffect(() => { const bars = [expectedRef.current, exceedingRef.current]; bars.forEach((bar) => { if (!bar) return; const target = bar.dataset.width; bar.style.width = '0%'; requestAnimationFrame(() => { requestAnimationFrame(() => { bar.style.width = `${target}%`; }); }); }); }, [expectedPct, exceedingPct]); if (expectedPct == null && exceedingPct == null) return null; return (
{name}
{/* Gridlines */}
{GRIDLINE_POSITIONS.map((pct) => (
))}
{/* National average marker */} {nationalExpectedPct != null && (
{nationalExpectedPct.toFixed(0)}%
)} {/* Bars */}
{expectedPct != null && (
{expectedPct.toFixed(0)}% expected
)} {exceedingPct != null && (
{exceedingPct.toFixed(0)}% exceeding
)}
{/* Ruler */}
{RULER_TICKS.map((pct, i) => (
{pct}%
))}
); } export default function SatsChart({ subjects }: SatsChartProps) { const visibleSubjects = subjects.filter( (s) => s.expectedPct != null || s.exceedingPct != null ); if (visibleSubjects.length === 0) return null; return (
{visibleSubjects.map((subject) => ( ))}
Expected standard
Exceeding / high score
National average
); }