/** * RankingsView Component * Client-side rankings interface with phase tabs and filters */ 'use client'; import { useRouter, usePathname, useSearchParams } from 'next/navigation'; import { useComparison } from '@/hooks/useComparison'; import type { RankingEntry, Filters, MetricDefinition } from '@/lib/types'; import { formatPercentage, formatProgress } from '@/lib/utils'; import { EmptyState } from './EmptyState'; import styles from './RankingsView.module.css'; const PRIMARY_CATEGORIES = ['expected', 'higher', 'progress', 'average', 'gender', 'equity', 'context', 'absence', 'trends']; const SECONDARY_CATEGORIES = ['gcse']; const PRIMARY_OPTGROUPS: { label: string; category: string }[] = [ { label: 'Expected Standard', category: 'expected' }, { label: 'Higher Standard', category: 'higher' }, { label: 'Progress Scores', category: 'progress' }, { label: 'Average Scores', category: 'average' }, { label: 'Gender Performance', category: 'gender' }, { label: 'Equity (Disadvantaged)', category: 'equity' }, { label: 'School Context', category: 'context' }, { label: 'Absence', category: 'absence' }, { label: '3-Year Trends', category: 'trends' }, ]; const SECONDARY_OPTGROUPS: { label: string; category: string }[] = [ { label: 'GCSE Performance', category: 'gcse' }, ]; interface RankingsViewProps { rankings: RankingEntry[]; filters: Filters; metrics: MetricDefinition[]; selectedMetric: string; selectedArea?: string; selectedYear?: number; selectedPhase?: string; } export function RankingsView({ rankings, filters, metrics, selectedMetric, selectedArea, selectedYear, selectedPhase = 'primary', }: RankingsViewProps) { const router = useRouter(); const pathname = usePathname(); const searchParams = useSearchParams(); const { addSchool, isSelected } = useComparison(); const isPrimary = selectedPhase === 'primary'; const allowedCategories = isPrimary ? PRIMARY_CATEGORIES : SECONDARY_CATEGORIES; const optgroups = isPrimary ? PRIMARY_OPTGROUPS : SECONDARY_OPTGROUPS; const updateFilters = (updates: Record) => { const params = new URLSearchParams(searchParams); Object.entries(updates).forEach(([key, value]) => { if (value) { params.set(key, value); } else { params.delete(key); } }); router.push(`${pathname}?${params.toString()}`); }; const handlePhaseChange = (phase: string) => { const defaultMetric = phase === 'secondary' ? 'attainment_8_score' : 'rwm_expected_pct'; updateFilters({ phase, metric: defaultMetric }); }; const handleMetricChange = (metric: string) => { updateFilters({ metric }); }; const handleAreaChange = (area: string) => { updateFilters({ local_authority: area || undefined }); }; const handleYearChange = (year: string) => { updateFilters({ year: year || undefined }); }; const handleAddToCompare = (ranking: RankingEntry) => { addSchool({ ...ranking, address: null, postcode: null, latitude: null, longitude: null, } as any); }; // Get metric definition const currentMetricDef = metrics.find((m) => m.key === selectedMetric); const metricLabel = currentMetricDef?.label || selectedMetric; const isProgressScore = selectedMetric.includes('progress'); const isPercentage = selectedMetric.includes('pct') || selectedMetric.includes('rate'); // Filter metrics to only show relevant categories const filteredMetrics = metrics.filter(m => allowedCategories.includes(m.category)); return (
{/* Header */}

School Rankings

Top-performing schools by {metricLabel.toLowerCase()} {!selectedArea && rankings.length > 0 && — showing top {rankings.length}}

{/* Phase Tabs */}
{currentMetricDef?.description && (

{currentMetricDef.description}

)} {isProgressScore && (

Progress scores: 0 = national average. Positive = above average.

)} {/* Filters */}
{/* Rankings Table */}
{rankings.length === 0 ? ( router.push(`${pathname}?phase=${selectedPhase}`), }} /> ) : (
{rankings.map((ranking, index) => { const rank = index + 1; const isTopThree = rank <= 3; const alreadyInComparison = isSelected(ranking.urn); // Format the value let displayValue: string; if (ranking.value === null || ranking.value === undefined) { displayValue = '-'; } else if (isProgressScore) { displayValue = formatProgress(ranking.value); } else if (isPercentage) { displayValue = formatPercentage(ranking.value); } else { displayValue = ranking.value.toFixed(1); } return ( ); })}
Rank School Area Type {metricLabel} Action
{isTopThree ? ( {rank} ) : ( {rank} )} {ranking.school_name} {ranking.local_authority || '-'} {ranking.school_type || '-'} {displayValue} View
)}
); }