/** * PerformanceChart Component * Displays school performance data over time using Chart.js */ 'use client'; import { Line } from 'react-chartjs-2'; import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend, ChartOptions, } from 'chart.js'; import type { SchoolResult } from '@/lib/types'; import { formatAcademicYear } from '@/lib/utils'; import styles from './PerformanceChart.module.css'; // Register Chart.js components ChartJS.register( CategoryScale, LinearScale, PointElement, LineElement, Title, Tooltip, Legend ); interface PerformanceChartProps { data: SchoolResult[]; schoolName: string; isSecondary?: boolean; } export function PerformanceChart({ data, schoolName, isSecondary = false }: PerformanceChartProps) { // Sort data by year const sortedData = [...data].sort((a, b) => a.year - b.year); const years = sortedData.map(d => formatAcademicYear(d.year)); // Prepare datasets — phase-aware const datasets = isSecondary ? [ { label: 'Attainment 8', data: sortedData.map(d => d.attainment_8_score), borderColor: 'rgb(59, 130, 246)', backgroundColor: 'rgba(59, 130, 246, 0.1)', tension: 0.3, yAxisID: 'y', }, { label: 'English & Maths Grade 4+', data: sortedData.map(d => d.english_maths_standard_pass_pct), borderColor: 'rgb(16, 185, 129)', backgroundColor: 'rgba(16, 185, 129, 0.1)', tension: 0.3, yAxisID: 'y', }, { label: 'Progress 8', data: sortedData.map(d => d.progress_8_score), borderColor: 'rgb(245, 158, 11)', backgroundColor: 'rgba(245, 158, 11, 0.1)', tension: 0.3, yAxisID: 'y1', }, ] : [ { label: 'Reading, Writing & Maths Expected %', data: sortedData.map(d => d.rwm_expected_pct), borderColor: 'rgb(59, 130, 246)', backgroundColor: 'rgba(59, 130, 246, 0.1)', tension: 0.3, }, { label: 'Reading, Writing & Maths Higher %', data: sortedData.map(d => d.rwm_high_pct), borderColor: 'rgb(16, 185, 129)', backgroundColor: 'rgba(16, 185, 129, 0.1)', tension: 0.3, }, { label: 'Reading Progress', data: sortedData.map(d => d.reading_progress), borderColor: 'rgb(245, 158, 11)', backgroundColor: 'rgba(245, 158, 11, 0.1)', tension: 0.3, yAxisID: 'y1', }, { label: 'Writing Progress', data: sortedData.map(d => d.writing_progress), borderColor: 'rgb(139, 92, 246)', backgroundColor: 'rgba(139, 92, 246, 0.1)', tension: 0.3, yAxisID: 'y1', }, { label: 'Maths Progress', data: sortedData.map(d => d.maths_progress), borderColor: 'rgb(236, 72, 153)', backgroundColor: 'rgba(236, 72, 153, 0.1)', tension: 0.3, yAxisID: 'y1', }, ]; const chartData = { labels: years, datasets, }; const options: ChartOptions<'line'> = { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index' as const, intersect: false, }, plugins: { legend: { position: 'top' as const, labels: { usePointStyle: true, padding: 15, font: { size: 12, }, }, }, title: { display: true, text: `${schoolName} - Performance Over Time`, font: { size: 16, weight: 'bold', }, padding: { bottom: 20, }, }, tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.8)', padding: 12, titleFont: { size: 14, }, bodyFont: { size: 13, }, callbacks: { label: function(context) { let label = context.dataset.label || ''; if (label) { label += ': '; } if (context.parsed.y !== null) { if (context.dataset.yAxisID === 'y1') { // Progress scores label += context.parsed.y.toFixed(1); } else { // Percentages label += context.parsed.y.toFixed(1) + '%'; } } return label; } } }, }, scales: { y: { type: 'linear' as const, display: true, position: 'left' as const, title: { display: true, text: isSecondary ? 'Score / Percentage (%)' : 'Percentage (%)', font: { size: 12, weight: 'bold', }, }, min: 0, max: isSecondary ? undefined : 100, grid: { color: 'rgba(0, 0, 0, 0.05)', }, }, y1: { type: 'linear' as const, display: true, position: 'right' as const, title: { display: true, text: isSecondary ? 'Progress 8 Score' : 'Progress Score', font: { size: 12, weight: 'bold', }, }, grid: { drawOnChartArea: false, }, }, x: { grid: { display: false, }, title: { display: true, text: 'Year', font: { size: 12, weight: 'bold', }, }, }, }, }; return (
); }