Files
UAS_WEBGIS_CindyDyraIslamay…/03PovertyMapping/assets/js/app.js
T

246 lines
7.5 KiB
JavaScript

/* ============================================================
app.js — Main app orchestrator with authentication
============================================================ */
'use strict';
// Flag to prevent duplicate initialization
let isAppInitialized = false;
document.addEventListener('DOMContentLoaded', async () => {
// Prevent duplicate initialization
if (isAppInitialized) {
console.warn('App already initialized, skipping duplicate call');
return;
}
// First check authentication
const isAuthed = await checkAuth();
if (!isAuthed) {
// Not logged in, redirect to login
window.location.href = 'login.html';
return;
}
// Initialize UI based on role
initUIByRole();
// Add logout button to sidebar
addLogoutButton();
// Init map
initMap();
// Init UI
initNavTabs();
initFilters();
initFormTabs();
initHelpModal();
// Load data
await loadAllData();
// Nav tab: activate placement modes
hookTabPlacementModes();
isAppInitialized = true;
});
async function refreshCenters() {
const r = await ApiCenters.list();
if (r.ok && r.data?.success) {
State.centers = r.data.data.centers || [];
recountCenterHouseholds(); // Hitung ulang setelah dapat data baru
renderCenters();
updateLayerCounts();
}
}
// Override loadAllData untuk memastikan recount
async function loadAllData() {
showLoading(true);
const params = {};
if (State.povertyFilter) params.poverty_status = State.povertyFilter;
if (State.aidFilter) params.aid_status = State.aidFilter;
if (State.searchQuery) params.q = State.searchQuery;
if (State.conditionFilter) params.house_condition = State.conditionFilter;
params.limit = 500;
const [centersRes, housesRes] = await Promise.all([
ApiCenters.list(),
ApiHouses.list(params),
loadStats()
]);
if (centersRes.ok && centersRes.data?.success) {
State.centers = centersRes.data.data.centers || [];
}
if (housesRes.ok && housesRes.data?.success) {
State.houses = housesRes.data.data.households || [];
}
recountCenterHouseholds(); // ⭐ PASTIKAN HITUNG ULANG
renderCenters();
renderHouses();
showLoading(false);
}
// Export fungsi refresh
window.refreshCenters = refreshCenters;
async function loadCenters() {
const r = await ApiCenters.list();
if (r.ok && r.data?.success) {
State.centers = r.data.data.centers || [];
}
renderCenters();
}
async function loadHouses() {
const params = {};
if (State.povertyFilter) params.poverty_status = State.povertyFilter;
if (State.aidFilter) params.aid_status = State.aidFilter;
if (State.searchQuery) params.q = State.searchQuery;
if (State.conditionFilter) params.house_condition = State.conditionFilter;
const r = await ApiHouses.list({ ...params, limit: 500 });
if (r.ok && r.data?.success) {
State.houses = r.data.data.households || [];
}
renderHouses();
}
async function loadStats() {
const r = await ApiStats.overview();
if (!r.ok || !r.data?.success) return;
const d = r.data.data;
State.stats = d;
animateCount('statCenters', d.centers);
animateCount('statHouses', d.households);
animateCount('statPopulation', d.population);
animateCount('statAided', d.aid_received);
animateCount('statPending', d.pending_public ?? 0);
}
// Export for public-reports.js
window.loadAllData = loadAllData;
window.loadStats = loadStats;
function animateCount(id, target) {
const el = document.getElementById(id);
if (!el) return;
const start = parseInt(el.textContent.replace(/\D/g,'')) || 0;
const diff = target - start;
const steps = 20;
let step = 0;
const interval = setInterval(() => {
step++;
el.textContent = Math.round(start + (diff * step / steps)).toLocaleString('id-ID');
if (step >= steps) clearInterval(interval);
}, 30);
}
function initNavTabs() {
document.querySelectorAll('.nav-tab').forEach(tab => {
tab.addEventListener('click', () => {
const key = tab.dataset.tab;
document.querySelectorAll('.nav-tab').forEach(t => t.classList.remove('active'));
tab.classList.add('active');
if (key === 'dashboard') {
openDashboard();
setTimeout(() => {
document.querySelectorAll('.nav-tab').forEach(t => t.classList.remove('active'));
document.querySelector('[data-tab="overview"]').classList.add('active');
}, 200);
} else if (key === 'overview') {
cancelPlacementMode();
State.activeFilter = 'all';
renderAllLayers();
}
});
});
}
function hookTabPlacementModes() {
document.querySelector('[data-tab="centers"]')?.addEventListener('click', () => {
setPlacementMode('center');
showToast('Klik peta untuk menambah tempat ibadah.', 'success', 3000);
});
document.querySelector('[data-tab="houses"]')?.addEventListener('click', () => {
setPlacementMode('house');
showToast('Klik peta untuk menambah rumah tangga.', 'success', 3000);
});
}
function initFilters() {
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
State.activeFilter = btn.dataset.filter;
renderAllLayers();
});
});
const searchInput = document.getElementById('searchInput');
if (searchInput) {
searchInput.addEventListener('input', debounce(async (e) => {
State.searchQuery = e.target.value.trim();
renderAllLayers();
}, 300));
}
}
let helpStep = 1;
const helpTotal = 5;
function initHelpModal() {
document.getElementById('helpBtn')?.addEventListener('click', () => {
helpStep = 1;
updateHelpStep();
openModal('helpModal');
});
}
function helpNav(dir) {
helpStep = Math.min(helpTotal, Math.max(1, helpStep + dir));
updateHelpStep();
}
function updateHelpStep() {
document.querySelectorAll('.help-step').forEach(s => s.classList.remove('active'));
document.querySelector(`.help-step[data-step="${helpStep}"]`)?.classList.add('active');
document.getElementById('helpProgress').textContent = helpStep + ' / ' + helpTotal;
document.getElementById('helpPrev').disabled = helpStep === 1;
document.getElementById('helpNext').disabled = helpStep === helpTotal;
if (helpStep === helpTotal) {
document.getElementById('helpNext').textContent = 'Selesai';
document.getElementById('helpNext').onclick = () => closeModal('helpModal');
} else {
document.getElementById('helpNext').textContent = 'Berikutnya →';
document.getElementById('helpNext').onclick = () => helpNav(1);
}
}
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
cancelPlacementMode();
document.querySelectorAll('.modal-overlay').forEach(m => {
if (m.style.display === 'flex') {
m.style.display = 'none';
document.body.style.overflow = '';
}
});
}
if (e.ctrlKey && e.key === 'r') {
e.preventDefault();
loadAllData().then(() => showToast('Data diperbarui.', 'success'));
}
});