198 lines
6.9 KiB
JavaScript
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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
} |