/** * Ofsted section — one visual grammar for inspection detail across all * three regimes (legacy graded, interim carried-forward, renewed-framework * report card). Copy comes verbatim from the reviewed mockups. */ 'use client'; import { OFSTED_LEGACY_GRADES, ofstedDisplay, rcAreaLabel, type OfstedDisplay, } from '@/lib/compareLogic'; import type { ComparisonData, OfstedInspection, School } from '@/lib/types'; import { Cell, Chip, Measure, Section, SectionGrid, sectionStyles as s } from './sectionShared'; const GRADE_TONE: Record = { 1: 'good', 2: 'good', 3: 'warn', 4: 'bad', }; const RC_CODE_TONE = (code: number): 'good' | 'warn' | 'bad' | 'neutral' => code <= 2 ? 'good' : code === 3 ? 'neutral' : code === 4 ? 'warn' : 'bad'; function formatInspectionDate(iso: string | null): string { if (!iso) return '—'; const d = new Date(iso); if (Number.isNaN(d.getTime())) return '—'; return d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' }); } function yearsSince(iso: string | null): number | null { if (!iso) return null; const d = new Date(iso); if (Number.isNaN(d.getTime())) return null; return (Date.now() - d.getTime()) / (365.25 * 24 * 3600 * 1000); } function ResultCell({ display }: { display: OfstedDisplay }) { if (display.kind === 'none') { return No inspection outcome in our dataset; } if (display.kind === 'report_card') { return ( <> Report card New-style inspection — no overall grade is given ); } if (display.kind === 'transitional') { return ( <> No overall grade Inspected under transitional framework (sub-judgements only) ); } return ( <> {display.gradeLabel} {display.carriedForward ? 'Grade carried forward from an earlier inspection (ungraded visit since)' : 'Overall grade (older-style inspection)'} ); } function JudgementDetailCell({ ofsted, display, schoolName, }: { ofsted: OfstedInspection; display: OfstedDisplay; schoolName: string; }) { if (display.kind === 'report_card') { const entries = Object.entries(ofsted.report_card ?? {}); return (
{entries.map(([key, entry]) => (
{rcAreaLabel(key)} {entry.label}
))} {ofsted.rc_safeguarding_met != null && (
Safeguarding {ofsted.rc_safeguarding_met ? 'Met' : 'Not met'}
)}
); } const legacyAreas: Array<[string, number | null | undefined]> = [ ['Quality of education', ofsted.quality_of_education], ['Behaviour & attitudes', ofsted.behaviour_attitudes], ['Personal development', ofsted.personal_development], ['Leadership & management', ofsted.leadership_management], ['Early years provision', ofsted.early_years_provision], ['Sixth form provision', ofsted.sixth_form_provision], ]; // Only real Ofsted grades (1–4) are judgements. The MI file uses sentinel // codes for "not applicable / no judgement" (9, and 0/8 variants) — those // must never render as a rating chip. const published = legacyAreas.filter( (entry): entry is [string, number] => entry[1] != null && entry[1] >= 1 && entry[1] <= 4, ); if (published.length === 0) { return ( We don't hold area-by-area detail for this inspection — see {schoolName}'s Ofsted page for the full report. ); } return (
{published.map(([label, grade]) => (
{label} {OFSTED_LEGACY_GRADES[grade as number] ?? String(grade)}
))}
); } export function CompareOfsted({ schools, data, }: { schools: School[]; data: Record; }) { const displays = schools.map((school) => ofstedDisplay(data[String(school.urn)]?.ofsted)); const kinds = new Set(displays.map((d) => d.kind).filter((k) => k !== 'none')); const mixedRegimes = kinds.size > 1; return (
Ofsted is the schools inspectorate. It stopped giving a single overall grade in{' '} September 2024; inspections between then and November 2025 kept the area-by-area judgements without an overall grade, and from November 2025{' '} new inspections produce a report card rating each area of school life on a five-point scale. {mixedRegimes && ( <> A report card and an older overall grade aren't directly comparable. )}{' '} (Ofsted's "Expected standard" rating is unrelated to the KS2 "expected standard" test measure further down this page.) } > {schools.map((school, i) => ( ))} {schools.map((school, i) => { const ofsted = data[String(school.urn)]?.ofsted; // A report card is dated by its OWN inspection date. The legacy // inspection_date belongs to an older inspection and must never // be shown against a report card (report cards exist only from // Nov 2025). const dateIso = displays[i].kind === 'report_card' ? ofsted?.rc_inspection_date ?? null : ofsted?.inspection_date ?? null; const age = yearsSince(dateIso); return ( {formatInspectionDate(dateIso)}{' '} {age != null && age > 4 && 4+ years ago} ); })} {schools.map((school, i) => { const ofsted = data[String(school.urn)]?.ofsted; return ( {ofsted ? ( ) : ( No inspection in our dataset )} ); })} {schools.map((school, i) => { const url = data[String(school.urn)]?.ofsted?.ofsted_page_url ?? `https://reports.ofsted.gov.uk/provider/21/${school.urn}`; return ( {school.school_name}'s Ofsted page → ); })}
); }