'use client'; /** * AdmissionsTrendChart * Compact line chart of the first-choice offer rate across admissions years. * Renders nothing unless at least two years carry an offer-rate value. */ import { Line } from 'react-chartjs-2'; import { ChartOptions } from 'chart.js'; import '@/lib/chartSetup'; import { formatAcademicYear } from '@/lib/utils'; import type { SchoolAdmissions } from '@/lib/types'; import styles from './AdmissionsTrendChart.module.css'; export default function AdmissionsTrendChart({ history }: { history: SchoolAdmissions[] }) { const pts = history.filter((h) => h.first_preference_offer_pct != null); if (pts.length < 2) return null; const labels = pts.map((p) => formatAcademicYear(p.year)); const values = pts.map((p) => p.first_preference_offer_pct as number); const lastIdx = pts.length - 1; // Auto-scale with headroom so variation is visible, clamped to 0–100. const lo = Math.min(...values); const hi = Math.max(...values); const padded = Math.max(5, Math.round((hi - lo) * 0.25)); const yMin = Math.max(0, Math.floor((lo - padded) / 5) * 5); const yMax = Math.min(100, Math.ceil((hi + padded) / 5) * 5); const options: ChartOptions<'line'> = { responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false }, plugins: { legend: { display: false }, title: { display: false }, tooltip: { backgroundColor: 'rgba(26,22,18,0.92)', padding: 10, titleFont: { size: 12 }, bodyFont: { size: 12 }, callbacks: { label: (ctx) => (ctx.parsed.y == null ? '' : `First-choice offers: ${Math.round(ctx.parsed.y)}%`), }, }, }, scales: { y: { min: yMin, max: yMax, grid: { color: 'rgba(0,0,0,0.05)' }, ticks: { font: { size: 11 }, maxTicksLimit: 5, callback: (v) => `${v}%` }, }, x: { grid: { display: false }, ticks: { font: { size: 11 }, autoSkip: true, maxRotation: 0, autoSkipPadding: 16 }, }, }, }; const data = { labels, datasets: [ { label: 'First-choice offer rate', data: values, borderColor: '#e07256', backgroundColor: 'rgba(224,114,86,0.10)', borderWidth: 2.5, tension: 0.3, fill: true, pointRadius: pts.map((_, i) => (i === lastIdx ? 5 : 3)), pointBackgroundColor: '#e07256', pointBorderColor: '#fff', pointBorderWidth: pts.map((_, i) => (i === lastIdx ? 2 : 0)), pointHoverRadius: 6, }, ], }; return (
); }