"use client" import type React from "react" import { useEffect, useRef, useState } from "react" import type { LocationData } from "@/lib/location/locationStorage" import { obfuscateLocation } from "@/lib/location/locationStorage" import type { PrecisionLevel } from "@/lib/location/types" // Leaflet types interface LeafletMap { setView: (coords: [number, number], zoom: number) => void remove: () => void } interface LeafletMarker { addTo: (map: LeafletMap) => LeafletMarker bindPopup: (content: string) => LeafletMarker } interface LeafletCircle { addTo: (map: LeafletMap) => LeafletCircle } interface LeafletTileLayer { addTo: (map: LeafletMap) => LeafletTileLayer } interface Leaflet { map: (element: HTMLElement, options?: any) => LeafletMap marker: (coords: [number, number], options?: any) => LeafletMarker circle: (coords: [number, number], options?: any) => LeafletCircle tileLayer: (url: string, options?: any) => LeafletTileLayer icon: (options: any) => any } declare global { interface Window { L?: Leaflet } } interface LocationMapProps { location: LocationData precision?: PrecisionLevel showAccuracy?: boolean height?: string } export const LocationMap: React.FC = ({ location, precision = "exact", showAccuracy = true, height = "400px", }) => { const mapContainer = useRef(null) const mapInstance = useRef(null) const [isLoading, setIsLoading] = useState(true) const [error, setError] = useState(null) useEffect(() => { // Load Leaflet CSS and JS const loadLeaflet = async () => { try { // Load CSS if (!document.querySelector('link[href*="leaflet.css"]')) { const link = document.createElement("link") link.rel = "stylesheet" link.href = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" link.integrity = "sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" link.crossOrigin = "" document.head.appendChild(link) } // Load JS if (!window.L) { await new Promise((resolve, reject) => { const script = document.createElement("script") script.src = "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" script.integrity = "sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" script.crossOrigin = "" script.onload = () => resolve() script.onerror = () => reject(new Error("Failed to load Leaflet")) document.head.appendChild(script) }) } setIsLoading(false) } catch (err) { setError("Failed to load map library") setIsLoading(false) } } loadLeaflet() }, []) useEffect(() => { if (!mapContainer.current || !window.L || isLoading) return // Clean up existing map if (mapInstance.current) { mapInstance.current.remove() } const L = window.L! // Get obfuscated location based on precision const { lat, lng, radius } = obfuscateLocation(location.latitude, location.longitude, precision) // Create map const map = L.map(mapContainer.current, { center: [lat, lng], zoom: precision === "exact" ? 15 : precision === "street" ? 14 : precision === "neighborhood" ? 12 : 10, zoomControl: true, attributionControl: true, }) // Add OpenStreetMap tiles L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '© OpenStreetMap contributors', maxZoom: 19, }).addTo(map) // Add marker const marker = L.marker([lat, lng], { icon: L.icon({ iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png", iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png", shadowUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png", iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41], }), }).addTo(map) // Add popup with location info const popupContent = `
Shared Location
Precision: ${precision}
${new Date(location.timestamp).toLocaleString()}
` marker.bindPopup(popupContent) // Add accuracy circle if showing accuracy if (showAccuracy && radius > 0) { L.circle([lat, lng], { radius: radius, color: "#3b82f6", fillColor: "#3b82f6", fillOpacity: 0.1, weight: 2, }).addTo(map) } mapInstance.current = map // Cleanup return () => { if (mapInstance.current) { mapInstance.current.remove() mapInstance.current = null } } }, [location, precision, showAccuracy, isLoading]) if (error) { return (

{error}

) } if (isLoading) { return (

Loading map...

) } return (

Showing {precision} location • Last updated {new Date(location.timestamp).toLocaleTimeString()}

) }