2026-02-02 20:34:35 +00:00
|
|
|
/**
|
|
|
|
|
* SchoolCard Component
|
|
|
|
|
* Displays school information with metrics and actions
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import Link from 'next/link';
|
|
|
|
|
import type { School } from '@/lib/types';
|
|
|
|
|
import { formatPercentage, formatProgress, calculateTrend, getTrendColor } from '@/lib/utils';
|
|
|
|
|
import styles from './SchoolCard.module.css';
|
|
|
|
|
|
|
|
|
|
interface SchoolCardProps {
|
|
|
|
|
school: School;
|
|
|
|
|
onAddToCompare?: (school: School) => void;
|
2026-03-23 21:31:28 +00:00
|
|
|
onRemoveFromCompare?: (urn: number) => void;
|
2026-02-02 20:34:35 +00:00
|
|
|
showDistance?: boolean;
|
|
|
|
|
distance?: number;
|
2026-03-05 09:33:47 +00:00
|
|
|
isInCompare?: boolean;
|
2026-02-02 20:34:35 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-23 21:31:28 +00:00
|
|
|
export function SchoolCard({ school, onAddToCompare, onRemoveFromCompare, showDistance, distance, isInCompare = false }: SchoolCardProps) {
|
2026-02-02 20:34:35 +00:00
|
|
|
const trend = calculateTrend(school.rwm_expected_pct, school.prev_rwm_expected_pct);
|
|
|
|
|
const trendColor = getTrendColor(trend);
|
|
|
|
|
|
|
|
|
|
return (
|
2026-03-05 09:33:47 +00:00
|
|
|
<div className={`${styles.card} ${isInCompare ? styles.cardInCompare : ''}`}>
|
2026-02-02 20:34:35 +00:00
|
|
|
<div className={styles.header}>
|
|
|
|
|
<h3 className={styles.title}>
|
|
|
|
|
<Link href={`/school/${school.urn}`}>
|
|
|
|
|
{school.school_name}
|
|
|
|
|
</Link>
|
|
|
|
|
</h3>
|
|
|
|
|
{showDistance && distance !== undefined && (
|
|
|
|
|
<span className={styles.distance}>
|
2026-03-05 09:33:47 +00:00
|
|
|
{(distance / 1.60934).toFixed(1)} miles away
|
2026-02-02 20:34:35 +00:00
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className={styles.meta}>
|
|
|
|
|
{school.local_authority && (
|
|
|
|
|
<span className={styles.metaItem}>{school.local_authority}</span>
|
|
|
|
|
)}
|
|
|
|
|
{school.school_type && (
|
|
|
|
|
<span className={styles.metaItem}>{school.school_type}</span>
|
|
|
|
|
)}
|
|
|
|
|
{school.religious_denomination && school.religious_denomination !== 'Does not apply' && (
|
|
|
|
|
<span className={styles.metaItem}>{school.religious_denomination}</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{(school.rwm_expected_pct !== null || school.reading_progress !== null) && (
|
|
|
|
|
<div className={styles.metrics}>
|
|
|
|
|
{school.rwm_expected_pct !== null && (
|
|
|
|
|
<div className={styles.metric}>
|
2026-03-23 21:31:28 +00:00
|
|
|
<span className={styles.metricLabel}>
|
2026-03-05 09:33:47 +00:00
|
|
|
RWM Expected
|
2026-03-23 21:31:28 +00:00
|
|
|
<span className={styles.metricHint}>% meeting expected standard</span>
|
2026-03-05 09:33:47 +00:00
|
|
|
</span>
|
2026-02-02 20:34:35 +00:00
|
|
|
<div className={styles.metricValue}>
|
|
|
|
|
<strong>{formatPercentage(school.rwm_expected_pct)}</strong>
|
|
|
|
|
{school.prev_rwm_expected_pct !== null && (
|
|
|
|
|
<span
|
2026-02-03 14:12:48 +00:00
|
|
|
className={`${styles.trend} ${styles[`trend${trend.charAt(0).toUpperCase() + trend.slice(1)}`]}`}
|
2026-03-05 09:33:47 +00:00
|
|
|
title={`Previous year: ${formatPercentage(school.prev_rwm_expected_pct)}`}
|
2026-02-02 20:34:35 +00:00
|
|
|
>
|
2026-02-03 14:12:48 +00:00
|
|
|
{trend === 'up' && (
|
|
|
|
|
<svg viewBox="0 0 16 16" fill="none" className={styles.trendIcon}>
|
|
|
|
|
<path
|
|
|
|
|
d="M8 3L14 10H2L8 3Z"
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
/>
|
|
|
|
|
</svg>
|
|
|
|
|
)}
|
|
|
|
|
{trend === 'down' && (
|
|
|
|
|
<svg viewBox="0 0 16 16" fill="none" className={styles.trendIcon}>
|
|
|
|
|
<path
|
|
|
|
|
d="M8 13L2 6H14L8 13Z"
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
/>
|
|
|
|
|
</svg>
|
|
|
|
|
)}
|
|
|
|
|
{trend === 'stable' && (
|
|
|
|
|
<svg viewBox="0 0 16 16" fill="none" className={styles.trendIcon}>
|
|
|
|
|
<rect x="2" y="7" width="12" height="2" rx="1" fill="currentColor" />
|
|
|
|
|
</svg>
|
|
|
|
|
)}
|
2026-02-02 20:34:35 +00:00
|
|
|
</span>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{school.reading_progress !== null && (
|
|
|
|
|
<div className={styles.metric}>
|
2026-03-23 21:31:28 +00:00
|
|
|
<span className={styles.metricLabel}>
|
2026-03-05 09:33:47 +00:00
|
|
|
Reading
|
2026-03-23 21:31:28 +00:00
|
|
|
<span className={styles.metricHint}>progress score (0 = avg)</span>
|
2026-03-05 09:33:47 +00:00
|
|
|
</span>
|
2026-02-02 20:34:35 +00:00
|
|
|
<strong>{formatProgress(school.reading_progress)}</strong>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{school.writing_progress !== null && (
|
|
|
|
|
<div className={styles.metric}>
|
2026-03-23 21:31:28 +00:00
|
|
|
<span className={styles.metricLabel}>
|
2026-03-05 09:33:47 +00:00
|
|
|
Writing
|
2026-03-23 21:31:28 +00:00
|
|
|
<span className={styles.metricHint}>progress score (0 = avg)</span>
|
2026-03-05 09:33:47 +00:00
|
|
|
</span>
|
2026-02-02 20:34:35 +00:00
|
|
|
<strong>{formatProgress(school.writing_progress)}</strong>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{school.maths_progress !== null && (
|
|
|
|
|
<div className={styles.metric}>
|
2026-03-23 21:31:28 +00:00
|
|
|
<span className={styles.metricLabel}>
|
2026-03-05 09:33:47 +00:00
|
|
|
Maths
|
2026-03-23 21:31:28 +00:00
|
|
|
<span className={styles.metricHint}>progress score (0 = avg)</span>
|
2026-03-05 09:33:47 +00:00
|
|
|
</span>
|
2026-02-02 20:34:35 +00:00
|
|
|
<strong>{formatProgress(school.maths_progress)}</strong>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<div className={styles.actions}>
|
2026-03-23 21:31:28 +00:00
|
|
|
<Link href={`/school/${school.urn}`} className={styles.btnPrimary}>
|
2026-02-02 20:34:35 +00:00
|
|
|
View Details
|
|
|
|
|
</Link>
|
|
|
|
|
{onAddToCompare && (
|
|
|
|
|
<button
|
2026-03-23 21:31:28 +00:00
|
|
|
onClick={() => isInCompare ? onRemoveFromCompare?.(school.urn) : onAddToCompare(school)}
|
|
|
|
|
className={isInCompare ? styles.btnRemove : styles.btnSecondary}
|
2026-02-02 20:34:35 +00:00
|
|
|
>
|
2026-03-23 21:31:28 +00:00
|
|
|
{isInCompare ? '✓ Remove' : 'Add to Compare'}
|
2026-02-02 20:34:35 +00:00
|
|
|
</button>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|