// Lazy-loaded sites map hook (Leaflet). Leaflet itself is loaded on // demand via ensureLeaflet (no bundling), so this chunk is small. import { ensureLeaflet } from "../lib/leaflet" declare const L: any export const SitesMap = { map: null as any, markers: null as any, mounted(this: any) { ensureLeaflet().then(() => { const sitesData = JSON.parse(this.el.dataset.sites || '[]') this.initializeLeaflet(sitesData) this.handleEvent("site_clicked", (payload: any) => { this.pushEvent("site_clicked", payload) }) }).catch((e: any) => { console.error('SitesMap: Leaflet failed to load', e) }) }, updated(this: any) { if (this.map) { const sitesData = JSON.parse(this.el.dataset.sites || '[]') this.updateSites(sitesData) } }, destroyed(this: any) { if (this.map) { this.map.remove() this.map = null this.markers = null } }, initializeLeaflet(this: any, sites: any[]) { this.map = L.map(this.el, { zoomControl: true, scrollWheelZoom: true }) L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors', maxZoom: 18 }).addTo(this.map) this.updateSites(sites) }, updateSites(this: any, sites: any[]) { if (!this.map) return if (this.markers) { this.map.removeLayer(this.markers) } this.markers = L.layerGroup() if (sites.length === 0) { this.map.setView([39.8283, -98.5795], 4) this.markers.addTo(this.map) return } const bounds = L.latLngBounds([]) sites.forEach((site: any) => { if (site.latitude && site.longitude) { const marker = L.marker([site.latitude, site.longitude]) let popupContent = `

${site.name}

` if (site.description) { popupContent += `

${site.description}

` } if (site.address) { popupContent += `

${site.address}

` } popupContent += `

${site.latitude.toFixed(4)}, ${site.longitude.toFixed(4)}

` if (site.device_count > 0) { popupContent += `

${site.device_count} device${site.device_count !== 1 ? 's' : ''}

` } popupContent += `
` marker.bindPopup(popupContent) marker.on('popupopen', () => { const button = marker.getPopup()?.getElement()?.querySelector('[data-action="view-site"]') as HTMLElement if (button) { button.addEventListener('click', () => { this.pushEvent("site_clicked", { site_id: button.dataset.siteId }) }) } }) this.markers.addLayer(marker) bounds.extend([site.latitude, site.longitude]) } }) this.markers.addTo(this.map) if (bounds.isValid()) { this.map.fitBounds(bounds, { padding: [20, 20] }) } } } // Single-marker map for site detail page. Loads Leaflet via ensureLeaflet // rather than relying on a global script polled with setTimeout. export const LeafletMap = { map: null as any, mounted(this: any) { const lat = parseFloat(this.el.dataset.lat) const lng = parseFloat(this.el.dataset.lng) const zoom = parseInt(this.el.dataset.zoom || '14') const title = this.el.dataset.markerTitle || '' if (isNaN(lat) || isNaN(lng)) return ensureLeaflet().then(() => { this.map = L.map(this.el, { scrollWheelZoom: false, zoomControl: true }) this.map.setView([lat, lng], zoom) L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(this.map) L.marker([lat, lng]).addTo(this.map).bindPopup(title) setTimeout(() => this.map.invalidateSize(), 200) }).catch((e: any) => { console.error('LeafletMap: Leaflet failed to load', e) }) }, destroyed(this: any) { if (this.map) { this.map.remove(); this.map = null } } }