// 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]) const popupEl = document.createElement('div') popupEl.className = 'p-2' const h3 = popupEl.appendChild(document.createElement('h3')) h3.className = 'font-semibold text-lg mb-1' h3.textContent = site.name if (site.description) { const descP = popupEl.appendChild(document.createElement('p')) descP.className = 'text-sm text-gray-600 mb-1' descP.textContent = site.description } if (site.address) { const addrP = popupEl.appendChild(document.createElement('p')) addrP.className = 'text-xs text-gray-500 mb-1' addrP.textContent = site.address } const coordsP = popupEl.appendChild(document.createElement('p')) coordsP.className = 'text-xs text-gray-500 mb-2' coordsP.textContent = `${site.latitude.toFixed(4)}, ${site.longitude.toFixed(4)}` if (site.device_count > 0) { const deviceP = popupEl.appendChild(document.createElement('p')) deviceP.className = 'text-xs text-blue-600 mb-2' deviceP.textContent = `${site.device_count} device${site.device_count !== 1 ? 's' : ''}` } const button = popupEl.appendChild(document.createElement('button')) button.setAttribute('data-site-id', site.id) button.setAttribute('data-action', 'view-site') button.className = 'text-xs bg-blue-600 text-white px-2 py-1 rounded hover:bg-blue-700' button.textContent = 'View Site →' marker.bindPopup(popupEl) 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 } } }