import React, { useEffect, useRef, useState } from "react"; import mapboxgl from "mapbox-gl"; import "mapbox-gl/dist/mapbox-gl.css"; import { MapPin, Target, Lightbulb } from "lucide-react"; interface MapboxMapProps { initialLat?: number; initialLng?: number; onLocationChange?: (lat: number, lng: number) => void; height?: string; } export const MapboxMap: React.FC = ({ initialLat = -23.5505, // São Paulo como padrão initialLng = -46.6333, onLocationChange, height = "400px", }) => { const mapContainer = useRef(null); const map = useRef(null); const marker = useRef(null); const [currentLat, setCurrentLat] = useState(initialLat); const [currentLng, setCurrentLng] = useState(initialLng); const [mapLoaded, setMapLoaded] = useState(false); const [error, setError] = useState(null); useEffect(() => { if (!mapContainer.current || map.current) return; try { console.log("🗺️ Inicializando mapa Mapbox..."); // Configurar token const token = import.meta.env.VITE_MAPBOX_TOKEN; if (!token) { setError( "❌ Token do Mapbox não encontrado. Configure VITE_MAPBOX_TOKEN no arquivo .env.local" ); return; } mapboxgl.accessToken = token; // Inicializar mapa map.current = new mapboxgl.Map({ container: mapContainer.current, style: "mapbox://styles/mapbox/streets-v12", center: [initialLng, initialLat], zoom: 15, }); console.log("✅ Mapa criado com sucesso"); // Adicionar controles de navegação map.current.addControl(new mapboxgl.NavigationControl(), "top-right"); // Adicionar controle de localização map.current.addControl( new mapboxgl.GeolocateControl({ positionOptions: { enableHighAccuracy: true, }, trackUserLocation: true, showUserHeading: true, }), "top-right" ); // Criar marcador arrastável marker.current = new mapboxgl.Marker({ color: "#c5a059", draggable: true, }) .setLngLat([initialLng, initialLat]) .addTo(map.current); // Evento quando o marcador é arrastado marker.current.on("dragend", () => { if (marker.current) { const lngLat = marker.current.getLngLat(); setCurrentLat(lngLat.lat); setCurrentLng(lngLat.lng); if (onLocationChange) { onLocationChange(lngLat.lat, lngLat.lng); } } }); // Evento de clique no mapa para mover o marcador map.current.on("click", (e) => { if (marker.current) { marker.current.setLngLat([e.lngLat.lng, e.lngLat.lat]); setCurrentLat(e.lngLat.lat); setCurrentLng(e.lngLat.lng); if (onLocationChange) { onLocationChange(e.lngLat.lat, e.lngLat.lng); } } }); map.current.on("load", () => { setMapLoaded(true); }); } catch (error: any) { console.error("Erro ao inicializar mapa:", error); const errorMsg = error?.message || String(error); if ( errorMsg.includes("token") || errorMsg.includes("Unauthorized") || errorMsg.includes("401") ) { setError( "❌ Token do Mapbox inválido. Obtenha um token gratuito em https://account.mapbox.com/ e configure em services/mapboxService.ts" ); } else { setError(`Erro ao carregar o mapa: ${errorMsg}`); } } // Cleanup return () => { if (marker.current) { marker.current.remove(); } if (map.current) { map.current.remove(); map.current = null; } }; }, []); // Executar apenas uma vez // Atualizar posição do marcador quando as coordenadas mudarem externamente useEffect(() => { if (marker.current && map.current && mapLoaded) { marker.current.setLngLat([initialLng, initialLat]); map.current.flyTo({ center: [initialLng, initialLat], zoom: 15, duration: 1500, }); setCurrentLat(initialLat); setCurrentLng(initialLng); } }, [initialLat, initialLng, mapLoaded]); const centerOnMarker = () => { if (map.current && marker.current) { const lngLat = marker.current.getLngLat(); map.current.flyTo({ center: [lngLat.lng, lngLat.lat], zoom: 17, duration: 1000, }); } }; return (
{error && (
{error}
)}
{/* Info cards abaixo do mapa */}
{/* Card de Coordenadas */}

Coordenadas

{currentLat.toFixed(4)}, {currentLng.toFixed(4)}

{/* Card de Instruções */}

Como usar:

  • Arraste o marcador ou{" "} clique no mapa
  • Use os controles para navegação
); };