157 lines
7.0 KiB
TypeScript
157 lines
7.0 KiB
TypeScript
/**
|
|||
|
|
* HistorySection — results over time (chart plus historical table).
|
||
|
|
* Primary pages; the secondary equivalent is SecondaryHistorySection (the two
|
||
|
|
* were only 40% similar). Server component.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import dynamic from 'next/dynamic';
|
||
|
|
import type { School, SchoolResult, NationalAverages } from '@/lib/types';
|
||
|
|
import { formatPercentage, formatProgress, formatAcademicYear } from '@/lib/utils';
|
||
|
|
import { Section, sectionStyles as styles } from './sectionShared';
|
||
|
|
|
||
|
|
const PerformanceChart = dynamic(
|
||
|
|
() => import('../PerformanceChart').then((m) => m.PerformanceChart),
|
||
|
|
{ ssr: false },
|
||
|
|
);
|
||
|
|
const SatsChart = dynamic(() => import('../SatsChart'), { ssr: false });
|
||
|
|
|
||
|
|
export function HistorySection({
|
||
|
|
yearlyData, schoolInfo, nationalAvg, primaryAvg, secondaryAvg,
|
||
|
|
isAllThrough, isPrimary, isSecondary, hasKS2Results, hasKS4Results,
|
||
|
|
suppressKs2Comparison, suppressKs4Comparison,
|
||
|
|
}: {
|
||
|
|
yearlyData: SchoolResult[];
|
||
|
|
schoolInfo: School;
|
||
|
|
nationalAvg: NationalAverages | null;
|
||
|
|
primaryAvg: Record<string, number>;
|
||
|
|
secondaryAvg: Record<string, number>;
|
||
|
|
isAllThrough: boolean;
|
||
|
|
isPrimary: boolean;
|
||
|
|
isSecondary: boolean;
|
||
|
|
hasKS2Results: boolean;
|
||
|
|
hasKS4Results: boolean;
|
||
|
|
suppressKs2Comparison: boolean;
|
||
|
|
suppressKs4Comparison: boolean;
|
||
|
|
}) {
|
||
|
|
return (
|
||
|
|
<section id="history" className={styles.card}>
|
||
|
|
<h2 className={styles.sectionTitle}>Results Over Time</h2>
|
||
|
|
{isAllThrough ? (
|
||
|
|
// All-through: KS2 and KS4 trends are on different scales and have
|
||
|
|
// different gap stories, so render them as two stacked charts
|
||
|
|
// rather than crowding 8+ series onto one axis.
|
||
|
|
<>
|
||
|
|
{hasKS2Results && (
|
||
|
|
<>
|
||
|
|
<h3 className={styles.subSectionTitle}>Primary — KS2 SATs</h3>
|
||
|
|
<div className={styles.chartContainer}>
|
||
|
|
<PerformanceChart
|
||
|
|
data={yearlyData}
|
||
|
|
schoolName={schoolInfo.school_name}
|
||
|
|
isSecondary={false}
|
||
|
|
nationalRwmAvg={suppressKs2Comparison ? null : (primaryAvg.rwm_expected_pct ?? null)}
|
||
|
|
nationalByYear={suppressKs2Comparison ? undefined : nationalAvg?.by_year}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
{hasKS4Results && (
|
||
|
|
<>
|
||
|
|
<h3 className={styles.subSectionTitle} style={{ marginTop: '1.5rem' }}>Secondary — GCSEs</h3>
|
||
|
|
<div className={styles.chartContainer}>
|
||
|
|
<PerformanceChart
|
||
|
|
data={yearlyData}
|
||
|
|
schoolName={schoolInfo.school_name}
|
||
|
|
isSecondary={true}
|
||
|
|
nationalAtt8Avg={suppressKs4Comparison ? null : (secondaryAvg.attainment_8_score ?? null)}
|
||
|
|
nationalByYear={suppressKs4Comparison ? undefined : nationalAvg?.by_year}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</>
|
||
|
|
) : (
|
||
|
|
<div className={styles.chartContainer}>
|
||
|
|
<PerformanceChart
|
||
|
|
data={yearlyData}
|
||
|
|
schoolName={schoolInfo.school_name}
|
||
|
|
isSecondary={isSecondary}
|
||
|
|
nationalRwmAvg={isPrimary && !suppressKs2Comparison ? (primaryAvg.rwm_expected_pct ?? null) : null}
|
||
|
|
nationalAtt8Avg={isSecondary && !suppressKs4Comparison ? (secondaryAvg.attainment_8_score ?? null) : null}
|
||
|
|
nationalByYear={(isPrimary ? suppressKs2Comparison : suppressKs4Comparison) ? undefined : nationalAvg?.by_year}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
{yearlyData.length > 1 && (
|
||
|
|
<details className={styles.historyDisclosure}>
|
||
|
|
<summary className={styles.historyToggle}>View raw year-by-year data</summary>
|
||
|
|
<div className={styles.tableWrapper}>
|
||
|
|
<table className={styles.dataTable}>
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th>Year</th>
|
||
|
|
{isAllThrough ? (
|
||
|
|
<>
|
||
|
|
<th>RWM (expected %)</th>
|
||
|
|
<th>Exceeding (%)</th>
|
||
|
|
<th>Attainment 8</th>
|
||
|
|
<th>Progress 8</th>
|
||
|
|
<th>English & Maths Grade 4+</th>
|
||
|
|
</>
|
||
|
|
) : isSecondary ? (
|
||
|
|
<>
|
||
|
|
<th>Attainment 8</th>
|
||
|
|
<th>Progress 8</th>
|
||
|
|
<th>English & Maths Grade 4+</th>
|
||
|
|
<th>English & Maths Grade 5+</th>
|
||
|
|
</>
|
||
|
|
) : (
|
||
|
|
<>
|
||
|
|
<th>Reading, Writing & Maths (expected %)</th>
|
||
|
|
<th>Exceeding expected (%)</th>
|
||
|
|
<th>Reading Progress</th>
|
||
|
|
<th>Writing Progress</th>
|
||
|
|
<th>Maths Progress</th>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody>
|
||
|
|
{yearlyData.map((result) => (
|
||
|
|
<tr key={result.year}>
|
||
|
|
<td className={styles.yearCell}>{formatAcademicYear(result.year)}</td>
|
||
|
|
{isAllThrough ? (
|
||
|
|
<>
|
||
|
|
<td>{result.rwm_expected_pct !== null ? formatPercentage(result.rwm_expected_pct) : '-'}</td>
|
||
|
|
<td>{result.rwm_high_pct !== null ? formatPercentage(result.rwm_high_pct) : '-'}</td>
|
||
|
|
<td>{result.attainment_8_score !== null ? result.attainment_8_score.toFixed(1) : '-'}</td>
|
||
|
|
<td>{result.progress_8_score !== null ? formatProgress(result.progress_8_score) : '-'}</td>
|
||
|
|
<td>{result.english_maths_standard_pass_pct !== null ? formatPercentage(result.english_maths_standard_pass_pct) : '-'}</td>
|
||
|
|
</>
|
||
|
|
) : isSecondary ? (
|
||
|
|
<>
|
||
|
|
<td>{result.attainment_8_score !== null ? result.attainment_8_score.toFixed(1) : '-'}</td>
|
||
|
|
<td>{result.progress_8_score !== null ? formatProgress(result.progress_8_score) : '-'}</td>
|
||
|
|
<td>{result.english_maths_standard_pass_pct !== null ? formatPercentage(result.english_maths_standard_pass_pct) : '-'}</td>
|
||
|
|
<td>{result.english_maths_strong_pass_pct !== null ? formatPercentage(result.english_maths_strong_pass_pct) : '-'}</td>
|
||
|
|
</>
|
||
|
|
) : (
|
||
|
|
<>
|
||
|
|
<td>{result.rwm_expected_pct !== null ? formatPercentage(result.rwm_expected_pct) : '-'}</td>
|
||
|
|
<td>{result.rwm_high_pct !== null ? formatPercentage(result.rwm_high_pct) : '-'}</td>
|
||
|
|
<td>{result.reading_progress !== null ? formatProgress(result.reading_progress) : '-'}</td>
|
||
|
|
<td>{result.writing_progress !== null ? formatProgress(result.writing_progress) : '-'}</td>
|
||
|
|
<td>{result.maths_progress !== null ? formatProgress(result.maths_progress) : '-'}</td>
|
||
|
|
</>
|
||
|
|
)}
|
||
|
|
</tr>
|
||
|
|
))}
|
||
|
|
</tbody>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</details>
|
||
|
|
)}
|
||
|
|
</section>
|
||
|
|
);
|
||
|
|
}
|