Upload files to "/"
This commit is contained in:
@@ -0,0 +1,290 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'koneksi.php';
|
||||||
|
cekLogin();
|
||||||
|
cekRole('pengurus','relawan','admin');
|
||||||
|
|
||||||
|
$page = 'konfirmasi';
|
||||||
|
$pageTitle = 'Konfirmasi Bantuan';
|
||||||
|
$pageSubtitle = 'Verifikasi Penerimaan di Lapangan';
|
||||||
|
|
||||||
|
// Filter tab
|
||||||
|
$tab = $_GET['tab'] ?? 'menunggu';
|
||||||
|
|
||||||
|
$where = "WHERE 1=1";
|
||||||
|
if ($tab === 'menunggu') $where .= " AND bt.status_konfirmasi = 'Menunggu'";
|
||||||
|
if ($tab === 'dikonfirmasi') $where .= " AND bt.status_konfirmasi = 'Dikonfirmasi'";
|
||||||
|
if ($tab === 'ditolak') $where .= " AND bt.status_konfirmasi = 'Ditolak'";
|
||||||
|
|
||||||
|
$data = $conn->query("
|
||||||
|
SELECT bt.*, rm.nama_kepala_keluarga, rm.kelurahan, rm.rt_rw,
|
||||||
|
rm.kondisi_rumah, rm.no_telp AS telp_warga,
|
||||||
|
u.nama_lengkap AS input_oleh
|
||||||
|
FROM bantuan_tersalur bt
|
||||||
|
LEFT JOIN rumah_miskin rm ON bt.warga_id = rm.id
|
||||||
|
LEFT JOIN users u ON bt.disalurkan_oleh = u.id
|
||||||
|
$where
|
||||||
|
ORDER BY bt.created_at DESC
|
||||||
|
");
|
||||||
|
$total = $data->num_rows;
|
||||||
|
|
||||||
|
// Count per tab
|
||||||
|
$cMenunggu = $conn->query("SELECT COUNT(*) AS c FROM bantuan_tersalur WHERE status_konfirmasi='Menunggu'") ->fetch_assoc()['c'];
|
||||||
|
$cDikonfirmasi = $conn->query("SELECT COUNT(*) AS c FROM bantuan_tersalur WHERE status_konfirmasi='Dikonfirmasi'") ->fetch_assoc()['c'];
|
||||||
|
$cDitolak = $conn->query("SELECT COUNT(*) AS c FROM bantuan_tersalur WHERE status_konfirmasi='Ditolak'") ->fetch_assoc()['c'];
|
||||||
|
|
||||||
|
include 'includes/sidebar.php';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.custom-header-wrapper {
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: space-between !important;
|
||||||
|
align-items: center !important;
|
||||||
|
margin-bottom: 25px !important;
|
||||||
|
background: #ffffff !important;
|
||||||
|
padding: 20px 24px !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05) !important;
|
||||||
|
}
|
||||||
|
.custom-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-bottom: 2px solid #e2e8f0;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
.custom-tab-item {
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #64748b;
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.custom-tab-item:hover {
|
||||||
|
color: #2563eb;
|
||||||
|
}
|
||||||
|
.custom-tab-item.active {
|
||||||
|
color: #2563eb;
|
||||||
|
border-bottom-color: #2563eb;
|
||||||
|
}
|
||||||
|
.custom-tab-badge {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.custom-header-wrapper {
|
||||||
|
flex-direction: column !important;
|
||||||
|
align-items: flex-start !important;
|
||||||
|
gap: 15px !important;
|
||||||
|
}
|
||||||
|
.custom-tabs {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="custom-header-wrapper">
|
||||||
|
<div>
|
||||||
|
<h2 style="margin: 0; font-size: 24px; color: #1e293b; font-weight: 700; display: flex; align-items: center; gap: 10px;">
|
||||||
|
<span>📋</span> Konfirmasi Penerimaan Bantuan
|
||||||
|
</h2>
|
||||||
|
<p style="margin: 4px 0 0 0; color: #64748b; font-size: 14px;">
|
||||||
|
Halaman khusus Relawan & Pengurus untuk verifikasi logistik di lapangan
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="custom-tabs">
|
||||||
|
<a href="konfirmasi-bantuan.php?tab=menunggu" class="custom-tab-item <?= $tab==='menunggu'?'active':'' ?>">
|
||||||
|
⏳ Menunggu
|
||||||
|
<span class="custom-tab-badge" style="background:#fef3c7; color:#d97706;"><?= $cMenunggu ?></span>
|
||||||
|
</a>
|
||||||
|
<a href="konfirmasi-bantuan.php?tab=dikonfirmasi" class="custom-tab-item <?= $tab==='dikonfirmasi'?'active':'' ?>">
|
||||||
|
✅ Dikonfirmasi
|
||||||
|
<span class="custom-tab-badge" style="background:#dcfce7; color:#16a34a;"><?= $cDikonfirmasi ?></span>
|
||||||
|
</a>
|
||||||
|
<a href="konfirmasi-bantuan.php?tab=ditolak" class="custom-tab-item <?= $tab==='ditolak'?'active':'' ?>">
|
||||||
|
❌ Ditolak / Masalah
|
||||||
|
<span class="custom-tab-badge" style="background:#fee2e2; color:#dc2626;"><?= $cDitolak ?></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Penyaluran Status: <span style="text-transform: capitalize; color: var(--primary)"><?= $tab ?></span></h3>
|
||||||
|
<span class="badge badge-gray"><?= $total ?> Transaksi</span>
|
||||||
|
</div>
|
||||||
|
<div class="tbl-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th>Penerima (KPM) & Alamat</th>
|
||||||
|
<th>Detail Item Bantuan</th>
|
||||||
|
<th>Tanggal Input</th>
|
||||||
|
<th>Dibuat Oleh</th>
|
||||||
|
<?php if ($tab !== 'menunggu'): ?>
|
||||||
|
<th>Info Verifikasi</th>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($tab === 'menunggu'): ?>
|
||||||
|
<th>Verifikasi Lapangan</th>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if ($total === 0): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="7" style="text-align:center;padding:40px;color:var(--gray)">
|
||||||
|
<i class="fa fa-inbox" style="font-size:24px;display:block;margin-bottom:8px;color:#94a3b8"></i>
|
||||||
|
Tidak ada data bantuan dalam kategori ini
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php else: $no=1; while ($r = $data->fetch_assoc()): ?>
|
||||||
|
<tr>
|
||||||
|
<td style="color:#94a3b8;font-weight:600;font-size:12px"><?= $no++ ?></td>
|
||||||
|
<td>
|
||||||
|
<div style="font-weight:700;font-size:13px"><?= htmlspecialchars($r['nama_kepala_keluarga'] ?? 'Warga Dihapus') ?></div>
|
||||||
|
<div style="font-size:11px;color:var(--gray);margin-top:2px">
|
||||||
|
<?= htmlspecialchars($r['rt_rw'] ?? '') ?>, Kel. <?= htmlspecialchars($r['kelurahan'] ?? '') ?>
|
||||||
|
</div>
|
||||||
|
<?php if ($r['telp_warga']): ?>
|
||||||
|
<div style="font-size:11px;color:#2563eb;margin-top:2px"><i class="fa fa-phone"></i> <?= htmlspecialchars($r['telp_warga']) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge badge-blue" style="font-weight:600"><?= htmlspecialchars($r['jenis_bantuan']) ?></span>
|
||||||
|
<div style="font-weight:700;font-size:13px;margin-top:4px;color:#1e293b">Jml: <?= htmlspecialchars($r['jumlah'] ?? '-') ?></div>
|
||||||
|
<?php if ($r['keterangan']): ?>
|
||||||
|
<div style="font-size:11px;color:var(--gray);font-style:italic;margin-top:2px">Note: <?= htmlspecialchars($r['keterangan']) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td style="font-size:12px;color:var(--gray)"><?= date('d M Y H:i', strtotime($r['created_at'])) ?></td>
|
||||||
|
<td style="font-size:12px;font-weight:500"><?= htmlspecialchars($r['input_oleh'] ?? 'Sistem') ?></td>
|
||||||
|
|
||||||
|
<?php if ($tab !== 'menunggu'): ?>
|
||||||
|
<td>
|
||||||
|
<div style="font-size:12px">
|
||||||
|
<strong>Status:</strong>
|
||||||
|
<span class="badge <?= $tab==='dikonfirmasi'?'badge-green':'badge-red' ?>">
|
||||||
|
<?= htmlspecialchars($r['status_konfirmasi']) ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<?php if ($r['catatan_konfirmasi']): ?>
|
||||||
|
<div style="font-size:11px;color:var(--gray);background:#f8fafc;padding:4px 6px;border-radius:4px;margin-top:4px;border:1px solid #e2e8f0">
|
||||||
|
<strong>Ket:</strong> <?= htmlspecialchars($r['catatan_konfirmasi']) ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div style="font-size:10px;color:#94a3b8;margin-top:4px">
|
||||||
|
Waktu: <?= $r['waktu_konfirmasi'] ? date('d/m/Y H:i', strtotime($r['waktu_konfirmasi'])) : '-' ?>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($tab === 'menunggu'): ?>
|
||||||
|
<td>
|
||||||
|
<div style="display:flex;gap:6px">
|
||||||
|
<button class="btn btn-success btn-sm" onclick="konfirmasiTerima(<?= $r['id'] ?>, '<?= htmlspecialchars($r['nama_kepala_keluarga'], ENT_QUOTES) ?>')" style="display:flex;align-items:center;gap:4px">
|
||||||
|
<i class="fa fa-check"></i> Terima
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-danger btn-sm" onclick="bukaModalTolak(<?= $r['id'] ?>, '<?= htmlspecialchars($r['nama_kepala_keluarga'], ENT_QUOTES) ?>')" style="display:flex;align-items:center;gap:4px">
|
||||||
|
<i class="fa fa-times"></i> Bermasalah
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tr>
|
||||||
|
<?php endwhile; endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-overlay" id="modalTolak">
|
||||||
|
<div class="modal-box" style="max-width:400px">
|
||||||
|
<div class="modal-head">
|
||||||
|
<h3>Tolak / Laporkan Masalah</h3>
|
||||||
|
<button class="btn-close" onclick="closeModal('modalTolak')">✕</button>
|
||||||
|
</div>
|
||||||
|
<form method="POST" action="proses.php">
|
||||||
|
<input type="hidden" name="aksi" value="konfirmasi_bantuan">
|
||||||
|
<input type="hidden" name="id" id="mt_id">
|
||||||
|
<input type="hidden" name="status" value="Ditolak">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div style="font-size:13px; font-weight:600; color:#dc2626; margin-bottom:12px;" id="mt_nama_label"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Alasan Penolakan / Laporan Masalah *</label>
|
||||||
|
<textarea class="form-control" name="catatan_konfirmasi" rows="3" required
|
||||||
|
placeholder="cth: Penerima tidak ditemukan di alamat, bantuan belum sampai, barang rusak..."></textarea>
|
||||||
|
</div>
|
||||||
|
<div style="background:var(--red-lt);border-radius:var(--radius-sm);padding:9px 12px;font-size:12px;color:var(--red)">
|
||||||
|
Data ini akan dilaporkan kembali ke pihak manajemen/pemerintah untuk ditindaklanjuti.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-foot">
|
||||||
|
<button type="button" class="btn btn-ghost" onclick="closeModal('modalTolak')">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-danger">Kirim Laporan</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function openModal(id) {
|
||||||
|
const modal = document.getElementById(id);
|
||||||
|
if(modal) modal.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fungsi menutup form modal
|
||||||
|
function closeModal(id) {
|
||||||
|
const modal = document.getElementById(id);
|
||||||
|
if(modal) modal.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Fungsi Klik Tombol "Terima" (Langsung Setujui Distribusi lewat POST virtual form)
|
||||||
|
function konfirmasiTerima(id, namaWarga) {
|
||||||
|
if (confirm(`Apakah Anda sudah memverifikasi di lapangan bahwa bantuan untuk KK "${namaWarga}" telah DITERIMA dengan benar?`)) {
|
||||||
|
// Membuat elemen form virtual di dalam memori dokumen browser
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.method = 'POST';
|
||||||
|
form.action = 'proses.php';
|
||||||
|
|
||||||
|
form.innerHTML = `
|
||||||
|
<input type="hidden" name="aksi" value="konfirmasi_bantuan">
|
||||||
|
<input type="hidden" name="id" value="${id}">
|
||||||
|
<input type="hidden" name="status" value="Dikonfirmasi">
|
||||||
|
<input type="hidden" name="catatan_konfirmasi" value="Bantuan diterima dengan baik di lapangan.">
|
||||||
|
`;
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Fungsi Klik Tombol "Bermasalah" (Membuka Modal Laporan Dampak)
|
||||||
|
function bukaModalTolak(id, namaWarga) {
|
||||||
|
document.getElementById('mt_id').value = id;
|
||||||
|
document.getElementById('mt_nama_label').innerHTML = `<i class="fa fa-user"></i> Masalah Distribusi: <strong>${namaWarga}</strong>`;
|
||||||
|
|
||||||
|
// Reset isi form teks area sebelumnya
|
||||||
|
document.querySelector('#modalTolak textarea[name="catatan_konfirmasi"]').value = "";
|
||||||
|
|
||||||
|
openModal('modalTolak');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menutup modal otomatis apabila pengguna mengklik area luar box modal yang gelap
|
||||||
|
window.onclick = function(event) {
|
||||||
|
if (event.target.classList.contains('modal-overlay')) {
|
||||||
|
closeModal(event.target.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
include 'includes/footer.php';
|
||||||
|
?>
|
||||||
+259
@@ -0,0 +1,259 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'koneksi.php';
|
||||||
|
cekLogin();
|
||||||
|
$page = 'laporan';
|
||||||
|
$pageTitle = 'Laporan & Statistik';
|
||||||
|
$pageSubtitle= 'Analisis Data Kemiskinan';
|
||||||
|
|
||||||
|
$totalKpm = $conn->query("SELECT COUNT(*) AS c FROM rumah_miskin")->fetch_assoc()['c'];
|
||||||
|
$terjangkau = $conn->query("SELECT COUNT(*) AS c FROM rumah_miskin WHERE status_bantuan='Terjangkau'")->fetch_assoc()['c'];
|
||||||
|
$sudahTerima = $conn->query("SELECT COUNT(*) AS c FROM rumah_miskin WHERE status_bantuan='Sudah Menerima'")->fetch_assoc()['c'];
|
||||||
|
$blankSpot = $conn->query("SELECT COUNT(*) AS c FROM rumah_miskin WHERE status_bantuan='Belum Terbantu'")->fetch_assoc()['c'];
|
||||||
|
$prioritas = $conn->query("SELECT COUNT(*) AS c FROM rumah_miskin WHERE prioritas=1")->fetch_assoc()['c'];
|
||||||
|
$totalBantuan = $conn->query("SELECT COUNT(*) AS c FROM bantuan_tersalur")->fetch_assoc()['c'];
|
||||||
|
$totalIbadah = $conn->query("SELECT COUNT(*) AS c FROM rumah_ibadah")->fetch_assoc()['c'];
|
||||||
|
$totalTanggungan = $conn->query("SELECT SUM(jumlah_tanggungan) AS c FROM rumah_miskin")->fetch_assoc()['c'] ?? 0;
|
||||||
|
$avgPendapatan = $conn->query("SELECT AVG(pendapatan_bulanan) AS c FROM rumah_miskin")->fetch_assoc()['c'] ?? 0;
|
||||||
|
$pct = $totalKpm > 0 ? round(($terjangkau + $sudahTerima) / $totalKpm * 100) : 0;
|
||||||
|
|
||||||
|
$byKondisi = $conn->query("SELECT kondisi_rumah, COUNT(*) AS c FROM rumah_miskin GROUP BY kondisi_rumah");
|
||||||
|
$kondisiData = [];
|
||||||
|
while ($r = $byKondisi->fetch_assoc()) $kondisiData[$r['kondisi_rumah']] = $r['c'];
|
||||||
|
|
||||||
|
$byKec = $conn->query("SELECT kecamatan, COUNT(*) AS c FROM rumah_miskin WHERE kecamatan IS NOT NULL AND kecamatan!='' GROUP BY kecamatan ORDER BY c DESC LIMIT 10");
|
||||||
|
|
||||||
|
$ibadahPerf = $conn->query("SELECT ri.nama_ibadah, ri.kuota_bantuan, ri.radius_m, COUNT(bt.id) AS total_salur FROM rumah_ibadah ri LEFT JOIN bantuan_tersalur bt ON ri.id=bt.ibadah_id GROUP BY ri.id ORDER BY total_salur DESC");
|
||||||
|
|
||||||
|
$pendDist = $conn->query("SELECT
|
||||||
|
SUM(CASE WHEN pendapatan_bulanan < 500000 THEN 1 ELSE 0 END) AS sangat_rendah,
|
||||||
|
SUM(CASE WHEN pendapatan_bulanan BETWEEN 500000 AND 1000000 THEN 1 ELSE 0 END) AS rendah,
|
||||||
|
SUM(CASE WHEN pendapatan_bulanan BETWEEN 1000001 AND 2000000 THEN 1 ELSE 0 END) AS menengah,
|
||||||
|
SUM(CASE WHEN pendapatan_bulanan > 2000000 THEN 1 ELSE 0 END) AS atas
|
||||||
|
FROM rumah_miskin")->fetch_assoc();
|
||||||
|
|
||||||
|
include 'includes/sidebar.php';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.lp-grid4 { display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:16px; }
|
||||||
|
.lp-grid21 { display:grid; grid-template-columns:2fr 1fr; gap:14px; margin-bottom:14px; }
|
||||||
|
.lp-grid11 { display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-bottom:14px; }
|
||||||
|
|
||||||
|
/* Stat box sederhana */
|
||||||
|
.lp-stat {
|
||||||
|
background:#fff; border:1px solid var(--gray-md); border-radius:var(--radius);
|
||||||
|
padding:16px 18px;
|
||||||
|
}
|
||||||
|
.lp-stat .lp-num { font-size:26px; font-weight:800; line-height:1; margin-bottom:3px; }
|
||||||
|
.lp-stat .lp-lbl { font-size:11px; color:var(--gray); font-weight:500; }
|
||||||
|
.lp-stat .lp-sub { font-size:11px; font-weight:600; margin-top:3px; }
|
||||||
|
.lp-stat .lp-line { height:2px; border-radius:99px; margin-top:12px; }
|
||||||
|
|
||||||
|
/* Bar label */
|
||||||
|
.bar-row { margin-bottom:11px; }
|
||||||
|
.bar-row-top { display:flex; justify-content:space-between; font-size:12px; font-weight:600; margin-bottom:4px; }
|
||||||
|
.bar-track { height:8px; background:var(--gray-lt); border-radius:99px; overflow:hidden; }
|
||||||
|
.bar-fill { height:100%; border-radius:99px; transition:.5s; }
|
||||||
|
|
||||||
|
/* Kondisi kotak */
|
||||||
|
.kond-box { text-align:center; padding:12px 8px; background:var(--gray-lt); border-radius:var(--radius-sm); }
|
||||||
|
.kond-box .knum { font-size:22px; font-weight:800; line-height:1; }
|
||||||
|
.kond-box .klbl { font-size:10px; color:var(--gray); margin-top:3px; }
|
||||||
|
|
||||||
|
/* Avg box */
|
||||||
|
.avg-box {
|
||||||
|
text-align:center; padding:12px; background:var(--yellow-lt);
|
||||||
|
border-radius:var(--radius-sm); margin-top:12px;
|
||||||
|
}
|
||||||
|
.avg-box .a-lbl { font-size:11px; color:var(--yellow); font-weight:600; }
|
||||||
|
.avg-box .a-num { font-size:18px; font-weight:800; color:var(--yellow); margin-top:2px; }
|
||||||
|
.avg-box .a-sub { font-size:10px; color:var(--yellow); margin-top:1px; }
|
||||||
|
|
||||||
|
@media(max-width:900px){
|
||||||
|
.lp-grid4 { grid-template-columns:repeat(2,1fr); }
|
||||||
|
.lp-grid21 { grid-template-columns:1fr; }
|
||||||
|
.lp-grid11 { grid-template-columns:1fr; }
|
||||||
|
}
|
||||||
|
@media print{
|
||||||
|
#sidebar,#topbar,.btn { display:none!important; }
|
||||||
|
#main-wrap { margin-left:0!important; }
|
||||||
|
.card { break-inside:avoid; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="page-head" style="margin-bottom:16px">
|
||||||
|
<div>
|
||||||
|
<h2>Laporan & Statistik</h2>
|
||||||
|
<p>Data per <?= date('d F Y') ?></p>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-ghost btn-sm" onclick="window.print()">
|
||||||
|
<i class="fa fa-print"></i> Cetak
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- BARIS 1 — 4 stat cards, semua clickable -->
|
||||||
|
<div class="lp-grid4">
|
||||||
|
<a href="data-warga.php" class="lp-stat" style="text-decoration:none;color:inherit">
|
||||||
|
<div class="lp-num" style="color:var(--orange)"><?= $totalKpm ?></div>
|
||||||
|
<div class="lp-lbl">Total KPM Terdata</div>
|
||||||
|
<div class="lp-sub" style="color:var(--orange)"><?= $totalTanggungan ?> jiwa</div>
|
||||||
|
<div class="lp-line" style="background:var(--orange)"></div>
|
||||||
|
</a>
|
||||||
|
<a href="data-warga.php?status=Terjangkau" class="lp-stat" style="text-decoration:none;color:inherit">
|
||||||
|
<div class="lp-num" style="color:var(--green)"><?= $pct ?>%</div>
|
||||||
|
<div class="lp-lbl">Cakupan Bantuan</div>
|
||||||
|
<div class="lp-sub" style="color:var(--green)"><?= $terjangkau + $sudahTerima ?> KK</div>
|
||||||
|
<div class="lp-line" style="background:var(--green)"></div>
|
||||||
|
</a>
|
||||||
|
<a href="data-warga.php?status=Belum+Terbantu" class="lp-stat" style="text-decoration:none;color:inherit">
|
||||||
|
<div class="lp-num" style="color:var(--red)"><?= $blankSpot ?></div>
|
||||||
|
<div class="lp-lbl">Blank Spot</div>
|
||||||
|
<div class="lp-sub" style="color:var(--red)">Belum terjangkau</div>
|
||||||
|
<div class="lp-line" style="background:var(--red)"></div>
|
||||||
|
</a>
|
||||||
|
<a href="bantuan.php" class="lp-stat" style="text-decoration:none;color:inherit">
|
||||||
|
<div class="lp-num" style="color:var(--purple)"><?= $totalBantuan ?></div>
|
||||||
|
<div class="lp-lbl">Bantuan Tersalur</div>
|
||||||
|
<div class="lp-sub" style="color:var(--purple)">Transaksi tercatat</div>
|
||||||
|
<div class="lp-line" style="background:var(--purple)"></div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- BARIS 2 — Distribusi status + Pendapatan -->
|
||||||
|
<div class="lp-grid21">
|
||||||
|
|
||||||
|
<!-- Distribusi status -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-hd"><h3>Distribusi Status KPM</h3></div>
|
||||||
|
<div class="card-bd">
|
||||||
|
<?php
|
||||||
|
$statusArr = [
|
||||||
|
'Belum Terbantu' => [$blankSpot, '#dc2626'],
|
||||||
|
'Terjangkau' => [$terjangkau, '#16a34a'],
|
||||||
|
'Sudah Menerima' => [$sudahTerima, '#2563eb'],
|
||||||
|
'Prioritas Bencana' => [$prioritas, '#ea580c'],
|
||||||
|
];
|
||||||
|
foreach ($statusArr as $label => [$val, $color]):
|
||||||
|
$p = $totalKpm > 0 ? round($val / $totalKpm * 100) : 0;
|
||||||
|
?>
|
||||||
|
<div class="bar-row">
|
||||||
|
<div class="bar-row-top">
|
||||||
|
<span style="color:var(--dark)"><?= $label ?></span>
|
||||||
|
<span style="color:<?= $color ?>"><?= $val ?> KK <?= $p ?>%</span>
|
||||||
|
</div>
|
||||||
|
<div class="bar-track">
|
||||||
|
<div class="bar-fill" style="width:<?= $p ?>%;background:<?= $color ?>"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<div style="border-top:1px solid var(--gray-md);margin-top:14px;padding-top:14px;display:grid;grid-template-columns:repeat(3,1fr);gap:10px">
|
||||||
|
<?php foreach(['Sangat Tidak Layak'=>'#dc2626','Tidak Layak'=>'#ea580c','Layak'=>'#16a34a'] as $k=>$c): ?>
|
||||||
|
<div class="kond-box">
|
||||||
|
<div class="knum" style="color:<?= $c ?>"><?= $kondisiData[$k] ?? 0 ?></div>
|
||||||
|
<div class="klbl"><?= $k ?></div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Distribusi pendapatan -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-hd"><h3>Distribusi Pendapatan</h3></div>
|
||||||
|
<div class="card-bd">
|
||||||
|
<?php
|
||||||
|
$pendArr = [
|
||||||
|
'< Rp500 rb' => [$pendDist['sangat_rendah'], '#dc2626'],
|
||||||
|
'Rp500rb – 1jt' => [$pendDist['rendah'], '#ea580c'],
|
||||||
|
'Rp1jt – 2jt' => [$pendDist['menengah'], '#d97706'],
|
||||||
|
'> Rp2 jt' => [$pendDist['atas'], '#16a34a'],
|
||||||
|
];
|
||||||
|
foreach ($pendArr as $label => [$val, $color]):
|
||||||
|
$pp = $totalKpm > 0 ? round($val / $totalKpm * 100) : 0;
|
||||||
|
?>
|
||||||
|
<div class="bar-row">
|
||||||
|
<div class="bar-row-top">
|
||||||
|
<span style="color:var(--gray);font-size:11px"><?= $label ?></span>
|
||||||
|
<span style="color:<?= $color ?>"><?= $val ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="bar-track">
|
||||||
|
<div class="bar-fill" style="width:<?= $pp ?>%;background:<?= $color ?>"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<div class="avg-box">
|
||||||
|
<div class="a-lbl">Rata-rata Pendapatan</div>
|
||||||
|
<div class="a-num"><?= rupiah(round($avgPendapatan)) ?></div>
|
||||||
|
<div class="a-sub">per bulan / KK</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- BARIS 3 — Sebaran kecamatan + Performa ibadah -->
|
||||||
|
<div class="lp-grid11">
|
||||||
|
|
||||||
|
<!-- Sebaran kecamatan -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-hd"><h3>Sebaran per Kecamatan</h3></div>
|
||||||
|
<div class="tbl-w">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Kecamatan</th><th style="text-align:right">KPM</th><th>Proporsi</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if ($byKec->num_rows === 0): ?>
|
||||||
|
<tr><td colspan="3" style="text-align:center;padding:24px;color:var(--gray)">Data wilayah belum diisi</td></tr>
|
||||||
|
<?php else: while ($r = $byKec->fetch_assoc()):
|
||||||
|
$p2 = $totalKpm > 0 ? round($r['c'] / $totalKpm * 100) : 0;
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td style="font-weight:600"><?= htmlspecialchars($r['kecamatan']) ?></td>
|
||||||
|
<td style="text-align:right;font-weight:700;color:var(--purple)"><?= $r['c'] ?></td>
|
||||||
|
<td style="width:120px">
|
||||||
|
<div style="display:flex;align-items:center;gap:6px">
|
||||||
|
<div class="bar-track" style="flex:1;height:6px">
|
||||||
|
<div class="bar-fill" style="width:<?= $p2 ?>%;background:var(--purple)"></div>
|
||||||
|
</div>
|
||||||
|
<span style="font-size:11px;font-weight:600;color:var(--purple);min-width:28px"><?= $p2 ?>%</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endwhile; endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Performa ibadah -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-hd">
|
||||||
|
<h3>Performa Rumah Ibadah</h3>
|
||||||
|
<a href="data-ibadah.php" style="font-size:12px;color:var(--blue);text-decoration:none;font-weight:600">Lihat semua</a>
|
||||||
|
</div>
|
||||||
|
<div class="tbl-w">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>Nama</th><th style="text-align:center">Kuota</th><th style="text-align:center">Radius</th><th style="text-align:center">Bantuan</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if ($ibadahPerf->num_rows === 0): ?>
|
||||||
|
<tr><td colspan="4" style="text-align:center;padding:24px;color:var(--gray)">Belum ada data</td></tr>
|
||||||
|
<?php else: while ($r = $ibadahPerf->fetch_assoc()): ?>
|
||||||
|
<tr>
|
||||||
|
<td style="font-weight:600;font-size:12px"><?= htmlspecialchars($r['nama_ibadah']) ?></td>
|
||||||
|
<td style="text-align:center;font-size:12px"><?= $r['kuota_bantuan'] ?> KK</td>
|
||||||
|
<td style="text-align:center;font-size:12px"><?= $r['radius_m'] ?> m</td>
|
||||||
|
<td style="text-align:center"><span class="badge badge-green"><?= $r['total_salur'] ?>x</span></td>
|
||||||
|
</tr>
|
||||||
|
<?php endwhile; endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php include 'includes/footer.php'; ?>
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
<?php
|
||||||
|
// login.php
|
||||||
|
require_once 'koneksi.php';
|
||||||
|
|
||||||
|
if (session_status() === PHP_SESSION_NONE) {
|
||||||
|
session_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jika pengguna sudah terlanjur login, langsung arahkan sesuai rolenya
|
||||||
|
if (isset($_SESSION['user_id']) && isset($_SESSION['role'])) {
|
||||||
|
if ($_SESSION['role'] === 'admin') {
|
||||||
|
header('Location: dashboard-admin.php');
|
||||||
|
} elseif ($_SESSION['role'] === 'pemerintah') {
|
||||||
|
header('Location: dashboard-pemerintah.php');
|
||||||
|
} elseif ($_SESSION['role'] === 'pengurus') {
|
||||||
|
header('Location: dashboard-pengurus.php');
|
||||||
|
} elseif ($_SESSION['role'] === 'relawan') {
|
||||||
|
header('Location: dashboard-relawan.php');
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$username = bersih($_POST['username'] ?? '', $conn);
|
||||||
|
$password = $_POST['password'] ?? '';
|
||||||
|
|
||||||
|
if ($username && $password) {
|
||||||
|
$query = "SELECT * FROM users WHERE (username='$username' OR email='$username') AND aktif=1 LIMIT 1";
|
||||||
|
$result = $conn->query($query);
|
||||||
|
$user = $result->fetch_assoc();
|
||||||
|
|
||||||
|
// Menggunakan pencocokan plain-text / teks biasa sesuai permintaan Anda
|
||||||
|
if ($user && $password === $user['password']) {
|
||||||
|
$_SESSION['user_id'] = $user['id'];
|
||||||
|
$_SESSION['nama'] = $user['nama_lengkap'];
|
||||||
|
$_SESSION['role'] = $user['role'];
|
||||||
|
$_SESSION['username'] = $user['username'];
|
||||||
|
|
||||||
|
$conn->query("UPDATE users SET last_login=NOW() WHERE id={$user['id']}");
|
||||||
|
|
||||||
|
// PENGALIHAN OTOMATIS KE 4 DASHBOARD BERBEDA
|
||||||
|
if ($_SESSION['role'] === 'admin') {
|
||||||
|
header('Location: dashboard-admin.php');
|
||||||
|
} elseif ($_SESSION['role'] === 'pemerintah') {
|
||||||
|
header('Location: dashboard-pemerintah.php');
|
||||||
|
} elseif ($_SESSION['role'] === 'pengurus') {
|
||||||
|
header('Location: dashboard-pengurus.php');
|
||||||
|
} elseif ($_SESSION['role'] === 'relawan') {
|
||||||
|
header('Location: dashboard-relawan.php');
|
||||||
|
} else {
|
||||||
|
header('Location: login.php');
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
} else {
|
||||||
|
$error = 'Username/password salah atau akun Anda tidak aktif.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$error = 'Semua kolom formulir wajib diisi.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Login - WebGIS Poverty Mapping</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"/>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body { font-family: 'Inter', sans-serif; background: #ffffff; display: flex; height: 100vh; overflow: hidden; }
|
||||||
|
.split-container { display: flex; width: 100%; height: 100%; }
|
||||||
|
|
||||||
|
.left-side { flex: 1.2; background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%); display: flex; flex-direction: column; justify-content: space-between; padding: 50px; color: #e2e8f0; position: relative; }
|
||||||
|
.left-side::before { content: ''; position: absolute; top:0; left:0; right:0; bottom:0; background: radial-gradient(circle at 80% 20%, rgba(255,255,255,0.1) 0%, transparent 50%); }
|
||||||
|
.brand-logo { font-size: 20px; font-weight: 800; color: #ffffff; display: flex; align-items: center; gap: 10px; z-index: 5; }
|
||||||
|
.brand-speech { z-index: 5; max-width: 500px; margin-bottom: 40px; }
|
||||||
|
.brand-speech h1 { font-size: 32px; color: white; font-weight: 800; line-height: 1.3; margin-bottom: 16px; }
|
||||||
|
.brand-speech p { font-size: 15px; line-height: 1.6; color: #bfdbfe; }
|
||||||
|
.brand-footer { z-index: 5; font-size: 13px; display: flex; gap: 20px; }
|
||||||
|
.brand-footer a { color: #93c5fd; text-decoration: none; transition: 0.2s; }
|
||||||
|
.brand-footer a:hover { color: white; }
|
||||||
|
|
||||||
|
.right-side { flex: 1; background: #f8fafc; display: flex; align-items: center; justify-content: center; padding: 40px; border-left: 1px solid #e2e8f0; }
|
||||||
|
.login-card { background: white; padding: 40px; border-radius: 16px; box-shadow: 0 10px 25px rgba(30, 58, 138, 0.05); width: 100%; max-width: 420px; border: 1px solid #e2e8f0; }
|
||||||
|
.login-header { margin-bottom: 24px; }
|
||||||
|
.login-header h2 { color: #1e3a8a; font-size: 22px; font-weight: 700; }
|
||||||
|
.login-header p { color: #64748b; font-size: 14px; margin-top: 4px; }
|
||||||
|
.form-group { margin-bottom: 20px; }
|
||||||
|
.form-group label { display: block; font-size: 13px; font-weight: 600; color: #1e293b; margin-bottom: 6px; }
|
||||||
|
.input-wrap { position: relative; display: flex; align-items: center; }
|
||||||
|
.input-wrap i.input-icon { position: absolute; left: 14px; color: #94a3b8; font-size: 14px; }
|
||||||
|
.form-input { width: 100%; padding: 12px 14px 12px 42px; border: 1px solid #cbd5e1; border-radius: 8px; font-size: 14px; color: #0f172a; outline: none; transition: 0.2s; font-family: inherit; }
|
||||||
|
.form-input:focus { border-color: #3b82f6; box-shadow: 0 0 0 4px rgba(59,130,246,0.1); }
|
||||||
|
.toggle-pw { position: absolute; right: 14px; background: none; border: none; color: #94a3b8; cursor: pointer; padding: 0; font-size: 14px; }
|
||||||
|
|
||||||
|
.btn-login { width: 100%; padding: 12px; background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%); color: white; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; margin-top: 8px; transition: 0.2s; display: flex; align-items: center; justify-content: center; gap: 8px; box-shadow: 0 4px 12px rgba(30, 58, 138, 0.2); }
|
||||||
|
.btn-login:hover { opacity: 0.95; transform: translateY(-1px); }
|
||||||
|
|
||||||
|
.alert-error { background: #fef2f2; color: #991b1b; padding: 12px 16px; border-radius: 8px; font-size: 13px; margin-bottom: 20px; border: 1px solid #fee2e2; font-weight: 500; display: flex; align-items: center; gap: 8px; }
|
||||||
|
.lr-foot { text-align: center; margin-top: 24px; font-size: 13px; color: #64748b; line-height: 1.5; border-top: 1px solid #f1f5f9; padding-top: 20px; }
|
||||||
|
|
||||||
|
@media (max-width: 900px) { .left-side { display: none; } .right-side { flex: 1; } }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="split-container">
|
||||||
|
<div class="left-side">
|
||||||
|
<div class="brand-logo">
|
||||||
|
<i class="fa fa-map-location-dot"></i> WebGIS Poverty Mapping
|
||||||
|
</div>
|
||||||
|
<div class="brand-speech">
|
||||||
|
<h1>Sistem Pemetaan Terpadu Penanggulangan Kemiskinan</h1>
|
||||||
|
<p>Akses masuk terbatas khusus bagi jajaran Aparatur Pemerintahan, Pengurus Internal Rumah Ibadah, serta Mitra Relawan Lapangan terverifikasi.</p>
|
||||||
|
</div>
|
||||||
|
<div class="brand-footer">
|
||||||
|
<span style="color: #93c5fd;">Sistem Informasi Geografis v2.1.0</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="right-side">
|
||||||
|
<div class="login-card">
|
||||||
|
<div class="login-header">
|
||||||
|
<h2>Selamat Datang Kembali</h2>
|
||||||
|
<p>Gunakan kredensial akun terdaftar Anda</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="alert-error">
|
||||||
|
<i class="fa fa-circle-exclamation"></i> <?= $error ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="" method="POST">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Username atau Email</label>
|
||||||
|
<div class="input-wrap">
|
||||||
|
<i class="fa fa-user input-icon"></i>
|
||||||
|
<input class="form-input" type="text" name="username" placeholder="Masukkan username/email..." required autofocus value="<?= htmlspecialchars($_POST['username'] ?? '') ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Password</label>
|
||||||
|
<div class="input-wrap">
|
||||||
|
<i class="fa fa-lock input-icon"></i>
|
||||||
|
<input class="form-input" type="password" name="password" id="pw" placeholder="Masukkan sandi akun..." required>
|
||||||
|
<button type="button" class="toggle-pw" onclick="togglePw()"><i class="fa fa-eye" id="eye-ic"></i></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn-login">
|
||||||
|
<i class="fa fa-right-to-bracket"></i> Masuk Sistem
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="lr-foot">
|
||||||
|
Butuh otorisasi akses atau lupa kata sandi?<br>Hubungi Administrator Pusat.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function togglePw() {
|
||||||
|
var pw = document.getElementById('pw');
|
||||||
|
var ic = document.getElementById('eye-ic');
|
||||||
|
if (pw.type === 'password') {
|
||||||
|
pw.type = 'text';
|
||||||
|
ic.className = 'fa fa-eye-slash';
|
||||||
|
} else {
|
||||||
|
pw.type = 'password';
|
||||||
|
ic.className = 'fa fa-eye';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
// logout.php
|
||||||
|
require_once 'koneksi.php';
|
||||||
|
session_destroy();
|
||||||
|
header('Location: login.php');
|
||||||
|
exit;
|
||||||
@@ -0,0 +1,364 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'koneksi.php';
|
||||||
|
cekLogin();
|
||||||
|
cekRole('admin');
|
||||||
|
|
||||||
|
$page = 'users';
|
||||||
|
$pageTitle = 'Manajemen User';
|
||||||
|
$pageSubtitle = 'Kelola Akun Pengguna Sistem';
|
||||||
|
|
||||||
|
$users = $conn->query("SELECT * FROM users ORDER BY role ASC, nama_lengkap ASC");
|
||||||
|
$total = $users->num_rows;
|
||||||
|
|
||||||
|
include 'includes/sidebar.php';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.custom-header-wrapper {
|
||||||
|
display: flex !important;
|
||||||
|
justify-content: space-between !important;
|
||||||
|
align-items: center !important;
|
||||||
|
margin-bottom: 25px !important;
|
||||||
|
background: #ffffff !important;
|
||||||
|
padding: 20px 24px !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05) !important;
|
||||||
|
}
|
||||||
|
.custom-stat-grid {
|
||||||
|
display: grid !important;
|
||||||
|
grid-template-columns: repeat(4, 1fr) !important;
|
||||||
|
gap: 20px !important;
|
||||||
|
margin-bottom: 30px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.custom-stat-box {
|
||||||
|
background: #ffffff !important;
|
||||||
|
padding: 16px 20px !important;
|
||||||
|
border-radius: 12px !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
gap: 16px !important;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.05) !important;
|
||||||
|
border: 1px solid #e2e8f0 !important;
|
||||||
|
}
|
||||||
|
.custom-stat-icon {
|
||||||
|
width: 48px !important;
|
||||||
|
height: 48px !important;
|
||||||
|
border-radius: 10px !important;
|
||||||
|
display: flex !important;
|
||||||
|
align-items: center !important;
|
||||||
|
justify-content: center !important;
|
||||||
|
flex-shrink: 0 !important;
|
||||||
|
}
|
||||||
|
.custom-stat-info {
|
||||||
|
display: flex !important;
|
||||||
|
flex-direction: column !important;
|
||||||
|
}
|
||||||
|
.custom-stat-info .num {
|
||||||
|
font-size: 24px !important;
|
||||||
|
font-weight: 800 !important;
|
||||||
|
line-height: 1.2 !important;
|
||||||
|
margin-bottom: 2px !important;
|
||||||
|
}
|
||||||
|
.custom-stat-info .lbl {
|
||||||
|
color: #64748b !important;
|
||||||
|
font-size: 13px !important;
|
||||||
|
font-weight: 500 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsif jika dibuka di HP agar layout menyesuaikan otomatis */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.custom-header-wrapper {
|
||||||
|
flex-direction: column !important;
|
||||||
|
align-items: flex-start !important;
|
||||||
|
gap: 15px !important;
|
||||||
|
}
|
||||||
|
.custom-stat-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr) !important;
|
||||||
|
gap: 12px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.custom-stat-grid {
|
||||||
|
grid-template-columns: 1fr !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="custom-header-wrapper">
|
||||||
|
<div>
|
||||||
|
<h2 style="margin: 0; font-size: 24px; color: #1e293b; font-weight: 700; display: flex; align-items: center; gap: 10px;">
|
||||||
|
<span>👥</span> Manajemen User
|
||||||
|
</h2>
|
||||||
|
<p style="margin: 4px 0 0 0; color: #64748b; font-size: 14px;">
|
||||||
|
Total <strong style="color: #7c3aed; font-weight: 600;"><?= $total ?></strong> akun terdaftar dalam sistem
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-purple" onclick="openModal('modalTambah')" style="display: flex; align-items: center; gap: 8px; padding: 10px 18px; font-weight: 600; border-radius: 8px; cursor: pointer;">
|
||||||
|
<i class="fa fa-user-plus"></i> Tambah User Baru
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$roleStats = [];
|
||||||
|
$rs = $conn->query("SELECT role, COUNT(*) AS c FROM users GROUP BY role");
|
||||||
|
while ($r = $rs->fetch_assoc()) $roleStats[$r['role']] = $r['c'];
|
||||||
|
?>
|
||||||
|
<div class="custom-stat-grid">
|
||||||
|
<?php
|
||||||
|
$roles = [
|
||||||
|
'admin' => ['🛡️','Administrator','#7c3aed','#ede9fe'],
|
||||||
|
'relawan' => ['🙋','Relawan','#ea580c','#ffedd5'],
|
||||||
|
'pengurus' => ['🕌','Pengurus Ibadah','#2563eb','#dbeafe'],
|
||||||
|
'pemerintah' => ['🏛️','Pemerintah','#16a34a','#dcfce7'],
|
||||||
|
];
|
||||||
|
foreach ($roles as $key => [$ic, $lbl, $color, $bg]):
|
||||||
|
?>
|
||||||
|
<div class="custom-stat-box">
|
||||||
|
<div class="custom-stat-icon" style="background:<?= $bg ?>;">
|
||||||
|
<span style="font-size:22px"><?= $ic ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="custom-stat-info">
|
||||||
|
<span class="num" style="color:<?= $color ?>;"><?= $roleStats[$key] ?? 0 ?></span>
|
||||||
|
<span class="lbl"><?= $lbl ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header"><h3><i class="fa fa-users" style="color:#7c3aed"></i> Daftar Akun</h3></div>
|
||||||
|
<div class="tbl-wrap">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>#</th><th>Nama Lengkap</th><th>Username</th><th>Email</th><th>Role</th><th>Status</th><th>Terakhir Login</th><th>Aksi</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php $no=1; $users->data_seek(0); while ($r = $users->fetch_assoc()): ?>
|
||||||
|
<?php
|
||||||
|
$roleLabel = ['admin'=>'Administrator','relawan'=>'Relawan','pengurus'=>'Pengurus Ibadah','pemerintah'=>'Pemerintah'];
|
||||||
|
$roleClass = ['admin'=>'badge-purple','relawan'=>'badge-orange','pengurus'=>'badge-blue','pemerintah'=>'badge-green'];
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td style="color:#94a3b8;font-weight:600"><?= $no++ ?></td>
|
||||||
|
<td>
|
||||||
|
<div style="display:flex;align-items:center;gap:10px">
|
||||||
|
<div style="width:34px;height:34px;border-radius:50%;background:<?= ['admin'=>'#7c3aed','relawan'=>'#ea580c','pengurus'=>'#2563eb','pemerintah'=>'#16a34a'][$r['role']]??'#64748b' ?>;display:flex;align-items:center;justify-content:center;color:white;font-weight:700;font-size:13px;flex-shrink:0">
|
||||||
|
<?= strtoupper(substr($r['nama_lengkap'],0,1)) ?>
|
||||||
|
</div>
|
||||||
|
<span style="font-weight:700"><?= htmlspecialchars($r['nama_lengkap']) ?></span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td style="font-family:monospace;font-size:13px;color:#2563eb">@<?= htmlspecialchars($r['username']) ?></td>
|
||||||
|
<td style="font-size:12px;color:#64748b"><?= htmlspecialchars($r['email']) ?></td>
|
||||||
|
<td><span class="badge <?= $roleClass[$r['role']]??'badge-gray' ?>"><?= $roleLabel[$r['role']]??$r['role'] ?></span></td>
|
||||||
|
<td>
|
||||||
|
<?php if ($r['aktif']): ?>
|
||||||
|
<span class="badge badge-green">● Aktif</span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-red">● Nonaktif</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td style="font-size:12px;color:#64748b">
|
||||||
|
<?= $r['last_login'] ? date('d M Y H:i', strtotime($r['last_login'])) : '<span style="color:#94a3b8">Belum pernah</span>' ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div style="display:flex;gap:4px">
|
||||||
|
<button class="btn btn-primary btn-sm" onclick='editUser(<?= json_encode($r) ?>)' title="Edit User"><i class="fa fa-edit"></i></button>
|
||||||
|
<button class="btn btn-warning btn-sm" onclick="resetPassword(<?= $r['id'] ?>, '<?= htmlspecialchars($r['nama_lengkap'], ENT_QUOTES) ?>')" title="Reset Password"><i class="fa fa-key"></i></button>
|
||||||
|
<?php if ($r['id'] != $_SESSION['user_id']): ?>
|
||||||
|
<button class="btn <?= $r['aktif']?'btn-ghost':'btn-success' ?> btn-sm" onclick="toggleAktif(<?= $r['id'] ?>, <?= $r['aktif'] ?>)" title="<?= $r['aktif']?'Nonaktifkan':'Aktifkan' ?>">
|
||||||
|
<i class="fa <?= $r['aktif']?'fa-ban':'fa-check' ?>"></i>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-danger btn-sm" onclick="hapusUser(<?= $r['id'] ?>)" title="Hapus User"><i class="fa fa-trash"></i></button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endwhile; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-overlay" id="modalTambah">
|
||||||
|
<div class="modal-box" style="max-width:480px">
|
||||||
|
<div class="modal-head">
|
||||||
|
<h3><i class="fa fa-user-plus" style="color:#7c3aed"></i> Tambah User Baru</h3>
|
||||||
|
<button class="btn-close" onclick="closeModal('modalTambah')">✕</button>
|
||||||
|
</div>
|
||||||
|
<form method="POST" action="proses.php" onsubmit="return validasiPassword('modalTambah')">
|
||||||
|
<input type="hidden" name="aksi" value="tambah_user">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group"><label>Nama Lengkap *</label><input class="form-control" name="nama_lengkap" required placeholder="Nama lengkap pengguna"></div>
|
||||||
|
<div class="form-grid-2">
|
||||||
|
<div class="form-group"><label>Username *</label><input class="form-control" name="username" required placeholder="username unik"></div>
|
||||||
|
<div class="form-group"><label>Role *</label>
|
||||||
|
<select class="form-control" name="role">
|
||||||
|
<option value="relawan">🙋 Relawan</option>
|
||||||
|
<option value="pengurus">🕌 Pengurus Ibadah</option>
|
||||||
|
<option value="pemerintah">🏛️ Pemerintah</option>
|
||||||
|
<option value="admin">🛡️ Admin</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group"><label>Email *</label><input class="form-control" type="email" name="email" required placeholder="email@domain.com"></div>
|
||||||
|
<div class="form-grid-2">
|
||||||
|
<div class="form-group"><label>Password *</label><input class="form-control" type="password" name="password" required placeholder="Min. 6 karakter" minlength="6"></div>
|
||||||
|
<div class="form-group"><label>Konfirmasi Password *</label><input class="form-control" type="password" name="password2" required placeholder="Ulangi password"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-foot">
|
||||||
|
<button type="button" class="btn btn-ghost" onclick="closeModal('modalTambah')">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-purple"><i class="fa fa-save"></i> Buat Akun</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-overlay" id="modalEdit">
|
||||||
|
<div class="modal-box" style="max-width:480px">
|
||||||
|
<div class="modal-head">
|
||||||
|
<h3><i class="fa fa-edit" style="color:#2563eb"></i> Edit User</h3>
|
||||||
|
<button class="btn-close" onclick="closeModal('modalEdit')">✕</button>
|
||||||
|
</div>
|
||||||
|
<form method="POST" action="proses.php">
|
||||||
|
<input type="hidden" name="aksi" value="edit_user">
|
||||||
|
<input type="hidden" name="id" id="eu_id">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="form-group"><label>Nama Lengkap *</label><input class="form-control" name="nama_lengkap" id="eu_nama" required></div>
|
||||||
|
<div class="form-grid-2">
|
||||||
|
<div class="form-group"><label>Username *</label><input class="form-control" name="username" id="eu_username" required></div>
|
||||||
|
<div class="form-group"><label>Role</label>
|
||||||
|
<select class="form-control" name="role" id="eu_role">
|
||||||
|
<option value="relawan">🙋 Relawan</option>
|
||||||
|
<option value="pengurus">🕌 Pengurus Ibadah</option>
|
||||||
|
<option value="pemerintah">🏛️ Pemerintah</option>
|
||||||
|
<option value="admin">🛡️ Admin</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group"><label>Email *</label><input class="form-control" type="email" name="email" id="eu_email" required></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-foot">
|
||||||
|
<button type="button" class="btn btn-ghost" onclick="closeModal('modalEdit')">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="fa fa-save"></i> Simpan</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-overlay" id="modalReset">
|
||||||
|
<div class="modal-box" style="max-width:400px">
|
||||||
|
<div class="modal-head">
|
||||||
|
<h3><i class="fa fa-key" style="color:#ea580c"></i> Reset Password</h3>
|
||||||
|
<button class="btn-close" onclick="closeModal('modalReset')">✕</button>
|
||||||
|
</div>
|
||||||
|
<form method="POST" action="proses.php" onsubmit="return validasiPassword('modalReset')">
|
||||||
|
<input type="hidden" name="aksi" value="reset_password">
|
||||||
|
<input type="hidden" name="id" id="rp_id">
|
||||||
|
<div class="modal-body">
|
||||||
|
<p style="font-size:13px;color:#64748b;margin-bottom:16px">Reset password untuk: <strong id="rp_nama"></strong></p>
|
||||||
|
<div class="form-group"><label>Password Baru *</label><input class="form-control" type="password" name="password_baru" required placeholder="Min. 6 karakter" minlength="6"></div>
|
||||||
|
<div class="form-group"><label>Konfirmasi *</label><input class="form-control" type="password" name="password_baru2" required placeholder="Ulangi password"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-foot">
|
||||||
|
<button type="button" class="btn btn-ghost" onclick="closeModal('modalReset')">Batal</button>
|
||||||
|
<button type="submit" class="btn btn-warning"><i class="fa fa-key"></i> Reset</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function openModal(id) {
|
||||||
|
const modal = document.getElementById(id);
|
||||||
|
if(modal) {
|
||||||
|
modal.style.display = 'flex';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal(id) {
|
||||||
|
const modal = document.getElementById(id);
|
||||||
|
if(modal) {
|
||||||
|
modal.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function editUser(data) {
|
||||||
|
document.getElementById('eu_id').value = data.id;
|
||||||
|
document.getElementById('eu_nama').value = data.nama_lengkap;
|
||||||
|
document.getElementById('eu_username').value = data.username;
|
||||||
|
document.getElementById('eu_email').value = data.email;
|
||||||
|
document.getElementById('eu_role').value = data.role;
|
||||||
|
|
||||||
|
openModal('modalEdit');
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetPassword(id, nama) {
|
||||||
|
document.getElementById('rp_id').value = id;
|
||||||
|
document.getElementById('rp_nama').innerText = nama;
|
||||||
|
|
||||||
|
openModal('modalReset');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hapusUser(id) {
|
||||||
|
if (confirm('Apakah Anda yakin ingin menghapus user ini secara permanen?')) {
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.method = 'POST';
|
||||||
|
form.action = 'proses.php';
|
||||||
|
|
||||||
|
form.innerHTML = `
|
||||||
|
<input type="hidden" name="aksi" value="hapus_user">
|
||||||
|
<input type="hidden" name="id" value="${id}">
|
||||||
|
`;
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleAktif(id, statusSekarang) {
|
||||||
|
const pesan = statusSekarang ? 'menonaktifkan' : 'mengaktifkan';
|
||||||
|
if (confirm(`Apakah Anda yakin ingin ${pesan} akun ini?`)) {
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.method = 'POST';
|
||||||
|
form.action = 'proses.php';
|
||||||
|
|
||||||
|
form.innerHTML = `
|
||||||
|
<input type="hidden" name="aksi" value="toggle_aktif">
|
||||||
|
<input type="hidden" name="id" value="${id}">
|
||||||
|
<input type="hidden" name="aktif" value="${statusSekarang ? 0 : 1}">
|
||||||
|
`;
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validasiPassword(modalId) {
|
||||||
|
let p1, p2;
|
||||||
|
if(modalId === 'modalTambah') {
|
||||||
|
p1 = document.querySelector('#modalTambah input[name="password"]').value;
|
||||||
|
p2 = document.querySelector('#modalTambah input[name="password2"]').value;
|
||||||
|
} else {
|
||||||
|
p1 = document.querySelector('#modalReset input[name="password_baru"]').value;
|
||||||
|
p2 = document.querySelector('#modalReset input[name="password_baru2"]').value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p1 !== p2) {
|
||||||
|
alert('Konfirmasi password tidak cocok! Silakan periksa kembali.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menutup modal jika pengguna mengklik area luar modal-box
|
||||||
|
window.onclick = function(event) {
|
||||||
|
if (event.target.classList.contains('modal-overlay')) {
|
||||||
|
event.target.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
include 'includes/footer.php';
|
||||||
|
?>
|
||||||
Reference in New Issue
Block a user