PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m14s
PR Checks / Backend Smoke (pull_request) Successful in 10s
PR Checks / Build Backend (no push) (pull_request) Successful in 19s
PR Checks / Build Frontend (no push) (pull_request) Successful in 1m19s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 11s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 1m20s
Rewrites every visitor-facing string that used an em dash, choosing the punctuation for what the dash was doing: a colon before a list or explanation, a comma for an aside, a full stop between two thoughts, parentheses for an aside mid-sentence. Covers page titles and meta descriptions, the home and admissions guide copy, school page headings and notes, the compare page, metric labels and tooltips. Two rewrites also fix the sentence around them: the closure banner no longer repeats "proposed for closure", and the cut-off caveat's list of priorities now parses. A lone dash marking a missing value in a table cell stays: it is a data convention, not prose. A Jest guard walks the source with the TypeScript parser and fails on any other em dash in a string or JSX text node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
123 lines
5.3 KiB
TypeScript
123 lines
5.3 KiB
TypeScript
/**
|
|
* 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.
|
|
*/
|
|
|
|
import type { School, SchoolAdmissions, SchoolAdmissionDistance } from '@/lib/types';
|
|
import { formatPercentage } from '@/lib/utils';
|
|
import { Section, sectionStyles as styles } from './sectionShared';
|
|
import {
|
|
describeCutoff, describeCutoffAbsence,
|
|
CUTOFF_NOTE, CUTOFF_MEASUREMENT_NOTE,
|
|
} from './lastDistanceOffered';
|
|
|
|
export function SecondaryAdmissionsSection({
|
|
admissions, admissionsHistory, admissionDistance, schoolInfo,
|
|
}: {
|
|
/* 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;
|
|
admissionsHistory: SchoolAdmissions[];
|
|
admissionDistance: SchoolAdmissionDistance | null | undefined;
|
|
schoolInfo: School;
|
|
}) {
|
|
const cutoff = describeCutoff(admissionDistance);
|
|
/* 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;
|
|
// Moved with this section from SecondarySchoolDetailView, its only consumer.
|
|
const admissionsTag = (() => {
|
|
const policy = schoolInfo.admissions_policy?.toLowerCase() ?? '';
|
|
if (policy.includes('selective')) return 'Selective';
|
|
const denom = schoolInfo.religious_denomination ?? '';
|
|
if (denom && denom !== 'Does not apply') return 'Faith priority';
|
|
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}`}>
|
|
<strong>{admissionsTag}:</strong>{' '}
|
|
{admissionsTag === 'Selective'
|
|
? 'entry to this school is by selective examination (e.g. 11+).'
|
|
: `this school has a faith-based admissions priority (${schoolInfo.religious_denomination}).`}
|
|
</div>
|
|
)}
|
|
|
|
<div className={styles.metricsGrid}>
|
|
{admissions?.places_offered != null && (
|
|
<div className={styles.metricCard}>
|
|
<div className={styles.metricLabel}>Year 7 places offered</div>
|
|
<div className={styles.metricValue}>{admissions.places_offered}</div>
|
|
</div>
|
|
)}
|
|
{admissions?.total_applications != null && (
|
|
<div className={styles.metricCard}>
|
|
<div className={styles.metricLabel}>Total applications</div>
|
|
<div className={styles.metricValue}>{admissions.total_applications.toLocaleString()}</div>
|
|
</div>
|
|
)}
|
|
{admissions?.first_preference_applications != null && (
|
|
<div className={styles.metricCard}>
|
|
<div className={styles.metricLabel}>1st preference applications</div>
|
|
<div className={styles.metricValue}>{admissions.first_preference_applications.toLocaleString()}</div>
|
|
</div>
|
|
)}
|
|
{admissions?.first_preference_offer_pct != null && (
|
|
<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>
|
|
)}
|
|
{cutoff && (
|
|
<div className={`${styles.metricCard} ${styles.metricCardDistance}`}>
|
|
<div className={styles.metricLabel}>
|
|
Last distance offered · {cutoff.entryYear}
|
|
</div>
|
|
<div className={styles.metricValue}>
|
|
{cutoff.primary}{' '}
|
|
<span className={styles.metricValueSub}>{cutoff.secondary}</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
{admissions?.oversubscribed != null && (
|
|
<div className={`${styles.admissionsBadge} ${admissions.oversubscribed ? styles.statusWarn : styles.statusGood}`}>
|
|
{admissions.oversubscribed
|
|
? '⚠ Applications exceeded places last year'
|
|
: '✓ Places were available last year'}
|
|
</div>
|
|
)}
|
|
|
|
{/* 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>
|
|
) : featureOn ? (
|
|
<p className={styles.sectionSubtitle} style={{ marginTop: '1rem' }}>
|
|
{describeCutoffAbsence({
|
|
localAuthority: schoolInfo.local_authority,
|
|
admissionsPolicy: schoolInfo.admissions_policy,
|
|
admissionsHistory,
|
|
})}
|
|
</p>
|
|
) : null}
|
|
|
|
</section>
|
|
);
|
|
}
|