Add authentication, roles, dashboard and access control

This commit is contained in:
SatryaIrvannurYudha
2026-06-06 22:02:14 +07:00
parent 02ec3dab8a
commit 15c5ae63d7
17 changed files with 612 additions and 17 deletions
+116 -5
View File
@@ -1,3 +1,10 @@
<?php
include 'auth.php';
include 'koneksi.php';
$userRole = getUserRole();
$userIbadahId = getUserIbadahId();
$isAdmin = isAdminPemerintah();
?>
<!DOCTYPE html>
<html lang="id">
<head>
@@ -160,12 +167,15 @@
<button class="btn-mode active" id="btn-view" onclick="setMode('view')">
<i class="bi bi-eye-fill"></i> Mode Lihat
</button>
<button class="btn-mode" id="btn-ibadah" onclick="setMode('ibadah')">
<i class="bi bi-building-fill" style="color:#6fffe9"></i> Tambah Rumah Ibadah
</button>
<?php if($isAdmin): ?>
<button class="btn-mode" id="btn-penduduk" onclick="setMode('penduduk')">
<i class="bi bi-person-fill" style="color:#f39c12"></i> Tambah Penduduk
</button>
<?php else: ?>
<button class="btn-mode" id="btn-ibadah" onclick="setMode('ibadah')">
<i class="bi bi-building-fill" style="color:#6fffe9"></i> Tambah Rumah Ibadah
</button>
<?php endif; ?>
<hr class="divider">
<p class="section-label">Legenda</p>
<div class="legend">
@@ -178,6 +188,13 @@
<button class="btn-mode" onclick="loadData()" style="color:#6fffe9;">
<i class="bi bi-arrow-clockwise"></i> Refresh Data
</button>
<hr class="divider">
<a href="dashboard.php" class="btn-mode" style="text-decoration:none;">
<i class="bi bi-speedometer2" style="color:#f39c12"></i> Dashboard
</a>
<a href="logout.php" class="btn-mode" style="text-decoration:none;" onclick="return confirm('Yakin ingin logout?')">
<i class="bi bi-box-arrow-right" style="color:#e74c3c"></i> Logout
</a>
</div>
</div>
@@ -205,6 +222,11 @@
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@6/turf.min.js"></script>
<script>
// ===== ROLE CONFIG (dari PHP) =====
const USER_ROLE = '<?= $userRole ?>';
const USER_IBADAH_ID = <?= $userIbadahId ? $userIbadahId : 'null' ?>;
const IS_ADMIN = <?= $isAdmin ? 'true' : 'false' ?>;
// ===== INIT MAP =====
const map = L.map('map', { zoomControl: false }).setView([-0.0263, 109.3425], 13);
L.control.zoom({ position: 'bottomright' }).addTo(map);
@@ -308,13 +330,27 @@ function renderIbadah() {
fillOpacity: 0.08, weight: 1.5, dashArray: '6,4'
});
// Tombol ubah radius: hanya admin_ibadah (pemilik)
const canEditRadius = (!IS_ADMIN && USER_IBADAH_ID === d.id);
const radiusBtn = canEditRadius ? `
<label class="f-label" style="margin-top:12px">Ubah Radius (meter)</label>
<div style="display:flex;gap:8px">
<input type="number" id="edit-radius-${d.id}" class="f-input" value="${d.radius}" min="50" max="50000" style="margin-bottom:0;flex:1">
<button class="btn-submit" style="width:auto;padding:0 16px" onclick="updateRadius(${d.id})"><i class="bi bi-check-lg"></i></button>
</div>` : '';
// Tombol hapus: hanya admin_ibadah (pemilik) yang bisa menghapus
const hapusBtn = (!IS_ADMIN && USER_IBADAH_ID === d.id) ? `
<button class="btn-submit" style="background: rgba(231,76,60,0.1); color: #e74c3c; border: 1px solid #e74c3c; margin-top: 12px; box-shadow: none;" onclick="hapusData('ibadah', ${d.id})"><i class="bi bi-trash"></i> Hapus Rumah Ibadah</button>` : '';
marker.bindPopup(`
<div class="p-header"><i class="bi bi-building-fill"></i> Rumah Ibadah</div>
<div class="p-body">
<div class="info-row"><span class="key">Nama</span><span class="val">${d.nama_ibadah}</span></div>
<div class="info-row"><span class="key">Radius</span><span class="val">${d.radius.toLocaleString()} m</span></div>
<div class="info-row"><span class="key">Koordinat</span><span class="val">${d.latitude.toFixed(5)}, ${d.longitude.toFixed(5)}</span></div>
<button class="btn-submit" style="background: rgba(231,76,60,0.1); color: #e74c3c; border: 1px solid #e74c3c; margin-top: 12px; box-shadow: none;" onclick="hapusData('ibadah', ${d.id})"><i class="bi bi-trash"></i> Hapus Rumah Ibadah</button>
${radiusBtn}
${hapusBtn}
</div>
`);
@@ -333,13 +369,27 @@ function renderPenduduk() {
? '<span class="badge-warna badge-hijau">Tercakup</span>'
: '<span class="badge-warna badge-merah">Belum Tercakup</span>';
// Tombol hapus: hanya admin_pemerintah
const hapusBtn = IS_ADMIN ? `
<button class="btn-submit" style="background: rgba(231,76,60,0.1); color: #e74c3c; border: 1px solid #e74c3c; margin-top: 12px; box-shadow: none;" onclick="hapusData('penduduk', ${d.id})"><i class="bi bi-trash"></i> Hapus Data Penduduk</button>` : '';
// Tombol konfirmasi bantuan: admin_ibadah saja, hanya penduduk tercakup
const bantuanStatus = d.status_bantuan || 'Belum';
const bantuanBadge = bantuanStatus === 'Sudah'
? '<span class="badge-warna badge-hijau">Sudah Disalurkan</span>'
: '<span class="badge-warna badge-merah">Belum Disalurkan</span>';
const konfirmasiBtn = (!IS_ADMIN && d.status_warna === 'Hijau' && bantuanStatus === 'Belum') ? `
<button class="btn-submit" style="background: rgba(46,204,113,0.1); color: #2ecc71; border: 1px solid #2ecc71; margin-top: 8px; box-shadow: none;" onclick="konfirmasiBantuan(${d.id})"><i class="bi bi-check-circle"></i> Konfirmasi Bantuan</button>` : '';
marker.bindPopup(`
<div class="p-header"><i class="bi bi-person-fill"></i> Data Penduduk</div>
<div class="p-body">
<div class="info-row"><span class="key">Nama</span><span class="val">${d.nama_penduduk}</span></div>
<div class="info-row"><span class="key">Status</span>${badge}</div>
<div class="info-row"><span class="key">Bantuan</span>${bantuanBadge}</div>
<div class="info-row"><span class="key">Koordinat</span><span class="val">${d.latitude.toFixed(5)}, ${d.longitude.toFixed(5)}</span></div>
<button class="btn-submit" style="background: rgba(231,76,60,0.1); color: #e74c3c; border: 1px solid #e74c3c; margin-top: 12px; box-shadow: none;" onclick="hapusData('penduduk', ${d.id})"><i class="bi bi-trash"></i> Hapus Data Penduduk</button>
${hapusBtn}
${konfirmasiBtn}
</div>
`);
layerPenduduk.addLayer(marker);
@@ -531,6 +581,67 @@ async function simpanPenduduk(lat, lng) {
}
}
// ===== UPDATE RADIUS =====
async function updateRadius(id) {
const input = document.getElementById('edit-radius-' + id);
const radius = parseInt(input?.value);
if (!radius || radius < 50) { showToast('<i class="bi bi-exclamation"></i> Radius minimal 50m!', '#e74c3c'); return; }
try {
const fd = new FormData();
fd.append('action', 'update_radius');
fd.append('id', id);
fd.append('radius', radius);
const res = await fetch('ambil.php', { method: 'POST', body: fd });
const text = await res.text();
try {
const data = JSON.parse(text);
if (data.status === 'success') {
map.closePopup();
showToast(`<i class="bi bi-check-circle-fill"></i> ${data.message}`, '#2ecc71');
await loadData();
} else {
showToast(`<i class="bi bi-x-circle"></i> ${data.message}`, '#e74c3c');
}
} catch(e) {
showToast(`<i class="bi bi-bug"></i> Error Server`, '#e74c3c');
}
} catch(e) {
showToast('<i class="bi bi-wifi-off"></i> Gagal update radius', '#e74c3c');
}
}
// ===== KONFIRMASI BANTUAN =====
async function konfirmasiBantuan(id) {
if(!confirm("Konfirmasi bahwa bantuan telah disalurkan?")) return;
try {
const fd = new FormData();
fd.append('action', 'konfirmasi_bantuan');
fd.append('id', id);
const res = await fetch('ambil.php', { method: 'POST', body: fd });
const text = await res.text();
try {
const data = JSON.parse(text);
if (data.status === 'success') {
map.closePopup();
showToast(`<i class="bi bi-check-circle-fill"></i> ${data.message}`, '#2ecc71');
await loadData();
} else {
showToast(`<i class="bi bi-x-circle"></i> ${data.message}`, '#e74c3c');
}
} catch(e) {
showToast(`<i class="bi bi-bug"></i> Error Server`, '#e74c3c');
}
} catch(e) {
showToast('<i class="bi bi-wifi-off"></i> Gagal konfirmasi bantuan', '#e74c3c');
}
}
// ===== BOOT =====
loadData();
</script>