feat: add dashboard feature with modular API endpoints and UI integration

This commit is contained in:
Syariffullah
2026-06-11 09:17:48 +07:00
parent b77d4f6869
commit db3ff299c1
13 changed files with 1054 additions and 17 deletions
+37 -9
View File
@@ -36,6 +36,18 @@ function makeMiskinIcon(inRadius) {
let ibadahDataList = [];
let miskinMarkerList = []; // Simpan referensi marker untuk update warna
// Helper: cek apakah koordinat (lat, lng) berada dalam radius ibadah pengelola yang login
function isInMyIbadahRadius(lat, lng) {
if (!window.currentUser || window.currentUser.role !== 'pengelola') return true; // admin selalu bisa
const myIbadahId = window.currentUser.ibadah_id;
if (!myIbadahId) return false;
const ib = ibadahDataList.find(i => i.id == myIbadahId);
if (!ib) return false;
const dist = L.latLng(lat, lng).distanceTo(L.latLng(ib.lat, ib.lng));
return dist <= ib.radius;
}
window.isInMyIbadahRadius = isInMyIbadahRadius;
let isResizing = false;
let resizingCircle = null;
let resizingIbadah = null;
@@ -177,8 +189,22 @@ function addIbadahMarker(item) {
// Konteks Menu untuk Tambah Penduduk Miskin (klik kanan peta)
map.on('contextmenu', function(e) {
const canManage = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
if (!canManage) return;
const isAdminOrPengelola = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
if (!isAdminOrPengelola) return;
const canAddHere = isInMyIbadahRadius(e.latlng.lat, e.latlng.lng);
if (!canAddHere) {
// Pengelola: lokasi di luar radius ibadahnya
const warnContent = `
<div class="popup-form">
<h4>⚠️ Di Luar Radius</h4>
<p style="font-size:12px; color:#e11d48; margin:4px 0 0;">Anda hanya dapat menambah penduduk miskin di dalam radius rumah ibadah yang Anda kelola.</p>
</div>
`;
L.popup().setLatLng(e.latlng).setContent(warnContent).openOn(map);
return;
}
const popupContent = `
<div class="popup-form">
@@ -397,7 +423,9 @@ function addMiskinMarker(item) {
const lng = parseFloat(item.lng);
if (isNaN(lat) || isNaN(lng)) return;
const canManage = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
// Pengelola hanya bisa manage marker yang ada di dalam radius ibadahnya
const isAdminOrPengelola = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
const canManage = isAdminOrPengelola && isInMyIbadahRadius(lat, lng);
const marker = L.marker([lat, lng], { icon: makeMiskinIcon(false), draggable: canManage });
marker.miskinData = item;
@@ -475,8 +503,8 @@ window.formAddMiskin = function(lat, lng) {
<label>Lat: ${lat.toFixed(6)}, Lng: ${lng.toFixed(6)}</label>
</div>
<div class="form-group">
<label>Nama Penduduk</label>
<input type="text" id="miskinNama" placeholder="Nama Lengkap">
<label>Nama Kepala Keluarga</label>
<input type="text" id="miskinNama" placeholder="Nama Kepala Keluarga">
</div>
<div class="form-group">
<label>Kategori Bantuan</label>
@@ -510,7 +538,7 @@ window.saveNewMiskin = function(lat, lng) {
const fotoRumahInput = document.getElementById('miskinFotoRumah');
const fotoKKInput = document.getElementById('miskinFotoKK');
if (!nama) { alert('Nama harus diisi!'); return; }
if (!nama) { alert('Nama kepala keluarga harus diisi!'); return; }
const formData = new FormData();
formData.append('nama', nama);
@@ -543,7 +571,7 @@ window.openEditMiskinModal = function(id) {
const bodyHTML = `
<div class="form-group">
<label>Nama Penduduk</label>
<label>Nama Kepala Keluarga</label>
<input type="text" id="editMiskinNama" value="${d.nama}">
</div>
<div class="form-group">
@@ -679,7 +707,7 @@ window.openImportMiskinModal = function() {
<table style="width:100%; border-collapse:collapse; font-size:11px; text-align:left;">
<thead>
<tr style="background:#f1f5f9; border-bottom:1px solid #cbd5e1; color:#475569; position: sticky; top: 0;">
<th style="padding:6px 8px;">Nama</th>
<th style="padding:6px 8px;">Kepala Keluarga</th>
<th style="padding:6px 8px;">Kategori</th>
<th style="padding:6px 8px;">Jiwa</th>
<th style="padding:6px 8px;">Koordinat</th>
@@ -845,7 +873,7 @@ function handleImportFileChange(e) {
parsedImportData = validRows;
if (validRows.length === 0) {
errorMsg.textContent = "Tidak ditemukan data valid (pastikan kolom nama, lat, dan lng terisi).";
errorMsg.textContent = "Tidak ditemukan data valid (pastikan kolom nama_kk/nama, lat, dan lng terisi).";
errorMsg.style.display = 'block';
return;
}