/** * Getting a place — admissions framed the way the expert review requires: * total applications are "named on N forms" (any preference rank, not * head-to-head), one consistent chip metric (first-preference success), * equal-preference and offers-vs-intake explanations up front. */ 'use client'; import { admissionsForPhase, summariseAdmissions } from '@/lib/compareLogic'; import type { ComparisonData, School } from '@/lib/types'; import { CHART_COLORS } from '@/lib/utils'; import { Cell, Chip, Measure, Section, SectionGrid, sectionStyles as s } from './sectionShared'; export function CompareAdmissions({ schools, data, isSecondary = false, }: { schools: School[]; data: Record; isSecondary?: boolean; }) { // Admissions rounds are phase-specific: an all-through school's Year 7 // round must never stand in for Reception on the primary tab (and vice // versa) — beside pure primaries it reads as Reception odds. const rows = schools.map((school) => admissionsForPhase(data[String(school.urn)], isSecondary)); const roundLabel = isSecondary ? 'Year 7' : 'Reception'; const anyData = rows.some(Boolean); const entryYear = rows.find(Boolean)?.year; const entryLabel = entryYear ? `September ${String(entryYear).slice(0, 4)} entry` : 'the most recent admissions round'; if (!anyData) { return (
<>
); } return (
From the most recent admissions round ({entryLabel}). "First choice" means families who ranked the school top of their application form — officially a "first preference". Schools never see your ranking: places are decided only by the school's admission criteria, so listing a school lower down never hurts your chances. These are National Offer Day offers — waiting lists and appeals can change the final intake. } > {schools.map((school, i) => { const a = rows[i]; return ( {a?.total_applications != null && a?.places_offered != null ? ( <> Named on {a.total_applications.toLocaleString('en-GB')} forms ·{' '} {a.places_offered.toLocaleString('en-GB')} places ) : ( We don't hold {roundLabel} admissions data for this school )} ); })} {schools.map((school, i) => { const summary = summariseAdmissions(rows[i]); return ( {summary.firstPrefPct != null ? ( <> {summary.firstPrefPct}%{' '} {summary.chip && summary.chip.tone === 'warn' && ( {summary.chip.text} )} ) : ( No data )} ); })} {schools.map((school, i) => { const a = rows[i]; const summary = summariseAdmissions(a); const info = data[String(school.urn)]?.school_info; const selective = (info?.admissions_policy ?? '').toLowerCase() === 'selective'; const faith = !!info?.religious_denomination && !/^(none|does not apply|not applicable)$/i.test(info.religious_denomination); let text: string | null = null; if (summary.firstPrefPct != null) { if (selective) { // Selective schools: the entrance test decides, whatever the // offer percentage looks like — never the distance template. text = 'Entry is by entrance test — the school is selective; distance and preference rank don’t decide places.'; } else if (summary.firstPrefPct >= 100) { text = `Every family who put ${school.school_name} first got a place.`; } else if (summary.firstPrefPct >= 90) { text = `Nearly every family who put ${school.school_name} first got a place.`; } else if (a?.oversubscribed) { text = isSecondary ? faith ? 'More first-choice applications than places — check the school’s admission criteria (faith-based criteria may apply).' : 'More first-choice applications than places — check the school’s admission criteria (catchment or distance often decides, but criteria vary).' : 'More first-choice applications than places — check the school’s admission criteria (for most non-faith primaries, distance decides).'; } else { text = `${summary.firstPrefPct}% of first-choice families received an offer.`; } } return ( {text ? {text} : } ); })}
); }