191 lines
12 KiB
PHP
191 lines
12 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../config/db.php';
|
|
require_once __DIR__ . '/../config/auth_check.php';
|
|
requireAnyRole(['enumerator']);
|
|
$user = currentUser();
|
|
$wilayah = $user['wilayah_tugas'] ?: 'Belum ditentukan';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Input Data Warga — Enumerator</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
|
|
<style>
|
|
*{margin:0;padding:0;box-sizing:border-box;font-family:'Inter',sans-serif;}
|
|
body{background:#F3F4F6;color:#111827;padding-bottom:90px;}
|
|
.topbar{position:sticky;top:0;z-index:500;background:linear-gradient(135deg,#2563EB,#1D4ED8);color:#fff;padding:14px 16px;display:flex;align-items:center;gap:12px;box-shadow:0 2px 8px rgba(0,0,0,.15);}
|
|
.topbar a{color:#fff;text-decoration:none;font-size:1.2rem;}
|
|
.topbar h1{font-size:1rem;font-weight:700;}
|
|
.topbar .sub{font-size:0.72rem;opacity:.9;}
|
|
.container{max-width:560px;margin:0 auto;padding:16px;}
|
|
.section{background:#fff;border:1px solid #E5E7EB;border-radius:14px;padding:16px;margin-bottom:14px;}
|
|
.section h3{font-size:0.85rem;color:#2563EB;margin-bottom:12px;text-transform:uppercase;letter-spacing:.5px;}
|
|
label{display:block;font-size:0.8rem;font-weight:600;margin-bottom:5px;color:#374151;}
|
|
input,select{width:100%;padding:12px;border:1px solid #D1D5DB;border-radius:10px;font-size:0.95rem;margin-bottom:12px;outline:none;}
|
|
input:focus,select:focus{border-color:#2563EB;}
|
|
.row2{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
|
|
.gps-btn{width:100%;background:#059669;color:#fff;border:none;padding:14px;border-radius:10px;font-size:0.95rem;font-weight:600;cursor:pointer;margin-bottom:10px;display:flex;align-items:center;justify-content:center;gap:8px;}
|
|
#map{height:240px;border-radius:10px;border:1px solid #E5E7EB;margin-bottom:10px;}
|
|
.coord{font-size:0.78rem;color:#6B7280;text-align:center;margin-bottom:8px;}
|
|
.photo-prev{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;}
|
|
.photo-prev img{width:72px;height:72px;object-fit:cover;border-radius:8px;border:1px solid #E5E7EB;}
|
|
.savebar{position:fixed;bottom:0;left:0;right:0;background:#fff;border-top:1px solid #E5E7EB;padding:12px 16px;display:flex;gap:10px;max-width:560px;margin:0 auto;}
|
|
.btn-save{flex:1;background:#2563EB;color:#fff;border:none;padding:14px;border-radius:10px;font-size:1rem;font-weight:700;cursor:pointer;}
|
|
.btn-save:disabled{opacity:.6;}
|
|
.toast{position:fixed;top:70px;left:50%;transform:translateX(-50%);background:#111827;color:#fff;padding:12px 20px;border-radius:10px;font-size:0.88rem;z-index:1000;opacity:0;transition:.3s;}
|
|
.toast.show{opacity:1;}
|
|
.toast.err{background:#DC2626;}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="topbar">
|
|
<a href="<?= app_url('enumerator/index.php') ?>"><i class="fas fa-arrow-left"></i></a>
|
|
<div><h1>Input Data Warga</h1><div class="sub">Wilayah: <?= htmlspecialchars($wilayah) ?></div></div>
|
|
</div>
|
|
|
|
<div class="container">
|
|
<div class="section">
|
|
<h3>📍 Lokasi (Geotagging)</h3>
|
|
<button type="button" class="gps-btn" onclick="getGPS()"><i class="fas fa-location-crosshairs"></i> <span id="gpsLabel">Gunakan GPS Otomatis</span></button>
|
|
<div id="map"></div>
|
|
<div class="coord" id="coordHint">Gunakan GPS, <b>ketuk peta</b>, <b>geser pin</b>, atau ketik koordinat manual di bawah.</div>
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px;">
|
|
<div><label>Latitude</label><input id="inLat" type="number" step="any" inputmode="decimal" placeholder="-0.0500" onchange="applyManual()"></div>
|
|
<div><label>Longitude</label><input id="inLng" type="number" step="any" inputmode="decimal" placeholder="109.3450" onchange="applyManual()"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>👤 Identitas</h3>
|
|
<label>Nama Kepala Keluarga *</label><input id="nama" placeholder="Nama lengkap KK">
|
|
<label>NIK KK</label><input id="nik" maxlength="16" inputmode="numeric" placeholder="16 digit">
|
|
<label>Alamat</label><input id="alamat" placeholder="Alamat tempat tinggal">
|
|
<div class="row2"><div><label>RT</label><input id="rt"></div><div><label>RW</label><input id="rw"></div></div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>👨👩👧 Demografi & Ekonomi</h3>
|
|
<div class="row2">
|
|
<div><label>Jumlah Jiwa</label><input id="jiwa" type="number" inputmode="numeric"></div>
|
|
<div><label>Tanggungan</label><input id="tanggungan" type="number" inputmode="numeric"></div>
|
|
</div>
|
|
<label>Pekerjaan KK</label><input id="pekerjaan" placeholder="mis. Buruh harian">
|
|
<label>Penghasilan / bulan (Rp)</label><input id="penghasilan" type="number" inputmode="numeric">
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>🏠 Kondisi Rumah</h3>
|
|
<label>Sumber Air</label>
|
|
<select id="air"><option value="">-</option><option>SUMUR_BOR</option><option>PDAM</option><option>SUNGAI</option><option>HUJAN</option><option>TIDAK_ADA</option></select>
|
|
<label>Listrik</label>
|
|
<select id="listrik"><option value="">-</option><option>PLN</option><option>NON_PLN</option><option>TIDAK_ADA</option></select>
|
|
<label>Material Dinding</label>
|
|
<select id="dinding"><option value="">-</option><option>PERMANEN</option><option>SEMI_PERMANEN</option><option>TIDAK_PERMANEN</option></select>
|
|
<label>Status Kepemilikan</label>
|
|
<select id="kepemilikan"><option value="">-</option><option>MILIK</option><option>SEWA</option><option>NUMPANG</option><option>LAINNYA</option></select>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>📷 Foto Kondisi Rumah</h3>
|
|
<input type="file" id="foto" accept="image/*" capture="environment" multiple>
|
|
<div class="photo-prev" id="photoPrev"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="savebar">
|
|
<button class="btn-save" id="btnSave" onclick="simpan()"><i class="fas fa-save"></i> Simpan Data</button>
|
|
</div>
|
|
|
|
<div class="toast" id="toast"></div>
|
|
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
<script>
|
|
const APP_BASE = '<?= app_url() ?>';
|
|
let map, marker, lat=null, lng=null;
|
|
|
|
function initMap(){
|
|
map = L.map('map').setView([-0.0500,109.3450],13);
|
|
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png',{subdomains:'abcd',maxZoom:19}).addTo(map);
|
|
map.on('click',e=>setPoint(e.latlng.lat,e.latlng.lng,false));
|
|
}
|
|
function ensureMarker(la,ln){
|
|
if(!marker){
|
|
marker=L.marker([la,ln],{draggable:true}).addTo(map);
|
|
marker.on('dragend',ev=>{const p=ev.target.getLatLng();lat=p.lat;lng=p.lng;syncInputs();});
|
|
} else { marker.setLatLng([la,ln]); }
|
|
}
|
|
function setPoint(la,ln,zoom){
|
|
lat=la; lng=ln;
|
|
ensureMarker(la,ln);
|
|
if(zoom!==false) map.setView([la,ln],16);
|
|
syncInputs();
|
|
}
|
|
function syncInputs(){
|
|
document.getElementById('inLat').value = lat.toFixed(6);
|
|
document.getElementById('inLng').value = lng.toFixed(6);
|
|
document.getElementById('coordHint').innerHTML = `📌 Titik terpasang: ${lat.toFixed(6)}, ${lng.toFixed(6)} — geser pin / ketik untuk koreksi.`;
|
|
}
|
|
function applyManual(){
|
|
const la=parseFloat(document.getElementById('inLat').value), ln=parseFloat(document.getElementById('inLng').value);
|
|
if(isNaN(la)||isNaN(ln)){ showToast('Koordinat tidak valid','err'); return; }
|
|
setPoint(la,ln);
|
|
}
|
|
function getGPS(){
|
|
const lbl=document.getElementById('gpsLabel');
|
|
if(!navigator.geolocation){ toast('GPS tidak didukung perangkat','err'); return; }
|
|
lbl.textContent='Mencari lokasi...';
|
|
navigator.geolocation.getCurrentPosition(
|
|
pos=>{ setPoint(pos.coords.latitude,pos.coords.longitude); lbl.textContent='GPS Terdeteksi ✓'; toast('Lokasi GPS terisi'); },
|
|
err=>{ lbl.textContent='Gunakan GPS Otomatis'; toast('Gagal ambil GPS: '+err.message+'. Ketuk peta manual.','err'); },
|
|
{ enableHighAccuracy:true, timeout:10000 }
|
|
);
|
|
}
|
|
// preview foto
|
|
document.getElementById('foto').addEventListener('change',function(){
|
|
const p=document.getElementById('photoPrev'); p.innerHTML='';
|
|
[...this.files].slice(0,5).forEach(f=>{ const img=document.createElement('img'); img.src=URL.createObjectURL(f); p.appendChild(img); });
|
|
});
|
|
function toast(msg,type){ const t=document.getElementById('toast'); t.textContent=msg; t.className='toast show'+(type==='err'?' err':''); setTimeout(()=>t.className='toast',3000); }
|
|
|
|
async function simpan(){
|
|
const nama=document.getElementById('nama').value.trim();
|
|
if(!nama) return toast('Nama KK wajib diisi','err');
|
|
if(lat===null||lng===null) return toast('Tentukan lokasi (GPS / ketuk peta)','err');
|
|
const btn=document.getElementById('btnSave'); btn.disabled=true; btn.innerHTML='Menyimpan...';
|
|
const body={
|
|
nama_kk:nama, nik_kk:document.getElementById('nik').value.trim(),
|
|
alamat:document.getElementById('alamat').value.trim(),
|
|
rt:document.getElementById('rt').value.trim(), rw:document.getElementById('rw').value.trim(),
|
|
jumlah_jiwa:document.getElementById('jiwa').value||null,
|
|
jumlah_tanggungan:parseInt(document.getElementById('tanggungan').value)||0,
|
|
pekerjaan_kk:document.getElementById('pekerjaan').value.trim(),
|
|
penghasilan:parseFloat(document.getElementById('penghasilan').value)||0,
|
|
sumber_air:document.getElementById('air').value, status_listrik:document.getElementById('listrik').value,
|
|
material_dinding:document.getElementById('dinding').value, status_kepemilikan:document.getElementById('kepemilikan').value,
|
|
geometry:{type:'Point',coordinates:[lng,lat]}
|
|
};
|
|
try{
|
|
const res=await fetch(APP_BASE+'/api/warga_miskin.php',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});
|
|
const d=await res.json();
|
|
if(d.status!=='success'){ toast(d.message||'Gagal','err'); btn.disabled=false; btn.innerHTML='<i class="fas fa-save"></i> Simpan Data'; return; }
|
|
const wid=d.data.id;
|
|
const files=document.getElementById('foto').files;
|
|
if(files.length){
|
|
const fd=new FormData(); fd.append('warga_id',wid);
|
|
for(const f of files) fd.append('foto[]',f);
|
|
btn.innerHTML='Mengunggah foto...';
|
|
await fetch(APP_BASE+'/api/foto.php',{method:'POST',body:fd});
|
|
}
|
|
toast('Data tersimpan ✓');
|
|
setTimeout(()=>{ window.location.href=APP_BASE+'/enumerator/index.php'; },1200);
|
|
}catch(e){ toast('Error: '+e.message,'err'); btn.disabled=false; btn.innerHTML='<i class="fas fa-save"></i> Simpan Data'; }
|
|
}
|
|
initMap();
|
|
</script>
|
|
</body>
|
|
</html>
|