58 lines
1.7 KiB
TypeScript
58 lines
1.7 KiB
TypeScript
|
|
/**
|
||
|
|
* SchoolMap Component
|
||
|
|
* Client-side Leaflet map wrapper for displaying school locations
|
||
|
|
*/
|
||
|
|
|
||
|
|
'use client';
|
||
|
|
|
||
|
|
import dynamic from 'next/dynamic';
|
||
|
|
import type { School } from '@/lib/types';
|
||
|
|
import styles from './SchoolMap.module.css';
|
||
|
|
|
||
|
|
// Dynamic import to avoid SSR issues with Leaflet
|
||
|
|
const LeafletMap = dynamic(() => import('./LeafletMapInner'), {
|
||
|
|
ssr: false,
|
||
|
|
loading: () => (
|
||
|
|
<div className={styles.mapLoading}>
|
||
|
|
<div className={styles.spinner}></div>
|
||
|
|
<p>Loading map...</p>
|
||
|
|
</div>
|
||
|
|
),
|
||
|
|
});
|
||
|
|
|
||
|
|
interface SchoolMapProps {
|
||
|
|
schools: School[];
|
||
|
|
center?: [number, number];
|
||
|
|
zoom?: number;
|
||
|
|
onMarkerClick?: (school: School) => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function SchoolMap({ schools, center, zoom = 13, onMarkerClick }: SchoolMapProps) {
|
||
|
|
// Calculate center if not provided
|
||
|
|
const mapCenter: [number, number] = center || (() => {
|
||
|
|
if (schools.length === 0) return [51.5074, -0.1278]; // Default to London
|
||
|
|
if (schools.length === 1 && schools[0].latitude && schools[0].longitude) {
|
||
|
|
return [schools[0].latitude, schools[0].longitude];
|
||
|
|
}
|
||
|
|
|
||
|
|
// Calculate average position
|
||
|
|
const validSchools = schools.filter(s => s.latitude && s.longitude);
|
||
|
|
if (validSchools.length === 0) return [51.5074, -0.1278];
|
||
|
|
|
||
|
|
const avgLat = validSchools.reduce((sum, s) => sum + (s.latitude || 0), 0) / validSchools.length;
|
||
|
|
const avgLng = validSchools.reduce((sum, s) => sum + (s.longitude || 0), 0) / validSchools.length;
|
||
|
|
return [avgLat, avgLng];
|
||
|
|
})();
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className={styles.mapWrapper}>
|
||
|
|
<LeafletMap
|
||
|
|
schools={schools}
|
||
|
|
center={mapCenter}
|
||
|
|
zoom={zoom}
|
||
|
|
onMarkerClick={onMarkerClick}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|