2026-07-13 23:49:17 +01:00
/**
* Who goes there — the school's community from the latest census plus GIAS
* facts. Benchmark chips use the computed state-school averages and must
* carry their provenance wording (never "England average" for computed
* figures). Copy verbatim from the reviewed mockups.
*/
'use client' ;
import { verdict } from '@/lib/compareLogic' ;
import type { Benchmarks , ComparisonData , School } from '@/lib/types' ;
2026-07-15 07:50:01 +01:00
import { Cell , Chip , Measure , Section , SectionGrid , sectionStyles as s } from './sectionShared' ;
2026-07-13 23:49:17 +01:00
function pctSplit ( part : number | null | undefined , total : number | null | undefined ) : string | null {
if ( part == null || total == null || total === 0 ) return null ;
return ` ${ Math . round (( part / total ) * 100 ) } %` ;
}
export function CompareCommunity ({
schools ,
data ,
benchmarks ,
} : {
schools : School [];
data : Record < string , ComparisonData >;
benchmarks? : Benchmarks ;
}) {
const isSecondary = schools . some (
( school ) => data [ String ( school . urn )] ? . school_info ? . attainment_8_score != null ,
);
const bench = isSecondary ? benchmarks?.secondary : benchmarks?.primary ;
const fsmChip = ( value : number | null ) => {
if ( value == null || bench ? . disadvantaged_pct == null ) return null ;
const v = verdict ( value , bench . disadvantaged_pct , 3 );
return (
< Chip tone = "neutral" >
{ v === 'above' && 'Above the state-school average' }
{ v === 'close' && 'About the state-school average' }
{ v === 'below' && 'Below the state-school average' }
</ Chip >
);
};
return (
< Section
title = "Who goes there"
how = "The school's community, from the latest school census. State-school averages are computed from our dataset and shown for context — there's no “right” number here."
>
< SectionGrid schools = { schools }>
2026-07-15 07:50:01 +01:00
< Measure label = "Pupils on roll" >
2026-07-13 23:49:17 +01:00
{ schools . map (( school , i ) => {
const info = data [ String ( school . urn )] ? . school_info as ( School & { gias_total_pupils? : number | null ; capacity? : number | null }) | undefined ;
const census = data [ String ( school . urn )] ? . census ;
const pupils = census ? . total_pupils ?? info ? . gias_total_pupils ?? null ;
const capacity = info ? . capacity ?? null ;
let capNote : string | null = null ;
if ( pupils != null && capacity != null && capacity > 0 ) {
capNote =
pupils >= capacity
? ` ${ capacity . toLocaleString ( 'en-GB' ) } places — at or above capacity`
: `of ${ capacity . toLocaleString ( 'en-GB' ) } places ( ${ Math . round (( pupils / capacity ) * 100 ) } % full)` ;
}
return (
< Cell key = { school . urn } school = { school } index = { i }>
{ pupils != null ? (
<>
{ pupils . toLocaleString ( 'en-GB' )}
{ capNote && < span className = { s . small }>{ capNote }</ span >}
</>
) : (
< span className = { s . small }> No data </ span >
)}
</ Cell >
);
})}
2026-07-15 07:50:01 +01:00
</ Measure >
2026-07-13 23:49:17 +01:00
2026-07-15 07:50:01 +01:00
< Measure label = "Girls / boys" >
2026-07-13 23:49:17 +01:00
{ schools . map (( school , i ) => {
const census = data [ String ( school . urn )] ? . census ;
const girls = pctSplit ( census ? . female_pupils , census ? . total_pupils );
const boys = pctSplit ( census ? . male_pupils , census ? . total_pupils );
return (
< Cell key = { school . urn } school = { school } index = { i }>
{ girls && boys ? ` ${ girls } / ${ boys } ` : < span className = { s . small }> No data </ span >}
</ Cell >
);
})}
2026-07-15 07:50:01 +01:00
</ Measure >
2026-07-13 23:49:17 +01:00
2026-07-15 07:50:01 +01:00
< Measure
tip = "% of pupils eligible for free school meals — a common measure of how many pupils come from lower-income families. Benchmark computed across state schools in our dataset."
label = "Free school meals"
>
2026-07-13 23:49:17 +01:00
{ schools . map (( school , i ) => {
const fsm = data [ String ( school . urn )] ? . census ? . fsm_pct ?? null ;
return (
< Cell key = { school . urn } school = { school } index = { i }>
{ fsm != null ? (
<>
{ Math . round ( fsm )} % { fsmChip ( fsm )}
</>
) : (
< span className = { s . small }> No data </ span >
)}
</ Cell >
);
})}
2026-07-15 07:50:01 +01:00
</ Measure >
2026-07-13 23:49:17 +01:00
2026-07-15 07:50:01 +01:00
< Measure
tip = "% of pupils whose first language is known or believed to be other than English. State-school average computed from our dataset."
label = "English as an additional language"
>
2026-07-13 23:49:17 +01:00
{ schools . map (( school , i ) => {
const eal = data [ String ( school . urn )] ? . census ? . eal_pct ?? null ;
return (
< Cell key = { school . urn } school = { school } index = { i }>
{ eal != null ? ` ${ Math . round ( eal ) } %` : < span className = { s . small }> No data </ span >}
</ Cell >
);
})}
2026-07-15 07:50:01 +01:00
</ Measure >
2026-07-13 23:49:17 +01:00
2026-07-15 07:50:01 +01:00
< Measure
tip = "% of pupils receiving SEN support (not including EHC plans). A high figure can mean the school hosts specialist provision — often a strength, not a warning sign. State-school average computed from our dataset."
label = "Extra learning support (SEN)"
>
2026-07-13 23:49:17 +01:00
{ schools . map (( school , i ) => {
const rows = data [ String ( school . urn )] ? . yearly_data ?? [];
let sen : number | null = null ;
for ( let r = rows . length - 1 ; r >= 0 ; r -- ) {
if ( rows [ r ]. sen_support_pct != null ) {
sen = rows [ r ]. sen_support_pct ;
break ;
}
}
const high =
sen != null && bench ? . sen_support_pct != null && sen >= bench . sen_support_pct * 1.75 ;
return (
< Cell key = { school . urn } school = { school } index = { i }>
{ sen != null ? (
<>
{ Math . round ( sen )} % { high && < Chip tone = "neutral" > Well above average </ Chip >}
</>
) : (
< span className = { s . small }> No data </ span >
)}
</ Cell >
);
})}
2026-07-15 07:50:01 +01:00
</ Measure >
2026-07-13 23:49:17 +01:00
2026-07-15 07:50:01 +01:00
< Measure label = "Faith character" >
2026-07-13 23:49:17 +01:00
{ schools . map (( school , i ) => {
const info = data [ String ( school . urn )] ? . school_info ;
const faith = info ? . religious_denomination ;
const none = ! faith || faith === 'Does not apply' || faith === 'None' ;
return (
< Cell key = { school . urn } school = { school } index = { i }>
{ none ? 'None' : faith }
</ Cell >
);
})}
2026-07-15 07:50:01 +01:00
</ Measure >
2026-07-13 23:49:17 +01:00
2026-07-15 07:50:01 +01:00
< Measure label = "Ages" >
2026-07-13 23:49:17 +01:00
{ schools . map (( school , i ) => {
const info = data [ String ( school . urn )] ? . school_info ;
return (
< Cell key = { school . urn } school = { school } index = { i }>
{ info ? . age_range || < span className = { s . small }> No data </ span >}
</ Cell >
);
})}
2026-07-15 07:50:01 +01:00
</ Measure >
2026-07-13 23:49:17 +01:00
2026-07-15 07:50:01 +01:00
< Measure label = "Run by" >
2026-07-13 23:49:17 +01:00
{ schools . map (( school , i ) => {
const info = data [ String ( school . urn )] ? . school_info ;
const trust = info ? . trust_name ;
const la = info ? . local_authority ?? school . local_authority ;
return (
< Cell key = { school . urn } school = { school } index = { i }>
{ trust ? trust : la ? ` ${ la } council` : < span className = { s . small }> No data </ span >}
</ Cell >
);
})}
2026-07-15 07:50:01 +01:00
</ Measure >
2026-07-13 23:49:17 +01:00
</ SectionGrid >
</ Section >
);
}