Upload files to "/"

This commit is contained in:
2026-06-05 03:08:55 +00:00
commit afcd403620
5 changed files with 1961 additions and 0 deletions
+611
View File
@@ -0,0 +1,611 @@
<!DOCTYPE html>
<html lang="id">
<head>
<?php
session_start();
if (!isset($_SESSION['login']) || $_SESSION['login'] !== true) {
header("Location: login.php");
exit;
}
?>
<meta charset="UTF-8">
<title>WebGIS Kemiskinan - Dashboard Admin</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
* { box-sizing: border-box; }
body { margin:0; font-family:Arial,sans-serif; display:flex; background:#f0f2f5; }
.sidebar {
width: 360px;
min-width: 360px;
background: #2c3e50;
color: white;
padding: 15px;
overflow-y: auto;
height: 100vh;
}
.sidebar h2 {
text-align: center;
margin: 0 0 5px 0;
font-size: 16px;
color: #ecf0f1;
}
.sidebar .user-info {
text-align: center;
font-size: 12px;
color: #bdc3c7;
margin-bottom: 15px;
}
.card {
background: white;
color: #2c3e50;
padding: 12px;
border-radius: 8px;
margin-bottom: 12px;
}
.card h3 {
margin: 0 0 10px 0;
font-size: 14px;
color: #2c3e50;
border-bottom: 2px solid #3498db;
padding-bottom: 5px;
}
.card input,
.card select,
.card textarea {
width: 100%;
padding: 7px 9px;
margin-bottom: 8px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 13px;
outline: none;
}
.card input:focus,
.card select:focus,
.card textarea:focus { border-color: #3498db; }
.card button {
width: 100%;
padding: 9px;
background: #27ae60;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 13px;
font-weight: bold;
transition: background 0.2s;
}
.card button:hover { background: #219a52; }
.card button.btn-logout {
background: #e74c3c;
}
.card button.btn-logout:hover { background: #c0392b; }
.stat-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
.stat-item {
background: #f8f9fa;
border-radius: 6px;
padding: 8px;
text-align: center;
font-size: 12px;
}
.stat-item .num {
font-size: 22px;
font-weight: bold;
display: block;
}
.stat-item.green .num { color: #27ae60; }
.stat-item.red .num { color: #e74c3c; }
.stat-item.blue .num { color: #3498db; }
.stat-item.orange .num { color: #e67e22; }
.table-box { max-height: 180px; overflow-y: auto; }
table { width: 100%; border-collapse: collapse; font-size: 11px; }
table th { background: #3498db; color: white; padding: 5px 6px; text-align: left; }
table td { padding: 5px 6px; border-bottom: 1px solid #eee; }
table tr:hover td { background: #f5f5f5; }
.radius-val { font-size: 20px; font-weight: bold; color: #e67e22; text-align: center; }
#map { flex: 1; height: 100vh; }
.btn-edit {
background: #f39c12 !important;
color: white !important;
width: 48% !important;
display: inline-block !important;
margin-top: 5px !important;
padding: 5px !important;
font-size: 10px !important;
border: none !important;
border-radius: 4px !important;
cursor: pointer !important;
}
.btn-hapus {
background: #e74c3c !important;
color: white !important;
width: 48% !important;
display: inline-block !important;
margin-top: 5px !important;
padding: 5px !important;
font-size: 10px !important;
border: none !important;
border-radius: 4px !important;
cursor: pointer !important;
float: right !important;
}
.btn-edit:hover { background: #e67e22 !important; }
.btn-hapus:hover { background: #c0392b !important; }
.clearfix::after { content: ""; clear: both; display: table; }
.popup-form input, .popup-form textarea, .popup-form select {
width: 100%;
padding: 6px;
margin-bottom: 8px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 12px;
box-sizing: border-box;
}
.foto-preview {
margin: 10px 0;
text-align: center;
}
.foto-preview img {
max-width: 100%;
max-height: 120px;
border-radius: 8px;
border: 1px solid #ddd;
padding: 3px;
}
</style>
</head>
<body>
<div class="sidebar">
<h2>🗺️ Dashboard Admin</h2>
<div class="user-info">Login sebagai: <strong><?= htmlspecialchars($_SESSION['username']) ?></strong></div>
<div class="card">
<h3>📊 Statistik</h3>
<div class="stat-grid">
<div class="stat-item blue"><span class="num" id="ibadah">0</span> Rumah Ibadah</div>
<div class="stat-item red"><span class="num" id="miskin">0</span> Penduduk Miskin</div>
<div class="stat-item green"><span class="num" id="dalam">0</span> ✅ Dalam Radius</div>
<div class="stat-item orange"><span class="num" id="luar">0</span> ❌ Luar Radius</div>
</div>
</div>
<div class="card">
<h3>🎯 Radius Bantuan</h3>
<input type="range" min="100" max="500" step="50" value="300" id="radiusSlider" style="padding:0; border:none; background:transparent;">
<div class="radius-val"><span id="radiusValue">300</span> Meter</div>
<button onclick="terapkanRadius()" style="margin-top:8px;">🔄 Terapkan Radius</button>
</div>
<div class="card">
<h3> Tambah Bantuan</h3>
<select id="bJenis">
<option value="Beras">🌾 Beras</option>
<option value="Sembako">🛒 Sembako</option>
<option value="Uang Tunai">💰 Uang Tunai</option>
<option value="Pendidikan">📚 Pendidikan</option>
<option value="Kesehatan">🏥 Kesehatan</option>
</select>
<input type="text" id="bJumlah" placeholder="Jumlah (misal: 10 kg / Rp 500.000)">
<input type="date" id="bTanggal">
<textarea id="bKeterangan" placeholder="Keterangan tambahan" rows="2"></textarea>
<button onclick="simpanBantuan()">💾 Simpan Bantuan</button>
</div>
<div class="card">
<h3>📋 Histori Bantuan</h3>
<div class="table-box"><table id="tabelBantuan"><tr><th>Tanggal</th><th>Nama</th><th>Bantuan</th></tr></table></div>
</div>
<div class="card">
<h3>📈 Grafik Bantuan (Bulanan)</h3>
<canvas id="grafik" height="150"></canvas>
</div>
<div class="card">
<button onclick="window.location='laporan.php'" style="background:#8e44ad;margin-bottom:8px;">📋 Download Laporan</button>
<button class="btn-logout" onclick="window.location='logout.php'">🚪 Logout</button>
</div>
</div>
<!-- MODAL TAMBAH PENDUDUK MISKIN -->
<div id="modalPoverty" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:9999; align-items:center; justify-content:center;">
<div style="background:white; width:400px; max-width:95vw; border-radius:12px; padding:25px; max-height:90vh; overflow-y:auto; box-shadow: 0 20px 60px rgba(0,0,0,0.4);">
<h3 style="margin:0 0 15px 0; color:#e74c3c; font-size:16px;">⚠️ Tambah Penduduk Miskin</h3>
<input type="text" id="fNamaPoverty" placeholder="Nama Kepala Keluarga *" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="text" id="fNikPoverty" placeholder="NIK" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="text" id="fAlamatPoverty" placeholder="Alamat" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="text" id="fPekerjaanPoverty" placeholder="Pekerjaan" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="number" id="fPenghasilanPoverty" placeholder="Penghasilan (Rp)" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="number" id="fAnggotaPoverty" placeholder="Jumlah Anggota Keluarga" value="1" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="number" id="fTanggunganPoverty" placeholder="Jumlah Tanggungan" value="0" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<select id="fKategoriPoverty" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<option value="Miskin">Miskin</option><option value="Miskin Ekstrem">Miskin Ekstrem</option><option value="Hampir Miskin">Hampir Miskin</option>
</select>
<select id="fStatusBantuanPoverty" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<option value="Belum">Belum Menerima</option><option value="Pernah">Pernah Menerima</option><option value="Sedang">Sedang Menerima</option>
</select>
<textarea id="fKetPoverty" placeholder="Keterangan" rows="2" style="width:100%;padding:9px;margin-bottom:12px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;"></textarea>
<input type="file" id="fFotoPoverty" accept="image/*" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;" onchange="previewFoto(this)">
<div id="previewFotoPoverty" class="foto-preview" style="display:none;"><img id="previewImgPoverty" src=""></div>
<p id="modalKoordinat" style="font-size:12px;color:#888;margin:0 0 12px 0;"></p>
<div style="display:flex;gap:8px;">
<button onclick="simpanPoverty()" style="flex:1;padding:10px;background:#e74c3c;color:white;border:none;border-radius:5px;cursor:pointer;font-size:14px;font-weight:bold;">💾 Simpan</button>
<button onclick="tutupModalPoverty()" style="flex:1;padding:10px;background:#95a5a6;color:white;border:none;border-radius:5px;cursor:pointer;font-size:14px;">✖ Batal</button>
</div>
</div>
</div>
<!-- MODAL EDIT PENDUDUK MISKIN -->
<div id="modalEditPoverty" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:9999; align-items:center; justify-content:center;">
<div style="background:white; width:400px; max-width:95vw; border-radius:12px; padding:25px; max-height:90vh; overflow-y:auto; box-shadow: 0 20px 60px rgba(0,0,0,0.4);">
<h3 style="margin:0 0 15px 0; color:#f39c12; font-size:16px;">✏️ Edit Penduduk Miskin</h3>
<input type="hidden" id="eIdPoverty">
<input type="text" id="eNamaPoverty" placeholder="Nama Kepala Keluarga *" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="text" id="eNikPoverty" placeholder="NIK" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="text" id="eAlamatPoverty" placeholder="Alamat" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="text" id="ePekerjaanPoverty" placeholder="Pekerjaan" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="number" id="ePenghasilanPoverty" placeholder="Penghasilan (Rp)" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="number" id="eAnggotaPoverty" placeholder="Jumlah Anggota Keluarga" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<input type="number" id="eTanggunganPoverty" placeholder="Jumlah Tanggungan" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<select id="eKategoriPoverty" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<option value="Miskin">Miskin</option><option value="Miskin Ekstrem">Miskin Ekstrem</option><option value="Hampir Miskin">Hampir Miskin</option>
</select>
<select id="eStatusBantuanPoverty" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;">
<option value="Belum">Belum Menerima</option><option value="Pernah">Pernah Menerima</option><option value="Sedang">Sedang Menerima</option>
</select>
<textarea id="eKetPoverty" placeholder="Keterangan" rows="2" style="width:100%;padding:9px;margin-bottom:12px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;"></textarea>
<input type="file" id="eFotoPoverty" accept="image/*" style="width:100%;padding:9px;margin-bottom:8px;border:1px solid #ddd;border-radius:5px;font-size:13px;box-sizing:border-box;" onchange="previewEditFoto(this)">
<input type="hidden" id="eFotoLama" value="">
<div id="editPreviewFoto" class="foto-preview" style="display:none;"><img id="editPreviewImg" src=""></div>
<div style="display:flex;gap:8px;">
<button onclick="simpanEditPoverty()" style="flex:1;padding:10px;background:#f39c12;color:white;border:none;border-radius:5px;cursor:pointer;font-size:14px;font-weight:bold;">💾 Simpan</button>
<button onclick="tutupModalEditPoverty()" style="flex:1;padding:10px;background:#95a5a6;color:white;border:none;border-radius:5px;cursor:pointer;font-size:14px;">✖ Batal</button>
</div>
</div>
</div>
<!-- MODAL HAPUS DAN BERI BANTUAN (SEDERHANA) -->
<div id="modalHapusPoverty" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:9999; align-items:center; justify-content:center;">
<div style="background:white; width:340px; border-radius:12px; padding:25px; text-align:center;">
<h3 style="color:#e74c3c;">Hapus Data?</h3>
<p id="modalHapusNama" style="margin:15px 0;"></p>
<button onclick="konfirmasiHapusPoverty()" style="background:#e74c3c;color:white;padding:10px 20px;border:none;border-radius:5px;cursor:pointer;">Ya, Hapus</button>
<button onclick="document.getElementById('modalHapusPoverty').style.display='none'" style="background:#95a5a6;color:white;padding:10px 20px;border:none;border-radius:5px;cursor:pointer;">Batal</button>
</div>
</div>
<div id="modalBeriBantuan" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:9999; align-items:center; justify-content:center;">
<div style="background:white; width:380px; border-radius:12px; padding:25px;">
<h3 style="color:#27ae60;">🎁 Beri Bantuan</h3>
<p id="beriNamaPenduduk"></p>
<input type="hidden" id="beriPendudukId">
<select id="beriJenis" style="width:100%;padding:8px;margin:10px 0;"><option value="Beras">🌾 Beras</option><option value="Sembako">🛒 Sembako</option><option value="Uang Tunai">💰 Uang Tunai</option></select>
<input type="text" id="beriJumlah" placeholder="Jumlah" style="width:100%;padding:8px;margin:10px 0;">
<input type="date" id="beriTanggal" style="width:100%;padding:8px;margin:10px 0;">
<textarea id="beriKeterangan" placeholder="Keterangan" rows="2" style="width:100%;padding:8px;margin:10px 0;"></textarea>
<button onclick="simpanBeriBantuan()" style="background:#27ae60;color:white;padding:10px;width:100%;border:none;border-radius:5px;cursor:pointer;">💾 Simpan</button>
<button onclick="document.getElementById('modalBeriBantuan').style.display='none'" style="background:#95a5a6;color:white;padding:10px;width:100%;border:none;border-radius:5px;cursor:pointer;margin-top:5px;">Batal</button>
</div>
</div>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
// ==================== MAP INIT ====================
var map = L.map('map').setView([-0.0263, 109.3425], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '&copy; OpenStreetMap' }).addTo(map);
var masjidLayer = L.layerGroup().addTo(map);
var gerejaLayer = L.layerGroup().addTo(map);
var povertyLayer = L.layerGroup().addTo(map);
var radiusLayer = L.layerGroup().addTo(map);
var masjidPoints = [], gerejaPoints = [], povertyPoints = [];
var currentRadius = 300;
// ==================== IKON ====================
function createMasjidIcon() {
return L.divIcon({ className: 'masjid-icon', html: '<div style="background:#27ae60; width:28px; height:28px; border-radius:50%; display:flex; align-items:center; justify-content:center; border:2px solid white; box-shadow:0 2px 5px rgba(0,0,0,0.3);"><span style="font-size:14px;">🕌</span></div>', iconSize: [28,28], iconAnchor: [14,14], popupAnchor: [0,-14] });
}
function createGerejaIcon() {
return L.divIcon({ className: 'gereja-icon', html: '<div style="background:#9b59b6; width:28px; height:28px; border-radius:50%; display:flex; align-items:center; justify-content:center; border:2px solid white; box-shadow:0 2px 5px rgba(0,0,0,0.3);"><span style="font-size:14px;">⛪</span></div>', iconSize: [28,28], iconAnchor: [14,14], popupAnchor: [0,-14] });
}
function createPovertyIcon(isInside) {
var color = isInside ? '#27ae60' : '#e74c3c';
var iconChar = isInside ? '✓' : '⚠️';
return L.divIcon({ className: 'poverty-icon', html: '<div style="background:'+color+'; width:22px; height:22px; border-radius:50%; display:flex; align-items:center; justify-content:center; border:2px solid white; box-shadow:0 2px 5px rgba(0,0,0,0.3);"><span style="font-size:11px; color:white; font-weight:bold;">'+iconChar+'</span></div>', iconSize: [22,22], iconAnchor: [11,11], popupAnchor: [0,-11] });
}
function escapeHtml(str) { if (!str) return ''; return str.replace(/['"\\]/g, '\\$&').replace(/\n/g, '\\n'); }
// ==================== PREVIEW FOTO ====================
function previewFoto(input) {
var previewDiv = document.getElementById('previewFotoPoverty');
var previewImg = document.getElementById('previewImgPoverty');
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) { previewImg.src = e.target.result; previewDiv.style.display = 'block'; }
reader.readAsDataURL(input.files[0]);
} else { previewDiv.style.display = 'none'; previewImg.src = ''; }
}
function previewEditFoto(input) {
var previewDiv = document.getElementById('editPreviewFoto');
var previewImg = document.getElementById('editPreviewImg');
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) { previewImg.src = e.target.result; previewDiv.style.display = 'block'; }
reader.readAsDataURL(input.files[0]);
} else if (document.getElementById('eFotoLama').value) { previewImg.src = document.getElementById('eFotoLama').value; previewDiv.style.display = 'block'; }
else { previewDiv.style.display = 'none'; previewImg.src = ''; }
}
// ==================== LOAD DATA ====================
function loadSemua() { loadMasjid(); loadGereja(); loadPoverty(); loadBantuan(); loadGrafik(); }
function loadMasjid() {
fetch('api.php?action=get_masjid').then(r=>r.json()).then(data=>{
masjidLayer.clearLayers(); masjidPoints = Array.isArray(data)?data:[];
masjidPoints.forEach(item=>{
var marker = L.marker([parseFloat(item.lat), parseFloat(item.lng)], {icon: createMasjidIcon()});
marker.data = item; marker.on('click', e=>showMasjidPopup(e.target.data));
marker.addTo(masjidLayer);
});
updateStats();
}).catch(()=>console.error('Gagal load masjid'));
}
function loadGereja() {
fetch('api.php?action=get_gereja').then(r=>r.json()).then(data=>{
gerejaLayer.clearLayers(); gerejaPoints = Array.isArray(data)?data:[];
gerejaPoints.forEach(item=>{
var marker = L.marker([parseFloat(item.lat), parseFloat(item.lng)], {icon: createGerejaIcon()});
marker.data = item; marker.on('click', e=>showGerejaPopup(e.target.data));
marker.addTo(gerejaLayer);
});
updateStats();
}).catch(()=>console.error('Gagal load gereja'));
}
function loadPoverty() {
fetch('api.php?action=get_poverty').then(r=>r.json()).then(data=>{
povertyPoints = Array.isArray(data)?data:[];
document.getElementById('miskin').innerHTML = povertyPoints.length;
updateStats();
}).catch(()=>console.error('Gagal load poverty'));
}
function loadBantuan() {
fetch('api.php?action=get_bantuan').then(r=>r.json()).then(data=>{
var tabel = document.getElementById('tabelBantuan');
while(tabel.rows.length>1) tabel.deleteRow(1);
if(Array.isArray(data)) data.forEach(b=>{ var row=tabel.insertRow(); row.insertCell(0).innerHTML=b.tanggal_bantuan||'-'; row.insertCell(1).innerHTML=b.nama_penduduk||'-'; row.insertCell(2).innerHTML=b.jenis_bantuan||'-'; });
}).catch(()=>{});
}
var grafikChart=null;
function loadGrafik() {
fetch('api.php?action=get_stats_bantuan').then(r=>r.json()).then(data=>{
var labels=['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agt','Sep','Okt','Nov','Des'], values=new Array(12).fill(0);
if(Array.isArray(data)) data.forEach(d=>{ var idx=labels.indexOf(d.bulan); if(idx>=0) values[idx]=parseInt(d.jumlah); });
var ctx=document.getElementById('grafik'); if(grafikChart) grafikChart.destroy();
grafikChart=new Chart(ctx,{type:'bar',data:{labels:labels,datasets:[{label:'Jumlah Bantuan',data:values,backgroundColor:'#3498db'}]},options:{responsive:true,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{stepSize:1}}}}});
}).catch(()=>{ var ctx=document.getElementById('grafik'); if(grafikChart) grafikChart.destroy(); grafikChart=new Chart(ctx,{type:'bar',data:{labels:['Jan','Feb','Mar','Apr','Mei'],datasets:[{label:'Jumlah Bantuan',data:[0,0,0,0,0],backgroundColor:'#3498db'}]},options:{responsive:true,plugins:{legend:{display:false}}}}); });
}
// ==================== POPUP ====================
function showMasjidPopup(data){
var content='<div style="min-width:250px;"><h4 style="margin:0 0 8px 0;color:#2c3e50;">🕌 MASJID</h4><div><strong>Nama:</strong> '+(data.nama||'-')+'</div><div><strong>Alamat:</strong> '+(data.alamat||'-')+'</div><div><strong>Koordinat:</strong> '+data.lat+', '+data.lng+'</div><div class="clearfix"><button class="btn-edit" onclick="editMasjid('+data.id+',\''+escapeHtml(data.nama)+'\',\''+escapeHtml(data.alamat)+'\','+data.lat+','+data.lng+')">✏️ Edit</button><button class="btn-hapus" onclick="hapusMasjid('+data.id+')">🗑️ Hapus</button></div></div>';
L.popup().setLatLng([data.lat,data.lng]).setContent(content).openOn(map);
}
function showGerejaPopup(data){
var content='<div style="min-width:250px;"><h4 style="margin:0 0 8px 0;color:#2c3e50;">⛪ GEREJA</h4><div><strong>Nama:</strong> '+(data.nama||'-')+'</div><div><strong>Alamat:</strong> '+(data.alamat||'-')+'</div><div><strong>Koordinat:</strong> '+data.lat+', '+data.lng+'</div><div class="clearfix"><button class="btn-edit" onclick="editGereja('+data.id+',\''+escapeHtml(data.nama)+'\',\''+escapeHtml(data.alamat)+'\','+data.lat+','+data.lng+')">✏️ Edit</button><button class="btn-hapus" onclick="hapusGereja('+data.id+')">🗑️ Hapus</button></div></div>';
L.popup().setLatLng([data.lat,data.lng]).setContent(content).openOn(map);
}
function editMasjid(id,namaLama,alamatLama,lat,lng){
map.closePopup();
var form='<div class="popup-form"><h4>✏️ Edit Masjid</h4><input type="text" id="editNama" value="'+escapeHtml(namaLama)+'" placeholder="Nama Masjid"><input type="text" id="editAlamat" value="'+escapeHtml(alamatLama)+'" placeholder="Alamat"><button onclick="simpanEditMasjid('+id+','+lat+','+lng+')" style="width:100%;padding:8px;background:#27ae60;color:white;border:none;border-radius:4px;cursor:pointer;">💾 Simpan Perubahan</button></div>';
L.popup().setLatLng([lat,lng]).setContent(form).openOn(map);
}
function simpanEditMasjid(id,lat,lng){
var namaBaru=document.getElementById('editNama').value.trim(), alamatBaru=document.getElementById('editAlamat').value.trim();
if(!namaBaru){ alert('Nama masjid wajib diisi!'); return; }
fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'update_masjid',id:id,nama:namaBaru,alamat:alamatBaru,lat:lat,lng:lng})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ alert('✅ Masjid berhasil diupdate!'); map.closePopup(); loadMasjid(); loadGereja(); } else { alert('❌ Gagal: '+(res.msg||'')); } });
}
function editGereja(id,namaLama,alamatLama,lat,lng){
map.closePopup();
var form='<div class="popup-form"><h4>✏️ Edit Gereja</h4><input type="text" id="editNama" value="'+escapeHtml(namaLama)+'" placeholder="Nama Gereja"><input type="text" id="editAlamat" value="'+escapeHtml(alamatLama)+'" placeholder="Alamat"><button onclick="simpanEditGereja('+id+','+lat+','+lng+')" style="width:100%;padding:8px;background:#9b59b6;color:white;border:none;border-radius:4px;cursor:pointer;">💾 Simpan Perubahan</button></div>';
L.popup().setLatLng([lat,lng]).setContent(form).openOn(map);
}
function simpanEditGereja(id,lat,lng){
var namaBaru=document.getElementById('editNama').value.trim(), alamatBaru=document.getElementById('editAlamat').value.trim();
if(!namaBaru){ alert('Nama gereja wajib diisi!'); return; }
fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'update_gereja',id:id,nama:namaBaru,alamat:alamatBaru,lat:lat,lng:lng})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ alert('✅ Gereja berhasil diupdate!'); map.closePopup(); loadMasjid(); loadGereja(); } else { alert('❌ Gagal: '+(res.msg||'')); } });
}
function hapusMasjid(id){ if(confirm('Yakin ingin menghapus masjid ini?')){ fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'delete_masjid',id:id})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ alert('✅ Masjid dihapus!'); map.closePopup(); loadMasjid(); loadGereja(); } }); } }
function hapusGereja(id){ if(confirm('Yakin ingin menghapus gereja ini?')){ fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'delete_gereja',id:id})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ alert('✅ Gereja dihapus!'); map.closePopup(); loadMasjid(); loadGereja(); } }); } }
var _hapusPovertyId=0;
function hapusPoverty(id){ _hapusPovertyId=id; var p=povertyPoints.find(x=>x.id==id); var nama=p?p.nama:'data ini'; document.getElementById('modalHapusNama').innerHTML='Data "'+nama+'" akan dihapus permanen.'; map.closePopup(); document.getElementById('modalHapusPoverty').style.display='flex'; }
function konfirmasiHapusPoverty(){ document.getElementById('modalHapusPoverty').style.display='none'; fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'delete_poverty',id:_hapusPovertyId})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ alert('✅ Data berhasil dihapus!'); loadPoverty(); } else { alert('❌ Gagal: '+(res.msg||'')); } }).catch(err=>{ alert('❌ Error: '+err.message); }); }
// ==================== STATISTIK & RADIUS ====================
function updateStats(){
var allIbadah=masjidPoints.length+gerejaPoints.length;
document.getElementById('ibadah').innerHTML=allIbadah;
document.getElementById('miskin').innerHTML=povertyPoints.length;
radiusLayer.clearLayers();
var allIbadahPoints=masjidPoints.concat(gerejaPoints);
allIbadahPoints.forEach(item=>{ L.circle([parseFloat(item.lat),parseFloat(item.lng)],{radius:currentRadius,color:'#3498db',fillColor:'#3498db',fillOpacity:0.1,weight:1.5}).addTo(radiusLayer); });
povertyLayer.clearLayers();
var dalam=0,luar=0;
povertyPoints.forEach(p=>{
var isInside=false, pLat=parseFloat(p.lat), pLng=parseFloat(p.lng);
allIbadahPoints.forEach(item=>{ if(map.distance([parseFloat(item.lat),parseFloat(item.lng)],[pLat,pLng])<=currentRadius) isInside=true; });
if(isInside) dalam++; else luar++;
var fotoHtml=(p.foto && p.foto!='')?'<img src="'+p.foto+'" style="max-width:100%; max-height:100px; border-radius:8px; margin:5px 0;"><br>':'';
L.marker([pLat,pLng],{icon:createPovertyIcon(isInside)}).bindPopup('<b>👤 '+(p.nama||'-')+'</b><br>'+fotoHtml+'NIK: '+(p.nik||'-')+'<br>Pekerjaan: '+(p.pekerjaan||'-')+'<br>Penghasilan: Rp '+(parseInt(p.penghasilan||0)).toLocaleString('id-ID')+'<br>Anggota: '+(p.jumlah_anggota_keluarga||'1')+'<br>Kategori: '+(p.kategori_kemiskinan||'-')+'<br>Status Bantuan: '+(p.status_bantuan||'-')+'<br>Status: '+(isInside?'✅ Dalam Radius':'❌ Luar Radius')+'<br><div style="margin-top:8px;"><button onclick="bukaBeriBantuan('+p.id+',\''+(p.nama||'')+'\')" style="width:100%;padding:6px;background:#27ae60;color:white;border:none;border-radius:4px;cursor:pointer;margin-bottom:4px;font-size:11px;">🎁 Beri Bantuan</button></div><div class="clearfix"><button class="btn-edit" onclick="bukaEditPoverty('+p.id+')">✏️ Edit</button><button class="btn-hapus" onclick="hapusPoverty('+p.id+')">🗑️ Hapus</button></div>').addTo(povertyLayer);
});
document.getElementById('dalam').innerHTML=dalam;
document.getElementById('luar').innerHTML=luar;
}
document.getElementById('radiusSlider').addEventListener('input',function(){ document.getElementById('radiusValue').innerHTML=this.value; });
function terapkanRadius(){ currentRadius=parseInt(document.getElementById('radiusSlider').value); updateStats(); }
function simpanBantuan(){
var jenis=document.getElementById('bJenis').value, jumlah=document.getElementById('bJumlah').value.trim(), tanggal=document.getElementById('bTanggal').value, ket=document.getElementById('bKeterangan').value.trim();
if(!jumlah||!tanggal){ alert('Jumlah dan tanggal wajib diisi!'); return; }
fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'add_bantuan',jenis_bantuan:jenis,jumlah:jumlah,tanggal:tanggal,keterangan:ket})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ alert('✅ Bantuan berhasil disimpan!'); document.getElementById('bJumlah').value=''; document.getElementById('bTanggal').value=''; document.getElementById('bKeterangan').value=''; loadBantuan(); loadGrafik(); } else { alert('❌ Gagal: '+(res.msg||'')); } });
}
// ==================== KLIK PETA ====================
map.on('click',function(e){ var lat=e.latlng.lat, lng=e.latlng.lng; var form='<div class="popup-form"><b>📍 Tambah Data</b><br><br><button onclick="bukaFormMasjid('+lat+','+lng+')" style="width:100%;padding:7px;margin-bottom:5px;background:#27ae60;color:white;border:none;border-radius:4px;cursor:pointer;">🕌 Tambah Masjid</button><button onclick="bukaFormGereja('+lat+','+lng+')" style="width:100%;padding:7px;margin-bottom:5px;background:#9b59b6;color:white;border:none;border-radius:4px;cursor:pointer;">⛪ Tambah Gereja</button><button onclick="bukaFormPoverty('+lat+','+lng+')" style="width:100%;padding:7px;background:#e74c3c;color:white;border:none;border-radius:4px;cursor:pointer;">⚠️ Tambah Penduduk Miskin</button></div>'; L.popup().setLatLng([lat,lng]).setContent(form).openOn(map); });
function bukaFormMasjid(lat,lng){ map.closePopup(); var form='<div class="popup-form"><b>🕌 Input Masjid</b><br><br><input type="text" id="fNamaMasjid" placeholder="Nama Masjid *"><input type="text" id="fAlamatMasjid" placeholder="Alamat"><button onclick="simpanMasjid('+lat+','+lng+')" style="width:100%;padding:7px;background:#27ae60;color:white;border:none;border-radius:4px;cursor:pointer;">💾 Simpan</button></div>'; L.popup().setLatLng([lat,lng]).setContent(form).openOn(map); }
function bukaFormGereja(lat,lng){ map.closePopup(); var form='<div class="popup-form"><b>⛪ Input Gereja</b><br><br><input type="text" id="fNamaGereja" placeholder="Nama Gereja *"><input type="text" id="fAlamatGereja" placeholder="Alamat"><button onclick="simpanGereja('+lat+','+lng+')" style="width:100%;padding:7px;background:#9b59b6;color:white;border:none;border-radius:4px;cursor:pointer;">💾 Simpan</button></div>'; L.popup().setLatLng([lat,lng]).setContent(form).openOn(map); }
var _povertyLat=0,_povertyLng=0;
function bukaFormPoverty(lat,lng){ map.closePopup(); _povertyLat=lat; _povertyLng=lng; document.getElementById('fNamaPoverty').value=''; document.getElementById('fNikPoverty').value=''; document.getElementById('fAlamatPoverty').value=''; document.getElementById('fPekerjaanPoverty').value=''; document.getElementById('fPenghasilanPoverty').value=''; document.getElementById('fAnggotaPoverty').value='1'; document.getElementById('fTanggunganPoverty').value='0'; document.getElementById('fKategoriPoverty').value='Miskin'; document.getElementById('fStatusBantuanPoverty').value='Belum'; document.getElementById('fKetPoverty').value=''; document.getElementById('fFotoPoverty').value=''; document.getElementById('previewFotoPoverty').style.display='none'; document.getElementById('modalKoordinat').innerHTML='📍 Koordinat: '+lat.toFixed(6)+', '+lng.toFixed(6); document.getElementById('modalPoverty').style.display='flex'; }
function tutupModalPoverty(){ document.getElementById('modalPoverty').style.display='none'; }
function bukaEditPoverty(id){
map.closePopup();
var p=povertyPoints.find(x=>x.id==id);
if(!p){ alert('Data tidak ditemukan!'); return; }
document.getElementById('eIdPoverty').value=p.id;
document.getElementById('eNamaPoverty').value=p.nama||'';
document.getElementById('eNikPoverty').value=p.nik||'';
document.getElementById('eAlamatPoverty').value=p.alamat||'';
document.getElementById('ePekerjaanPoverty').value=p.pekerjaan||'';
document.getElementById('ePenghasilanPoverty').value=p.penghasilan||0;
document.getElementById('eAnggotaPoverty').value=p.jumlah_anggota_keluarga||1;
document.getElementById('eTanggunganPoverty').value=p.jumlah_tanggungan||0;
document.getElementById('eKategoriPoverty').value=p.kategori_kemiskinan||'Miskin';
document.getElementById('eStatusBantuanPoverty').value=p.status_bantuan||'Belum';
document.getElementById('eKetPoverty').value=p.keterangan||'';
var previewDiv=document.getElementById('editPreviewFoto'), previewImg=document.getElementById('editPreviewImg');
if(p.foto && p.foto!=''){ previewImg.src=p.foto; previewDiv.style.display='block'; document.getElementById('eFotoLama').value=p.foto; }
else{ previewDiv.style.display='none'; document.getElementById('eFotoLama').value=''; }
document.getElementById('eFotoPoverty').value='';
document.getElementById('modalEditPoverty').style.display='flex';
}
function tutupModalEditPoverty(){ document.getElementById('modalEditPoverty').style.display='none'; }
function bukaBeriBantuan(id,nama){ map.closePopup(); document.getElementById('beriPendudukId').value=id; document.getElementById('beriNamaPenduduk').innerHTML='Penerima: '+nama; document.getElementById('beriJenis').value='Sembako'; document.getElementById('beriJumlah').value=''; document.getElementById('beriTanggal').value=new Date().toISOString().split('T')[0]; document.getElementById('beriKeterangan').value=''; document.getElementById('modalBeriBantuan').style.display='flex'; }
function simpanBeriBantuan(){
var penduduk_id=parseInt(document.getElementById('beriPendudukId').value), jenis=document.getElementById('beriJenis').value, jumlah=document.getElementById('beriJumlah').value.trim(), tanggal=document.getElementById('beriTanggal').value, ket=document.getElementById('beriKeterangan').value.trim();
if(!jumlah||!tanggal){ alert('Jumlah dan tanggal wajib diisi!'); return; }
fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'add_bantuan',id_penduduk:penduduk_id,jenis_bantuan:jenis,jumlah:jumlah,tanggal:tanggal,keterangan:ket})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ return fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'update_poverty',id:penduduk_id,status_bantuan:'Pernah'})}).then(r=>r.json()); } else { throw new Error(res.msg||'Gagal simpan bantuan'); } }).then(res2=>{ document.getElementById('modalBeriBantuan').style.display='none'; alert('✅ Bantuan berhasil dicatat!'); loadPoverty(); loadBantuan(); loadGrafik(); }).catch(err=>{ alert('❌ Error: '+err.message); });
}
// ==================== SIMPAN POVERTY DENGAN FOTO (YANG DIPERBAIKI) ====================
function simpanPoverty(){
var nama=document.getElementById('fNamaPoverty').value.trim();
var nik=document.getElementById('fNikPoverty').value.trim();
var alamat=document.getElementById('fAlamatPoverty').value.trim();
var pekerjaan=document.getElementById('fPekerjaanPoverty').value.trim();
var penghasilan=parseInt(document.getElementById('fPenghasilanPoverty').value)||0;
var anggota=parseInt(document.getElementById('fAnggotaPoverty').value)||1;
var tanggungan=parseInt(document.getElementById('fTanggunganPoverty').value)||0;
var kategori=document.getElementById('fKategoriPoverty').value;
var status_bantuan=document.getElementById('fStatusBantuanPoverty').value;
var ket=document.getElementById('fKetPoverty').value.trim();
var lat=_povertyLat;
var lng=_povertyLng;
var fotoFile=document.getElementById('fFotoPoverty').files[0];
if(!nama){ alert('Nama wajib diisi!'); return; }
if(fotoFile){
var formData=new FormData();
formData.append('action','upload_foto');
formData.append('foto',fotoFile);
fetch('api.php',{method:'POST',body:formData})
.then(r=>r.json())
.then(uploadRes=>{
if(uploadRes.status==='ok'){
simpanPovertyData(uploadRes.foto_url,nama,nik,alamat,pekerjaan,penghasilan,anggota,tanggungan,kategori,status_bantuan,ket,lat,lng);
} else { alert('Gagal upload foto: '+uploadRes.msg); }
}).catch(err=>{ alert('Error upload: '+err.message); });
} else {
simpanPovertyData('',nama,nik,alamat,pekerjaan,penghasilan,anggota,tanggungan,kategori,status_bantuan,ket,lat,lng);
}
}
function simpanPovertyData(fotoUrl,nama,nik,alamat,pekerjaan,penghasilan,anggota,tanggungan,kategori,status_bantuan,ket,lat,lng){
fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'add_poverty',nama:nama,nik:nik,alamat:alamat,pekerjaan:pekerjaan,penghasilan:penghasilan,anggota:anggota,tanggungan:tanggungan,kategori:kategori,status_bantuan:status_bantuan,keterangan:ket,foto:fotoUrl,lat:lat,lng:lng})})
.then(r=>r.json())
.then(res=>{
if(res.status==='ok'){
alert('✅ Data penduduk miskin berhasil ditambahkan!');
tutupModalPoverty();
document.getElementById('fFotoPoverty').value='';
document.getElementById('previewFotoPoverty').style.display='none';
loadPoverty();
} else { alert('❌ Gagal: '+(res.msg||'')); }
}).catch(err=>{ alert('❌ Error: '+err.message); });
}
function simpanEditPoverty(){
var id=parseInt(document.getElementById('eIdPoverty').value);
var nama=document.getElementById('eNamaPoverty').value.trim();
var nik=document.getElementById('eNikPoverty').value.trim();
var alamat=document.getElementById('eAlamatPoverty').value.trim();
var pekerjaan=document.getElementById('ePekerjaanPoverty').value.trim();
var penghasilan=parseInt(document.getElementById('ePenghasilanPoverty').value)||0;
var anggota=parseInt(document.getElementById('eAnggotaPoverty').value)||1;
var tanggungan=parseInt(document.getElementById('eTanggunganPoverty').value)||0;
var kategori=document.getElementById('eKategoriPoverty').value;
var status_bantuan=document.getElementById('eStatusBantuanPoverty').value;
var ket=document.getElementById('eKetPoverty').value.trim();
var fotoLama=document.getElementById('eFotoLama').value;
var fotoFile=document.getElementById('eFotoPoverty').files[0];
if(!nama){ alert('Nama wajib diisi!'); return; }
if(fotoFile){
var formData=new FormData();
formData.append('action','upload_foto');
formData.append('foto',fotoFile);
fetch('api.php',{method:'POST',body:formData})
.then(r=>r.json())
.then(uploadRes=>{
if(uploadRes.status==='ok'){ updatePovertyData(id,uploadRes.foto_url,nama,nik,alamat,pekerjaan,penghasilan,anggota,tanggungan,kategori,status_bantuan,ket); }
else{ alert('Gagal upload foto: '+uploadRes.msg); }
}).catch(err=>{ alert('Error upload: '+err.message); });
} else { updatePovertyData(id,fotoLama,nama,nik,alamat,pekerjaan,penghasilan,anggota,tanggungan,kategori,status_bantuan,ket); }
}
function updatePovertyData(id,fotoUrl,nama,nik,alamat,pekerjaan,penghasilan,anggota,tanggungan,kategori,status_bantuan,ket){
fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'update_poverty',id:id,nama:nama,nik:nik,alamat:alamat,pekerjaan:pekerjaan,penghasilan:penghasilan,anggota:anggota,tanggungan:tanggungan,kategori:kategori,status_bantuan:status_bantuan,keterangan:ket,foto:fotoUrl})})
.then(r=>r.json())
.then(res=>{
if(res.status==='ok'){ alert('✅ Data berhasil diupdate!'); tutupModalEditPoverty(); loadPoverty(); }
else{ alert('❌ Gagal: '+(res.msg||'')); }
}).catch(err=>{ alert('❌ Error: '+err.message); });
}
function simpanMasjid(lat,lng){ var nama=document.getElementById('fNamaMasjid').value.trim(), alamat=document.getElementById('fAlamatMasjid').value.trim(); if(!nama){ alert('Nama masjid wajib diisi!'); return; } fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'add_masjid',nama:nama,alamat:alamat,lat:lat,lng:lng})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ alert('✅ Masjid berhasil ditambahkan!'); map.closePopup(); loadMasjid(); } else { alert('❌ Gagal: '+(res.msg||'')); } }); }
function simpanGereja(lat,lng){ var nama=document.getElementById('fNamaGereja').value.trim(), alamat=document.getElementById('fAlamatGereja').value.trim(); if(!nama){ alert('Nama gereja wajib diisi!'); return; } fetch('api.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'add_gereja',nama:nama,alamat:alamat,lat:lat,lng:lng})}).then(r=>r.json()).then(res=>{ if(res.status==='ok'){ alert('✅ Gereja berhasil ditambahkan!'); map.closePopup(); loadGereja(); } else { alert('❌ Gagal: '+(res.msg||'')); } }); }
// ==================== LOAD KECAMATAN & START ====================
fetch('Admin_Kecamatan.json').then(r=>r.json()).then(data=>{ L.geoJSON(data,{style:{color:'#2c3e50',weight:2,fillOpacity:0.04,dashArray:'5,5'}}).addTo(map); }).catch(err=>console.warn('GeoJSON tidak ditemukan:',err));
loadSemua();
</script>
</body>
</html>