Fix resident aid saving bug and implement Bantuan Darurat status

This commit is contained in:
fananazril
2026-06-13 13:06:30 +07:00
parent bd95f5581d
commit ac5fbeb72e
14 changed files with 55 additions and 20 deletions
+1 -1
View File
@@ -76,7 +76,7 @@ $ibadahList = $db->query("SELECT id, nama, jenis FROM rumah_ibadah ORDER BY nama
</code> </code>
</div> </div>
<div style="margin-top:10px;font-size:11px;color:var(--text3);"> <div style="margin-top:10px;font-size:11px;color:var(--text3);">
⚠️ status_bantuan: belum / sudah / menunggu &nbsp;|&nbsp; Baris pertama bisa berupa header (akan dideteksi otomatis) ⚠️ status_bantuan: belum / sudah / menunggu / darurat &nbsp;|&nbsp; Baris pertama bisa berupa header (akan dideteksi otomatis)
</div> </div>
<a href="<?= BASE_URL ?>/admin/template_penduduk.csv" class="btn btn-ghost btn-sm" style="margin-top:12px;" onclick="downloadTemplate('penduduk');return false;"> <a href="<?= BASE_URL ?>/admin/template_penduduk.csv" class="btn btn-ghost btn-sm" style="margin-top:12px;" onclick="downloadTemplate('penduduk');return false;">
<i class="bi bi-download"></i> Download Template CSV <i class="bi bi-download"></i> Download Template CSV
+11 -4
View File
@@ -21,8 +21,9 @@ $stats = [
'sudah' => (int)$db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='sudah'")->fetchColumn(), 'sudah' => (int)$db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='sudah'")->fetchColumn(),
'belum' => (int)$db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='belum'")->fetchColumn(), 'belum' => (int)$db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='belum'")->fetchColumn(),
'menunggu' => (int)$db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='menunggu'")->fetchColumn(), 'menunggu' => (int)$db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='menunggu'")->fetchColumn(),
'darurat' => (int)$db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='darurat'")->fetchColumn(),
'anggota' => (int)$db->query("SELECT SUM(jumlah_anggota) FROM penduduk_miskin")->fetchColumn(), 'anggota' => (int)$db->query("SELECT SUM(jumlah_anggota) FROM penduduk_miskin")->fetchColumn(),
'nominal' => (float)$db->query("SELECT COALESCE(SUM(nominal_bantuan),0) FROM penduduk_miskin WHERE status_bantuan='sudah' AND nominal_bantuan IS NOT NULL")->fetchColumn(), 'nominal' => (float)$db->query("SELECT COALESCE(SUM(nominal_bantuan),0) FROM penduduk_miskin WHERE status_bantuan IN ('sudah','darurat') AND nominal_bantuan IS NOT NULL")->fetchColumn(),
]; ];
// Per jenis ibadah // Per jenis ibadah
@@ -103,6 +104,11 @@ $trenBulan = $db->query("
<div class="stat-value"><?= $stats['menunggu'] ?></div> <div class="stat-value"><?= $stats['menunggu'] ?></div>
<div class="stat-label">Menunggu Verif.</div> <div class="stat-label">Menunggu Verif.</div>
</div> </div>
<div class="stat-card purple" style="--purple:#a855f7">
<div class="stat-icon">🚨</div>
<div class="stat-value"><?= $stats['darurat'] ?></div>
<div class="stat-label">Bantuan Darurat (Musibah)</div>
</div>
<div class="stat-card blue"> <div class="stat-card blue">
<div class="stat-icon">👤</div> <div class="stat-icon">👤</div>
<div class="stat-value"><?= number_format($stats['anggota'], 0, ',', '.') ?></div> <div class="stat-value"><?= number_format($stats['anggota'], 0, ',', '.') ?></div>
@@ -133,6 +139,7 @@ $trenBulan = $db->query("
<span style="color:#22c55e">● Sudah: <?= $stats['sudah'] ?></span> <span style="color:#22c55e">● Sudah: <?= $stats['sudah'] ?></span>
<span style="color:#ef4444">● Belum: <?= $stats['belum'] ?></span> <span style="color:#ef4444">● Belum: <?= $stats['belum'] ?></span>
<span style="color:#f59e0b">● Menunggu: <?= $stats['menunggu'] ?></span> <span style="color:#f59e0b">● Menunggu: <?= $stats['menunggu'] ?></span>
<span style="color:#a855f7">● Darurat: <?= $stats['darurat'] ?></span>
</div> </div>
</div> </div>
</div> </div>
@@ -223,9 +230,9 @@ const cOpts = { responsive: true, maintainAspectRatio: false,
new Chart(document.getElementById('chart-status').getContext('2d'), { new Chart(document.getElementById('chart-status').getContext('2d'), {
type: 'doughnut', type: 'doughnut',
data: { data: {
labels: ['Sudah Dibantu','Belum Dibantu','Menunggu'], labels: ['Sudah Dibantu','Belum Dibantu','Menunggu','Bantuan Darurat'],
datasets: [{ data: [<?= $stats['sudah'] ?>,<?= $stats['belum'] ?>,<?= $stats['menunggu'] ?>], datasets: [{ data: [<?= $stats['sudah'] ?>,<?= $stats['belum'] ?>,<?= $stats['menunggu'] ?>,<?= $stats['darurat'] ?>],
backgroundColor: ['rgba(34,197,94,0.8)','rgba(239,68,68,0.8)','rgba(245,158,11,0.8)'], backgroundColor: ['rgba(34,197,94,0.8)','rgba(239,68,68,0.8)','rgba(245,158,11,0.8)','rgba(168,85,247,0.8)'],
borderColor: ['#161b27'], borderWidth: 2 }] borderColor: ['#161b27'], borderWidth: 2 }]
}, },
options: { ...cOpts, cutout:'65%' } options: { ...cOpts, cutout:'65%' }
+4 -2
View File
@@ -79,6 +79,7 @@ $ibadahList = $db->query("SELECT id, nama, jenis FROM rumah_ibadah ORDER BY nama
<option value="belum" <?= $filterSt==='belum'?'selected':'' ?>>❌ Belum Dibantu</option> <option value="belum" <?= $filterSt==='belum'?'selected':'' ?>>❌ Belum Dibantu</option>
<option value="menunggu" <?= $filterSt==='menunggu'?'selected':'' ?>>⏳ Menunggu</option> <option value="menunggu" <?= $filterSt==='menunggu'?'selected':'' ?>>⏳ Menunggu</option>
<option value="sudah" <?= $filterSt==='sudah'?'selected':'' ?>>✅ Sudah Dibantu</option> <option value="sudah" <?= $filterSt==='sudah'?'selected':'' ?>>✅ Sudah Dibantu</option>
<option value="darurat" <?= $filterSt==='darurat'?'selected':'' ?>>🚨 Bantuan Darurat</option>
</select> </select>
</div> </div>
<div> <div>
@@ -223,6 +224,7 @@ $ibadahList = $db->query("SELECT id, nama, jenis FROM rumah_ibadah ORDER BY nama
<option value="belum">❌ Belum Dibantu</option> <option value="belum">❌ Belum Dibantu</option>
<option value="menunggu">⏳ Menunggu Verifikasi</option> <option value="menunggu">⏳ Menunggu Verifikasi</option>
<option value="sudah">✅ Sudah Dibantu</option> <option value="sudah">✅ Sudah Dibantu</option>
<option value="darurat">🚨 Bantuan Darurat (Musibah)</option>
</select> </select>
</div> </div>
<div id="m-bantuan-fields" style="display:none;"> <div id="m-bantuan-fields" style="display:none;">
@@ -321,7 +323,7 @@ function fillMModal(data) {
function toggleMBantuan() { function toggleMBantuan() {
const statusVal = document.getElementById('m-status').value; const statusVal = document.getElementById('m-status').value;
document.getElementById('m-bantuan-fields').style.display = document.getElementById('m-bantuan-fields').style.display =
(statusVal === 'sudah' || statusVal === 'menunggu') ? 'block' : 'none'; (statusVal === 'sudah' || statusVal === 'menunggu' || statusVal === 'darurat') ? 'block' : 'none';
} }
async function loadMAnggota(pid) { async function loadMAnggota(pid) {
@@ -400,7 +402,7 @@ document.getElementById('btn-save-m').addEventListener('click', async function()
this.disabled = true; this.textContent = '⏳ Menyimpan...'; this.disabled = true; this.textContent = '⏳ Menyimpan...';
try { try {
const url = editId ? `${BASE}/api/penduduk_miskin.php?id=${editId}` : `${BASE}/api/penduduk_miskin.php`; const url = editId ? `${BASE}/api/penduduk_miskin.php?id=${editId}` : `${BASE}/api/penduduk_miskin.php`;
const resp = await fetch(url, { method: editId?'PUT':'POST', body: fd }); const resp = await fetch(url, { method: 'POST', body: fd });
const json = await resp.json(); const json = await resp.json();
if (json.success) { location.reload(); } else { Swal.fire('Error', json.message, 'error'); } if (json.success) { location.reload(); } else { Swal.fire('Error', json.message, 'error'); }
} catch { Swal.fire('Error','Gagal menyimpan','error'); } } catch { Swal.fire('Error','Gagal menyimpan','error'); }
+1 -1
View File
@@ -82,7 +82,7 @@ if ($type === 'penduduk') {
$subtitle = 'WebGIS Sebaran Penduduk Miskin — ' . APP_NAME; $subtitle = 'WebGIS Sebaran Penduduk Miskin — ' . APP_NAME;
$cols = ['No', 'Nama KK', 'NIK', 'Anggota', 'Kecamatan', 'Status', 'Nominal Bantuan', 'Rumah Ibadah', 'Jarak']; $cols = ['No', 'Nama KK', 'NIK', 'Anggota', 'Kecamatan', 'Status', 'Nominal Bantuan', 'Rumah Ibadah', 'Jarak'];
$tableRows = array_map(function($r, $i) { $tableRows = array_map(function($r, $i) {
$sc = ['sudah' => '#22c55e', 'menunggu' => '#f59e0b', 'belum' => '#ef4444'][$r['status_bantuan']] ?? '#ef4444'; $sc = ['sudah' => '#22c55e', 'menunggu' => '#f59e0b', 'belum' => '#ef4444', 'darurat' => '#a855f7'][$r['status_bantuan']] ?? '#ef4444';
return [$i + 1, $r['kk_nama'], $r['nik'] ?: '—', $r['jumlah_anggota'], return [$i + 1, $r['kk_nama'], $r['nik'] ?: '—', $r['jumlah_anggota'],
$r['kecamatan'] ?: '—', $r['kecamatan'] ?: '—',
"<span style='color:{$sc};font-weight:700'>".ucfirst($r['status_bantuan']).'</span>', "<span style='color:{$sc};font-weight:700'>".ucfirst($r['status_bantuan']).'</span>',
+1 -1
View File
@@ -95,7 +95,7 @@ if ($type === 'penduduk') {
$lng = (float)$row[7]; $lng = (float)$row[7];
if ($lat === 0.0 && $lng === 0.0) { $skipped++; continue; } if ($lat === 0.0 && $lng === 0.0) { $skipped++; continue; }
$status = in_array($row[8] ?? '', ['sudah','belum','menunggu']) ? $row[8] : 'belum'; $status = in_array($row[8] ?? '', ['sudah','belum','menunggu','darurat']) ? $row[8] : 'belum';
$tanggal_bantuan = !empty($row[10]) ? sanitize($row[10]) : null; $tanggal_bantuan = !empty($row[10]) ? sanitize($row[10]) : null;
$nominal_bantuan = isset($row[11]) && $row[11] !== '' ? (float)str_replace(['.', ','], ['', '.'], $row[11]) : null; $nominal_bantuan = isset($row[11]) && $row[11] !== '' ? (float)str_replace(['.', ','], ['', '.'], $row[11]) : null;
+9 -3
View File
@@ -20,6 +20,11 @@ $db = getDB();
$method = $_SERVER['REQUEST_METHOD']; $method = $_SERVER['REQUEST_METHOD'];
$id = isset($_GET['id']) ? (int)$_GET['id'] : null; $id = isset($_GET['id']) ? (int)$_GET['id'] : null;
// Override method if it's a POST request with an ID, to support multipart/form-data in updates (PUT)
if ($method === 'POST' && $id !== null) {
$method = 'PUT';
}
// ── GET ──────────────────────────────────────────────────────── // ── GET ────────────────────────────────────────────────────────
if ($method === 'GET') { if ($method === 'GET') {
if ($id) { if ($id) {
@@ -155,9 +160,10 @@ if ($method === 'POST') {
if ($method === 'PUT') { if ($method === 'PUT') {
if (!$id) jsonResponse(['success' => false, 'message' => 'ID wajib disertakan'], 400); if (!$id) jsonResponse(['success' => false, 'message' => 'ID wajib disertakan'], 400);
// Cek apakah multipart (ada file) atau JSON // Cek apakah form-data (ada file / urlencoded) atau JSON
$isMultipart = str_contains($_SERVER['CONTENT_TYPE'] ?? '', 'multipart/form-data'); $contentType = $_SERVER['CONTENT_TYPE'] ?? '';
$body = $isMultipart ? $_POST : (json_decode(file_get_contents('php://input'), true) ?? []); $isForm = str_contains($contentType, 'multipart/form-data') || str_contains($contentType, 'application/x-www-form-urlencoded');
$body = $isForm ? $_POST : (json_decode(file_get_contents('php://input'), true) ?? []);
$current = $db->prepare("SELECT * FROM penduduk_miskin WHERE id = ?"); $current = $db->prepare("SELECT * FROM penduduk_miskin WHERE id = ?");
$current->execute([$id]); $current->execute([$id]);
+3 -1
View File
@@ -16,7 +16,8 @@ $totalMiskin = $db->query("SELECT COUNT(*) FROM penduduk_miskin")->fetchColumn()
$sudahDibantu = $db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='sudah'")->fetchColumn(); $sudahDibantu = $db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='sudah'")->fetchColumn();
$belumDibantu = $db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='belum'")->fetchColumn(); $belumDibantu = $db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='belum'")->fetchColumn();
$menunggu = $db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='menunggu'")->fetchColumn(); $menunggu = $db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='menunggu'")->fetchColumn();
$totalNominal = $db->query("SELECT COALESCE(SUM(nominal_bantuan),0) FROM penduduk_miskin WHERE status_bantuan='sudah' AND nominal_bantuan IS NOT NULL")->fetchColumn(); $darurat = $db->query("SELECT COUNT(*) FROM penduduk_miskin WHERE status_bantuan='darurat'")->fetchColumn();
$totalNominal = $db->query("SELECT COALESCE(SUM(nominal_bantuan),0) FROM penduduk_miskin WHERE status_bantuan IN ('sudah','darurat') AND nominal_bantuan IS NOT NULL")->fetchColumn();
$totalNominalAll = $db->query("SELECT COALESCE(SUM(nominal_bantuan),0) FROM penduduk_miskin WHERE nominal_bantuan IS NOT NULL")->fetchColumn(); $totalNominalAll = $db->query("SELECT COALESCE(SUM(nominal_bantuan),0) FROM penduduk_miskin WHERE nominal_bantuan IS NOT NULL")->fetchColumn();
// Per jenis ibadah // Per jenis ibadah
@@ -54,6 +55,7 @@ jsonResponse([
'sudah_dibantu' => (int)$sudahDibantu, 'sudah_dibantu' => (int)$sudahDibantu,
'belum_dibantu' => (int)$belumDibantu, 'belum_dibantu' => (int)$belumDibantu,
'menunggu' => (int)$menunggu, 'menunggu' => (int)$menunggu,
'darurat' => (int)$darurat,
'total_nominal' => (float)$totalNominal, 'total_nominal' => (float)$totalNominal,
'total_nominal_all' => (float)$totalNominalAll, 'total_nominal_all' => (float)$totalNominalAll,
'jenis_stats' => $jenisStats, 'jenis_stats' => $jenisStats,
+4
View File
@@ -19,6 +19,7 @@
--green: #22c55e; --green: #22c55e;
--red: #ef4444; --red: #ef4444;
--yellow: #f59e0b; --yellow: #f59e0b;
--purple: #a855f7;
--glass: rgba(255,255,255,0.04); --glass: rgba(255,255,255,0.04);
--glass-hover: rgba(255,255,255,0.07); --glass-hover: rgba(255,255,255,0.07);
--radius: 12px; --radius: 12px;
@@ -167,6 +168,7 @@ html, body {
.stat-card.green::before { background: linear-gradient(90deg, var(--green), #16a34a); } .stat-card.green::before { background: linear-gradient(90deg, var(--green), #16a34a); }
.stat-card.red::before { background: linear-gradient(90deg, var(--red), #b91c1c); } .stat-card.red::before { background: linear-gradient(90deg, var(--red), #b91c1c); }
.stat-card.yellow::before { background: linear-gradient(90deg, var(--yellow), #d97706); } .stat-card.yellow::before { background: linear-gradient(90deg, var(--yellow), #d97706); }
.stat-card.purple::before { background: linear-gradient(90deg, var(--purple), #7e22ce); }
.stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow); } .stat-card:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.stat-icon { font-size: 26px; margin-bottom: 8px; } .stat-icon { font-size: 26px; margin-bottom: 8px; }
@@ -176,6 +178,7 @@ html, body {
.stat-card.green .stat-value { color: var(--green); } .stat-card.green .stat-value { color: var(--green); }
.stat-card.red .stat-value { color: var(--red); } .stat-card.red .stat-value { color: var(--red); }
.stat-card.yellow .stat-value { color: var(--yellow); } .stat-card.yellow .stat-value { color: var(--yellow); }
.stat-card.purple .stat-value { color: var(--purple); }
/* ── CARDS ──────────────────────────────────────────────────────── */ /* ── CARDS ──────────────────────────────────────────────────────── */
.card { .card {
@@ -227,6 +230,7 @@ html, body {
.badge-sudah { background: rgba(34,197,94,0.15); color: var(--green); } .badge-sudah { background: rgba(34,197,94,0.15); color: var(--green); }
.badge-belum { background: rgba(239,68,68,0.14); color: var(--red); } .badge-belum { background: rgba(239,68,68,0.14); color: var(--red); }
.badge-menunggu { background: rgba(245,158,11,0.15); color: var(--yellow); } .badge-menunggu { background: rgba(245,158,11,0.15); color: var(--yellow); }
.badge-darurat { background: rgba(168,85,247,0.15); color: var(--purple); }
.badge-admin { background: rgba(91,127,255,0.15); color: var(--accent); } .badge-admin { background: rgba(91,127,255,0.15); color: var(--accent); }
.badge-operator { background: rgba(34,197,94,0.12); color: var(--green); } .badge-operator { background: rgba(34,197,94,0.12); color: var(--green); }
+3
View File
@@ -21,6 +21,7 @@
--green: #22c55e; --green: #22c55e;
--red: #ef4444; --red: #ef4444;
--yellow: #f59e0b; --yellow: #f59e0b;
--purple: #a855f7;
--glass: rgba(255,255,255,0.04); --glass: rgba(255,255,255,0.04);
--glass-hover: rgba(255,255,255,0.07); --glass-hover: rgba(255,255,255,0.07);
--radius: 12px; --radius: 12px;
@@ -118,6 +119,7 @@ html, body { height: 100%; overflow: hidden; font-family: 'Plus Jakarta Sans', s
.stat-card.green .stat-num { color: var(--green); } .stat-card.green .stat-num { color: var(--green); }
.stat-card.red .stat-num { color: var(--red); } .stat-card.red .stat-num { color: var(--red); }
.stat-card.yellow .stat-num { color: var(--yellow); } .stat-card.yellow .stat-num { color: var(--yellow); }
.stat-card.purple .stat-num { color: var(--purple); }
/* Tabs */ /* Tabs */
.sidebar-tabs { .sidebar-tabs {
@@ -183,6 +185,7 @@ html, body { height: 100%; overflow: hidden; font-family: 'Plus Jakarta Sans', s
.badge-belum { background: rgba(239,68,68,0.15); color: var(--red); } .badge-belum { background: rgba(239,68,68,0.15); color: var(--red); }
.badge-sudah { background: rgba(34,197,94,0.15); color: var(--green); } .badge-sudah { background: rgba(34,197,94,0.15); color: var(--green); }
.badge-menunggu { background: rgba(245,158,11,0.15); color: var(--yellow); } .badge-menunggu { background: rgba(245,158,11,0.15); color: var(--yellow); }
.badge-darurat { background: rgba(168,85,247,0.15); color: var(--purple); }
/* Nearest tag */ /* Nearest tag */
.nearest-tag { font-size: 9px; color: var(--accent); background: rgba(91,127,255,0.12); padding: 2px 6px; border-radius: 4px; } .nearest-tag { font-size: 9px; color: var(--accent); background: rgba(91,127,255,0.12); padding: 2px 6px; border-radius: 4px; }
+9 -6
View File
@@ -55,8 +55,8 @@ const JENIS_EMOJI = {
Pura: '🛕', Vihara: '🛕', Pura: '🛕', Vihara: '🛕',
Klenteng: '⛩️', Lainnya: '🙏' Klenteng: '⛩️', Lainnya: '🙏'
}; };
const STATUS_COLOR = { sudah: '#22c55e', menunggu: '#f59e0b', belum: '#ef4444' }; const STATUS_COLOR = { sudah: '#22c55e', menunggu: '#f59e0b', belum: '#ef4444', darurat: '#a855f7' };
const STATUS_LABEL = { sudah: 'Sudah Dibantu', menunggu: 'Menunggu Verif.', belum: 'Belum Dibantu' }; const STATUS_LABEL = { sudah: 'Sudah Dibantu', menunggu: 'Menunggu Verif.', belum: 'Belum Dibantu', darurat: 'Bantuan Darurat (Musibah)' };
// ── HELPERS ────────────────────────────────────────────────────── // ── HELPERS ──────────────────────────────────────────────────────
function fmtRadius(v) { v = parseInt(v); return v >= 1000 ? (v/1000).toFixed(1)+' km' : v+' m'; } function fmtRadius(v) { v = parseInt(v); return v >= 1000 ? (v/1000).toFixed(1)+' km' : v+' m'; }
@@ -97,7 +97,8 @@ function createMiskinIcon(status) {
const c = STATUS_COLOR[status] || '#ef4444'; const c = STATUS_COLOR[status] || '#ef4444';
const glow = c.replace('#','') === '22c55e' const glow = c.replace('#','') === '22c55e'
? 'rgba(34,197,94,0.55)' : c === '#f59e0b' ? 'rgba(34,197,94,0.55)' : c === '#f59e0b'
? 'rgba(245,158,11,0.55)' : 'rgba(239,68,68,0.55)'; ? 'rgba(245,158,11,0.55)' : status === 'darurat'
? 'rgba(168,85,247,0.55)' : 'rgba(239,68,68,0.55)';
return L.divIcon({ return L.divIcon({
html: `<div style="background:${c};width:20px;height:20px;border-radius:50%; html: `<div style="background:${c};width:20px;height:20px;border-radius:50%;
border:3px solid #fff;box-shadow:0 2px 8px ${glow};"></div>`, border:3px solid #fff;box-shadow:0 2px 8px ${glow};"></div>`,
@@ -316,11 +317,13 @@ function updateStats() {
document.getElementById('stat-miskin').textContent = allMiskin.length; document.getElementById('stat-miskin').textContent = allMiskin.length;
document.getElementById('stat-sudah').textContent = allMiskin.filter(m => m.status_bantuan === 'sudah').length; document.getElementById('stat-sudah').textContent = allMiskin.filter(m => m.status_bantuan === 'sudah').length;
document.getElementById('stat-belum').textContent = allMiskin.filter(m => m.status_bantuan === 'belum').length; document.getElementById('stat-belum').textContent = allMiskin.filter(m => m.status_bantuan === 'belum').length;
const elDarurat = document.getElementById('stat-darurat');
if (elDarurat) elDarurat.textContent = allMiskin.filter(m => m.status_bantuan === 'darurat').length;
document.getElementById('count-ibadah').textContent = allIbadah.length; document.getElementById('count-ibadah').textContent = allIbadah.length;
document.getElementById('count-miskin').textContent = allMiskin.length; document.getElementById('count-miskin').textContent = allMiskin.length;
const totalNominal = allMiskin.reduce((acc, m) => { const totalNominal = allMiskin.reduce((acc, m) => {
return acc + (m.status_bantuan === 'sudah' && m.nominal_bantuan ? parseFloat(m.nominal_bantuan) : 0); return acc + ((m.status_bantuan === 'sudah' || m.status_bantuan === 'darurat') && m.nominal_bantuan ? parseFloat(m.nominal_bantuan) : 0);
}, 0); }, 0);
const elNominal = document.getElementById('stat-nominal'); const elNominal = document.getElementById('stat-nominal');
if (elNominal) elNominal.textContent = fmtRupiah(totalNominal); if (elNominal) elNominal.textContent = fmtRupiah(totalNominal);
@@ -674,7 +677,7 @@ window.openEditMiskin = function (id) {
function _toggleBantuanFields() { function _toggleBantuanFields() {
const st = document.getElementById('miskin-status').value; const st = document.getElementById('miskin-status').value;
const showBantuan = (st === 'sudah' || st === 'menunggu'); const showBantuan = (st === 'sudah' || st === 'menunggu' || st === 'darurat');
document.getElementById('bantuan-fields').style.display = showBantuan ? 'block' : 'none'; document.getElementById('bantuan-fields').style.display = showBantuan ? 'block' : 'none';
const ketWrap = document.getElementById('keterangan-menunggu-wrap'); const ketWrap = document.getElementById('keterangan-menunggu-wrap');
if (ketWrap) ketWrap.style.display = (st === 'menunggu') ? 'block' : 'none'; if (ketWrap) ketWrap.style.display = (st === 'menunggu') ? 'block' : 'none';
@@ -775,7 +778,7 @@ async function _saveMiskin() {
try { try {
const url = editId ? `${BASE_URL}/api/penduduk_miskin.php?id=${editId}` : `${BASE_URL}/api/penduduk_miskin.php`; const url = editId ? `${BASE_URL}/api/penduduk_miskin.php?id=${editId}` : `${BASE_URL}/api/penduduk_miskin.php`;
const resp = await fetch(url, { method: editId?'PUT':'POST', body: fd }); const resp = await fetch(url, { method: 'POST', body: fd });
const json = await resp.json(); const json = await resp.json();
if (json.success) { if (json.success) {
window.closeModalMiskin(); window.closeModalMiskin();
+1
View File
@@ -102,4 +102,5 @@ define('STATUS_BANTUAN', [
'belum' => ['label' => 'Belum Dibantu', 'color' => '#ef4444', 'badge' => 'danger'], 'belum' => ['label' => 'Belum Dibantu', 'color' => '#ef4444', 'badge' => 'danger'],
'sudah' => ['label' => 'Sudah Dibantu', 'color' => '#22c55e', 'badge' => 'success'], 'sudah' => ['label' => 'Sudah Dibantu', 'color' => '#22c55e', 'badge' => 'success'],
'menunggu' => ['label' => 'Menunggu Verif', 'color' => '#f59e0b', 'badge' => 'warning'], 'menunggu' => ['label' => 'Menunggu Verif', 'color' => '#f59e0b', 'badge' => 'warning'],
'darurat' => ['label' => 'Bantuan Darurat (Musibah)', 'color' => '#a855f7', 'badge' => 'secondary'],
]); ]);
+1 -1
View File
@@ -53,7 +53,7 @@ CREATE TABLE IF NOT EXISTS penduduk_miskin (
lng DECIMAL(10,7) NOT NULL, lng DECIMAL(10,7) NOT NULL,
rumah_ibadah_id INT DEFAULT NULL, rumah_ibadah_id INT DEFAULT NULL,
jarak_ke_ibadah DECIMAL(10,2) DEFAULT NULL, jarak_ke_ibadah DECIMAL(10,2) DEFAULT NULL,
status_bantuan ENUM('belum','sudah','menunggu') NOT NULL DEFAULT 'belum', status_bantuan ENUM('belum','sudah','menunggu','darurat') NOT NULL DEFAULT 'belum',
jenis_bantuan VARCHAR(200) DEFAULT NULL, jenis_bantuan VARCHAR(200) DEFAULT NULL,
tanggal_bantuan DATE DEFAULT NULL, tanggal_bantuan DATE DEFAULT NULL,
nominal_bantuan DECIMAL(15,2) DEFAULT NULL COMMENT 'Nominal bantuan dalam Rupiah', nominal_bantuan DECIMAL(15,2) DEFAULT NULL COMMENT 'Nominal bantuan dalam Rupiah',
+1
View File
@@ -65,6 +65,7 @@
<option value="belum"> Belum Dibantu</option> <option value="belum"> Belum Dibantu</option>
<option value="menunggu"> Menunggu Verifikasi</option> <option value="menunggu"> Menunggu Verifikasi</option>
<option value="sudah"> Sudah Dibantu</option> <option value="sudah"> Sudah Dibantu</option>
<option value="darurat">🚨 Bantuan Darurat (Musibah)</option>
</select> </select>
</div> </div>
+6
View File
@@ -60,6 +60,7 @@ require_once __DIR__ . '/config/config.php';
<option value="belum">Belum Dibantu</option> <option value="belum">Belum Dibantu</option>
<option value="sudah">Sudah Dibantu</option> <option value="sudah">Sudah Dibantu</option>
<option value="menunggu">Menunggu</option> <option value="menunggu">Menunggu</option>
<option value="darurat">Bantuan Darurat</option>
</select> </select>
<select class="filter-select" id="filter-jenis"> <select class="filter-select" id="filter-jenis">
<option value="">Semua Ibadah</option> <option value="">Semua Ibadah</option>
@@ -105,6 +106,10 @@ require_once __DIR__ . '/config/config.php';
<div class="stat-num" id="stat-belum">0</div> <div class="stat-num" id="stat-belum">0</div>
<div class="stat-label">Belum Dibantu</div> <div class="stat-label">Belum Dibantu</div>
</div> </div>
<div class="stat-card purple full">
<div class="stat-num" id="stat-darurat">0</div>
<div class="stat-label">Bantuan Darurat (Musibah)</div>
</div>
</div> </div>
<div style="background:rgba(34,197,94,0.1); border:1px solid rgba(34,197,94,0.2); border-radius:12px; padding:12px; margin-bottom:16px; display:flex; align-items:center; gap:12px;"> <div style="background:rgba(34,197,94,0.1); border:1px solid rgba(34,197,94,0.2); border-radius:12px; padding:12px; margin-bottom:16px; display:flex; align-items:center; gap:12px;">
@@ -199,6 +204,7 @@ require_once __DIR__ . '/config/config.php';
<div class="legend-item"><div class="legend-dot" style="background:#22c55e"></div> Sudah Dibantu</div> <div class="legend-item"><div class="legend-dot" style="background:#22c55e"></div> Sudah Dibantu</div>
<div class="legend-item"><div class="legend-dot" style="background:#ef4444"></div> Belum Dibantu</div> <div class="legend-item"><div class="legend-dot" style="background:#ef4444"></div> Belum Dibantu</div>
<div class="legend-item"><div class="legend-dot" style="background:#f59e0b"></div> Menunggu Verif.</div> <div class="legend-item"><div class="legend-dot" style="background:#f59e0b"></div> Menunggu Verif.</div>
<div class="legend-item"><div class="legend-dot" style="background:#a855f7"></div> Bantuan Darurat (Musibah)</div>
<div class="legend-item" style="margin-top:6px;"> <div class="legend-item" style="margin-top:6px;">
<div class="legend-rect" style="background:rgba(91,127,255,0.15);border:1px dashed #5b7fff"></div> Radius Layanan <div class="legend-rect" style="background:rgba(91,127,255,0.15);border:1px dashed #5b7fff"></div> Radius Layanan
</div> </div>