fix(compare): Ofsted rows show the grade still in force and the latest visit
'Inspected' is the school's latest visit, so Washwood Heath reads 21 May 2025 rather than '3 Mar 2020 · 4+ years ago' (audit M1). The Result row names the inspection a grade came from, or says 'No overall grade'; 'Grade carried forward' and 'transitional framework' go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9ef48da4b1
commit
d37baa572b
3 files changed
+56
-37
No files matched your search
@@ -33,18 +33,26 @@ function ofsted(partial: Partial<OfstedInspection>): OfstedInspection {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const schools = [school(1, 'Graded School'), school(2, 'Carried School'), school(3, 'Card School')];
|
const schools = [school(1, 'Graded School'), school(2, 'Confirmed School'), school(3, 'Card School')];
|
||||||
|
|
||||||
const data: Record<string, ComparisonData> = {
|
const data: Record<string, ComparisonData> = {
|
||||||
'1': {
|
'1': {
|
||||||
school_info: schools[0],
|
school_info: schools[0],
|
||||||
yearly_data: [],
|
yearly_data: [],
|
||||||
ofsted: ofsted({ overall_effectiveness: 1, grade_source: 'graded' }),
|
ofsted: ofsted({
|
||||||
|
overall_effectiveness: 1,
|
||||||
|
current_grade: { grade: 1, date: '2021-10-07', basis: 'graded' },
|
||||||
|
latest_visit: { date: '2021-10-07', kind: 'graded', outcome: null },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
'2': {
|
'2': {
|
||||||
school_info: schools[1],
|
school_info: schools[1],
|
||||||
yearly_data: [],
|
yearly_data: [],
|
||||||
ofsted: ofsted({ overall_effectiveness: 2, grade_source: 'ungraded_carried_forward' }),
|
ofsted: ofsted({
|
||||||
|
overall_effectiveness: 2,
|
||||||
|
current_grade: { grade: 2, date: '2023-03-14', basis: 'confirmed' },
|
||||||
|
latest_visit: { date: '2023-03-14', kind: 'ungraded', outcome: 'School remains Good' },
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
'3': {
|
'3': {
|
||||||
school_info: schools[2],
|
school_info: schools[2],
|
||||||
@@ -65,9 +73,9 @@ describe('CompareOfsted', () => {
|
|||||||
render(<CompareOfsted schools={schools} data={data} />);
|
render(<CompareOfsted schools={schools} data={data} />);
|
||||||
|
|
||||||
expect(screen.getByText('Outstanding')).toBeInTheDocument();
|
expect(screen.getByText('Outstanding')).toBeInTheDocument();
|
||||||
// Carried-forward grade is shown but marked as such
|
// A grade confirmed at an ungraded visit says so, with that visit's date
|
||||||
expect(screen.getByText('Good')).toBeInTheDocument();
|
expect(screen.getByText('Good')).toBeInTheDocument();
|
||||||
expect(screen.getByText(/carried forward/i)).toBeInTheDocument();
|
expect(screen.getByText('Confirmed at an ungraded inspection, 14 March 2023')).toBeInTheDocument();
|
||||||
// Report card: label present, no overall-grade badge for that school
|
// Report card: label present, no overall-grade badge for that school
|
||||||
expect(screen.getByText('Report card')).toBeInTheDocument();
|
expect(screen.getByText('Report card')).toBeInTheDocument();
|
||||||
expect(screen.getByText(/no overall grade/i)).toBeInTheDocument();
|
expect(screen.getByText(/no overall grade/i)).toBeInTheDocument();
|
||||||
@@ -104,7 +112,7 @@ describe('CompareOfsted', () => {
|
|||||||
yearly_data: [],
|
yearly_data: [],
|
||||||
ofsted: ofsted({
|
ofsted: ofsted({
|
||||||
overall_effectiveness: 2,
|
overall_effectiveness: 2,
|
||||||
grade_source: 'graded',
|
current_grade: { grade: 2, date: '2021-10-07', basis: 'graded' },
|
||||||
quality_of_education: 1,
|
quality_of_education: 1,
|
||||||
early_years_provision: 9,
|
early_years_provision: 9,
|
||||||
sixth_form_provision: 2,
|
sixth_form_provision: 2,
|
||||||
@@ -167,4 +175,26 @@ describe('CompareOfsted', () => {
|
|||||||
expect(screen.getAllByText('Graded').length).toBe(4);
|
expect(screen.getAllByText('Graded').length).toBe(4);
|
||||||
expect(screen.getAllByText('Card').length).toBe(4);
|
expect(screen.getAllByText('Card').length).toBe(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('dates "Inspected" by the latest visit, not the graded inspection (Washwood Heath)', () => {
|
||||||
|
const s1 = school(7, 'Washwood Heath Academy');
|
||||||
|
render(<CompareOfsted schools={[s1]} data={{ '7': { school_info: s1, yearly_data: [], ofsted: ofsted({
|
||||||
|
inspection_date: '2020-03-03', overall_effectiveness: 2, quality_of_education: 2,
|
||||||
|
current_grade: { grade: 2, date: '2020-03-03', basis: 'graded' },
|
||||||
|
latest_visit: { date: '2025-05-21', kind: 'ungraded', outcome: 'Standards maintained' },
|
||||||
|
}) } }} />);
|
||||||
|
expect(screen.getByText(/21 May 2025/)).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('4+ years ago')).not.toBeInTheDocument();
|
||||||
|
expect(screen.getByText('Graded inspection, 3 March 2020')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows no overall grade after a no-grade inspection (Rabbsfarm)', () => {
|
||||||
|
const s1 = school(8, 'Rabbsfarm Primary School');
|
||||||
|
render(<CompareOfsted schools={[s1]} data={{ '8': { school_info: s1, yearly_data: [], ofsted: ofsted({
|
||||||
|
inspection_date: '2025-06-17', quality_of_education: 3,
|
||||||
|
current_grade: null, latest_visit: { date: '2025-06-17', kind: 'graded', outcome: null },
|
||||||
|
}) } }} />);
|
||||||
|
expect(screen.getAllByText('No overall grade').length).toBeGreaterThan(0);
|
||||||
|
expect(screen.queryByText('Good')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -78,21 +78,18 @@ export function CompareAtAGlance({
|
|||||||
return (
|
return (
|
||||||
<Cell key={school.urn} school={school} index={i}>
|
<Cell key={school.urn} school={school} index={i}>
|
||||||
{display.kind === 'report_card' && <ReportCardChips summary={display.summary} />}
|
{display.kind === 'report_card' && <ReportCardChips summary={display.summary} />}
|
||||||
{(display.kind === 'graded' || display.kind === 'carried_forward') && (
|
{(display.kind === 'graded' || display.kind === 'confirmed') && (
|
||||||
<>
|
<>
|
||||||
<span className={`${s.badge} ${display.grade <= 2 ? s.badgeGood : display.grade === 3 ? s.badgeWarn : s.badgeBad}`}>
|
<span className={`${s.badge} ${display.grade <= 2 ? s.badgeGood : display.grade === 3 ? s.badgeWarn : s.badgeBad}`}>
|
||||||
{display.gradeLabel}
|
{display.gradeLabel}
|
||||||
</span>
|
</span>
|
||||||
{display.carriedForward && <span className={s.small}>Grade carried forward</span>}
|
{display.kind === 'confirmed' && <span className={s.small}>Confirmed at an ungraded inspection</span>}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{display.kind === 'transitional' && (
|
{display.kind === 'no_overall_grade' && (
|
||||||
<>
|
<span className={s.badge} style={{ backgroundColor: 'var(--bg-secondary)', color: 'var(--text-secondary)' }}>
|
||||||
<span className={s.badge} style={{ backgroundColor: 'var(--bg-secondary)', color: 'var(--text-secondary)' }}>
|
No overall grade
|
||||||
No overall grade
|
</span>
|
||||||
</span>
|
|
||||||
<span className={s.small}>Sub-judgements only</span>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
{display.kind === 'none' && <span className={s.small}>No inspection in our dataset</span>}
|
{display.kind === 'none' && <span className={s.small}>No inspection in our dataset</span>}
|
||||||
</Cell>
|
</Cell>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Ofsted section — one visual grammar for inspection detail across all
|
* Ofsted section — one visual grammar for inspection detail across all
|
||||||
* three regimes (legacy graded, interim carried-forward, renewed-framework
|
* three regimes (legacy graded, no overall grade, renewed-framework report
|
||||||
* report card). Copy comes verbatim from the reviewed mockups.
|
* card). The grade shown is the one still in force, with the inspection that
|
||||||
|
* awarded or confirmed it; "Inspected" is the latest visit.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use client';
|
'use client';
|
||||||
@@ -12,7 +13,8 @@ import {
|
|||||||
rcAreaLabel,
|
rcAreaLabel,
|
||||||
type OfstedDisplay,
|
type OfstedDisplay,
|
||||||
} from '@/lib/compareLogic';
|
} from '@/lib/compareLogic';
|
||||||
import type { ComparisonData, OfstedInspection, School } from '@/lib/types';
|
import { gradeSourceLine } from '@/lib/ofstedStatus';
|
||||||
|
import type { ComparisonData, OfstedCurrentGrade, OfstedInspection, School } from '@/lib/types';
|
||||||
import { Cell, Chip, Measure, Section, SectionGrid, sectionStyles as s } from './sectionShared';
|
import { Cell, Chip, Measure, Section, SectionGrid, sectionStyles as s } from './sectionShared';
|
||||||
|
|
||||||
const GRADE_TONE: Record<number, 'good' | 'warn' | 'bad'> = {
|
const GRADE_TONE: Record<number, 'good' | 'warn' | 'bad'> = {
|
||||||
@@ -39,7 +41,7 @@ function yearsSince(iso: string | null): number | null {
|
|||||||
return (Date.now() - d.getTime()) / (365.25 * 24 * 3600 * 1000);
|
return (Date.now() - d.getTime()) / (365.25 * 24 * 3600 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ResultCell({ display }: { display: OfstedDisplay }) {
|
function ResultCell({ display, current }: { display: OfstedDisplay; current: OfstedCurrentGrade | null }) {
|
||||||
if (display.kind === 'none') {
|
if (display.kind === 'none') {
|
||||||
return <span className={s.small}>No inspection outcome in our dataset</span>;
|
return <span className={s.small}>No inspection outcome in our dataset</span>;
|
||||||
}
|
}
|
||||||
@@ -51,15 +53,13 @@ function ResultCell({ display }: { display: OfstedDisplay }) {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (display.kind === 'transitional') {
|
if (display.kind === 'no_overall_grade') {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span className={s.badge} style={{ backgroundColor: 'var(--bg-secondary)', color: 'var(--text-secondary)' }}>
|
<span className={s.badge} style={{ backgroundColor: 'var(--bg-secondary)', color: 'var(--text-secondary)' }}>
|
||||||
No overall grade
|
No overall grade
|
||||||
</span>
|
</span>
|
||||||
<span className={s.small}>
|
<span className={s.small}>Ofsted stopped giving overall grades in September 2024</span>
|
||||||
Inspected under transitional framework (sub-judgements only)
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -68,11 +68,7 @@ function ResultCell({ display }: { display: OfstedDisplay }) {
|
|||||||
<span className={`${s.badge} ${display.grade <= 2 ? s.badgeGood : display.grade === 3 ? s.badgeWarn : s.badgeBad}`}>
|
<span className={`${s.badge} ${display.grade <= 2 ? s.badgeGood : display.grade === 3 ? s.badgeWarn : s.badgeBad}`}>
|
||||||
{display.gradeLabel}
|
{display.gradeLabel}
|
||||||
</span>
|
</span>
|
||||||
<span className={s.small}>
|
{current && <span className={s.small}>{gradeSourceLine(current)}</span>}
|
||||||
{display.carriedForward
|
|
||||||
? 'Grade carried forward from an earlier inspection (ungraded visit since)'
|
|
||||||
: 'Overall grade (older-style inspection)'}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -179,7 +175,7 @@ export function CompareOfsted({
|
|||||||
<Measure label="Result">
|
<Measure label="Result">
|
||||||
{schools.map((school, i) => (
|
{schools.map((school, i) => (
|
||||||
<Cell key={school.urn} school={school} index={i}>
|
<Cell key={school.urn} school={school} index={i}>
|
||||||
<ResultCell display={displays[i]} />
|
<ResultCell display={displays[i]} current={data[String(school.urn)]?.ofsted?.current_grade ?? null} />
|
||||||
</Cell>
|
</Cell>
|
||||||
))}
|
))}
|
||||||
</Measure>
|
</Measure>
|
||||||
@@ -187,19 +183,15 @@ export function CompareOfsted({
|
|||||||
<Measure label="Inspected">
|
<Measure label="Inspected">
|
||||||
{schools.map((school, i) => {
|
{schools.map((school, i) => {
|
||||||
const ofsted = data[String(school.urn)]?.ofsted;
|
const ofsted = data[String(school.urn)]?.ofsted;
|
||||||
// A report card is dated by its OWN inspection date. The legacy
|
// The school's latest visit of any kind (a report card's own date
|
||||||
// inspection_date belongs to an older inspection and must never
|
// when there is one), never an older inspection a grade comes from.
|
||||||
// be shown against a report card (report cards exist only from
|
const dateIso = ofsted?.latest_visit?.date ?? ofsted?.rc_inspection_date ?? null;
|
||||||
// Nov 2025).
|
|
||||||
const dateIso =
|
|
||||||
displays[i].kind === 'report_card'
|
|
||||||
? ofsted?.rc_inspection_date ?? null
|
|
||||||
: ofsted?.inspection_date ?? null;
|
|
||||||
const age = yearsSince(dateIso);
|
const age = yearsSince(dateIso);
|
||||||
return (
|
return (
|
||||||
<Cell key={school.urn} school={school} index={i}>
|
<Cell key={school.urn} school={school} index={i}>
|
||||||
{formatInspectionDate(dateIso)}{' '}
|
{formatInspectionDate(dateIso)}{' '}
|
||||||
{age != null && age > 4 && <Chip tone="neutral">4+ years ago</Chip>}
|
{age != null && age > 4 && <Chip tone="neutral">4+ years ago</Chip>}
|
||||||
|
{ofsted?.latest_visit?.outcome && <span className={s.small}>{ofsted.latest_visit.outcome}</span>}
|
||||||
</Cell>
|
</Cell>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Reference in new issue
Block a user