Files
school_compare/nextjs-app/components/school/OfstedSection.tsx
T
TudorandClaude Opus 5.5 9ef48da4b1 fix(school): the Ofsted section shows the grade still in force and the latest visit
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>
2026-10-05 16:31:26 +01:00

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&apos; 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>
);
}