2026-08-02 21:33:28 +01:00
|
|
|
/**
|
|
|
|
|
* SecondaryAdmissionsSection — secondary pages.
|
|
|
|
|
*
|
|
|
|
|
* Not shared with the primary AdmissionsSection: the two were only 14%
|
|
|
|
|
* similar. This one has no year/trend toggle, so it ships no client
|
|
|
|
|
* JavaScript at all. Server component.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-08-15 22:48:30 +01:00
|
|
|
import type { School, SchoolAdmissions, SchoolAdmissionDistance } from '@/lib/types';
|
2026-10-02 23:43:43 +01:00
|
|
|
import { formatPercentage, hasReligiousCharacter, isSelective } from '@/lib/utils';
|
2026-08-02 21:33:28 +01:00
|
|
|
import { Section, sectionStyles as styles } from './sectionShared';
|
2026-08-16 13:42:06 +01:00
|
|
|
import {
|
2026-08-20 14:54:02 +01:00
|
|
|
describeCutoff, describeCutoffAbsence,
|
2026-08-16 13:42:06 +01:00
|
|
|
CUTOFF_NOTE, CUTOFF_MEASUREMENT_NOTE,
|
|
|
|
|
} from './lastDistanceOffered';
|
2026-08-02 21:33:28 +01:00
|
|
|
|
|
|
|
|
export function SecondaryAdmissionsSection({
|
2026-08-28 16:15:21 +01:00
|
|
|
admissions, admissionsHistory, admissionDistance, schoolInfo,
|
2026-08-02 21:33:28 +01:00
|
|
|
}: {
|
2026-08-15 22:48:30 +01:00
|
|
|
/* Nullable for the same reason as the primary section: a school can have a
|
|
|
|
|
published cut-off and no EES admissions row. */
|
|
|
|
|
admissions: SchoolAdmissions | null;
|
2026-08-16 13:42:06 +01:00
|
|
|
admissionsHistory: SchoolAdmissions[];
|
2026-08-27 21:17:16 +01:00
|
|
|
admissionDistance: SchoolAdmissionDistance | null | undefined;
|
2026-08-02 21:33:28 +01:00
|
|
|
schoolInfo: School;
|
|
|
|
|
}) {
|
2026-08-15 22:48:30 +01:00
|
|
|
const cutoff = describeCutoff(admissionDistance);
|
2026-08-27 21:17:16 +01:00
|
|
|
/* Absent means cut-offs are not being published at all; null means this
|
|
|
|
|
school has no published cut-off. Only the second is a fact about the
|
|
|
|
|
school, and only the second can be stated. Saying "X has not published a
|
|
|
|
|
cut-off" while the feature is dark describes us, and is false wherever the
|
|
|
|
|
authority does publish one. */
|
|
|
|
|
const featureOn = admissionDistance !== undefined;
|
2026-08-02 21:33:28 +01:00
|
|
|
// Moved with this section from SecondarySchoolDetailView, its only consumer.
|
|
|
|
|
const admissionsTag = (() => {
|
2026-10-02 23:43:43 +01:00
|
|
|
if (isSelective(schoolInfo.admissions_policy)) return 'Selective';
|
|
|
|
|
if (hasReligiousCharacter(schoolInfo.religious_denomination)) return 'Faith priority';
|
2026-08-02 21:33:28 +01:00
|
|
|
return null;
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<section id="admissions" className={styles.card}>
|
|
|
|
|
<h2 className={styles.sectionTitle}>Admissions</h2>
|
|
|
|
|
|
|
|
|
|
{admissionsTag && (
|
|
|
|
|
<div className={`${styles.admissionsTypeBadge} ${admissionsTag === 'Selective' ? styles.admissionsSelective : styles.admissionsFaith}`}>
|
2026-09-24 22:04:27 +01:00
|
|
|
<strong>{admissionsTag}:</strong>{' '}
|
2026-08-02 21:33:28 +01:00
|
|
|
{admissionsTag === 'Selective'
|
2026-09-24 22:04:27 +01:00
|
|
|
? 'entry to this school is by selective examination (e.g. 11+).'
|
|
|
|
|
: `this school has a faith-based admissions priority (${schoolInfo.religious_denomination}).`}
|
2026-08-02 21:33:28 +01:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<div className={styles.metricsGrid}>
|
2026-08-15 22:48:30 +01:00
|
|
|
{admissions?.places_offered != null && (
|
2026-08-02 21:33:28 +01:00
|
|
|
<div className={styles.metricCard}>
|
|
|
|
|
<div className={styles.metricLabel}>Year 7 places offered</div>
|
|
|
|
|
<div className={styles.metricValue}>{admissions.places_offered}</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-08-15 22:48:30 +01:00
|
|
|
{admissions?.total_applications != null && (
|
2026-08-02 21:33:28 +01:00
|
|
|
<div className={styles.metricCard}>
|
|
|
|
|
<div className={styles.metricLabel}>Total applications</div>
|
|
|
|
|
<div className={styles.metricValue}>{admissions.total_applications.toLocaleString()}</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-08-15 22:48:30 +01:00
|
|
|
{admissions?.first_preference_applications != null && (
|
2026-08-02 21:33:28 +01:00
|
|
|
<div className={styles.metricCard}>
|
|
|
|
|
<div className={styles.metricLabel}>1st preference applications</div>
|
|
|
|
|
<div className={styles.metricValue}>{admissions.first_preference_applications.toLocaleString()}</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-08-15 22:48:30 +01:00
|
|
|
{admissions?.first_preference_offer_pct != null && (
|
2026-08-02 21:33:28 +01:00
|
|
|
<div className={styles.metricCard}>
|
|
|
|
|
<div className={styles.metricLabel}>Families who got their first choice</div>
|
|
|
|
|
<div className={styles.metricValue}>{formatPercentage(admissions.first_preference_offer_pct)}</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-08-15 22:48:30 +01:00
|
|
|
{cutoff && (
|
|
|
|
|
<div className={`${styles.metricCard} ${styles.metricCardDistance}`}>
|
|
|
|
|
<div className={styles.metricLabel}>
|
|
|
|
|
Last distance offered · {cutoff.entryYear}
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles.metricValue}>
|
2026-08-20 21:01:28 +01:00
|
|
|
{cutoff.primary}{' '}
|
2026-08-15 22:48:30 +01:00
|
|
|
<span className={styles.metricValueSub}>{cutoff.secondary}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-08-02 21:33:28 +01:00
|
|
|
</div>
|
2026-08-15 22:48:30 +01:00
|
|
|
{admissions?.oversubscribed != null && (
|
2026-08-02 21:33:28 +01:00
|
|
|
<div className={`${styles.admissionsBadge} ${admissions.oversubscribed ? styles.statusWarn : styles.statusGood}`}>
|
|
|
|
|
{admissions.oversubscribed
|
|
|
|
|
? '⚠ Applications exceeded places last year'
|
|
|
|
|
: '✓ Places were available last year'}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-08-15 22:48:30 +01:00
|
|
|
{/* Replaces a blanket "distance cut-off data is not available for this
|
|
|
|
|
school", which was hardcoded onto every secondary page and was untrue
|
|
|
|
|
wherever the local authority does publish. The absence is now stated
|
|
|
|
|
only when it is real, and names the authority that would hold it. */}
|
|
|
|
|
{cutoff ? (
|
|
|
|
|
<p className={styles.admissionsDistanceNote}>
|
|
|
|
|
{CUTOFF_NOTE} {CUTOFF_MEASUREMENT_NOTE}
|
|
|
|
|
{cutoff.routeNote && <> {cutoff.routeNote}</>}
|
|
|
|
|
</p>
|
2026-08-27 21:17:16 +01:00
|
|
|
) : featureOn ? (
|
2026-08-15 22:48:30 +01:00
|
|
|
<p className={styles.sectionSubtitle} style={{ marginTop: '1rem' }}>
|
2026-08-16 13:42:06 +01:00
|
|
|
{describeCutoffAbsence({
|
|
|
|
|
localAuthority: schoolInfo.local_authority,
|
|
|
|
|
admissionsPolicy: schoolInfo.admissions_policy,
|
|
|
|
|
admissionsHistory,
|
|
|
|
|
})}
|
2026-08-15 22:48:30 +01:00
|
|
|
</p>
|
2026-08-27 21:17:16 +01:00
|
|
|
) : null}
|
2026-08-02 21:33:28 +01:00
|
|
|
|
|
|
|
|
</section>
|
|
|
|
|
);
|
|
|
|
|
}
|