add poverty

This commit is contained in:
tistopandita
2026-06-11 13:56:18 +07:00
parent 7ef7620d2a
commit 5386300498
4 changed files with 1421 additions and 227 deletions
+162 -7
View File
@@ -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);
+457
View File
@@ -0,0 +1,457 @@
<!doctype html>
<html lang="id">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ajukan Bantuan Sosial WebGIS Gereja Peduli</title>
<meta name="description" content="Form pengajuan bantuan sosial dari gereja. Isi data diri Anda dan tim kami akan segera memproses permohonan Anda." />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet" />
<style>
:root {
--accent: #7c3aed;
--accent2: #06b6d4;
--dark: #0f172a;
--panel: #111827;
--border: rgba(148,163,184,.22);
--shadow: 0 24px 70px rgba(15,23,42,.24);
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
font-family: "Inter", system-ui, sans-serif;
background:
radial-gradient(circle at top left, rgba(124,58,237,.32), transparent 36%),
linear-gradient(135deg, #130f2e 0%, #111827 50%, #312e81 100%);
display: flex;
flex-direction: column;
align-items: center;
padding: 32px 16px 64px;
}
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; }
/* ── Hero ── */
.hero {
text-align: center;
color: white;
max-width: 600px;
margin-bottom: 36px;
}
.hero small {
display: block;
font-size: .78rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: .1em;
color: #a5b4fc;
margin-bottom: 12px;
}
.hero h1 {
margin: 0 0 14px;
font-size: clamp(1.8rem, 5vw, 2.8rem);
line-height: 1.1;
background: linear-gradient(135deg, #e0e7ff, #c4b5fd, #93c5fd);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.hero p {
margin: 0;
color: #cbd5e1;
line-height: 1.6;
font-size: .95rem;
}
/* ── Status badges ── */
.status-flow {
display: flex;
gap: 8px;
flex-wrap: wrap;
justify-content: center;
margin: 22px 0 0;
}
.flow-step {
display: flex;
align-items: center;
gap: 6px;
padding: 7px 14px;
border-radius: 999px;
border: 1px solid rgba(255,255,255,.15);
background: rgba(255,255,255,.07);
color: #e5e7eb;
font-size: .78rem;
font-weight: 700;
}
/* ── Card ── */
.card {
width: 100%;
max-width: 680px;
background: rgba(255,255,255,.96);
border-radius: 28px;
box-shadow: var(--shadow);
overflow: hidden;
}
.card-head {
padding: 24px 28px 20px;
border-bottom: 1px solid #e5e7eb;
background: linear-gradient(135deg, #f8fafc, #f0f4ff);
}
.card-head h2 {
margin: 0 0 4px;
font-size: 1.22rem;
color: #1e1b4b;
}
.card-head p {
margin: 0;
color: #64748b;
font-size: .86rem;
line-height: 1.5;
}
.card-body { padding: 26px 28px; }
/* ── Form ── */
.form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.full { grid-column: 1 / -1; }
label {
display: grid;
gap: 6px;
color: #334155;
font-size: .82rem;
font-weight: 800;
}
input[type="text"],
input[type="date"],
input[type="tel"],
select,
textarea {
width: 100%;
border: 1px solid #dbe2ea;
border-radius: 14px;
padding: 11px 13px;
outline: none;
color: #1e293b;
background: #f8fafc;
transition: border-color .15s, box-shadow .15s;
font-size: .9rem;
}
input:focus, select:focus, textarea:focus {
border-color: #a78bfa;
box-shadow: 0 0 0 4px rgba(124,58,237,.1);
background: #fff;
}
textarea { min-height: 100px; resize: vertical; }
/* ── Required mark ── */
.req { color: #dc2626; }
/* ── Divider ── */
.divider {
grid-column: 1/-1;
border: 0;
border-top: 1px solid #e2e8f0;
margin: 6px 0;
}
/* ── Info box ── */
.info-box {
grid-column: 1/-1;
background: #eff6ff;
border: 1px solid #bfdbfe;
border-radius: 14px;
padding: 14px 16px;
color: #1e3a8a;
font-size: .84rem;
line-height: 1.5;
}
.info-box strong { display: block; margin-bottom: 4px; }
/* ── Submit ── */
.btn-submit {
width: 100%;
margin-top: 18px;
border: 0;
border-radius: 16px;
padding: 15px;
background: linear-gradient(135deg, var(--accent), var(--accent2));
color: white;
font-weight: 800;
font-size: 1rem;
cursor: pointer;
box-shadow: 0 14px 32px rgba(124,58,237,.3);
transition: transform .15s, box-shadow .15s;
}
.btn-submit:hover { transform: translateY(-2px); box-shadow: 0 18px 38px rgba(124,58,237,.4); }
.btn-submit:disabled { opacity: .6; cursor: not-allowed; transform: none; }
/* ── Success ── */
.success-screen {
display: none;
text-align: center;
padding: 40px 28px;
animation: fadeUp .4s ease forwards;
}
.success-icon {
font-size: 4rem;
margin-bottom: 18px;
display: block;
}
.success-screen h2 { margin: 0 0 10px; color: #14532d; font-size: 1.5rem; }
.success-screen p { margin: 0 0 8px; color: #475569; line-height: 1.5; }
.ref-num { font-weight: 800; color: var(--accent); font-size: 1.1rem; }
.btn-back {
display: inline-block;
margin-top: 20px;
padding: 11px 22px;
border-radius: 14px;
background: var(--accent);
color: white;
font-weight: 700;
font-size: .88rem;
cursor: pointer;
border: 0;
transition: .15s;
}
.btn-back:hover { background: #6d28d9; }
/* ── Toast ── */
.toast {
position: fixed;
bottom: 22px;
right: 22px;
background: #0f172a;
color: white;
padding: 12px 16px;
border-radius: 13px;
box-shadow: var(--shadow);
opacity: 0;
transform: translateY(10px);
pointer-events: none;
transition: .22s ease;
z-index: 1000;
max-width: 320px;
font-size: .88rem;
}
.toast.show { opacity: 1; transform: translateY(0); }
/* ── Footer links ── */
.footer-links {
display: flex;
gap: 14px;
justify-content: center;
flex-wrap: wrap;
margin-top: 28px;
}
.footer-links a {
color: rgba(255,255,255,.6);
font-size: .82rem;
font-weight: 600;
transition: color .15s;
}
.footer-links a:hover { color: #fff; }
@keyframes fadeUp {
from { opacity: 0; transform: translateY(16px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 580px) {
.form-grid { grid-template-columns: 1fr; }
.card-head, .card-body { padding: 20px; }
}
</style>
</head>
<body>
<div class="toast" id="toast"></div>
<!-- Hero -->
<div class="hero">
<small>⛪ Gereja Peduli — Program Bantuan Sosial</small>
<h1>Ajukan Bantuan Sosial</h1>
<p>Isi formulir berikut untuk mengajukan permohonan bantuan. Tim kami akan memverifikasi dan menghubungi Anda secepatnya.</p>
<div class="status-flow">
<div class="flow-step">📋 Ajukan</div>
<div class="flow-step">🔍 Verifikasi</div>
<div class="flow-step">✅ Disetujui</div>
<div class="flow-step">🤝 Tersalurkan</div>
</div>
</div>
<!-- Form Card -->
<div class="card" id="formCard">
<div class="card-head">
<h2>Formulir Pengajuan Bantuan</h2>
<p>Semua data akan dijaga kerahasiaannya dan digunakan hanya untuk keperluan verifikasi bantuan.</p>
</div>
<div class="card-body">
<form id="pengajuanForm">
<div class="form-grid">
<div class="info-box">
<strong>📌 Petunjuk Pengisian</strong>
Isi semua kolom bertanda <span class="req">*</span> dengan data yang benar dan sesuai KTP.
Pengajuan akan diproses dalam 37 hari kerja.
</div>
<hr class="divider" />
<!-- Data Diri -->
<label class="full">Nama Lengkap <span class="req">*</span>
<input type="text" id="nama_pemohon" placeholder="Sesuai Kartu Tanda Penduduk" required />
</label>
<label>NIK (16 digit) <span class="req">*</span>
<input type="tel" id="nik" placeholder="1234567890123456" maxlength="16" pattern="[0-9]{16}" required />
</label>
<label>Tanggal Pengajuan <span class="req">*</span>
<input type="date" id="tanggal_pengajuan" required />
</label>
<label class="full">Alamat Lengkap <span class="req">*</span>
<textarea id="alamat" placeholder="Nama jalan, nomor rumah, RT/RW…" required></textarea>
</label>
<label>Wilayah / Paroki <span class="req">*</span>
<input type="text" id="wilayah" placeholder="Contoh: Paroki Katedral" required />
</label>
<label>No. Telepon / WhatsApp
<input type="tel" id="telepon" placeholder="08xxxxxxxxxx" />
</label>
<hr class="divider" />
<!-- Kondisi -->
<label class="full">Alasan & Kondisi Ekonomi Saat Ini <span class="req">*</span>
<textarea id="alasan" rows="5"
placeholder="Jelaskan kondisi ekonomi Anda saat ini, jenis bantuan yang dibutuhkan (pangan, pendidikan, kesehatan, dll.), dan alasan mengajukan permohonan ini…"
required></textarea>
</label>
<label>Pekerjaan Saat Ini
<select id="pekerjaan">
<option value="">— Pilih Pekerjaan —</option>
<option value="pengangguran">Tidak Bekerja / Pengangguran</option>
<option value="buruh_harian">Buruh Harian</option>
<option value="petani">Petani</option>
<option value="nelayan">Nelayan</option>
<option value="pedagang_kecil">Pedagang Kecil</option>
<option value="karyawan">Karyawan</option>
<option value="wiraswasta">Wiraswasta</option>
<option value="lainnya">Lainnya</option>
</select>
</label>
<label>Jumlah Anggota Keluarga
<input type="tel" id="jumlah_anggota" placeholder="Contoh: 5" pattern="[0-9]+" />
</label>
<div class="info-box full" style="background:#f0fdf4;border-color:#bbf7d0;color:#14532d">
<strong>🔒 Privasi &amp; Keamanan Data</strong>
Data Anda hanya digunakan untuk keperluan verifikasi bantuan sosial.
Kami tidak akan membagikan informasi Anda kepada pihak lain tanpa persetujuan.
</div>
<label class="full" style="flex-direction:row;align-items:flex-start;gap:10px;cursor:pointer">
<input type="checkbox" id="setuju" required style="width:auto;margin-top:2px" />
<span style="font-weight:600;color:#334155">
Saya menyatakan bahwa data yang saya isi adalah benar dan saya bertanggung jawab atas kebenaran informasi tersebut. <span class="req">*</span>
</span>
</label>
</div>
<button type="submit" class="btn-submit" id="submitBtn">
📋 Kirim Permohonan Bantuan
</button>
</form>
<!-- Success Screen -->
<div class="success-screen" id="successScreen">
<span class="success-icon">🎉</span>
<h2>Permohonan Terkirim!</h2>
<p>Nomor referensi pengajuan Anda:</p>
<p class="ref-num" id="refNum">#000</p>
<p style="margin-top:12px">Tim kami akan segera memverifikasi permohonan Anda dan menghubungi Anda melalui nomor telepon yang tercantum.</p>
<p style="margin-top:8px;color:#94a3b8;font-size:.82rem">Proses verifikasi biasanya memakan waktu 37 hari kerja.</p>
<button class="btn-back" onclick="resetForm()">📋 Ajukan Lagi</button>
</div>
</div>
</div>
<!-- Footer links -->
<div class="footer-links">
<a href="/poverty-map.html">🗺️ Lihat Peta Distribusi</a>
<a href="/admin-poverty.html">⚙️ Admin</a>
<a href="/">⛽ WebGIS SPBU</a>
</div>
<script>
const API = "/api/poverty";
const el = (id) => document.getElementById(id);
// Set today's date as default
el("tanggal_pengajuan").value = new Date().toISOString().slice(0, 10);
let toastTimer;
function toast(msg, dur = 3000) {
el("toast").textContent = msg;
el("toast").classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => el("toast").classList.remove("show"), dur);
}
function resetForm() {
el("pengajuanForm").reset();
el("tanggal_pengajuan").value = new Date().toISOString().slice(0, 10);
el("pengajuanForm").style.display = "block";
el("successScreen").style.display = "none";
el("submitBtn").style.display = "block";
}
el("pengajuanForm").addEventListener("submit", async (e) => {
e.preventDefault();
const btn = el("submitBtn");
btn.disabled = true;
btn.textContent = "⏳ Mengirim…";
const payload = {
nama_pemohon: el("nama_pemohon").value.trim(),
nik: el("nik").value.trim(),
alamat: el("alamat").value.trim(),
wilayah: el("wilayah").value.trim() || "Belum Dipetakan",
alasan: el("alasan").value.trim(),
tanggal_pengajuan: el("tanggal_pengajuan").value,
};
// Basic NIK validation
if (!/^\d{16}$/.test(payload.nik)) {
toast("⚠️ NIK harus 16 digit angka.");
btn.disabled = false;
btn.textContent = "📋 Kirim Permohonan Bantuan";
return;
}
try {
const res = await fetch(`${API}/pengajuan`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
const data = await res.json();
if (!res.ok || data.success === false) throw new Error(data.message || "Pengajuan gagal dikirim.");
// Show success
el("refNum").textContent = `#${String(data.id).padStart(4, "0")}`;
el("pengajuanForm").style.display = "none";
el("submitBtn").style.display = "none";
el("successScreen").style.display = "block";
} catch (err) {
toast(`${err.message}`);
btn.disabled = false;
btn.textContent = "📋 Kirim Permohonan Bantuan";
}
});
</script>
</body>
</html>
+641 -207
View File
File diff suppressed because it is too large Load Diff