/** * One place page, shared by all four families. * * They differ in what fills the registry, not in what the page shows, so a * second component would be a second place to forget the same change. * * The local-versus-England comparison is the reason this page is not a list: * it is the one number a parent cannot get by reading the schools one by one, * and it is what keeps the page from reading as a name dropped into a * template. */ import Link from 'next/link'; import type { PlaceDetail, PlaceSummary } from '@/lib/places'; import { placeUrl, authoritySlug } from '@/lib/places'; import type { School } from '@/lib/types'; import { schoolUrl } from '@/lib/utils'; import { absoluteUrl } from '@/lib/site'; import styles from './PlaceView.module.css'; interface Props { detail: PlaceDetail; phase?: 'primary' | 'secondary'; englandAverage: number | null; /** Nearby places, so the page links onward instead of dead-ending. */ neighbours: PlaceSummary[]; } // Ofsted grades in the order they are reported. const OFSTED_LABELS: Array<[number, string]> = [ [1, 'Outstanding'], [2, 'Good'], [3, 'Requires improvement'], [4, 'Inadequate'], ]; /** * Column headings, taken from the site's own metric dictionary rather than * invented here — see METRIC_DEFINITIONS in backend/schemas.py, surfaced at * /api/metrics. The first cut said "RWM expected", which is jargon that * appears nowhere else on the site. */ const METRICS = { primary: { key: 'rwm_expected_pct' as const, heading: 'Reading, writing & maths', hint: '% meeting the expected standard in reading, writing and maths', unit: '%', }, secondary: { key: 'attainment_8_score' as const, heading: 'Attainment 8', hint: "Average grade across a pupil's best 8 GCSEs, including English and maths", unit: '', }, }; type PhaseKey = keyof typeof METRICS; /** All-through schools sit in both phases, matching the search filters. */ function isPhase(school: School, phase: PhaseKey): boolean { const p = (school.phase ?? '').toLowerCase(); if (p === 'all-through') return true; return phase === 'secondary' ? p.includes('secondary') || p === '16 plus' : p.includes('primary') || p.includes('middle'); } function SchoolTable({ schools, phase }: { schools: School[]; phase: PhaseKey }) { const metric = METRICS[phase]; return (
| School | {metric.heading} |
|---|---|
| {s.school_name} | {value == null ? Not published : `${Math.round(Number(value))}${metric.unit}`} |
{place.count} schools {place.parent_authority && ( <> {' · '} {place.parent_authority} > )}
{place.name} averages {Math.round(local)} against{' '} {Math.round(englandAverage)} across England.
)} {graded.length > 0 && (