Files
aviation/ui/src/components/AirportLayer.tsx
2025-05-23 09:20:08 -04:00

66 lines
1.8 KiB
TypeScript

import { useEffect, useRef, useState } from 'react';
import { Airport, AirportCategory } from '@lib/airport.types.ts';
import { useMapEvents } from 'react-leaflet';
import debounce from 'lodash.debounce';
import { getAirports } from '@lib/airport.ts';
import AirportMarker from '@components/AirportMarker.tsx';
import { LayerInfo } from '@/App.tsx';
import { LatLng } from 'leaflet';
export default function AirportLayer({
setAirport,
showNoMetar,
selectedLayer
}: {
setAirport: (airport: Airport) => void;
showNoMetar: boolean;
selectedLayer: LayerInfo;
}) {
const [airports, setAirports] = useState<Airport[]>([]);
const lastBoundsRef = useRef<{ ne: LatLng; sw: LatLng } | null>(null);
const debouncedLoad = useRef(
debounce(async (map: any) => {
const bounds = map.getBounds();
const ne = bounds.getNorthEast();
const sw = bounds.getSouthWest();
lastBoundsRef.current = { ne, sw };
try {
const resp = await getAirports({
bounds: { northEast: ne, southWest: sw },
metars: true,
categories: [AirportCategory.HELIPORT, AirportCategory.SMALL, AirportCategory.MEDIUM, AirportCategory.LARGE]
});
setAirports(resp.data);
} catch (err) {
console.error('fetch error', err);
setAirports([]);
}
}, 300)
).current;
const map = useMapEvents({
move: () => debouncedLoad(map)
});
useEffect(() => {
if (map) debouncedLoad(map);
return () => {
debouncedLoad.cancel();
};
}, [map, debouncedLoad]);
return (
<>
{airports.map((airport, index) => (
<div key={index}>
{(showNoMetar || airport.latest_metar != undefined) && (
<AirportMarker airport={airport} index={index} setAirport={setAirport} selectedLayer={selectedLayer} />
)}
</div>
))}
</>
);
}