Files
2026-06-03 05:09:44 +00:00

444 lines
23 KiB
PHP

<?php
require_once 'koneksi.php';
cekLogin();
$page = 'peta';
$pageTitle = 'Peta Interaktif';
$pageSubtitle = '';
$extraHead = '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<style>
/* Peta harus full, override page-wrap padding */
#main-wrap { display:flex; flex-direction:column; }
.page-wrap { padding:0 !important; display:flex; flex-direction:column; flex:1; overflow:hidden; }
/* Toolbar */
#map-toolbar {
background:#fff; border-bottom:1px solid var(--gray-md);
padding:8px 16px; display:flex; align-items:center; gap:10px; flex-wrap:wrap;
flex-shrink:0; z-index:500;
}
.mpill {
padding:5px 13px; border:none; border-radius:99px; font-size:12px;
font-weight:600; cursor:pointer; background:transparent; color:var(--gray); transition:.15s;
}
.mpill.active { background:#0f172a; color:#fff; }
.mpill:hover:not(.active) { background:var(--gray-lt); }
.layer-btn {
padding:4px 11px; border:1px solid var(--gray-md); border-radius:99px;
font-size:12px; font-weight:600; cursor:pointer; background:#fff; color:var(--gray); transition:.15s;
}
.layer-btn.active { background:#0f172a; color:#fff; border-color:#0f172a; }
.stat-pill {
font-size:11px; font-weight:700; padding:3px 10px; border-radius:99px;
}
/* Map area */
#map {
flex:1; width:100%; z-index:100; min-height:0;
}
/* Legend */
#map-legend {
position:absolute; bottom:24px; right:16px; z-index:400;
background:#fff; border-radius:8px; padding:11px 13px;
border:1px solid var(--gray-md); box-shadow:0 4px 14px rgba(0,0,0,.08);
font-size:12px; min-width:148px; pointer-events:none;
}
#map-legend .leg-title { font-size:9px; font-weight:700; color:var(--gray); text-transform:uppercase; letter-spacing:.6px; margin-bottom:8px; }
.leg-row { display:flex; align-items:center; gap:7px; margin-bottom:5px; font-size:12px; color:var(--dark); }
.leg-dot { width:9px; height:9px; border-radius:50%; flex-shrink:0; }
.leg-rect { width:16px; height:8px; border-radius:2px; flex-shrink:0; }
/* Mode hint */
#mode-hint {
position:absolute; top:14px; left:50%; transform:translateX(-50%); z-index:400;
background:rgba(15,23,42,.88); color:#fff; padding:7px 18px; border-radius:99px;
font-size:12px; font-weight:500; display:none; pointer-events:none;
}
/* Popup */
.leaflet-popup-content-wrapper{border-radius:10px!important;box-shadow:0 8px 28px rgba(0,0,0,.14)!important;padding:0!important;overflow:hidden}
.leaflet-popup-content{margin:0!important}
.pw{width:270px;font-family:var(--font)}
.ph{padding:11px 13px;font-size:13px;font-weight:700;color:#fff;display:flex;align-items:center;gap:6px}
.ph.blue{background:linear-gradient(135deg,#1e3a8a,#3b82f6)}
.ph.green{background:linear-gradient(135deg,#16a34a,#22c55e)}
.ph.red{background:linear-gradient(135deg,#dc2626,#ef4444)}
.ph.orange{background:linear-gradient(135deg,#ea580c,#f97316)}
.pb{padding:11px 13px}
.dr{display:flex;justify-content:space-between;padding:4px 0;border-bottom:1px solid #f9fafb;font-size:12px}
.dr:last-child{border-bottom:none}
.dr .k{color:var(--gray)}.dr .v{font-weight:700;text-align:right;max-width:55%}
.br{display:flex;gap:5px;margin-top:9px}
.bp{flex:1;padding:7px;font-size:12px;font-weight:700;border:none;border-radius:6px;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:4px;transition:.15s;font-family:var(--font)}
.bp-primary{background:#1e3a8a;color:#fff}
.bp-danger{background:#dc2626;color:#fff}
.bp-ghost{background:var(--gray-lt);color:var(--dark)}
.sw{margin-top:9px;padding-top:9px;border-top:1px solid #f9fafb}
.sw label{font-size:11px;font-weight:700;color:var(--gray);display:flex;justify-content:space-between}
.sw .rv{color:#1e3a8a;font-weight:800}
input[type=range]{width:100%;accent-color:#1e3a8a;cursor:pointer;margin-top:4px}
.fg-p{margin-bottom:7px}
.fg-p label{display:block;font-size:10px;font-weight:700;color:var(--gray);text-transform:uppercase;margin-bottom:3px}
.fg-p input,.fg-p select,.fg-p textarea{width:100%;padding:6px 9px;border:1px solid var(--gray-md);border-radius:5px;font-size:12px;font-family:var(--font);transition:.15s}
.fg-p input:focus,.fg-p select:focus{outline:none;border-color:#1e3a8a}
.fg-p input.ro{background:var(--gray-lt);color:var(--gray);font-size:11px;cursor:default}
.fc2{display:grid;grid-template-columns:1fr 1fr;gap:7px}
</style>';
include 'includes/sidebar.php';
?>
<!-- TOOLBAR -->
<div id="map-toolbar">
<!-- Mode -->
<div style="display:flex;background:var(--gray-lt);border-radius:99px;padding:3px;gap:1px">
<button class="mpill active" data-mode="view" onclick="setMode('view')">Lihat</button>
<?php if (in_array($_SESSION['role'],['admin','relawan'])): ?>
<button class="mpill" data-mode="miskin" onclick="setMode('miskin')">+ KPM</button>
<?php endif; ?>
<?php if (in_array($_SESSION['role'],['admin','pengurus'])): ?>
<button class="mpill" data-mode="ibadah" onclick="setMode('ibadah')">+ Ibadah</button>
<?php endif; ?>
</div>
<div style="width:1px;height:18px;background:var(--gray-md)"></div>
<!-- Layer -->
<div style="display:flex;gap:5px">
<button class="layer-btn active" id="chip-street" onclick="switchLayer('street')">Jalan</button>
<button class="layer-btn" id="chip-satellite" onclick="switchLayer('satellite')">Satelit</button>
<button class="layer-btn" id="chip-topo" onclick="switchLayer('topo')">Topografi</button>
</div>
<div style="width:1px;height:18px;background:var(--gray-md)"></div>
<!-- Toggle -->
<div style="display:flex;gap:12px;font-size:12px;font-weight:600;color:var(--gray)">
<label style="display:flex;align-items:center;gap:4px;cursor:pointer"><input type="checkbox" id="tog-ibadah" checked onchange="toggleLayer('ibadah',this.checked)"> Ibadah</label>
<label style="display:flex;align-items:center;gap:4px;cursor:pointer"><input type="checkbox" id="tog-miskin" checked onchange="toggleLayer('miskin',this.checked)"> KPM</label>
<label style="display:flex;align-items:center;gap:4px;cursor:pointer"><input type="checkbox" id="tog-radius" checked onchange="toggleLayer('radius',this.checked)"> Radius</label>
<label style="display:flex;align-items:center;gap:4px;cursor:pointer"><input type="checkbox" id="tog-prioritas" onchange="toggleLayer('prioritas',this.checked)"> Prioritas</label>
</div>
<div style="flex:1"></div>
<!-- Stats -->
<div style="display:flex;gap:6px">
<span class="stat-pill" style="background:#e0f2fe;color:#0369a1" id="s-ibadah">0 Ibadah</span>
<span class="stat-pill" style="background:var(--green-lt);color:var(--green)" id="s-ok">0 Terjangkau</span>
<span class="stat-pill" style="background:var(--red-lt);color:var(--red)" id="s-blank">0 Blank Spot</span>
</div>
</div>
<!-- MAP -->
<div style="position:relative;flex:1;display:flex;flex-direction:column;min-height:0">
<div id="map"></div>
<div id="mode-hint"></div>
<div id="map-legend">
<div class="leg-title">Legenda</div>
<div class="leg-row"><div class="leg-dot" style="background:#2563eb"></div> Rumah Ibadah</div>
<div class="leg-row"><div class="leg-rect" style="border:1.5px solid #2563eb;background:rgba(37,99,235,.12)"></div> Radius</div>
<div class="leg-row"><div class="leg-dot" style="background:#16a34a"></div> KPM Terjangkau</div>
<div class="leg-row"><div class="leg-dot" style="background:#dc2626"></div> KPM Blank Spot</div>
<div class="leg-row"><div class="leg-dot" style="background:#f97316"></div> KPM Prioritas</div>
</div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// ── Layers ──
var layerStreet = L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png',{attribution:'© CARTO'});
var layerSatellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',{attribution:'© Esri'});
var layerTopo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',{attribution:'© OpenTopoMap'});
var map = L.map('map',{center:[-0.0263,109.3425],zoom:14,layers:[layerStreet],zoomControl:false});
L.control.zoom({position:'bottomleft'}).addTo(map);
setTimeout(()=>map.invalidateSize(),300);
var curBase = 'street';
var bases = {street:layerStreet,satellite:layerSatellite,topo:layerTopo};
function switchLayer(l){
map.removeLayer(bases[curBase]); map.addLayer(bases[l]); curBase=l;
document.querySelectorAll('.layer-btn').forEach(b=>b.classList.remove('active'));
document.getElementById('chip-'+l).classList.add('active');
}
// ── Icons ──
function mkIco(c){
return new L.Icon({
iconUrl:`https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-${c}.png`,
shadowUrl:'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/images/marker-shadow.png',
iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],shadowSize:[41,41]
});
}
var ico={blue:mkIco('blue'),green:mkIco('green'),red:mkIco('red'),orange:mkIco('orange')};
// ── State ──
var dIbadah={},dMiskin={},showL={ibadah:true,miskin:true,radius:true,prioritas:false};
var curMode='view',tmpMk=null;
// ── Mode ──
function setMode(m){
curMode=m;
if(tmpMk){map.removeLayer(tmpMk);tmpMk=null;}
document.querySelectorAll('.mpill').forEach(p=>p.classList.toggle('active',p.dataset.mode===m));
var hint=document.getElementById('mode-hint');
if(m==='view'){hint.style.display='none';map.getContainer().style.cursor='';return;}
map.getContainer().style.cursor='crosshair';
hint.textContent='Mencari GPS perangkat Anda...';
hint.style.display='block';
if(!navigator.geolocation){
hint.textContent='GPS tidak tersedia. Klik manual di peta.';
return;
}
navigator.geolocation.getCurrentPosition(
function(pos){
var lat=pos.coords.latitude.toFixed(6), lng=pos.coords.longitude.toFixed(6);
var ll=L.latLng(lat,lng);
map.flyTo(ll,16);
tmpMk=L.marker(ll,{icon:m==='ibadah'?ico.blue:ico.orange}).addTo(map);
if(m==='ibadah') formIbadah(lat,lng,ll);
else formMiskin(lat,lng,ll);
hint.textContent='Lokasi ditemukan. Isi form di bawah ini.';
setTimeout(()=>{hint.style.display='none';},2500);
},
function(){
hint.textContent='GPS gagal. Silakan klik lokasi di peta.';
},
{enableHighAccuracy:true,timeout:7000}
);
}
// ── Klik manual ──
map.on('click',function(e){
if(curMode==='view') return;
var lat=e.latlng.lat.toFixed(6), lng=e.latlng.lng.toFixed(6);
if(tmpMk) map.removeLayer(tmpMk);
tmpMk=L.marker(e.latlng,{icon:curMode==='ibadah'?ico.blue:ico.orange}).addTo(map);
if(curMode==='ibadah') formIbadah(lat,lng,e.latlng);
else formMiskin(lat,lng,e.latlng);
});
map.on('popupclose',function(){if(tmpMk){map.removeLayer(tmpMk);tmpMk=null;}});
// ── Toggle layer ──
function toggleLayer(t,show){
showL[t]=show;
if(t==='ibadah') Object.values(dIbadah).forEach(d=>show?d.mk.addTo(map):map.removeLayer(d.mk));
if(t==='radius') Object.values(dIbadah).forEach(d=>show?d.ci.addTo(map):map.removeLayer(d.ci));
if(t==='miskin') Object.values(dMiskin).forEach(d=>{
if(show){if(!showL.prioritas||d.data.prioritas==1)d.mk.addTo(map);}else map.removeLayer(d.mk);
});
if(t==='prioritas') Object.values(dMiskin).forEach(d=>{
if(show){if(d.data.prioritas==1)d.mk.addTo(map);else map.removeLayer(d.mk);}
else{if(showL.miskin)d.mk.addTo(map);}
});
}
// ── Form Ibadah ──
function formIbadah(lat,lng,ll){
var h=`<div class="pw"><div class="ph blue">Tambah Rumah Ibadah</div><div class="pb">
<div class="fg-p"><label>Nama Lembaga *</label><input id="fi_nama" placeholder="Masjid Al-Ikhlas..."></div>
<div class="fc2">
<div class="fg-p"><label>Kategori</label><select id="fi_kat"><option>Masjid</option><option>Musholla</option><option>Gereja</option><option>Pura</option><option>Vihara</option><option>Klenteng</option><option>Lainnya</option></select></div>
<div class="fg-p"><label>Kuota (KK)</label><input type="number" id="fi_kuota" value="20"></div>
</div>
<div class="fg-p"><label>Alamat</label><input id="fi_alamat" placeholder="Jl. ..."></div>
<div class="fc2">
<div class="fg-p"><label>Pengurus</label><input id="fi_peng"></div>
<div class="fg-p"><label>No. Telp</label><input id="fi_telp"></div>
</div>
<div class="fg-p"><label>Radius Awal (m)</label><input type="number" id="fi_rad" value="300"></div>
<div class="fg-p"><label>Koordinat</label><input class="ro" readonly value="${lat}, ${lng}"></div>
<div class="br">
<button class="bp bp-ghost" onclick="map.closePopup()">Batal</button>
<button class="bp bp-primary" onclick="simpanIbadah('${lat}','${lng}')">Simpan</button>
</div></div></div>`;
L.popup({maxWidth:290}).setLatLng(ll).setContent(h).openOn(map);
}
function simpanIbadah(lat,lng){
var nama=document.getElementById('fi_nama').value.trim();
if(!nama){alert('Nama wajib diisi!');return;}
var fd=new FormData();
fd.append('aksi','simpan_ibadah');
fd.append('nama_ibadah',nama);
fd.append('kategori',document.getElementById('fi_kat').value);
fd.append('alamat',document.getElementById('fi_alamat').value);
fd.append('nama_pengurus',document.getElementById('fi_peng').value);
fd.append('no_telp',document.getElementById('fi_telp').value);
fd.append('kuota_bantuan',document.getElementById('fi_kuota').value);
fd.append('radius_m',document.getElementById('fi_rad').value);
fd.append('lat',lat);fd.append('lng',lng);
fetch('proses.php',{method:'POST',body:fd}).then(r=>r.json()).then(d=>{
if(d.status==='ok'){map.closePopup();loadData();toastP('Rumah ibadah disimpan','success');setMode('view');}
else toastP(d.message,'error');
});
}
// ── Form KPM ──
function formMiskin(lat,lng,ll){
var h=`<div class="pw"><div class="ph orange">Tambah Data KPM</div><div class="pb">
<div class="fg-p"><label>Nama Kepala Keluarga *</label><input id="fm_nama" placeholder="Nama lengkap..."></div>
<div class="fc2">
<div class="fg-p"><label>NIK</label><input id="fm_nik" maxlength="16" placeholder="16 digit"></div>
<div class="fg-p"><label>Tanggal Lahir</label><input type="date" id="fm_tgl"></div>
</div>
<div class="fc2">
<div class="fg-p"><label>Tanggungan</label><input type="number" id="fm_tang" value="1" min="0"></div>
<div class="fg-p"><label>Pendapatan/bln</label><input type="number" id="fm_pend" value="0"></div>
</div>
<div class="fc2">
<div class="fg-p"><label>Kondisi Rumah</label><select id="fm_kond"><option>Tidak Layak</option><option>Sangat Tidak Layak</option><option>Layak</option></select></div>
<div class="fg-p"><label>Pekerjaan</label><input id="fm_kerja" placeholder="Buruh..."></div>
</div>
<div class="fc2">
<div class="fg-p"><label>RT/RW</label><input id="fm_rtrw" placeholder="RT 01/RW 02"></div>
<div class="fg-p"><label>Kelurahan</label><input id="fm_kel"></div>
</div>
<div class="fg-p"><label>Koordinat</label><input class="ro" readonly value="${lat}, ${lng}"></div>
<div class="br">
<button class="bp bp-ghost" onclick="map.closePopup()">Batal</button>
<button class="bp bp-primary" style="background:#ea580c" onclick="simpanMiskin('${lat}','${lng}')">Simpan</button>
</div></div></div>`;
L.popup({maxWidth:290}).setLatLng(ll).setContent(h).openOn(map);
}
function simpanMiskin(lat,lng){
var nama=document.getElementById('fm_nama').value.trim();
if(!nama){alert('Nama wajib diisi!');return;}
var fd=new FormData();
fd.append('aksi','simpan_miskin');
fd.append('nama_kk',nama);
fd.append('nik',document.getElementById('fm_nik').value);
fd.append('tanggal_lahir',document.getElementById('fm_tgl').value);
fd.append('jumlah_tanggungan',document.getElementById('fm_tang').value);
fd.append('pendapatan_bulanan',document.getElementById('fm_pend').value);
fd.append('kondisi_rumah',document.getElementById('fm_kond').value);
fd.append('pekerjaan',document.getElementById('fm_kerja').value);
fd.append('rt_rw',document.getElementById('fm_rtrw').value);
fd.append('kelurahan',document.getElementById('fm_kel').value);
fd.append('lat',lat);fd.append('lng',lng);
fetch('proses.php',{method:'POST',body:fd}).then(r=>r.json()).then(d=>{
if(d.status==='ok'){map.closePopup();loadData();toastP('Data KPM disimpan','success');setMode('view');}
else toastP(d.message,'error');
});
}
// ── Popup detail ──
function popIbadah(row){
var canEdit=<?= in_array($_SESSION['role'],['admin','pengurus'])?'true':'false' ?>;
var canDel=<?= $_SESSION['role']==='admin'?'true':'false' ?>;
return `<div class="pw"><div class="ph blue">${row.kategori} — ${row.nama_ibadah}</div><div class="pb">
<div class="dr"><span class="k">Pengurus</span><span class="v">${row.nama_pengurus||'-'}</span></div>
<div class="dr"><span class="k">Kuota</span><span class="v">${row.kuota_bantuan} KK</span></div>
${canEdit?`<div class="sw"><label>Radius <span class="rv" id="rv_${row.id}">${row.radius_m}</span> m</label>
<input type="range" min="100" max="3000" step="50" value="${row.radius_m}"
oninput="updRad(${row.id},this.value)" onchange="saveRad(${row.id},this.value)"></div>`
:`<div class="dr"><span class="k">Radius</span><span class="v">${row.radius_m} m</span></div>`}
${canDel?`<div class="br"><button class="bp bp-danger" onclick="del('ibadah',${row.id})"><i class='fa fa-trash'></i> Hapus</button></div>`:''}
</div></div>`;
}
function popMiskin(row){
var ok=row.status_bantuan==='Terjangkau', pr=row.prioritas==1;
var canDel=<?= $_SESSION['role']==='admin'?'true':'false' ?>;
return `<div class="pw"><div class="ph ${ok?'green':'red'}">${pr?'🚨 ':''}${row.nama_kepala_keluarga}</div><div class="pb">
<div class="dr"><span class="k">NIK</span><span class="v">${row.nik||'-'}</span></div>
<div class="dr"><span class="k">Kondisi Rumah</span><span class="v">${row.kondisi_rumah}</span></div>
<div class="dr"><span class="k">Tanggungan</span><span class="v">${row.jumlah_tanggungan} jiwa</span></div>
<div class="dr"><span class="k">Status</span><span class="v" style="color:${ok?'#16a34a':'#dc2626'}">${row.status_bantuan}</span></div>
${pr?'<div style="background:var(--red-lt);border-radius:5px;padding:5px 8px;font-size:11px;font-weight:700;color:var(--red);margin-top:6px">Warga Prioritas Bencana</div>':''}
${canDel?`<div class="br"><button class="bp bp-danger" onclick="del('miskin',${row.id})"><i class='fa fa-trash'></i> Hapus</button></div>`:''}
</div></div>`;
}
// ── Load data ──
function loadData(){
Object.values(dIbadah).forEach(d=>{map.removeLayer(d.mk);map.removeLayer(d.ci);});
Object.values(dMiskin).forEach(d=>map.removeLayer(d.mk));
dIbadah={}; dMiskin={};
fetch('proses.php?aksi=tampil_semua').then(r=>r.json()).then(res=>{
res.ibadah.forEach(row=>{
var ll=[row.lat,row.lng];
var ci=L.circle(ll,{color:'#1e3a8a',fillColor:'#3b82f6',fillOpacity:.1,weight:1.5,radius:parseInt(row.radius_m)}).addTo(map);
var mk=L.marker(ll,{icon:ico.blue,draggable:true}).addTo(map);
mk.bindPopup(popIbadah(row),{maxWidth:290});
mk.on('drag',e=>{ci.setLatLng(e.target.getLatLng());kalkulasi();});
mk.on('dragend',e=>{
var p=e.target.getLatLng();
var fd=new FormData();fd.append('aksi','update_coords');fd.append('jenis','ibadah');fd.append('id',row.id);fd.append('lat',p.lat.toFixed(6));fd.append('lng',p.lng.toFixed(6));
fetch('proses.php',{method:'POST',body:fd});
});
dIbadah[row.id]={mk,ci,data:row};
if(!showL.ibadah) map.removeLayer(mk);
if(!showL.radius) map.removeLayer(ci);
});
res.miskin.forEach(row=>{
var ll=[row.lat,row.lng];
var mk=L.marker(ll,{icon:ico.red,draggable:true}).addTo(map);
mk.bindPopup(popMiskin(row),{maxWidth:290});
mk.on('drag',()=>kalkulasi());
mk.on('dragend',e=>{
var p=e.target.getLatLng();
var fd=new FormData();fd.append('aksi','update_coords');fd.append('jenis','miskin');fd.append('id',row.id);fd.append('lat',p.lat.toFixed(6));fd.append('lng',p.lng.toFixed(6));
fetch('proses.php',{method:'POST',body:fd});
});
dMiskin[row.id]={mk,data:row};
if(!showL.miskin) map.removeLayer(mk);
});
kalkulasi();
});
}
function kalkulasi(){
var upd=[],ok=0,blank=0;
Object.values(dMiskin).forEach(m=>{
var ll=m.mk.getLatLng(), masuk=false, pr=m.data.prioritas==1;
Object.values(dIbadah).forEach(ib=>{
if(!masuk && ll.distanceTo(ib.mk.getLatLng())<=ib.ci.getRadius()) masuk=true;
});
var st=masuk?'Terjangkau':'Belum Terbantu';
m.data.status_bantuan=st;
m.mk.setIcon(pr?ico.orange:(masuk?ico.green:ico.red));
m.mk.setPopupContent(popMiskin(m.data));
masuk?ok++:blank++;
upd.push({id:m.data.id,status:st});
if(showL.prioritas&&!pr) map.removeLayer(m.mk);
else if(showL.miskin) m.mk.addTo(map);
});
document.getElementById('s-ibadah').textContent = Object.keys(dIbadah).length+' Ibadah';
document.getElementById('s-ok').textContent = ok+' Terjangkau';
document.getElementById('s-blank').textContent = blank+' Blank Spot';
if(upd.length) fetch('proses.php?aksi=update_status_bantuan',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(upd)});
}
window.updRad=function(id,r){
var el=document.getElementById('rv_'+id);if(el)el.textContent=r;
if(dIbadah[id])dIbadah[id].ci.setRadius(parseInt(r));
kalkulasi();
};
window.saveRad=function(id,r){
var fd=new FormData();fd.append('aksi','update_radius');fd.append('id',id);fd.append('radius',r);
fetch('proses.php',{method:'POST',body:fd});
};
window.del=function(j,id){
if(!confirm('Hapus data ini?')) return;
var fd=new FormData();fd.append('aksi','hapus');fd.append('jenis',j);fd.append('id',id);
fetch('proses.php',{method:'POST',body:fd}).then(()=>{map.closePopup();loadData();toastP('Data dihapus','success');});
};
function toastP(msg,type){
var el=document.createElement('div');
el.innerHTML=(type==='success'?'✅':'❌')+' '+msg;
el.style.cssText='position:fixed;bottom:24px;left:50%;transform:translateX(-50%);z-index:99999;background:#fff;border-radius:8px;padding:9px 16px;box-shadow:0 4px 18px rgba(0,0,0,.14);font-size:12px;font-weight:600;border-left:3px solid '+(type==='success'?'#16a34a':'#dc2626');
document.body.appendChild(el);
setTimeout(()=>el.remove(),3000);
}
loadData();
</script>
<?php include 'includes/footer.php'; ?>