let allData = []; let allRI = []; let filteredData = []; let sortField = 'nama'; let sortDir = 'asc'; const PAGE_SIZE = 20; let currentPage = 1; document.addEventListener('auth-ready', function (e) { const user = e.detail; document.body.classList.add('auth-loaded', 'role-' + user.role); document.getElementById('user-display-name').textContent = user.username; const roleMap = { 'admin': 'Admin', 'petugas_lapangan': 'Rumah Ibadah', 'guest': 'Guest' }; document.getElementById('user-display-role').textContent = roleMap[user.role] || user.role; // Hide admin-nav for non-admin document.querySelectorAll('.admin-nav').forEach(el => { if (user.role !== 'admin') el.style.display = 'none'; }); loadData(user); }); async function loadData(user) { try { const [pmRes, riRes] = await Promise.all([ fetch('api/penduduk_miskin.php'), fetch('api/rumah_ibadah.php') ]); const [pmData, riData] = await Promise.all([pmRes.json(), riRes.json()]); allData = pmData.data || []; allRI = riData.data || []; // For petugas_lapangan: filter to only show residents in their radius if (user && user.role === 'petugas_lapangan') { const myRiId = String(user.rumah_ibadah_id); allData = allData.filter(p => p.status_proximity === 'dalam_radius' && String(p.rumah_ibadah_id) === myRiId); } // Populate RI filter const riFilter = document.getElementById('filter-ri'); allRI.forEach(r => { const opt = document.createElement('option'); opt.value = r.id; opt.textContent = r.nama; riFilter.appendChild(opt); }); updateSummary(); applyFilters(); } catch (err) { document.getElementById('pm-tbody').innerHTML = `Gagal memuat data: ${esc(err.message)}`; } } function updateSummary() { const total = allData.length; const jiwa = allData.reduce((s, p) => s + (parseInt(p.jumlah_anggota, 10) || 0), 0); const dalam = allData.filter(p => p.status_proximity === 'dalam_radius').length; const luar = allData.filter(p => p.status_proximity !== 'dalam_radius').length; const withBantuan = allData.filter(p => p.total_bantuan > 0).length; document.getElementById('sum-total').textContent = total; document.getElementById('sum-jiwa').textContent = jiwa; document.getElementById('sum-dalam').textContent = dalam; document.getElementById('sum-luar').textContent = luar; document.getElementById('sum-bantuan').textContent = withBantuan; } function applyFilters() { const query = document.getElementById('search-input').value.toLowerCase().trim(); const proximity = document.getElementById('filter-proximity').value; const riId = document.getElementById('filter-ri').value; const bantuan = document.getElementById('filter-bantuan').value; filteredData = allData.filter(p => { const matchQ = !query || p.nama.toLowerCase().includes(query) || (p.nik && p.nik.includes(query)) || (p.alamat && p.alamat.toLowerCase().includes(query)) || (p.nama_rumah_ibadah && p.nama_rumah_ibadah.toLowerCase().includes(query)); const matchProx = !proximity || p.status_proximity === proximity; const matchRI = !riId || String(p.rumah_ibadah_id) === riId; const matchBantuan = !bantuan || (bantuan === 'pernah' ? p.total_bantuan > 0 : p.total_bantuan === 0); return matchQ && matchProx && matchRI && matchBantuan; }); // Sort filteredData.sort((a, b) => { let va = a[sortField], vb = b[sortField]; if (typeof va === 'string') va = va.toLowerCase(); if (typeof vb === 'string') vb = vb.toLowerCase(); if (va < vb) return sortDir === 'asc' ? -1 : 1; if (va > vb) return sortDir === 'asc' ? 1 : -1; return 0; }); currentPage = 1; document.getElementById('filter-count').textContent = `${filteredData.length} data`; renderTable(); } function sortBy(field) { if (sortField === field) { sortDir = sortDir === 'asc' ? 'desc' : 'asc'; } else { sortField = field; sortDir = 'asc'; } // Update sort icons document.querySelectorAll('.pm-table thead th').forEach(th => { th.classList.remove('sort-asc', 'sort-desc'); }); const ths = document.querySelectorAll('.pm-table thead th'); const fieldIdx = { 'nama': 0, 'nik': 1, 'jumlah_anggota': 2, 'total_bantuan': 5 }; if (fieldIdx[field] !== undefined) { ths[fieldIdx[field]].classList.add(sortDir === 'asc' ? 'sort-asc' : 'sort-desc'); } applyFilters(); } function renderTable() { const tbody = document.getElementById('pm-tbody'); const total = filteredData.length; if (total === 0) { tbody.innerHTML = `
πŸ”

Tidak ada data

Coba ubah kriteria pencarian atau filter.

`; document.getElementById('pagination').style.display = 'none'; return; } const totalPages = Math.ceil(total / PAGE_SIZE); if (currentPage > totalPages) currentPage = totalPages; const start = (currentPage - 1) * PAGE_SIZE; const slice = filteredData.slice(start, start + PAGE_SIZE); tbody.innerHTML = slice.map((p, idx) => { const inR = p.status_proximity === 'dalam_radius'; const hasPemb = p.bantuan_pemberdayaan > 0; const hasKons = p.bantuan_konsumtif > 0; return `
${esc(p.nama)}
${p.alamat ? `
πŸ“ ${esc(p.alamat.substring(0, 50))}${p.alamat.length > 50 ? '…' : ''}
` : ''} ${p.nik ? esc(p.nik) : 'β€”'} ${p.jumlah_anggota} jiwa ${inR ? 'βœ… Dalam' : '❌ Luar'} ${p.nama_rumah_ibadah ? `β›ͺ ${esc(p.nama_rumah_ibadah)}` : 'β€”'}
${p.total_bantuan === 0 ? 'Belum ada' : ''} ${hasPemb ? `πŸ“š ${p.bantuan_pemberdayaan}` : ''} ${hasKons ? `πŸ›οΈ ${p.bantuan_konsumtif}` : ''}
`; }).join(''); // Pagination const pag = document.getElementById('pagination'); const pagInfo = document.getElementById('pagination-info'); const pagBtns = document.getElementById('pagination-btns'); pag.style.display = 'flex'; pagInfo.textContent = `Menampilkan ${start + 1}–${Math.min(start + PAGE_SIZE, total)} dari ${total} data`; // Build page buttons let btns = ''; btns += ``; const rangeStart = Math.max(1, currentPage - 2); const rangeEnd = Math.min(totalPages, currentPage + 2); if (rangeStart > 1) btns += `${rangeStart > 2 ? '…' : ''}`; for (let i = rangeStart; i <= rangeEnd; i++) { btns += ``; } if (rangeEnd < totalPages) btns += `${rangeEnd < totalPages - 1 ? '…' : ''}`; btns += ``; pagBtns.innerHTML = btns; } function goPage(page) { const totalPages = Math.ceil(filteredData.length / PAGE_SIZE); if (page < 1 || page > totalPages) return; currentPage = page; renderTable(); window.scrollTo({ top: 0, behavior: 'smooth' }); } async function openDrawer(id) { document.getElementById('detail-overlay').classList.add('open'); document.getElementById('drawer-body').innerHTML = `

Memuat detail…

`; try { const [pmRes, logRes] = await Promise.all([ fetch(`api/penduduk_miskin.php?id=${id}`), fetch(`api/log_bantuan.php?penduduk_miskin_id=${id}`) ]); const [pmData, logData] = await Promise.all([pmRes.json(), logRes.json()]); if (pmData.status !== 'success') throw new Error(pmData.message); renderDrawer(pmData.data, logData.data || []); } catch (err) { document.getElementById('drawer-body').innerHTML = `

Gagal memuat: ${esc(err.message)}

`; } } function renderDrawer(p, logs) { document.getElementById('drawer-title').textContent = p.nama; const inR = p.status_proximity === 'dalam_radius'; const isAdmin = window.currentUser && window.currentUser.role === 'admin'; const isPetugas = window.currentUser && window.currentUser.role === 'petugas_lapangan'; const isResidentInMyRadius = isPetugas && inR && String(p.rumah_ibadah_id) === String(window.currentUser.rumah_ibadah_id); const canEdit = isAdmin || isResidentInMyRadius; document.getElementById('drawer-body').innerHTML = `
${inR ? `βœ… Dalam radius jangkauan ${esc(p.nama_rumah_ibadah || 'rumah ibadah')}` : '❌ Di luar radius semua rumah ibadah'}
Informasi Pribadi
Nama Lengkap${esc(p.nama)}
NIK${p.nik ? esc(p.nik) : 'β€”'}
No. WhatsApp${p.no_wa ? esc(p.no_wa) : 'β€”'}
Jumlah Anggota${p.jumlah_anggota} jiwa
Alamat${p.alamat ? esc(p.alamat) : 'β€”'}
Koordinat${p.latitude.toFixed(6)}, ${p.longitude.toFixed(6)}
Terdata Sejak${new Date(p.created_at).toLocaleDateString('id-ID', { day: 'numeric', month: 'long', year: 'numeric' })}
Ringkasan Bantuan
${p.ringkasan_bantuan && p.ringkasan_bantuan.length ? p.ringkasan_bantuan.map(rb => `
${rb.tipe_bantuan === 'Pemberdayaan' ? 'πŸ“š Pemberdayaan' : 'πŸ›οΈ Konsumtif'} ${rb.jumlah} kali
`).join('') : '
Belum pernah menerima bantuan.
'}
${canEdit ? `
` : ''} ${logs.length ? `
Riwayat Bantuan (${logs.length})
${logs.map(l => `
`).join('')}
` : ''} `; } function closeDrawer(e) { if (e && e.target !== document.getElementById('detail-overlay')) return; document.getElementById('detail-overlay').classList.remove('open'); } function openLogBantuanFromDrawer(pmId, pmNama) { // Redirect to peta with log bantuan opened window.location.href = '?page=map'; } function exportCSV() { if (!filteredData.length) return toast('Tidak ada data untuk diekspor', 'error'); const headers = ['Nama', 'NIK', 'No WA', 'Alamat', 'Jumlah Anggota', 'Status Proximity', 'Rumah Ibadah', 'Total Bantuan', 'Bantuan Pemberdayaan', 'Bantuan Konsumtif', 'Latitude', 'Longitude']; const rows = filteredData.map(p => [ p.nama, p.nik || '', p.no_wa || '', p.alamat || '', p.jumlah_anggota, p.status_proximity, p.nama_rumah_ibadah || '', p.total_bantuan, p.bantuan_pemberdayaan, p.bantuan_konsumtif, p.latitude, p.longitude ]); const csv = [headers, ...rows].map(row => row.map(cell => `"${String(cell).replace(/"/g, '""')}"`).join(',')).join('\n'); const blob = new Blob(['\uFEFF' + csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `penduduk_miskin_${new Date().toISOString().slice(0, 10)}.csv`; a.click(); URL.revokeObjectURL(url); toast(`${filteredData.length} data berhasil diekspor`, 'success'); } function esc(s) { if (s == null) return ''; return String(s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } function toast(msg, type = 'info') { const t = document.createElement('div'); t.className = `toast ${type}`; t.textContent = msg; document.getElementById('toast-container').appendChild(t); setTimeout(() => t.remove(), 3500); } 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 { alert('Gagal logout.'); } }