feat : fix fetch bug
This commit is contained in:
+67
-24
@@ -66,7 +66,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="tabel_body_mustahik" class="divide-y divide-gray-200 text-sm text-gray-700">
|
<tbody id="tabel_body_mustahik" class="divide-y divide-gray-200 text-sm text-gray-700">
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id="pesan_tabel_kosong" class="p-10 text-center text-gray-400 text-sm hidden">Tidak ada rekaman data warga di dalam sistem.</div>
|
<div id="pesan_tabel_kosong" class="p-10 text-center text-gray-400 text-sm hidden">Tidak ada rekaman data warga di dalam sistem.</div>
|
||||||
@@ -74,8 +74,33 @@
|
|||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<div id="modal_konfirmasi" class="fixed inset-0 z-50 flex items-center justify-center hidden bg-gray-900 bg-opacity-50 backdrop-blur-sm transition-opacity">
|
||||||
|
<div class="bg-white p-6 rounded-2xl shadow-2xl w-full max-w-sm border border-gray-200 transform transition-all">
|
||||||
|
<div class="flex items-center gap-4 mb-4">
|
||||||
|
<div class="w-12 h-12 rounded-full bg-yellow-50 flex items-center justify-center text-yellow-500 flex-shrink-0">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-900">Konfirmasi Aksi</h3>
|
||||||
|
<p class="text-xs text-gray-500 mt-1">Tindakan ini akan mengubah basis data.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p id="teks_pesan_modal" class="text-sm text-gray-700 mb-6 py-2 border-y border-gray-100">
|
||||||
|
Apakah Anda yakin ingin mengubah status data ini?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-3">
|
||||||
|
<button onclick="tutup_modal()" class="px-4 py-2.5 text-xs font-bold text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-xl transition-colors">Batalkan</button>
|
||||||
|
<button onclick="eksekusi_perubahan_status()" id="btn_modal_setuju" class="px-4 py-2.5 text-xs font-bold text-white bg-gray-900 hover:bg-gray-800 rounded-xl transition-colors shadow-sm">Ya, Lanjutkan</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Fungsi membersihkan dan memperbarui isi baris tabel secara aman (XSS Prevention)
|
let antrean_id_warga = null;
|
||||||
|
let antrean_status_baru = null;
|
||||||
|
|
||||||
function muat_data_ke_tabel_admin(daftar_mustahik) {
|
function muat_data_ke_tabel_admin(daftar_mustahik) {
|
||||||
const tbody = document.getElementById('tabel_body_mustahik');
|
const tbody = document.getElementById('tabel_body_mustahik');
|
||||||
const pesan_kosong = document.getElementById('pesan_tabel_kosong');
|
const pesan_kosong = document.getElementById('pesan_tabel_kosong');
|
||||||
@@ -100,9 +125,6 @@
|
|||||||
const baris = document.createElement('tr');
|
const baris = document.createElement('tr');
|
||||||
baris.className = 'hover:bg-gray-50 transition-colors';
|
baris.className = 'hover:bg-gray-50 transition-colors';
|
||||||
|
|
||||||
/* Baris Kompleks: Kita menyusun kerangka visual baris menggunakan template literal,
|
|
||||||
namun pengisian teks string sensitif tetap diserahkan ke fungsi properti textContent
|
|
||||||
pada sub-elemen guna meminimalkan celah eksploitasi kode HTML injeksi berbahaya. */
|
|
||||||
baris.innerHTML = `
|
baris.innerHTML = `
|
||||||
<td class="p-4 text-xs font-mono text-gray-400">${indeks + 1}</td>
|
<td class="p-4 text-xs font-mono text-gray-400">${indeks + 1}</td>
|
||||||
<td class="p-4 font-semibold text-gray-900 kolom-nama"></td>
|
<td class="p-4 font-semibold text-gray-900 kolom-nama"></td>
|
||||||
@@ -119,7 +141,6 @@
|
|||||||
</td>
|
</td>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Menyuntikkan nilai teks string secara terisolasi dan aman
|
|
||||||
baris.querySelector('.kolom-nama').textContent = warga.nama_kk;
|
baris.querySelector('.kolom-nama').textContent = warga.nama_kk;
|
||||||
baris.querySelector('.kolom-nik').textContent = warga.nik;
|
baris.querySelector('.kolom-nik').textContent = warga.nik;
|
||||||
baris.querySelector('.kolom-nokk').textContent = warga.no_kk || '-';
|
baris.querySelector('.kolom-nokk').textContent = warga.no_kk || '-';
|
||||||
@@ -139,7 +160,6 @@
|
|||||||
tbody.appendChild(baris);
|
tbody.appendChild(baris);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Perbarui papan indikator agregat atas secara asinkron
|
|
||||||
document.getElementById('label_total_baris').textContent = `${daftar_mustahik.length} Rekaman`;
|
document.getElementById('label_total_baris').textContent = `${daftar_mustahik.length} Rekaman`;
|
||||||
document.getElementById('stat_total_warga').textContent = daftar_mustahik.length;
|
document.getElementById('stat_total_warga').textContent = daftar_mustahik.length;
|
||||||
document.getElementById('stat_pending_warga').textContent = hitung_pending;
|
document.getElementById('stat_pending_warga').textContent = hitung_pending;
|
||||||
@@ -147,13 +167,13 @@
|
|||||||
document.getElementById('stat_rejected_warga').textContent = hitung_rejected;
|
document.getElementById('stat_rejected_warga').textContent = hitung_rejected;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Meminta daftar seluruh entitas warga dari sistem peladen Express
|
|
||||||
async function ambil_data_admin_mustahik() {
|
async function ambil_data_admin_mustahik() {
|
||||||
const banner_error = document.getElementById('banner_error_admin');
|
const banner_error = document.getElementById('banner_error_admin');
|
||||||
try {
|
try {
|
||||||
banner_error.classList.add('hidden');
|
banner_error.classList.add('hidden');
|
||||||
|
|
||||||
const http_response = await fetch('http://localhost:3000/api/admin/mustahik');
|
// Diubah ke relative path
|
||||||
|
const http_response = await fetch('/api/admin/mustahik');
|
||||||
const json_result = await http_response.json();
|
const json_result = await http_response.json();
|
||||||
|
|
||||||
if (!http_response.ok) throw new Error(json_result.error || 'Gagal menarik data dari server.');
|
if (!http_response.ok) throw new Error(json_result.error || 'Gagal menarik data dari server.');
|
||||||
@@ -166,44 +186,67 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mengubah status persetujuan verifikasi warga via metode AJAX PATCH menuju backend
|
function ubah_status_verifikasi(id_warga, status_baru) {
|
||||||
async function ubah_status_verifikasi(id_warga, status_baru) {
|
antrean_id_warga = id_warga;
|
||||||
const banner_error = document.getElementById('banner_error_admin');
|
antrean_status_baru = status_baru;
|
||||||
|
|
||||||
if (!confirm(`Apakah Anda yakin ingin mengubah status data ini menjadi ${status_baru}?`)) {
|
const teks_pesan = document.getElementById('teks_pesan_modal');
|
||||||
return;
|
teks_pesan.innerHTML = `Apakah Anda yakin ingin mengubah status validasi menjadi <span class="font-bold text-gray-900">${status_baru}</span>?`;
|
||||||
|
|
||||||
|
const tombol_setuju = document.getElementById('btn_modal_setuju');
|
||||||
|
if (status_baru === 'Verified') {
|
||||||
|
tombol_setuju.className = 'px-4 py-2.5 text-xs font-bold text-white bg-emerald-600 hover:bg-emerald-700 rounded-xl transition-colors shadow-sm';
|
||||||
|
} else {
|
||||||
|
tombol_setuju.className = 'px-4 py-2.5 text-xs font-bold text-white bg-red-600 hover:bg-red-700 rounded-xl transition-colors shadow-sm';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.getElementById('modal_konfirmasi').classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function tutup_modal() {
|
||||||
|
document.getElementById('modal_konfirmasi').classList.add('hidden');
|
||||||
|
antrean_id_warga = null;
|
||||||
|
antrean_status_baru = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function eksekusi_perubahan_status() {
|
||||||
|
if (!antrean_id_warga || !antrean_status_baru) return;
|
||||||
|
|
||||||
|
const banner_error = document.getElementById('banner_error_admin');
|
||||||
|
const tombol_setuju = document.getElementById('btn_modal_setuju');
|
||||||
|
|
||||||
|
tombol_setuju.disabled = true;
|
||||||
|
tombol_setuju.textContent = 'Memproses...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* Baris Kompleks: Melakukan transmisi parsial status data menggunakan metode HTTP PATCH
|
// Diubah ke relative path
|
||||||
menuju endpoint verifikasi admin, membawa payload status terenkapsulasi JSON
|
const http_response = await fetch(`/api/admin/verifikasi/${antrean_id_warga}`, {
|
||||||
sehingga perubahan status langsung tercermin di file SQLite tanpa memuat ulang layar. */
|
|
||||||
const http_response = await fetch(`http://localhost:3000/api/admin/verifikasi/${id_warga}`, {
|
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ status_validasi: status_baru })
|
body: JSON.stringify({ status_validasi: antrean_status_baru })
|
||||||
});
|
});
|
||||||
|
|
||||||
const json_result = await http_response.json();
|
const json_result = await http_response.json();
|
||||||
|
|
||||||
if (!http_response.ok) throw new Error(json_result.error || 'Gagal mengubah status verifikasi.');
|
if (!http_response.ok) throw new Error(json_result.error || 'Gagal mengubah status verifikasi.');
|
||||||
|
|
||||||
// Segera sinkronkan ulang isi tabel setelah proses mutasi data berhasil
|
tutup_modal();
|
||||||
ambil_data_admin_mustahik();
|
ambil_data_admin_mustahik();
|
||||||
|
|
||||||
} catch (error_sistem) {
|
} catch (error_sistem) {
|
||||||
|
tutup_modal();
|
||||||
banner_error.textContent = 'Gagal memproses mutasi data: ' + error_sistem.message;
|
banner_error.textContent = 'Gagal memproses mutasi data: ' + error_sistem.message;
|
||||||
banner_error.classList.remove('hidden');
|
banner_error.classList.remove('hidden');
|
||||||
|
} finally {
|
||||||
|
tombol_setuju.disabled = false;
|
||||||
|
tombol_setuju.textContent = 'Ya, Lanjutkan';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mengakhiri sesi masuk administrator utama
|
|
||||||
function eksekusi_logout_admin() {
|
function eksekusi_logout_admin() {
|
||||||
localStorage.removeItem('token_admin');
|
localStorage.removeItem('token_admin');
|
||||||
window.location.href = 'index.html';
|
window.location.href = 'index.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inisialisasi awal penarikan data saat halaman terbuka sempurna
|
|
||||||
ambil_data_admin_mustahik();
|
ambil_data_admin_mustahik();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+66
-18
@@ -85,27 +85,49 @@
|
|||||||
|
|
||||||
<div class="bg-white p-5 rounded-xl shadow-sm border border-gray-200 space-y-3 text-center">
|
<div class="bg-white p-5 rounded-xl shadow-sm border border-gray-200 space-y-3 text-center">
|
||||||
<h3 class="text-xs font-bold uppercase tracking-wider text-gray-500 mb-2">Aksi Otoritas Dokumen</h3>
|
<h3 class="text-xs font-bold uppercase tracking-wider text-gray-500 mb-2">Aksi Otoritas Dokumen</h3>
|
||||||
<button onclick="proses_keputusan_admin('Verified')" class="w-full py-3 bg-emerald-600 hover:bg-emerald-700 text-white text-xs font-bold rounded-lg transition-colors shadow-sm">Setujui Sebagai Mustahik</button>
|
<button onclick="ubah_status_verifikasi(id_warga_terpilih, 'Verified')" class="w-full py-3 bg-emerald-600 hover:bg-emerald-700 text-white text-xs font-bold rounded-lg transition-colors shadow-sm">Setujui Sebagai Mustahik</button>
|
||||||
<button onclick="proses_keputusan_admin('Rejected')" class="w-full py-3 bg-red-600 hover:bg-red-700 text-white text-xs font-bold rounded-lg transition-colors shadow-sm">Tolak Pengajuan Bantuan</button>
|
<button onclick="ubah_status_verifikasi(id_warga_terpilih, 'Rejected')" class="w-full py-3 bg-red-600 hover:bg-red-700 text-white text-xs font-bold rounded-lg transition-colors shadow-sm">Tolak Pengajuan Bantuan</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<div id="modal_konfirmasi" class="fixed inset-0 z-50 flex items-center justify-center hidden bg-gray-900 bg-opacity-50 backdrop-blur-sm transition-opacity">
|
||||||
|
<div class="bg-white p-6 rounded-2xl shadow-2xl w-full max-w-sm border border-gray-200 transform transition-all">
|
||||||
|
<div class="flex items-center gap-4 mb-4">
|
||||||
|
<div class="w-12 h-12 rounded-full bg-yellow-50 flex items-center justify-center text-yellow-500 flex-shrink-0">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-bold text-gray-900">Konfirmasi Aksi</h3>
|
||||||
|
<p class="text-xs text-gray-500 mt-1">Tindakan ini akan mengubah basis data.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p id="teks_pesan_modal" class="text-sm text-gray-700 mb-6 py-2 border-y border-gray-100">
|
||||||
|
Apakah Anda yakin ingin mengubah status data ini?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="flex justify-end gap-3">
|
||||||
|
<button onclick="tutup_modal()" class="px-4 py-2.5 text-xs font-bold text-gray-600 bg-gray-100 hover:bg-gray-200 rounded-xl transition-colors">Batalkan</button>
|
||||||
|
<button onclick="eksekusi_perubahan_status()" id="btn_modal_setuju" class="px-4 py-2.5 text-xs font-bold text-white bg-gray-900 hover:bg-gray-800 rounded-xl transition-colors shadow-sm">Ya, Lanjutkan</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Ekstraksi parameter ID dari string URL query browser
|
|
||||||
const parameter_url = new URLSearchParams(window.location.search);
|
const parameter_url = new URLSearchParams(window.location.search);
|
||||||
const id_warga_terpilih = parameter_url.get('id');
|
const id_warga_terpilih = parameter_url.get('id');
|
||||||
|
|
||||||
let instansi_peta_detail = null;
|
let instansi_peta_detail = null;
|
||||||
|
let antrean_id_warga = null;
|
||||||
|
let antrean_status_baru = null;
|
||||||
|
|
||||||
// Memformat nominal angka reguler menjadi format mata uang Rupiah Indonesia
|
|
||||||
function format_mata_uang_rupiah(angka) {
|
function format_mata_uang_rupiah(angka) {
|
||||||
return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', maximumFractionDigits: 0 }).format(angka);
|
return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', maximumFractionDigits: 0 }).format(angka);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memetakan posisi koordinat spasial warga ke dalam objek Leaflet.js
|
|
||||||
function petakan_lokasi_warga(lat, lng, nama) {
|
function petakan_lokasi_warga(lat, lng, nama) {
|
||||||
if (!lat || !lng) return;
|
if (!lat || !lng) return;
|
||||||
|
|
||||||
@@ -119,9 +141,7 @@
|
|||||||
.openPopup();
|
.openPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merender seluruh string objek data yang ditarik secara aman ke komponen UI
|
|
||||||
function isi_komponen_antarmuka(data) {
|
function isi_komponen_antarmuka(data) {
|
||||||
// Keamanan XSS: Memanfaatkan textContent murni untuk mencegah injeksi skrip HTML
|
|
||||||
document.getElementById('det_id_sistem').textContent = data.id;
|
document.getElementById('det_id_sistem').textContent = data.id;
|
||||||
document.getElementById('det_nama_kk').textContent = data.nama_kk;
|
document.getElementById('det_nama_kk').textContent = data.nama_kk;
|
||||||
document.getElementById('det_nik').textContent = data.nik;
|
document.getElementById('det_nik').textContent = data.nik;
|
||||||
@@ -152,20 +172,17 @@
|
|||||||
badge.className = 'inline-block px-2.5 py-1 text-[10px] font-bold rounded-md bg-yellow-50 text-yellow-700 border border-yellow-200';
|
badge.className = 'inline-block px-2.5 py-1 text-[10px] font-bold rounded-md bg-yellow-50 text-yellow-700 border border-yellow-200';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eksekusi pemetaan visual spasial
|
|
||||||
petakan_lokasi_warga(parseFloat(data.lat), parseFloat(data.lng), data.nama_kk);
|
petakan_lokasi_warga(parseFloat(data.lat), parseFloat(data.lng), data.nama_kk);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Meminta muatan data spesifik satu warga ke peladen Express Node.js
|
|
||||||
async function ambil_data_detail_warga() {
|
async function ambil_data_detail_warga() {
|
||||||
if (!id_warga_terpilih) {
|
if (!id_warga_terpilih) {
|
||||||
return alert('ID parameter tidak ditemukan pada URL peramban.');
|
return alert('ID parameter tidak ditemukan pada URL peramban.');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* Baris Kompleks: Melakukan pemanggilan asinkron GET menuju rute detail REST API
|
// Diubah ke relative path
|
||||||
dengan menyertakan nilai parameter ID target untuk diolah kueri SQL JOIN oleh peladen. */
|
const http_response = await fetch(`/api/admin/mustahik/${id_warga_terpilih}`);
|
||||||
const http_response = await fetch(`http://localhost:3000/api/admin/mustahik/${id_warga_terpilih}`);
|
|
||||||
const json_result = await http_response.json();
|
const json_result = await http_response.json();
|
||||||
|
|
||||||
if (!http_response.ok) throw new Error(json_result.error || 'Gagal mengambil data detail.');
|
if (!http_response.ok) throw new Error(json_result.error || 'Gagal mengambil data detail.');
|
||||||
@@ -177,29 +194,60 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memproses mutasi perubahan status persetujuan data dari panel admin ke server
|
function ubah_status_verifikasi(id_warga, status_baru) {
|
||||||
async function proses_keputusan_admin(keputusan_status) {
|
antrean_id_warga = id_warga;
|
||||||
if (!confirm(`Apakah Anda yakin memvalidasi data ini dengan status ${keputusan_status}?`)) return;
|
antrean_status_baru = status_baru;
|
||||||
|
|
||||||
|
const teks_pesan = document.getElementById('teks_pesan_modal');
|
||||||
|
teks_pesan.innerHTML = `Apakah Anda yakin memvalidasi data ini dengan status <span class="font-bold text-gray-900">${status_baru}</span>?`;
|
||||||
|
|
||||||
|
const tombol_setuju = document.getElementById('btn_modal_setuju');
|
||||||
|
if (status_baru === 'Verified') {
|
||||||
|
tombol_setuju.className = 'px-4 py-2.5 text-xs font-bold text-white bg-emerald-600 hover:bg-emerald-700 rounded-xl transition-colors shadow-sm';
|
||||||
|
} else {
|
||||||
|
tombol_setuju.className = 'px-4 py-2.5 text-xs font-bold text-white bg-red-600 hover:bg-red-700 rounded-xl transition-colors shadow-sm';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('modal_konfirmasi').classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function tutup_modal() {
|
||||||
|
document.getElementById('modal_konfirmasi').classList.add('hidden');
|
||||||
|
antrean_id_warga = null;
|
||||||
|
antrean_status_baru = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function eksekusi_perubahan_status() {
|
||||||
|
if (!antrean_id_warga || !antrean_status_baru) return;
|
||||||
|
|
||||||
|
const tombol_setuju = document.getElementById('btn_modal_setuju');
|
||||||
|
tombol_setuju.disabled = true;
|
||||||
|
tombol_setuju.textContent = 'Memproses...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const http_response = await fetch(`http://localhost:3000/api/admin/verifikasi/${id_warga_terpilih}`, {
|
// Diubah ke relative path
|
||||||
|
const http_response = await fetch(`/api/admin/verifikasi/${antrean_id_warga}`, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ status_validasi: keputusan_status })
|
body: JSON.stringify({ status_validasi: antrean_status_baru })
|
||||||
});
|
});
|
||||||
|
|
||||||
const json_result = await http_response.json();
|
const json_result = await http_response.json();
|
||||||
if (!http_response.ok) throw new Error(json_result.error || 'Gagal mengubah status.');
|
if (!http_response.ok) throw new Error(json_result.error || 'Gagal mengubah status.');
|
||||||
|
|
||||||
|
tutup_modal();
|
||||||
alert('Status otorisasi data berhasil diperbarui!');
|
alert('Status otorisasi data berhasil diperbarui!');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
|
|
||||||
} catch (error_sistem) {
|
} catch (error_sistem) {
|
||||||
|
tutup_modal();
|
||||||
alert('Gagal mengeksekusi perintah: ' + error_sistem.message);
|
alert('Gagal mengeksekusi perintah: ' + error_sistem.message);
|
||||||
|
} finally {
|
||||||
|
tombol_setuju.disabled = false;
|
||||||
|
tombol_setuju.textContent = 'Ya, Lanjutkan';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eksekusi inisialisasi pemuatan data awal
|
|
||||||
ambil_data_detail_warga();
|
ambil_data_detail_warga();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+2
-9
@@ -33,7 +33,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Mengirimkan data otentikasi admin menuju API backend server secara asinkron
|
|
||||||
async function eksekusi_login_admin() {
|
async function eksekusi_login_admin() {
|
||||||
const username_val = document.getElementById('input_username').value;
|
const username_val = document.getElementById('input_username').value;
|
||||||
const password_val = document.getElementById('input_password').value;
|
const password_val = document.getElementById('input_password').value;
|
||||||
@@ -51,10 +50,8 @@
|
|||||||
tombol_login.textContent = 'Otorisasi Sistem...';
|
tombol_login.textContent = 'Otorisasi Sistem...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* Baris Kompleks: Mengirimkan request POST JSON payload kredensial admin ke server port 3000.
|
// Diubah ke relative path
|
||||||
Jika kredensial terverifikasi sah oleh database, string token otorisasi disimpan ke dalam localStorage
|
const http_response = await fetch('/api/auth/login-admin', {
|
||||||
peramban sebelum mengalihkan hak akses visual secara penuh ke halaman dasbor admin. */
|
|
||||||
const http_response = await fetch('http://localhost:3000/api/auth/login-admin', {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@@ -71,10 +68,7 @@
|
|||||||
throw new Error(json_result.error || 'Akses ditolak oleh otoritas server.');
|
throw new Error(json_result.error || 'Akses ditolak oleh otoritas server.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Menyimpan identitas sesi token administrator ke memori lokal peramban web
|
|
||||||
localStorage.setItem('token_admin', json_result.token);
|
localStorage.setItem('token_admin', json_result.token);
|
||||||
|
|
||||||
// Redireksi antarmuka secara instan menuju halaman dasbor pusat kontrol utama
|
|
||||||
window.location.href = 'admin_dasbor.html';
|
window.location.href = 'admin_dasbor.html';
|
||||||
|
|
||||||
} catch (error_sistem) {
|
} catch (error_sistem) {
|
||||||
@@ -86,7 +80,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mengikat event liistener enter pada kolom kata sandi admin untuk efisiensi aksesibilitas
|
|
||||||
document.getElementById('input_password').addEventListener('keypress', function(e) {
|
document.getElementById('input_password').addEventListener('keypress', function(e) {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
eksekusi_login_admin();
|
eksekusi_login_admin();
|
||||||
|
|||||||
+5
-11
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
<div id="hasil_pencarian" class="mt-6 hidden p-4 rounded-xl border max-w-xl mx-auto text-left bg-white text-gray-800 shadow-lg transition-all">
|
<div id="hasil_pencarian" class="mt-6 hidden p-4 rounded-xl border max-w-xl mx-auto text-left bg-white text-gray-800 shadow-lg transition-all">
|
||||||
<p id="pesan_hasil" class="text-sm font-semibold"></p>
|
<p id="pesan_hasil" class="text-sm font-semibold"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -105,22 +105,17 @@
|
|||||||
|
|
||||||
let map_marker = null;
|
let map_marker = null;
|
||||||
|
|
||||||
// Fungsi baru untuk memuat statistik secara asinkron dari basis data
|
|
||||||
async function muat_statistik_publik() {
|
async function muat_statistik_publik() {
|
||||||
try {
|
try {
|
||||||
const respons_http = await fetch('http://localhost:3000/api/survey/statistik');
|
// Diubah ke relative path
|
||||||
|
const respons_http = await fetch('/api/survey/statistik');
|
||||||
if (!respons_http.ok) throw new Error('Gagal mengambil data statistik');
|
if (!respons_http.ok) throw new Error('Gagal mengambil data statistik');
|
||||||
|
|
||||||
const data_agregat = await respons_http.json();
|
const data_agregat = await respons_http.json();
|
||||||
|
|
||||||
// Memasukkan hasil hitungan ke dalam DOM menggunakan textContent
|
|
||||||
document.getElementById('stat_publik_terverifikasi').textContent = data_agregat.terverifikasi || 0;
|
document.getElementById('stat_publik_terverifikasi').textContent = data_agregat.terverifikasi || 0;
|
||||||
document.getElementById('stat_publik_diproses').textContent = data_agregat.diproses || 0;
|
document.getElementById('stat_publik_diproses').textContent = data_agregat.diproses || 0;
|
||||||
|
|
||||||
/* Baris Kompleks: Menggunakan objek bawaan Date pada JavaScript untuk
|
|
||||||
mendapatkan waktu spesifik saat skrip ini berjalan di perangkat pengguna,
|
|
||||||
lalu memformatnya secara spesifik ke dalam zona waktu WIB (Asia/Jakarta)
|
|
||||||
agar seragam untuk seluruh pengunjung situs terlepas dari lokasi fisik perangkat mereka. */
|
|
||||||
const objek_waktu_sekarang = new Date();
|
const objek_waktu_sekarang = new Date();
|
||||||
const waktu_terformat_wib = objek_waktu_sekarang.toLocaleTimeString('id-ID', {
|
const waktu_terformat_wib = objek_waktu_sekarang.toLocaleTimeString('id-ID', {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
@@ -150,7 +145,8 @@
|
|||||||
tombol_cari.textContent = 'Mencari...';
|
tombol_cari.textContent = 'Mencari...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const http_response = await fetch(`http://localhost:3000/api/survey/cek-nik/${input_nik_value}`);
|
// Diubah ke relative path
|
||||||
|
const http_response = await fetch(`/api/survey/cek-nik/${input_nik_value}`);
|
||||||
|
|
||||||
if (!http_response.ok) {
|
if (!http_response.ok) {
|
||||||
throw new Error('Data tidak ditemukan');
|
throw new Error('Data tidak ditemukan');
|
||||||
@@ -186,9 +182,7 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mengeksekusi penarikan data statistik tepat saat halaman selesai dimuat
|
|
||||||
muat_statistik_publik();
|
muat_statistik_publik();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+7
-36
@@ -62,27 +62,18 @@
|
|||||||
<div id="status_message_container" class="p-8 text-center text-sm text-gray-500 hidden"></div>
|
<div id="status_message_container" class="p-8 text-center text-sm text-gray-500 hidden"></div>
|
||||||
|
|
||||||
<div class="divide-y divide-gray-100" id="wadah_list_antrean">
|
<div class="divide-y divide-gray-100" id="wadah_list_antrean">
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Mengambil token autentikasi petugas untuk validasi sesi REST API
|
|
||||||
const token_petugas = localStorage.getItem('token_petugas');
|
const token_petugas = localStorage.getItem('token_petugas');
|
||||||
|
|
||||||
// Fungsi pengecekan proteksi halaman (RBAC) saat pertama kali dimuat
|
|
||||||
function periksa_sesi_petugas() {
|
function periksa_sesi_petugas() {
|
||||||
/* Sesi dummy dinonaktifkan sementara untuk mempermudah pengujian UAS.
|
// Sesi dinonaktifkan sementara untuk mempermudah testing
|
||||||
Jika nanti sistem login admin/petugas Anda sudah aktif menggunakan JWT,
|
|
||||||
cukup hapus baris komentar pada blok proteksi di bawah ini. */
|
|
||||||
// if (!token_petugas) {
|
|
||||||
// alert('Akses ditolak. Silakan login terlebih dahulu.');
|
|
||||||
// window.location.href = 'petugas_login.html';
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fungsi merender list data antrean warga ke elemen DOM secara aman (XSS Prevention)
|
|
||||||
function render_data_ke_tabel(daftar_warga) {
|
function render_data_ke_tabel(daftar_warga) {
|
||||||
const wadah_list = document.getElementById('wadah_list_antrean');
|
const wadah_list = document.getElementById('wadah_list_antrean');
|
||||||
const label_antrean = document.getElementById('label_jumlah_antrean');
|
const label_antrean = document.getElementById('label_jumlah_antrean');
|
||||||
@@ -96,7 +87,6 @@
|
|||||||
|
|
||||||
label_antrean.textContent = `${daftar_warga.length} Rumah Tangga`;
|
label_antrean.textContent = `${daftar_warga.length} Rumah Tangga`;
|
||||||
|
|
||||||
// Variabel counter untuk menghitung jumlah status agregat data
|
|
||||||
let total_pending = 0;
|
let total_pending = 0;
|
||||||
let total_verified = 0;
|
let total_verified = 0;
|
||||||
|
|
||||||
@@ -107,9 +97,6 @@
|
|||||||
const item_div = document.createElement('div');
|
const item_div = document.createElement('div');
|
||||||
item_div.className = 'p-4 flex justify-between items-center hover:bg-gray-50 transition-colors';
|
item_div.className = 'p-4 flex justify-between items-center hover:bg-gray-50 transition-colors';
|
||||||
|
|
||||||
/* Baris Kompleks: Pembuatan elemen daftar dilakukan dengan kombinasi literal template Tailwind CSS.
|
|
||||||
Setiap teks string mentah yang berasal dari properti database dilewatkan melalui properti textContent
|
|
||||||
pada sub-elemen internal terpisah guna menangkal celah keamanan injeksi skrip berbahaya (Cross-Site Scripting). */
|
|
||||||
item_div.innerHTML = `
|
item_div.innerHTML = `
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
<h4 class="font-bold text-gray-800 text-sm kelas-nama"></h4>
|
<h4 class="font-bold text-gray-800 text-sm kelas-nama"></h4>
|
||||||
@@ -123,14 +110,12 @@
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Menyuntikkan nilai data secara aman menggunakan textContent
|
|
||||||
item_div.querySelector('.kelas-nama').textContent = warga.nama_kk;
|
item_div.querySelector('.kelas-nama').textContent = warga.nama_kk;
|
||||||
item_div.querySelector('.kelas-nik').textContent = warga.nik;
|
item_div.querySelector('.kelas-nik').textContent = warga.nik;
|
||||||
|
|
||||||
const badge = item_div.querySelector('.kelas-badge');
|
const badge = item_div.querySelector('.kelas-badge');
|
||||||
badge.textContent = warga.status_validasi;
|
badge.textContent = warga.status_validasi;
|
||||||
|
|
||||||
// Menentukan warna badge visual berdasarkan status validasi dari database
|
|
||||||
if (warga.status_validasi.toLowerCase() === 'verified') {
|
if (warga.status_validasi.toLowerCase() === 'verified') {
|
||||||
badge.className += ' bg-emerald-50 text-emerald-700';
|
badge.className += ' bg-emerald-50 text-emerald-700';
|
||||||
} else if (warga.status_validasi.toLowerCase() === 'rejected') {
|
} else if (warga.status_validasi.toLowerCase() === 'rejected') {
|
||||||
@@ -142,13 +127,11 @@
|
|||||||
wadah_list.appendChild(item_div);
|
wadah_list.appendChild(item_div);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Memperbarui indikator angka papan KPI atas
|
|
||||||
document.getElementById('stat_total').textContent = daftar_warga.length;
|
document.getElementById('stat_total').textContent = daftar_warga.length;
|
||||||
document.getElementById('stat_pending').textContent = total_pending;
|
document.getElementById('stat_pending').textContent = total_pending;
|
||||||
document.getElementById('stat_verified').textContent = total_verified;
|
document.getElementById('stat_verified').textContent = total_verified;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mengambil data seluruh antrean mustahik dari server backend Node.js
|
|
||||||
async function ambil_antrean_survei() {
|
async function ambil_antrean_survei() {
|
||||||
const msg_container = document.getElementById('status_message_container');
|
const msg_container = document.getElementById('status_message_container');
|
||||||
|
|
||||||
@@ -156,22 +139,13 @@
|
|||||||
msg_container.classList.remove('hidden');
|
msg_container.classList.remove('hidden');
|
||||||
msg_container.textContent = 'Memuat daftar antrean wilayah...';
|
msg_container.textContent = 'Memuat daftar antrean wilayah...';
|
||||||
|
|
||||||
/* Contoh implementasi fetch asinkron ke server lokal port 3000.
|
// Diubah ke relative path dan diaktifkan untuk mengambil data aslinya
|
||||||
Gunakan endpoint yang sesuai (misal mengambil seluruh data MUSTAHIK untuk petugas) */
|
const respons = await fetch('/api/admin/mustahik');
|
||||||
// const respons = await fetch('http://localhost:3000/api/survey/list-antrean');
|
if (!respons.ok) throw new Error('Gagal mengambil data dari server.');
|
||||||
// if (!respons.ok) throw new Error('Gagal mengambil data dari server.');
|
const data_warga = await respons.json();
|
||||||
// const data_warga = await respons.json();
|
|
||||||
|
|
||||||
// Simulasi Data Mock untuk testing (Hapus blok ini jika endpoint backend Anda sudah siap)
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 600));
|
|
||||||
const data_warga_mock = [
|
|
||||||
{ nik: "6171012345670001", nama_kk: "Syahroni", status_validasi: "Pending" },
|
|
||||||
{ nik: "6171029876540002", nama_kk: "Mariani", status_validasi: "Pending" },
|
|
||||||
{ nik: "6171031122330003", nama_kk: "Zulkifli", status_validasi: "Verified" }
|
|
||||||
];
|
|
||||||
|
|
||||||
msg_container.classList.add('hidden');
|
msg_container.classList.add('hidden');
|
||||||
render_data_ke_tabel(data_warga_mock);
|
render_data_ke_tabel(data_warga);
|
||||||
|
|
||||||
} catch (error_sistem) {
|
} catch (error_sistem) {
|
||||||
msg_container.classList.remove('hidden');
|
msg_container.classList.remove('hidden');
|
||||||
@@ -179,17 +153,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fungsi menghapus token autentikasi sesi saat petugas keluar aplikasi
|
|
||||||
function proses_logout_petugas() {
|
function proses_logout_petugas() {
|
||||||
localStorage.removeItem('token_petugas');
|
localStorage.removeItem('token_petugas');
|
||||||
alert('Sesi berhasil diakhiri.');
|
alert('Sesi berhasil diakhiri.');
|
||||||
window.location.href = 'index.html';
|
window.location.href = 'index.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eksekusi trigger inisialisasi awal saat halaman selesai dimuat oleh browser
|
|
||||||
periksa_sesi_petugas();
|
periksa_sesi_petugas();
|
||||||
ambil_antrean_survei();
|
ambil_antrean_survei();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
+2
-10
@@ -28,14 +28,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Mengirimkan data otentikasi menuju API backend server
|
|
||||||
async function eksekusi_login_petugas() {
|
async function eksekusi_login_petugas() {
|
||||||
const username_val = document.getElementById('input_username').value;
|
const username_val = document.getElementById('input_username').value;
|
||||||
const password_val = document.getElementById('input_password').value;
|
const password_val = document.getElementById('input_password').value;
|
||||||
const wadah_error = document.getElementById('pesan_error');
|
const wadah_error = document.getElementById('pesan_error');
|
||||||
const tombol_login = document.getElementById('btn_submit_login');
|
const tombol_login = document.getElementById('btn_submit_login');
|
||||||
|
|
||||||
// Validasi masukan dasar pada sisi klien sebelum memicu lalu lintas jaringan
|
|
||||||
if (!username_val || !password_val) {
|
if (!username_val || !password_val) {
|
||||||
wadah_error.textContent = 'Kolom username dan kata sandi tidak boleh kosong.';
|
wadah_error.textContent = 'Kolom username dan kata sandi tidak boleh kosong.';
|
||||||
wadah_error.classList.remove('hidden');
|
wadah_error.classList.remove('hidden');
|
||||||
@@ -47,10 +45,8 @@
|
|||||||
tombol_login.textContent = 'Memverifikasi...';
|
tombol_login.textContent = 'Memverifikasi...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* Baris Kompleks: Melakukan transmisi payload data sensitif terenkripsi via jaringan menggunakan HTTP POST
|
// Diubah ke relative path
|
||||||
menuju peladen port 3000, serta menyimpan string token autentikasi ke media penyimpanan lokal peramban
|
const http_response = await fetch('/api/auth/login-petugas', {
|
||||||
(localStorage) jika validasi kredensial dinyatakan sah oleh server database. */
|
|
||||||
const http_response = await fetch('http://localhost:3000/api/auth/login-petugas', {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
@@ -67,10 +63,7 @@
|
|||||||
throw new Error(json_result.error || 'Gagal masuk ke dalam sistem.');
|
throw new Error(json_result.error || 'Gagal masuk ke dalam sistem.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Menyimpan identitas sesi token ke memori peramban web klien
|
|
||||||
localStorage.setItem('token_petugas', json_result.token);
|
localStorage.setItem('token_petugas', json_result.token);
|
||||||
|
|
||||||
// Mengalihkan fokus antarmuka menuju halaman dasbor manajemen tugas lapangan
|
|
||||||
window.location.href = 'petugas_dasbor.html';
|
window.location.href = 'petugas_dasbor.html';
|
||||||
|
|
||||||
} catch (error_sistem) {
|
} catch (error_sistem) {
|
||||||
@@ -82,7 +75,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mendukung eksekusi tombol enter saat berada di kolom input kata sandi
|
|
||||||
document.getElementById('input_password').addEventListener('keypress', function(e) {
|
document.getElementById('input_password').addEventListener('keypress', function(e) {
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
eksekusi_login_petugas();
|
eksekusi_login_petugas();
|
||||||
|
|||||||
+3
-20
@@ -196,7 +196,6 @@
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Deklarasi Status Langkah Global
|
|
||||||
let langkah_sekarang = 1;
|
let langkah_sekarang = 1;
|
||||||
const total_langkah = 4;
|
const total_langkah = 4;
|
||||||
|
|
||||||
@@ -208,25 +207,19 @@
|
|||||||
const btn_kirim = document.getElementById('btn_kirim');
|
const btn_kirim = document.getElementById('btn_kirim');
|
||||||
const peringatan_error = document.getElementById('peringatan_error');
|
const peringatan_error = document.getElementById('peringatan_error');
|
||||||
|
|
||||||
// Menampilkan pesan notifikasi kegagalan validasi ke antarmuka pengguna
|
|
||||||
function tampilkan_error(pesan) {
|
function tampilkan_error(pesan) {
|
||||||
peringatan_error.textContent = pesan;
|
peringatan_error.textContent = pesan;
|
||||||
peringatan_error.classList.remove('hidden');
|
peringatan_error.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Menyembunyikan wadah notifikasi kegagalan
|
|
||||||
function sembunyikan_error() {
|
function sembunyikan_error() {
|
||||||
peringatan_error.classList.add('hidden');
|
peringatan_error.classList.add('hidden');
|
||||||
peringatan_error.textContent = '';
|
peringatan_error.textContent = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memastikan kelayakan data masukan di setiap bagian formulir sebelum melangkah
|
|
||||||
function validasi_langkah_aktif() {
|
function validasi_langkah_aktif() {
|
||||||
sembunyikan_error();
|
sembunyikan_error();
|
||||||
|
|
||||||
/* Baris Kompleks: Logika kondisional bersarang (switch case) memisahkan aturan validasi
|
|
||||||
berdasarkan indeks tahapan aktif, memastikan konversi dan ekspresi reguler teks tepat
|
|
||||||
sebelum dievaluasi agar terhindar dari pengiriman muatan bernilai kosong ke server. */
|
|
||||||
switch(langkah_sekarang) {
|
switch(langkah_sekarang) {
|
||||||
case 1:
|
case 1:
|
||||||
if (!/^\d{16}$/.test(document.getElementById('input_nik').value)) {
|
if (!/^\d{16}$/.test(document.getElementById('input_nik').value)) {
|
||||||
@@ -260,7 +253,7 @@
|
|||||||
!document.getElementById('input_sumber_penerangan').value ||
|
!document.getElementById('input_sumber_penerangan').value ||
|
||||||
!document.getElementById('input_frekuensi_makan').value ||
|
!document.getElementById('input_frekuensi_makan').value ||
|
||||||
!document.getElementById('input_kepemilikan_aset').value) {
|
!document.getElementById('input_kepemilikan_aset').value) {
|
||||||
tampilkan_error('Seluruh parameter utilitas dan sosial ekonomi wajib dipilih.');
|
tampilkan_error('Seluruh parameter utilitas and sosial ekonomi wajib dipilih.');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (document.getElementById('input_pekerjaan').value.trim() === '') {
|
if (document.getElementById('input_pekerjaan').value.trim() === '') {
|
||||||
@@ -283,7 +276,6 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Menggerakkan alur visual formulir multi-langkah maju atau mundur
|
|
||||||
function ubah_langkah(arah) {
|
function ubah_langkah(arah) {
|
||||||
if (arah === 1 && !validasi_langkah_aktif()) return;
|
if (arah === 1 && !validasi_langkah_aktif()) return;
|
||||||
|
|
||||||
@@ -294,7 +286,6 @@
|
|||||||
perbarui_antarmuka_wizard();
|
perbarui_antarmuka_wizard();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sinkronisasi status bar kemajuan dan kontrol tombol navigasi bawah
|
|
||||||
function perbarui_antarmuka_wizard() {
|
function perbarui_antarmuka_wizard() {
|
||||||
if (langkah_sekarang === 1) {
|
if (langkah_sekarang === 1) {
|
||||||
btn_mundur.classList.add('hidden');
|
btn_mundur.classList.add('hidden');
|
||||||
@@ -327,7 +318,6 @@
|
|||||||
if(document.getElementById('garis_3')) document.getElementById('garis_3').style.width = langkah_sekarang >= 4 ? '100%' : '0%';
|
if(document.getElementById('garis_3')) document.getElementById('garis_3').style.width = langkah_sekarang >= 4 ? '100%' : '0%';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inisialisasi komponen GIS Leaflet untuk penentuan lokasi rumah warga
|
|
||||||
function inisialisasi_peta() {
|
function inisialisasi_peta() {
|
||||||
if (instansi_peta !== null) {
|
if (instansi_peta !== null) {
|
||||||
instansi_peta.invalidateSize();
|
instansi_peta.invalidateSize();
|
||||||
@@ -339,9 +329,6 @@
|
|||||||
attribution: '© OpenStreetMap'
|
attribution: '© OpenStreetMap'
|
||||||
}).addTo(instansi_peta);
|
}).addTo(instansi_peta);
|
||||||
|
|
||||||
/* Baris Kompleks: Penangkapan event klik pada objek peta Leaflet secara dinamis
|
|
||||||
mengekstrak properti koordinat lintang dan bujur (latlng) untuk memindahkan objek penanda
|
|
||||||
serta mengisi elemen masukan teks masukan secara otomatis. */
|
|
||||||
instansi_peta.on('click', function(e) {
|
instansi_peta.on('click', function(e) {
|
||||||
const lat = e.latlng.lat;
|
const lat = e.latlng.lat;
|
||||||
const lng = e.latlng.lng;
|
const lng = e.latlng.lng;
|
||||||
@@ -355,7 +342,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mengakses perangkat keras penerima gelombang navigasi satelit melalui web API browser
|
|
||||||
function dapatkan_lokasi_gps() {
|
function dapatkan_lokasi_gps() {
|
||||||
if (navigator.geolocation) {
|
if (navigator.geolocation) {
|
||||||
navigator.geolocation.getCurrentPosition(
|
navigator.geolocation.getCurrentPosition(
|
||||||
@@ -380,14 +366,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mengirimkan enkapsulasi objek data survei menuju web server secara asinkron
|
|
||||||
async function kirim_data_survei() {
|
async function kirim_data_survei() {
|
||||||
if (!validasi_langkah_aktif()) return;
|
if (!validasi_langkah_aktif()) return;
|
||||||
|
|
||||||
btn_kirim.disabled = true;
|
btn_kirim.disabled = true;
|
||||||
btn_kirim.innerHTML = 'Mengirim Data...';
|
btn_kirim.innerHTML = 'Mengirim Data...';
|
||||||
|
|
||||||
// Konstruksi objek payload JSON disesuaikan secara presisi dengan skema database_baru.sqlite
|
|
||||||
const payload_survei = {
|
const payload_survei = {
|
||||||
nik: document.getElementById('input_nik').value,
|
nik: document.getElementById('input_nik').value,
|
||||||
nama_kk: document.getElementById('input_nama_kk').value,
|
nama_kk: document.getElementById('input_nama_kk').value,
|
||||||
@@ -411,9 +395,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* Baris Kompleks: Eksekusi transmisi data asinkron via HTTP POST menuju endpoint server.
|
// Diubah ke relative path
|
||||||
Header 'Content-Type' diset ke JSON agar dapat dibaca oleh middleware express.json() di backend. */
|
const http_response = await fetch('/api/survey/submit', {
|
||||||
const http_response = await fetch('http://localhost:3000/api/survey/submit', {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(payload_survei)
|
body: JSON.stringify(payload_survei)
|
||||||
|
|||||||
Reference in New Issue
Block a user