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>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
'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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user