fix(ui): remove duplicate data, merge sections, add sticky nav
All checks were successful
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 34s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 1m12s
Build and Push Docker Images / Build Integrator (push) Successful in 59s
Build and Push Docker Images / Build Kestra Init (push) Successful in 32s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
All checks were successful
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 34s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 1m12s
Build and Push Docker Images / Build Integrator (push) Successful in 59s
Build and Push Docker Images / Build Kestra Init (push) Successful in 32s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
UX audit round 2: - Remove Summary Strip (duplicated Ofsted grade + parent happy/safe/recommend) - Fold "% would recommend" into Ofsted section header - Merge SATs Results + Subject Breakdown into one section - Merge Results Over Time chart + Year-by-Year table into one section - Add sticky section nav with dynamic pills based on available data - Unify colour system: replace ad-hoc pill colours with semantic status classes - Guard Pupils & Inclusion so it only renders with actual data - Add year to Admissions section title - Fix progress score 0.0 colour (was neutral gap at ±0.1, now at 0) - Remove unused .metricTrend CSS class Page reduced from 16 to 13 sections. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
border: 1px solid var(--border-color, #e5dfd5);
|
||||
border-radius: 10px;
|
||||
padding: 1.25rem 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
margin-bottom: 0;
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
@@ -117,41 +117,51 @@
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Quick Summary Strip */
|
||||
.summaryStrip {
|
||||
display: flex;
|
||||
gap: 0.625rem;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 0 1.25rem;
|
||||
/* ── Sticky Section Navigation ──────────────────────── */
|
||||
.sectionNav {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: var(--bg-card, white);
|
||||
border: 1px solid var(--border-color, #e5dfd5);
|
||||
border-top: none;
|
||||
border-radius: 0 0 10px 10px;
|
||||
padding: 0.5rem 1rem;
|
||||
margin-bottom: 1rem;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.summaryPill {
|
||||
padding: 0.35rem 0.875rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
.sectionNav::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sectionNavInner {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.summaryPillGood {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
.sectionNavLink {
|
||||
display: inline-block;
|
||||
padding: 0.3rem 0.625rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-secondary, #5c564d);
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
transition: all 0.15s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.summaryPillWarn {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
.sectionNavLink:hover {
|
||||
background: var(--bg-secondary, #f3ede4);
|
||||
color: var(--text-primary, #1a1612);
|
||||
}
|
||||
|
||||
.summaryPillBad {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
/* Unified card — replaces summary / chartsSection / detailedMetrics /
|
||||
absenceSection / historySection / supplementarySection / mapSection */
|
||||
/* Unified card for all content sections */
|
||||
.card {
|
||||
background: var(--bg-card, white);
|
||||
border: 1px solid var(--border-color, #e5dfd5);
|
||||
@@ -159,6 +169,7 @@
|
||||
padding: 1.25rem 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
box-shadow: var(--shadow-soft);
|
||||
scroll-margin-top: 3.5rem;
|
||||
}
|
||||
|
||||
/* Section Title */
|
||||
@@ -192,7 +203,7 @@
|
||||
margin: -0.5rem 0 1rem;
|
||||
}
|
||||
|
||||
/* Response count badge (used in "What Parents Say") */
|
||||
/* Response count badge */
|
||||
.responseBadge {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
@@ -211,6 +222,18 @@
|
||||
margin: 1.25rem 0 0.75rem;
|
||||
}
|
||||
|
||||
/* Parent recommendation line in Ofsted section */
|
||||
.parentRecommendLine {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary, #5c564d);
|
||||
margin: 0.5rem 0 0;
|
||||
}
|
||||
|
||||
.parentRecommendLine strong {
|
||||
color: var(--accent-teal, #2d7d7d);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* Metrics Grid & Cards */
|
||||
.metricsGrid {
|
||||
display: grid;
|
||||
@@ -252,11 +275,6 @@
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.metricTrend {
|
||||
font-size: 1rem;
|
||||
color: var(--accent-teal, #2d7d7d);
|
||||
}
|
||||
|
||||
/* Progress score colour coding */
|
||||
.progressPositive {
|
||||
color: var(--accent-teal, #2d7d7d);
|
||||
@@ -268,6 +286,22 @@
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ── Semantic status colours (unified) ────────────── */
|
||||
.statusGood {
|
||||
background: rgba(45, 125, 125, 0.10);
|
||||
color: var(--accent-teal, #2d7d7d);
|
||||
}
|
||||
|
||||
.statusWarn {
|
||||
background: rgba(201, 162, 39, 0.12);
|
||||
color: #b8920e;
|
||||
}
|
||||
|
||||
.statusBad {
|
||||
background: rgba(224, 114, 86, 0.12);
|
||||
color: var(--accent-coral, #e07256);
|
||||
}
|
||||
|
||||
/* Charts Section */
|
||||
.chartContainer {
|
||||
width: 100%;
|
||||
@@ -339,6 +373,12 @@
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.historicalSubtitle {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-muted, #8a847a);
|
||||
margin: 1.25rem 0 0.25rem;
|
||||
}
|
||||
|
||||
.dataTable {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
@@ -468,7 +508,7 @@
|
||||
color: var(--text-primary, #1a1612);
|
||||
}
|
||||
|
||||
/* Admissions badges */
|
||||
/* Admissions badge — uses unified status colours */
|
||||
.admissionsBadge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -480,16 +520,6 @@
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.admissionsBadgeWarn {
|
||||
background: rgba(201, 162, 39, 0.15);
|
||||
color: #b8920e;
|
||||
}
|
||||
|
||||
.admissionsBadgeGood {
|
||||
background: rgba(60, 140, 60, 0.12);
|
||||
color: #3c8c3c;
|
||||
}
|
||||
|
||||
/* Deprivation dot scale */
|
||||
.deprivationDots {
|
||||
display: flex;
|
||||
|
||||
@@ -36,17 +36,10 @@ const NATIONAL_AVG = {
|
||||
per_pupil_spend: 6000,
|
||||
};
|
||||
|
||||
function pillClass(pct: number | null | undefined): string {
|
||||
if (pct == null) return styles.summaryPillWarn;
|
||||
if (pct >= 80) return styles.summaryPillGood;
|
||||
if (pct >= 60) return styles.summaryPillWarn;
|
||||
return styles.summaryPillBad;
|
||||
}
|
||||
|
||||
function progressClass(val: number | null | undefined): string {
|
||||
if (val == null) return '';
|
||||
if (val > 0.1) return styles.progressPositive;
|
||||
if (val < -0.1) return styles.progressNegative;
|
||||
if (val > 0) return styles.progressPositive;
|
||||
if (val < 0) return styles.progressNegative;
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -82,13 +75,39 @@ export function SchoolDetailView({
|
||||
}
|
||||
};
|
||||
|
||||
// Deprivation plain-English description
|
||||
const deprivationDesc = (decile: number) => {
|
||||
if (decile <= 3) return `This school is in one of England's most deprived areas (decile ${decile}/10). Many pupils may face additional challenges at home.`;
|
||||
if (decile <= 7) return `This school is in an area with average levels of deprivation (decile ${decile}/10).`;
|
||||
return `This school is in one of England's less deprived areas (decile ${decile}/10).`;
|
||||
};
|
||||
|
||||
// Guard for Pupils & Inclusion — only show if at least one metric is available
|
||||
const hasInclusionData = (latestResults?.disadvantaged_pct != null)
|
||||
|| (latestResults?.eal_pct != null)
|
||||
|| (latestResults?.sen_support_pct != null)
|
||||
|| senDetail != null;
|
||||
|
||||
const hasSchoolLife = absenceData != null || census?.class_size_avg != null;
|
||||
const hasPhonics = phonics != null && phonics.year1_phonics_pct != null;
|
||||
const hasDeprivation = deprivation != null && deprivation.idaci_decile != null;
|
||||
const hasFinance = finance != null && finance.per_pupil_spend != null;
|
||||
const hasLocation = schoolInfo.latitude != null && schoolInfo.longitude != null;
|
||||
|
||||
// Build section nav items dynamically — only sections with data
|
||||
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 (latestResults) navItems.push({ id: 'sats', label: 'SATs' });
|
||||
if (hasPhonics) 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 (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' });
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{/* Back Navigation */}
|
||||
@@ -154,35 +173,20 @@ export function SchoolDetailView({
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Quick Summary Strip */}
|
||||
{(ofsted || parentView) && (
|
||||
<div className={styles.summaryStrip}>
|
||||
{ofsted?.overall_effectiveness != null && (
|
||||
<span className={`${styles.summaryPill} ${styles[`ofstedGrade${ofsted.overall_effectiveness}`]}`}>
|
||||
Ofsted: {OFSTED_LABELS[ofsted.overall_effectiveness]}
|
||||
</span>
|
||||
)}
|
||||
{parentView?.q_happy_pct != null && (
|
||||
<span className={`${styles.summaryPill} ${pillClass(parentView.q_happy_pct)}`}>
|
||||
{Math.round(parentView.q_happy_pct)}% say child is happy
|
||||
</span>
|
||||
)}
|
||||
{parentView?.q_safe_pct != null && (
|
||||
<span className={`${styles.summaryPill} ${pillClass(parentView.q_safe_pct)}`}>
|
||||
{Math.round(parentView.q_safe_pct)}% say child is safe
|
||||
</span>
|
||||
)}
|
||||
{parentView?.q_recommend_pct != null && (
|
||||
<span className={`${styles.summaryPill} ${pillClass(parentView.q_recommend_pct)}`}>
|
||||
{Math.round(parentView.q_recommend_pct)}% would recommend
|
||||
</span>
|
||||
)}
|
||||
{/* Sticky Section Navigation */}
|
||||
{navItems.length > 0 && (
|
||||
<nav className={styles.sectionNav} aria-label="Page sections">
|
||||
<div className={styles.sectionNavInner}>
|
||||
{navItems.map(({ id, label }) => (
|
||||
<a key={id} href={`#${id}`} className={styles.sectionNavLink}>{label}</a>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
)}
|
||||
|
||||
{/* Ofsted Rating */}
|
||||
{ofsted && (
|
||||
<section className={styles.card}>
|
||||
<section id="ofsted" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>
|
||||
Ofsted Rating
|
||||
{ofsted.inspection_date && (
|
||||
@@ -210,6 +214,11 @@ export function SchoolDetailView({
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{parentView?.q_recommend_pct != null && parentView.total_responses != null && parentView.total_responses > 0 && (
|
||||
<p className={styles.parentRecommendLine}>
|
||||
<strong>{Math.round(parentView.q_recommend_pct)}%</strong> of parents would recommend this school ({parentView.total_responses.toLocaleString()} responses)
|
||||
</p>
|
||||
)}
|
||||
<div className={styles.metricsGrid}>
|
||||
{[
|
||||
{ label: 'Quality of Teaching', value: ofsted.quality_of_education },
|
||||
@@ -233,7 +242,7 @@ export function SchoolDetailView({
|
||||
|
||||
{/* What Parents Say */}
|
||||
{parentView && parentView.total_responses != null && parentView.total_responses > 0 && (
|
||||
<section className={styles.card}>
|
||||
<section id="parents" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>
|
||||
What Parents Say
|
||||
<span className={styles.responseBadge}>
|
||||
@@ -267,13 +276,15 @@ export function SchoolDetailView({
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* SATs Results */}
|
||||
{/* SATs Results (merged with Subject Breakdown) */}
|
||||
{latestResults && (
|
||||
<section className={styles.card}>
|
||||
<section id="sats" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>SATs Results ({latestResults.year})</h2>
|
||||
<p className={styles.sectionSubtitle}>
|
||||
End-of-primary-school tests taken by Year 6 pupils. National averages shown for comparison.
|
||||
</p>
|
||||
|
||||
{/* Headline numbers: RWM combined */}
|
||||
<div className={styles.metricsGrid}>
|
||||
{latestResults.rwm_expected_pct !== null && (
|
||||
<div className={styles.metricCard}>
|
||||
@@ -289,44 +300,10 @@ export function SchoolDetailView({
|
||||
<div className={styles.metricHint}>National avg: {NATIONAL_AVG.rwm_high}%</div>
|
||||
</div>
|
||||
)}
|
||||
{latestResults.reading_progress !== null && (
|
||||
<div className={styles.metricCard}>
|
||||
<div className={styles.metricLabel}>Reading Progress</div>
|
||||
<div className={`${styles.metricValue} ${progressClass(latestResults.reading_progress)}`}>
|
||||
{formatProgress(latestResults.reading_progress)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{latestResults.writing_progress !== null && (
|
||||
<div className={styles.metricCard}>
|
||||
<div className={styles.metricLabel}>Writing Progress</div>
|
||||
<div className={`${styles.metricValue} ${progressClass(latestResults.writing_progress)}`}>
|
||||
{formatProgress(latestResults.writing_progress)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{latestResults.maths_progress !== null && (
|
||||
<div className={styles.metricCard}>
|
||||
<div className={styles.metricLabel}>Maths Progress</div>
|
||||
<div className={`${styles.metricValue} ${progressClass(latestResults.maths_progress)}`}>
|
||||
{formatProgress(latestResults.maths_progress)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{(latestResults.reading_progress !== null || latestResults.writing_progress !== null || latestResults.maths_progress !== null) && (
|
||||
<p className={styles.progressNote}>
|
||||
Progress scores measure how much pupils improved compared to similar schools nationally. Above 0 = better than average, below 0 = below average.
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Detailed Subject Breakdown */}
|
||||
{latestResults && (
|
||||
<section className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>Subject Breakdown ({latestResults.year})</h2>
|
||||
<div className={styles.metricGroupsGrid}>
|
||||
{/* Per-subject detail table */}
|
||||
<div className={styles.metricGroupsGrid} style={{ marginTop: '1rem' }}>
|
||||
<div className={styles.metricGroup}>
|
||||
<h3 className={styles.metricGroupTitle}>Reading</h3>
|
||||
<div className={styles.metricTable}>
|
||||
@@ -345,7 +322,9 @@ export function SchoolDetailView({
|
||||
{latestResults.reading_progress !== null && (
|
||||
<div className={styles.metricRow}>
|
||||
<span className={styles.metricName}>Progress score</span>
|
||||
<span className={styles.metricValue}>{formatProgress(latestResults.reading_progress)}</span>
|
||||
<span className={`${styles.metricValue} ${progressClass(latestResults.reading_progress)}`}>
|
||||
{formatProgress(latestResults.reading_progress)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{latestResults.reading_avg_score !== null && (
|
||||
@@ -375,7 +354,9 @@ export function SchoolDetailView({
|
||||
{latestResults.writing_progress !== null && (
|
||||
<div className={styles.metricRow}>
|
||||
<span className={styles.metricName}>Progress score</span>
|
||||
<span className={styles.metricValue}>{formatProgress(latestResults.writing_progress)}</span>
|
||||
<span className={`${styles.metricValue} ${progressClass(latestResults.writing_progress)}`}>
|
||||
{formatProgress(latestResults.writing_progress)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -399,7 +380,9 @@ export function SchoolDetailView({
|
||||
{latestResults.maths_progress !== null && (
|
||||
<div className={styles.metricRow}>
|
||||
<span className={styles.metricName}>Progress score</span>
|
||||
<span className={styles.metricValue}>{formatProgress(latestResults.maths_progress)}</span>
|
||||
<span className={`${styles.metricValue} ${progressClass(latestResults.maths_progress)}`}>
|
||||
{formatProgress(latestResults.maths_progress)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{latestResults.maths_avg_score !== null && (
|
||||
@@ -411,12 +394,18 @@ export function SchoolDetailView({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{(latestResults.reading_progress !== null || latestResults.writing_progress !== null || latestResults.maths_progress !== null) && (
|
||||
<p className={styles.progressNote}>
|
||||
Progress scores measure how much pupils improved compared to similar schools nationally. Above 0 = better than average, below 0 = below average.
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Year 1 Phonics */}
|
||||
{phonics && phonics.year1_phonics_pct != null && (
|
||||
<section className={styles.card}>
|
||||
{hasPhonics && phonics && (
|
||||
<section id="phonics" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>Year 1 Phonics ({phonics.year})</h2>
|
||||
<p className={styles.sectionSubtitle}>
|
||||
Phonics is a key early reading skill. Children are tested at the end of Year 1.
|
||||
@@ -438,8 +427,8 @@ export function SchoolDetailView({
|
||||
)}
|
||||
|
||||
{/* School Life */}
|
||||
{(absenceData || census?.class_size_avg != null) && (
|
||||
<section className={styles.card}>
|
||||
{hasSchoolLife && (
|
||||
<section id="school-life" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>School Life</h2>
|
||||
<div className={styles.metricsGrid}>
|
||||
{census?.class_size_avg != null && (
|
||||
@@ -469,8 +458,8 @@ export function SchoolDetailView({
|
||||
|
||||
{/* How Hard to Get In */}
|
||||
{admissions && (
|
||||
<section className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>How Hard to Get Into This School</h2>
|
||||
<section id="admissions" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>How Hard to Get Into This School ({admissions.year})</h2>
|
||||
<div className={styles.metricsGrid}>
|
||||
{admissions.published_admission_number != null && (
|
||||
<div className={styles.metricCard}>
|
||||
@@ -492,7 +481,7 @@ export function SchoolDetailView({
|
||||
)}
|
||||
</div>
|
||||
{admissions.oversubscribed != null && (
|
||||
<div className={`${styles.admissionsBadge} ${admissions.oversubscribed ? styles.admissionsBadgeWarn : styles.admissionsBadgeGood}`}>
|
||||
<div className={`${styles.admissionsBadge} ${admissions.oversubscribed ? styles.statusWarn : styles.statusGood}`}>
|
||||
{admissions.oversubscribed
|
||||
? '⚠ More applications than places last year'
|
||||
: '✓ Places were available last year'}
|
||||
@@ -502,8 +491,8 @@ export function SchoolDetailView({
|
||||
)}
|
||||
|
||||
{/* Pupils & Inclusion */}
|
||||
{(latestResults || senDetail) && (
|
||||
<section className={styles.card}>
|
||||
{hasInclusionData && (
|
||||
<section id="inclusion" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>Pupils & Inclusion</h2>
|
||||
<div className={styles.metricsGrid}>
|
||||
{latestResults?.disadvantaged_pct != null && (
|
||||
@@ -553,13 +542,13 @@ export function SchoolDetailView({
|
||||
)}
|
||||
|
||||
{/* Location */}
|
||||
{schoolInfo.latitude && schoolInfo.longitude && (
|
||||
<section className={styles.card}>
|
||||
{hasLocation && (
|
||||
<section id="location" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>Location</h2>
|
||||
<div className={styles.mapContainer}>
|
||||
<SchoolMap
|
||||
schools={[schoolInfo]}
|
||||
center={[schoolInfo.latitude, schoolInfo.longitude]}
|
||||
center={[schoolInfo.latitude!, schoolInfo.longitude!]}
|
||||
zoom={15}
|
||||
/>
|
||||
</div>
|
||||
@@ -567,8 +556,8 @@ export function SchoolDetailView({
|
||||
)}
|
||||
|
||||
{/* Local Area Context */}
|
||||
{deprivation && deprivation.idaci_decile != null && (
|
||||
<section className={styles.card}>
|
||||
{hasDeprivation && deprivation && (
|
||||
<section id="local-area" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>Local Area Context</h2>
|
||||
<div className={styles.deprivationDots}>
|
||||
{Array.from({ length: 10 }, (_, i) => (
|
||||
@@ -583,13 +572,13 @@ export function SchoolDetailView({
|
||||
<span>Most deprived</span>
|
||||
<span>Least deprived</span>
|
||||
</div>
|
||||
<p className={styles.deprivationDesc}>{deprivationDesc(deprivation.idaci_decile)}</p>
|
||||
<p className={styles.deprivationDesc}>{deprivationDesc(deprivation.idaci_decile!)}</p>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Finances */}
|
||||
{finance && finance.per_pupil_spend != null && (
|
||||
<section className={styles.card}>
|
||||
{hasFinance && finance && (
|
||||
<section id="finances" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>School Finances ({finance.year})</h2>
|
||||
<p className={styles.sectionSubtitle}>
|
||||
Per-pupil spending shows how much the school has to spend on each child's education.
|
||||
@@ -597,7 +586,7 @@ export function SchoolDetailView({
|
||||
<div className={styles.metricsGrid}>
|
||||
<div className={styles.metricCard}>
|
||||
<div className={styles.metricLabel}>Total spend per pupil per year</div>
|
||||
<div className={styles.metricValue}>£{Math.round(finance.per_pupil_spend).toLocaleString()}</div>
|
||||
<div className={styles.metricValue}>£{Math.round(finance.per_pupil_spend!).toLocaleString()}</div>
|
||||
<div className={styles.metricHint}>National avg: ~£{NATIONAL_AVG.per_pupil_spend.toLocaleString()}</div>
|
||||
</div>
|
||||
{finance.teacher_cost_pct != null && (
|
||||
@@ -616,9 +605,9 @@ export function SchoolDetailView({
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Results Over Time */}
|
||||
{/* Results Over Time (merged: chart + historical table) */}
|
||||
{yearlyData.length > 0 && (
|
||||
<section className={styles.card}>
|
||||
<section id="history" className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>Results Over Time</h2>
|
||||
<div className={styles.chartContainer}>
|
||||
<PerformanceChart
|
||||
@@ -626,13 +615,9 @@ export function SchoolDetailView({
|
||||
schoolName={schoolInfo.school_name}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Historical Data Table */}
|
||||
{yearlyData.length > 1 && (
|
||||
<section className={styles.card}>
|
||||
<h2 className={styles.sectionTitle}>Year-by-Year Summary</h2>
|
||||
<>
|
||||
<p className={styles.historicalSubtitle}>Detailed year-by-year figures</p>
|
||||
<div className={styles.tableWrapper}>
|
||||
<table className={styles.dataTable}>
|
||||
<thead>
|
||||
@@ -659,6 +644,8 @@ export function SchoolDetailView({
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user