import { initMap } from './modules/map.js'; import { setupDrawControls } from './modules/draw.js'; import { renderForm } from './modules/form.js'; import { spbuService, jalanService, kavlingService, rumahIbadahService, wargaMiskinService, haversineService } from './services/api.service.js'; let appMap; let drawControl; let currentRadiusCircle = null; let currentHighlightLayer = null; export const createIcon = (svgPath, color) => { return L.divIcon({ className: 'custom-icon', html: `
${svgPath}
`, iconSize: [34, 34], iconAnchor: [17, 34], popupAnchor: [0, -34] }); }; const iconSPBU = (is24h) => createIcon('', is24h ? '#10B981' : '#EF4444'); const iconRumah = createIcon('', '#8B5CF6'); const iconWarga = createIcon('', '#EF4444'); window.showToast = (msg, type='success') => { const t = document.createElement('div'); t.className = `toast ${type}`; t.innerHTML = msg; document.getElementById('toast-container').appendChild(t); setTimeout(() => { t.style.transform='translateX(100%)'; t.style.opacity=0; setTimeout(()=>t.remove(),300); }, 3000); }; const loadAllData = async () => { try { const [spbu, jalan, kavling, rumah, warga] = await Promise.all([ spbuService.getAll(), jalanService.getAll(), kavlingService.getAll(), rumahIbadahService.getAll(), wargaMiskinService.getAll() ]); const spbuLayer = L.geoJSON(spbu, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconSPBU(f.properties.buka_24_jam) }), onEachFeature: (f, l) => bindPopup(l, 'spbu', f.properties) }).addTo(appMap); const jalanLayer = L.geoJSON(jalan, { style: { color: '#F59E0B', weight: 4 }, onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties) }).addTo(appMap); const kavlingLayer = L.geoJSON(kavling, { style: { color: '#3B82F6', weight: 2, fillColor: '#3B82F6', fillOpacity: 0.3 }, onEachFeature: (f, l) => bindPopup(l, 'kavling', f.properties) }).addTo(appMap); const rumahLayer = L.geoJSON(rumah, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconRumah }), onEachFeature: (f, l) => bindPopup(l, 'rumah_ibadah', f.properties, f) }).addTo(appMap); const wargaLayer = L.geoJSON(warga, { pointToLayer: (f, ll) => L.marker(ll, { icon: iconWarga }), onEachFeature: (f, l) => bindPopup(l, 'warga_miskin', f.properties) }).addTo(appMap); // Bind checkbox events document.getElementById('layer-spbu').addEventListener('change', (e) => { if (e.target.checked) appMap.addLayer(spbuLayer); else appMap.removeLayer(spbuLayer); }); document.getElementById('layer-jalan').addEventListener('change', (e) => { if (e.target.checked) appMap.addLayer(jalanLayer); else appMap.removeLayer(jalanLayer); }); document.getElementById('layer-kavling').addEventListener('change', (e) => { if (e.target.checked) appMap.addLayer(kavlingLayer); else appMap.removeLayer(kavlingLayer); }); document.getElementById('layer-rumah').addEventListener('change', (e) => { if (e.target.checked) appMap.addLayer(rumahLayer); else appMap.removeLayer(rumahLayer); }); document.getElementById('layer-warga').addEventListener('change', (e) => { if (e.target.checked) appMap.addLayer(wargaLayer); else appMap.removeLayer(wargaLayer); }); } catch (e) { window.showToast("Gagal meload data: "+e.message, 'error'); } }; const bindPopup = (layer, type, props, feature=null) => { let ext = ''; if(type==='spbu') ext = `

24 Jam: ${props.buka_24_jam?'Ya':'Tidak'}

`; if(type==='rumah_ibadah' && feature) ext = ``; layer.bindPopup(` `); }; window.checkRadius = async (rumahId, lat, lng) => { if (currentRadiusCircle) appMap.removeLayer(currentRadiusCircle); if (currentHighlightLayer) appMap.removeLayer(currentHighlightLayer); currentRadiusCircle = L.circle([lat, lng], { radius: 1000, color: '#8B5CF6', fillColor: '#8B5CF6', fillOpacity: 0.15, weight: 2 }).addTo(appMap); appMap.flyTo([lat, lng], 15); window.showToast('Menghitung jarak...'); try { const res = await haversineService.getDalamRadius(rumahId, 1); const container = document.getElementById('radius-results'); container.innerHTML = res.features.length ? '' : '

Tidak ada warga miskin.

'; res.features.forEach(f => { const d = parseFloat(f.properties.jarak_km).toFixed(2); container.innerHTML += `
${f.properties.nama}${d} km
`; }); currentHighlightLayer = L.geoJSON(res, { pointToLayer: (f, ll) => L.circleMarker(ll, { radius:8, fillColor:'#EF4444', color:'#fff', weight:2, fillOpacity:1 }) }).addTo(appMap); } catch(e) { window.showToast('Gagal kalkulasi', 'error'); } }; window.deleteData = async (type, id) => { if(!confirm('Yakin menghapus?')) return; try { if(type==='spbu') await spbuService.delete(id); if(type==='jalan') await jalanService.delete(id); if(type==='kavling') await kavlingService.delete(id); if(type==='rumah_ibadah') await rumahIbadahService.delete(id); if(type==='warga_miskin') await wargaMiskinService.delete(id); window.showToast('Data dihapus'); setTimeout(()=>location.reload(), 800); } catch(e) { window.showToast('Gagal hapus', 'error'); } }; const handleGeometryCreated = (type, geometry, layer) => { const tempLayer = L.geoJSON(geometry).addTo(appMap); renderForm(type, geometry, async (payload) => { try { if(type==='spbu') await spbuService.create(payload); if(type==='jalan') await jalanService.create(payload); if(type==='kavling') { const kavlingPayload = { nama_pemilik: payload.nama, luas: payload.luas || 0, geometry: payload.geometry }; await kavlingService.create(kavlingPayload); } if(type==='rumah_ibadah') await rumahIbadahService.create(payload); if(type==='warga_miskin') await wargaMiskinService.create(payload); window.showToast('Tersimpan'); setTimeout(()=>location.reload(), 800); } catch(e) { window.showToast('Gagal simpan', 'error'); } }, () => appMap.removeLayer(tempLayer)); }; const init = async () => { appMap = initMap('map'); // Bind extra draw events for 02 document.getElementById('btn-draw-rumah')?.addEventListener('click', () => { window.currentDrawType='rumah_ibadah'; new L.Draw.Marker(appMap).enable(); }); document.getElementById('btn-draw-warga')?.addEventListener('click', () => { window.currentDrawType='warga_miskin'; new L.Draw.Marker(appMap).enable(); }); drawControl = setupDrawControls(appMap, handleGeometryCreated); await loadAllData(); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }