add files and folders
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../php/koneksi.php';
|
||||
require_once __DIR__ . '/../php/middleware/auth.php';
|
||||
|
||||
function render_header(string $title): void {
|
||||
$user = $_SESSION['user_nama'] ?? 'Tamu';
|
||||
$role = $_SESSION['role'] ?? '';
|
||||
$unread = 0;
|
||||
global $pdo;
|
||||
if (!empty($_SESSION['user_id'])) {
|
||||
try {
|
||||
$stmtN = $pdo->prepare("SELECT COUNT(*) FROM notifikasi WHERE user_id=:u AND dibaca=0");
|
||||
$stmtN->execute([':u' => $_SESSION['user_id']]);
|
||||
$unread = (int)$stmtN->fetchColumn();
|
||||
} catch(Exception $e){}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title><?= h($title) ?> — WebGIS Kemiskinan</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
:root{--bg:#0f172a;--sur:#1e293b;--sur2:#334155;--acc:#3b82f6;--green:#22c55e;--red:#ef4444;--yellow:#f59e0b;--txt:#f1f5f9;--txt2:#94a3b8;--brd:#334155;--rad:12px}
|
||||
body{font-family:'Segoe UI',system-ui,sans-serif;background:var(--bg);color:var(--txt);min-height:100vh}
|
||||
#topbar{background:var(--sur);border-bottom:1px solid var(--brd);padding:0 20px;height:54px;display:flex;align-items:center;gap:12px;position:sticky;top:0;z-index:100}
|
||||
#topbar .logo{font-weight:900;font-size:15px} #topbar .logo span{color:var(--acc)}
|
||||
#topbar .spacer{flex:1}
|
||||
#topbar .user{font-size:12px;color:var(--txt2);font-weight:700}
|
||||
#topbar a.tbtn,#topbar button.tbtn{background:var(--sur2);border:1px solid var(--brd);color:var(--txt);padding:6px 12px;border-radius:8px;font-size:12px;font-weight:700;text-decoration:none;cursor:pointer;transition:.2s;display:inline-flex;align-items:center;gap:5px}
|
||||
#topbar a.tbtn:hover,#topbar button.tbtn:hover{background:var(--acc);border-color:var(--acc);color:#fff}
|
||||
#wrap{display:flex;min-height:calc(100vh - 54px)}
|
||||
#nav{width:220px;background:var(--sur);border-right:1px solid var(--brd);padding:16px 0;flex-shrink:0}
|
||||
#nav a{display:flex;align-items:center;gap:10px;padding:10px 20px;color:var(--txt2);text-decoration:none;font-size:13px;font-weight:700;transition:.2s;border-left:3px solid transparent}
|
||||
#nav a:hover,#nav a.active{color:var(--txt);background:rgba(59,130,246,.1);border-left-color:var(--acc)}
|
||||
#nav .nav-section{padding:12px 20px 4px;font-size:10px;font-weight:900;color:var(--brd);text-transform:uppercase;letter-spacing:.5px}
|
||||
#content{flex:1;padding:24px;overflow-x:auto}
|
||||
.page-title{font-size:20px;font-weight:900;margin-bottom:20px;display:flex;align-items:center;gap:10px}
|
||||
.card{background:var(--sur);border:1px solid var(--brd);border-radius:var(--rad);padding:20px;margin-bottom:16px}
|
||||
.stats-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-bottom:20px}
|
||||
.stat{background:var(--sur);border:1px solid var(--brd);border-radius:var(--rad);padding:16px;text-align:center}
|
||||
.stat .val{font-size:28px;font-weight:900} .stat .lbl{font-size:11px;color:var(--txt2);font-weight:700;margin-top:2px}
|
||||
.stat.red .val{color:var(--red)} .stat.yellow .val{color:var(--yellow)} .stat.green .val{color:var(--green)} .stat.blue .val{color:var(--acc)}
|
||||
table{width:100%;border-collapse:collapse;font-size:13px}
|
||||
th{background:var(--sur2);padding:10px 12px;text-align:left;font-size:11px;font-weight:900;color:var(--txt2);text-transform:uppercase}
|
||||
td{padding:10px 12px;border-bottom:1px solid var(--brd)}
|
||||
tr:hover td{background:rgba(255,255,255,.02)}
|
||||
.tag{display:inline-block;padding:2px 8px;border-radius:99px;font-size:11px;font-weight:800}
|
||||
.tag.miskin{background:rgba(239,68,68,.15);color:var(--red)}
|
||||
.tag.rentan{background:rgba(245,158,11,.15);color:var(--yellow)}
|
||||
.tag.mampu{background:rgba(34,197,94,.15);color:var(--green)}
|
||||
.tag.pending{background:rgba(245,158,11,.15);color:var(--yellow)}
|
||||
.tag.diproses{background:rgba(59,130,246,.15);color:var(--acc)}
|
||||
.tag.selesai{background:rgba(34,197,94,.15);color:var(--green)}
|
||||
.tag.darurat{background:rgba(239,68,68,.2);color:var(--red)}
|
||||
.btn{padding:8px 16px;border-radius:8px;border:none;cursor:pointer;font-weight:700;font-size:12px;display:inline-flex;align-items:center;gap:5px;transition:.2s;text-decoration:none}
|
||||
.btn-primary{background:var(--acc);color:#fff} .btn-primary:hover{background:#2563eb}
|
||||
.btn-success{background:var(--green);color:#fff}
|
||||
.btn-danger{background:var(--red);color:#fff}
|
||||
.btn-secondary{background:var(--sur2);color:var(--txt);border:1px solid var(--brd)}
|
||||
.btn-sm{padding:4px 10px;font-size:11px}
|
||||
input,select,textarea{background:var(--sur2);border:1px solid var(--brd);color:var(--txt);padding:8px 12px;border-radius:8px;font-size:13px;width:100%}
|
||||
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--acc)}
|
||||
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
||||
.form-group{display:flex;flex-direction:column;gap:5px}
|
||||
.form-group.full{grid-column:1/-1}
|
||||
label{font-size:11px;font-weight:700;color:var(--txt2);text-transform:uppercase}
|
||||
.notice{padding:10px 14px;border-radius:8px;border:1px solid;font-size:13px;margin-bottom:12px}
|
||||
.actions{display:flex;gap:6px;flex-wrap:wrap}
|
||||
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
||||
@media(max-width:768px){#nav{display:none}#content{padding:16px}.form-grid{grid-template-columns:1fr}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="topbar">
|
||||
<div class="logo">🗺️ <span>WebGIS</span> Kemiskinan</div>
|
||||
<div class="spacer"></div>
|
||||
<span class="user">👤 <?= h($user) ?> <span style="color:var(--acc)">(<?= h($role) ?>)</span></span>
|
||||
<a class="tbtn" href="../index.html"><i class="fa-solid fa-map"></i> Buka Peta</a>
|
||||
<a class="tbtn" href="logout.php"><i class="fa-solid fa-right-from-bracket"></i> Logout</a>
|
||||
</div>
|
||||
<div id="wrap">
|
||||
<div id="nav">
|
||||
<div class="nav-section">Menu Utama</div>
|
||||
<a href="index.php" <?= basename($_SERVER['PHP_SELF'])==='index.php'?'class="active"':'' ?>><i class="fa-solid fa-gauge" style="width:16px"></i> Dashboard</a>
|
||||
|
||||
<?php if (in_array($role, ['admin','pengurus'])): ?>
|
||||
<div class="nav-section">Data</div>
|
||||
<a href="penduduk.php" <?= basename($_SERVER['PHP_SELF'])==='penduduk.php'?'class="active"':'' ?>><i class="fa-solid fa-users" style="width:16px"></i> Penduduk</a>
|
||||
<a href="keluarga.php" <?= basename($_SERVER['PHP_SELF'])==='keluarga.php'?'class="active"':'' ?>><i class="fa-solid fa-house-chimney-user" style="width:16px"></i> Keluarga (KK)</a>
|
||||
<a href="rumah_ibadah.php" <?= basename($_SERVER['PHP_SELF'])==='rumah_ibadah.php'?'class="active"':'' ?>><i class="fa-solid fa-mosque" style="width:16px"></i> Rumah Ibadah</a>
|
||||
|
||||
<div class="nav-section">Bantuan</div>
|
||||
<a href="bantuan.php" <?= basename($_SERVER['PHP_SELF'])==='bantuan.php'?'class="active"':'' ?>><i class="fa-solid fa-gift" style="width:16px"></i> Catat Bantuan</a>
|
||||
<a href="histori_bantuan.php" <?= basename($_SERVER['PHP_SELF'])==='histori_bantuan.php'?'class="active"':'' ?>><i class="fa-solid fa-clock-rotate-left" style="width:16px"></i> Histori Bantuan</a>
|
||||
<a href="belum_dibantu.php" <?= basename($_SERVER['PHP_SELF'])==='belum_dibantu.php'?'class="active"':'' ?>><i class="fa-solid fa-triangle-exclamation" style="width:16px;color:var(--red)"></i> Belum Dibantu</a>
|
||||
|
||||
<div class="nav-section">Laporan</div>
|
||||
<a href="laporan.php" <?= basename($_SERVER['PHP_SELF'])==='laporan.php'?'class="active"':'' ?>><i class="fa-solid fa-flag" style="width:16px"></i> Laporan Masuk</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($role === 'admin'): ?>
|
||||
<div class="nav-section">Sistem</div>
|
||||
<a href="users.php" <?= basename($_SERVER['PHP_SELF'])==='users.php'?'class="active"':'' ?>><i class="fa-solid fa-user-shield" style="width:16px"></i> Manajemen User</a>
|
||||
<a href="log.php" <?= basename($_SERVER['PHP_SELF'])==='log.php'?'class="active"':'' ?>><i class="fa-solid fa-scroll" style="width:16px"></i> Log Aktivitas</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div id="content">
|
||||
<?php
|
||||
}
|
||||
|
||||
function render_footer(): void {
|
||||
echo '</div></div></body></html>';
|
||||
}
|
||||
|
||||
function require_login(array $roles = []): void {
|
||||
requireLogin($roles);
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin','pengurus']);
|
||||
|
||||
$msg = ''; $err = '';
|
||||
$nikPre = $_GET['nik'] ?? '';
|
||||
$namaPre = $_GET['nama'] ?? '';
|
||||
|
||||
if (isset($_POST['save'])) {
|
||||
$nik = trim($_POST['nik'] ?? '');
|
||||
$idJb = (int)($_POST['id_jenis_bantuan'] ?? 0);
|
||||
$tgl = $_POST['tanggal'] ?? date('Y-m-d');
|
||||
if (!preg_match('/^\d{16}$/', $nik)) $err = 'NIK tidak valid.';
|
||||
elseif (!$idJb) $err = 'Jenis bantuan wajib dipilih.';
|
||||
else {
|
||||
try {
|
||||
// Cek penduduk ada
|
||||
$pddk = $pdo->prepare("SELECT nik,id_keluarga FROM penduduk WHERE nik=:nik AND status_hidup='hidup'");
|
||||
$pddk->execute([':nik'=>$nik]);
|
||||
$pddk = $pddk->fetch();
|
||||
if (!$pddk) throw new Exception("Penduduk dengan NIK $nik tidak ditemukan / meninggal.");
|
||||
|
||||
$bukti = null;
|
||||
if (!empty($_FILES['bukti']['name'])) {
|
||||
$bukti = uploadFile($_FILES['bukti'], UPLOAD_BUKTI);
|
||||
}
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO histori_bantuan (nik,id_jenis_bantuan,id_keluarga,rumah_ibadah_id,tanggal,jumlah,nilai_rupiah,status_penyaluran,catatan,bukti_file,disalurkan_oleh)
|
||||
VALUES(:nik,:jb,:kk,:ri,:tgl,:jml,:rp,:status,:cat,:bukti,:user)
|
||||
");
|
||||
$stmt->execute([
|
||||
':nik'=>$nik, ':jb'=>$idJb, ':kk'=>$pddk['id_keluarga'],
|
||||
':ri'=>$_SESSION['rumah_ibadah_id'] ?: null,
|
||||
':tgl'=>$tgl, ':jml'=>$_POST['jumlah']??'' ?: null,
|
||||
':rp'=>$_POST['nilai_rupiah']??'' ?: null,
|
||||
':status'=>$_POST['status_penyaluran']??'disalurkan',
|
||||
':cat'=>$_POST['catatan']??'' ?: null,
|
||||
':bukti'=>$bukti, ':user'=>$_SESSION['user_id'],
|
||||
]);
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'CREATE', 'histori_bantuan', (string)$pdo->lastInsertId());
|
||||
$msg = "Bantuan untuk NIK $nik berhasil dicatat.";
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
}
|
||||
}
|
||||
|
||||
$jenisList = $pdo->query("SELECT * FROM jenis_bantuan WHERE aktif=1 ORDER BY kategori,nama")->fetchAll();
|
||||
|
||||
render_header('Catat Bantuan');
|
||||
?>
|
||||
<div class="page-title">🎁 Catat Penyaluran Bantuan</div>
|
||||
<?php if ($msg): ?><div class="notice" style="border-color:#bbf7d0;background:#f0fdf4;color:#166534"><?= h($msg) ?></div><?php endif; ?>
|
||||
<?php if ($err): ?><div class="notice" style="border-color:#fecaca;background:#fef2f2;color:#991b1b"><?= h($err) ?></div><?php endif; ?>
|
||||
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px">
|
||||
<div>
|
||||
<div class="card">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<div class="form-grid">
|
||||
<div class="form-group full">
|
||||
<label>NIK Penerima *</label>
|
||||
<input name="nik" maxlength="16" value="<?= h($nikPre) ?>" placeholder="16 digit NIK" required onblur="cekPenduduk(this.value)">
|
||||
</div>
|
||||
<div class="form-group full" id="info-pddk" style="background:#334155;border-radius:8px;padding:10px;font-size:12px;display:<?= $namaPre?'block':'none' ?>">
|
||||
<?= $namaPre ? '👤 '.$namaPre : '' ?>
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label>Jenis Bantuan *</label>
|
||||
<select name="id_jenis_bantuan" required>
|
||||
<option value="">— Pilih —</option>
|
||||
<?php foreach ($jenisList as $j): ?>
|
||||
<option value="<?= $j['id'] ?>"><?= h($j['nama']) ?> (<?= h($j['kategori']) ?>)</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Tanggal *</label>
|
||||
<input type="date" name="tanggal" required value="<?= date('Y-m-d') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Status</label>
|
||||
<select name="status_penyaluran">
|
||||
<option value="disalurkan">Disalurkan</option>
|
||||
<option value="dijadwalkan">Dijadwalkan</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Jumlah / Keterangan</label>
|
||||
<input name="jumlah" placeholder="mis: 1 paket sembako">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Nilai (Rp)</label>
|
||||
<input type="number" name="nilai_rupiah" placeholder="0">
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label>Catatan</label>
|
||||
<textarea name="catatan" rows="2" placeholder="Opsional"></textarea>
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label>Bukti Foto/Dokumen</label>
|
||||
<input type="file" name="bukti" accept=".jpg,.jpeg,.png,.webp,.pdf">
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" name="save" value="1" class="btn btn-success" style="margin-top:14px;width:100%">✅ Simpan Bantuan</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="card">
|
||||
<strong>📋 Bantuan Terakhir Disalurkan</strong>
|
||||
<table style="margin-top:12px">
|
||||
<thead><tr><th>Penerima</th><th>Bantuan</th><th>Tanggal</th></tr></thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$recent = $pdo->query("
|
||||
SELECT p.nama_lengkap, jb.nama AS nama_bantuan, hb.tanggal
|
||||
FROM histori_bantuan hb
|
||||
JOIN penduduk p ON p.nik=hb.nik
|
||||
JOIN jenis_bantuan jb ON jb.id=hb.id_jenis_bantuan
|
||||
WHERE hb.status_penyaluran='disalurkan'
|
||||
ORDER BY hb.created_at DESC LIMIT 10
|
||||
")->fetchAll();
|
||||
foreach ($recent as $r): ?>
|
||||
<tr>
|
||||
<td><?= h($r['nama_lengkap']) ?></td>
|
||||
<td><?= h($r['nama_bantuan']) ?></td>
|
||||
<td style="font-size:11px"><?= date('d/m/Y', strtotime($r['tanggal'])) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function cekPenduduk(nik) {
|
||||
if (!/^\d{16}$/.test(nik)) return;
|
||||
const res = await fetch('../php/api/penduduk.php?action=detail&nik='+nik);
|
||||
const json = await res.json();
|
||||
const info = document.getElementById('info-pddk');
|
||||
if (json.success) {
|
||||
const p = json.data;
|
||||
info.style.display = 'block';
|
||||
info.innerHTML = `👤 <strong>${p.nama_lengkap}</strong> | ${p.umur}th |
|
||||
<span style="color:${p.status_ekonomi==='miskin'?'#ef4444':'#f59e0b'}">${p.status_ekonomi}</span> |
|
||||
Sudah dibantu: ${json.histori.length}x`;
|
||||
} else {
|
||||
info.style.display = 'block';
|
||||
info.innerHTML = '<span style="color:#ef4444">❌ NIK tidak ditemukan</span>';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin','pengurus','pimpinan']);
|
||||
|
||||
$rows = [];
|
||||
try {
|
||||
$rows = $pdo->query("
|
||||
SELECT p.nik, p.nama_lengkap, p.status_ekonomi, p.kondisi_kesehatan,
|
||||
p.umur, p.pekerjaan, p.penghasilan, p.alamat,
|
||||
k.no_kk, k.nama_kk, ri.nama AS nama_ri, ri.jenis AS jenis_ri
|
||||
FROM penduduk p
|
||||
LEFT JOIN keluarga k ON k.id=p.id_keluarga
|
||||
LEFT JOIN rumah_ibadah ri ON ri.id=k.rumah_ibadah_id
|
||||
WHERE p.status_hidup='hidup'
|
||||
AND p.status_ekonomi IN ('miskin','rentan')
|
||||
AND NOT EXISTS(
|
||||
SELECT 1 FROM histori_bantuan hb
|
||||
WHERE hb.nik=p.nik AND hb.status_penyaluran='disalurkan'
|
||||
)
|
||||
ORDER BY
|
||||
CASE p.status_ekonomi WHEN 'miskin' THEN 1 ELSE 2 END,
|
||||
CASE p.kondisi_kesehatan WHEN 'sakit_parah' THEN 1 WHEN 'disabilitas' THEN 2 WHEN 'sakit_ringan' THEN 3 ELSE 4 END,
|
||||
p.nama_lengkap
|
||||
")->fetchAll();
|
||||
} catch(Exception $e) {}
|
||||
|
||||
render_header('Belum Pernah Dibantu');
|
||||
?>
|
||||
<div class="page-title">⚠️ Warga Belum Pernah Menerima Bantuan</div>
|
||||
|
||||
<div style="background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.3);border-radius:12px;padding:14px 18px;margin-bottom:16px;font-size:13px">
|
||||
Ditemukan <strong style="color:#ef4444"><?= count($rows) ?> jiwa</strong> dengan status ekonomi miskin/rentan yang belum pernah menerima bantuan apapun. Prioritaskan yang kondisi kesehatannya kritis.
|
||||
</div>
|
||||
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th>Nama</th><th>NIK</th><th>Status</th><th>Kesehatan</th><th>Umur</th><th>Pekerjaan</th><th>Rumah Ibadah</th>
|
||||
<?php if (in_array($_SESSION['role'], ['admin','pengurus'])): ?><th>Aksi</th><?php endif; ?>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r):
|
||||
$kritis = $r['status_ekonomi']==='miskin' && in_array($r['kondisi_kesehatan'],['sakit_parah','disabilitas']);
|
||||
?>
|
||||
<tr <?= $kritis ? 'style="background:rgba(239,68,68,.05)"' : '' ?>>
|
||||
<td>
|
||||
<?= $kritis ? '🔥 ' : '' ?><strong><?= h($r['nama_lengkap']) ?></strong>
|
||||
<?= $r['status_ekonomi']==='miskin' && $r['kondisi_kesehatan']==='sakit_parah' ? '<span class="tag darurat" style="font-size:9px;margin-left:4px">KRITIS</span>' : '' ?>
|
||||
</td>
|
||||
<td style="font-size:11px;color:#94a3b8"><?= h($r['nik']) ?></td>
|
||||
<td><span class="tag <?= $r['status_ekonomi'] ?>"><?= h($r['status_ekonomi']) ?></span></td>
|
||||
<td><?= h(str_replace('_',' ',$r['kondisi_kesehatan'])) ?></td>
|
||||
<td><?= $r['umur'] ?> th</td>
|
||||
<td><?= h($r['pekerjaan'] ?: '-') ?></td>
|
||||
<td><?= h($r['nama_ri'] ?: '-') ?></td>
|
||||
<?php if (in_array($_SESSION['role'], ['admin','pengurus'])): ?>
|
||||
<td>
|
||||
<a href="bantuan.php?nik=<?= h($r['nik']) ?>&nama=<?= urlencode($r['nama_lengkap']) ?>" class="btn btn-success btn-sm">
|
||||
🎁 Beri Bantuan
|
||||
</a>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($rows)): ?>
|
||||
<tr><td colspan="8" style="text-align:center;padding:24px;color:#22c55e">🎉 Semua warga miskin/rentan sudah pernah dibantu!</td></tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Lupa Password — WebGIS Pengentasan Kemiskinan</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:'Segoe UI',system-ui,sans-serif;background:#0f172a;color:#f1f5f9;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:16px}
|
||||
.card{background:#1e293b;border:1px solid #334155;border-radius:20px;padding:40px 36px;width:100%;max-width:400px;box-shadow:0 25px 60px rgba(0,0,0,.5)}
|
||||
.logo{text-align:center;margin-bottom:28px}
|
||||
.logo .icon{font-size:40px;margin-bottom:8px}
|
||||
.logo h1{font-size:20px;font-weight:900}
|
||||
.logo p{font-size:12px;color:#94a3b8;margin-top:4px}
|
||||
.form-group{margin-bottom:16px}
|
||||
label{display:block;font-size:11px;font-weight:700;color:#94a3b8;text-transform:uppercase;margin-bottom:6px}
|
||||
input{width:100%;background:#0f172a;border:1px solid #334155;color:#f1f5f9;padding:11px 14px;border-radius:10px;font-size:14px}
|
||||
input:focus{outline:none;border-color:#3b82f6}
|
||||
.btn{width:100%;background:#3b82f6;color:#fff;border:none;padding:12px;border-radius:10px;font-size:14px;font-weight:800;cursor:pointer;transition:.2s}
|
||||
.btn:hover{background:#2563eb}
|
||||
.error{background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.3);color:#ef4444;padding:10px 14px;border-radius:8px;font-size:13px;margin-bottom:16px;}
|
||||
.success{background:rgba(34,197,94,.1);border:1px solid rgba(34,197,94,.3);color:#22c55e;padding:10px 14px;border-radius:8px;font-size:13px;margin-bottom:16px;}
|
||||
.back{text-align:center;margin-top:16px}
|
||||
.back a{color:#3b82f6;font-size:13px;text-decoration:none}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
require_once __DIR__ . '/../php/koneksi.php';
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = sanitizeStr($_POST['username'] ?? '');
|
||||
$email = sanitizeStr($_POST['email'] ?? '');
|
||||
$new_password = $_POST['new_password'] ?? '';
|
||||
|
||||
if (!$username || !$email || !$new_password) {
|
||||
$error = 'Semua kolom wajib diisi.';
|
||||
} else {
|
||||
// Cek kecocokan username dan email
|
||||
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = :u AND email = :e LIMIT 1");
|
||||
$stmt->execute([':u' => $username, ':e' => $email]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user) {
|
||||
$hash = password_hash($new_password, PASSWORD_DEFAULT);
|
||||
$update = $pdo->prepare("UPDATE users SET password_hash = :p WHERE id = :id");
|
||||
$update->execute([':p' => $hash, ':id' => $user['id']]);
|
||||
$success = 'Password berhasil direset! Silakan login dengan password baru Anda.';
|
||||
} else {
|
||||
$error = 'Username dan Email tidak cocok atau tidak ditemukan.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="card">
|
||||
<div class="logo">
|
||||
<div class="icon">🔑</div>
|
||||
<h1>Reset Password</h1>
|
||||
<p>Masukkan Username & Email Terdaftar</p>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="error"><?= h($error) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($success): ?>
|
||||
<div class="success"><?= h($success) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<input type="text" name="username" placeholder="Cth: admin" required autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Email Terdaftar</label>
|
||||
<input type="email" name="email" placeholder="Cth: admin@webgis.local" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password Baru</label>
|
||||
<input type="password" name="new_password" placeholder="Masukkan password baru" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn">🔄 Reset Password</button>
|
||||
</form>
|
||||
|
||||
<div class="back"><a href="login.php">← Kembali ke Halaman Login</a></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin','pengurus','pimpinan']);
|
||||
|
||||
$rows = [];
|
||||
try {
|
||||
$rows = $pdo->query("
|
||||
SELECT hb.id, hb.nik, p.nama_lengkap, hb.tanggal,
|
||||
jb.nama AS nama_bantuan, jb.kategori,
|
||||
hb.jumlah, hb.nilai_rupiah, hb.status_penyaluran,
|
||||
ri.nama AS nama_ri, u.nama AS disalurkan_oleh
|
||||
FROM histori_bantuan hb
|
||||
JOIN penduduk p ON p.nik=hb.nik
|
||||
JOIN jenis_bantuan jb ON jb.id=hb.id_jenis_bantuan
|
||||
LEFT JOIN rumah_ibadah ri ON ri.id=hb.rumah_ibadah_id
|
||||
LEFT JOIN users u ON u.id=hb.disalurkan_oleh
|
||||
ORDER BY hb.tanggal DESC
|
||||
LIMIT 500
|
||||
")->fetchAll();
|
||||
} catch(Exception $e) {}
|
||||
|
||||
render_header('Histori Bantuan');
|
||||
?>
|
||||
<div class="page-title">📜 Histori Penyaluran Bantuan</div>
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th>#</th><th>Nama Penerima</th><th>Jenis Bantuan</th><th>Jumlah</th>
|
||||
<th>Tanggal</th><th>Rumah Ibadah</th><th>Disalurkan Oleh</th><th>Status</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r): ?>
|
||||
<tr>
|
||||
<td><?= $r['id'] ?></td>
|
||||
<td><?= h($r['nama_lengkap']) ?><br><span style="font-size:10px;color:#94a3b8"><?= h($r['nik']) ?></span></td>
|
||||
<td><?= h($r['nama_bantuan']) ?> <span style="font-size:10px;color:#94a3b8">(<?= h($r['kategori']) ?>)</span></td>
|
||||
<td><?= h($r['jumlah'] ?? '-') ?><?= $r['nilai_rupiah'] ? '<br><span style="font-size:10px;color:#22c55e">Rp '.number_format($r['nilai_rupiah'],0,',','.').'</span>' : '' ?></td>
|
||||
<td><?= date('d/m/Y', strtotime($r['tanggal'])) ?></td>
|
||||
<td><?= h($r['nama_ri'] ?? '-') ?></td>
|
||||
<td><?= h($r['disalurkan_oleh'] ?? '-') ?></td>
|
||||
<td><span class="tag <?= $r['status_penyaluran']==='disalurkan'?'selesai':($r['status_penyaluran']==='dijadwalkan'?'pending':'darurat') ?>"><?= h($r['status_penyaluran']) ?></span></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($rows)): ?><tr><td colspan="8" style="text-align:center;padding:24px;color:#94a3b8">Belum ada data</td></tr><?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin','pengurus','pimpinan']);
|
||||
|
||||
$stats = [];
|
||||
try {
|
||||
$stats = $pdo->query("
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM penduduk WHERE status_ekonomi='miskin' AND status_hidup='hidup') AS miskin,
|
||||
(SELECT COUNT(*) FROM penduduk WHERE status_ekonomi='rentan' AND status_hidup='hidup') AS rentan,
|
||||
(SELECT COUNT(*) FROM penduduk WHERE status_hidup='hidup') AS total_pddk,
|
||||
(SELECT COUNT(*) FROM keluarga) AS total_kk,
|
||||
(SELECT COUNT(*) FROM rumah_ibadah) AS total_ri,
|
||||
(SELECT COUNT(*) FROM laporan WHERE status='pending') AS laporan_pending,
|
||||
(SELECT COUNT(*) FROM laporan WHERE tingkat_urgensi='darurat' AND status NOT IN ('selesai','ditolak')) AS laporan_darurat,
|
||||
(SELECT COUNT(*) FROM histori_bantuan WHERE MONTH(tanggal)=MONTH(CURDATE()) AND YEAR(tanggal)=YEAR(CURDATE()) AND status_penyaluran='disalurkan') AS bantuan_bulan,
|
||||
(SELECT COUNT(*) FROM penduduk WHERE status_hidup='hidup' AND status_ekonomi IN ('miskin','rentan')
|
||||
AND NOT EXISTS(SELECT 1 FROM histori_bantuan hb WHERE hb.nik=penduduk.nik AND hb.status_penyaluran='disalurkan')
|
||||
) AS belum_dibantu
|
||||
")->fetch();
|
||||
} catch(Exception $e) {}
|
||||
|
||||
// Laporan terbaru
|
||||
$laporan_terbaru = [];
|
||||
try {
|
||||
$laporan_terbaru = $pdo->query("
|
||||
SELECT l.id, l.tingkat_urgensi, l.kategori, l.status, l.created_at,
|
||||
l.nama_pelapor, p.nama_lengkap AS nama_terdampak
|
||||
FROM laporan l
|
||||
LEFT JOIN penduduk p ON p.nik = l.nik_terdampak
|
||||
ORDER BY
|
||||
CASE l.tingkat_urgensi WHEN 'darurat' THEN 1 WHEN 'tinggi' THEN 2 ELSE 3 END,
|
||||
l.created_at DESC
|
||||
LIMIT 8
|
||||
")->fetchAll();
|
||||
} catch(Exception $e) {}
|
||||
|
||||
// Prioritas belum dibantu
|
||||
$prioritas = [];
|
||||
try {
|
||||
$prioritas = $pdo->query("
|
||||
SELECT p.nik, p.nama_lengkap, p.status_ekonomi, p.kondisi_kesehatan,
|
||||
p.alamat, k.no_kk, ri.nama AS nama_ri
|
||||
FROM penduduk p
|
||||
LEFT JOIN keluarga k ON k.id=p.id_keluarga
|
||||
LEFT JOIN rumah_ibadah ri ON ri.id=k.rumah_ibadah_id
|
||||
WHERE p.status_hidup='hidup'
|
||||
AND p.status_ekonomi='miskin'
|
||||
AND p.kondisi_kesehatan IN ('sakit_parah','disabilitas')
|
||||
AND NOT EXISTS(SELECT 1 FROM histori_bantuan hb WHERE hb.nik=p.nik AND hb.status_penyaluran='disalurkan')
|
||||
ORDER BY CASE p.kondisi_kesehatan WHEN 'sakit_parah' THEN 1 ELSE 2 END
|
||||
LIMIT 5
|
||||
")->fetchAll();
|
||||
} catch(Exception $e) {}
|
||||
|
||||
render_header('Dashboard');
|
||||
?>
|
||||
|
||||
<div class="page-title">📊 Dashboard Monitoring</div>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="stats-row">
|
||||
<div class="stat red"><div class="val"><?= $stats['miskin'] ?? 0 ?></div><div class="lbl">Warga Miskin</div></div>
|
||||
<div class="stat yellow"><div class="val"><?= $stats['rentan'] ?? 0 ?></div><div class="lbl">Warga Rentan</div></div>
|
||||
<div class="stat blue"><div class="val"><?= $stats['total_kk'] ?? 0 ?></div><div class="lbl">Total KK</div></div>
|
||||
<div class="stat green"><div class="val"><?= $stats['bantuan_bulan'] ?? 0 ?></div><div class="lbl">Bantuan Bulan Ini</div></div>
|
||||
<div class="stat red"><div class="val"><?= $stats['laporan_pending'] ?? 0 ?></div><div class="lbl">Laporan Pending</div></div>
|
||||
<div class="stat red"><div class="val"><?= $stats['belum_dibantu'] ?? 0 ?></div><div class="lbl">Belum Pernah Dibantu</div></div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($stats['laporan_darurat']) && $stats['laporan_darurat'] > 0): ?>
|
||||
<div style="background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.3);border-radius:12px;padding:14px 18px;margin-bottom:16px;display:flex;align-items:center;gap:12px">
|
||||
<span style="font-size:24px">🚨</span>
|
||||
<div>
|
||||
<div style="font-weight:900;color:#ef4444"><?= $stats['laporan_darurat'] ?> LAPORAN DARURAT belum ditangani!</div>
|
||||
<div style="font-size:12px;color:#94a3b8;margin-top:2px">Segera tindak lanjuti laporan kondisi darurat dari masyarakat.</div>
|
||||
</div>
|
||||
<a href="laporan.php?filter=darurat" class="btn btn-danger" style="margin-left:auto">Lihat →</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px">
|
||||
|
||||
<!-- Laporan terbaru -->
|
||||
<div class="card">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px">
|
||||
<strong>📋 Laporan Terbaru</strong>
|
||||
<a href="laporan.php" class="btn btn-secondary btn-sm">Semua →</a>
|
||||
</div>
|
||||
<table>
|
||||
<thead><tr><th>Pelapor/Terdampak</th><th>Urgensi</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($laporan_terbaru as $l): ?>
|
||||
<tr>
|
||||
<td><?= h($l['nama_terdampak'] ?? $l['nama_pelapor'] ?? 'Anonim') ?></td>
|
||||
<td><span class="tag <?= $l['tingkat_urgensi'] === 'darurat' ? 'darurat' : 'pending' ?>"><?= h($l['tingkat_urgensi']) ?></span></td>
|
||||
<td><span class="tag <?= $l['status'] ?>"><?= h($l['status']) ?></span></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($laporan_terbaru)): ?><tr><td colspan="3" style="text-align:center;color:#94a3b8">Belum ada laporan</td></tr><?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Prioritas kritis -->
|
||||
<div class="card">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px">
|
||||
<strong>🔥 Prioritas KRITIS (Belum Dibantu)</strong>
|
||||
<a href="belum_dibantu.php" class="btn btn-danger btn-sm">Semua →</a>
|
||||
</div>
|
||||
<table>
|
||||
<thead><tr><th>Nama</th><th>Status</th><th>Kesehatan</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($prioritas as $p): ?>
|
||||
<tr>
|
||||
<td><a href="penduduk.php?detail=<?= h($p['nik']) ?>" style="color:var(--acc)"><?= h($p['nama_lengkap']) ?></a></td>
|
||||
<td><span class="tag miskin"><?= h($p['status_ekonomi']) ?></span></td>
|
||||
<td style="color:#ef4444"><?= h($p['kondisi_kesehatan']) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($prioritas)): ?><tr><td colspan="3" style="text-align:center;color:#94a3b8">🎉 Tidak ada kasus kritis saat ini</td></tr><?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
// Script inisialisasi — jalankan SEKALI untuk membuat akun admin & demo
|
||||
// URL: http://localhost/webgis-kemiskinan/admin/init_admin.php
|
||||
// HAPUS file ini setelah dipakai di produksi!
|
||||
|
||||
require_once __DIR__ . '/../php/koneksi.php';
|
||||
|
||||
$users = [
|
||||
['admin', 'Administrator', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 1, null],
|
||||
['pengurus1', 'H. Ahmad Fauzi (Pengurus)', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 2, 1],
|
||||
['pimpinan1', 'Camat Pontianak Selatan', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 3, null],
|
||||
['warga1', 'Budi Santoso', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 4, null],
|
||||
];
|
||||
|
||||
$created = 0;
|
||||
foreach ($users as [$uname, $nama, $hash, $role, $ri]) {
|
||||
$cek = $pdo->prepare("SELECT id FROM users WHERE username=:u");
|
||||
$cek->execute([':u'=>$uname]);
|
||||
if (!$cek->fetch()) {
|
||||
$pdo->prepare("INSERT INTO users (role_id,nama,username,password_hash,rumah_ibadah_id) VALUES(:r,:n,:u,:p,:ri)")
|
||||
->execute([':r'=>$role,':n'=>$nama,':u'=>$uname,':p'=>$hash,':ri'=>$ri]);
|
||||
$created++;
|
||||
echo "✅ User '$uname' dibuat.<br>";
|
||||
} else {
|
||||
echo "ℹ️ User '$uname' sudah ada — dilewati.<br>";
|
||||
}
|
||||
}
|
||||
|
||||
echo "<br><strong>$created user baru dibuat.</strong><br>";
|
||||
echo "<br>Password semua akun demo: <code>password</code><br>";
|
||||
echo "<br><strong>Segera hapus file ini setelah digunakan!</strong><br>";
|
||||
echo "<br><a href='login.php'>→ Ke halaman login</a>";
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin','pengurus','pimpinan']);
|
||||
|
||||
$role = $_SESSION['role'];
|
||||
$canEdit = in_array($role, ['admin','pengurus']);
|
||||
$msg = ''; $err = '';
|
||||
|
||||
// DELETE
|
||||
if ($canEdit && isset($_GET['delete'])) {
|
||||
$id = (int)$_GET['delete'];
|
||||
try {
|
||||
$pdo->prepare("DELETE FROM keluarga WHERE id=:id")->execute([':id'=>$id]);
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'DELETE', 'keluarga', (string)$id);
|
||||
$msg = "Data keluarga #$id dihapus.";
|
||||
} catch(Exception $e) { $err = 'Gagal hapus: '.$e->getMessage(); }
|
||||
}
|
||||
|
||||
// SAVE
|
||||
if ($canEdit && isset($_POST['save'])) {
|
||||
$nokk = trim($_POST['no_kk'] ?? '');
|
||||
$nama = trim($_POST['nama_kk'] ?? '');
|
||||
$idEdit = (int)($_POST['id_edit'] ?? 0);
|
||||
if (!preg_match('/^\d{16}$/', $nokk)) $err = 'No KK harus 16 digit.';
|
||||
elseif (strlen($nama) < 3) $err = 'Nama KK terlalu pendek.';
|
||||
else {
|
||||
try {
|
||||
$data = [
|
||||
':nokk' => $nokk, ':nama' => $nama,
|
||||
':almt' => $_POST['alamat']??'' ?: null,
|
||||
':kel' => $_POST['kelurahan']??'' ?: null,
|
||||
':kec' => $_POST['kecamatan']??'' ?: null,
|
||||
':kota' => $_POST['kota']??'' ?: null,
|
||||
':lat' => $_POST['latitude']??'' ?: null,
|
||||
':lng' => $_POST['longitude']??'' ?: null,
|
||||
':se' => $_POST['status_ekonomi']??'rentan',
|
||||
':ri' => $_POST['rumah_ibadah_id']??'' ?: null,
|
||||
];
|
||||
if ($idEdit) {
|
||||
$data[':id'] = $idEdit;
|
||||
$pdo->prepare("UPDATE keluarga SET no_kk=:nokk,nama_kk=:nama,alamat=:almt,kelurahan=:kel,
|
||||
kecamatan=:kec,kota=:kota,latitude=:lat,longitude=:lng,status_ekonomi=:se,
|
||||
rumah_ibadah_id=:ri WHERE id=:id")->execute($data);
|
||||
$msg = "Data KK $nama diperbarui.";
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'UPDATE', 'keluarga', (string)$idEdit);
|
||||
} else {
|
||||
$pdo->prepare("INSERT INTO keluarga (no_kk,nama_kk,alamat,kelurahan,kecamatan,kota,latitude,longitude,status_ekonomi,rumah_ibadah_id)
|
||||
VALUES(:nokk,:nama,:almt,:kel,:kec,:kota,:lat,:lng,:se,:ri)")->execute($data);
|
||||
$msg = "Keluarga $nama berhasil ditambahkan.";
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'CREATE', 'keluarga', (string)$pdo->lastInsertId());
|
||||
}
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
}
|
||||
}
|
||||
|
||||
$edit = null;
|
||||
if (isset($_GET['edit'])) {
|
||||
$s = $pdo->prepare("SELECT * FROM keluarga WHERE id=:id");
|
||||
$s->execute([':id'=>(int)$_GET['edit']]);
|
||||
$edit = $s->fetch() ?: null;
|
||||
}
|
||||
|
||||
$search = trim($_GET['s'] ?? '');
|
||||
$where = []; $params = [];
|
||||
if ($search) { $where[] = '(k.nama_kk LIKE :q OR k.no_kk LIKE :q2)'; $params[':q']='%'.$search.'%'; $params[':q2']='%'.$search.'%'; }
|
||||
$whereStr = $where ? 'WHERE '.implode(' AND ',$where) : '';
|
||||
$rows = $pdo->prepare("
|
||||
SELECT k.*, ri.nama AS nama_ri,
|
||||
(SELECT COUNT(*) FROM penduduk p WHERE p.id_keluarga=k.id) AS jml_anggota
|
||||
FROM keluarga k
|
||||
LEFT JOIN rumah_ibadah ri ON ri.id=k.rumah_ibadah_id
|
||||
$whereStr ORDER BY k.nama_kk LIMIT 300
|
||||
");
|
||||
$rows->execute($params);
|
||||
$rows = $rows->fetchAll();
|
||||
$riList = $pdo->query("SELECT id,nama,jenis FROM rumah_ibadah ORDER BY nama")->fetchAll();
|
||||
|
||||
render_header('Keluarga (KK)');
|
||||
?>
|
||||
<div class="page-title">🏠 Data Keluarga (Kartu Keluarga)</div>
|
||||
|
||||
<?php if ($msg): ?><div class="notice" style="border-color:#bbf7d0;background:#f0fdf4;color:#166534"><?= h($msg) ?></div><?php endif; ?>
|
||||
<?php if ($err): ?><div class="notice" style="border-color:#fecaca;background:#fef2f2;color:#991b1b"><?= h($err) ?></div><?php endif; ?>
|
||||
|
||||
<div style="display:grid;grid-template-columns:<?= $canEdit ? '1fr 1.5fr' : '1fr' ?>;gap:16px">
|
||||
<?php if ($canEdit): ?>
|
||||
<div class="card">
|
||||
<strong><?= $edit ? '✏️ Edit KK' : '➕ Tambah KK' ?></strong><br><br>
|
||||
<form method="POST">
|
||||
<?php if ($edit): ?><input type="hidden" name="id_edit" value="<?= $edit['id'] ?>"><?php endif; ?>
|
||||
<div class="form-grid">
|
||||
<div class="form-group full"><label>No KK (16 digit) *</label>
|
||||
<input name="no_kk" maxlength="16" required value="<?= h($edit['no_kk'] ?? '') ?>"></div>
|
||||
<div class="form-group full"><label>Nama Kepala Keluarga *</label>
|
||||
<input name="nama_kk" required value="<?= h($edit['nama_kk'] ?? '') ?>"></div>
|
||||
<div class="form-group full"><label>Alamat</label>
|
||||
<textarea name="alamat" rows="2"><?= h($edit['alamat'] ?? '') ?></textarea></div>
|
||||
<div class="form-group"><label>Kelurahan</label>
|
||||
<input name="kelurahan" value="<?= h($edit['kelurahan'] ?? '') ?>"></div>
|
||||
<div class="form-group"><label>Kecamatan</label>
|
||||
<input name="kecamatan" value="<?= h($edit['kecamatan'] ?? '') ?>"></div>
|
||||
<div class="form-group"><label>Status Ekonomi</label>
|
||||
<select name="status_ekonomi">
|
||||
<?php foreach (['miskin','rentan','mampu'] as $s): ?>
|
||||
<option value="<?= $s ?>" <?= ($edit['status_ekonomi'] ?? 'rentan')===$s?'selected':'' ?>><?= ucfirst($s) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select></div>
|
||||
<div class="form-group"><label>Rumah Ibadah Terdekat</label>
|
||||
<select name="rumah_ibadah_id">
|
||||
<option value="">— Tidak ada —</option>
|
||||
<?php foreach ($riList as $ri): ?>
|
||||
<option value="<?= $ri['id'] ?>" <?= ($edit['rumah_ibadah_id'] ?? '')==$ri['id']?'selected':'' ?>><?= h($ri['nama']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select></div>
|
||||
<div class="form-group"><label>Latitude</label>
|
||||
<input name="latitude" type="number" step="any" value="<?= h($edit['latitude'] ?? '') ?>"></div>
|
||||
<div class="form-group"><label>Longitude</label>
|
||||
<input name="longitude" type="number" step="any" value="<?= h($edit['longitude'] ?? '') ?>"></div>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" name="save" class="btn btn-primary"><?= $edit ? '💾 Update' : '➕ Simpan' ?></button>
|
||||
<?php if ($edit): ?><a href="keluarga.php" class="btn btn-secondary">Batal</a><?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div>
|
||||
<div style="display:flex;gap:8px;margin-bottom:12px">
|
||||
<form method="GET" style="display:flex;gap:8px;flex:1">
|
||||
<input name="s" placeholder="Cari nama / No KK…" value="<?= h($search) ?>" style="flex:1">
|
||||
<button class="btn btn-primary">🔍</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<table>
|
||||
<thead><tr><th>No KK</th><th>Nama KK</th><th>Status</th><th>Anggota</th><th>Rumah Ibadah</th><?= $canEdit?'<th>Aksi</th>':'' ?></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r): ?>
|
||||
<tr>
|
||||
<td style="font-size:11px"><?= h($r['no_kk']) ?></td>
|
||||
<td><strong><?= h($r['nama_kk']) ?></strong><br><span style="font-size:11px;color:#94a3b8"><?= h($r['kecamatan']??'') ?></span></td>
|
||||
<td><span class="tag <?= $r['status_ekonomi'] ?>"><?= h($r['status_ekonomi']) ?></span></td>
|
||||
<td><?= $r['jml_anggota'] ?> jiwa</td>
|
||||
<td style="font-size:12px"><?= h($r['nama_ri'] ?? '-') ?></td>
|
||||
<?php if ($canEdit): ?>
|
||||
<td class="actions">
|
||||
<a href="?edit=<?= $r['id'] ?>" class="btn btn-secondary btn-sm">✏️</a>
|
||||
<a href="?delete=<?= $r['id'] ?>" class="btn btn-danger btn-sm" onclick="return confirm('Hapus KK ini?')">🗑️</a>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($rows)): ?><tr><td colspan="6" style="text-align:center;padding:24px;color:#94a3b8">Belum ada data</td></tr><?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin','pengurus','pimpinan']);
|
||||
|
||||
$currentUser = ['id' => (int)$_SESSION['user_id'], 'role' => $_SESSION['role']];
|
||||
$filter = $_GET['filter'] ?? 'semua';
|
||||
$msg = ''; $err = '';
|
||||
|
||||
// Update status laporan
|
||||
if (isset($_POST['update_status']) && in_array($currentUser['role'], ['admin','pengurus'])) {
|
||||
$id = (int)($_POST['lap_id'] ?? 0);
|
||||
$status = $_POST['status'] ?? '';
|
||||
$catatan = trim($_POST['catatan'] ?? '');
|
||||
$valid = ['diverifikasi','diproses','selesai','ditolak'];
|
||||
if ($id > 0 && in_array($status, $valid)) {
|
||||
try {
|
||||
$sets = ['status=:s','updated_at=NOW()'];
|
||||
$params = [':s'=>$status,':id'=>$id];
|
||||
if ($status === 'diverifikasi') { $sets[] = 'diverifikasi_oleh=:v'; $params[':v'] = $currentUser['id']; }
|
||||
if ($status === 'diproses') { $sets[] = 'ditangani_oleh=:t'; $params[':t'] = $currentUser['id']; }
|
||||
if ($status === 'selesai') { $sets[] = 'tanggal_selesai=NOW()'; }
|
||||
if ($catatan) { $sets[] = 'catatan_verifikasi=:c'; $params[':c'] = $catatan; }
|
||||
$pdo->prepare("UPDATE laporan SET ".implode(',',$sets)." WHERE id=:id")->execute($params);
|
||||
logAktivitas($pdo, $currentUser['id'], 'UPDATE', 'laporan', (string)$id, null, ['status'=>$status]);
|
||||
$msg = "Status laporan #$id diperbarui ke '$status'.";
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
}
|
||||
}
|
||||
|
||||
// Ambil laporan
|
||||
$where = [];
|
||||
$params = [];
|
||||
if ($filter === 'pending') { $where[] = "status='pending'"; }
|
||||
if ($filter === 'darurat') { $where[] = "tingkat_urgensi IN ('darurat','tinggi')"; }
|
||||
if ($filter === 'diproses') { $where[] = "status IN ('diverifikasi','diproses')"; }
|
||||
if ($filter === 'selesai') { $where[] = "status='selesai'"; }
|
||||
$whereStr = $where ? 'WHERE '.implode(' AND ',$where) : '';
|
||||
|
||||
$rows = [];
|
||||
try {
|
||||
$rows = $pdo->query("
|
||||
SELECT l.*, p.nama_lengkap AS nama_terdampak, u.nama AS nama_verifikator
|
||||
FROM laporan l
|
||||
LEFT JOIN penduduk p ON p.nik=l.nik_terdampak
|
||||
LEFT JOIN users u ON u.id=l.diverifikasi_oleh
|
||||
$whereStr
|
||||
ORDER BY CASE l.tingkat_urgensi WHEN 'darurat' THEN 1 WHEN 'tinggi' THEN 2 ELSE 3 END,
|
||||
CASE l.status WHEN 'pending' THEN 1 WHEN 'diverifikasi' THEN 2 ELSE 3 END,
|
||||
l.created_at DESC
|
||||
")->fetchAll();
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
|
||||
render_header('Manajemen Laporan');
|
||||
?>
|
||||
|
||||
<div class="page-title">🚩 Laporan Masyarakat</div>
|
||||
|
||||
<?php if ($msg): ?><div class="notice" style="border-color:#bbf7d0;background:#f0fdf4;color:#166534"><?= h($msg) ?></div><?php endif; ?>
|
||||
<?php if ($err): ?><div class="notice" style="border-color:#fecaca;background:#fef2f2;color:#991b1b"><?= h($err) ?></div><?php endif; ?>
|
||||
|
||||
<div style="display:flex;gap:8px;margin-bottom:16px;flex-wrap:wrap">
|
||||
<?php foreach (['semua'=>'Semua','pending'=>'Pending','darurat'=>'🔴 Darurat','diproses'=>'Diproses','selesai'=>'Selesai'] as $k=>$v): ?>
|
||||
<a href="?filter=<?= $k ?>" class="btn <?= $filter===$k?'btn-primary':'btn-secondary' ?>"><?= $v ?></a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th><th>Pelapor</th><th>Terdampak</th><th>Kategori</th>
|
||||
<th>Urgensi</th><th>Status</th><th>Tanggal</th><th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r): ?>
|
||||
<tr>
|
||||
<td><?= $r['id'] ?></td>
|
||||
<td><?= h($r['nama_pelapor'] ?: 'Anonim') ?></td>
|
||||
<td><?= h($r['nama_terdampak'] ?? ($r['nik_terdampak'] ?? '-')) ?></td>
|
||||
<td style="font-size:11px"><?= h(str_replace('_',' ',$r['kategori'])) ?></td>
|
||||
<td><span class="tag <?= $r['tingkat_urgensi']==='darurat'?'darurat':'pending' ?>"><?= h($r['tingkat_urgensi']) ?></span></td>
|
||||
<td><span class="tag <?= $r['status'] ?>"><?= h($r['status']) ?></span></td>
|
||||
<td style="font-size:11px"><?= date('d/m/y H:i', strtotime($r['created_at'])) ?></td>
|
||||
<td>
|
||||
<?php if (in_array($currentUser['role'], ['admin','pengurus'])): ?>
|
||||
<button class="btn btn-secondary btn-sm" onclick="showUpdate(<?= $r['id'] ?>, '<?= h($r['status']) ?>', '<?= addslashes($r['catatan_verifikasi'] ?? '') ?>')">
|
||||
Update
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<button class="btn btn-secondary btn-sm" onclick="showDetail(<?= htmlspecialchars(json_encode($r), ENT_QUOTES) ?>)">Detail</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($rows)): ?>
|
||||
<tr><td colspan="8" style="text-align:center;padding:30px;color:#94a3b8">Tidak ada laporan</td></tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Modal Update Status -->
|
||||
<div id="modal-update" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:999;align-items:center;justify-content:center">
|
||||
<div style="background:#1e293b;border-radius:16px;padding:24px;width:100%;max-width:440px;border:1px solid #334155">
|
||||
<h3 style="margin-bottom:16px">Update Status Laporan #<span id="upd-id"></span></h3>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="lap_id" id="upd-lap-id">
|
||||
<div class="form-group" style="margin-bottom:12px">
|
||||
<label>Status Baru</label>
|
||||
<select name="status" id="upd-status">
|
||||
<option value="diverifikasi">Diverifikasi</option>
|
||||
<option value="diproses">Diproses</option>
|
||||
<option value="selesai">Selesai</option>
|
||||
<option value="ditolak">Ditolak</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom:16px">
|
||||
<label>Catatan</label>
|
||||
<textarea name="catatan" id="upd-catatan" rows="3" placeholder="Catatan verifikasi/tindakan..."></textarea>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;justify-content:flex-end">
|
||||
<button type="button" class="btn btn-secondary" onclick="document.getElementById('modal-update').style.display='none'">Batal</button>
|
||||
<button type="submit" name="update_status" value="1" class="btn btn-primary">Simpan</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Detail -->
|
||||
<div id="modal-detail" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:999;align-items:center;justify-content:center">
|
||||
<div style="background:#1e293b;border-radius:16px;padding:24px;width:100%;max-width:520px;border:1px solid #334155;max-height:80vh;overflow-y:auto">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
|
||||
<h3>Detail Laporan</h3>
|
||||
<button class="btn btn-secondary btn-sm" onclick="document.getElementById('modal-detail').style.display='none'">✕</button>
|
||||
</div>
|
||||
<div id="detail-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function showUpdate(id, status, catatan) {
|
||||
document.getElementById('upd-id').textContent = id;
|
||||
document.getElementById('upd-lap-id').value = id;
|
||||
document.getElementById('upd-status').value = status;
|
||||
document.getElementById('upd-catatan').value = catatan;
|
||||
const m = document.getElementById('modal-update');
|
||||
m.style.display = 'flex';
|
||||
}
|
||||
function showDetail(data) {
|
||||
const m = document.getElementById('modal-detail');
|
||||
document.getElementById('detail-content').innerHTML = `
|
||||
<div style="font-size:13px;display:grid;gap:8px">
|
||||
<div><strong>Pelapor:</strong> ${data.nama_pelapor || 'Anonim'}</div>
|
||||
<div><strong>Terdampak:</strong> ${data.nik_terdampak || '-'}</div>
|
||||
<div><strong>Kategori:</strong> ${data.kategori.replace(/_/g,' ')}</div>
|
||||
<div><strong>Urgensi:</strong> ${data.tingkat_urgensi}</div>
|
||||
<div><strong>Alamat:</strong> ${data.alamat || '-'}</div>
|
||||
<div style="background:#334155;border-radius:8px;padding:10px;margin-top:4px"><strong>Deskripsi:</strong><br>${data.deskripsi}</div>
|
||||
${data.catatan_verifikasi ? `<div><strong>Catatan:</strong> ${data.catatan_verifikasi}</div>` : ''}
|
||||
${data.foto ? `<div><strong>Foto:</strong> <a href="../uploads/foto_laporan/${data.foto}" target="_blank" style="color:#3b82f6">Lihat Foto</a></div>` : ''}
|
||||
</div>
|
||||
`;
|
||||
m.style.display = 'flex';
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin']);
|
||||
|
||||
$rows = $pdo->query("
|
||||
SELECT l.*, u.nama AS nama_user
|
||||
FROM log_aktivitas l
|
||||
LEFT JOIN users u ON u.id=l.user_id
|
||||
ORDER BY l.created_at DESC
|
||||
LIMIT 200
|
||||
")->fetchAll();
|
||||
|
||||
render_header('Log Aktivitas');
|
||||
?>
|
||||
<div class="page-title">📜 Log Aktivitas Sistem</div>
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<table>
|
||||
<thead><tr><th>Waktu</th><th>User</th><th>Aksi</th><th>Tabel</th><th>Record</th><th>IP</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r): ?>
|
||||
<tr>
|
||||
<td style="font-size:11px"><?= date('d/m/y H:i:s', strtotime($r['created_at'])) ?></td>
|
||||
<td><?= h($r['nama_user'] ?? 'Sistem') ?></td>
|
||||
<td><span class="tag <?= $r['aksi']==='DELETE'?'darurat':($r['aksi']==='CREATE'?'selesai':'pending') ?>"><?= h($r['aksi']) ?></span></td>
|
||||
<td style="font-size:11px"><?= h($r['tabel'] ?? '-') ?></td>
|
||||
<td style="font-size:11px"><?= h($r['record_id'] ?? '-') ?></td>
|
||||
<td style="font-size:10px;color:#94a3b8"><?= h($r['ip_address'] ?? '-') ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,89 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Login — WebGIS Pengentasan Kemiskinan</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:'Segoe UI',system-ui,sans-serif;background:#0f172a;color:#f1f5f9;min-height:100vh;display:flex;align-items:center;justify-content:center;padding:16px}
|
||||
.card{background:#1e293b;border:1px solid #334155;border-radius:20px;padding:40px 36px;width:100%;max-width:400px;box-shadow:0 25px 60px rgba(0,0,0,.5)}
|
||||
.logo{text-align:center;margin-bottom:28px}
|
||||
.logo .icon{font-size:40px;margin-bottom:8px}
|
||||
.logo h1{font-size:20px;font-weight:900}
|
||||
.logo p{font-size:12px;color:#94a3b8;margin-top:4px}
|
||||
.form-group{margin-bottom:16px}
|
||||
label{display:block;font-size:11px;font-weight:700;color:#94a3b8;text-transform:uppercase;margin-bottom:6px}
|
||||
input{width:100%;background:#0f172a;border:1px solid #334155;color:#f1f5f9;padding:11px 14px;border-radius:10px;font-size:14px}
|
||||
input:focus{outline:none;border-color:#3b82f6}
|
||||
.btn{width:100%;background:#3b82f6;color:#fff;border:none;padding:12px;border-radius:10px;font-size:14px;font-weight:800;cursor:pointer;transition:.2s}
|
||||
.btn:hover{background:#2563eb}
|
||||
.error{background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.3);color:#ef4444;padding:10px 14px;border-radius:8px;font-size:13px;margin-bottom:16px;display:none}
|
||||
.roles{margin-top:20px;background:#0f172a;border-radius:10px;padding:14px}
|
||||
.roles h4{font-size:11px;font-weight:900;color:#94a3b8;margin-bottom:10px;text-transform:uppercase}
|
||||
.role-row{display:flex;justify-content:space-between;font-size:12px;margin-bottom:6px;padding:6px 0;border-bottom:1px solid #1e293b}
|
||||
.role-row:last-child{border:none;margin:0}
|
||||
.role-badge{background:#334155;padding:2px 8px;border-radius:99px;font-size:10px;font-weight:700}
|
||||
.back{text-align:center;margin-top:16px}
|
||||
.back a{color:#3b82f6;font-size:13px;text-decoration:none}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
require_once __DIR__ . '/../php/koneksi.php';
|
||||
require_once __DIR__ . '/../php/middleware/auth.php';
|
||||
|
||||
$error = '';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$result = doLogin($pdo, $_POST['username'] ?? '', $_POST['password'] ?? '');
|
||||
if ($result['success']) {
|
||||
$redirect = [
|
||||
'admin' => 'index.php',
|
||||
'pengurus' => 'index.php',
|
||||
'pimpinan' => 'index.php',
|
||||
'masyarakat' => '../index.html',
|
||||
];
|
||||
header('Location: ' . ($redirect[$result['role']] ?? 'index.php'));
|
||||
exit;
|
||||
}
|
||||
$error = $result['message'];
|
||||
}
|
||||
?>
|
||||
<div class="card">
|
||||
<div class="logo">
|
||||
<div class="icon">🗺️</div>
|
||||
<h1>WebGIS Kemiskinan</h1>
|
||||
<p>Berbasis Masyarakat & Rumah Ibadah</p>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="error" style="display:block"><?= h($error) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<input type="text" name="username" placeholder="Masukkan username" required autofocus value="<?= h($_POST['username'] ?? '') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<input type="password" name="password" placeholder="Masukkan password" required>
|
||||
</div>
|
||||
<div class="form-group" style="text-align:right; margin-top:-8px; margin-bottom:16px;">
|
||||
<a href="forgot.php" style="color:#3b82f6; font-size:11px; text-decoration:none; font-weight:700;">Lupa Password?</a>
|
||||
</div>
|
||||
<button type="submit" class="btn">🔐 Masuk</button>
|
||||
</form>
|
||||
|
||||
<div class="roles">
|
||||
<h4>Akun Demo (password: password)</h4>
|
||||
<div class="role-row"><span>admin</span><span class="role-badge">Administrator</span></div>
|
||||
<div class="role-row"><span>pengurus1</span><span class="role-badge">Pengurus Masjid</span></div>
|
||||
<div class="role-row"><span>pimpinan1</span><span class="role-badge">Pimpinan Daerah</span></div>
|
||||
<div class="role-row"><span>warga1</span><span class="role-badge">Masyarakat</span></div>
|
||||
</div>
|
||||
|
||||
<div class="back"><a href="../../index.html">← Kembali ke Landing Page</a></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../php/koneksi.php';
|
||||
require_once __DIR__ . '/../php/middleware/auth.php';
|
||||
doLogout($pdo);
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
@@ -0,0 +1,297 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin','pengurus','pimpinan']);
|
||||
|
||||
$role = $_SESSION['role'];
|
||||
$canEdit = in_array($role, ['admin','pengurus']);
|
||||
|
||||
$msg = ''; $err = '';
|
||||
|
||||
// DELETE
|
||||
if ($canEdit && isset($_GET['delete'])) {
|
||||
$nik = $_GET['delete'];
|
||||
try {
|
||||
$pdo->prepare("DELETE FROM penduduk WHERE nik=:nik")->execute([':nik'=>$nik]);
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'DELETE', 'penduduk', $nik);
|
||||
$msg = "Penduduk NIK $nik dihapus.";
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
}
|
||||
|
||||
// SAVE
|
||||
if ($canEdit && isset($_POST['save'])) {
|
||||
$nik = trim($_POST['nik'] ?? '');
|
||||
$nama = trim($_POST['nama_lengkap'] ?? '');
|
||||
$tgl = $_POST['tanggal_lahir'] ?? '';
|
||||
$nikEdit = $_POST['nik_edit'] ?? '';
|
||||
|
||||
if (!preg_match('/^\d{16}$/', $nik)) $err = 'NIK harus 16 digit.';
|
||||
elseif (strlen($nama) < 3) $err = 'Nama terlalu pendek.';
|
||||
else {
|
||||
try {
|
||||
$data = [
|
||||
':kk'=>$_POST['id_keluarga']?:(null),
|
||||
':nama'=>$nama, ':jk'=>$_POST['jenis_kelamin']??'L',
|
||||
':tgl'=>$tgl, ':sk'=>$_POST['status_keluarga']??'anggota_lain',
|
||||
':sp'=>$_POST['status_perkawinan']??'belum_kawin',
|
||||
':sh'=>$_POST['status_hidup']??'hidup',
|
||||
':ptk'=>$_POST['pendidikan_terakhir']??'tidak_sekolah',
|
||||
':spd'=>$_POST['status_pendidikan']??'tidak_sekolah',
|
||||
':pkr'=>$_POST['pekerjaan']??'' ?: null,
|
||||
':pgn'=>(float)($_POST['penghasilan']??0),
|
||||
':se'=>$_POST['status_ekonomi']??'rentan',
|
||||
':kkh'=>$_POST['kondisi_kesehatan']??'sehat',
|
||||
':ckkh'=>$_POST['catatan_kesehatan']??'' ?: null,
|
||||
':tlp'=>$_POST['no_telp']??'' ?: null,
|
||||
':almt'=>$_POST['alamat']??'' ?: null,
|
||||
':lat'=>$_POST['latitude']??'' ?: null,
|
||||
':lng'=>$_POST['longitude']??'' ?: null,
|
||||
];
|
||||
if ($nikEdit) {
|
||||
$data[':nik'] = $nikEdit;
|
||||
$pdo->prepare("UPDATE penduduk SET id_keluarga=:kk,nama_lengkap=:nama,jenis_kelamin=:jk,tanggal_lahir=:tgl,
|
||||
status_keluarga=:sk,status_perkawinan=:sp,status_hidup=:sh,pendidikan_terakhir=:ptk,status_pendidikan=:spd,
|
||||
pekerjaan=:pkr,penghasilan=:pgn,status_ekonomi=:se,kondisi_kesehatan=:kkh,catatan_kesehatan=:ckkh,
|
||||
no_telp=:tlp,alamat=:almt,latitude=:lat,longitude=:lng WHERE nik=:nik")->execute($data);
|
||||
$msg = "Data penduduk $nama diperbarui.";
|
||||
} else {
|
||||
$data[':nik'] = $nik;
|
||||
$pdo->prepare("INSERT INTO penduduk (nik,id_keluarga,nama_lengkap,jenis_kelamin,tanggal_lahir,
|
||||
status_keluarga,status_perkawinan,status_hidup,pendidikan_terakhir,status_pendidikan,
|
||||
pekerjaan,penghasilan,status_ekonomi,kondisi_kesehatan,catatan_kesehatan,no_telp,alamat,latitude,longitude)
|
||||
VALUES(:nik,:kk,:nama,:jk,:tgl,:sk,:sp,:sh,:ptk,:spd,:pkr,:pgn,:se,:kkh,:ckkh,:tlp,:almt,:lat,:lng)")->execute($data);
|
||||
$msg = "Penduduk $nama berhasil ditambahkan.";
|
||||
}
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], $nikEdit?'UPDATE':'CREATE', 'penduduk', $nik);
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
}
|
||||
}
|
||||
|
||||
$edit = null;
|
||||
if (isset($_GET['edit'])) {
|
||||
$stmt = $pdo->prepare("SELECT * FROM penduduk WHERE nik=:nik");
|
||||
$stmt->execute([':nik'=>$_GET['edit']]);
|
||||
$edit = $stmt->fetch() ?: null;
|
||||
}
|
||||
|
||||
// List penduduk
|
||||
$search = trim($_GET['s'] ?? '');
|
||||
$se = $_GET['se'] ?? '';
|
||||
$where = []; $params = [];
|
||||
if ($search) { $where[] = '(p.nama_lengkap LIKE :q OR p.nik LIKE :q2)'; $params[':q']='%'.$search.'%'; $params[':q2']='%'.$search.'%'; }
|
||||
if ($se) { $where[] = 'p.status_ekonomi=:se'; $params[':se']=$se; }
|
||||
$whereStr = $where ? 'WHERE '.implode(' AND ',$where) : '';
|
||||
|
||||
$rows = $pdo->prepare("
|
||||
SELECT p.nik,p.nama_lengkap,p.umur,p.jenis_kelamin,p.status_ekonomi,p.kondisi_kesehatan,
|
||||
p.pekerjaan,p.status_hidup,k.no_kk,ri.nama AS nama_ri,
|
||||
(SELECT COUNT(*) FROM histori_bantuan hb WHERE hb.nik=p.nik AND hb.status_penyaluran='disalurkan') AS jml_bantuan
|
||||
FROM penduduk p
|
||||
LEFT JOIN keluarga k ON k.id=p.id_keluarga
|
||||
LEFT JOIN rumah_ibadah ri ON ri.id=k.rumah_ibadah_id
|
||||
$whereStr
|
||||
ORDER BY CASE p.status_ekonomi WHEN 'miskin' THEN 1 WHEN 'rentan' THEN 2 ELSE 3 END, p.nama_lengkap
|
||||
LIMIT 300
|
||||
");
|
||||
$rows->execute($params);
|
||||
$rows = $rows->fetchAll();
|
||||
|
||||
// Keluarga untuk dropdown
|
||||
$kkList = $pdo->query("SELECT id, no_kk, nama_kk FROM keluarga ORDER BY nama_kk")->fetchAll();
|
||||
|
||||
render_header('Manajemen Penduduk');
|
||||
?>
|
||||
<div class="page-title">👥 Manajemen Penduduk</div>
|
||||
|
||||
<?php if ($msg): ?><div class="notice" style="border-color:#bbf7d0;background:#f0fdf4;color:#166534"><?= h($msg) ?></div><?php endif; ?>
|
||||
<?php if ($err): ?><div class="notice" style="border-color:#fecaca;background:#fef2f2;color:#991b1b"><?= h($err) ?></div><?php endif; ?>
|
||||
|
||||
<?php if ($canEdit): ?>
|
||||
<!-- FORM -->
|
||||
<div class="card">
|
||||
<strong><?= $edit ? '✏️ Edit: '.h($edit['nama_lengkap']) : '➕ Tambah Penduduk' ?></strong>
|
||||
<form method="POST" style="margin-top:14px">
|
||||
<input type="hidden" name="nik_edit" value="<?= h($edit['nik']??'') ?>">
|
||||
<div class="form-grid">
|
||||
<div class="form-group">
|
||||
<label>NIK *</label>
|
||||
<input name="nik" maxlength="16" required value="<?= h($edit['nik']??'') ?>" <?= $edit?'readonly':'' ?>>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Keluarga (KK)</label>
|
||||
<select name="id_keluarga">
|
||||
<option value="">— Pilih KK —</option>
|
||||
<?php foreach ($kkList as $kk): ?>
|
||||
<option value="<?= $kk['id'] ?>" <?= ($edit['id_keluarga']??'')==$kk['id']?'selected':'' ?>><?= h($kk['no_kk'].' — '.$kk['nama_kk']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label>Nama Lengkap *</label>
|
||||
<input name="nama_lengkap" required value="<?= h($edit['nama_lengkap']??'') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Jenis Kelamin</label>
|
||||
<select name="jenis_kelamin">
|
||||
<option value="L" <?= ($edit['jenis_kelamin']??'L')==='L'?'selected':'' ?>>Laki-laki</option>
|
||||
<option value="P" <?= ($edit['jenis_kelamin']??'')==='P'?'selected':'' ?>>Perempuan</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Tanggal Lahir *</label>
|
||||
<input type="date" name="tanggal_lahir" required value="<?= h($edit['tanggal_lahir']??'') ?>" onchange="hitungUmur(this)">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Status Keluarga</label>
|
||||
<select name="status_keluarga">
|
||||
<?php foreach (['kepala_keluarga'=>'Kepala Keluarga','istri'=>'Istri','anak'=>'Anak','menantu'=>'Menantu','orang_tua'=>'Orang Tua','anggota_lain'=>'Anggota Lain'] as $v=>$l): ?>
|
||||
<option value="<?= $v ?>" <?= ($edit['status_keluarga']??'')===$v?'selected':'' ?>><?= $l ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Status Perkawinan</label>
|
||||
<select name="status_perkawinan">
|
||||
<?php foreach (['belum_kawin'=>'Belum Kawin','kawin'=>'Kawin','cerai_hidup'=>'Cerai Hidup','cerai_mati'=>'Cerai Mati'] as $v=>$l): ?>
|
||||
<option value="<?= $v ?>" <?= ($edit['status_perkawinan']??'')===$v?'selected':'' ?>><?= $l ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Status Hidup</label>
|
||||
<select name="status_hidup">
|
||||
<option value="hidup" <?= ($edit['status_hidup']??'hidup')==='hidup'?'selected':'' ?>>Hidup</option>
|
||||
<option value="meninggal" <?= ($edit['status_hidup']??'')==='meninggal'?'selected':'' ?>>Meninggal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Pendidikan Terakhir</label>
|
||||
<select name="pendidikan_terakhir" onchange="cekPendidikan()">
|
||||
<?php foreach (['tidak_sekolah','SD','SMP','SMA','SMK','D3','S1','S2','S3'] as $v): ?>
|
||||
<option value="<?= $v ?>" <?= ($edit['pendidikan_terakhir']??'')===$v?'selected':'' ?>><?= $v ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Status Pendidikan</label>
|
||||
<select name="status_pendidikan" id="status_pendidikan" onchange="cekPendidikan()">
|
||||
<option value="sekolah" <?= ($edit['status_pendidikan']??'')==='sekolah'?'selected':'' ?>>Masih Sekolah</option>
|
||||
<option value="tidak_sekolah" <?= ($edit['status_pendidikan']??'')==='tidak_sekolah'?'selected':'' ?>>Tidak Sekolah</option>
|
||||
<option value="lulus" <?= ($edit['status_pendidikan']??'')==='lulus'?'selected':'' ?>>Lulus</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Status Ekonomi</label>
|
||||
<select name="status_ekonomi">
|
||||
<option value="miskin" <?= ($edit['status_ekonomi']??'')==='miskin'?'selected':'' ?>>Miskin</option>
|
||||
<option value="rentan" <?= ($edit['status_ekonomi']??'rentan')==='rentan'?'selected':'' ?>>Rentan</option>
|
||||
<option value="mampu" <?= ($edit['status_ekonomi']??'')==='mampu'?'selected':'' ?>>Mampu</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Kondisi Kesehatan</label>
|
||||
<select name="kondisi_kesehatan">
|
||||
<?php foreach (['sehat'=>'Sehat','sakit_ringan'=>'Sakit Ringan','sakit_parah'=>'Sakit Parah','disabilitas'=>'Disabilitas'] as $v=>$l): ?>
|
||||
<option value="<?= $v ?>" <?= ($edit['kondisi_kesehatan']??'sehat')===$v?'selected':'' ?>><?= $l ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Pekerjaan</label>
|
||||
<input name="pekerjaan" value="<?= h($edit['pekerjaan']??'') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Penghasilan / Bulan (Rp)</label>
|
||||
<input type="number" name="penghasilan" value="<?= h($edit['penghasilan']??0) ?>">
|
||||
</div>
|
||||
<div class="form-group full">
|
||||
<label>Alamat</label>
|
||||
<input name="alamat" value="<?= h($edit['alamat']??'') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Latitude</label>
|
||||
<input name="latitude" value="<?= h($edit['latitude']??'') ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Longitude</label>
|
||||
<input name="longitude" value="<?= h($edit['longitude']??'') ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div id="pendidikan-warn" style="display:none;background:rgba(245,158,11,.1);border:1px solid rgba(245,158,11,.3);border-radius:8px;padding:8px 12px;font-size:12px;color:#f59e0b;margin-top:10px"></div>
|
||||
<div style="display:flex;gap:8px;margin-top:14px">
|
||||
<button type="submit" name="save" value="1" class="btn btn-primary">💾 <?= $edit ? 'Update' : 'Simpan' ?></button>
|
||||
<?php if ($edit): ?><a href="penduduk.php" class="btn btn-secondary">Batal</a><?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- TABEL -->
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<div style="padding:14px 16px;display:flex;gap:10px;align-items:center;flex-wrap:wrap;border-bottom:1px solid var(--brd)">
|
||||
<form method="GET" style="display:flex;gap:8px;flex:1;min-width:200px">
|
||||
<input name="s" placeholder="Cari nama / NIK..." value="<?= h($search) ?>" style="flex:1">
|
||||
<select name="se" style="width:120px">
|
||||
<option value="">Semua Status</option>
|
||||
<option value="miskin" <?= $se==='miskin'?'selected':'' ?>>Miskin</option>
|
||||
<option value="rentan" <?= $se==='rentan'?'selected':'' ?>>Rentan</option>
|
||||
<option value="mampu" <?= $se==='mampu'?'selected':'' ?>>Mampu</option>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-secondary">Cari</button>
|
||||
<a href="penduduk.php" class="btn btn-secondary">Reset</a>
|
||||
</form>
|
||||
<span style="font-size:12px;color:#94a3b8"><?= count($rows) ?> data</span>
|
||||
</div>
|
||||
<table>
|
||||
<thead><tr><th>NIK</th><th>Nama</th><th>Umur/JK</th><th>Status Ekonomi</th><th>Kesehatan</th><th>Bantuan</th><th>Rumah Ibadah</th><?php if($canEdit): ?><th>Aksi</th><?php endif; ?></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r): ?>
|
||||
<tr>
|
||||
<td style="font-size:11px"><?= h($r['nik']) ?></td>
|
||||
<td><strong><?= h($r['nama_lengkap']) ?></strong><?= $r['status_hidup']==='meninggal'?'<br><span style="font-size:10px;color:#ef4444">†meninggal</span>':'' ?></td>
|
||||
<td><?= $r['umur'] ?>th / <?= $r['jenis_kelamin']==='L'?'♂':'♀' ?></td>
|
||||
<td><span class="tag <?= $r['status_ekonomi'] ?>"><?= h($r['status_ekonomi']) ?></span></td>
|
||||
<td style="font-size:11px"><?= h(str_replace('_',' ',$r['kondisi_kesehatan'])) ?></td>
|
||||
<td><?= $r['jml_bantuan'] > 0 ? "<span style='color:#22c55e'>✅ {$r['jml_bantuan']}x</span>" : "<span style='color:#ef4444'>⚠️ Belum</span>" ?></td>
|
||||
<td style="font-size:11px"><?= h($r['nama_ri'] ?? '-') ?></td>
|
||||
<?php if($canEdit): ?>
|
||||
<td class="actions">
|
||||
<a href="penduduk.php?edit=<?= h($r['nik']) ?>" class="btn btn-secondary btn-sm">Edit</a>
|
||||
<a href="bantuan.php?nik=<?= h($r['nik']) ?>&nama=<?= urlencode($r['nama_lengkap']) ?>" class="btn btn-success btn-sm">Bantu</a>
|
||||
<?php if ($_SESSION['role']==='admin'): ?>
|
||||
<a href="penduduk.php?delete=<?= h($r['nik']) ?>" class="btn btn-danger btn-sm" onclick="return confirm('Hapus <?= h(addslashes($r['nama_lengkap'])) ?>?')">Hapus</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($rows)): ?><tr><td colspan="8" style="text-align:center;padding:24px;color:#94a3b8">Tidak ada data</td></tr><?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function hitungUmur(el) {
|
||||
const tgl = el.value;
|
||||
if (!tgl) return;
|
||||
const umur = Math.floor((new Date() - new Date(tgl)) / (365.25*24*3600*1000));
|
||||
cekPendidikanUmur(umur);
|
||||
}
|
||||
function cekPendidikan() {
|
||||
const tgl = document.querySelector('[name=tanggal_lahir]').value;
|
||||
if (!tgl) return;
|
||||
const umur = Math.floor((new Date() - new Date(tgl)) / (365.25*24*3600*1000));
|
||||
cekPendidikanUmur(umur);
|
||||
}
|
||||
function cekPendidikanUmur(umur) {
|
||||
const status = document.getElementById('status_pendidikan').value;
|
||||
const warn = document.getElementById('pendidikan-warn');
|
||||
let msg = '';
|
||||
if (umur>=7&&umur<=12&&status!=='sekolah') msg = `⚠️ Anak usia ${umur} tahun seharusnya masih sekolah SD.`;
|
||||
if (umur>=13&&umur<=15&&status!=='sekolah') msg = `⚠️ Anak usia ${umur} tahun seharusnya masih sekolah SMP.`;
|
||||
if (umur>=16&&umur<=18&&status!=='sekolah') msg = `⚠️ Anak usia ${umur} tahun seharusnya masih sekolah SMA/SMK.`;
|
||||
warn.style.display = msg ? 'block' : 'none';
|
||||
warn.textContent = msg;
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin','pengurus','pimpinan']);
|
||||
|
||||
$role = $_SESSION['role'];
|
||||
$canEdit = in_array($role, ['admin','pengurus']);
|
||||
$msg = ''; $err = '';
|
||||
|
||||
// DELETE
|
||||
if ($canEdit && isset($_GET['delete'])) {
|
||||
$id = (int)$_GET['delete'];
|
||||
try {
|
||||
$pdo->prepare("DELETE FROM rumah_ibadah WHERE id=:id")->execute([':id'=>$id]);
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'DELETE', 'rumah_ibadah', (string)$id);
|
||||
$msg = "Rumah ibadah #$id dihapus.";
|
||||
} catch(Exception $e) { $err = 'Gagal hapus: '.$e->getMessage(); }
|
||||
}
|
||||
|
||||
// SAVE
|
||||
if ($canEdit && isset($_POST['save'])) {
|
||||
$nama = trim($_POST['nama'] ?? '');
|
||||
$lat = $_POST['latitude'] ?? '';
|
||||
$lng = $_POST['longitude'] ?? '';
|
||||
$idEdit = (int)($_POST['id_edit'] ?? 0);
|
||||
if (strlen($nama) < 3) $err = 'Nama terlalu pendek.';
|
||||
elseif (!is_numeric($lat) || !is_numeric($lng)) $err = 'Latitude/Longitude tidak valid.';
|
||||
else {
|
||||
try {
|
||||
$data = [
|
||||
':nama' => $nama,
|
||||
':jenis' => $_POST['jenis']??'Lainnya',
|
||||
':kontak'=> $_POST['kontak']??'' ?: null,
|
||||
':rad' => (float)($_POST['radius_meter']??300),
|
||||
':lat' => (float)$lat, ':lng' => (float)$lng,
|
||||
':almt' => $_POST['alamat']??'' ?: null,
|
||||
':kel' => $_POST['kelurahan']??'' ?: null,
|
||||
':kec' => $_POST['kecamatan']??'' ?: null,
|
||||
':kota' => $_POST['kota']??'' ?: null,
|
||||
':desk' => $_POST['deskripsi']??'' ?: null,
|
||||
];
|
||||
if ($idEdit) {
|
||||
$data[':id'] = $idEdit;
|
||||
$pdo->prepare("UPDATE rumah_ibadah SET nama=:nama,jenis=:jenis,kontak=:kontak,radius_meter=:rad,
|
||||
latitude=:lat,longitude=:lng,alamat=:almt,kelurahan=:kel,kecamatan=:kec,kota=:kota,deskripsi=:desk
|
||||
WHERE id=:id")->execute($data);
|
||||
$msg = "$nama diperbarui.";
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'UPDATE', 'rumah_ibadah', (string)$idEdit);
|
||||
} else {
|
||||
$pdo->prepare("INSERT INTO rumah_ibadah (nama,jenis,kontak,radius_meter,latitude,longitude,alamat,kelurahan,kecamatan,kota,deskripsi)
|
||||
VALUES(:nama,:jenis,:kontak,:rad,:lat,:lng,:almt,:kel,:kec,:kota,:desk)")->execute($data);
|
||||
$msg = "$nama berhasil ditambahkan.";
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'CREATE', 'rumah_ibadah', (string)$pdo->lastInsertId());
|
||||
}
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
}
|
||||
}
|
||||
|
||||
$edit = null;
|
||||
if (isset($_GET['edit'])) {
|
||||
$s = $pdo->prepare("SELECT * FROM rumah_ibadah WHERE id=:id");
|
||||
$s->execute([':id'=>(int)$_GET['edit']]);
|
||||
$edit = $s->fetch() ?: null;
|
||||
}
|
||||
|
||||
$rows = $pdo->query("
|
||||
SELECT ri.*,
|
||||
(SELECT COUNT(*) FROM keluarga k WHERE k.rumah_ibadah_id=ri.id) AS jml_kk
|
||||
FROM rumah_ibadah ri ORDER BY ri.nama
|
||||
")->fetchAll();
|
||||
|
||||
$jenisOpts = ['Masjid','Musholla','Gereja Protestan','Gereja Katolik','Pura','Vihara','Klenteng','Lainnya'];
|
||||
|
||||
render_header('Rumah Ibadah');
|
||||
?>
|
||||
<div class="page-title">🕌 Data Rumah Ibadah</div>
|
||||
|
||||
<?php if ($msg): ?><div class="notice" style="border-color:#bbf7d0;background:#f0fdf4;color:#166534"><?= h($msg) ?></div><?php endif; ?>
|
||||
<?php if ($err): ?><div class="notice" style="border-color:#fecaca;background:#fef2f2;color:#991b1b"><?= h($err) ?></div><?php endif; ?>
|
||||
|
||||
<div style="display:grid;grid-template-columns:<?= $canEdit ? '1fr 1.5fr' : '1fr' ?>;gap:16px">
|
||||
<?php if ($canEdit): ?>
|
||||
<div class="card">
|
||||
<strong><?= $edit ? '✏️ Edit' : '➕ Tambah Rumah Ibadah' ?></strong><br><br>
|
||||
<form method="POST">
|
||||
<?php if ($edit): ?><input type="hidden" name="id_edit" value="<?= $edit['id'] ?>"><?php endif; ?>
|
||||
<div class="form-grid">
|
||||
<div class="form-group full"><label>Nama *</label>
|
||||
<input name="nama" required value="<?= h($edit['nama'] ?? '') ?>"></div>
|
||||
<div class="form-group"><label>Jenis</label>
|
||||
<select name="jenis">
|
||||
<?php foreach ($jenisOpts as $j): ?>
|
||||
<option value="<?= $j ?>" <?= ($edit['jenis']??'Lainnya')===$j?'selected':'' ?>><?= $j ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select></div>
|
||||
<div class="form-group"><label>Kontak / No Telp</label>
|
||||
<input name="kontak" value="<?= h($edit['kontak'] ?? '') ?>"></div>
|
||||
<div class="form-group"><label>Radius Layanan (meter)</label>
|
||||
<input name="radius_meter" type="number" min="50" max="5000" value="<?= $edit['radius_meter'] ?? 300 ?>"></div>
|
||||
<div class="form-group"><label>Latitude *</label>
|
||||
<input name="latitude" type="number" step="any" required value="<?= $edit['latitude'] ?? '' ?>"></div>
|
||||
<div class="form-group"><label>Longitude *</label>
|
||||
<input name="longitude" type="number" step="any" required value="<?= $edit['longitude'] ?? '' ?>"></div>
|
||||
<div class="form-group full"><label>Alamat</label>
|
||||
<textarea name="alamat" rows="2"><?= h($edit['alamat'] ?? '') ?></textarea></div>
|
||||
<div class="form-group"><label>Kelurahan</label>
|
||||
<input name="kelurahan" value="<?= h($edit['kelurahan'] ?? '') ?>"></div>
|
||||
<div class="form-group"><label>Kecamatan</label>
|
||||
<input name="kecamatan" value="<?= h($edit['kecamatan'] ?? '') ?>"></div>
|
||||
</div>
|
||||
<br>
|
||||
<button type="submit" name="save" class="btn btn-primary"><?= $edit ? '💾 Update' : '➕ Simpan' ?></button>
|
||||
<?php if ($edit): ?><a href="rumah_ibadah.php" class="btn btn-secondary">Batal</a><?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<table>
|
||||
<thead><tr><th>Nama</th><th>Jenis</th><th>Alamat</th><th>Radius</th><th>KK</th><?= $canEdit?'<th>Aksi</th>':'' ?></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r): ?>
|
||||
<tr>
|
||||
<td><strong><?= h($r['nama']) ?></strong><br><span style="font-size:10px;color:#94a3b8"><?= h($r['kontak']??'') ?></span></td>
|
||||
<td style="font-size:12px"><?= h($r['jenis']) ?></td>
|
||||
<td style="font-size:11px"><?= h($r['kelurahan']??'') ?><?= $r['kecamatan'] ? ', '.$r['kecamatan'] : '' ?></td>
|
||||
<td><?= $r['radius_meter'] ?>m</td>
|
||||
<td><?= $r['jml_kk'] ?> KK</td>
|
||||
<?php if ($canEdit): ?>
|
||||
<td class="actions">
|
||||
<a href="?edit=<?= $r['id'] ?>" class="btn btn-secondary btn-sm">✏️</a>
|
||||
<a href="?delete=<?= $r['id'] ?>" class="btn btn-danger btn-sm" onclick="return confirm('Hapus rumah ibadah ini?')">🗑️</a>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($rows)): ?><tr><td colspan="6" style="text-align:center;padding:24px;color:#94a3b8">Belum ada data</td></tr><?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php render_footer(); ?>
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/_layout.php';
|
||||
require_login(['admin']);
|
||||
|
||||
$msg = ''; $err = '';
|
||||
|
||||
// TOGGLE AKTIF
|
||||
if (isset($_GET['toggle'])) {
|
||||
$id = (int)$_GET['toggle'];
|
||||
if ($id !== (int)$_SESSION['user_id']) {
|
||||
try {
|
||||
$pdo->prepare("UPDATE users SET aktif = 1 - aktif WHERE id=:id")->execute([':id'=>$id]);
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'UPDATE', 'users', (string)$id);
|
||||
$msg = "Status user #$id diperbarui.";
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
} else { $err = 'Tidak dapat mengubah status akun sendiri.'; }
|
||||
}
|
||||
|
||||
// RESET PASSWORD
|
||||
if (isset($_POST['reset_pw'])) {
|
||||
$id = (int)($_POST['user_id'] ?? 0);
|
||||
$pw = $_POST['new_password'] ?? '';
|
||||
if (strlen($pw) < 6) $err = 'Password minimal 6 karakter.';
|
||||
else {
|
||||
$hash = password_hash($pw, PASSWORD_BCRYPT);
|
||||
$pdo->prepare("UPDATE users SET password_hash=:h WHERE id=:id")->execute([':h'=>$hash,':id'=>$id]);
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'UPDATE', 'users', (string)$id, null, ['action'=>'reset_password']);
|
||||
$msg = "Password user #$id berhasil direset.";
|
||||
}
|
||||
}
|
||||
|
||||
// SAVE USER BARU
|
||||
if (isset($_POST['save'])) {
|
||||
$uname = trim($_POST['username'] ?? '');
|
||||
$nama = trim($_POST['nama'] ?? '');
|
||||
$pw = $_POST['password'] ?? '';
|
||||
$idEdit = (int)($_POST['id_edit'] ?? 0);
|
||||
if (strlen($uname) < 3) $err = 'Username minimal 3 karakter.';
|
||||
elseif (strlen($nama) < 3) $err = 'Nama minimal 3 karakter.';
|
||||
elseif (!$idEdit && strlen($pw) < 6) $err = 'Password minimal 6 karakter.';
|
||||
else {
|
||||
try {
|
||||
if ($idEdit) {
|
||||
$pdo->prepare("UPDATE users SET nama=:nama,role_id=:rid,email=:em,no_telp=:tlp,rumah_ibadah_id=:ri WHERE id=:id")
|
||||
->execute([':nama'=>$nama,':rid'=>(int)$_POST['role_id'],':em'=>$_POST['email']??'' ?: null,
|
||||
':tlp'=>$_POST['no_telp']??'' ?: null,':ri'=>$_POST['rumah_ibadah_id']??'' ?: null,':id'=>$idEdit]);
|
||||
$msg = "User $nama diperbarui.";
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'UPDATE', 'users', (string)$idEdit);
|
||||
} else {
|
||||
$hash = password_hash($pw, PASSWORD_BCRYPT);
|
||||
$pdo->prepare("INSERT INTO users (role_id,nama,username,email,password_hash,no_telp,rumah_ibadah_id)
|
||||
VALUES(:rid,:nama,:uname,:em,:hash,:tlp,:ri)")
|
||||
->execute([':rid'=>(int)$_POST['role_id'],':nama'=>$nama,':uname'=>$uname,
|
||||
':em'=>$_POST['email']??'' ?: null,':hash'=>$hash,
|
||||
':tlp'=>$_POST['no_telp']??'' ?: null,':ri'=>$_POST['rumah_ibadah_id']??'' ?: null]);
|
||||
$msg = "User $uname berhasil dibuat.";
|
||||
logAktivitas($pdo, (int)$_SESSION['user_id'], 'CREATE', 'users', (string)$pdo->lastInsertId());
|
||||
}
|
||||
} catch(Exception $e) { $err = $e->getMessage(); }
|
||||
}
|
||||
}
|
||||
|
||||
$edit = null;
|
||||
if (isset($_GET['edit'])) {
|
||||
$s = $pdo->prepare("SELECT * FROM users WHERE id=:id");
|
||||
$s->execute([':id'=>(int)$_GET['edit']]);
|
||||
$edit = $s->fetch() ?: null;
|
||||
}
|
||||
|
||||
$rows = $pdo->query("
|
||||
SELECT u.*, r.nama AS role_nama, ri.nama AS nama_ri
|
||||
FROM users u
|
||||
JOIN roles r ON r.id=u.role_id
|
||||
LEFT JOIN rumah_ibadah ri ON ri.id=u.rumah_ibadah_id
|
||||
ORDER BY u.role_id, u.nama
|
||||
")->fetchAll();
|
||||
|
||||
$roles = $pdo->query("SELECT * FROM roles ORDER BY id")->fetchAll();
|
||||
$riList = $pdo->query("SELECT id,nama FROM rumah_ibadah ORDER BY nama")->fetchAll();
|
||||
|
||||
render_header('Manajemen User');
|
||||
?>
|
||||
<div class="page-title">👥 Manajemen User</div>
|
||||
|
||||
<?php if ($msg): ?><div class="notice" style="border-color:#bbf7d0;background:#f0fdf4;color:#166534"><?= h($msg) ?></div><?php endif; ?>
|
||||
<?php if ($err): ?><div class="notice" style="border-color:#fecaca;background:#fef2f2;color:#991b1b"><?= h($err) ?></div><?php endif; ?>
|
||||
|
||||
<div style="display:grid;grid-template-columns:1fr 1.8fr;gap:16px">
|
||||
<div>
|
||||
<div class="card">
|
||||
<strong><?= $edit ? '✏️ Edit User' : '➕ Tambah User' ?></strong><br><br>
|
||||
<form method="POST">
|
||||
<?php if ($edit): ?><input type="hidden" name="id_edit" value="<?= $edit['id'] ?>"><?php endif; ?>
|
||||
<div class="form-group" style="margin-bottom:10px"><label>Username <?= $edit ? '' : '*' ?></label>
|
||||
<input name="username" <?= $edit ? 'disabled value="'.h($edit['username'] ?? '').'"' : 'required' ?>></div>
|
||||
<div class="form-group" style="margin-bottom:10px"><label>Nama Lengkap *</label>
|
||||
<input name="nama" required value="<?= h($edit['nama'] ?? '') ?>"></div>
|
||||
<?php if (!$edit): ?>
|
||||
<div class="form-group" style="margin-bottom:10px"><label>Password * (min 6 karakter)</label>
|
||||
<input name="password" type="password" required minlength="6"></div>
|
||||
<?php endif; ?>
|
||||
<div class="form-group" style="margin-bottom:10px"><label>Role</label>
|
||||
<select name="role_id">
|
||||
<?php foreach ($roles as $r): ?>
|
||||
<option value="<?= $r['id'] ?>" <?= ($edit['role_id']??4)==$r['id']?'selected':'' ?>><?= h($r['label']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select></div>
|
||||
<div class="form-group" style="margin-bottom:10px"><label>Email</label>
|
||||
<input name="email" type="email" value="<?= h($edit['email'] ?? '') ?>"></div>
|
||||
<div class="form-group" style="margin-bottom:10px"><label>No Telp</label>
|
||||
<input name="no_telp" value="<?= h($edit['no_telp'] ?? '') ?>"></div>
|
||||
<div class="form-group" style="margin-bottom:10px"><label>Rumah Ibadah (untuk Pengurus)</label>
|
||||
<select name="rumah_ibadah_id">
|
||||
<option value="">— Tidak ada —</option>
|
||||
<?php foreach ($riList as $ri): ?>
|
||||
<option value="<?= $ri['id'] ?>" <?= ($edit['rumah_ibadah_id']??'')==$ri['id']?'selected':'' ?>><?= h($ri['nama']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select></div>
|
||||
<br>
|
||||
<button type="submit" name="save" class="btn btn-primary"><?= $edit ? '💾 Update' : '➕ Buat' ?></button>
|
||||
<?php if ($edit): ?><a href="users.php" class="btn btn-secondary">Batal</a><?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if ($edit): ?>
|
||||
<div class="card" style="margin-top:0">
|
||||
<strong>🔑 Reset Password</strong><br><br>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="user_id" value="<?= $edit['id'] ?>">
|
||||
<div class="form-group" style="margin-bottom:10px"><label>Password Baru *</label>
|
||||
<input name="new_password" type="password" required minlength="6" placeholder="min 6 karakter"></div>
|
||||
<button type="submit" name="reset_pw" class="btn btn-danger">🔑 Reset</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="card" style="padding:0;overflow:hidden">
|
||||
<table>
|
||||
<thead><tr><th>Nama</th><th>Username</th><th>Role</th><th>Rumah Ibadah</th><th>Status</th><th>Aksi</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $r): ?>
|
||||
<tr <?= !$r['aktif'] ? 'style="opacity:.5"' : '' ?>>
|
||||
<td><strong><?= h($r['nama']) ?></strong><br><span style="font-size:10px;color:#94a3b8"><?= h($r['email']??'') ?></span></td>
|
||||
<td style="font-size:12px"><?= h($r['username']) ?></td>
|
||||
<td><span class="tag <?= $r['role_nama']==='admin'?'darurat':($r['role_nama']==='pengurus'?'diproses':'pending') ?>"><?= h($r['role_nama']) ?></span></td>
|
||||
<td style="font-size:11px"><?= h($r['nama_ri'] ?? '-') ?></td>
|
||||
<td><?= $r['aktif'] ? '<span class="tag selesai">Aktif</span>' : '<span class="tag darurat">Nonaktif</span>' ?></td>
|
||||
<td class="actions">
|
||||
<a href="?edit=<?= $r['id'] ?>" class="btn btn-secondary btn-sm">✏️</a>
|
||||
<?php if ($r['id'] != $_SESSION['user_id']): ?>
|
||||
<a href="?toggle=<?= $r['id'] ?>" class="btn <?= $r['aktif']?'btn-danger':'btn-success' ?> btn-sm" onclick="return confirm('Ubah status user ini?')">
|
||||
<?= $r['aktif'] ? '🚫' : '✅' ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php render_footer(); ?>
|
||||
Reference in New Issue
Block a user