feat(map): fetch all schools for map view, add reference pin, cap radius at 5mi
All checks were successful
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 45s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 1m6s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 31s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s

- Remove 10-mile radius option; cap backend radius max at 5 miles
- Raise backend page_size max to 500 so map can fetch all schools in one call
- HomeView: when map view is active, fetch all schools within radius
  (page_size=500) instead of showing only the paginated first page;
  falls back to initial SSR schools while loading
- SchoolMap/LeafletMapInner: accept referencePoint prop and render a
  distinctive coral circle pin at the search postcode location

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-30 09:13:14 +01:00
parent daf24e4739
commit d6a45b8e12
5 changed files with 54 additions and 10 deletions

View File

@@ -23,12 +23,14 @@ interface LeafletMapInnerProps {
schools: School[];
center: [number, number];
zoom: number;
referencePoint?: [number, number];
onMarkerClick?: (school: School) => void;
}
export default function LeafletMapInner({ schools, center, zoom, onMarkerClick }: LeafletMapInnerProps) {
export default function LeafletMapInner({ schools, center, zoom, referencePoint, onMarkerClick }: LeafletMapInnerProps) {
const mapRef = useRef<L.Map | null>(null);
const mapContainerRef = useRef<HTMLDivElement>(null);
const refMarkerRef = useRef<L.Marker | null>(null);
useEffect(() => {
if (!mapContainerRef.current) return;
@@ -43,13 +45,36 @@ export default function LeafletMapInner({ schools, center, zoom, onMarkerClick }
}).addTo(mapRef.current);
}
// Clear existing markers
// Clear existing school markers (not the reference pin)
mapRef.current.eachLayer((layer) => {
if (layer instanceof L.Marker) {
if (layer instanceof L.Marker && layer !== refMarkerRef.current) {
mapRef.current!.removeLayer(layer);
}
});
// Add reference pin (search location)
if (refMarkerRef.current) {
refMarkerRef.current.remove();
refMarkerRef.current = null;
}
if (referencePoint && mapRef.current) {
const refIcon = L.divIcon({
html: `<div style="
width: 20px; height: 20px;
background: #e07256;
border: 3px solid white;
border-radius: 50%;
box-shadow: 0 2px 8px rgba(0,0,0,0.35);
"></div>`,
iconSize: [20, 20],
iconAnchor: [10, 10],
className: '',
});
refMarkerRef.current = L.marker(referencePoint, { icon: refIcon, zIndexOffset: 1000 })
.addTo(mapRef.current)
.bindPopup('<strong>Search location</strong>');
}
// Add markers for schools
schools.forEach((school) => {
if (school.latitude && school.longitude && mapRef.current) {
@@ -89,7 +114,7 @@ export default function LeafletMapInner({ schools, center, zoom, onMarkerClick }
return () => {
// Don't destroy map on every update, just clean markers
};
}, [schools, center, zoom, onMarkerClick]);
}, [schools, center, zoom, referencePoint, onMarkerClick]);
// Cleanup map on unmount
useEffect(() => {