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

437 lines
35 KiB
PHP

<?php
require_once __DIR__ . '/auth.php';
require_login(false);
$user = current_user();
$role = $user['role'];
$bulanIni = (int) date('n');
$tahunIni = (int) date('Y');
function scalar_count($sql, $types = '', $params = []) {
global $koneksi;
$stmt = $koneksi->prepare($sql);
if ($types) stmt_bind($stmt, $types, $params);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
return (int) array_values($row)[0];
}
$riAdminList = ($role === 'admin_rumah_ibadah') ? get_admin_rumah_ibadah_list((int)$user['id'], true) : [];
$riAdminIds = array_map('intval', array_column($riAdminList, 'id'));
$stats = [];
if ($role === 'super_admin') {
$stats['Total Rumah Ibadah'] = scalar_count("SELECT COUNT(*) FROM rumah_ibadah WHERE COALESCE(status_hapus,'normal')<>'disetujui'");
$stats['Rumah Ibadah Menunggu'] = scalar_count("SELECT COUNT(*) FROM rumah_ibadah WHERE status_pengajuan='menunggu' AND COALESCE(status_hapus,'normal')<>'disetujui'");
$stats['Total Penerima'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE COALESCE(status_hapus,'normal')<>'disetujui'");
$stats['Penerima Menunggu'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE status_pengajuan='menunggu' AND COALESCE(status_hapus,'normal')<>'disetujui'");
$stats['Penerima Diterima'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE status_pengajuan='diterima' AND COALESCE(status_hapus,'normal')<>'disetujui'");
$stats['Penerima Ditolak'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE status_pengajuan='ditolak' AND COALESCE(status_hapus,'normal')<>'disetujui'");
$stats['Penerima Dibatalkan'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE status_pengajuan='dibatalkan' AND COALESCE(status_hapus,'normal')<>'disetujui'");
$stats['Program Aktif'] = scalar_count("SELECT COUNT(*) FROM program_bantuan WHERE status_program='aktif'");
$stats['Bantuan Tersalurkan'] = scalar_count("SELECT COUNT(*) FROM penyaluran_bantuan");
} elseif ($role === 'admin_rumah_ibadah') {
if (!empty($riAdminIds)) {
$stats['Jumlah Rumah Ibadah'] = count($riAdminIds);
$stats['Rumah Ibadah'] = implode(', ', array_column($riAdminList, 'nama_rumah_ibadah'));
$types = ''; $params = []; $in = build_in_condition('rumah_ibadah_id', $riAdminIds, $types, $params);
$stats['Pengajuan Dalam Radius'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE $in AND status_pengajuan='menunggu' AND COALESCE(status_hapus,'normal')<>'disetujui'", $types, $params);
$types = ''; $params = []; $in = build_in_condition('rumah_ibadah_id', $riAdminIds, $types, $params);
$stats['Penerima Diterima'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE $in AND status_pengajuan='diterima' AND COALESCE(status_hapus,'normal')<>'disetujui'", $types, $params);
$types = ''; $params = []; $in = build_in_condition('rumah_ibadah_id', $riAdminIds, $types, $params);
$stats['Penerima Ditolak'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE $in AND status_pengajuan='ditolak' AND COALESCE(status_hapus,'normal')<>'disetujui'", $types, $params);
$types = ''; $params = []; $in = build_in_condition('rumah_ibadah_id', $riAdminIds, $types, $params);
$stats['Program Aktif'] = scalar_count("SELECT COUNT(*) FROM program_bantuan WHERE $in AND status_program='aktif'", $types, $params);
$types = ''; $params = []; $in = build_in_condition('rumah_ibadah_id', $riAdminIds, $types, $params);
$stats['Bantuan Tersalurkan'] = scalar_count("SELECT COUNT(*) FROM penyaluran_bantuan WHERE $in", $types, $params);
} else {
$stats['Rumah Ibadah'] = 'Belum ada rumah ibadah diterima';
}
} elseif ($role === 'penerima') {
$uid = (int)$user['id'];
$stats['Pengajuan Saya'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE user_id=? AND COALESCE(status_hapus,'normal')<>'disetujui'", 'i', [$uid]);
$stats['Status Diterima'] = scalar_count("SELECT COUNT(*) FROM penerima_bantuan WHERE user_id=? AND status_pengajuan='diterima' AND COALESCE(status_hapus,'normal')<>'disetujui'", 'i', [$uid]);
$stats['Bantuan Bulan Ini'] = scalar_count("SELECT COUNT(*) FROM penyaluran_bantuan pn JOIN penerima_bantuan pb ON pb.id=pn.penerima_id WHERE pb.user_id=? AND MONTH(pn.tanggal_penyaluran)=? AND YEAR(pn.tanggal_penyaluran)=?", 'iii', [$uid, $bulanIni, $tahunIni]);
}
$hapusRumahRows = [];
$hapusPenerimaRows = [];
if ($role === 'super_admin') {
$stmt = $koneksi->prepare("SELECT ri.*, u.nama AS nama_admin, u.username AS username_admin FROM rumah_ibadah ri LEFT JOIN users u ON u.id=ri.user_id WHERE ri.status_hapus='menunggu' ORDER BY ri.updated_at DESC");
$hapusRumahRows = fetch_all_stmt($stmt);
$stmt = $koneksi->prepare("SELECT pb.*, u.username AS username_penerima, ri.nama_rumah_ibadah FROM penerima_bantuan pb LEFT JOIN users u ON u.id=pb.user_id LEFT JOIN rumah_ibadah ri ON ri.id=pb.rumah_ibadah_id WHERE pb.status_hapus='menunggu' ORDER BY pb.updated_at DESC");
$hapusPenerimaRows = fetch_all_stmt($stmt);
}
?>
<!DOCTYPE html><html lang="id"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Dashboard WebGIS Poverty Mapping</title>
<style>
*{box-sizing:border-box}body{margin:0;font-family:Arial,sans-serif;background:#f8fafc;color:#0f172a}.top{background:#0f766e;color:#fff;padding:18px 24px;display:flex;justify-content:space-between;gap:12px;align-items:center}.top h1{font-size:22px;margin:0}.top a{color:#fff;text-decoration:none;background:rgba(255,255,255,.16);padding:8px 12px;border-radius:8px}.wrap{padding:22px;max-width:1280px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px}.card,.section{background:#fff;border:1px solid #e2e8f0;border-radius:14px;box-shadow:0 8px 24px rgba(15,23,42,.06)}.card{padding:16px}.card .k{color:#64748b;font-size:12px}.card .v{font-size:22px;font-weight:800;margin-top:7px}.section{padding:18px;margin-top:18px}.section h2{font-size:18px;margin:0 0 14px}.filters,.row2{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px}.fg label{display:block;font-size:12px;font-weight:700;color:#475569;margin-bottom:5px}.fg input,.fg select,.fg textarea{width:100%;border:1px solid #cbd5e1;border-radius:9px;padding:9px}.fg textarea{min-height:70px}.btn{border:0;border-radius:9px;padding:9px 12px;font-weight:700;cursor:pointer}.btn[disabled]{cursor:not-allowed;opacity:.55}.btn.primary{background:#0f766e;color:#fff}.btn.gray{background:#e2e8f0;color:#334155}.btn.small{padding:7px 9px;font-size:12px}table{width:100%;border-collapse:collapse;font-size:13px}th,td{padding:10px;border-bottom:1px solid #e2e8f0;text-align:left;vertical-align:top}th{background:#f1f5f9;color:#334155}.muted{color:#64748b;font-size:12px}.badge{display:inline-block;border-radius:999px;padding:4px 8px;font-size:11px;font-weight:700;background:#e2e8f0}.belum_diberi{background:#fee2e2;color:#991b1b}.sudah_diberi,.sesuai_target{background:#dcfce7;color:#166534}.belum_memenuhi_target{background:#fef3c7;color:#92400e}.melebihi_target{background:#e0e7ff;color:#3730a3}.readonly{background:#f8fafc}.notice{background:#ecfeff;border:1px solid #a5f3fc;color:#155e75;padding:10px;border-radius:10px;margin-bottom:12px}.toastbox{position:fixed;right:18px;top:18px;z-index:9999;display:grid;gap:10px}.toast{background:#0f172a;color:#fff;padding:12px 14px;border-radius:10px;box-shadow:0 12px 30px rgba(15,23,42,.25);max-width:360px;font-size:13px}.toast.err{background:#991b1b}.toast.ok{background:#166534}
</style></head><body>
<div class="top"><div><h1>Dashboard WebGIS Poverty Mapping</h1><div class="muted" style="color:#d1fae5">Role: <?= htmlspecialchars($role) ?> | <?= htmlspecialchars($user['nama']) ?></div></div><div><a href="index.php">Buka Peta</a> <a href="logout.php">Logout</a></div></div>
<div id="toastBox" class="toastbox"></div>
<div class="wrap">
<div class="grid"><?php foreach($stats as $k=>$v): ?><div class="card"><div class="k"><?= htmlspecialchars($k) ?></div><div class="v"><?= htmlspecialchars((string)$v) ?></div></div><?php endforeach; ?></div>
<?php if($role === 'super_admin'): ?>
<div class="section">
<h2>Persetujuan Hapus Marker/Pin</h2>
<p class="muted">Admin rumah ibadah dan penerima hanya mengajukan hapus. Marker benar-benar hilang dari peta setelah disetujui super admin.</p>
<h3 style="font-size:15px;margin:12px 0 8px">Pengajuan Hapus Rumah Ibadah</h3>
<div style="overflow:auto"><table><thead><tr><th>Rumah Ibadah</th><th>Admin</th><th>Alasan</th><th>Aksi</th></tr></thead><tbody>
<?php if(empty($hapusRumahRows)): ?><tr><td colspan="4">Tidak ada pengajuan hapus rumah ibadah.</td></tr><?php endif; ?>
<?php foreach($hapusRumahRows as $r): ?><tr>
<td><b><?= htmlspecialchars($r['nama_rumah_ibadah']) ?></b><br><span class="muted"><?= htmlspecialchars($r['agama']) ?> | <?= htmlspecialchars($r['alamat']) ?></span></td>
<td><?= htmlspecialchars($r['nama_admin'] ?? '-') ?><br><span class="muted"><?= htmlspecialchars($r['username_admin'] ?? '-') ?></span></td>
<td><?= htmlspecialchars($r['alasan_hapus'] ?? '-') ?></td>
<td><button class="btn primary small" onclick="updateStatusRumahIbadah(<?= (int)$r['id'] ?>,'hapus_disetujui')">Setujui</button> <button class="btn gray small" onclick="updateStatusRumahIbadah(<?= (int)$r['id'] ?>,'hapus_ditolak')">Tolak</button></td>
</tr><?php endforeach; ?>
</tbody></table></div>
<h3 style="font-size:15px;margin:16px 0 8px">Pengajuan Hapus Penerima</h3>
<div style="overflow:auto"><table><thead><tr><th>Penerima</th><th>Rumah Ibadah</th><th>Alasan</th><th>Aksi</th></tr></thead><tbody>
<?php if(empty($hapusPenerimaRows)): ?><tr><td colspan="4">Tidak ada pengajuan hapus penerima.</td></tr><?php endif; ?>
<?php foreach($hapusPenerimaRows as $p): ?><tr>
<td><b><?= htmlspecialchars($p['nama_penerima']) ?></b><br><span class="muted">User: <?= htmlspecialchars($p['username_penerima'] ?? '-') ?> | <?= htmlspecialchars($p['alamat']) ?></span></td>
<td><?= htmlspecialchars($p['nama_rumah_ibadah'] ?? '-') ?></td>
<td><?= htmlspecialchars($p['alasan_hapus'] ?? '-') ?></td>
<td><button class="btn primary small" onclick="updateStatusPenerima(<?= (int)$p['id'] ?>,'hapus_disetujui')">Setujui</button> <button class="btn gray small" onclick="updateStatusPenerima(<?= (int)$p['id'] ?>,'hapus_ditolak')">Tolak</button></td>
</tr><?php endforeach; ?>
</tbody></table></div>
</div>
<?php endif; ?>
<?php if($role === 'super_admin' || $role === 'admin_rumah_ibadah'): ?>
<div class="section">
<h2>Kelola Akun Pengguna</h2>
<p class="muted">
<?php if($role === 'super_admin'): ?>
Super admin dapat mengelola akun penerima dan admin rumah ibadah. Akun super admin lain tidak ditampilkan di daftar ini.
<?php else: ?>
Admin rumah ibadah hanya dapat mengelola akun penerima. Akun admin rumah ibadah lain tidak bisa dilihat atau diubah.
<?php endif; ?>
</p>
<input type="hidden" id="u_id" value="">
<div class="filters">
<div class="fg"><label>Nama</label><input id="u_nama" placeholder="Contoh: Admin Masjid / Nama Penerima"></div>
<div class="fg"><label>Username</label><input id="u_username" placeholder="Contoh: adminmasjid / penerima01"></div>
<div class="fg"><label>Password</label><input id="u_password" type="password" placeholder="Minimal 6 karakter. Kosongkan saat edit jika tidak diganti."></div>
<div class="fg"><label>Role</label><select id="u_role">
<?php if($role === 'super_admin'): ?><option value="admin_rumah_ibadah">Admin Rumah Ibadah</option><?php endif; ?>
<option value="penerima">Penerima</option>
</select></div>
<div class="fg"><label>Status</label><select id="u_status"><option value="aktif">Aktif</option><option value="nonaktif">Nonaktif</option></select></div>
<div class="fg"><label>&nbsp;</label><button class="btn primary" id="u_submit_btn" onclick="submitUser()">Buat Akun</button></div>
<div class="fg"><label>&nbsp;</label><button class="btn gray" onclick="resetUserForm()">Reset Form</button></div>
</div>
<h3 style="font-size:15px;margin:16px 0 8px">Daftar Akun</h3>
<div class="filters">
<div class="fg"><label>Filter Role</label><select id="fu_role" onchange="loadUsers()">
<?php if($role === 'super_admin'): ?>
<option value="semua">Semua</option>
<option value="admin_rumah_ibadah">Admin Rumah Ibadah</option>
<?php endif; ?>
<option value="penerima">Penerima</option>
</select></div>
<div class="fg"><label>Filter Status</label><select id="fu_status" onchange="loadUsers()"><option value="semua">Semua</option><option value="aktif">Aktif</option><option value="nonaktif">Nonaktif</option></select></div>
<div class="fg"><label>Cari Nama/Username</label><input id="fu_keyword" placeholder="Ketik nama atau username" oninput="debouncedLoadUsers()"></div>
<div class="fg"><label>&nbsp;</label><button class="btn primary" onclick="loadUsers()">Terapkan Filter</button></div>
</div>
<div style="overflow:auto"><table><thead><tr><th>Akun</th><th>Role</th><th>Status</th><th>Relasi Data</th><th>Dibuat/Update</th><th>Aksi</th></tr></thead><tbody id="akunBody"><tr><td colspan="6">Memuat akun...</td></tr></tbody></table></div>
</div>
<?php endif; ?>
<div class="section">
<h2>Monitoring Penyaluran Per Periode</h2>
<div class="filters">
<div class="fg"><label>Bulan</label><select id="f_bulan"><?php for($i=1;$i<=12;$i++): ?><option value="<?= $i ?>" <?= $i===$bulanIni?'selected':'' ?>><?= $i ?></option><?php endfor; ?></select></div>
<div class="fg"><label>Tahun</label><input id="f_tahun" type="number" value="<?= $tahunIni ?>"></div>
<div class="fg"><label>Rumah Ibadah</label><select id="f_rumah_ibadah"><option value="">Semua</option></select></div>
<div class="fg"><label>Agama</label><select id="f_agama"><option value="">Semua</option><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>Program Bantuan</label><select id="f_program"><option value="">Semua</option></select></div>
<div class="fg"><label>Jenis Bantuan</label><select id="f_jenis"><option value="">Semua</option><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="fg"><label>Status</label><select id="f_status"><option value="semua">Semua</option><option value="belum_diberi">Belum diberi</option><option value="sudah_diberi">Sudah diberi</option><option value="belum_memenuhi_target">Belum memenuhi target</option><option value="sesuai_target">Sesuai target</option><option value="melebihi_target">Melebihi target</option></select></div>
<div class="fg"><label>&nbsp;</label><button class="btn primary" onclick="loadLaporanPenyaluran()">Terapkan Filter</button></div>
</div>
</div>
<div class="section">
<h2>Rekap Penyaluran</h2>
<div class="grid" id="rekapBox"></div>
</div>
<?php if($role === 'super_admin' || $role === 'admin_rumah_ibadah'): ?>
<div class="row2">
<div class="section">
<h2>Buat Program Bantuan</h2>
<div class="notice">Jenis bantuan, nominal, dan jumlah item yang diatur di sini akan otomatis dipakai saat penyaluran. Petugas tidak perlu mengetik ulang agar data sinkron.</div>
<?php if($role === 'super_admin' || $role === 'admin_rumah_ibadah'): ?><div class="fg"><label>Rumah Ibadah</label><select id="pr_rumah_ibadah_id"><option value="">Pilih rumah ibadah</option></select></div><?php endif; ?>
<div class="fg"><label>Nama Program</label><input id="pr_nama" placeholder="Contoh: Sembako Januari 2026"></div>
<div class="filters">
<div class="fg"><label>Jenis</label><select id="pr_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="fg"><label>Bulan</label><input type="number" id="pr_bulan" value="<?= $bulanIni ?>"></div>
<div class="fg"><label>Tahun</label><input type="number" id="pr_tahun" value="<?= $tahunIni ?>"></div>
<div class="fg"><label>Target Frekuensi</label><input type="number" id="pr_target" value="1"></div>
</div>
<div class="filters">
<div class="fg"><label>Nominal Program</label><input type="number" id="pr_nominal" placeholder="Opsional, contoh: 50000"></div>
<div class="fg"><label>Jumlah Item/Paket</label><input id="pr_jumlah_item" placeholder="Contoh: 1 paket sembako / 5 kg beras"></div>
</div>
<div class="fg"><label>Deskripsi</label><textarea id="pr_deskripsi"></textarea></div>
<button class="btn primary" onclick="submitProgramBantuan()">Simpan Program</button>
<h3 style="font-size:15px;margin:16px 0 8px">Daftar Program</h3>
<div style="overflow:auto"><table><thead><tr><th>Program</th><th>Periode</th><th>Jenis</th><th>Nominal/Item</th><th>Status</th><th>Aksi</th></tr></thead><tbody id="programBody"><tr><td colspan="6">Memuat program...</td></tr></tbody></table></div>
</div>
<div class="section">
<h2>Catat Penyaluran Bantuan</h2>
<div class="fg"><label>Program</label><select id="pn_program" onchange="syncProgramDetail()"></select></div>
<div class="fg"><label>Penerima Diterima</label><select id="pn_penerima"></select></div>
<div class="filters">
<div class="fg"><label>Jenis dari Program</label><input id="pn_jenis_view" class="readonly" readonly></div>
<div class="fg"><label>Nominal dari Program</label><input id="pn_nominal_view" class="readonly" readonly></div>
<div class="fg"><label>Jumlah Item dari Program</label><input id="pn_jumlah_item_view" class="readonly" readonly></div>
<div class="fg"><label>Tanggal</label><input type="date" id="pn_tanggal" value="<?= date('Y-m-d') ?>"></div>
</div>
<div class="fg"><label>Keterangan</label><textarea id="pn_keterangan" placeholder="Isi alasan jika bantuan melebihi target program"></textarea></div>
<button class="btn primary" onclick="submitPenyaluran()">Catat Bantuan</button>
</div>
</div>
<?php endif; ?>
<div class="section">
<h2>Data Laporan Penerima Sudah/Belum Diberi Bantuan</h2>
<div style="overflow:auto"><table><thead><tr><th>Penerima</th><th>Rumah Ibadah</th><th>Program</th><th>Target</th><th>Jumlah</th><th>Status</th><th>Terakhir</th><th>Riwayat Bulan Ini</th><th>Aksi</th></tr></thead><tbody id="laporanBody"><tr><td colspan="9">Memuat data...</td></tr></tbody></table></div>
</div>
<div class="section">
<h2>Riwayat Pengajuan dan Bantuan</h2>
<div id="riwayatBox" class="muted">Memuat riwayat...</div>
</div>
</div>
<script>
const USER_ROLE = <?= json_encode($role) ?>;
function esc(v){return String(v??'').replace(/[&<>"']/g,m=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[m]))}
function toast(msg,type='ok'){ const box=document.getElementById('toastBox'); if(!box){console.log(msg);return;} const el=document.createElement('div'); el.className='toast '+type; el.textContent=msg; box.appendChild(el); setTimeout(()=>{el.style.opacity='0';el.style.transform='translateY(-6px)';},3000); setTimeout(()=>el.remove(),3500); }
function getFilterQuery(){ const q=new URLSearchParams(); q.set('bulan',document.getElementById('f_bulan').value); q.set('tahun',document.getElementById('f_tahun').value); q.set('rumah_ibadah_id',document.getElementById('f_rumah_ibadah')?.value||''); q.set('agama',document.getElementById('f_agama')?.value||''); q.set('program_id',document.getElementById('f_program').value); q.set('jenis_bantuan',document.getElementById('f_jenis').value); q.set('status_penyaluran',document.getElementById('f_status').value); return q.toString(); }
let userSearchTimer=null;
function debouncedLoadUsers(){ clearTimeout(userSearchTimer); userSearchTimer=setTimeout(loadUsers, 350); }
function resetUserForm(){
if(!document.getElementById('u_id')) return;
document.getElementById('u_id').value='';
['u_nama','u_username','u_password'].forEach(id=>document.getElementById(id).value='');
document.getElementById('u_status').value='aktif';
const roleSelect=document.getElementById('u_role'); if(roleSelect) roleSelect.selectedIndex=0;
document.getElementById('u_submit_btn').textContent='Buat Akun';
}
function submitUser(){
const namaEl=document.getElementById('u_nama'); if(!namaEl) return;
const id=document.getElementById('u_id').value;
const usernameEl=document.getElementById('u_username');
const passwordEl=document.getElementById('u_password');
// FIX: validasi input sebelum fetch.
if(!namaEl.value.trim()){ toast('Nama akun wajib diisi.','err'); return; }
if(!usernameEl.value.trim()){ toast('Username wajib diisi.','err'); return; }
if(!id && !passwordEl.value){ toast('Password wajib diisi saat membuat akun baru.','err'); return; }
if(passwordEl.value && passwordEl.value.length < 6){ toast('Password minimal 6 karakter.','err'); return; }
const fd=new FormData();
fd.append('id', id);
fd.append('nama', namaEl.value);
fd.append('username', usernameEl.value);
fd.append('password', passwordEl.value);
fd.append('role', document.getElementById('u_role').value);
fd.append('status_akun', document.getElementById('u_status').value);
const url = id ? 'edit_user.php' : 'tambah_user.php';
fetch(url,{method:'POST',body:fd}).then(r=>r.json()).then(res=>{
toast(res.message, res.status==='ok'?'ok':'err');
if(res.status==='ok'){ resetUserForm(); loadUsers(); }
}).catch(e=>toast('Gagal menyimpan akun: '+e.message,'err'));
}
function loadUsers(){
const body=document.getElementById('akunBody'); if(!body) return;
const q=new URLSearchParams();
q.set('role', document.getElementById('fu_role').value);
q.set('status_akun', document.getElementById('fu_status').value);
q.set('keyword', document.getElementById('fu_keyword').value);
body.innerHTML='<tr><td colspan="6">Memuat akun...</td></tr>';
fetch('ambil_user.php?'+q.toString()).then(r=>r.json()).then(res=>{
if(res.status!=='ok') throw new Error(res.message);
renderUserTable(res.data||[]);
}).catch(e=>{ body.innerHTML=`<tr><td colspan="6">${esc(e.message)}</td></tr>`; });
}
function renderUserTable(rows){
const body=document.getElementById('akunBody'); if(!body) return;
if(!rows.length){body.innerHTML='<tr><td colspan="6">Tidak ada akun sesuai filter.</td></tr>'; return;}
body.innerHTML=rows.map(u=>{
const relasi = u.role==='admin_rumah_ibadah'
? `Rumah ibadah: ${esc(u.rumah_ibadah_dikelola||'-')}`
: `Titik penerima: ${esc(u.jumlah_titik_penerima||0)}<br><span class="muted">Rumah ibadah: ${esc(u.rumah_ibadah_penerima||'-')}</span>`;
return `<tr>
<td><b>${esc(u.nama)}</b><br><span class="muted">${esc(u.username)}</span></td>
<td><span class="badge">${esc(u.role)}</span></td>
<td><span class="badge">${esc(u.status_akun)}</span></td>
<td>${relasi}</td>
<td><span class="muted">${esc(u.created_at||'-')}<br>${esc(u.updated_at||'-')}</span></td>
<td><!--<button class="btn primary small" onclick='editUserForm(${JSON.stringify(u).replace(/'/g,"&#039;")})'>Edit</button>--> <button class="btn gray small" onclick="hapusUser(${u.id})">Hapus/Nonaktifkan</button></td>
</tr>`;
}).join('');
}
function editUserForm(u){
document.getElementById('u_id').value=u.id;
document.getElementById('u_nama').value=u.nama||'';
document.getElementById('u_username').value=u.username||'';
document.getElementById('u_password').value='';
const roleSelect=document.getElementById('u_role');
if([...roleSelect.options].some(o=>o.value===u.role)) roleSelect.value=u.role;
document.getElementById('u_status').value=u.status_akun||'aktif';
document.getElementById('u_submit_btn').textContent='Update Akun';
window.scrollTo({top: document.getElementById('u_nama').getBoundingClientRect().top + window.scrollY - 120, behavior:'smooth'});
}
function hapusUser(id){
if(!confirm('Hapus akun ini? Jika sudah punya relasi data, akun akan dinonaktifkan agar data tidak rusak.')) return;
const fd=new FormData(); fd.append('id', id);
fetch('hapus_user.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{toast(res.message); if(res.status==='ok'){resetUserForm();loadUsers();}}).catch(e=>toast('Gagal hapus akun: '+e.message));
}
function programOption(p){
const label=`${esc(p.nama_program)} (${p.bulan}/${p.tahun}, ${esc(p.jenis_bantuan)}, target ${p.target_frekuensi})`;
// FIX: tambah data-riid agar syncProgramDetail bisa filter penerima per RI.
return `<option value="${p.id}" data-jenis="${esc(p.jenis_bantuan)}" data-nominal="${esc(p.nominal??'')}" data-jumlah="${esc(p.jumlah_item??'')}" data-riid="${esc(p.rumah_ibadah_id??'')}">${label}</option>`;
}
function renderProgramTable(rows){
const body=document.getElementById('programBody'); if(!body) return;
if(!rows.length){body.innerHTML='<tr><td colspan="6">Belum ada program.</td></tr>'; return;}
body.innerHTML=rows.map(p=>`<tr><td><b>${esc(p.nama_program)}</b><br><span class="muted">${esc(p.deskripsi||'')}</span></td><td>${p.bulan}/${p.tahun}<br><span class="muted">Target ${p.target_frekuensi} kali</span></td><td>${esc(p.jenis_bantuan)}</td><td>Nominal: ${esc(p.nominal??'-')}<br>Item: ${esc(p.jumlah_item||'-')}</td><td><span class="badge">${esc(p.status_program)}</span></td><td><button class="btn gray small" onclick="hapusProgramBantuan(${p.id})">Hapus</button></td></tr>`).join('');
}
function hapusProgramBantuan(id){
if(!confirm('Hapus program bantuan ini? Jika sudah ada penyaluran, status program akan dibatalkan.')) return;
const fd=new FormData(); fd.append('id',id);
fetch('hapus_program_bantuan.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{toast(res.message); if(res.status==='ok'){loadProgramBantuan().then(loadLaporanPenyaluran);}}).catch(e=>toast('Gagal hapus program: '+e.message));
}
function syncProgramDetail(){
const sel=document.getElementById('pn_program'); if(!sel) return;
const opt=sel.options[sel.selectedIndex];
document.getElementById('pn_jenis_view').value=opt?.dataset?.jenis||'';
document.getElementById('pn_nominal_view').value=opt?.dataset?.nominal||'-';
document.getElementById('pn_jumlah_item_view').value=opt?.dataset?.jumlah||'-';
// FIX: reload penerima sesuai RI dari program yang dipilih.
const riId=opt?.dataset?.riid||null;
loadPenerimaDiterima(riId);
}
function loadProgramBantuan(){
return fetch('ambil_program_bantuan.php').then(r=>r.json()).then(res=>{
if(res.status!=='ok') throw new Error(res.message);
const f=document.getElementById('f_program'); const pn=document.getElementById('pn_program');
f.innerHTML='<option value="">Semua</option>'; if(pn) pn.innerHTML='';
(res.data||[]).forEach(p=>{ const opt=programOption(p); f.insertAdjacentHTML('beforeend',opt); if(pn && p.status_program!=='dibatalkan') pn.insertAdjacentHTML('beforeend',opt); });
renderProgramTable(res.data||[]);
syncProgramDetail();
});
}
function loadRumahIbadahUntukProgram(){
const pr=document.getElementById('pr_rumah_ibadah_id');
const fr=document.getElementById('f_rumah_ibadah');
fetch('ambil_data_peta.php').then(r=>r.json()).then(res=>{
const rows=(res.data.rumah_ibadah||[]).filter(ri=>ri.status_pengajuan==='diterima');
rows.forEach(ri=>{
const opt=`<option value="${ri.id}">${esc(ri.nama_rumah_ibadah)} - ${esc(ri.agama)}</option>`;
if(pr) pr.insertAdjacentHTML('beforeend',opt);
if(fr) fr.insertAdjacentHTML('beforeend',opt);
});
});
}
function loadPenerimaDiterima(filterRiId=null){
const el=document.getElementById('pn_penerima'); if(!el) return;
fetch('ambil_data_peta.php').then(r=>r.json()).then(res=>{
el.innerHTML='';
let list = (res.data.penerima||[]).filter(p=>p.status_pengajuan==='diterima');
// FIX: filter penerima sesuai RI dari program yang dipilih agar tidak bisa pilih penerima RI lain.
if(filterRiId) list = list.filter(p=>String(p.rumah_ibadah_id)===String(filterRiId));
if(!list.length) el.insertAdjacentHTML('beforeend','<option value="">-- Tidak ada penerima di RI ini --</option>');
list.forEach(p=>el.insertAdjacentHTML('beforeend',`<option value="${p.id}">${esc(p.nama_penerima)} - ${esc(p.nama_rumah_ibadah||'')}</option>`));
});
}
function submitProgramBantuan(){
const namaEl = document.getElementById('pr_nama');
const bulanEl = document.getElementById('pr_bulan');
const tahunEl = document.getElementById('pr_tahun');
// FIX: validasi input wajib sebelum fetch.
if(!namaEl?.value.trim()){ toast('Nama program wajib diisi.','err'); return; }
if(!bulanEl?.value || bulanEl.value < 1 || bulanEl.value > 12){ toast('Bulan tidak valid (1-12).','err'); return; }
if(!tahunEl?.value || tahunEl.value < 2000){ toast('Tahun tidak valid.','err'); return; }
const fd=new FormData();
const ri=document.getElementById('pr_rumah_ibadah_id');
if(ri) fd.append('rumah_ibadah_id',ri.value);
fd.append('nama_program', namaEl.value);
fd.append('jenis_bantuan', document.getElementById('pr_jenis').value);
fd.append('bulan', bulanEl.value);
fd.append('tahun', tahunEl.value);
fd.append('target_frekuensi', document.getElementById('pr_target').value);
fd.append('nominal', document.getElementById('pr_nominal').value);
fd.append('jumlah_item', document.getElementById('pr_jumlah_item').value);
fd.append('deskripsi', document.getElementById('pr_deskripsi').value);
fetch('tambah_program_bantuan.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{
toast(res.message, res.status==='ok'?'ok':'err');
if(res.status==='ok'){ loadProgramBantuan().then(loadLaporanPenyaluran); }
}).catch(e=>toast('Gagal membuat program: '+e.message,'err'));
}
function submitPenyaluran(customProgramId=null, customPenerimaId=null){
const programId = customProgramId || document.getElementById('pn_program').value;
const penerimaId = customPenerimaId || document.getElementById('pn_penerima').value;
// FIX: validasi input wajib sebelum fetch agar tidak kirim request dengan data kosong.
if(!programId){ toast('Pilih program bantuan terlebih dahulu.','err'); return; }
if(!penerimaId){ toast('Pilih penerima terlebih dahulu.','err'); return; }
const fd=new FormData();
fd.append('program_id', programId);
fd.append('penerima_id', penerimaId);
fd.append('keterangan', customProgramId ? 'Dicatat cepat dari tabel laporan.' : document.getElementById('pn_keterangan').value);
fd.append('tanggal_penyaluran', document.getElementById('pn_tanggal')?.value || new Date().toISOString().slice(0,10));
fetch('tambah_penyaluran.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{
toast(res.message, res.status==='ok'?'ok':'err');
if(res.status==='ok'){ loadLaporanPenyaluran(); loadPenerimaDiterima(); }
}).catch(e=>toast('Gagal mencatat penyaluran: '+e.message,'err'));
}
function quickCatatPenyaluran(programId,penerimaId){
if(!confirm('Catat penyaluran bantuan untuk penerima ini sesuai jenis, nominal, dan jumlah item pada program?')) return;
submitPenyaluran(programId,penerimaId);
}
function loadLaporanPenyaluran(){
fetch('ambil_laporan_penyaluran.php?'+getFilterQuery()).then(r=>r.json()).then(res=>{ if(res.status!=='ok') throw new Error(res.message); renderRekapPenyaluran(res.data.rekap); renderTabelPenyaluran(res.data.rows); }).catch(e=>{document.getElementById('laporanBody').innerHTML=`<tr><td colspan="9">${esc(e.message)}</td></tr>`});
}
function renderRekapPenyaluran(r){
const labels={total:'Total Baris',belum_diberi:'Belum diberi',sudah_diberi:'Sudah diberi',belum_memenuhi_target:'Belum memenuhi target',sesuai_target:'Sesuai target',melebihi_target:'Melebihi target'};
document.getElementById('rekapBox').innerHTML=Object.keys(labels).map(k=>`<div class="card"><div class="k">${labels[k]}</div><div class="v">${r?.[k]??0}</div></div>`).join('');
}
function renderTabelPenyaluran(rows){
const body=document.getElementById('laporanBody');
if(!rows.length){body.innerHTML='<tr><td colspan="9">Tidak ada data sesuai filter.</td></tr>'; return;}
body.innerHTML=rows.map(r=>{
const target=Number(r.target_frekuensi||1), jumlah=Number(r.jumlah_penyaluran||0);
const bolehCatat = USER_ROLE!=='penerima' && jumlah < target && r.status_program !== 'selesai';
let aksiLabel = 'Sudah sesuai target';
if(r.status_program==='selesai') aksiLabel = 'Program selesai';
const aksi = bolehCatat ? `<button class="btn primary small" onclick="quickCatatPenyaluran(${r.program_id},${r.penerima_id})">Catat</button>` : `<button class="btn gray small" disabled>${aksiLabel}</button>`;
return `<tr><td><b>${esc(r.nama_penerima)}</b><br><span class="muted">${esc(r.no_hp||'')}</span></td><td>${esc(r.nama_rumah_ibadah)}<br><span class="muted">${esc(r.agama)}</span></td><td>${esc(r.nama_program)}<br><span class="muted">${r.bulan}/${r.tahun} - ${esc(r.jenis_bantuan)}</span><br><span class="muted">Nominal: ${esc(r.nominal??'-')} | Item: ${esc(r.jumlah_item||'-')}</span></td><td>${r.target_frekuensi}</td><td>${r.jumlah_penyaluran}</td><td><span class="badge ${r.status_penyaluran}">${esc(r.status_penyaluran)}</span></td><td>${esc(r.tanggal_terakhir||'-')}</td><td>${(r.riwayat||[]).map(x=>`<div>${esc(x)}</div>`).join('')||'-'}</td><td>${aksi}</td></tr>`;
}).join('');
}
function filterLaporanPenyaluran(){ loadLaporanPenyaluran(); }
function updateStatusPenerima(id,status){
const alasan=prompt('Masukkan catatan/alasan:')||'';
const fd=new FormData(); fd.append('id',id); fd.append('status_pengajuan',status); fd.append('alasan_status',alasan);
fetch('update_status_penerima.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{toast(res.message); if(res.status==='ok') location.reload();}).catch(e=>toast('Gagal update: '+e.message));
}
function updateStatusRumahIbadah(id,status){
const alasan=prompt('Masukkan catatan/alasan:')||'';
const fd=new FormData(); fd.append('id',id); fd.append('status_pengajuan',status); fd.append('keterangan',alasan);
fetch('update_status_rumah_ibadah.php',{method:'POST',body:fd}).then(r=>r.json()).then(res=>{toast(res.message); if(res.status==='ok') location.reload();}).catch(e=>toast('Gagal update: '+e.message));
}
function loadRiwayat(){ fetch('ambil_riwayat.php').then(r=>r.json()).then(res=>{ const d=res.data; document.getElementById('riwayatBox').innerHTML=`<b>Pengajuan:</b> ${(d.pengajuan||[]).length} data<br><b>Perubahan status:</b> ${(d.status||[]).length} data<br><b>Penyaluran:</b> ${(d.penyaluran||[]).length} data`; }); }
['f_bulan','f_tahun','f_rumah_ibadah','f_agama','f_program','f_jenis','f_status'].forEach(id=>document.getElementById(id)?.addEventListener('change',filterLaporanPenyaluran));
loadUsers();
loadRumahIbadahUntukProgram();
loadProgramBantuan().then(()=>{loadLaporanPenyaluran();loadPenerimaDiterima();loadRiwayat();});
</script></body></html>