fix(school-detail): hero Ofsted chip mislabels OEIF schools as Report Card
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 13s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 45s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 12s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s

The API returns ``framework`` as the literal string "NULL" for older OEIF
inspections (it comes from the upstream ``event_type_grouping`` column),
not real null. The original render path checks ``=== 'ReportCard'`` and
correctly treats anything else as OEIF — but buildOfstedHeroChip inverted
that and treated anything not exactly equal to ``'OEIF'`` as Report Card,
so OLQH (inspected Nov 2023, Outstanding) was being labelled as a Report
Card school in the hero strip and the at-a-glance tile.

- Invert the helper: only branch into Report Card when framework is
  explicitly ``'ReportCard'``; treat OEIF / null / "NULL" / anything else
  as OEIF, and require ``overall_effectiveness`` to render the grade word.
- Replace the toneClass field (which reused .ofstedGrade{N} / .rcGrade{N}
  badge classes and dragged in their backgrounds) with a clean tone enum
  ``teal | green | gold | coral | neutral``. The serif Ofsted heroStat
  picked up the badge background and rendered as a green box around
  "Report Card" — gone now.
- Hero chip backgrounds use color-mix() against the tone variable so all
  five tones share one rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Tudor Sitaru
2026-04-08 10:44:37 +01:00
parent c749d72a6a
commit 2d6e39eebc
3 changed files with 70 additions and 70 deletions
+41 -27
View File
@@ -423,59 +423,73 @@ function formatOfstedMonth(date: string | null | undefined): string {
return d.toLocaleDateString('en-GB', { month: 'long', year: 'numeric' });
}
export type HeroTone = 'teal' | 'green' | 'gold' | 'coral' | 'neutral';
export interface OfstedHeroChip {
state: 'oeif' | 'reportCard' | 'none';
title: string; // Main label (e.g. "Ofsted Outstanding", "Ofsted Report Card")
subtitle: string; // Context line (e.g. "Inspected November 2023")
detail?: string; // Optional extra line (e.g. "Safeguarding: Met")
toneClass: string; // CSS class key — matches .ofstedGrade{N} / .rcGrade{N} / neutral
tone: HeroTone; // Maps to dedicated hero tone classes (not badge classes)
}
/**
* Build the hero-strip Ofsted chip, branching on the inspection framework.
* Never synthesises a single overall grade for ReportCard schools.
*
* Note: the API may return ``framework`` as a literal string ``"NULL"`` for
* older inspections, so we explicitly only branch into the ReportCard layout
* when the value is exactly ``"ReportCard"``. Anything else with an
* ``overall_effectiveness`` score is treated as OEIF.
*/
export function buildOfstedHeroChip(ofsted: OfstedInspection | null | undefined): OfstedHeroChip {
if (!ofsted || !ofsted.framework) {
if (!ofsted) {
return {
state: 'none',
title: 'Ofsted pending',
subtitle: 'No inspection on record',
toneClass: 'heroChipNeutral',
tone: 'neutral',
};
}
const when = formatOfstedMonth(ofsted.inspection_date);
if (ofsted.framework === 'OEIF') {
const grade = ofsted.overall_effectiveness;
if (grade && OFSTED_OEIF_WORDS[grade]) {
return {
state: 'oeif',
title: `Ofsted ${OFSTED_OEIF_WORDS[grade]}`,
subtitle: when ? `Inspected ${when}` : 'Inspected',
toneClass: `ofstedGrade${grade}`,
};
}
// ReportCard branch — only if the API explicitly says so
if (ofsted.framework === 'ReportCard') {
const safeguarding = ofsted.rc_safeguarding_met;
return {
state: 'oeif',
title: 'Ofsted inspected',
subtitle: when ? `Inspected ${when}` : 'Inspection on record',
toneClass: 'heroChipNeutral',
state: 'reportCard',
title: 'Ofsted Report Card',
subtitle: when ? `Inspected ${when}` : 'New framework inspection',
detail:
safeguarding == null
? undefined
: safeguarding ? 'Safeguarding: Met' : 'Safeguarding: Not met',
tone: safeguarding === false ? 'coral' : 'green',
};
}
// Otherwise treat as OEIF (covers framework === 'OEIF', null, "NULL", etc.)
const grade = ofsted.overall_effectiveness;
if (grade && OFSTED_OEIF_WORDS[grade]) {
const oeifTone: HeroTone =
grade === 1 ? 'teal' :
grade === 2 ? 'green' :
grade === 3 ? 'gold' :
'coral';
return {
state: 'oeif',
title: `Ofsted ${OFSTED_OEIF_WORDS[grade]}`,
subtitle: when ? `Inspected ${when}` : 'Inspected',
tone: oeifTone,
};
}
// ReportCard — never fabricate an overall grade
const safeguarding = ofsted.rc_safeguarding_met;
return {
state: 'reportCard',
title: 'Ofsted Report Card',
subtitle: when ? `Inspected ${when}` : 'New framework inspection',
detail:
safeguarding == null
? undefined
: safeguarding ? 'Safeguarding: Met' : 'Safeguarding: Not met',
toneClass: safeguarding === false ? 'rcGrade5' : 'rcGrade2',
state: 'oeif',
title: 'Ofsted inspected',
subtitle: when ? `Inspected ${when}` : 'Inspection on record',
tone: 'neutral',
};
}