From 23d7390286734e89abd77c854deba6e59543fe97 Mon Sep 17 00:00:00 2001 From: Tudor Date: Wed, 1 Jul 2026 09:51:46 +0100 Subject: [PATCH] feat(school-detail): reorder sections by parent demand (analytics-led) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorders the detail-page sections so the most-sought content leads, based on 30-day section_nav_used analytics (nav clicks over-count buried sections, so a low, high-demand section is a strong "surface me" signal): Primary: Ofsted → SATs Results → Admissions → Pupils & Inclusion → History → Phonics → What Parents Say → School Life → Location → Local Area → Finances Secondary: Ofsted → GCSEs → Admissions → History → Parents → Wellbeing → Location → Finances Key moves: Admissions (23%, most-clicked) lifted from #6→#3; Pupils & Inclusion (18%) from #7→#4; History (13%) off the bottom. Ofsted stays first (its low click rate is positional — everyone reaches it first). Low-demand context sections (Local Area, Finances) stay last. Brings the primary page in line with secondary. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Lh7Js5xSetKNzLVr9ArXLF --- nextjs-app/components/SchoolDetailView.tsx | 347 +++++++++--------- .../components/SecondarySchoolDetailView.tsx | 175 ++++----- 2 files changed, 264 insertions(+), 258 deletions(-) diff --git a/nextjs-app/components/SchoolDetailView.tsx b/nextjs-app/components/SchoolDetailView.tsx index 7b77a5c..d11488d 100644 --- a/nextjs-app/components/SchoolDetailView.tsx +++ b/nextjs-app/components/SchoolDetailView.tsx @@ -218,20 +218,23 @@ export function SchoolDetailView({ const hasKS4Results = latestResults != null && latestResults.attainment_8_score != null; const hasAnyResults = hasKS2Results || hasKS4Results; - // Build section nav items dynamically — only sections with data + // Build section nav items dynamically — only sections with data. + // Order is engagement-led (from section_nav_used analytics): the most-sought + // sections — results, admissions, inclusion, history — sit near the top, + // after the recognised Ofsted badge; low-demand context sections stay last. const navItems: { id: string; label: string }[] = []; if (ofsted) navItems.push({ id: 'ofsted', label: 'Ofsted' }); - if (parentView && parentView.total_responses != null && parentView.total_responses > 0) - navItems.push({ id: 'parents', label: 'Parents' }); if (hasAnyResults) navItems.push({ id: 'results', label: isSecondary ? 'GCSEs' : 'SATs' }); - if (hasPhonics && isPrimary) navItems.push({ id: 'phonics', label: 'Phonics' }); - if (hasSchoolLife) navItems.push({ id: 'school-life', label: 'School Life' }); if (admissions) navItems.push({ id: 'admissions', label: 'Admissions' }); if (hasInclusionData) navItems.push({ id: 'inclusion', label: 'Pupils' }); + if (yearlyData.length > 0) navItems.push({ id: 'history', label: 'History' }); + if (hasPhonics && isPrimary) navItems.push({ id: 'phonics', label: 'Phonics' }); + if (parentView && parentView.total_responses != null && parentView.total_responses > 0) + navItems.push({ id: 'parents', label: 'Parents' }); + if (hasSchoolLife) navItems.push({ id: 'school-life', label: 'School Life' }); if (hasLocation) navItems.push({ id: 'location', label: 'Location' }); if (hasDeprivation) navItems.push({ id: 'local-area', label: 'Local Area' }); if (hasFinance) navItems.push({ id: 'finances', label: 'Finances' }); - if (yearlyData.length > 0) navItems.push({ id: 'history', label: 'History' }); // Track active section as user scrolls useEffect(() => { @@ -670,42 +673,6 @@ export function SchoolDetailView({ )} - {/* What Parents Say */} - {parentView && parentView.total_responses != null && parentView.total_responses > 0 && ( -
-

- What Parents Say - - {parentView.total_responses.toLocaleString()} responses - -

-

- From the Ofsted Parent View survey — parents share their experience of this school. -

-
- {[ - { label: 'Would recommend this school', pct: parentView.q_recommend_pct }, - { label: 'My child is happy here', pct: parentView.q_happy_pct }, - { label: 'My child feels safe here', pct: parentView.q_safe_pct }, - { label: 'Teaching is good', pct: parentView.q_teaching_pct }, - { label: 'My child makes good progress', pct: parentView.q_progress_pct }, - { label: 'School looks after pupils\' wellbeing', pct: parentView.q_wellbeing_pct }, - { label: 'Behaviour is well managed', pct: parentView.q_behaviour_pct }, - { label: 'School deals well with bullying', pct: parentView.q_bullying_pct }, - { label: 'Communicates well with parents', pct: parentView.q_communication_pct }, - ].filter(q => q.pct != null).map(({ label, pct }) => ( -
- {label} -
-
-
- {Math.round(pct!)}% -
- ))} -
-
- )} - {/* Results Section (SATs for primary, GCSEs for secondary) */} {hasAnyResults && latestResults && (
@@ -950,69 +917,6 @@ export function SchoolDetailView({
)} - {/* Year 1 Phonics — primary only */} - {hasPhonics && isPrimary && phonics && ( -
-

Year 1 Phonics ({formatAcademicYear(phonics.year)})

-

- Phonics is a key early reading skill. Children are tested at the end of Year 1. -

-
-
-
Passed the phonics check
-
{formatPercentage(phonics.year1_phonics_pct)}
-
Phonics is a key early reading skill tested at end of Year 1
-
- {phonics.year2_phonics_pct != null && ( -
-
Year 2 pupils who retook and passed
-
{formatPercentage(phonics.year2_phonics_pct)}
-
- )} -
-
- )} - - {/* School Life */} - {hasSchoolLife && ( -
-

School Life

-
- {census?.class_size_avg != null && ( -
-
Average class size
-
{census.class_size_avg.toFixed(1)}
-
Average number of pupils per class
-
- )} - {absenceData?.overall_absence_rate != null && ( -
-
- Days missed (overall absence) - -
-
{formatPercentage(absenceData.overall_absence_rate)}
- {primaryAvg.overall_absence_pct != null && ( -
National avg: ~{primaryAvg.overall_absence_pct.toFixed(1)}%
- )} -
- )} - {absenceData?.persistent_absence_rate != null && ( -
-
- Regularly missing school - -
-
{formatPercentage(absenceData.persistent_absence_rate)}
- {primaryAvg.persistent_absence_pct != null && ( -
National avg: ~{primaryAvg.persistent_absence_pct.toFixed(0)}%
- )} -
- )} -
-
- )} - {/* How Hard to Get In */} {admissions && (
@@ -1200,73 +1104,6 @@ export function SchoolDetailView({
)} - {/* Location */} - {hasLocation && ( -
-

Location

-
- -
-
- )} - - {/* Local Area Context */} - {hasDeprivation && deprivation && ( -
-

- Local Area Context - -

-
- {Array.from({ length: 10 }, (_, i) => ( -
- ))} -
-
- Most deprived - Least deprived -
-

{deprivationDesc(deprivation.idaci_decile!)}

-
- )} - - {/* Finances */} - {hasFinance && finance && ( -
-

School Finances ({formatAcademicYear(finance.year)})

-

- Per-pupil spending shows how much the school has to spend on each child's education. -

-
-
-
Total spend per pupil per year
-
£{Math.round(finance.per_pupil_spend!).toLocaleString()}
-
How much the school has to spend on each pupil annually
-
- {finance.teacher_cost_pct != null && ( -
-
Share of budget spent on teachers
-
{finance.teacher_cost_pct.toFixed(1)}%
-
- )} - {finance.staff_cost_pct != null && ( -
-
Share of budget spent on all staff
-
{finance.staff_cost_pct.toFixed(1)}%
-
- )} -
-
- )} - {/* Results Over Time (merged: chart + historical table) */} {yearlyData.length > 0 && (
@@ -1336,6 +1173,172 @@ export function SchoolDetailView({ )}
)} + {/* Year 1 Phonics — primary only */} + {hasPhonics && isPrimary && phonics && ( +
+

Year 1 Phonics ({formatAcademicYear(phonics.year)})

+

+ Phonics is a key early reading skill. Children are tested at the end of Year 1. +

+
+
+
Passed the phonics check
+
{formatPercentage(phonics.year1_phonics_pct)}
+
Phonics is a key early reading skill tested at end of Year 1
+
+ {phonics.year2_phonics_pct != null && ( +
+
Year 2 pupils who retook and passed
+
{formatPercentage(phonics.year2_phonics_pct)}
+
+ )} +
+
+ )} + + {/* What Parents Say */} + {parentView && parentView.total_responses != null && parentView.total_responses > 0 && ( +
+

+ What Parents Say + + {parentView.total_responses.toLocaleString()} responses + +

+

+ From the Ofsted Parent View survey — parents share their experience of this school. +

+
+ {[ + { label: 'Would recommend this school', pct: parentView.q_recommend_pct }, + { label: 'My child is happy here', pct: parentView.q_happy_pct }, + { label: 'My child feels safe here', pct: parentView.q_safe_pct }, + { label: 'Teaching is good', pct: parentView.q_teaching_pct }, + { label: 'My child makes good progress', pct: parentView.q_progress_pct }, + { label: 'School looks after pupils\' wellbeing', pct: parentView.q_wellbeing_pct }, + { label: 'Behaviour is well managed', pct: parentView.q_behaviour_pct }, + { label: 'School deals well with bullying', pct: parentView.q_bullying_pct }, + { label: 'Communicates well with parents', pct: parentView.q_communication_pct }, + ].filter(q => q.pct != null).map(({ label, pct }) => ( +
+ {label} +
+
+
+ {Math.round(pct!)}% +
+ ))} +
+
+ )} + + {/* School Life */} + {hasSchoolLife && ( +
+

School Life

+
+ {census?.class_size_avg != null && ( +
+
Average class size
+
{census.class_size_avg.toFixed(1)}
+
Average number of pupils per class
+
+ )} + {absenceData?.overall_absence_rate != null && ( +
+
+ Days missed (overall absence) + +
+
{formatPercentage(absenceData.overall_absence_rate)}
+ {primaryAvg.overall_absence_pct != null && ( +
National avg: ~{primaryAvg.overall_absence_pct.toFixed(1)}%
+ )} +
+ )} + {absenceData?.persistent_absence_rate != null && ( +
+
+ Regularly missing school + +
+
{formatPercentage(absenceData.persistent_absence_rate)}
+ {primaryAvg.persistent_absence_pct != null && ( +
National avg: ~{primaryAvg.persistent_absence_pct.toFixed(0)}%
+ )} +
+ )} +
+
+ )} + + {/* Location */} + {hasLocation && ( +
+

Location

+
+ +
+
+ )} + + {/* Local Area Context */} + {hasDeprivation && deprivation && ( +
+

+ Local Area Context + +

+
+ {Array.from({ length: 10 }, (_, i) => ( +
+ ))} +
+
+ Most deprived + Least deprived +
+

{deprivationDesc(deprivation.idaci_decile!)}

+
+ )} + + {/* Finances */} + {hasFinance && finance && ( +
+

School Finances ({formatAcademicYear(finance.year)})

+

+ Per-pupil spending shows how much the school has to spend on each child's education. +

+
+
+
Total spend per pupil per year
+
£{Math.round(finance.per_pupil_spend!).toLocaleString()}
+
How much the school has to spend on each pupil annually
+
+ {finance.teacher_cost_pct != null && ( +
+
Share of budget spent on teachers
+
{finance.teacher_cost_pct.toFixed(1)}%
+
+ )} + {finance.staff_cost_pct != null && ( +
+
Share of budget spent on all staff
+
{finance.staff_cost_pct.toFixed(1)}%
+
+ )} +
+
+ )} + ); } diff --git a/nextjs-app/components/SecondarySchoolDetailView.tsx b/nextjs-app/components/SecondarySchoolDetailView.tsx index 4298e1b..d3c1961 100644 --- a/nextjs-app/components/SecondarySchoolDetailView.tsx +++ b/nextjs-app/components/SecondarySchoolDetailView.tsx @@ -134,16 +134,19 @@ export function SecondarySchoolDetailView({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [schoolInfo.urn]); - // Build nav items dynamically based on available data + // Build nav items dynamically based on available data. + // Engagement-led order (matches the primary page): recognised Ofsted badge, + // then the most-sought sections — results, admissions, history — with the + // experience and context sections following. const navItems: { id: string; label: string }[] = []; if (ofsted) navItems.push({ id: 'ofsted', label: 'Ofsted' }); - if (hasParents) navItems.push({ id: 'parents', label: 'Parents' }); if (hasResults) navItems.push({ id: 'gcse', label: 'GCSEs' }); if (admissions) navItems.push({ id: 'admissions', label: 'Admissions' }); + if (yearlyData.length > 1) navItems.push({ id: 'history', label: 'History' }); + if (hasParents) navItems.push({ id: 'parents', label: 'Parents' }); if (hasWellbeing) navItems.push({ id: 'wellbeing', label: 'Wellbeing' }); if (hasLocation) navItems.push({ id: 'location', label: 'Location' }); if (hasFinance) navItems.push({ id: 'finances', label: 'Finances' }); - if (yearlyData.length > 1) navItems.push({ id: 'history', label: 'History' }); // Track active section as user scrolls useEffect(() => { @@ -469,42 +472,6 @@ export function SecondarySchoolDetailView({ )} - {/* ── Parent View ────────────────────────────────── */} - {hasParents && parentView && ( -
-

- What Parents Say - - {parentView.total_responses!.toLocaleString()} responses - -

-

- From the Ofsted Parent View survey — parents share their experience of this school. -

-
- {[ - { label: 'Would recommend this school', pct: parentView.q_recommend_pct }, - { label: 'My child is happy here', pct: parentView.q_happy_pct }, - { label: 'My child feels safe here', pct: parentView.q_safe_pct }, - { label: 'Teaching is good', pct: parentView.q_teaching_pct }, - { label: 'My child makes good progress', pct: parentView.q_progress_pct }, - { label: 'School looks after pupils\' wellbeing', pct: parentView.q_wellbeing_pct }, - { label: 'Behaviour is well managed', pct: parentView.q_behaviour_pct }, - { label: 'School deals well with bullying', pct: parentView.q_bullying_pct }, - { label: 'Communicates well with parents', pct: parentView.q_communication_pct }, - ].filter(q => q.pct != null).map(({ label, pct }) => ( -
- {label} -
-
-
- {Math.round(pct!)}% -
- ))} -
-
- )} - {/* ── GCSE Results ───────────────────────────────── */} {hasResults && latestResults && (
@@ -790,6 +757,89 @@ export function SecondarySchoolDetailView({
)} + {/* ── History table ──────────────────────────────── */} + {yearlyData.length > 1 && ( +
+

Historical Results

+ {yearlyData.length > 0 && ( + <> +

Results Over Time

+
+ +
+ + )} +
+ View raw year-by-year data +
+ + + + + + + + + + + + {yearlyData.map((result) => ( + + + + + + + + ))} + +
YearAttainment 8Progress 8Eng & Maths 4+EBacc entry %
{formatAcademicYear(result.year)}{result.attainment_8_score != null ? result.attainment_8_score.toFixed(1) : '-'}{result.progress_8_score != null ? formatProgress(result.progress_8_score) : '-'}{result.english_maths_standard_pass_pct != null ? formatPercentage(result.english_maths_standard_pass_pct) : '-'}{result.ebacc_entry_pct != null ? formatPercentage(result.ebacc_entry_pct) : '-'}
+
+
+
+ )} + {/* ── Parent View ────────────────────────────────── */} + {hasParents && parentView && ( +
+

+ What Parents Say + + {parentView.total_responses!.toLocaleString()} responses + +

+

+ From the Ofsted Parent View survey — parents share their experience of this school. +

+
+ {[ + { label: 'Would recommend this school', pct: parentView.q_recommend_pct }, + { label: 'My child is happy here', pct: parentView.q_happy_pct }, + { label: 'My child feels safe here', pct: parentView.q_safe_pct }, + { label: 'Teaching is good', pct: parentView.q_teaching_pct }, + { label: 'My child makes good progress', pct: parentView.q_progress_pct }, + { label: 'School looks after pupils\' wellbeing', pct: parentView.q_wellbeing_pct }, + { label: 'Behaviour is well managed', pct: parentView.q_behaviour_pct }, + { label: 'School deals well with bullying', pct: parentView.q_bullying_pct }, + { label: 'Communicates well with parents', pct: parentView.q_communication_pct }, + ].filter(q => q.pct != null).map(({ label, pct }) => ( +
+ {label} +
+
+
+ {Math.round(pct!)}% +
+ ))} +
+
+ )} + {/* ── Wellbeing ──────────────────────────────────── */} {hasWellbeing && (
@@ -936,53 +986,6 @@ export function SecondarySchoolDetailView({
)} - {/* ── History table ──────────────────────────────── */} - {yearlyData.length > 1 && ( -
-

Historical Results

- {yearlyData.length > 0 && ( - <> -

Results Over Time

-
- -
- - )} -
- View raw year-by-year data -
- - - - - - - - - - - - {yearlyData.map((result) => ( - - - - - - - - ))} - -
YearAttainment 8Progress 8Eng & Maths 4+EBacc entry %
{formatAcademicYear(result.year)}{result.attainment_8_score != null ? result.attainment_8_score.toFixed(1) : '-'}{result.progress_8_score != null ? formatProgress(result.progress_8_score) : '-'}{result.english_maths_standard_pass_pct != null ? formatPercentage(result.english_maths_standard_pass_pct) : '-'}{result.ebacc_entry_pct != null ? formatPercentage(result.ebacc_entry_pct) : '-'}
-
-
-
- )} ); }