import StopDataProvider from "../data/StopDataProvider"; import "./map.css"; import { useEffect, useRef, useState } from "react"; import { useApp } from "../AppContext"; import Map, { AttributionControl, GeolocateControl, Layer, NavigationControl, Source, type MapRef, type MapLayerMouseEvent, type StyleSpecification, } from "react-map-gl/maplibre"; import { loadStyle } from "app/maps/styleloader"; import type { Feature as GeoJsonFeature, Point } from "geojson"; import { StopSheet } from "~/components/StopSheet"; import { useTranslation } from "react-i18next"; // Default minimal fallback style before dynamic loading const defaultStyle: StyleSpecification = { version: 8, glyphs: `${window.location.origin}/maps/fonts/{fontstack}/{range}.pbf`, sprite: `${window.location.origin}/maps/spritesheet/sprite`, sources: {}, layers: [], }; // Componente principal del mapa export default function StopMap() { const { t } = useTranslation(); const [stops, setStops] = useState< GeoJsonFeature[] >([]); const [selectedStop, setSelectedStop] = useState<{ stopId: number; name: string; } | null>(null); const [isSheetOpen, setIsSheetOpen] = useState(false); const { mapState, updateMapState, theme } = useApp(); const mapRef = useRef(null); const [mapStyleKey, setMapStyleKey] = useState("light"); // Style state for Map component const [mapStyle, setMapStyle] = useState(defaultStyle); // Handle click events on clusters and individual stops const onMapClick = (e: MapLayerMouseEvent) => { const features = e.features; if (!features || features.length === 0) return; const feature = features[0]; const props: any = feature.properties; handlePointClick(feature); }; useEffect(() => { StopDataProvider.getStops().then((data) => { const features: GeoJsonFeature< Point, { stopId: number; name: string; lines: string[] } >[] = data.map((s) => ({ type: "Feature", geometry: { type: "Point", coordinates: [s.longitude as number, s.latitude as number], }, properties: { stopId: s.stopId, name: s.name.original, lines: s.lines }, })); setStops(features); }); }, []); useEffect(() => { //const styleName = "carto"; const styleName = "openfreemap"; loadStyle(styleName, theme) .then((style) => setMapStyle(style)) .catch((error) => console.error("Failed to load map style:", error)); }, [mapStyleKey, theme]); useEffect(() => { const handleMapChange = () => { if (!mapRef.current) return; const map = mapRef.current.getMap(); if (!map) return; const center = map.getCenter(); const zoom = map.getZoom(); updateMapState([center.lat, center.lng], zoom); }; if (mapRef.current) { const map = mapRef.current.getMap(); if (map) { map.on("moveend", handleMapChange); } } return () => { if (mapRef.current) { const map = mapRef.current.getMap(); if (map) { map.off("moveend", handleMapChange); } } }; }, [mapRef.current]); const getLatitude = (center: any) => Array.isArray(center) ? center[0] : center.lat; const getLongitude = (center: any) => Array.isArray(center) ? center[1] : center.lng; const handlePointClick = (feature: any) => { const props: any = feature.properties; // fetch full stop to get lines array StopDataProvider.getStopById(props.stopId).then((stop) => { if (!stop) return; setSelectedStop({ stopId: stop.stopId, name: stop.name.original, }); setIsSheetOpen(true); }); }; return ( {selectedStop && ( setIsSheetOpen(false)} stopId={selectedStop.stopId} stopName={selectedStop.name} /> )} ); }