2026-08-02 21:39:21 +01:00
|
|
|
/**
|
|
|
|
|
* PrimarySchoolSections — the section sequence for primary and all-through
|
|
|
|
|
* detail pages. Server component.
|
|
|
|
|
*
|
|
|
|
|
* All-through schools route here rather than to SecondarySchoolSections,
|
|
|
|
|
* because this list renders BOTH the KS2 and KS4 blocks (ResultsSection and
|
|
|
|
|
* HistorySection branch on isAllThrough); the secondary list is KS4-only and
|
|
|
|
|
* would silently drop their SATs data.
|
|
|
|
|
*
|
|
|
|
|
* The render conditions here MUST match buildNavItems in lib/schoolSections,
|
|
|
|
|
* or the sticky nav will link to sections that do not exist.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import type {
|
|
|
|
|
School, SchoolResult, AbsenceData, OfstedInspection, SchoolCensus,
|
2026-08-15 22:48:30 +01:00
|
|
|
SchoolAdmissions, SchoolAdmissionDistance, SchoolDeprivation, SchoolFinance, NationalAverages,
|
2026-09-22 11:59:27 +01:00
|
|
|
NearbySchool,
|
2026-08-02 21:39:21 +01:00
|
|
|
} from '@/lib/types';
|
|
|
|
|
import { ofstedLegacyAreas } from '@/lib/utils';
|
|
|
|
|
import type { SchoolFlags } from '@/lib/schoolSections';
|
|
|
|
|
import { OfstedSection } from './OfstedSection';
|
|
|
|
|
import { ResultsSection } from './ResultsSection';
|
|
|
|
|
import { AdmissionsSection } from './AdmissionsSection';
|
2026-08-20 14:54:02 +01:00
|
|
|
import { DistanceSection } from './DistanceSection';
|
2026-08-02 21:39:21 +01:00
|
|
|
import { InclusionSection } from './InclusionSection';
|
|
|
|
|
import { HistorySection } from './HistorySection';
|
|
|
|
|
import { SchoolLifeSection } from './SchoolLifeSection';
|
|
|
|
|
import { LocalAreaSection } from './LocalAreaSection';
|
|
|
|
|
import { FinancesSection } from './FinancesSection';
|
2026-09-22 11:59:27 +01:00
|
|
|
import { NearbySchoolsSection } from './NearbySchoolsSection';
|
2026-08-02 21:39:21 +01:00
|
|
|
|
|
|
|
|
export interface PrimarySchoolSectionsProps {
|
|
|
|
|
schoolInfo: School;
|
|
|
|
|
yearlyData: SchoolResult[];
|
|
|
|
|
absenceData: AbsenceData | null;
|
|
|
|
|
ofsted: OfstedInspection | null;
|
|
|
|
|
census: SchoolCensus | null;
|
|
|
|
|
admissions: SchoolAdmissions | null;
|
|
|
|
|
admissionsHistory: SchoolAdmissions[];
|
2026-08-15 22:48:30 +01:00
|
|
|
admissionDistance: SchoolAdmissionDistance | null;
|
2026-08-02 21:39:21 +01:00
|
|
|
deprivation: SchoolDeprivation | null;
|
|
|
|
|
finance: SchoolFinance | null;
|
|
|
|
|
nationalAvg: NationalAverages | null;
|
2026-09-21 22:42:59 +01:00
|
|
|
/** Nearby schools of a comparable intake. Absent on an older API build. */
|
2026-09-22 11:59:27 +01:00
|
|
|
nearbySchools?: NearbySchool[];
|
2026-08-02 21:39:21 +01:00
|
|
|
flags: SchoolFlags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function PrimarySchoolSections({
|
|
|
|
|
schoolInfo, yearlyData, absenceData, ofsted, census,
|
2026-08-20 18:44:57 +01:00
|
|
|
admissions, admissionsHistory, admissionDistance,
|
2026-09-22 11:59:27 +01:00
|
|
|
deprivation, finance, nationalAvg, nearbySchools, flags,
|
2026-08-02 21:39:21 +01:00
|
|
|
}: PrimarySchoolSectionsProps) {
|
|
|
|
|
const primaryAvg = nationalAvg?.primary ?? {};
|
|
|
|
|
const secondaryAvg = nationalAvg?.secondary ?? {};
|
|
|
|
|
|
|
|
|
|
const isReportCard = !!(ofsted?.report_card && Object.keys(ofsted.report_card).length > 0);
|
|
|
|
|
// Report cards are dated by their own inspection (rc_inspection_date), never
|
|
|
|
|
// the legacy inspection_date (report cards exist only from Nov 2025).
|
|
|
|
|
const ofstedInspectedDate = isReportCard
|
|
|
|
|
? ofsted?.rc_inspection_date ?? null
|
|
|
|
|
: ofsted?.inspection_date ?? null;
|
|
|
|
|
const oeifAreas = ofsted ? ofstedLegacyAreas(ofsted) : [];
|
|
|
|
|
const oeifAllSameGrade =
|
|
|
|
|
!!ofsted &&
|
|
|
|
|
!isReportCard &&
|
|
|
|
|
oeifAreas.length >= 3 &&
|
|
|
|
|
oeifAreas.every((a) => a.value === ofsted.overall_effectiveness);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
{ofsted && (
|
|
|
|
|
<OfstedSection
|
|
|
|
|
ofsted={ofsted}
|
|
|
|
|
urn={schoolInfo.urn}
|
|
|
|
|
isReportCard={isReportCard}
|
|
|
|
|
ofstedInspectedDate={ofstedInspectedDate}
|
|
|
|
|
oeifAllSameGrade={oeifAllSameGrade}
|
|
|
|
|
oeifAreas={oeifAreas}
|
|
|
|
|
variant="primary"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{flags.hasAnyResults && flags.latestResults && (
|
|
|
|
|
<ResultsSection
|
|
|
|
|
latestResults={flags.latestResults}
|
|
|
|
|
schoolInfo={schoolInfo}
|
|
|
|
|
primaryAvg={primaryAvg}
|
|
|
|
|
secondaryAvg={secondaryAvg}
|
|
|
|
|
isAllThrough={flags.isAllThrough}
|
|
|
|
|
isSecondary={flags.isSecondary}
|
|
|
|
|
isSpecial={flags.isSpecial}
|
|
|
|
|
hasKS2Results={flags.hasKS2Results}
|
|
|
|
|
hasKS4Results={flags.hasKS4Results}
|
|
|
|
|
ks2Placeholder={flags.ks2Placeholder}
|
|
|
|
|
suppressKs2Comparison={flags.suppressKs2Comparison}
|
|
|
|
|
suppressKs4Comparison={flags.suppressKs4Comparison}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-08-15 22:48:30 +01:00
|
|
|
{/* Either source is enough to justify the section. The cut-off distance
|
|
|
|
|
and the EES admissions figures come from different places and a
|
|
|
|
|
minority of schools have one without the other — gating on admissions
|
|
|
|
|
alone would hide a published distance on those pages. */}
|
|
|
|
|
{(admissions || admissionDistance) && (
|
2026-08-02 21:39:21 +01:00
|
|
|
<AdmissionsSection
|
|
|
|
|
admissions={admissions}
|
|
|
|
|
admissionsHistory={admissionsHistory}
|
2026-08-15 22:48:30 +01:00
|
|
|
admissionDistance={admissionDistance}
|
2026-08-02 21:39:21 +01:00
|
|
|
isAllThrough={flags.isAllThrough}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-08-20 14:54:02 +01:00
|
|
|
{/* Its own section, directly after Admissions: it answers the question
|
|
|
|
|
the tile above raises. */}
|
2026-08-20 18:44:57 +01:00
|
|
|
<DistanceSection admissionDistance={admissionDistance} schoolInfo={schoolInfo} />
|
2026-08-20 14:54:02 +01:00
|
|
|
|
2026-08-02 21:39:21 +01:00
|
|
|
{flags.hasInclusionData && (
|
|
|
|
|
<InclusionSection
|
|
|
|
|
latestResults={flags.latestResults}
|
|
|
|
|
census={census}
|
|
|
|
|
hasGenderSplit={flags.hasGenderSplit}
|
|
|
|
|
primaryAvg={primaryAvg}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{yearlyData.length > 0 && (
|
|
|
|
|
<HistorySection
|
|
|
|
|
yearlyData={yearlyData}
|
|
|
|
|
schoolInfo={schoolInfo}
|
|
|
|
|
nationalAvg={nationalAvg}
|
|
|
|
|
primaryAvg={primaryAvg}
|
|
|
|
|
secondaryAvg={secondaryAvg}
|
|
|
|
|
isAllThrough={flags.isAllThrough}
|
|
|
|
|
isPrimary={flags.isPrimary}
|
|
|
|
|
isSecondary={flags.isSecondary}
|
|
|
|
|
hasKS2Results={flags.hasKS2Results}
|
|
|
|
|
hasKS4Results={flags.hasKS4Results}
|
|
|
|
|
suppressKs2Comparison={flags.suppressKs2Comparison}
|
|
|
|
|
suppressKs4Comparison={flags.suppressKs4Comparison}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{flags.hasSchoolLife && (
|
|
|
|
|
<SchoolLifeSection absenceData={absenceData} primaryAvg={primaryAvg} />
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{flags.hasDeprivation && deprivation && (
|
|
|
|
|
<LocalAreaSection deprivation={deprivation} />
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{flags.hasFinance && finance && <FinancesSection finance={finance} />}
|
2026-09-21 22:42:59 +01:00
|
|
|
|
|
|
|
|
{/* Last: it is where the reader goes next, not part of this school. */}
|
2026-09-22 11:59:27 +01:00
|
|
|
<NearbySchoolsSection
|
2026-09-21 22:42:59 +01:00
|
|
|
urn={schoolInfo.urn}
|
|
|
|
|
schoolName={schoolInfo.school_name}
|
2026-09-22 06:41:49 +01:00
|
|
|
phase={schoolInfo.phase}
|
2026-09-21 22:42:59 +01:00
|
|
|
thisMetricValue={flags.latestResults?.rwm_expected_pct ?? null}
|
2026-09-22 11:59:27 +01:00
|
|
|
nearby={nearbySchools}
|
2026-09-21 22:42:59 +01:00
|
|
|
/>
|
2026-08-02 21:39:21 +01:00
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|