/** * Phase variants of a place page. * * Phase is part of the query — "primary schools in beccles", "secondary * schools in brentwood" — not a filter applied afterwards, so each gets its * own indexable path. A place with no schools of the phase has no page: the * per-phase threshold, not an error. */ import { notFound } from 'next/navigation'; import type { Metadata } from 'next'; import { fetchPlace } from '@/lib/places'; import { fetchNationalAverages } from '@/lib/api'; import { PlaceView } from '@/components/places/PlaceView'; import { absoluteUrl } from '@/lib/site'; interface Props { params: Promise<{ place: string; phase: string }> } export const revalidate = 604800; export const dynamicParams = true; const PHASES = ['primary', 'secondary'] as const; type Phase = (typeof PHASES)[number]; const isPhase = (v: string): v is Phase => (PHASES as readonly string[]).includes(v); async function resolve(slug: string, phase: Phase) { return (await fetchPlace('town', slug, phase)) ?? (await fetchPlace('locality', slug, phase)); } export async function generateMetadata({ params }: Props): Promise { const { place: slug, phase } = await params; if (!isPhase(phase)) return { title: 'Place Not Found' }; const detail = await resolve(slug, phase); if (!detail || detail.schools.length === 0) return { title: 'Place Not Found' }; const word = phase === 'secondary' ? 'Secondary' : 'Primary'; const { name } = detail.place; return { // Not "Ranked": the table is alphabetical, so the word would be a claim // the page does not keep. title: { absolute: `${word} Schools in ${name} | schoolcompare` }, description: `Every ${phase} school in ${name}, with results, Ofsted grades and the local ` + `average against England.`, alternates: { canonical: absoluteUrl(`/schools/${slug}/${phase}`) }, }; } export default async function PlacePhasePage({ params }: Props) { const { place: slug, phase } = await params; if (!isPhase(phase)) notFound(); const detail = await resolve(slug, phase); if (!detail || detail.schools.length === 0) notFound(); const national = await fetchNationalAverages().catch(() => null); const englandAverage = phase === 'secondary' ? national?.secondary?.attainment_8_score ?? null : national?.primary?.rwm_expected_pct ?? null; return ; }