Files
TudorandClaude Opus 5 a7f6ff4035 refactor(detail): extract sections as server components
Moves ~1,300 lines of section markup out of the two client views into
components/school/, mirroring the components/compare/ layout. Twelve section
components plus shared primitives, all server components. The only client
file is AdmissionsViewToggle, which owns the hidden/aria-pressed state and
receives both views as server-rendered children.

JSX was extracted mechanically rather than retyped, so the markup the CSS
modules depend on is verbatim.

Sharing follows measured similarity, not assumption:
- Finances (91%) shared. The secondary premises-cost card is gated behind a
  prop so primary pages are unchanged; enabling it is a one-line follow-up.
- Ofsted (80%) shared, but behind a variant prop. The headline similarity hid
  a real fork: on a school with no overall grade the primary page shows a
  "Not rated" badge while the secondary shows a four-area OEIF panel, and the
  disclaimer copy differs. Both preserved exactly; reconciling them is a
  human decision, not a side effect of a move.
- Admissions (14%) and History (40%) kept separate.

Not yet wired up -- the old views still render.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 21:33:28 +01:00

59 lines
1.8 KiB
TypeScript

'use client';
import { useState, type ReactNode } from 'react';
import styles from './schoolSections.module.css';
/**
* The only interactive part of the primary admissions section, and the only
* client component in components/school/.
*
* Both views are always present in the DOM and visibility is toggled with the
* `hidden` attribute — matching the previous behaviour exactly — so the
* server-rendered markup passed in as yearView/trendView never ships as client
* JavaScript.
*
* It spans the header and the viewport because the segmented control sits
* inside .admissionsHeader beside the <h2> while the viewport is a sibling
* below it; wrapping only one would change the DOM the CSS depends on.
*/
export function AdmissionsViewToggle({
title,
subtitle,
trendLabel,
yearView,
trendView,
}: {
title: ReactNode;
subtitle: ReactNode;
trendLabel: string;
yearView: ReactNode;
trendView: ReactNode;
}) {
const [view, setView] = useState<'year' | 'trend'>('year');
return (
<>
<div className={styles.admissionsHeader}>
<h2 className={styles.sectionTitle}>{title}</h2>
<div className={styles.admissionsSeg} role="group" aria-label="Admissions view">
<button type="button" aria-pressed={view === 'year'} onClick={() => setView('year')}>
This year
</button>
<button type="button" aria-pressed={view === 'trend'} onClick={() => setView('trend')}>
{trendLabel}
</button>
</div>
</div>
{subtitle}
<div className={styles.admissionsViewport}>
<div className={styles.admissionsViewYear} hidden={view !== 'year'}>
{yearView}
</div>
<div className={styles.admissionsViewTrend} hidden={view !== 'trend'}>
{trendView}
</div>
</div>
</>
);
}