const Penduduk = (() => {
let all = [], filtered = [], editNIK = null;
const DEMO = [
{ nik:'6171010101010001', nama_lengkap:'Ahmad Suryana', umur:44, status_keluarga:'kepala', pekerjaan:'Buruh Harian', penghasilan:900000, status_ekonomi:'miskin', kondisi_kesehatan:'sehat', pendidikan_terakhir:'SMP', no_kk:'6171010101010001', kecamatan:'Pontianak Timur' },
{ nik:'6171010101010002', nama_lengkap:'Siti Rahma', umur:39, status_keluarga:'istri', pekerjaan:'Ibu RT', penghasilan:0, status_ekonomi:'miskin', kondisi_kesehatan:'sakit_ringan',pendidikan_terakhir:'SD', no_kk:'6171010101010001', kecamatan:'Pontianak Timur' },
{ nik:'6171010101010003', nama_lengkap:'Budi Suryana', umur:12, status_keluarga:'anak', pekerjaan:'Pelajar', penghasilan:0, status_ekonomi:'miskin', kondisi_kesehatan:'sehat', pendidikan_terakhir:'SMP', no_kk:'6171010101010001', kecamatan:'Pontianak Timur' },
{ nik:'6171010101010004', nama_lengkap:'Samsul Bahri', umur:49, status_keluarga:'kepala', pekerjaan:'Pedagang Kaki Lima',penghasilan:1200000,status_ekonomi:'rentan', kondisi_kesehatan:'sehat', pendidikan_terakhir:'SMA_SMK', no_kk:'6171010101010002', kecamatan:'Pontianak Kota' },
{ nik:'6171010101010005', nama_lengkap:'Dewi Kartika', umur:46, status_keluarga:'istri', pekerjaan:'Buruh Cuci', penghasilan:500000, status_ekonomi:'rentan', kondisi_kesehatan:'sehat', pendidikan_terakhir:'SD', no_kk:'6171010101010002', kecamatan:'Pontianak Kota' },
{ nik:'6171010101010006', nama_lengkap:'Maria Magdalena', umur:54, status_keluarga:'kepala', pekerjaan:'Penjual Gorengan',penghasilan:800000, status_ekonomi:'miskin', kondisi_kesehatan:'sakit_berat', pendidikan_terakhir:'SD', no_kk:'6171010101010003', kecamatan:'Pontianak Selatan' },
{ nik:'6171010101010007', nama_lengkap:'Petrus Yulius', umur:19, status_keluarga:'anak', pekerjaan:'Pelajar', penghasilan:0, status_ekonomi:'miskin', kondisi_kesehatan:'sehat', pendidikan_terakhir:'SMA_SMK', no_kk:'6171010101010003', kecamatan:'Pontianak Selatan' },
{ nik:'6171010101010010', nama_lengkap:'Lim Ah Kow', umur:59, status_keluarga:'kepala', pekerjaan:'Tidak Bekerja', penghasilan:0, status_ekonomi:'miskin', kondisi_kesehatan:'sakit_berat', pendidikan_terakhir:'SD', no_kk:'6171010101010005', kecamatan:'Pontianak Kota' },
{ nik:'6171010101010012', nama_lengkap:'Mulyadi', umur:45, status_keluarga:'kepala', pekerjaan:'PNS Gol. III', penghasilan:4500000, status_ekonomi:'mampu', kondisi_kesehatan:'sehat', pendidikan_terakhir:'S1', no_kk:'6171010101010006', kecamatan:'Pontianak Timur' },
{ nik:'6171010101010014', nama_lengkap:'Tan Eng Huat', umur:65, status_keluarga:'kepala', pekerjaan:'Pemulung', penghasilan:600000, status_ekonomi:'miskin', kondisi_kesehatan:'disabilitas', pendidikan_terakhir:'SD', no_kk:'6171010101010008', kecamatan:'Pontianak Kota' },
];
async function load() {
try { all = await Api.get('/penduduk'); } catch { all = DEMO; }
filtered = [...all];
render(filtered);
ge('pf-count').textContent = `${all.length} total`;
}
function search(q) { applyFilter(q); }
function applyFilter(qOverride) {
const q = qOverride ?? gv('pf-search');
const ek = gv('pf-ekonomi');
const ke = gv('pf-kesehatan');
filtered = all.filter(p =>
(!q || p.nama_lengkap?.toLowerCase().includes(q.toLowerCase()) || p.nik?.includes(q)) &&
(!ek || p.status_ekonomi === ek) &&
(!ke || p.kondisi_kesehatan === ke)
);
render(filtered);
ge('pf-count').textContent = `${filtered.length} / ${all.length}`;
}
const pendidikanLabel = { tidak_sekolah:'Tdk Sekolah', SD:'SD', SMP:'SMP', SMA_SMK:'SMA/SMK', D1_D3:'D3', S1:'S1', S2_S3:'S2/S3' };
function render(data) {
const tb = ge('tbody-penduduk');
if (!data.length) { tb.innerHTML = '
π Tidak ada dataCoba ubah filter pencarian |
'; return; }
tb.innerHTML = data.map(p => `
| ${p.nik} |
${p.nama_lengkap} ${p.kecamatan||''} |
${p.umur||'?'} th |
${cap(p.status_keluarga)} |
${p.pekerjaan||'β'} |
${rp(p.penghasilan)} |
${bdg(p.status_ekonomi,'')} |
${bdg(p.kondisi_kesehatan,'')} |
${pendidikanLabel[p.pendidikan_terakhir]||p.pendidikan_terakhir||'β'} |
|
`).join('');
}
async function showForm(nik = null) {
editNIK = nik;
ge('mp-title').textContent = nik ? `βοΈ Edit β ${nik}` : 'β Tambah Penduduk Baru';
ge('fp-nik').readOnly = !!nik;
await loadKKDropdown();
if (nik) {
try {
const p = await Api.get(`/penduduk/${nik}`);
fillForm(p);
} catch {
const p = all.find(x => x.nik === nik);
if (p) fillForm(p);
}
} else {
['fp-nik','fp-nama','fp-tempat','fp-pekerjaan','fp-ket-sehat'].forEach(id => sv(id,''));
sv('fp-penghasilan','0'); sv('fp-umur','');
ge('fp-warn').classList.add('hidden');
}
App.showModal('modal-penduduk');
}
function fillForm(p) {
sv('fp-nik', p.nik); sv('fp-nama', p.nama_lengkap);
sv('fp-jkel', p.jenis_kelamin); sv('fp-tgl', p.tanggal_lahir?.substring(0,10));
sv('fp-umur', p.umur ? `${p.umur} tahun` : '');
sv('fp-tempat', p.tempat_lahir); sv('fp-agama', p.agama);
sv('fp-status-kk', p.status_keluarga); sv('fp-kawin', p.status_perkawinan);
sv('fp-hidup', p.status_hidup); sv('fp-ekonomi', p.status_ekonomi);
sv('fp-pekerjaan', p.pekerjaan); sv('fp-penghasilan', p.penghasilan || 0);
sv('fp-pendidikan', p.pendidikan_terakhir); sv('fp-stat-pend', p.status_pendidikan);
sv('fp-kesehatan', p.kondisi_kesehatan); sv('fp-ket-sehat', p.keterangan_kesehatan);
if (p.id_keluarga) sv('fp-kk', p.id_keluarga);
}
async function loadKKDropdown() {
const sel = ge('fp-kk');
try {
const list = await Api.get('/keluarga');
sel.innerHTML = list.map(k => ``).join('');
} catch {
sel.innerHTML = '';
}
}
function hitungUmur() {
const tgl = gv('fp-tgl');
if (!tgl) return;
const umur = Math.floor((Date.now() - new Date(tgl)) / (365.25*24*3600*1000));
sv('fp-umur', `${umur} tahun`);
// Validasi
const pend = gv('fp-pendidikan'), stat = gv('fp-stat-pend');
const warns = [];
if (umur >= 7 && umur <= 15 && stat === 'tidak_sekolah')
warns.push(`β οΈ Usia ${umur} tahun β seharusnya masih wajib belajar (SD/SMP)`);
if (umur >= 16 && umur <= 18 && stat === 'tidak_sekolah' && ['tidak_sekolah','SD'].includes(pend))
warns.push(`β οΈ Usia ${umur} tahun β disarankan melanjutkan ke SMA/SMK`);
const wEl = ge('fp-warn');
if (warns.length) { wEl.innerHTML = warns.join('
'); wEl.classList.remove('hidden'); }
else wEl.classList.add('hidden');
}
async function save() {
const nik = gv('fp-nik');
if (!nik || nik.length !== 16 || !/^\d+$/.test(nik)) { App.toast('NIK harus 16 digit angka','error'); return; }
if (!gv('fp-nama')) { App.toast('Nama lengkap wajib diisi','error'); return; }
if (!gv('fp-tgl')) { App.toast('Tanggal lahir wajib diisi','error'); return; }
const body = {
nik, id_keluarga: gv('fp-kk'),
nama_lengkap: gv('fp-nama'), jenis_kelamin: gv('fp-jkel'),
tanggal_lahir: gv('fp-tgl'), tempat_lahir: gv('fp-tempat'),
agama: gv('fp-agama'), status_keluarga: gv('fp-status-kk'),
status_perkawinan: gv('fp-kawin'), status_hidup: gv('fp-hidup'),
pekerjaan: gv('fp-pekerjaan'), penghasilan: +gv('fp-penghasilan')||0,
status_ekonomi: gv('fp-ekonomi'), pendidikan_terakhir: gv('fp-pendidikan'),
status_pendidikan: gv('fp-stat-pend'), kondisi_kesehatan: gv('fp-kesehatan'),
keterangan_kesehatan: gv('fp-ket-sehat'),
};
try {
if (editNIK) { await Api.put(`/penduduk/${editNIK}`, body); App.toast('Data diperbarui β
','success'); }
else { await Api.post('/penduduk', body); App.toast('Penduduk ditambahkan β
','success'); }
App.closeModal('modal-penduduk');
await load();
App.updateHeaderStats();
} catch(e) { App.toast(e.message,'error'); }
}
async function hapus(nik) {
if (!confirm(`Hapus data penduduk NIK ${nik}?\nTindakan ini tidak dapat dibatalkan.`)) return;
try {
await Api.delete(`/penduduk/${nik}`);
App.toast('Data dihapus','success');
load(); App.updateHeaderStats();
} catch(e) { App.toast(e.message,'error'); }
}
async function showDetail(nik) {
ge('dp-title').textContent = 'Memuatβ¦';
ge('detail-panel').classList.add('open');
let p;
try { p = await Api.get(`/penduduk/${nik}`); }
catch { p = all.find(x => x.nik === nik); }
if (!p) { App.toast('Gagal memuat detail','error'); return; }
ge('dp-title').textContent = p.nama_lengkap;
const histori = p.histori_bantuan || [];
ge('dp-body').innerHTML = `
Identitas
${field('NIK', `
${p.nik}`)}
${field('Jenis Kelamin', p.jenis_kelamin === 'L' ? 'Laki-laki' : 'Perempuan')}
${field('Umur', `${p.umur||'?'} tahun`)}
${field('Tempat Lahir', p.tempat_lahir||'β')}
${field('Agama', p.agama||'β')}
${field('Status KK', cap(p.status_keluarga))}
${field('Perkawinan', cap(p.status_perkawinan))}
Sosial Ekonomi
${field('Pekerjaan', p.pekerjaan||'β')}
${field('Penghasilan', rp(p.penghasilan))}
${field('Status Ekonomi', bdg(p.status_ekonomi,''))}
${field('Pendidikan', p.pendidikan_terakhir?.replace('_','/')||'β')}
${field('Kesehatan', bdg(p.kondisi_kesehatan,''))}
Lokasi
${field('Kelurahan', p.kelurahan||'β')}
${field('Kecamatan', p.kecamatan||'β')}
${field('Alamat', p.alamat||'β')}
${field('Rumah Ibadah', p.nama_ri||'β')}
Riwayat Bantuan (${histori.length}x)
${histori.length ? histori.map(h=>`
${h.nama_bantuan}${h.tanggal?.substring(0,10)}
${h.nama_ri||''} Β· ${h.jumlah} ${h.satuan||''}
`).join('') : '
Belum pernah menerima bantuan
'}
${App.canEdit() ? `
` : ''}
`;
}
function field(lbl, val) {
return `${lbl}${val}
`;
}
function closeDetail() { ge('detail-panel').classList.remove('open'); }
return { load, search, applyFilter, showForm, hitungUmur, save, hapus, showDetail, closeDetail };
})();