740 lines
35 KiB
PHP
740 lines
35 KiB
PHP
<?php
|
|
session_start();
|
|
|
|
function is_logged_in() {
|
|
return isset($_SESSION['user']);
|
|
}
|
|
|
|
function current_role() {
|
|
return $_SESSION['user']['role'] ?? 'masyarakat';
|
|
}
|
|
|
|
function current_instansi() {
|
|
return $_SESSION['user']['instansi'] ?? '';
|
|
}
|
|
|
|
function is_admin() {
|
|
return current_role() === 'admin';
|
|
}
|
|
|
|
function is_walikota() {
|
|
return current_role() === 'walikota';
|
|
}
|
|
|
|
function is_dinas() {
|
|
return current_role() === 'dinas';
|
|
}
|
|
|
|
function can_view_dashboard() {
|
|
return is_admin() || is_walikota() || is_dinas();
|
|
}
|
|
|
|
function can_add_histori() {
|
|
return is_admin() || is_dinas();
|
|
}
|
|
|
|
if (!can_view_dashboard()) {
|
|
header('Location: index.php');
|
|
exit;
|
|
}
|
|
|
|
$roleLabel = ['admin' => 'Admin Pengelola', 'walikota' => 'Wali Kota', 'dinas' => 'Dinas Terkait'][$_SESSION['user']['role'] ?? ''] ?? 'Masyarakat Umum';
|
|
$instansiLabel = current_instansi();
|
|
$admin = is_admin();
|
|
$canAddHistori = can_add_histori();
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Dashboard WebGIS Kemiskinan Pontianak</title>
|
|
<link rel="stylesheet" href="style.css?v=fix-no-alert-bersih-1">
|
|
</head>
|
|
<body class="dashboard-body">
|
|
<div class="dashboard-shell dashboard-shell-wide">
|
|
<header class="dashboard-header">
|
|
<div>
|
|
<h1>Dashboard WebGIS Kemiskinan Pontianak</h1>
|
|
<p>
|
|
Login: <?= htmlspecialchars($_SESSION['user']['nama']) ?>
|
|
(<?= htmlspecialchars($roleLabel) ?><?= $instansiLabel ? ' - ' . htmlspecialchars($instansiLabel) : '' ?>)
|
|
</p>
|
|
</div>
|
|
<div class="dashboard-header-actions">
|
|
<a href="index.php">Kembali ke Peta</a>
|
|
<a href="index.php?logout=1">Logout</a>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="dashboard-note">
|
|
Dashboard ini berisi ringkasan dan tabel utama sistem: laporan cepat, histori bantuan, masyarakat prasejahtera,
|
|
dan rumah ibadah. Pilih tombol data di bawah untuk membuka tabel yang ingin dilihat. Data SPBU, jalan,
|
|
dan parsil tanah tidak ditampilkan di dashboard ini.
|
|
</section>
|
|
|
|
<section class="dashboard-card dashboard-summary-card">
|
|
<div class="section-title-row">
|
|
<div>
|
|
<h2>Ringkasan Utama</h2>
|
|
<p class="section-subtitle">Angka penting untuk memantau laporan masyarakat, bantuan, dan data sosial.</p>
|
|
</div>
|
|
</div>
|
|
<div id="statCards" class="stat-grid compact-stat-grid"></div>
|
|
</section>
|
|
|
|
<section class="dashboard-card">
|
|
<h2>Pilih Data Dashboard</h2>
|
|
<p class="section-subtitle">Klik salah satu tombol. Tabel akan muncul penuh di bawah agar lebih mudah dibaca.</p>
|
|
<div class="dashboard-menu-grid">
|
|
<button class="dashboard-menu-btn active" data-target="laporan" onclick="showDashboardSection('laporan', this)">Laporan Cepat</button>
|
|
<button class="dashboard-menu-btn" data-target="histori" onclick="showDashboardSection('histori', this)">Histori Bantuan</button>
|
|
<button class="dashboard-menu-btn" data-target="penduduk" onclick="showDashboardSection('penduduk', this)">Masyarakat Prasejahtera</button>
|
|
<button class="dashboard-menu-btn" data-target="rumah" onclick="showDashboardSection('rumah', this)">Rumah Ibadah</button>
|
|
<button class="dashboard-menu-btn" data-target="download" onclick="showDashboardSection('download', this)">Download Data</button>
|
|
<?php if ($admin): ?>
|
|
<button class="dashboard-menu-btn" data-target="akun" onclick="showDashboardSection('akun', this)">Kelola Akun</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
</section>
|
|
|
|
<section id="section-laporan" class="dashboard-card dashboard-section">
|
|
<div class="section-title-row">
|
|
<div>
|
|
<h2 id="laporanTitle">Laporan Cepat Masyarakat</h2>
|
|
<p id="laporanNote" class="section-subtitle"></p>
|
|
</div>
|
|
<a class="small-action" href="index.php?download=laporan">Download CSV</a>
|
|
</div>
|
|
<div id="laporanTable" class="dashboard-table-wrap"></div>
|
|
</section>
|
|
|
|
<section id="section-histori" class="dashboard-card dashboard-section hidden">
|
|
<div class="section-title-row">
|
|
<div>
|
|
<h2>Histori Bantuan</h2>
|
|
<p class="section-subtitle">Catatan bantuan yang sudah diterima masyarakat prasejahtera.</p>
|
|
</div>
|
|
<a class="small-action" href="index.php?download=histori">Download CSV</a>
|
|
</div>
|
|
<div id="historiForm"></div>
|
|
<div id="historiTable" class="dashboard-table-wrap"></div>
|
|
</section>
|
|
|
|
<section id="section-penduduk" class="dashboard-card dashboard-section hidden">
|
|
<div class="section-title-row">
|
|
<div>
|
|
<h2>Data Masyarakat Prasejahtera</h2>
|
|
<p class="section-subtitle">Data warga/keluarga yang menjadi objek pemetaan dan monitoring bantuan.</p>
|
|
</div>
|
|
<a class="small-action" href="index.php?download=penduduk">Download CSV</a>
|
|
</div>
|
|
<div id="pendudukTable" class="dashboard-table-wrap"></div>
|
|
</section>
|
|
|
|
<section id="section-rumah" class="dashboard-card dashboard-section hidden">
|
|
<div class="section-title-row">
|
|
<div>
|
|
<h2>Data Rumah Ibadah</h2>
|
|
<p class="section-subtitle">Data rumah ibadah dan radius jangkauan yang digunakan sebagai indikator spasial.</p>
|
|
</div>
|
|
<a class="small-action" href="index.php?download=rumah_ibadah">Download CSV</a>
|
|
</div>
|
|
<div id="rumahIbadahTable" class="dashboard-table-wrap"></div>
|
|
</section>
|
|
|
|
<section id="section-download" class="dashboard-card dashboard-section hidden">
|
|
<h2>Download Data</h2>
|
|
<p class="section-subtitle">Unduhan hanya untuk data utama sistem bantuan masyarakat prasejahtera.</p>
|
|
<div class="download-grid dashboard-download-grid">
|
|
<a href="index.php?download=laporan">Laporan Cepat</a>
|
|
<a href="index.php?download=histori">Histori Bantuan</a>
|
|
<a href="index.php?download=penduduk">Masyarakat Prasejahtera</a>
|
|
<a href="index.php?download=rumah_ibadah">Rumah Ibadah</a>
|
|
</div>
|
|
</section>
|
|
|
|
<?php if ($admin): ?>
|
|
<section id="section-akun" class="dashboard-card dashboard-section hidden">
|
|
<h2>Kelola Akun Pengguna</h2>
|
|
<p class="section-subtitle">Admin dapat menambahkan akun admin, wali kota, dan dinas terkait.</p>
|
|
<div id="akunForm"></div>
|
|
<div id="akunTable" class="dashboard-table-wrap"></div>
|
|
</section>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<script>
|
|
const IS_ADMIN = <?= $admin ? 'true' : 'false' ?>;
|
|
const CAN_ADD_HISTORI = <?= $canAddHistori ? 'true' : 'false' ?>;
|
|
const USER_ROLE = '<?= htmlspecialchars($_SESSION['user']['role'] ?? 'masyarakat', ENT_QUOTES) ?>';
|
|
const USER_INSTANSI = '<?= htmlspecialchars(current_instansi(), ENT_QUOTES) ?>';
|
|
let allData = {};
|
|
|
|
function esc(value) {
|
|
return String(value ?? '').replace(/[&<>\"]/g, char => ({
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"'
|
|
}[char]));
|
|
}
|
|
|
|
function optionSet(options, selected) {
|
|
return options.map(option => `
|
|
<option value="${esc(option)}" ${String(option) === String(selected) ? 'selected' : ''}>
|
|
${esc(option)}
|
|
</option>
|
|
`).join('');
|
|
}
|
|
|
|
function numberFormat(value) {
|
|
return new Intl.NumberFormat('id-ID').format(Number(value || 0));
|
|
}
|
|
|
|
function rupiah(value) {
|
|
return 'Rp ' + new Intl.NumberFormat('id-ID').format(Number(value || 0));
|
|
}
|
|
|
|
function normalizeText(value) {
|
|
return String(value ?? '').trim().toLowerCase().replace(/\s+/g, ' ');
|
|
}
|
|
|
|
function findMatchingPendudukForLaporan(item) {
|
|
const penduduk = allData.penduduk_kemiskinan || [];
|
|
const nikLaporan = normalizeText(item.data_nik || '');
|
|
const namaLaporan = normalizeText(item.data_nama_kepala_keluarga || '');
|
|
|
|
if (nikLaporan !== '') {
|
|
const byNik = penduduk.find(p => normalizeText(p.nik || '') === nikLaporan);
|
|
if (byNik) return { item: byNik, reason: 'NIK sama' };
|
|
}
|
|
|
|
if (namaLaporan !== '') {
|
|
const byName = penduduk.find(p => normalizeText(p.nama_kepala_keluarga || '') === namaLaporan);
|
|
if (byName) return { item: byName, reason: 'Nama sama' };
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function showDashboardSection(sectionName, button = null) {
|
|
document.querySelectorAll('.dashboard-section').forEach(section => section.classList.add('hidden'));
|
|
const target = document.getElementById('section-' + sectionName);
|
|
if (target) target.classList.remove('hidden');
|
|
|
|
document.querySelectorAll('.dashboard-menu-btn').forEach(btn => btn.classList.remove('active'));
|
|
if (button) {
|
|
button.classList.add('active');
|
|
} else {
|
|
const autoButton = document.querySelector(`.dashboard-menu-btn[data-target="${sectionName}"]`);
|
|
if (autoButton) autoButton.classList.add('active');
|
|
}
|
|
}
|
|
|
|
function hitungStatistik() {
|
|
const laporan = allData.laporan_masyarakat || [];
|
|
const histori = allData.histori_bantuan || [];
|
|
const penduduk = allData.penduduk_kemiskinan || [];
|
|
const rumahIbadah = allData.masjid || [];
|
|
|
|
return {
|
|
laporanMasuk: laporan.filter(x => x.status_laporan === 'Masuk').length,
|
|
laporanDiproses: laporan.filter(x => ['Ditinjau', 'Diproses'].includes(x.status_laporan)).length,
|
|
laporanSelesai: laporan.filter(x => x.status_laporan === 'Selesai').length,
|
|
laporanDijadikan: laporan.filter(x => x.status_laporan === 'Dijadikan Data Masyarakat').length,
|
|
totalPenduduk: penduduk.length,
|
|
belumMenerima: penduduk.filter(x => x.status_bantuan === 'Belum menerima').length,
|
|
sudahMenerima: penduduk.filter(x => x.status_bantuan === 'Sudah menerima').length,
|
|
totalHistori: histori.length,
|
|
totalRumahIbadah: rumahIbadah.length
|
|
};
|
|
}
|
|
|
|
function renderStats() {
|
|
const s = hitungStatistik();
|
|
document.getElementById('statCards').innerHTML = `
|
|
<div class="stat-card important"><span>Masyarakat Prasejahtera</span><b>${numberFormat(s.totalPenduduk)}</b><small>Total data warga</small></div>
|
|
<div class="stat-card"><span>Belum Menerima Bantuan</span><b>${numberFormat(s.belumMenerima)}</b><small>Prioritas pengecekan bantuan</small></div>
|
|
<div class="stat-card"><span>Sudah Menerima Bantuan</span><b>${numberFormat(s.sudahMenerima)}</b><small>Warga tercatat menerima bantuan</small></div>
|
|
<div class="stat-card important"><span>Laporan Masuk</span><b>${numberFormat(s.laporanMasuk)}</b><small>Perlu ditinjau admin</small></div>
|
|
<div class="stat-card"><span>Ditinjau/Diproses</span><b>${numberFormat(s.laporanDiproses)}</b><small>Laporan sedang ditangani</small></div>
|
|
<div class="stat-card"><span>Laporan Selesai</span><b>${numberFormat(s.laporanSelesai)}</b><small>Laporan sudah selesai</small></div>
|
|
<div class="stat-card"><span>Jadi Data Masyarakat</span><b>${numberFormat(s.laporanDijadikan)}</b><small>Laporan valid yang dikonversi</small></div>
|
|
<div class="stat-card"><span>Histori Bantuan</span><b>${numberFormat(s.totalHistori)}</b><small>Jumlah bantuan tercatat</small></div>
|
|
<div class="stat-card"><span>Rumah Ibadah</span><b>${numberFormat(s.totalRumahIbadah)}</b><small>Potensi pemberi bantuan</small></div>
|
|
`;
|
|
}
|
|
|
|
|
|
function renderAutoLinkBox(item) {
|
|
const status = String(item.status_laporan || '');
|
|
|
|
if (item.penduduk_id) {
|
|
return `
|
|
<div class="match-note success">
|
|
Laporan ini sudah terhubung ke data masyarakat prasejahtera.
|
|
Jika bantuan diberikan, catat melalui tab <b>Histori Bantuan</b>.
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
if (status !== 'Selesai') {
|
|
const match = findMatchingPendudukForLaporan(item);
|
|
const matchText = match
|
|
? `Terdeteksi data lama yang cocok: <b>${esc(match.item.nama_kepala_keluarga)}</b> (${esc(match.reason)}).`
|
|
: `Belum ada data masyarakat prasejahtera yang cocok.`;
|
|
|
|
return `
|
|
<div class="match-note muted">
|
|
${matchText}<br>
|
|
Laporan belum bisa dijadikan/diHubungkan ke data masyarakat karena status masih <b>${esc(status || 'Masuk')}</b>.
|
|
Ubah status menjadi <b>Selesai</b> setelah laporan benar-benar valid.
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
const match = findMatchingPendudukForLaporan(item);
|
|
const matchedId = match?.item?.id ? String(match.item.id) : '';
|
|
const options = (allData.penduduk_kemiskinan || []).map(p => `
|
|
<option value="${p.id}" ${String(p.id) === matchedId ? 'selected' : ''}>
|
|
${esc(p.nama_kepala_keluarga)} - NIK: ${esc(p.nik || '-')} - ${esc(p.kelurahan || '-')}
|
|
</option>
|
|
`).join('');
|
|
|
|
const matchNote = match
|
|
? `<div class="match-note">Terdeteksi cocok otomatis: <b>${esc(match.item.nama_kepala_keluarga)}</b> (${esc(match.reason)}). Karena status sudah <b>Selesai</b>, klik <b>Hubungkan</b> agar laporan masuk ke data warga yang sama.</div>`
|
|
: `<div class="match-note muted">Belum ada data lama yang cocok. Jika warga memang belum terdaftar dan laporan sudah valid, gunakan <b>Jadikan Data Baru</b>.</div>`;
|
|
|
|
return `
|
|
${matchNote}
|
|
<div class="mini-link-box">
|
|
<select id="link_penduduk_${item.id}">
|
|
<option value="">-- Hubungkan ke data lama --</option>
|
|
${options}
|
|
</select>
|
|
<button onclick="linkLaporan(${item.id})">Hubungkan</button>
|
|
</div>
|
|
<button onclick="convertLaporan(${item.id})">Jadikan Data Baru</button>
|
|
`;
|
|
}
|
|
|
|
function renderLaporan() {
|
|
const data = allData.laporan_masyarakat || [];
|
|
document.getElementById('laporanTitle').textContent = USER_ROLE === 'dinas' ? 'Laporan Instansi' : 'Laporan Cepat Masyarakat';
|
|
document.getElementById('laporanNote').innerHTML = USER_ROLE === 'dinas'
|
|
? `Data yang tampil hanya laporan dengan tujuan <b>${esc(USER_INSTANSI || 'Dinas Sosial')}</b>.`
|
|
: 'Rekap laporan cepat yang dikirim masyarakat melalui titik lokasi pada peta.';
|
|
|
|
document.getElementById('laporanTable').innerHTML = `
|
|
<table class="dashboard-table wide-table">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Pelapor</th>
|
|
<th>Warga Dilaporkan</th>
|
|
<th>Alamat Warga</th>
|
|
<th>No HP</th>
|
|
<th>Kategori</th>
|
|
<th>Aktor Tujuan</th>
|
|
<th>Status</th>
|
|
<th>Deskripsi</th>
|
|
<th>Koordinat</th>
|
|
<th>Tanggal</th>
|
|
<th>Aksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${data.map(item => `
|
|
<tr>
|
|
<td>${esc(item.id)}</td>
|
|
<td>${esc(item.nama_pelapor)}</td>
|
|
<td>
|
|
<b>${esc(item.data_nama_kepala_keluarga || '-')}</b><br>
|
|
<small>NIK: ${esc(item.data_nik || '-')}</small><br>
|
|
<small>KK: ${esc(item.data_jumlah_kk || '-')}</small>
|
|
</td>
|
|
<td>
|
|
${esc(item.data_alamat || '-')}<br>
|
|
<small>${esc(item.data_kelurahan || '-')}, ${esc(item.data_kecamatan || '-')}</small><br>
|
|
<small>Kesehatan: ${esc(item.data_riwayat_penyakit || '-')}</small>
|
|
</td>
|
|
<td>${esc(item.no_hp)}</td>
|
|
<td>${esc(item.kategori_laporan)}</td>
|
|
<td>${esc(item.aktor_tujuan)}</td>
|
|
<td>
|
|
${IS_ADMIN ? `
|
|
<select id="status_laporan_${item.id}">
|
|
${optionSet(['Masuk', 'Ditinjau', 'Diproses', 'Selesai', 'Dijadikan Data Masyarakat', 'Ditolak'], item.status_laporan)}
|
|
</select>
|
|
` : `<b>${esc(item.status_laporan)}</b>`}
|
|
</td>
|
|
<td>${esc(item.deskripsi)}</td>
|
|
<td>${esc(item.latitude)}, ${esc(item.longitude)}</td>
|
|
<td>${esc(item.created_at)}</td>
|
|
<td>
|
|
${IS_ADMIN ? `
|
|
<button onclick="updateStatusLaporan(${item.id})">Update Status</button>
|
|
${(!item.penduduk_id && item.status_laporan !== 'Ditolak') ? `
|
|
${renderAutoLinkBox(item)}
|
|
` : `<small>Sudah terhubung/selesai</small>`}
|
|
<button class="danger" onclick="deleteData('laporan_masyarakat', ${item.id})">Hapus</button>
|
|
` : `<small>Hanya lihat</small>`}
|
|
</td>
|
|
</tr>
|
|
`).join('') || `<tr><td colspan="12">Belum ada data laporan.</td></tr>`}
|
|
</tbody>
|
|
</table>
|
|
`;
|
|
}
|
|
|
|
function renderHistori() {
|
|
const data = allData.histori_bantuan || [];
|
|
const options = (allData.penduduk_kemiskinan || []).map(item => `
|
|
<option value="${item.id}">${esc(item.nama_kepala_keluarga)}</option>
|
|
`).join('');
|
|
|
|
const rumahOptions = (allData.masjid || []).map(item => `
|
|
<option value="${item.id}">${esc(item.nama_masjid)} - ${esc(item.jenis_rumah_ibadah)}</option>
|
|
`).join('');
|
|
|
|
const sumberDefault = USER_ROLE === 'dinas' ? (USER_INSTANSI || 'Dinas Terkait') : 'Pemkot Pontianak / Rumah Ibadah / Donatur';
|
|
document.getElementById('historiForm').innerHTML = CAN_ADD_HISTORI ? `
|
|
<p class="info-note">Bantuan bisa diberikan berulang kali. Tambahkan histori baru untuk warga yang sama setiap kali bantuan diberikan.</p>
|
|
<div class="dashboard-inline-form">
|
|
<select id="penduduk_id">
|
|
<option value="">-- Pilih masyarakat penerima --</option>
|
|
${options}
|
|
</select>
|
|
<input id="jenis_bantuan" placeholder="Jenis bantuan, contoh: sembako / PKH / pemeriksaan kesehatan">
|
|
<input id="tanggal_bantuan" type="date">
|
|
<input id="nominal" type="number" placeholder="Nominal bantuan / 0 jika non-uang">
|
|
<input id="sumber_bantuan" value="${esc(sumberDefault)}">
|
|
<select id="masjid_id">
|
|
<option value="">-- Rumah ibadah pemberi bantuan, jika ada --</option>
|
|
${rumahOptions}
|
|
</select>
|
|
<input id="keterangan" placeholder="Keterangan bantuan">
|
|
<button onclick="addHistori()">Tambah Histori</button>
|
|
</div>
|
|
` : `<p class="info-note">Role ini hanya dapat melihat dan mengunduh histori bantuan.</p>`;
|
|
|
|
document.getElementById('historiTable').innerHTML = `
|
|
<table class="dashboard-table">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Kepala Keluarga</th>
|
|
<th>Jenis Bantuan</th>
|
|
<th>Tanggal</th>
|
|
<th>Nominal</th>
|
|
<th>Sumber</th>
|
|
<th>Rumah Ibadah</th>
|
|
<th>Keterangan</th>
|
|
<th>Aksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${data.map(item => `
|
|
<tr>
|
|
<td>${esc(item.id)}</td>
|
|
<td>${esc(item.nama_kepala_keluarga)}</td>
|
|
<td>${esc(item.jenis_bantuan)}</td>
|
|
<td>${esc(item.tanggal_bantuan)}</td>
|
|
<td>${rupiah(item.nominal)}</td>
|
|
<td>${esc(item.sumber_bantuan)}</td>
|
|
<td>${item.nama_masjid ? `${esc(item.nama_masjid)}<br><small>${esc(item.jenis_rumah_ibadah || '-')}</small>` : '-'}</td>
|
|
<td>${esc(item.keterangan)}</td>
|
|
<td>${IS_ADMIN ? `<button class="danger" onclick="deleteData('histori_bantuan', ${item.id})">Hapus</button>` : `<small>Hanya lihat</small>`}</td>
|
|
</tr>
|
|
`).join('') || `<tr><td colspan="9">Belum ada histori bantuan.</td></tr>`}
|
|
</tbody>
|
|
</table>
|
|
`;
|
|
}
|
|
|
|
function renderPenduduk() {
|
|
const data = allData.penduduk_kemiskinan || [];
|
|
document.getElementById('pendudukTable').innerHTML = `
|
|
<table class="dashboard-table wide-table">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Nama Kepala Keluarga</th>
|
|
<th>NIK</th>
|
|
<th>Tanggal Lahir</th>
|
|
<th>Pendidikan</th>
|
|
<th>Riwayat Penyakit</th>
|
|
<th>Jumlah KK</th>
|
|
<th>Alamat</th>
|
|
<th>Kecamatan</th>
|
|
<th>Kelurahan</th>
|
|
<th>Status Bantuan</th>
|
|
<th>Koordinat</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${data.map(item => `
|
|
<tr>
|
|
<td>${esc(item.id)}</td>
|
|
<td>${esc(item.nama_kepala_keluarga)}</td>
|
|
<td>${esc(item.nik || '-')}</td>
|
|
<td>${esc(item.tanggal_lahir || '-')}</td>
|
|
<td>${esc(item.pendidikan)}</td>
|
|
<td>${esc(item.riwayat_penyakit || '-')}</td>
|
|
<td>${esc(item.jumlah_kk)}</td>
|
|
<td>${esc(item.alamat)}</td>
|
|
<td>${esc(item.kecamatan || '-')}</td>
|
|
<td>${esc(item.kelurahan || '-')}</td>
|
|
<td><b>${esc(item.status_bantuan)}</b></td>
|
|
<td>${esc(item.latitude)}, ${esc(item.longitude)}</td>
|
|
</tr>
|
|
`).join('') || `<tr><td colspan="12">Belum ada data masyarakat prasejahtera.</td></tr>`}
|
|
</tbody>
|
|
</table>
|
|
`;
|
|
}
|
|
|
|
function renderRumahIbadah() {
|
|
const data = allData.masjid || [];
|
|
document.getElementById('rumahIbadahTable').innerHTML = `
|
|
<table class="dashboard-table">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Jenis</th>
|
|
<th>Nama Rumah Ibadah</th>
|
|
<th>PIC</th>
|
|
<th>Alamat</th>
|
|
<th>Radius</th>
|
|
<th>Koordinat</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${data.map(item => `
|
|
<tr>
|
|
<td>${esc(item.id)}</td>
|
|
<td>${esc(item.jenis_rumah_ibadah)}</td>
|
|
<td>${esc(item.nama_masjid)}</td>
|
|
<td>${esc(item.pic_masjid)}</td>
|
|
<td>${esc(item.alamat_masjid)}</td>
|
|
<td>${esc(item.radius_meter)} meter</td>
|
|
<td>${esc(item.latitude)}, ${esc(item.longitude)}</td>
|
|
</tr>
|
|
`).join('') || `<tr><td colspan="7">Belum ada data rumah ibadah.</td></tr>`}
|
|
</tbody>
|
|
</table>
|
|
`;
|
|
}
|
|
|
|
function renderAkun() {
|
|
if (!IS_ADMIN) return;
|
|
const users = allData.users || [];
|
|
document.getElementById('akunForm').innerHTML = `
|
|
<div class="dashboard-inline-form">
|
|
<input id="user_nama" placeholder="Nama akun / nama dinas">
|
|
<input id="user_username" placeholder="Username">
|
|
<input id="user_password" type="password" placeholder="Password">
|
|
<select id="user_role">
|
|
${optionSet(['dinas', 'walikota', 'admin'], 'dinas')}
|
|
</select>
|
|
<select id="user_instansi">
|
|
${optionSet(['Dinas Sosial', 'Dinas Kesehatan', 'Wali Kota', 'Admin Pengelola'], 'Dinas Sosial')}
|
|
</select>
|
|
<button onclick="addUser()">Tambah Akun</button>
|
|
</div>
|
|
`;
|
|
|
|
document.getElementById('akunTable').innerHTML = `
|
|
<table class="dashboard-table">
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>Nama</th>
|
|
<th>Username</th>
|
|
<th>Role</th>
|
|
<th>Instansi</th>
|
|
<th>Dibuat</th>
|
|
<th>Aksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${users.map(item => `
|
|
<tr>
|
|
<td>${esc(item.id)}</td>
|
|
<td>${esc(item.nama)}</td>
|
|
<td>${esc(item.username)}</td>
|
|
<td>${esc(item.role)}</td>
|
|
<td>${esc(item.instansi || '-')}</td>
|
|
<td>${esc(item.created_at || '-')}</td>
|
|
<td><button class="danger" onclick="deleteUser(${item.id})">Hapus</button></td>
|
|
</tr>
|
|
`).join('') || `<tr><td colspan="7">Belum ada data akun.</td></tr>`}
|
|
</tbody>
|
|
</table>
|
|
`;
|
|
}
|
|
|
|
function renderDashboard() {
|
|
renderStats();
|
|
renderLaporan();
|
|
renderHistori();
|
|
renderPenduduk();
|
|
renderRumahIbadah();
|
|
renderAkun();
|
|
}
|
|
|
|
function loadDashboard() {
|
|
fetch('index.php?action=get_all')
|
|
.then(async response => {
|
|
const text = await response.text();
|
|
try {
|
|
return JSON.parse(text);
|
|
} catch (error) {
|
|
console.error('Response dashboard bukan JSON. Cek output PHP:', text);
|
|
return {
|
|
penduduk_kemiskinan: [],
|
|
masjid: [],
|
|
laporan_masyarakat: [],
|
|
histori_bantuan: [],
|
|
users: []
|
|
};
|
|
}
|
|
})
|
|
.then(data => {
|
|
allData = data || {};
|
|
renderDashboard();
|
|
showDashboardSection('laporan');
|
|
})
|
|
.catch(error => {
|
|
console.error('Gagal memuat dashboard:', error);
|
|
allData = {
|
|
penduduk_kemiskinan: [],
|
|
masjid: [],
|
|
laporan_masyarakat: [],
|
|
histori_bantuan: [],
|
|
users: []
|
|
};
|
|
renderDashboard();
|
|
showDashboardSection('laporan');
|
|
});
|
|
}
|
|
|
|
function updateStatusLaporan(id) {
|
|
if (!IS_ADMIN) return;
|
|
const status = document.getElementById('status_laporan_' + id).value;
|
|
const formData = new URLSearchParams();
|
|
formData.append('id', id);
|
|
formData.append('status_laporan', status);
|
|
|
|
fetch('index.php?action=update_status_laporan', { method: 'POST', body: formData })
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
alert(result.message);
|
|
loadDashboard();
|
|
});
|
|
}
|
|
|
|
|
|
function convertLaporan(id) {
|
|
if (!IS_ADMIN) return;
|
|
if (!confirm('Jadikan laporan ini sebagai data masyarakat prasejahtera? Bubble laporan akan disembunyikan dari peta, tetapi tetap masuk statistik dashboard.')) return;
|
|
|
|
const formData = new URLSearchParams();
|
|
formData.append('id', id);
|
|
|
|
fetch('index.php?action=convert_laporan_to_penduduk', { method: 'POST', body: formData })
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
alert(result.message);
|
|
loadDashboard();
|
|
});
|
|
}
|
|
|
|
function linkLaporan(id) {
|
|
if (!IS_ADMIN) return;
|
|
const select = document.getElementById('link_penduduk_' + id);
|
|
const pendudukId = select ? select.value : '';
|
|
if (!pendudukId) {
|
|
alert('Pilih data masyarakat prasejahtera yang sudah ada terlebih dahulu.');
|
|
return;
|
|
}
|
|
if (!confirm('Hubungkan laporan ini ke data masyarakat yang sudah ada? Laporan tetap tersimpan untuk arsip/statistik, tetapi bubble laporan akan disembunyikan dari peta.')) return;
|
|
|
|
const formData = new URLSearchParams();
|
|
formData.append('id', id);
|
|
formData.append('penduduk_id', pendudukId);
|
|
|
|
fetch('index.php?action=link_laporan_to_penduduk', { method: 'POST', body: formData })
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
alert(result.message);
|
|
loadDashboard();
|
|
});
|
|
}
|
|
|
|
function addHistori() {
|
|
if (!CAN_ADD_HISTORI) return;
|
|
const fields = ['penduduk_id', 'masjid_id', 'jenis_bantuan', 'tanggal_bantuan', 'nominal', 'sumber_bantuan', 'keterangan'];
|
|
const formData = new URLSearchParams();
|
|
fields.forEach(id => formData.append(id, document.getElementById(id).value));
|
|
|
|
fetch('index.php?action=add_histori', { method: 'POST', body: formData })
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
alert(result.message);
|
|
loadDashboard();
|
|
});
|
|
}
|
|
|
|
function deleteData(table, id) {
|
|
if (!IS_ADMIN) return;
|
|
if (!confirm('Yakin ingin menghapus data ini?')) return;
|
|
const formData = new URLSearchParams();
|
|
formData.append('table', table);
|
|
formData.append('id', id);
|
|
|
|
fetch('index.php?action=delete', { method: 'POST', body: formData })
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
alert(result.message);
|
|
loadDashboard();
|
|
});
|
|
}
|
|
|
|
function addUser() {
|
|
if (!IS_ADMIN) return;
|
|
const formData = new URLSearchParams();
|
|
formData.append('nama', document.getElementById('user_nama').value);
|
|
formData.append('username', document.getElementById('user_username').value);
|
|
formData.append('password', document.getElementById('user_password').value);
|
|
formData.append('role', document.getElementById('user_role').value);
|
|
formData.append('instansi', document.getElementById('user_instansi').value);
|
|
|
|
fetch('index.php?action=add_user', { method: 'POST', body: formData })
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
alert(result.message);
|
|
loadDashboard();
|
|
});
|
|
}
|
|
|
|
function deleteUser(id) {
|
|
if (!IS_ADMIN) return;
|
|
if (!confirm('Hapus akun ini?')) return;
|
|
const formData = new URLSearchParams();
|
|
formData.append('id', id);
|
|
|
|
fetch('index.php?action=delete_user', { method: 'POST', body: formData })
|
|
.then(response => response.json())
|
|
.then(result => {
|
|
alert(result.message);
|
|
loadDashboard();
|
|
});
|
|
}
|
|
|
|
loadDashboard();
|
|
</script>
|
|
</body>
|
|
</html>
|