diff --git a/nextjs-app/__tests__/components/SchoolRow.test.tsx b/nextjs-app/__tests__/components/SchoolRow.test.tsx index dcdab0e..1911d31 100644 --- a/nextjs-app/__tests__/components/SchoolRow.test.tsx +++ b/nextjs-app/__tests__/components/SchoolRow.test.tsx @@ -34,3 +34,21 @@ describe('SchoolRow religious character', () => { expect(screen.getByText('Church of England')).toBeInTheDocument(); }); }); + +describe('SchoolRow shares the school page flags', () => { + it("prints the type in the search filter's terms", () => { + render(); + expect(screen.getByText('State school')).toBeInTheDocument(); + expect(screen.queryByText('Free schools')).not.toBeInTheDocument(); + }); + + it('flags a nursery class', () => { + render(); + expect(screen.getByText('Nursery class')).toBeInTheDocument(); + }); + + it("flags a boys' school", () => { + render(); + expect(screen.getByText("Boys' school")).toBeInTheDocument(); + }); +}); diff --git a/nextjs-app/__tests__/components/SecondarySchoolRow.test.tsx b/nextjs-app/__tests__/components/SecondarySchoolRow.test.tsx index e3a25ac..9503a84 100644 --- a/nextjs-app/__tests__/components/SecondarySchoolRow.test.tsx +++ b/nextjs-app/__tests__/components/SecondarySchoolRow.test.tsx @@ -79,7 +79,7 @@ describe('SecondarySchoolRow admissions tag', () => { expect(screen.queryByText('Selective')).not.toBeInTheDocument(); }); - it.each(['None', 'Does not apply', '', null])( + it.each(['None', 'Does not apply'])( 'gives no faith tag when the religious character is %p', (religious_denomination) => { render( @@ -87,16 +87,32 @@ describe('SecondarySchoolRow admissions tag', () => { school={{ ...base, admissions_policy: 'Not applicable', religious_denomination }} />, ); + expect(screen.queryByText(religious_denomination)).not.toBeInTheDocument(); expect(screen.queryByText('Faith priority')).not.toBeInTheDocument(); }, ); - it('tags a school with a religious character', () => { + it('tags the religious character the register records, not "Faith priority"', () => { render( , ); - expect(screen.getByText('Faith priority')).toBeInTheDocument(); + expect(screen.getByText('Church of England')).toBeInTheDocument(); + expect(screen.queryByText('Faith priority')).not.toBeInTheDocument(); + }); +}); + +describe('SecondarySchoolRow shares the school page flags', () => { + it("prints the type in the search filter's terms", () => { + render(); + expect(screen.getByText('State school')).toBeInTheDocument(); + expect(screen.queryByText('Academy')).not.toBeInTheDocument(); + }); + + it("flags a girls' school and fees", () => { + render(); + expect(screen.getByText("Girls' school")).toBeInTheDocument(); + expect(screen.getByText('Fee-paying')).toBeInTheDocument(); }); }); diff --git a/nextjs-app/components/SchoolRow.module.css b/nextjs-app/components/SchoolRow.module.css index ce61578..4348519 100644 --- a/nextjs-app/components/SchoolRow.module.css +++ b/nextjs-app/components/SchoolRow.module.css @@ -100,6 +100,19 @@ color: var(--text-secondary); } +/* Changes who can apply or what it costs. Outlined, not tinted: a fact, not + a verdict. An inset ring keeps the box the size of its neighbours. */ +.conditionTag { + display: inline-block; + padding: 0.0625rem 0.4rem; + font-size: 0.75rem; + font-weight: 600; + line-height: 1.4; + border-radius: 4px; + box-shadow: inset 0 0 0 1px rgba(var(--ink-rgb), 0.4); + color: var(--text-primary); +} + /* Line 3: stats */ .line3 { display: flex; diff --git a/nextjs-app/components/SchoolRow.tsx b/nextjs-app/components/SchoolRow.tsx index fe167b0..f250975 100644 --- a/nextjs-app/components/SchoolRow.tsx +++ b/nextjs-app/components/SchoolRow.tsx @@ -3,13 +3,14 @@ * Four-line row for primary school search results * * Line 1: School name · Ofsted badge (framework-aware) - * Line 2: School type · Age range · Denomination · Gender + * Line 2: Phase · Type · Age range · the school page's flags (lib/schoolFacts) * Line 3: Reading, Writing & Maths % · trend arrow · vs-national delta · Pupils * Line 4: Local authority · Distance */ import type { School } from '@/lib/types'; -import { formatPercentage, calculateTrend, getPhaseStyle, schoolUrl, buildOfstedListBadge, formatAgeRange, hasReligiousCharacter, isProposedToClose, isSpecialSchool, listRwmValue } from '@/lib/utils'; +import { formatPercentage, calculateTrend, getPhaseStyle, schoolUrl, buildOfstedListBadge, formatAgeRange, isProposedToClose, isSpecialSchool, listRwmValue } from '@/lib/utils'; +import { schoolFlags, schoolTypeLabel } from '@/lib/schoolFacts'; import styles from './SchoolRow.module.css'; interface SchoolRowProps { @@ -33,8 +34,8 @@ export function SchoolRow({ const phase = getPhaseStyle(school.phase); const ofstedBadge = buildOfstedListBadge(school); - const showGender = school.gender && school.gender.toLowerCase() !== 'mixed'; - const showDenomination = hasReligiousCharacter(school.religious_denomination); + const typeLabel = schoolTypeLabel(school); + const flags = schoolFlags(school); // The school's OWN figure and its year-over-year trend are same-school // measures — shown whenever there's a real value (not the all-zero @@ -77,10 +78,16 @@ export function SchoolRow({ {phase.label} )} - {school.school_type && {school.school_type}} + {typeLabel && {typeLabel}} {school.age_range && {formatAgeRange(school.age_range)}} - {showDenomination && {school.religious_denomination}} - {showGender && {school.gender}} + {flags.map((flag) => ( + + {flag.label} + + ))} {isProposedToClose(school) && ( ⚠ Proposed to close )} diff --git a/nextjs-app/components/SecondarySchoolRow.module.css b/nextjs-app/components/SecondarySchoolRow.module.css index 2c82faa..1031f4c 100644 --- a/nextjs-app/components/SecondarySchoolRow.module.css +++ b/nextjs-app/components/SecondarySchoolRow.module.css @@ -183,9 +183,17 @@ white-space: nowrap; } -.selectiveTag { - background: rgba(var(--status-below-rgb), 0.1); - color: var(--status-below); +/* Changes who can apply or what it costs. Outlined, not tinted: a fact, not + a verdict. An inset ring keeps the box the size of its neighbours. */ +.conditionTag { + display: inline-block; + padding: 0.0625rem 0.4rem; + font-size: 0.75rem; + font-weight: 600; + line-height: 1.4; + border-radius: 4px; + box-shadow: inset 0 0 0 1px rgba(var(--ink-rgb), 0.4); + color: var(--text-primary); } /* ── Ofsted badge ────────────────────────────────────── */ diff --git a/nextjs-app/components/SecondarySchoolRow.tsx b/nextjs-app/components/SecondarySchoolRow.tsx index 762937d..2c5181e 100644 --- a/nextjs-app/components/SecondarySchoolRow.tsx +++ b/nextjs-app/components/SecondarySchoolRow.tsx @@ -3,7 +3,7 @@ * Four-line row for secondary school search results * * Line 1: School name · Ofsted badge - * Line 2: School type · Age range · Gender · Sixth form · Admissions tag + * Line 2: Phase · Type · Age range · the school page's flags (lib/schoolFacts) * Line 3: Attainment 8 (large) · ±LA avg delta · Pupils * Line 4: LA name · distance */ @@ -11,22 +11,10 @@ 'use client'; import type { School } from '@/lib/types'; -import { buildOfstedListBadge, getPhaseStyle, schoolUrl, formatAgeRange, hasReligiousCharacter, isProposedToClose, isSpecialSchool } from '@/lib/utils'; +import { buildOfstedListBadge, getPhaseStyle, schoolUrl, formatAgeRange, isProposedToClose, isSpecialSchool } from '@/lib/utils'; +import { schoolFlags, schoolTypeLabel } from '@/lib/schoolFacts'; import styles from './SecondarySchoolRow.module.css'; -function detectAdmissionsTag(school: School): string | null { - // Exact match: "Non-selective" contains "selective", so a substring test - // tagged every comprehensive as Selective. - if (school.admissions_policy?.trim().toLowerCase() === 'selective') return 'Selective'; - if (hasReligiousCharacter(school.religious_denomination)) return 'Faith priority'; - return null; -} - -function hasSixthForm(school: School): boolean { - // GIAS OfficialSixthForm flag; missing (pipeline not yet re-run) => false. - return school.has_sixth_form ?? false; -} - interface SecondarySchoolRowProps { school: School; isLocationSearch?: boolean; @@ -64,9 +52,8 @@ export function SecondarySchoolRow({ ? att8 - laAvgAttainment8 : null; - const admissionsTag = detectAdmissionsTag(school); - const sixthForm = hasSixthForm(school); - const showGender = school.gender && school.gender.toLowerCase() !== 'mixed'; + const typeLabel = schoolTypeLabel(school); + const flags = schoolFlags(school); return (
@@ -90,19 +77,16 @@ export function SecondarySchoolRow({ {phase.label} )} - {school.school_type && {school.school_type}} + {typeLabel && {typeLabel}} {school.age_range && {formatAgeRange(school.age_range)}} - {showGender && ( - {school.gender} - )} - {sixthForm && ( - Sixth form - )} - {admissionsTag && ( - - {admissionsTag} + {flags.map((flag) => ( + + {flag.label} - )} + ))} {isProposedToClose(school) && ( ⚠ Proposed to close )}