Update
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -77,7 +77,7 @@
|
||||
if (dashboardBtn) dashboardBtn.style.display = 'flex';
|
||||
|
||||
// Show user management button in sidebar for Admin
|
||||
const adminDivider = document.getElementById('sidebarAdminDivider');
|
||||
const adminDivider = document.getElementById('adminNavLabel');
|
||||
if (window.currentUser.role === 'admin') {
|
||||
if (menuUsersBtn) menuUsersBtn.style.display = 'flex';
|
||||
if (adminDivider) adminDivider.style.display = 'block';
|
||||
@@ -93,7 +93,7 @@
|
||||
document.getElementById('authLoginBtn').addEventListener('click', showLoginModal);
|
||||
if (menuUsersBtn) menuUsersBtn.style.display = 'none';
|
||||
if (dashboardBtn) dashboardBtn.style.display = 'none';
|
||||
const adminDivider = document.getElementById('sidebarAdminDivider');
|
||||
const adminDivider = document.getElementById('adminNavLabel');
|
||||
if (adminDivider) adminDivider.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ geoBtn.style.left = '0';
|
||||
geoBtn.style.right = 'auto';
|
||||
geoBtn.innerHTML = '<i class="fas fa-crosshairs fa-lg"></i>';
|
||||
geoBtn.title = 'Lokasi Saya';
|
||||
document.querySelector('.custom-zoom-control').appendChild(geoBtn);
|
||||
const zoomContainer = document.querySelector('.zoom-controls');
|
||||
if (zoomContainer) zoomContainer.appendChild(geoBtn);
|
||||
|
||||
let userMarker = null;
|
||||
|
||||
|
||||
@@ -444,8 +444,8 @@ function addMiskinMarker(item) {
|
||||
photoLinksHtml += `
|
||||
<div style="margin: 5px 0;">
|
||||
<b style="font-size:11px;">Foto Rumah:</b><br>
|
||||
<a href="/poverty/uploads/${d.foto_rumah}" target="_blank">
|
||||
<img src="/poverty/uploads/${d.foto_rumah}" alt="Foto Rumah"
|
||||
<a href="uploads/${d.foto_rumah}" target="_blank">
|
||||
<img src="uploads/${d.foto_rumah}" alt="Foto Rumah"
|
||||
style="max-width:150px; max-height:100px; border-radius:4px; margin-top:3px; border:1px solid #ddd; object-fit:cover; cursor:pointer;"
|
||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';"/>
|
||||
<span style="display:none; font-size:11px; color:#ef4444;">❌ Foto tidak dapat dimuat</span>
|
||||
@@ -456,8 +456,8 @@ function addMiskinMarker(item) {
|
||||
photoLinksHtml += `
|
||||
<div style="margin: 5px 0;">
|
||||
<b style="font-size:11px;">Foto KK:</b><br>
|
||||
<a href="/poverty/uploads/${d.foto_kk}" target="_blank">
|
||||
<img src="/poverty/uploads/${d.foto_kk}" alt="Foto KK"
|
||||
<a href="uploads/${d.foto_kk}" target="_blank">
|
||||
<img src="uploads/${d.foto_kk}" alt="Foto KK"
|
||||
style="max-width:150px; max-height:100px; border-radius:4px; margin-top:3px; border:1px solid #ddd; object-fit:cover; cursor:pointer;"
|
||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';"/>
|
||||
<span style="display:none; font-size:11px; color:#ef4444;">❌ Foto tidak dapat dimuat</span>
|
||||
@@ -590,8 +590,8 @@ window.openEditMiskinModal = function(id) {
|
||||
<input type="file" id="editMiskinFotoRumah" accept="image/*">
|
||||
${d.foto_rumah ? `
|
||||
<div style="margin-top:5px;">
|
||||
<a href="/poverty/uploads/${d.foto_rumah}" target="_blank">
|
||||
<img src="/poverty/uploads/${d.foto_rumah}" alt="Foto Rumah" style="max-width:120px; max-height:80px; border-radius:4px; border:1px solid #ddd; object-fit:cover;"
|
||||
<a href="uploads/${d.foto_rumah}" target="_blank">
|
||||
<img src="uploads/${d.foto_rumah}" alt="Foto Rumah" style="max-width:120px; max-height:80px; border-radius:4px; border:1px solid #ddd; object-fit:cover;"
|
||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';"/>
|
||||
<span style="display:none; font-size:11px; color:#ef4444;">❌ File gambar rusak atau tidak ditemukan</span>
|
||||
</a>
|
||||
@@ -603,8 +603,8 @@ window.openEditMiskinModal = function(id) {
|
||||
<input type="file" id="editMiskinFotoKK" accept="image/*">
|
||||
${d.foto_kk ? `
|
||||
<div style="margin-top:5px;">
|
||||
<a href="/poverty/uploads/${d.foto_kk}" target="_blank">
|
||||
<img src="/poverty/uploads/${d.foto_kk}" alt="Foto KK" style="max-width:120px; max-height:80px; border-radius:4px; border:1px solid #ddd; object-fit:cover;"
|
||||
<a href="uploads/${d.foto_kk}" target="_blank">
|
||||
<img src="uploads/${d.foto_kk}" alt="Foto KK" style="max-width:120px; max-height:80px; border-radius:4px; border:1px solid #ddd; object-fit:cover;"
|
||||
onerror="this.style.display='none'; this.nextElementSibling.style.display='inline';"/>
|
||||
<span style="display:none; font-size:11px; color:#ef4444;">❌ File gambar rusak atau tidak ditemukan</span>
|
||||
</a>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// ============================================================
|
||||
// WebGIS Kemiskinan Pontianak — map.js (Redesign)
|
||||
// ============================================================
|
||||
|
||||
// Inisialisasi Peta
|
||||
// Koordinat awal: [-0.0263, 109.3425] (Pontianak)
|
||||
const map = L.map('map', { zoomControl: false }).setView([-0.0263, 109.3425], 13);
|
||||
|
||||
// ===== Toast Notification =====
|
||||
@@ -7,86 +10,94 @@ window.showToast = function(message, type = 'success', duration = 3500) {
|
||||
const icons = { success: '✅', error: '❌', info: 'ℹ️', warning: '⚠️' };
|
||||
const container = document.getElementById('toastContainer');
|
||||
if (!container) return;
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.innerHTML = `<span class="toast-icon">${icons[type] || 'ℹ️'}</span><span>${message}</span>`;
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.add('hiding');
|
||||
toast.addEventListener('animationend', () => toast.remove());
|
||||
}, duration);
|
||||
};
|
||||
|
||||
// Custom Zoom Control Logic
|
||||
document.getElementById('zoomInBtn').addEventListener('click', function() { map.zoomIn(); });
|
||||
document.getElementById('zoomOutBtn').addEventListener('click', function() { map.zoomOut(); });
|
||||
// ===== Zoom Controls =====
|
||||
document.getElementById('zoomInBtn').addEventListener('click', () => map.zoomIn());
|
||||
document.getElementById('zoomOutBtn').addEventListener('click', () => map.zoomOut());
|
||||
|
||||
// Base Map dari OpenStreetMap
|
||||
// ===== Base Map =====
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
}).addTo(map);
|
||||
|
||||
// Inisialisasi FeatureGroups untuk masing-masing layer
|
||||
const rumahIbadahLayer = L.featureGroup().addTo(map);
|
||||
// ===== Feature Groups =====
|
||||
const rumahIbadahLayer = L.featureGroup().addTo(map);
|
||||
const pendudukMiskinLayer = L.featureGroup().addTo(map);
|
||||
const geoJsonLayer = L.featureGroup().addTo(map);
|
||||
const geoJsonLayer = L.featureGroup().addTo(map);
|
||||
|
||||
// ===== Sidebar Collapse =====
|
||||
const collapseBtn = document.getElementById('sidebarCollapseBtn');
|
||||
const collapseIcon = document.getElementById('collapseIcon');
|
||||
|
||||
if (collapseBtn) {
|
||||
collapseBtn.addEventListener('click', function() {
|
||||
const collapsed = document.body.classList.toggle('sidebar-collapsed');
|
||||
if (collapseIcon) collapseIcon.className = collapsed ? 'fas fa-chevron-right' : 'fas fa-chevron-left';
|
||||
setTimeout(() => map.invalidateSize(), 320);
|
||||
});
|
||||
}
|
||||
|
||||
// ===== Search =====
|
||||
const searchInput = document.getElementById('searchInput');
|
||||
const searchClear = document.getElementById('searchClear');
|
||||
const searchResultsEl = document.getElementById('searchResults');
|
||||
|
||||
searchInput.addEventListener('focus', function() {
|
||||
searchInput.addEventListener('focus', () => {
|
||||
if (typeof window.deactivateAddMode === 'function') window.deactivateAddMode();
|
||||
});
|
||||
|
||||
searchInput.addEventListener('input', function() {
|
||||
const val = this.value.toLowerCase();
|
||||
const val = this.value.toLowerCase().trim();
|
||||
if (val.length > 0) {
|
||||
searchClear.style.visibility = 'visible';
|
||||
window.showSearchResults(val);
|
||||
} else {
|
||||
searchClear.style.visibility = 'hidden';
|
||||
document.getElementById('searchResults').style.display = 'none';
|
||||
searchResultsEl.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
searchClear.addEventListener('click', function() {
|
||||
searchInput.value = '';
|
||||
searchClear.style.visibility = 'hidden';
|
||||
document.getElementById('searchResults').style.display = 'none';
|
||||
searchResultsEl.style.display = 'none';
|
||||
searchInput.focus();
|
||||
});
|
||||
|
||||
window.showSearchResults = function(query) {
|
||||
const resultsContainer = document.getElementById('searchResults');
|
||||
resultsContainer.innerHTML = '';
|
||||
let results = [];
|
||||
|
||||
document.addEventListener('click', function(e) {
|
||||
if (!e.target.closest('.search-bar') && !e.target.closest('#searchResults')) {
|
||||
searchResultsEl.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
window.showSearchResults = function(query) {
|
||||
searchResultsEl.innerHTML = '';
|
||||
let results = [];
|
||||
|
||||
|
||||
if (typeof rumahIbadahLayer !== 'undefined') {
|
||||
rumahIbadahLayer.eachLayer(layer => {
|
||||
if (layer.ibadahData && layer.ibadahData.nama && layer.ibadahData.nama.toLowerCase().includes(query)) {
|
||||
if(layer instanceof L.Marker) {
|
||||
results.push({ type: 'Rumah Ibadah', nama: layer.ibadahData.nama, layer: layer });
|
||||
}
|
||||
if (layer.ibadahData?.nama?.toLowerCase().includes(query) && layer instanceof L.Marker) {
|
||||
results.push({ type: 'Rumah Ibadah', icon: '🕌', nama: layer.ibadahData.nama, layer });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (results.length === 0) {
|
||||
resultsContainer.innerHTML = '<div style="padding: 10px 15px; color: #666; font-size: 14px;">Tidak ada hasil</div>';
|
||||
searchResultsEl.innerHTML = '<div class="search-result-item" style="color:#94a3b8;">Tidak ada hasil ditemukan</div>';
|
||||
} else {
|
||||
results.forEach(res => {
|
||||
const item = document.createElement('div');
|
||||
item.style.padding = '10px 15px';
|
||||
item.style.cursor = 'pointer';
|
||||
item.style.borderBottom = '1px solid #eee';
|
||||
item.style.fontSize = '14px';
|
||||
item.innerHTML = `<strong>${res.type}:</strong> ${res.nama}`;
|
||||
item.addEventListener('mouseenter', () => item.style.backgroundColor = '#f8f9fa');
|
||||
item.addEventListener('mouseleave', () => item.style.backgroundColor = 'white');
|
||||
item.className = 'search-result-item';
|
||||
item.innerHTML = `<span>${res.icon}</span><span><strong style="font-size:10px; color:#94a3b8; text-transform:uppercase;">${res.type}</strong><br>${res.nama}</span>`;
|
||||
item.addEventListener('click', () => {
|
||||
if (res.layer instanceof L.Marker) {
|
||||
map.setView(res.layer.getLatLng(), 17);
|
||||
@@ -94,38 +105,40 @@ window.showSearchResults = function(query) {
|
||||
map.fitBounds(res.layer.getBounds());
|
||||
}
|
||||
res.layer.openPopup();
|
||||
resultsContainer.style.display = 'none';
|
||||
searchResultsEl.style.display = 'none';
|
||||
searchInput.value = res.nama;
|
||||
searchClear.style.visibility = 'visible';
|
||||
});
|
||||
resultsContainer.appendChild(item);
|
||||
searchResultsEl.appendChild(item);
|
||||
});
|
||||
}
|
||||
resultsContainer.style.display = 'block';
|
||||
searchResultsEl.style.display = 'block';
|
||||
};
|
||||
|
||||
// UI Logic: Custom Layer Control Toggle
|
||||
// ===== Layer Panel Toggle =====
|
||||
const layerBtn = document.getElementById('layerBtn');
|
||||
const layerPanel = document.getElementById('layerPanel');
|
||||
|
||||
layerBtn.addEventListener('click', function() {
|
||||
if (typeof window.deactivateAddMode === 'function') window.deactivateAddMode();
|
||||
layerPanel.style.display = layerPanel.style.display === 'block' ? 'none' : 'block';
|
||||
const isOpen = layerPanel.classList.toggle('show');
|
||||
layerBtn.classList.toggle('active', isOpen);
|
||||
});
|
||||
|
||||
// Sembunyikan layer panel saat klik di peta
|
||||
map.on('click', function() {
|
||||
layerPanel.style.display = 'none';
|
||||
layerPanel.classList.remove('show');
|
||||
layerBtn.classList.remove('active');
|
||||
});
|
||||
|
||||
|
||||
// Logic untuk Toggle Layer Visibility
|
||||
// ===== Layer Visibility =====
|
||||
document.getElementById('layerRumahIbadah').addEventListener('change', function(e) {
|
||||
e.target.checked ? map.addLayer(rumahIbadahLayer) : map.removeLayer(rumahIbadahLayer);
|
||||
});
|
||||
|
||||
document.getElementById('layerMiskin').addEventListener('change', function(e) {
|
||||
e.target.checked ? map.addLayer(pendudukMiskinLayer) : map.removeLayer(pendudukMiskinLayer);
|
||||
});
|
||||
|
||||
// --- Sub-layer Toggle (expand/collapse) ---
|
||||
window.toggleSubLayer = function(subId, iconEl) {
|
||||
const sub = document.getElementById(subId);
|
||||
if (!sub) return;
|
||||
@@ -134,87 +147,58 @@ window.toggleSubLayer = function(subId, iconEl) {
|
||||
iconEl.classList.toggle('collapsed', !isHidden);
|
||||
};
|
||||
|
||||
// --- Sub-layer Filter ---
|
||||
window.applySubFilter = function(type) {
|
||||
|
||||
if (type === 'miskin') {
|
||||
const checked = [...document.querySelectorAll('.sub-miskin:checked')].map(el => el.value);
|
||||
pendudukMiskinLayer.eachLayer(layer => {
|
||||
if (!layer.miskinData) return;
|
||||
if (checked.includes(layer.miskinData.kategori_bantuan)) {
|
||||
layer.getElement && layer.getElement() && (layer.getElement().style.display = '');
|
||||
} else {
|
||||
layer.getElement && layer.getElement() && (layer.getElement().style.display = 'none');
|
||||
}
|
||||
const el = layer.getElement?.();
|
||||
if (el) el.style.display = checked.includes(layer.miskinData.kategori_bantuan) ? '' : 'none';
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// --- Modal Logic ---
|
||||
// ===== Modal Logic =====
|
||||
const unifiedModal = document.getElementById('unifiedModal');
|
||||
const modalTitle = document.getElementById('modalTitle');
|
||||
const modalBody = document.getElementById('modalBody');
|
||||
|
||||
window.openModal = function(title, bodyHTML, saveCallback) {
|
||||
modalTitle.textContent = title;
|
||||
modalBody.innerHTML = bodyHTML;
|
||||
document.getElementById('modalTitle').textContent = title;
|
||||
document.getElementById('modalBody').innerHTML = bodyHTML;
|
||||
unifiedModal.classList.add('show');
|
||||
|
||||
// Ambil elemen tombol save terbaru dari DOM
|
||||
const currentSaveBtn = document.getElementById('modalSaveBtn');
|
||||
|
||||
// Clone untuk menghapus semua event listener lama
|
||||
const newSaveBtn = currentSaveBtn.cloneNode(true);
|
||||
currentSaveBtn.parentNode.replaceChild(newSaveBtn, currentSaveBtn);
|
||||
|
||||
newSaveBtn.addEventListener('click', saveCallback);
|
||||
|
||||
const oldBtn = document.getElementById('modalSaveBtn');
|
||||
const newBtn = oldBtn.cloneNode(true);
|
||||
oldBtn.parentNode.replaceChild(newBtn, oldBtn);
|
||||
newBtn.addEventListener('click', saveCallback);
|
||||
};
|
||||
|
||||
window.closeModal = function() {
|
||||
unifiedModal.classList.remove('show');
|
||||
};
|
||||
window.closeModal = function() { unifiedModal.classList.remove('show'); };
|
||||
|
||||
const confirmModal = document.getElementById('confirmModal');
|
||||
const confirmMessage = document.getElementById('confirmMessage');
|
||||
|
||||
window.openConfirmModal = function(msg, confirmCallback) {
|
||||
confirmMessage.textContent = msg;
|
||||
document.getElementById('confirmMessage').textContent = msg;
|
||||
confirmModal.classList.add('show');
|
||||
|
||||
const currentYesBtn = document.getElementById('confirmYesBtn');
|
||||
const newYesBtn = currentYesBtn.cloneNode(true);
|
||||
currentYesBtn.parentNode.replaceChild(newYesBtn, currentYesBtn);
|
||||
|
||||
newYesBtn.addEventListener('click', function() {
|
||||
|
||||
const oldBtn = document.getElementById('confirmYesBtn');
|
||||
const newBtn = oldBtn.cloneNode(true);
|
||||
oldBtn.parentNode.replaceChild(newBtn, oldBtn);
|
||||
newBtn.addEventListener('click', function() {
|
||||
confirmModal.classList.remove('show');
|
||||
confirmCallback();
|
||||
});
|
||||
};
|
||||
|
||||
window.closeConfirmModal = function() {
|
||||
confirmModal.classList.remove('show');
|
||||
};
|
||||
window.closeConfirmModal = function() { confirmModal.classList.remove('show'); };
|
||||
|
||||
// --- Action Menu Logic (replaced by left sidebar) ---
|
||||
|
||||
window.currentAddMode = null; // 'rumah_ibadah' atau 'miskin_click'
|
||||
// ===== Add Mode =====
|
||||
window.currentAddMode = null;
|
||||
|
||||
window.activateAddMode = function(mode) {
|
||||
// Toggle: jika mode yang sama diklik lagi, batalkan
|
||||
if (window.currentAddMode === mode) {
|
||||
window.deactivateAddMode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.currentAddMode === mode) { window.deactivateAddMode(); return; }
|
||||
window.currentAddMode = mode;
|
||||
|
||||
// Tooltip
|
||||
const tooltips = {
|
||||
'rumah_ibadah': 'Klik untuk Tambah Rumah Ibadah'
|
||||
};
|
||||
const tooltips = { 'rumah_ibadah': 'Klik peta untuk tambah Rumah Ibadah' };
|
||||
if (window.cursorTooltip && tooltips[mode]) window.cursorTooltip.textContent = tooltips[mode];
|
||||
|
||||
// Ubah kursor map menjadi crosshair
|
||||
document.getElementById('map').style.cursor = 'crosshair';
|
||||
};
|
||||
|
||||
@@ -224,18 +208,16 @@ window.deactivateAddMode = function() {
|
||||
if (window.cursorTooltip) window.cursorTooltip.style.display = 'none';
|
||||
};
|
||||
|
||||
// --- Custom Tooltip Cursor ---
|
||||
// ===== Cursor Tooltip =====
|
||||
window.cursorTooltip = document.createElement('div');
|
||||
window.cursorTooltip.className = 'custom-cursor-tooltip';
|
||||
document.body.appendChild(window.cursorTooltip);
|
||||
|
||||
// Gunakan document-level mousemove agar selalu terpicu
|
||||
// bahkan saat Leaflet Draw overlay aktif menangkap event map
|
||||
document.addEventListener('mousemove', function(e) {
|
||||
if (window.currentAddMode) {
|
||||
window.cursorTooltip.style.display = 'block';
|
||||
window.cursorTooltip.style.left = e.pageX + 15 + 'px';
|
||||
window.cursorTooltip.style.top = e.pageY + 15 + 'px';
|
||||
window.cursorTooltip.style.top = e.pageY + 15 + 'px';
|
||||
} else {
|
||||
window.cursorTooltip.style.display = 'none';
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
let activePanel = null;
|
||||
|
||||
// ---- Elements ----
|
||||
const sidebarToggleBtn = document.getElementById('sidebarToggleBtn');
|
||||
const sidebarToggleIcon = document.getElementById('sidebarToggleIcon');
|
||||
// removed
|
||||
// removed
|
||||
const leftSidebar = document.getElementById('leftSidebar');
|
||||
const rightPanel = document.getElementById('rightPanel');
|
||||
const rightPanelTitle = document.getElementById('rightPanelTitle');
|
||||
@@ -25,19 +25,7 @@
|
||||
const rightPanelBody = document.getElementById('rightPanelBody');
|
||||
const rightPanelClose = document.getElementById('rightPanelClose');
|
||||
|
||||
// ---- Sidebar Toggle ----
|
||||
sidebarToggleBtn.addEventListener('click', function () {
|
||||
const isOpen = leftSidebar.style.display !== 'none';
|
||||
if (isOpen) {
|
||||
leftSidebar.style.display = 'none';
|
||||
sidebarToggleBtn.classList.remove('open');
|
||||
sidebarToggleIcon.className = 'fas fa-chevron-right';
|
||||
} else {
|
||||
leftSidebar.style.display = 'flex';
|
||||
sidebarToggleBtn.classList.add('open');
|
||||
sidebarToggleIcon.className = 'fas fa-chevron-left';
|
||||
}
|
||||
});
|
||||
// Sidebar collapse handled in map.js
|
||||
|
||||
// ---- Sidebar Buttons ----
|
||||
document.querySelectorAll('.sidebar-btn').forEach(btn => {
|
||||
@@ -83,8 +71,9 @@
|
||||
rightPanelActions.innerHTML = '';
|
||||
|
||||
switch (type) {
|
||||
case 'ibadah': renderIbadahPanel(); break;
|
||||
case 'miskin': renderMiskinPanel(); break;
|
||||
case 'ibadah': renderIbadahPanel(); break;
|
||||
case 'miskin': renderMiskinPanel(); break;
|
||||
case 'log_bantuan': renderLogBantuanPanel(); break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +227,59 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==========================
|
||||
// ===== Log Bantuan Panel ==
|
||||
// ==========================
|
||||
function renderLogBantuanPanel() {
|
||||
rightPanelTitle.textContent = '📋 Log Bantuan';
|
||||
rightPanelActions.innerHTML = '';
|
||||
const all = [];
|
||||
if (typeof pendudukMiskinLayer !== 'undefined') {
|
||||
pendudukMiskinLayer.eachLayer(l => { if (l.miskinData) all.push(l.miskinData); });
|
||||
}
|
||||
if (!all.length) {
|
||||
rightPanelBody.innerHTML = '<div class="panel-empty">Belum ada data penduduk miskin</div>';
|
||||
return;
|
||||
}
|
||||
rightPanelBody.innerHTML = '';
|
||||
const canLog = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
|
||||
|
||||
// Hint strip
|
||||
const hint = document.createElement('div');
|
||||
hint.className = 'panel-hint';
|
||||
hint.innerHTML = `<i class="fas fa-info-circle"></i> ${canLog ? 'Klik penduduk untuk lihat atau tambah log bantuan.' : 'Klik penduduk untuk melihat riwayat log bantuan.'}`;
|
||||
rightPanelBody.appendChild(hint);
|
||||
|
||||
// Summary badge
|
||||
const summary = document.createElement('div');
|
||||
summary.className = 'panel-section-title';
|
||||
summary.textContent = `${all.length} Kepala Keluarga`;
|
||||
rightPanelBody.appendChild(summary);
|
||||
|
||||
all.forEach(d => {
|
||||
const isMakan = d.kategori_bantuan === 'Makan';
|
||||
const card = document.createElement('div');
|
||||
card.className = 'log-person-card';
|
||||
const badgeHtml = isMakan
|
||||
? '<span class="data-card-badge badge-orange">Bantuan Makan</span>'
|
||||
: '<span class="data-card-badge badge-blue">Pemberdayaan</span>';
|
||||
const avatarCls = isMakan ? 'avatar-makan' : 'avatar-pmbr';
|
||||
card.innerHTML = `
|
||||
<div class="log-person-avatar ${avatarCls}">🏠</div>
|
||||
<div class="log-person-info">
|
||||
<div class="log-person-name">${escHtml(d.nama)}</div>
|
||||
<div class="log-person-meta">
|
||||
<span>👨👩👧 ${d.jumlah_jiwa || '-'} jiwa</span>
|
||||
${badgeHtml}
|
||||
</div>
|
||||
</div>
|
||||
<i class="fas fa-chevron-right log-person-arrow"></i>`;
|
||||
card.addEventListener('click', () => window.openLogBantuan(d.id, d.nama));
|
||||
rightPanelBody.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
function buildMiskinCard(d, terurus) {
|
||||
// Pengelola hanya boleh edit/hapus penduduk yang dalam radius ibadahnya
|
||||
const isPengelolaOrAdmin = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
|
||||
@@ -344,115 +386,140 @@
|
||||
}
|
||||
});
|
||||
|
||||
// ==========================
|
||||
// ===== Log Bantuan Modal ==
|
||||
// ==========================
|
||||
const logModal = document.getElementById('logBantuanModal');
|
||||
const logTitle = document.getElementById('logBantuanTitle');
|
||||
const logList = document.getElementById('logBantuanList');
|
||||
const logSaveBtn = document.getElementById('logSaveBtn');
|
||||
const logIbadahSel = document.getElementById('logIbadahId');
|
||||
let _logMiskinId = null;
|
||||
// ==========================================
|
||||
// ===== Log Bantuan Modal ==================
|
||||
// ==========================================
|
||||
|
||||
window.openLogBantuan = function (miskinId, nama) {
|
||||
_logMiskinId = miskinId;
|
||||
logTitle.textContent = `Log Bantuan — ${nama}`;
|
||||
logModal.classList.add('show');
|
||||
const modal = document.getElementById('logBantuanModal');
|
||||
document.getElementById('logBantuanTitle').textContent = '📋 Log Bantuan — ' + nama;
|
||||
document.getElementById('logBantuanMiskinId').value = miskinId;
|
||||
modal.classList.add('show');
|
||||
loadLogBantuan(miskinId);
|
||||
|
||||
const isAuth = !!window.currentUser;
|
||||
const formContainer = document.querySelector('#logBantuanModal .modal-body > div:last-child');
|
||||
const modalFooter = document.querySelector('#logBantuanModal .modal-footer');
|
||||
|
||||
if (isAuth) {
|
||||
if (formContainer) formContainer.style.display = 'block';
|
||||
if (modalFooter) modalFooter.style.display = 'flex';
|
||||
} else {
|
||||
if (formContainer) formContainer.style.display = 'none';
|
||||
if (modalFooter) modalFooter.style.display = 'none';
|
||||
}
|
||||
// Tampilkan form tambah hanya untuk admin/pengelola
|
||||
const canLog = !!(window.currentUser && (window.currentUser.role === 'admin' || window.currentUser.role === 'pengelola'));
|
||||
document.getElementById('logBantuanFormSection').style.display = canLog ? 'block' : 'none';
|
||||
|
||||
// Isi dropdown ibadah
|
||||
logIbadahSel.innerHTML = '<option value="">-- Pilih Rumah Ibadah --</option>';
|
||||
if (typeof ibadahDataList !== 'undefined') {
|
||||
ibadahDataList.forEach(ib => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = ib.id;
|
||||
opt.textContent = `${IBADAH_EMOJI[ib.jenis] || '🕌'} ${ib.nama}`;
|
||||
logIbadahSel.appendChild(opt);
|
||||
});
|
||||
}
|
||||
|
||||
if (window.currentUser && window.currentUser.role === 'pengelola') {
|
||||
logIbadahSel.value = window.currentUser.ibadah_id;
|
||||
logIbadahSel.disabled = true;
|
||||
} else {
|
||||
logIbadahSel.disabled = false;
|
||||
}
|
||||
|
||||
// Set tanggal default hari ini
|
||||
document.getElementById('logTanggal').valueAsDate = new Date();
|
||||
fetchLogBantuan(miskinId);
|
||||
// Isi dropdown ibadah jika pengelola (auto-select ibadahnya)
|
||||
if (canLog) populateLogIbadahSelect();
|
||||
};
|
||||
|
||||
window.closeLogBantuanModal = function () {
|
||||
logModal.classList.remove('show');
|
||||
_logMiskinId = null;
|
||||
document.getElementById('logBantuanModal').classList.remove('show');
|
||||
};
|
||||
|
||||
function fetchLogBantuan(miskinId) {
|
||||
logList.innerHTML = '<div class="panel-empty" style="padding:15px;">Memuat...</div>';
|
||||
fetch(`api/log_bantuan/read.php?miskin_id=${miskinId}`)
|
||||
function loadLogBantuan(miskinId) {
|
||||
const listEl = document.getElementById('logBantuanList');
|
||||
listEl.innerHTML = '<div class="panel-empty">Memuat log...</div>';
|
||||
fetch('api/log_bantuan/read.php?miskin_id=' + miskinId)
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (!data.data || !data.data.length) {
|
||||
logList.innerHTML = '<div class="panel-empty" style="padding:15px;">Belum ada riwayat bantuan</div>';
|
||||
.then(res => {
|
||||
if (res.status !== 'success' || !res.data.length) {
|
||||
listEl.innerHTML = '<div class="panel-empty">Belum ada log bantuan tercatat.</div>';
|
||||
return;
|
||||
}
|
||||
logList.innerHTML = '';
|
||||
data.data.forEach(log => {
|
||||
const tgl = new Date(log.tanggal).toLocaleDateString('id-ID', { day:'2-digit', month:'short', year:'numeric' });
|
||||
listEl.innerHTML = '';
|
||||
res.data.forEach(log => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'log-item';
|
||||
const tgl = new Date(log.tanggal).toLocaleDateString('id-ID', { day: '2-digit', month: 'short', year: 'numeric' });
|
||||
item.innerHTML = `
|
||||
<div class="log-dot"></div>
|
||||
<div class="log-info">
|
||||
<div class="log-type">${escHtml(log.tipe_bantuan)}</div>
|
||||
<div class="log-meta">${IBADAH_EMOJI[log.jenis_ibadah] || '🕌'} ${escHtml(log.nama_ibadah)} • ${tgl}</div>
|
||||
${log.keterangan ? `<div class="log-keterangan">${escHtml(log.keterangan)}</div>` : ''}
|
||||
</div>`;
|
||||
logList.appendChild(item);
|
||||
<div class="log-item-header">
|
||||
<span class="log-tipe-badge"><i class="fas fa-hand-holding-heart" style="margin-right:4px;font-size:10px;"></i>${escHtml(log.tipe_bantuan)}</span>
|
||||
<span class="log-tgl"><i class="fas fa-calendar-alt"></i>${tgl}</span>
|
||||
</div>
|
||||
<div class="log-ibadah"><span>🕌</span> ${escHtml(log.nama_ibadah)} <span class="log-jenis">${escHtml(log.jenis_ibadah)}</span></div>
|
||||
${log.keterangan ? `<div class="log-ket"><i class="fas fa-quote-left" style="margin-right:4px;font-size:9px;opacity:0.5;"></i>${escHtml(log.keterangan)}</div>` : ''}
|
||||
`;
|
||||
listEl.appendChild(item);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
logList.innerHTML = '<div class="panel-empty" style="padding:15px; color:#ef4444;">Gagal memuat data</div>';
|
||||
listEl.innerHTML = '<div class="panel-empty" style="color:var(--danger);">Gagal memuat data log.</div>';
|
||||
});
|
||||
}
|
||||
|
||||
logSaveBtn.addEventListener('click', function () {
|
||||
const ibadah_id = logIbadahSel.value;
|
||||
const tipe_bantuan = document.getElementById('logTipeBantuan').value;
|
||||
const tanggal = document.getElementById('logTanggal').value;
|
||||
const keterangan = document.getElementById('logKeterangan').value;
|
||||
function populateLogIbadahSelect() {
|
||||
const sel = document.getElementById('logIbadahId');
|
||||
sel.innerHTML = '<option value="">-- Pilih Rumah Ibadah --</option>';
|
||||
if (window.currentUser && window.currentUser.role === 'pengelola' && window.currentUser.ibadah_id) {
|
||||
// Pengelola hanya bisa pilih ibadah miliknya — fetch dari layer
|
||||
const id = window.currentUser.ibadah_id;
|
||||
let found = false;
|
||||
if (typeof rumahIbadahLayer !== 'undefined') {
|
||||
rumahIbadahLayer.eachLayer(l => {
|
||||
if (l.ibadahData) {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = l.ibadahData.id;
|
||||
opt.textContent = l.ibadahData.nama;
|
||||
if (l.ibadahData.id == id) { opt.selected = true; found = true; }
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Admin bisa pilih semua
|
||||
if (typeof rumahIbadahLayer !== 'undefined') {
|
||||
rumahIbadahLayer.eachLayer(l => {
|
||||
if (l.ibadahData) {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = l.ibadahData.id;
|
||||
opt.textContent = l.ibadahData.nama;
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ibadah_id) { alert('Pilih rumah ibadah terlebih dahulu!'); return; }
|
||||
if (!tanggal) { alert('Tanggal harus diisi!'); return; }
|
||||
document.getElementById('btnSaveLog').addEventListener('click', function () {
|
||||
const miskinId = parseInt(document.getElementById('logBantuanMiskinId').value);
|
||||
const ibadahId = parseInt(document.getElementById('logIbadahId').value);
|
||||
const tipe = document.getElementById('logTipeBantuan').value.trim();
|
||||
const tanggal = document.getElementById('logTanggal').value;
|
||||
const keterangan = document.getElementById('logKeterangan').value.trim();
|
||||
|
||||
if (!ibadahId || !tipe || !tanggal) {
|
||||
window.showToast('Lengkapi semua field wajib', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = this;
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Menyimpan...';
|
||||
|
||||
fetch('api/log_bantuan/create.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ miskin_id: _logMiskinId, ibadah_id, tipe_bantuan, tanggal, keterangan })
|
||||
body: JSON.stringify({ miskin_id: miskinId, ibadah_id: ibadahId, tipe_bantuan: tipe, tanggal, keterangan })
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
.then(res => {
|
||||
btn.disabled = false;
|
||||
btn.textContent = 'Simpan Log';
|
||||
if (res.status === 'success') {
|
||||
window.showToast('Log bantuan berhasil disimpan', 'success');
|
||||
document.getElementById('logTipeBantuan').value = '';
|
||||
document.getElementById('logTanggal').value = '';
|
||||
document.getElementById('logKeterangan').value = '';
|
||||
fetchLogBantuan(_logMiskinId);
|
||||
loadLogBantuan(miskinId);
|
||||
} else {
|
||||
alert(data.message || 'Gagal menyimpan');
|
||||
window.showToast(res.message || 'Gagal menyimpan log', 'error');
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
btn.disabled = false;
|
||||
btn.textContent = 'Simpan Log';
|
||||
window.showToast('Terjadi kesalahan koneksi', 'error');
|
||||
});
|
||||
});
|
||||
|
||||
// Close on overlay click
|
||||
document.getElementById('logBantuanModal').addEventListener('click', function(e) {
|
||||
if (e.target === this) window.closeLogBantuanModal();
|
||||
});
|
||||
|
||||
// ---- Utility ----
|
||||
function escHtml(str) {
|
||||
if (!str) return '';
|
||||
|
||||
Reference in New Issue
Block a user