Files
school_compare/nextjs-app/components/SchoolMap.tsx
Tudor ff7f5487e6
Some checks failed
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 1m26s
Build and Push Docker Images / Build Frontend (Next.js) (push) Failing after 1m48s
Build and Push Docker Images / Trigger Portainer Update (push) Has been skipped
Complete Next.js migration with SSR and Docker deployment
- Migrate from vanilla JavaScript SPA to Next.js 16 with App Router
- Add server-side rendering for all pages (Home, Compare, Rankings)
- Create individual school pages with dynamic routing (/school/[urn])
- Implement Chart.js and Leaflet map integrations
- Add comprehensive SEO with sitemap, robots.txt, and JSON-LD
- Set up Docker multi-service architecture (PostgreSQL, FastAPI, Next.js)
- Update CI/CD pipeline to build both backend and frontend images
- Fix Dockerfile to include devDependencies for TypeScript compilation
- Add Jest testing configuration
- Implement performance optimizations (code splitting, caching)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-02 20:34:35 +00:00

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>
);
}