'use client'; import { getAirports } from '@/api/airport'; import { Airport, AirportOrderField } from '@/api/airport.types'; import { getMetars } from '@/api/metar'; import { DivIcon, LatLngBounds } from 'leaflet'; import { useEffect, useState } from 'react'; import ReactDOMServer from 'react-dom/server'; import { Marker, TileLayer, Tooltip, useMap, useMapEvents } from 'react-leaflet'; import MetarModal from './MetarModal'; import { Avatar, MantineProvider } from '@mantine/core'; import { useRecoilState, useRecoilValue } from 'recoil'; import { coordinatesState, zoomState } from '@/state/map'; export default function MapTiles() { const [isOpen, setIsOpen] = useState(false); const [airports, setAirports] = useState([]); const [selectedAirport, setSelectedAirport] = useState(); const coordinates = useRecoilValue(coordinatesState); // eslint-disable-next-line @typescript-eslint/no-unused-vars const [zoom, setZoom] = useRecoilState(zoomState); // const [dragging, setDragging] = useState(false); const map = useMap(); const mapEvents = useMapEvents({ zoomend: async () => { setZoom(mapEvents.getZoom()); await updateAirports(mapEvents.getBounds()); }, movestart: () => { // setDragging(true); }, moveend: async () => { // setDragging(false); await updateAirports(mapEvents.getBounds()); } }); useEffect(() => { map.setView([coordinates.lat, coordinates.lon]); }, [coordinates]); function handleOpen(airport: Airport) { setSelectedAirport(airport); setIsOpen(true); } async function updateAirports(bounds: LatLngBounds) { const ne = bounds.getNorthEast(); const sw = bounds.getSouthWest(); const { data: airportData } = await getAirports({ bounds: { northEast: { lat: ne.lat, lon: ne.lng }, southWest: { lat: sw.lat, lon: sw.lng } }, order_field: AirportOrderField.CATEGORY, order_by: 'asc', limit: 100, page: 1 }); const { data: metars } = await getMetars(airportData.map((a) => a.icao)); metars.forEach((metar) => { airportData.forEach((airport) => { if (metar.station_id == airport.icao) { airport.metar = metar; } }); }); setAirports(airportData); } function metarIcon(airport: Airport) { function innerIcon({ tag, color, size = 'sm' }: { tag: string; color: string; size?: string }) { return new DivIcon({ html: ReactDOMServer.renderToString( {tag} ), className: 'metar-marker-icon' }); } if (airport.metar?.flight_category == 'VFR') { return innerIcon({ tag: 'V', color: 'green' }); } else if (airport.metar?.flight_category == 'MVFR') { return innerIcon({ tag: 'M', color: 'blue' }); } else if (airport.metar?.flight_category == 'IFR') { return innerIcon({ tag: 'I', color: 'red' }); } else if (airport.metar?.flight_category == 'LIFR') { return innerIcon({ tag: 'L', color: 'purple' }); } else { return innerIcon({ tag: 'U', color: 'black', size: 'xs' }); } } useEffect(() => { updateAirports(map.getBounds()); }, []); return ( <> {selectedAirport && setIsOpen(false)} airport={selectedAirport} />} {airports.map((airport) => ( handleOpen(airport) }} > {!isOpen && ( {airport.icao} - {airport.full_name} )} ))} ); }