The section is dated by the latest visit and headlines the grade still in force with the inspection that awarded or confirmed it, or 'No overall grade'. A later visit that isn't the grade's source gets its own line, with an ungraded outcome such as 'Standards maintained'. The primary and secondary no-grade branches merge, so the secondary page no longer drops the sixth-form and early-years judgements (audit M2), and 'Not rated' goes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
156 lines
6.5 KiB
TypeScript
156 lines
6.5 KiB
TypeScript
/**
|
|
* OfstedSection — shared between the primary and secondary detail pages.
|
|
*
|
|
* The headline is the school's current Ofsted status (backend:
|
|
* fact_ofsted_latest): the report card; or the overall grade still in force,
|
|
* with the inspection that awarded or confirmed it; or "No overall grade".
|
|
* A later visit that is not the grade's source gets its own line. Both pages
|
|
* render the same branches, so neither drops an area judgement (audit M2).
|
|
* Rule: docs/superpowers/specs/2026-10-05-ofsted-current-status-design.md
|
|
*
|
|
* Server component.
|
|
*/
|
|
|
|
import { ofstedDisplay } from '@/lib/compareLogic';
|
|
import { formatOfstedDate, gradeSourceLine, latestVisitLine, showLatestVisitLine } from '@/lib/ofstedStatus';
|
|
import type { OfstedInspection } from '@/lib/types';
|
|
import { Section, sectionStyles as styles } from './sectionShared';
|
|
|
|
const OFSTED_LABELS: Record<number, string> = {
|
|
1: 'Outstanding', 2: 'Good', 3: 'Requires Improvement', 4: 'Inadequate',
|
|
};
|
|
|
|
const RC_LABELS: Record<number, string> = {
|
|
1: 'Exceptional', 2: 'Strong', 3: 'Expected standard', 4: 'Needs attention', 5: 'Urgent improvement',
|
|
};
|
|
|
|
const RC_CATEGORIES = [
|
|
{ key: 'rc_inclusion' as const, label: 'Inclusion' },
|
|
{ key: 'rc_curriculum_teaching' as const, label: 'Curriculum & Teaching' },
|
|
{ key: 'rc_achievement' as const, label: 'Achievement' },
|
|
{ key: 'rc_attendance_behaviour' as const, label: 'Attendance & Behaviour' },
|
|
{ key: 'rc_personal_development' as const, label: 'Personal Development' },
|
|
{ key: 'rc_leadership_governance' as const, label: 'Leadership & Governance' },
|
|
{ key: 'rc_early_years' as const, label: 'Early Years' },
|
|
{ key: 'rc_sixth_form' as const, label: 'Sixth Form' },
|
|
];
|
|
|
|
export interface OfstedSectionProps {
|
|
ofsted: OfstedInspection;
|
|
urn: number;
|
|
isReportCard: boolean;
|
|
ofstedInspectedDate: string | null;
|
|
oeifAllSameGrade: boolean;
|
|
oeifAreas: { label: string; value: number }[];
|
|
}
|
|
|
|
export function OfstedSection({
|
|
ofsted, urn, isReportCard, ofstedInspectedDate,
|
|
oeifAllSameGrade, oeifAreas,
|
|
}: OfstedSectionProps) {
|
|
const display = ofstedDisplay(ofsted);
|
|
|
|
return (
|
|
<Section id="ofsted">
|
|
<h2 className={styles.sectionTitle}>
|
|
{isReportCard ? 'Ofsted Report Card' : 'Ofsted Rating'}
|
|
{ofstedInspectedDate && (
|
|
<span className={styles.ofstedDate}>
|
|
Inspected {new Date(ofstedInspectedDate).toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })}
|
|
</span>
|
|
)}
|
|
<a
|
|
href={`https://reports.ofsted.gov.uk/inspection-reports/find-inspection-report/provider/ELS/${urn}`}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className={styles.ofstedReportLink}
|
|
data-umami-event="external_link_clicked"
|
|
data-umami-event-target="ofsted"
|
|
>
|
|
Ofsted reports ↗
|
|
</a>
|
|
</h2>
|
|
|
|
{isReportCard ? (
|
|
/* ── New Report Card layout ── */
|
|
<>
|
|
<p className={styles.ofstedDisclaimer}>
|
|
From November 2025, Ofsted replaced single overall grades with Report Cards rating schools across several areas.
|
|
</p>
|
|
<div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
|
|
{ofsted.rc_safeguarding_met != null && (
|
|
<div className={styles.metricCard}>
|
|
<div className={styles.metricLabel}>Safeguarding</div>
|
|
<div className={`${styles.metricValue} ${ofsted.rc_safeguarding_met ? styles.safeguardingMet : styles.safeguardingNotMet}`}>
|
|
{ofsted.rc_safeguarding_met ? 'Met' : 'Not met'}
|
|
</div>
|
|
</div>
|
|
)}
|
|
{RC_CATEGORIES.map(({ key, label }) => {
|
|
const value = ofsted[key] as number | null;
|
|
return value != null ? (
|
|
<div key={key} className={styles.metricCard}>
|
|
<div className={styles.metricLabel}>{label}</div>
|
|
<div className={`${styles.metricValue} ${styles[`rcGrade${value}`]}`}>
|
|
{RC_LABELS[value]}
|
|
</div>
|
|
</div>
|
|
) : null;
|
|
})}
|
|
</div>
|
|
</>
|
|
) : (
|
|
<>
|
|
<div className={styles.ofstedHeader}>
|
|
{display.kind === 'graded' || display.kind === 'confirmed' ? (
|
|
<>
|
|
<span className={`${styles.ofstedGrade} ${styles[`ofstedGrade${display.grade}`]}`}>
|
|
{display.gradeLabel}
|
|
</span>
|
|
{ofsted.previous_overall != null && ofsted.previous_overall !== display.grade && (
|
|
<span className={styles.ofstedPrevious}>
|
|
Previously: {OFSTED_LABELS[ofsted.previous_overall]}
|
|
</span>
|
|
)}
|
|
</>
|
|
) : (
|
|
<span className={styles.ofstedGrade}>No overall grade</span>
|
|
)}
|
|
</div>
|
|
<p className={styles.ofstedDisclaimer}>
|
|
{ofsted.current_grade
|
|
? gradeSourceLine(ofsted.current_grade)
|
|
: 'Ofsted stopped giving overall grades in September 2024.'}
|
|
</p>
|
|
{showLatestVisitLine(ofsted) && ofsted.latest_visit && (
|
|
<p className={styles.ofstedDisclaimer}>Latest visit: {latestVisitLine(ofsted.latest_visit)}</p>
|
|
)}
|
|
{oeifAllSameGrade && (display.kind === 'graded' || display.kind === 'confirmed') ? (
|
|
<p className={styles.ofstedAllSame}>
|
|
Rated <strong>{display.gradeLabel}</strong> across all inspected areas: Quality of Teaching, Behaviour, Pupils' Development and Leadership.
|
|
</p>
|
|
) : oeifAreas.length > 0 ? (
|
|
<>
|
|
{ofsted.inspection_date && ofsted.inspection_date !== ofsted.latest_visit?.date && (
|
|
<p className={styles.ofstedDisclaimer}>
|
|
Area judgements from the graded inspection, {formatOfstedDate(ofsted.inspection_date)}.
|
|
</p>
|
|
)}
|
|
<div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
|
|
{oeifAreas.map(({ label, value }) => (
|
|
<div key={label} className={styles.metricCard}>
|
|
<div className={styles.metricLabel}>{label}</div>
|
|
<div className={`${styles.metricValue} ${styles[`ofstedGrade${value}`]}`}>
|
|
{OFSTED_LABELS[value]}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</>
|
|
) : null}
|
|
</>
|
|
)}
|
|
</Section>
|
|
);
|
|
}
|