2026-10-02 22:59:45 +01:00
|
|
|
/**
|
|
|
|
|
* The facts the school header and the search rows print, so a parent reads
|
|
|
|
|
* the same words in the list and on the page.
|
|
|
|
|
*
|
|
|
|
|
* Every value comes from one register field. Nothing is inferred or explained
|
|
|
|
|
* inline, and a missing field prints nothing.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import type { School } from './types';
|
2026-10-02 23:43:43 +01:00
|
|
|
import { hasNurseryClasses, hasReligiousCharacter, isSelective, singleSexLabel } from './utils';
|
2026-10-02 22:59:45 +01:00
|
|
|
|
|
|
|
|
/** The search filter's type groups (backend/school_groups.py), without its
|
|
|
|
|
* parenthesised notes: fees have a flag of their own. */
|
|
|
|
|
const TYPE_GROUP_LABELS: Record<string, string> = {
|
|
|
|
|
state: 'State school',
|
|
|
|
|
independent: 'Independent school',
|
|
|
|
|
special: 'Special school (SEND)',
|
|
|
|
|
post16: 'Sixth form or college',
|
|
|
|
|
alternative: 'Alternative provision',
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** The school's type in the search filter's terms, or the register's own name
|
|
|
|
|
* for a type in no group (secure units, online providers). */
|
|
|
|
|
export function schoolTypeLabel(school: Pick<School, 'type_group' | 'school_type'>): string | null {
|
|
|
|
|
const grouped = school.type_group ? TYPE_GROUP_LABELS[school.type_group] : undefined;
|
|
|
|
|
return grouped ?? (school.school_type?.trim() || null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** "condition": changes who can apply or what it costs.
|
|
|
|
|
* "provision": what the school offers. */
|
|
|
|
|
export type SchoolFlagKind = 'condition' | 'provision';
|
|
|
|
|
|
|
|
|
|
export interface SchoolFlag {
|
|
|
|
|
label: string;
|
|
|
|
|
kind: SchoolFlagKind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type FlagFields = Pick<
|
|
|
|
|
School,
|
|
|
|
|
'type_group' | 'admissions_policy' | 'gender' | 'religious_denomination'
|
|
|
|
|
| 'nursery_provision' | 'has_sixth_form' | 'phase'
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Flags for what applies, in a fixed order: conditions first, then provision.
|
|
|
|
|
*
|
|
|
|
|
* Selective needs the exact value. The register files a partly selective
|
|
|
|
|
* school as "Non-selective", so that value is never printed.
|
|
|
|
|
*/
|
|
|
|
|
export function schoolFlags(school: FlagFields): SchoolFlag[] {
|
|
|
|
|
const flags: SchoolFlag[] = [];
|
|
|
|
|
const condition = (label: string) => flags.push({ label, kind: 'condition' });
|
|
|
|
|
const provision = (label: string) => flags.push({ label, kind: 'provision' });
|
|
|
|
|
const phase = school.phase?.trim().toLowerCase();
|
|
|
|
|
|
|
|
|
|
if (school.type_group === 'independent') condition('Fee-paying');
|
2026-10-02 23:43:43 +01:00
|
|
|
if (isSelective(school.admissions_policy)) condition('Selective');
|
2026-10-02 22:59:45 +01:00
|
|
|
const singleSex = singleSexLabel(school.gender);
|
|
|
|
|
if (singleSex) condition(singleSex);
|
|
|
|
|
if (hasReligiousCharacter(school.religious_denomination)) {
|
|
|
|
|
condition(school.religious_denomination!.trim());
|
|
|
|
|
}
|
|
|
|
|
if (hasNurseryClasses(school.nursery_provision) && phase !== 'nursery') provision('Nursery class');
|
|
|
|
|
if (school.has_sixth_form && phase !== '16 plus') provision('Sixth form');
|
|
|
|
|
return flags;
|
|
|
|
|
}
|