Files
Webgis-Poverty/js/pages/dashboard.js
T
2026-06-11 01:50:37 +07:00

198 lines
6.9 KiB
JavaScript

document.addEventListener('auth-ready', function (e) {
const user = e.detail;
document.body.classList.add('auth-loaded');
// Update User Profile in Sidebar
document.getElementById('user-display-name').textContent = user.username;
// Format role name nicely
const roleMap = {
'admin': 'Admin',
'petugas_lapangan': 'Rumah Ibadah',
'guest': 'Guest'
};
document.getElementById('user-display-role').textContent = roleMap[user.role] || user.role;
// Show admin-only nav items
if (user.role === 'admin') {
document.getElementById('nav-akun').style.display = 'flex';
}
// Update Greeting
document.getElementById('greeting-title').textContent = `Selamat Datang, ${user.username}!`;
// Load stats data
loadDashboardStats();
});
// Format current date nicely in Indonesian
const dateOpts = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
document.getElementById('current-date').textContent = new Date().toLocaleDateString('id-ID', dateOpts);
async function handleLogout() {
if (!confirm('Apakah Anda yakin ingin keluar?')) return;
try {
const response = await fetch('api/logout.php');
const data = await response.json();
if (data.status === 'success') {
window.location.href = '?page=login';
}
} catch (err) {
alert('Gagal melakukan logout.');
}
}
async function loadDashboardStats() {
try {
const response = await fetch('api/dashboard_stats.php');
const result = await response.json();
if (result.status === 'success') {
const stats = result.data;
renderStatsCards(stats);
renderProximityChart(stats.proximity);
renderBantuanChart(stats.tipe_bantuan);
renderBantuanTable(stats.bantuan_terbaru);
renderRiTable(stats.ri_teraktif);
}
} catch (err) {
console.error('Gagal memuat statistik dashboard:', err);
}
}
function renderStatsCards(stats) {
// 1. Penduduk Miskin
document.getElementById('pm-total-kk').textContent = `${stats.penduduk_miskin.total_kk} KK`;
document.getElementById('pm-total-jiwa').textContent = `${stats.penduduk_miskin.total_jiwa} Jiwa terdata`;
// 2. Rumah Ibadah
document.getElementById('ri-total').textContent = stats.rumah_ibadah.total;
// 5. Log Bantuan
document.getElementById('lb-total-count').textContent = `${stats.log_bantuan.total_count} kali`;
const rpBantuan = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', maximumFractionDigits: 0 }).format(stats.log_bantuan.total_nilai || 0);
document.getElementById('lb-total-nilai').textContent = `Total ${rpBantuan}`;
}
let proximityChart = null;
function renderProximityChart(proximity) {
const ctx = document.getElementById('chart-proximity').getContext('2d');
if (proximityChart) proximityChart.destroy();
proximityChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Dalam Radius (Dalam Jangkauan)', 'Luar Radius (Di Luar Jangkauan)'],
datasets: [{
data: [proximity.dalam_radius, proximity.luar_radius],
backgroundColor: ['#10b981', '#f43f5e'],
borderWidth: 4,
borderColor: '#ffffff',
hoverOffset: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
boxWidth: 12,
font: { family: 'Inter', size: 11, weight: '600' },
color: '#475569'
}
}
},
cutout: '70%'
}
});
}
let bantuanChart = null;
function renderBantuanChart(tipeBantuan) {
const ctx = document.getElementById('chart-bantuan-tipe').getContext('2d');
if (bantuanChart) bantuanChart.destroy();
bantuanChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['📚 Pemberdayaan (Pelatihan)', '🛍️ Konsumtif (Makan/Barang)'],
datasets: [{
label: 'Penyaluran Bantuan',
data: [tipeBantuan.Pemberdayaan, tipeBantuan.Konsumtif],
backgroundColor: ['#2563eb', '#f59e0b'],
borderRadius: 8,
barThickness: 36
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
ticks: { stepSize: 1, color: '#64748b', font: { family: 'Inter' } },
grid: { color: '#f1f5f9' }
},
x: {
ticks: { color: '#475569', font: { family: 'Inter', weight: '600' } },
grid: { display: false }
}
},
plugins: {
legend: {
display: false
}
}
}
});
}
function renderBantuanTable(bantuanList) {
const tbody = document.getElementById('table-bantuan-body');
if (!bantuanList || bantuanList.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" class="loading">Belum ada riwayat bantuan</td></tr>';
return;
}
tbody.innerHTML = bantuanList.map(b => {
const rp = b.nilai_bantuan ? new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', maximumFractionDigits: 0 }).format(b.nilai_bantuan) : '—';
const badgeClass = b.tipe_bantuan === 'Pemberdayaan' ? 'pemberdayaan' : 'konsumtif';
return `
<tr>
<td><strong>${b.tanggal_bantuan}</strong></td>
<td>${escapeHTML(b.nama_penduduk)}</td>
<td><span class="db-badge ${badgeClass}">${b.tipe_bantuan}</span></td>
<td>${escapeHTML(b.sub_kategori || '—')}</td>
<td><strong>${rp}</strong></td>
<td>${escapeHTML(b.nama_rumah_ibadah)}</td>
</tr>
`;
}).join('');
}
function renderRiTable(riList) {
const tbody = document.getElementById('table-ri-body');
if (!riList || riList.length === 0) {
tbody.innerHTML = '<tr><td colspan="3" class="loading">Belum ada data penyaluran</td></tr>';
return;
}
tbody.innerHTML = riList.map(r => {
const rp = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', maximumFractionDigits: 0 }).format(r.nilai);
return `
<tr>
<td><strong>${escapeHTML(r.nama)}</strong></td>
<td>${r.count} kali</td>
<td><strong>${rp}</strong></td>
</tr>
`;
}).join('');
}
function escapeHTML(str) {
if (str == null) return '';
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}