add poverty
This commit is contained in:
+162
-7
@@ -137,6 +137,12 @@
|
||||
.butuh { background: #ffedd5; color: #7c2d12; }
|
||||
.rentan { background: #fef9c3; color: #713f12; }
|
||||
.mampu { background: #dcfce7; color: #14532d; }
|
||||
/* Status pengajuan */
|
||||
.status-menunggu { background: #fef3c7; color: #92400e; }
|
||||
.status-diverifikasi { background: #dbeafe; color: #1e40af; }
|
||||
.status-disetujui { background: #dcfce7; color: #14532d; }
|
||||
.status-ditolak { background: #fee2e2; color: #7f1d1d; }
|
||||
.status-selesai { background: #e0e7ff; color: #3730a3; }
|
||||
.bar-row { display: grid; grid-template-columns: 150px 1fr 48px; gap: 10px; align-items: center; margin: 10px 0; font-size: .86rem; }
|
||||
.bar-track { height: 12px; border-radius: 99px; background: #e2e8f0; overflow: hidden; }
|
||||
.bar-fill { height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--accent), var(--accent-2)); }
|
||||
@@ -203,8 +209,10 @@
|
||||
<button data-section="bantuan">Data Bantuan</button>
|
||||
<button data-section="kriteria">Kriteria SAW</button>
|
||||
<button data-section="ibadah">⛪ Tempat Ibadah</button>
|
||||
<button data-section="pengajuan">📋 Pengajuan Bantuan</button>
|
||||
<button data-section="peta">Preview Peta</button>
|
||||
<a href="/poverty-map.html">Buka Peta Poverty</a>
|
||||
<a href="/pengajuan.html">Form Pengajuan Publik</a>
|
||||
<a href="/admin.html">Admin SPBU</a>
|
||||
</nav>
|
||||
</aside>
|
||||
@@ -343,6 +351,9 @@
|
||||
<label>Jenis<select id="ibadah_jenis" required></select></label>
|
||||
<label>Alamat<input id="ibadah_alamat" required /></label>
|
||||
<label>Kelurahan<input id="ibadah_kelurahan" required /></label>
|
||||
<label>Kapasitas Bantuan (KK)<input id="ibadah_kapasitas" type="number" min="0" value="0" /></label>
|
||||
<div></div>
|
||||
<label class="full">Keterangan / Catatan<textarea id="ibadah_keterangan" placeholder="Jadwal bantuan, kontak, dll."></textarea></label>
|
||||
<div class="full">
|
||||
<label>Koordinat dari Peta</label>
|
||||
<div id="ibadahMap" class="ibadah-map"></div>
|
||||
@@ -365,13 +376,73 @@
|
||||
<div class="card-head"><h3>Daftar Tempat Ibadah</h3><span id="ibadahCount">0 data</span></div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>#</th><th>Nama</th><th>Jenis</th><th>Alamat</th><th>Kelurahan</th><th>Koordinat</th><th>Aksi</th></tr></thead>
|
||||
<thead><tr><th>#</th><th>Nama</th><th>Jenis</th><th>Alamat</th><th>Kelurahan</th><th>Koordinat</th><th>Kapasitas</th><th>Aksi</th></tr></thead>
|
||||
<tbody id="ibadahBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<!-- ═══════════════════════ PENGAJUAN BANTUAN ═══════════════════════ -->
|
||||
<section class="section" id="pengajuan">
|
||||
<div class="stats" style="grid-template-columns:repeat(3,minmax(0,1fr))">
|
||||
<article class="stat"><span>Total Pengajuan</span><strong id="statPengajuanTotal">0</strong></article>
|
||||
<article class="stat"><span>Menunggu</span><strong id="statPengajuanMenunggu">0</strong></article>
|
||||
<article class="stat"><span>Disetujui</span><strong id="statPengajuanDisetujui">0</strong></article>
|
||||
</div>
|
||||
<article class="card" style="margin-top:18px">
|
||||
<div class="card-head">
|
||||
<h3>Daftar Pengajuan Bantuan</h3>
|
||||
<select id="filterPengajuanStatus" style="min-width:160px;border-radius:10px;padding:7px 10px;border:1px solid #dbe2ea;font-size:.82rem">
|
||||
<option value="">Semua Status</option>
|
||||
<option value="menunggu">Menunggu</option>
|
||||
<option value="diverifikasi">Diverifikasi</option>
|
||||
<option value="disetujui">Disetujui</option>
|
||||
<option value="ditolak">Ditolak</option>
|
||||
<option value="selesai">Selesai</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead><tr><th>#</th><th>Pemohon</th><th>NIK</th><th>Wilayah</th><th>Alasan</th><th>Tgl Pengajuan</th><th>Status</th><th>Aksi</th></tr></thead>
|
||||
<tbody id="pengajuanBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<!-- Detail / Update Status Modal (inline) -->
|
||||
<article class="card" id="pengajuanDetailCard" style="display:none;margin-top:18px">
|
||||
<div class="card-head">
|
||||
<h3>Update Status Pengajuan</h3>
|
||||
<button class="btn secondary small" onclick="el('pengajuanDetailCard').style.display='none'">Tutup</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p id="pengajuanDetailInfo" style="color:#475569;margin:0 0 14px"></p>
|
||||
<div class="form-grid">
|
||||
<label>Status Baru
|
||||
<select id="pengajuanNewStatus">
|
||||
<option value="menunggu">Menunggu</option>
|
||||
<option value="diverifikasi">Diverifikasi</option>
|
||||
<option value="disetujui">Disetujui</option>
|
||||
<option value="ditolak">Ditolak</option>
|
||||
<option value="selesai">Selesai</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>Hubungkan ke Keluarga (opsional)
|
||||
<select id="pengajuanKeluarga"><option value="">— Tidak dihubungkan —</option></select>
|
||||
</label>
|
||||
<label class="full">Catatan Admin
|
||||
<textarea id="pengajuanCatatan" placeholder="Alasan penolakan, catatan verifikasi, dll."></textarea>
|
||||
</label>
|
||||
</div>
|
||||
<input type="hidden" id="pengajuanEditId" />
|
||||
<div class="actions">
|
||||
<button class="btn" id="savePengajuanStatus">Simpan Status</button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="section" id="peta">
|
||||
<article class="card">
|
||||
<div class="card-head"><h3>Preview Peta Keluarga Prioritas</h3><span>Klik peta untuk mengisi koordinat form keluarga.</span></div>
|
||||
@@ -384,7 +455,7 @@
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script>
|
||||
const API = "/api/poverty";
|
||||
const state = { keluarga: [], bantuan: [], riwayat: [], kriteria: [], ibadah: [], dashboard: null, analytics: null };
|
||||
const state = { keluarga: [], bantuan: [], riwayat: [], kriteria: [], ibadah: [], pengajuan: [], dashboard: null, analytics: null };
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
const DEFAULT_CENTER = [-0.0263, 109.3425];
|
||||
const IBADAH_TYPES = ["Gereja Katolik", "GPIB", "GKI", "HKBP", "Pentakosta"];
|
||||
@@ -469,6 +540,12 @@
|
||||
function refreshSelects() {
|
||||
el("riwayat_keluarga").innerHTML = state.keluarga.map((item) => `<option value="${item.id_keluarga}">${esc(item.nama_kepala_keluarga)} - ${esc(item.kategori || "")}</option>`).join("");
|
||||
el("riwayat_bantuan").innerHTML = state.bantuan.map((item) => `<option value="${item.id_bantuan}">${esc(item.jenis_bantuan)} (${rp(item.nilai_bantuan)})</option>`).join("");
|
||||
// Populate pengajuan keluarga select (with leading empty option)
|
||||
const pengajuanSel = el("pengajuanKeluarga");
|
||||
if (pengajuanSel) {
|
||||
pengajuanSel.innerHTML = `<option value="">— Tidak dihubungkan —</option>` +
|
||||
state.keluarga.map((item) => `<option value="${item.id_keluarga}">#${item.ranking||'-'} ${esc(item.nama_kepala_keluarga)} (${esc(item.wilayah)})</option>`).join("");
|
||||
}
|
||||
}
|
||||
|
||||
function renderBantuan() {
|
||||
@@ -497,9 +574,37 @@
|
||||
<td>${esc(item.alamat)}</td>
|
||||
<td>${esc(item.kelurahan)}</td>
|
||||
<td>${Number(item.lat).toFixed(6)}, ${Number(item.lng).toFixed(6)}</td>
|
||||
<td>${item.kapasitas_bantuan || 0} KK</td>
|
||||
<td><button class="btn secondary small" onclick="editIbadah(${item.id})">Edit</button> <button class="btn danger small" onclick="hapus('ibadah', ${item.id})">Hapus</button></td>
|
||||
</tr>
|
||||
`).join("") || `<tr><td colspan="7">Belum ada data tempat ibadah.</td></tr>`;
|
||||
`).join("") || `<tr><td colspan="8">Belum ada data tempat ibadah.</td></tr>`;
|
||||
}
|
||||
|
||||
function pengajuanBadgeClass(status) {
|
||||
return `status-${status || 'menunggu'}`;
|
||||
}
|
||||
|
||||
function renderPengajuan() {
|
||||
const rows = state.pengajuan;
|
||||
el("statPengajuanTotal").textContent = rows.length;
|
||||
el("statPengajuanMenunggu").textContent = rows.filter(r => r.status === "menunggu").length;
|
||||
el("statPengajuanDisetujui").textContent = rows.filter(r => r.status === "disetujui").length;
|
||||
|
||||
el("pengajuanBody").innerHTML = rows.map((item, idx) => `
|
||||
<tr>
|
||||
<td>${idx + 1}</td>
|
||||
<td><strong>${esc(item.nama_pemohon)}</strong></td>
|
||||
<td>${esc(item.nik)}</td>
|
||||
<td>${esc(item.wilayah)}</td>
|
||||
<td style="max-width:200px;white-space:normal;font-size:.82rem">${esc(item.alasan)}</td>
|
||||
<td>${fmt(item.tanggal_pengajuan)}</td>
|
||||
<td><span class="badge ${pengajuanBadgeClass(item.status)}">${esc(item.status)}</span></td>
|
||||
<td>
|
||||
<button class="btn secondary small" onclick="openPengajuanEdit(${item.id_pengajuan})">Review</button>
|
||||
<button class="btn danger small" onclick="hapusPengajuan(${item.id_pengajuan})">Hapus</button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join("") || `<tr><td colspan="8">Belum ada pengajuan.</td></tr>`;
|
||||
}
|
||||
|
||||
let ibadahMap, ibadahMarker, ibadahManual = false;
|
||||
@@ -565,6 +670,8 @@
|
||||
kelurahan: el("ibadah_kelurahan").value.trim(),
|
||||
lat: Number(el("ibadah_lat").value),
|
||||
lng: Number(el("ibadah_lng").value),
|
||||
kapasitas_bantuan: Number(el("ibadah_kapasitas").value) || 0,
|
||||
keterangan: el("ibadah_keterangan").value.trim() || null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -594,11 +701,12 @@
|
||||
}
|
||||
|
||||
async function loadAll() {
|
||||
const [dashboard, analytics, keluarga, bantuan, riwayat, kriteria, ibadah] = await Promise.all([
|
||||
api("/dashboard"), api("/analytics"), api("/keluarga"), api("/bantuan"), api("/riwayat-bantuan"), api("/kriteria"), api("/ibadah")
|
||||
const [dashboard, analytics, keluarga, bantuan, riwayat, kriteria, ibadah, pengajuan] = await Promise.all([
|
||||
api("/dashboard"), api("/analytics"), api("/keluarga"), api("/bantuan"),
|
||||
api("/riwayat-bantuan"), api("/kriteria"), api("/ibadah"), api("/pengajuan")
|
||||
]);
|
||||
Object.assign(state, { dashboard, analytics, keluarga, bantuan, riwayat, kriteria, ibadah });
|
||||
renderDashboard(); renderKeluarga(); renderBantuan(); renderKriteria(); renderIbadah();
|
||||
Object.assign(state, { dashboard, analytics, keluarga, bantuan, riwayat, kriteria, ibadah, pengajuan });
|
||||
renderDashboard(); renderKeluarga(); renderBantuan(); renderKriteria(); renderIbadah(); renderPengajuan();
|
||||
}
|
||||
|
||||
function familyPayload() {
|
||||
@@ -634,6 +742,8 @@
|
||||
function resetIbadah() {
|
||||
el("ibadahForm").reset();
|
||||
el("id_ibadah").value = "";
|
||||
el("ibadah_kapasitas").value = 0;
|
||||
el("ibadah_keterangan").value = "";
|
||||
el("ibadah_lat").readOnly = true;
|
||||
el("ibadah_lng").readOnly = true;
|
||||
ibadahManual = false;
|
||||
@@ -675,6 +785,8 @@
|
||||
el("ibadah_jenis").value = item.jenis;
|
||||
el("ibadah_alamat").value = item.alamat;
|
||||
el("ibadah_kelurahan").value = item.kelurahan;
|
||||
el("ibadah_kapasitas").value = item.kapasitas_bantuan || 0;
|
||||
el("ibadah_keterangan").value = item.keterangan || "";
|
||||
el("ibadahSubmit").textContent = "Update Tempat Ibadah";
|
||||
el("cancelIbadahEdit").style.display = "inline-flex";
|
||||
setTimeout(() => {
|
||||
@@ -682,6 +794,27 @@
|
||||
el("ibadah").scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}, 100);
|
||||
};
|
||||
|
||||
window.openPengajuanEdit = (id) => {
|
||||
const item = state.pengajuan.find(r => r.id_pengajuan === id);
|
||||
if (!item) return;
|
||||
document.querySelector('[data-section="pengajuan"]').click();
|
||||
el("pengajuanEditId").value = id;
|
||||
el("pengajuanNewStatus").value = item.status;
|
||||
el("pengajuanCatatan").value = item.catatan_admin || "";
|
||||
el("pengajuanKeluarga").value = item.id_keluarga || "";
|
||||
el("pengajuanDetailInfo").textContent =
|
||||
`Pemohon: ${item.nama_pemohon} | NIK: ${item.nik} | Wilayah: ${item.wilayah} | Tgl: ${String(item.tanggal_pengajuan||'').slice(0,10)}`;
|
||||
el("pengajuanDetailCard").style.display = "block";
|
||||
el("pengajuanDetailCard").scrollIntoView({ behavior: "smooth" });
|
||||
};
|
||||
|
||||
window.hapusPengajuan = async (id) => {
|
||||
if (!confirm("Hapus pengajuan ini?")) return;
|
||||
await api(`/pengajuan/${id}`, { method: "DELETE" });
|
||||
toast("Pengajuan berhasil dihapus.");
|
||||
await loadAll();
|
||||
};
|
||||
window.hapus = async (resource, id) => {
|
||||
if (!confirm("Hapus/nonaktifkan data ini?")) return;
|
||||
await api(`/${resource}/${id}`, { method: "DELETE" });
|
||||
@@ -757,6 +890,28 @@
|
||||
el("familySearch").addEventListener("input", renderKeluarga);
|
||||
el("recalculateBtn").addEventListener("click", async () => { await api("/recalculate", { method: "POST" }); toast("SAW berhasil dihitung ulang."); await loadAll(); });
|
||||
|
||||
el("filterPengajuanStatus").addEventListener("change", async () => {
|
||||
const status = el("filterPengajuanStatus").value;
|
||||
state.pengajuan = await api(`/pengajuan${status ? '?status='+status : ''}`);
|
||||
renderPengajuan();
|
||||
});
|
||||
|
||||
el("savePengajuanStatus").addEventListener("click", async () => {
|
||||
const id = el("pengajuanEditId").value;
|
||||
if (!id) return;
|
||||
await api(`/pengajuan/${id}/status`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
status: el("pengajuanNewStatus").value,
|
||||
catatan_admin: el("pengajuanCatatan").value.trim(),
|
||||
id_keluarga: el("pengajuanKeluarga").value || null,
|
||||
}),
|
||||
});
|
||||
toast("Status pengajuan berhasil diperbarui.");
|
||||
el("pengajuanDetailCard").style.display = "none";
|
||||
await loadAll();
|
||||
});
|
||||
|
||||
fillOptions("pekerjaan", labels.pekerjaan);
|
||||
fillOptions("pendidikan", labels.pendidikan);
|
||||
fillOptions("kondisi_rumah", labels.kondisi_rumah);
|
||||
|
||||
Reference in New Issue
Block a user