Files
D1041231091-WebGIS-All/05/index.php
T

287 lines
25 KiB
PHP

<?php
require_once __DIR__ . '/auth.php';
require_login(false);
$user = current_user();
$role = $user['role'];
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebGIS Poverty Mapping</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
*{margin:0;padding:0;box-sizing:border-box} html,body{height:100%;font-family:Arial,sans-serif;background:#f8fafc;color:#0f172a}
#header{height:50px;background:#0f766e;color:#fff;display:flex;align-items:center;justify-content:space-between;padding:0 18px;z-index:1000;position:relative;box-shadow:0 2px 12px rgba(15,23,42,.18)}
#header h1{font-size:16px}.nav{display:flex;gap:9px;align-items:center;font-size:13px}.nav a{color:#fff;text-decoration:none;background:rgba(255,255,255,.16);padding:7px 10px;border-radius:8px}.role{font-weight:700;text-transform:uppercase;font-size:11px;letter-spacing:.05em;background:#064e3b;padding:6px 8px;border-radius:999px}
#map{width:100%;height:calc(100vh - 50px)}
#toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(60px);background:#1f2937;color:#fff;padding:10px 18px;border-radius:999px;font-size:13px;z-index:9999;opacity:0;transition:.25s;box-shadow:0 10px 24px rgba(0,0,0,.22)}#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}#toast.ok{background:#16a34a}#toast.err{background:#dc2626}
#loading{display:none;position:fixed;inset:0;background:rgba(255,255,255,.55);z-index:9000;align-items:center;justify-content:center}.show-loading{display:flex!important}.spin{width:42px;height:42px;border-radius:50%;border:5px solid #cbd5e1;border-top-color:#0f766e;animation:sp .7s linear infinite}@keyframes sp{to{transform:rotate(360deg)}}
.leaflet-popup-content-wrapper{border-radius:12px!important;overflow:hidden;padding:0!important}.leaflet-popup-content{margin:0!important;min-width:280px}.ph{background:#0f766e;color:white;padding:10px 14px;font-weight:700}.pb{background:#fff;padding:12px 14px}.muted{color:#64748b;font-size:12px}.dt{width:100%;border-collapse:collapse;font-size:12px}.dt td{padding:4px;border-bottom:1px solid #eef2f7;vertical-align:top}.dt td:first-child{color:#64748b;width:115px}.fg{margin:8px 0}.fg label{font-size:11px;text-transform:uppercase;font-weight:700;color:#64748b;display:block;margin-bottom:4px}.fg input,.fg select,.fg textarea{width:100%;border:1px solid #cbd5e1;border-radius:8px;padding:8px;font-size:13px}.fg textarea{min-height:58px;resize:vertical}.br{display:flex;gap:7px;margin-top:9px;flex-wrap:wrap}.btn{border:0;border-radius:8px;padding:8px 10px;font-size:12px;font-weight:700;cursor:pointer}.bp{background:#0f766e;color:#fff}.bd{background:#dc2626;color:#fff}.bo{background:#f97316;color:#fff}.bs{background:#e2e8f0;color:#0f172a}.small{font-size:11px}.coord{background:#ecfeff;color:#155e75;border:1px solid #a5f3fc;border-radius:8px;padding:7px;font-size:12px;margin-bottom:8px}.legend{background:white;border-radius:10px;padding:10px 12px;box-shadow:0 6px 18px rgba(15,23,42,.18);font-size:12px}.legend b{display:block;margin-bottom:6px}.li{display:flex;align-items:center;gap:6px;margin:4px 0}.dot{width:12px;height:12px;border-radius:50%;border:1px solid rgba(0,0,0,.25)}.svg-marker{line-height:0}.actions{margin-top:8px}
</style>
</head>
<body>
<div id="header">
<h1>🗺️ WebGIS Poverty Mapping</h1>
<div class="nav"><span class="role"><?= htmlspecialchars($role) ?></span><span><?= htmlspecialchars($user['nama']) ?></span><a href="dashboard.php">Dashboard</a><a href="logout.php">Logout</a></div>
</div>
<div id="map"></div><div id="toast"></div><div id="loading"><div class="spin"></div></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
const USER_ROLE = <?= json_encode($role) ?>;
const USER_ID = <?= json_encode((int)$user['id']) ?>;
const USER_NAME = <?= json_encode($user['nama']) ?>;
const markersMap = {};
let map, tempPopup = null;
// Cek Leaflet sebelum inisialisasi peta.
if (typeof L === 'undefined') {
document.getElementById('map').innerHTML = '<div style="padding:20px;color:red">Leaflet gagal dimuat. Periksa internet/CDN.</div>';
throw new Error('Leaflet tidak tersedia');
}
// Inisialisasi peta.
map = L.map('map').setView([-0.05566422376778593, 109.34854622732368], 17);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {maxZoom: 20, attribution:'&copy; OpenStreetMap'}).addTo(map);
// Pembuatan Layer Groups.
const layerIslam = L.layerGroup();
const layerKristen = L.layerGroup();
const layerKatolik = L.layerGroup();
const layerHindu = L.layerGroup();
const layerBuddha = L.layerGroup();
const layerKonghucu = L.layerGroup();
const layerPenerimaDiterima = L.layerGroup();
const layerPenerimaMenunggu = L.layerGroup();
const layerPenerimaDibatalkan = L.layerGroup();
const layerRadiusBantuan = L.layerGroup();
// Layers Control.
const overlayMaps = {
"Rumah Ibadah Islam": layerIslam,
"Rumah Ibadah Kristen": layerKristen,
"Rumah Ibadah Katolik": layerKatolik,
"Rumah Ibadah Hindu": layerHindu,
"Rumah Ibadah Buddha": layerBuddha,
"Rumah Ibadah Konghucu": layerKonghucu,
"Penerima Diterima": layerPenerimaDiterima,
"Pengajuan Menunggu": layerPenerimaMenunggu,
"Penerima Dibatalkan": layerPenerimaDibatalkan,
"Radius Bantuan 300 Meter": layerRadiusBantuan
};
layerIslam.addTo(map); layerKristen.addTo(map); layerKatolik.addTo(map); layerHindu.addTo(map); layerBuddha.addTo(map); layerKonghucu.addTo(map);
layerPenerimaDiterima.addTo(map); layerRadiusBantuan.addTo(map);
if (USER_ROLE !== 'penerima') layerPenerimaMenunggu.addTo(map);
if (USER_ROLE === 'super_admin') layerPenerimaDibatalkan.addTo(map);
L.control.layers(null, overlayMaps).addTo(map);
// Penentuan warna marker.
function getRumahIbadahColor(data){
const c={islam:'#22c55e',kristen:'#3b82f6',katolik:'#8b5cf6',hindu:'#f97316',buddha:'#eab308',konghucu:'#ef4444'};
return c[data.agama] || '#0f766e';
}
function getPenerimaColor(data){
const c={menunggu:'#6b7280',diterima:'#111827',ditolak:'#dc2626',dibatalkan:'#92400e'};
return c[data.status_pengajuan] || '#111827';
}
// Pembuatan SVG marker via L.divIcon.
function svgIcon(color, label){
return L.divIcon({className:'svg-marker', iconSize:[30,42], iconAnchor:[15,42], popupAnchor:[0,-38], html:`
<svg width="30" height="42" viewBox="0 0 30 42" xmlns="http://www.w3.org/2000/svg">
<path d="M15 0C6.7 0 0 6.7 0 15c0 11.2 15 27 15 27s15-15.8 15-27C30 6.7 23.3 0 15 0z" fill="${color}" stroke="white" stroke-width="2"/>
<circle cx="15" cy="15" r="8" fill="white" opacity=".94"/><text x="15" y="19" text-anchor="middle" font-size="10" font-weight="700" fill="${color}">${label}</text>
</svg>`});
}
function createRumahIbadahIcon(data){ return svgIcon(getRumahIbadahColor(data), 'RI'); }
function createPenerimaIcon(data){ return svgIcon(getPenerimaColor(data), 'P'); }
function getRumahIbadahLayer(data){
return ({islam:layerIslam,kristen:layerKristen,katolik:layerKatolik,hindu:layerHindu,buddha:layerBuddha,konghucu:layerKonghucu})[data.agama] || layerIslam;
}
function getPenerimaLayer(data){
if(data.status_pengajuan==='menunggu') return layerPenerimaMenunggu;
if(data.status_pengajuan==='dibatalkan') return layerPenerimaDibatalkan;
return layerPenerimaDiterima;
}
function showToast(message,type='ok'){
const t=document.getElementById('toast'); t.textContent=message; t.className='show '+type; setTimeout(()=>t.className='',3200);
}
function showLoading(){document.getElementById('loading').classList.add('show-loading')}
function hideLoading(){document.getElementById('loading').classList.remove('show-loading')}
function esc(v){return String(v??'').replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[m]))}
function rupiah(n){ if(!n) return '-'; return 'Rp '+Number(n).toLocaleString('id-ID') }
// Perhitungan jarak frontend untuk tampilan. Validasi utama tetap di backend.
function hitungJarakMeter(lat1, lon1, lat2, lon2){
const R=6371000,dLat=(lat2-lat1)*Math.PI/180,dLon=(lon2-lon1)*Math.PI/180;
const a=Math.sin(dLat/2)**2+Math.cos(lat1*Math.PI/180)*Math.cos(lat2*Math.PI/180)*Math.sin(dLon/2)**2;
return R*2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));
}
function alamatDefault(lat,lng){ return `Koordinat: ${Number(lat).toFixed(6)}, ${Number(lng).toFixed(6)}`; }
function isiAlamatOtomatis(lat,lng,fieldId){
const el=document.getElementById(fieldId); if(!el) return;
const awal=alamatDefault(lat,lng); el.value=awal;
// Reverse geocoding dari OpenStreetMap. Jika gagal, alamat koordinat tetap dipakai dan bisa diedit manual.
fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${encodeURIComponent(lat)}&lon=${encodeURIComponent(lng)}&accept-language=id`)
.then(r=>r.ok?r.json():null).then(d=>{
const terbaru=document.getElementById(fieldId);
if(terbaru && d && d.display_name && (terbaru.value==='' || terbaru.value===awal)) terbaru.value=d.display_name;
}).catch(()=>{});
}
function addRumahIbadahMarker(data){
if(data.status_pengajuan==='ditolak' || data.status_hapus==='disetujui') return;
const layer=getRumahIbadahLayer(data);
const marker=L.marker([+data.latitude,+data.longitude],{icon:createRumahIbadahIcon(data)});
let actions = '';
const statusHapus = data.status_hapus || 'normal';
if(USER_ROLE==='super_admin' && data.status_pengajuan==='menunggu'){
actions += `<div class="br actions"><button class="btn bp" onclick="updateStatusRumahIbadah(${data.id},'diterima')">Setujui</button><button class="btn bd" onclick="updateStatusRumahIbadah(${data.id},'ditolak')">Tolak</button></div>`;
}
if(USER_ROLE==='super_admin' && statusHapus==='menunggu'){
actions += `<div class="br actions"><button class="btn bp" onclick="updateStatusRumahIbadah(${data.id},'hapus_disetujui')">Setujui Hapus</button><button class="btn bd" onclick="updateStatusRumahIbadah(${data.id},'hapus_ditolak')">Tolak Hapus</button></div>`;
}
if(USER_ROLE==='super_admin' && statusHapus!=='menunggu'){
actions += `<div class="br actions"><button class="btn bd" onclick="hapusRumahIbadah(${data.id})">Hapus Marker</button></div>`;
}
if(USER_ROLE==='admin_rumah_ibadah' && Number(data.user_id)===Number(USER_ID) && statusHapus!=='menunggu'){
actions += `<div class="br actions"><button class="btn bo" onclick="hapusRumahIbadah(${data.id})">Ajukan Hapus Marker</button></div>`;
}
const hapusInfo = statusHapus==='menunggu' ? `<div class="muted" style="margin-top:8px;color:#92400e"><b>Pengajuan hapus sedang menunggu persetujuan super admin.</b><br>${esc(data.alasan_hapus||'')}</div>` : '';
marker.bindPopup(`<div class="ph">${esc(data.nama_rumah_ibadah)}</div><div class="pb"><table class="dt"><tr><td>Agama</td><td>${esc(data.agama)}</td></tr><tr><td>Status</td><td>${esc(data.status_pengajuan)}</td></tr><tr><td>Status hapus</td><td>${esc(statusHapus)}</td></tr><tr><td>Alamat</td><td>${esc(data.alamat)}</td></tr><tr><td>No HP</td><td>${esc(data.nomor_hp)}</td></tr><tr><td>Koordinat</td><td>${(+data.latitude).toFixed(6)}, ${(+data.longitude).toFixed(6)}</td></tr></table><div class="muted">Radius bantuan: 300 meter.</div>${hapusInfo}${actions}</div>`);
marker.addTo(layer);
let circle=null;
// Pembuatan radius 300 meter untuk rumah ibadah yang diterima.
if(data.status_pengajuan==='diterima'){
circle=L.circle([+data.latitude,+data.longitude],{radius:300,color:getRumahIbadahColor(data),weight:1,fillOpacity:.08}).addTo(layerRadiusBantuan);
}
markersMap['rumah_'+data.id]={marker,layer,circle};
}
function addPenerimaMarker(data){
if(data.status_pengajuan==='ditolak') return;
if(data.status_hapus==='disetujui') return;
if(data.status_pengajuan==='menunggu' && USER_ROLE==='penerima') return;
if(data.status_pengajuan==='dibatalkan' && USER_ROLE!=='super_admin') return;
const layer=getPenerimaLayer(data);
const marker=L.marker([+data.latitude,+data.longitude],{icon:createPenerimaIcon(data)});
let actions='';
const statusHapus = data.status_hapus || 'normal';
if((USER_ROLE==='super_admin'||USER_ROLE==='admin_rumah_ibadah') && data.status_pengajuan==='menunggu'){
actions+=`<div class="br actions"><button class="btn bp" onclick="updateStatusPenerima(${data.id},'diterima')">Setujui</button><button class="btn bd" onclick="updateStatusPenerima(${data.id},'ditolak')">Tolak</button></div>`;
}
if(USER_ROLE==='super_admin' && statusHapus==='menunggu'){
actions+=`<div class="br actions"><button class="btn bp" onclick="updateStatusPenerima(${data.id},'hapus_disetujui')">Setujui Hapus</button><button class="btn bd" onclick="updateStatusPenerima(${data.id},'hapus_ditolak')">Tolak Hapus</button></div>`;
}
if(USER_ROLE==='super_admin' && statusHapus!=='menunggu'){
actions+=`<div class="br actions"><button class="btn bd" onclick="hapusPenerima(${data.id})">Hapus Marker</button></div>`;
}
if((USER_ROLE==='admin_rumah_ibadah'||USER_ROLE==='penerima') && statusHapus!=='menunggu'){
actions+=`<div class="br actions"><button class="btn bo" onclick="hapusPenerima(${data.id})">Ajukan Hapus Pin</button></div>`;
}
const hapusInfo = statusHapus==='menunggu' ? `<div class="muted" style="margin-top:8px;color:#92400e"><b>Pengajuan hapus sedang menunggu persetujuan super admin.</b><br>${esc(data.alasan_hapus||'')}</div>` : '';
marker.bindPopup(`<div class="ph">${esc(data.nama_penerima)}</div><div class="pb"><table class="dt"><tr><td>Status</td><td>${esc(data.status_pengajuan)}</td></tr><tr><td>Status hapus</td><td>${esc(statusHapus)}</td></tr><tr><td>Bantuan</td><td>${esc(data.jenis_bantuan)}</td></tr><tr><td>Pekerjaan</td><td>${esc(data.pekerjaan)}</td></tr><tr><td>Penghasilan</td><td>${rupiah(data.penghasilan)}</td></tr><tr><td>Tanggungan</td><td>${esc(data.jumlah_tanggungan)}</td></tr><tr><td>Rumah ibadah</td><td>${esc(data.nama_rumah_ibadah || '-')}</td></tr><tr><td>Jarak</td><td>${data.jarak_meter?Number(data.jarak_meter).toFixed(1)+' meter':'-'}</td></tr></table>${hapusInfo}${actions}</div>`);
marker.addTo(layer);
markersMap['penerima_'+data.id]={marker,layer,circle:null};
}
function removeMarkerFromMap(id,type){
const key=type+'_'+id, obj=markersMap[key]; if(!obj) return;
if(obj.marker && obj.layer) obj.layer.removeLayer(obj.marker);
if(obj.circle) layerRadiusBantuan.removeLayer(obj.circle);
delete markersMap[key];
}
function refreshMarkerAfterUpdate(data,type){ removeMarkerFromMap(data.id,type); if(type==='penerima') addPenerimaMarker(data); else addRumahIbadahMarker(data); }
function clearAll(){Object.keys(markersMap).forEach(k=>{const [type,id]=k.split('_'); removeMarkerFromMap(id,type)}); layerRadiusBantuan.clearLayers();}
function loadDataPeta(){
showLoading();
fetch('ambil_data_peta.php')
.then(r=>r.json()).then(res=>{
if(res.status!=='ok') throw new Error(res.message);
clearAll();
(res.data.rumah_ibadah||[]).forEach(addRumahIbadahMarker);
(res.data.penerima||[]).forEach(addPenerimaMarker);
}).catch(e=>showToast(e.message,'err')).finally(hideLoading);
}
function formPenerima(lat,lng){ return `<div class="ph">Tambah/Pengajuan Penerima</div><div class="pb"><div class="coord">Lat ${lat.toFixed(6)}<br>Lng ${lng.toFixed(6)}</div>
<input type="hidden" id="p_lat" value="${lat}"><input type="hidden" id="p_lng" value="${lng}">
${USER_ROLE!=='penerima'?'<div class="fg"><label>Username Akun Penerima</label><input id="p_username" placeholder="Username penerima yang terkait"></div>':''}
<div class="fg"><label>Nama Penerima</label><input id="p_nama" value="${USER_ROLE==='penerima'?esc(USER_NAME):''}"></div>
<div class="fg"><label>NIK</label><input id="p_nik"></div><div class="fg"><label>No HP</label><input id="p_hp"></div>
<div class="fg"><label>Alamat</label><textarea id="p_alamat">${esc(alamatDefault(lat,lng))}</textarea></div><div class="fg"><label>Pekerjaan</label><input id="p_pekerjaan"></div>
<div class="fg"><label>Penghasilan</label><input type="number" id="p_penghasilan" value="0"></div><div class="fg"><label>Jumlah Tanggungan</label><input type="number" id="p_tanggungan" value="0"></div>
<div class="fg"><label>Kondisi Rumah</label><select id="p_kondisi"><option value="baik">Baik</option><option value="sedang">Sedang</option><option value="rusak">Rusak</option></select></div>
<div class="fg"><label>Jenis Bantuan</label><select id="p_jenis"><option value="zakat">Zakat</option><option value="sembako">Sembako</option><option value="uang_tunai">Uang Tunai</option><option value="lainnya">Lainnya</option></select></div>
<div class="br"><button class="btn bp" onclick="submitPenerima()">Simpan Pengajuan</button></div></div>`; }
function formRumahIbadah(lat,lng){ return `<div class="ph">Ajukan Rumah Ibadah</div><div class="pb"><div class="coord">Lat ${lat.toFixed(6)}<br>Lng ${lng.toFixed(6)}</div>
<input type="hidden" id="ri_lat" value="${lat}"><input type="hidden" id="ri_lng" value="${lng}">
${USER_ROLE==='super_admin'?'<div class="fg"><label>Username Admin Rumah Ibadah</label><input id="ri_username_admin" placeholder="Username admin pengelola"></div>':''}
<div class="fg"><label>Nama Rumah Ibadah</label><input id="ri_nama"></div><div class="fg"><label>Agama</label><select id="ri_agama"><option value="islam">Islam</option><option value="kristen">Kristen</option><option value="katolik">Katolik</option><option value="hindu">Hindu</option><option value="buddha">Buddha</option><option value="konghucu">Konghucu</option></select></div>
<div class="fg"><label>Alamat</label><textarea id="ri_alamat">${esc(alamatDefault(lat,lng))}</textarea></div><div class="fg"><label>Nomor HP</label><input id="ri_hp"></div>
<div class="br"><button class="btn bp" onclick="submitRumahIbadah()">Ajukan</button></div></div>`; }
function showPopupTambahPenerima(latlng){ tempPopup=L.popup().setLatLng(latlng).setContent(formPenerima(latlng.lat,latlng.lng)).openOn(map); setTimeout(()=>isiAlamatOtomatis(latlng.lat,latlng.lng,'p_alamat'),80); }
function showPopupAjukanRumahIbadah(latlng){ tempPopup=L.popup().setLatLng(latlng).setContent(formRumahIbadah(latlng.lat,latlng.lng)).openOn(map); setTimeout(()=>isiAlamatOtomatis(latlng.lat,latlng.lng,'ri_alamat'),80); }
map.on('click', e=>{
if(USER_ROLE==='penerima') return showPopupTambahPenerima(e.latlng);
if(USER_ROLE==='admin_rumah_ibadah') return L.popup().setLatLng(e.latlng).setContent(`<div class="ph">Pilih Aksi</div><div class="pb"><div class="br"><button class="btn bp" onclick="showPopupTambahPenerima({lat:${e.latlng.lat},lng:${e.latlng.lng}})">Tambah Penerima</button><button class="btn bs" onclick="showPopupAjukanRumahIbadah({lat:${e.latlng.lat},lng:${e.latlng.lng}})">Ajukan Rumah Ibadah</button></div></div>`).openOn(map);
if(USER_ROLE==='super_admin') return L.popup().setLatLng(e.latlng).setContent(`<div class="ph">Pilih Aksi</div><div class="pb"><div class="br"><button class="btn bp" onclick="showPopupTambahPenerima({lat:${e.latlng.lat},lng:${e.latlng.lng}})">Tambah Penerima</button><button class="btn bs" onclick="showPopupAjukanRumahIbadah({lat:${e.latlng.lat},lng:${e.latlng.lng}})">Tambah Rumah Ibadah</button></div></div>`).openOn(map);
});
function submitPenerima(){
const fd=new FormData();
const userEl=document.getElementById('p_username'); if(userEl) fd.append('username_penerima', userEl.value);
fd.append('nama_penerima',document.getElementById('p_nama').value); fd.append('nik',document.getElementById('p_nik').value); fd.append('no_hp',document.getElementById('p_hp').value); fd.append('alamat',document.getElementById('p_alamat').value); fd.append('pekerjaan',document.getElementById('p_pekerjaan').value); fd.append('penghasilan',document.getElementById('p_penghasilan').value); fd.append('jumlah_tanggungan',document.getElementById('p_tanggungan').value); fd.append('kondisi_rumah',document.getElementById('p_kondisi').value); fd.append('jenis_bantuan',document.getElementById('p_jenis').value); fd.append('latitude',document.getElementById('p_lat').value); fd.append('longitude',document.getElementById('p_lng').value);
showLoading(); fetch('tambah_penerima.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{showToast(res.message,res.status==='ok'?'ok':'err'); if(res.status==='ok'){map.closePopup(); loadDataPeta();}}).catch(e=>showToast(e.message,'err')).finally(hideLoading);
}
function submitRumahIbadah(){
const fd=new FormData(); const adminEl=document.getElementById('ri_username_admin'); if(adminEl) fd.append('username_admin', adminEl.value); fd.append('nama_rumah_ibadah',document.getElementById('ri_nama').value); fd.append('agama',document.getElementById('ri_agama').value); fd.append('alamat',document.getElementById('ri_alamat').value); fd.append('nomor_hp',document.getElementById('ri_hp').value); fd.append('latitude',document.getElementById('ri_lat').value); fd.append('longitude',document.getElementById('ri_lng').value);
showLoading(); fetch('ajukan_rumah_ibadah.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{showToast(res.message,res.status==='ok'?'ok':'err'); if(res.status==='ok'){map.closePopup(); loadDataPeta();}}).catch(e=>showToast(e.message,'err')).finally(hideLoading);
}
function hapusPenerima(id){
const alasan=prompt(USER_ROLE==='super_admin'?'Alasan hapus marker penerima:':'Alasan mengajukan hapus pin penerima:')||'';
if(alasan.trim()==='') return showToast('Alasan penghapusan wajib diisi.','err');
const fd=new FormData(); fd.append('id',id); fd.append('alasan_hapus',alasan);
showLoading(); fetch('hapus_penerima.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{showToast(res.message,res.status==='ok'?'ok':'err'); if(res.status==='ok'){map.closePopup(); loadDataPeta();}}).catch(e=>showToast(e.message,'err')).finally(hideLoading);
}
function hapusRumahIbadah(id){
const alasan=prompt(USER_ROLE==='super_admin'?'Alasan hapus marker rumah ibadah:':'Alasan mengajukan hapus marker rumah ibadah:')||'';
if(alasan.trim()==='') return showToast('Alasan penghapusan wajib diisi.','err');
const fd=new FormData(); fd.append('id',id); fd.append('alasan_hapus',alasan);
showLoading(); fetch('hapus_rumah_ibadah.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{showToast(res.message,res.status==='ok'?'ok':'err'); if(res.status==='ok'){map.closePopup(); loadDataPeta();}}).catch(e=>showToast(e.message,'err')).finally(hideLoading);
}
function updateStatusPenerima(id,status,alasan=''){
if(!alasan && (status==='ditolak'||status==='dibatalkan'||status==='hapus_disetujui'||status==='hapus_ditolak')) alasan=prompt('Masukkan alasan/catatan:')||'';
const fd=new FormData(); fd.append('id',id); fd.append('status_pengajuan',status); fd.append('alasan_status',alasan);
showLoading(); fetch('update_status_penerima.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{showToast(res.message,res.status==='ok'?'ok':'err'); if(res.status==='ok'){map.closePopup(); refreshMarkerAfterUpdate(res.data,'penerima');}}).catch(e=>showToast(e.message,'err')).finally(hideLoading);
}
function updateStatusRumahIbadah(id,status,alasan=''){
if(!alasan && (status==='ditolak'||status==='hapus_disetujui'||status==='hapus_ditolak')) alasan=prompt('Masukkan alasan/catatan:')||'';
const fd=new FormData(); fd.append('id',id); fd.append('status_pengajuan',status); fd.append('keterangan',alasan);
showLoading(); fetch('update_status_rumah_ibadah.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{showToast(res.message,res.status==='ok'?'ok':'err'); if(res.status==='ok'){map.closePopup(); loadDataPeta();}}).catch(e=>showToast(e.message,'err')).finally(hideLoading);
}
// Fungsi berikut tersedia agar pola index konsisten dengan dashboard dan endpoint.
function loadProgramBantuan(){ return fetch('ambil_program_bantuan.php').then(r=>r.json()); }
function submitProgramBantuan(){ showToast('Kelola program bantuan tersedia di dashboard.','ok'); }
function submitPenyaluran(){ showToast('Catat penyaluran bantuan tersedia di dashboard.','ok'); }
function loadLaporanPenyaluran(){ return fetch('ambil_laporan_penyaluran.php').then(r=>r.json()); }
function renderTabelPenyaluran(data){ return data; }
function renderRekapPenyaluran(data){ return data; }
function filterLaporanPenyaluran(){ return loadLaporanPenyaluran(); }
function showDetailPenyaluran(id){ showToast('Detail penyaluran dapat dilihat di dashboard/riwayat.','ok'); }
const legend=L.control({position:'bottomright'}); legend.onAdd=function(){const d=L.DomUtil.create('div','legend');d.innerHTML='<b>Legenda</b><div class="li"><span class="dot" style="background:#22c55e"></span>Islam</div><div class="li"><span class="dot" style="background:#3b82f6"></span>Kristen</div><div class="li"><span class="dot" style="background:#8b5cf6"></span>Katolik</div><div class="li"><span class="dot" style="background:#111827"></span>Penerima diterima</div><div class="li"><span class="dot" style="background:#6b7280"></span>Menunggu</div><div class="li"><span class="dot" style="background:#92400e"></span>Dibatalkan</div>';return d};legend.addTo(map);
loadDataPeta();
</script>
</body>
</html>