initial commit pemetaan kemiskinan
This commit is contained in:
@@ -0,0 +1,500 @@
|
||||
<?php
|
||||
session_start();
|
||||
if(!isset($_SESSION['id'])){
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
$role = $_SESSION['role'];
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>WebGIS Kemiskinan</title>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box;font-family:Segoe UI;}
|
||||
body{display:flex;height:100vh;background:#eef2f7;}
|
||||
|
||||
.sidebar{
|
||||
width:380px;background:#fff;padding:15px;
|
||||
overflow-y:auto;box-shadow:4px 0 20px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
h2{font-size:16px;color:#0f766e;margin-bottom:10px;}
|
||||
|
||||
.role-box{
|
||||
padding:10px;border-radius:10px;
|
||||
background:#ecfeff;border:1px solid #a5f3fc;
|
||||
font-size:12px;margin-bottom:10px;
|
||||
}
|
||||
|
||||
.menu{
|
||||
display:flex;
|
||||
gap:8px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.menu button{
|
||||
flex:1;
|
||||
padding:8px;
|
||||
border:none;
|
||||
border-radius:10px;
|
||||
background:linear-gradient(135deg,#0ea5e9,#10b981);
|
||||
color:white;
|
||||
font-size:12px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.menu a{
|
||||
flex:1;
|
||||
text-decoration:none;
|
||||
text-align:center;
|
||||
padding:8px;
|
||||
border-radius:10px;
|
||||
background:linear-gradient(135deg,#64748b,#334155);
|
||||
color:white;
|
||||
font-size:12px;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
.section{
|
||||
background:#f8fafc;border:1px solid #e2e8f0;
|
||||
border-radius:12px;padding:10px;margin-bottom:10px;
|
||||
}
|
||||
|
||||
label{font-size:11px;color:#334155;margin-top:6px;display:block;}
|
||||
|
||||
input,select,textarea{
|
||||
width:100%;padding:7px;margin-top:4px;
|
||||
border-radius:8px;border:1px solid #cbd5e1;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
textarea{height:60px;}
|
||||
|
||||
button.action{
|
||||
width:100%;padding:9px;margin-top:10px;
|
||||
border:none;border-radius:10px;
|
||||
background:linear-gradient(135deg,#0ea5e9,#10b981);
|
||||
color:white;font-weight:bold;font-size:12px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#map{flex:1;}
|
||||
.hidden{display:none;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<?php
|
||||
$dashboard = "index.php";
|
||||
|
||||
if(isset($_SESSION['role'])){
|
||||
if($_SESSION['role'] == "admin"){
|
||||
$dashboard = "index.php";
|
||||
} elseif($_SESSION['role'] == "pengurus"){
|
||||
$dashboard = "index.php";
|
||||
} elseif($_SESSION['role'] == "pengguna"){
|
||||
$dashboard = "index.php";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="sidebar">
|
||||
|
||||
<h2>🗺 WebGIS Kemiskinan</h2>
|
||||
|
||||
<div class="role-box">
|
||||
Role: <b><?= htmlspecialchars($role) ?></b>
|
||||
</div>
|
||||
|
||||
<div class="menu">
|
||||
<?php if($role == 'admin' || $role == 'pengurus'): ?>
|
||||
<button onclick="setMode('ibadah')">🏛 Rumah Ibadah</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($role == 'admin' || $role == 'pengguna'): ?>
|
||||
<button onclick="setMode('miskin')">👨👩👧 Keluarga</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<a href="<?= $dashboard ?>">⬅ Dashboard</a>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<label>Latitude</label>
|
||||
<input id="lat" readonly>
|
||||
<label>Longitude</label>
|
||||
<input id="lng" readonly>
|
||||
</div>
|
||||
|
||||
<div class="section hidden" id="formIbadah">
|
||||
<h3 style="font-size:13px;color:#0f766e;">Form Rumah Ibadah</h3>
|
||||
|
||||
<input type="hidden" id="ibadah_id">
|
||||
|
||||
<input id="namaI" placeholder="Nama">
|
||||
<select id="jenisI">
|
||||
<option>Masjid</option><option>Gereja</option>
|
||||
<option>Vihara</option><option>Klenteng</option><option>Pura</option>
|
||||
</select>
|
||||
|
||||
<textarea id="alamatI" placeholder="Alamat"></textarea>
|
||||
<input id="ketuaI" placeholder="Ketua">
|
||||
<input id="hpI" placeholder="No HP">
|
||||
|
||||
<select id="radiusI">
|
||||
<option value="100">100m</option>
|
||||
<option value="200">200m</option>
|
||||
<option value="300">300m</option>
|
||||
<option value="400">400m</option>
|
||||
<option value="500">500m</option>
|
||||
</select>
|
||||
|
||||
<button class="action" onclick="saveIbadah()">Simpan</button>
|
||||
</div>
|
||||
|
||||
<div class="section hidden" id="formMiskin">
|
||||
<h3 style="font-size:13px;color:#0f766e;">Form Keluarga</h3>
|
||||
|
||||
<input type="hidden" id="miskin_id">
|
||||
|
||||
<input id="nik" placeholder="NIK">
|
||||
<input id="namaKK" placeholder="Nama KK">
|
||||
<textarea id="alamatM" placeholder="Alamat"></textarea>
|
||||
|
||||
<select id="penghasilan">
|
||||
<option>100k-500k</option>
|
||||
<option>500k-1jt</option>
|
||||
<option>1jt-2jt</option>
|
||||
<option>2jt+</option>
|
||||
</select>
|
||||
|
||||
<select id="prioritas">
|
||||
<option>Tinggi</option>
|
||||
<option>Sedang</option>
|
||||
<option>Rendah</option>
|
||||
</select>
|
||||
|
||||
<button class="action" onclick="saveMiskin()">Simpan</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<script>
|
||||
// Tangkap Role dari PHP ke JS
|
||||
const userRole = "<?= $role ?>";
|
||||
|
||||
const map = L.map('map').setView([-0.02,109.34],13);
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
|
||||
|
||||
async function getAlamat(lat, lng){
|
||||
try {
|
||||
let res = await fetch(
|
||||
`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`
|
||||
);
|
||||
let data = await res.json();
|
||||
return data.display_name || "Alamat tidak ditemukan";
|
||||
} catch (e) {
|
||||
return "Alamat tidak ditemukan";
|
||||
}
|
||||
}
|
||||
|
||||
// Diperbaiki string url icon yang error pada script aslinya
|
||||
const iconIbadah = L.icon({iconUrl:'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'});
|
||||
const iconHijau = L.icon({iconUrl:'http://maps.google.com/mapfiles/ms/icons/green-dot.png'});
|
||||
const iconMerah = L.icon({iconUrl:'http://maps.google.com/mapfiles/ms/icons/red-dot.png'});
|
||||
|
||||
// 🔥 MARKER TEMPORARY
|
||||
let tempMarker = null;
|
||||
|
||||
let tempLat=null,tempLng=null;
|
||||
|
||||
// Set mode default berdasarkan role
|
||||
let mode = (userRole === "pengguna") ? "miskin" : "ibadah";
|
||||
|
||||
function setMode(m){
|
||||
mode=m;
|
||||
document.getElementById('formIbadah').classList.toggle('hidden',m!=='ibadah');
|
||||
document.getElementById('formMiskin').classList.toggle('hidden',m!=='miskin');
|
||||
clearForm();
|
||||
}
|
||||
|
||||
// Inisialisasi tampilan mode pertama kali
|
||||
setMode(mode);
|
||||
|
||||
// ================= MAP CLICK (FIXED + PREVIEW MARKER) =================
|
||||
map.on('click', async (e)=>{
|
||||
// Mencegah pengguna memasukkan titik jika mode tidak sesuai
|
||||
if(userRole === 'pengguna' && mode !== 'miskin') return;
|
||||
if(userRole === 'pengurus' && mode !== 'ibadah') return;
|
||||
|
||||
tempLat = e.latlng.lat;
|
||||
tempLng = e.latlng.lng;
|
||||
|
||||
lat.value = tempLat;
|
||||
lng.value = tempLng;
|
||||
|
||||
// 🔥 AUTO ALAMAT
|
||||
let alamatAuto = await getAlamat(tempLat, tempLng);
|
||||
|
||||
// isi ke form aktif
|
||||
if(mode === "ibadah"){
|
||||
alamatI.value = alamatAuto;
|
||||
} else {
|
||||
alamatM.value = alamatAuto;
|
||||
}
|
||||
|
||||
// 🔥 HAPUS MARKER LAMA
|
||||
if(tempMarker){
|
||||
map.removeLayer(tempMarker);
|
||||
}
|
||||
|
||||
// 🔥 TAMBAH MARKER BARU (PREVIEW)
|
||||
tempMarker = L.marker([tempLat,tempLng]).addTo(map)
|
||||
.bindPopup("📍 Lokasi dipilih").openPopup();
|
||||
});
|
||||
|
||||
function clearForm(){
|
||||
ibadah_id.value="";
|
||||
miskin_id.value="";
|
||||
namaI.value="";ketuaI.value="";hpI.value="";alamatI.value="";radiusI.value="100";
|
||||
nik.value="";namaKK.value="";alamatM.value="";
|
||||
}
|
||||
|
||||
// ================= SAVE =================
|
||||
function saveIbadah(){
|
||||
if(userRole === 'pengguna') return alert("Akses Ditolak");
|
||||
let id=ibadah_id.value;
|
||||
|
||||
fetch(id?"api/rumah_ibadah_update.php":"api/rumah_ibadah_create.php",{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/x-www-form-urlencoded"},
|
||||
body:new URLSearchParams({
|
||||
id:id,
|
||||
nama:namaI.value,
|
||||
jenis:jenisI.value,
|
||||
alamat:alamatI.value,
|
||||
ketua_pengurus:ketuaI.value,
|
||||
no_hp:hpI.value,
|
||||
radius:radiusI.value,
|
||||
lat:tempLat,
|
||||
lng:tempLng
|
||||
})
|
||||
}).then(()=>{clearForm();loadData();});
|
||||
}
|
||||
|
||||
function saveMiskin(){
|
||||
if(userRole === 'pengurus') return alert("Akses Ditolak");
|
||||
let id=miskin_id.value;
|
||||
|
||||
fetch(id?"api/keluarga_update.php":"api/keluarga_create.php",{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/x-www-form-urlencoded"},
|
||||
body:new URLSearchParams({
|
||||
id:id,
|
||||
nik:nik.value,
|
||||
nama_kepala_keluarga:namaKK.value,
|
||||
alamat:alamatM.value,
|
||||
penghasilan:penghasilan.value,
|
||||
prioritas:prioritas.value,
|
||||
lat:tempLat,
|
||||
lng:tempLng
|
||||
})
|
||||
}).then(()=>{clearForm();loadData();});
|
||||
}
|
||||
|
||||
// ================= DATA =================
|
||||
let ibadah=[],miskin=[];
|
||||
|
||||
function loadData(){
|
||||
fetch("api/rumah_ibadah_read.php").then(r=>r.json()).then(d=>ibadah=d||[]).then(render);
|
||||
fetch("api/keluarga_read.php").then(r=>r.json()).then(d=>miskin=d||[]).then(render);
|
||||
}
|
||||
|
||||
loadData();
|
||||
|
||||
// ================= EDIT =================
|
||||
function editIbadah(i){
|
||||
if(userRole === 'pengguna') return;
|
||||
setMode('ibadah');
|
||||
ibadah_id.value=i.id;
|
||||
namaI.value=i.nama;
|
||||
jenisI.value=i.jenis;
|
||||
alamatI.value=i.alamat;
|
||||
ketuaI.value=i.ketua_pengurus;
|
||||
hpI.value=i.no_hp;
|
||||
radiusI.value=i.radius;
|
||||
}
|
||||
|
||||
function editMiskin(m){
|
||||
if(userRole === 'pengurus') return;
|
||||
setMode('miskin');
|
||||
miskin_id.value=m.id;
|
||||
nik.value=m.nik;
|
||||
namaKK.value=m.nama_kepala_keluarga;
|
||||
alamatM.value=m.alamat;
|
||||
penghasilan.value=m.penghasilan;
|
||||
prioritas.value=m.prioritas;
|
||||
}
|
||||
|
||||
// ================= DELETE =================
|
||||
function hapusIbadah(id){
|
||||
if(userRole === 'pengguna') return;
|
||||
if(!confirm("Hapus data?")) return;
|
||||
|
||||
fetch("api/rumah_ibadah_delete.php",{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/x-www-form-urlencoded"},
|
||||
body:new URLSearchParams({id:id})
|
||||
}).then(()=>loadData());
|
||||
}
|
||||
|
||||
function hapusMiskin(id){
|
||||
if(userRole === 'pengurus') return;
|
||||
if(!confirm("Hapus data?")) return;
|
||||
|
||||
fetch("api/keluarga_delete.php",{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/x-www-form-urlencoded"},
|
||||
body:new URLSearchParams({id:id})
|
||||
}).then(()=>loadData());
|
||||
}
|
||||
|
||||
// ================= RENDER =================
|
||||
function render(){
|
||||
|
||||
map.eachLayer(l=>{
|
||||
if(l instanceof L.Marker || l instanceof L.Circle) map.removeLayer(l);
|
||||
});
|
||||
|
||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
|
||||
|
||||
// IBADAH
|
||||
ibadah.forEach(i=>{
|
||||
let r=Number(i.radius)||100;
|
||||
|
||||
L.circle([i.lat,i.lng],{
|
||||
radius:r,color:"#0ea5e9",fillOpacity:0.12
|
||||
}).addTo(map);
|
||||
|
||||
// Hanya tampilkan tombol jika admin atau pengurus
|
||||
let ibadahActions = "";
|
||||
if(userRole === 'admin' || userRole === 'pengurus'){
|
||||
ibadahActions = `
|
||||
<div style="display:flex;gap:6px;margin-top:10px;">
|
||||
<button onclick="editIbadah(ibadah.find(x=>x.id==${i.id}))"
|
||||
style="flex:1;padding:6px;border:none;border-radius:8px;
|
||||
background:#0ea5e9;color:white;font-size:11px;cursor:pointer;">
|
||||
✏ Edit
|
||||
</button>
|
||||
|
||||
<button onclick="hapusIbadah(${i.id})"
|
||||
style="flex:1;padding:6px;border:none;border-radius:8px;
|
||||
background:#ef4444;color:white;font-size:11px;cursor:pointer;">
|
||||
🗑 Hapus
|
||||
</button>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
L.marker([i.lat,i.lng],{icon:iconIbadah})
|
||||
.addTo(map)
|
||||
.bindPopup(`
|
||||
<div style="
|
||||
font-family:Segoe UI;
|
||||
min-width:220px;
|
||||
background:#ffffff;
|
||||
border-radius:12px;
|
||||
padding:10px;
|
||||
box-shadow:0 10px 20px rgba(0,0,0,0.15);
|
||||
">
|
||||
|
||||
<div style="font-weight:bold;font-size:14px;color:#0ea5e9;margin-bottom:6px;">
|
||||
🏛 ${i.nama}
|
||||
</div>
|
||||
|
||||
<div style="font-size:12px;line-height:1.6;color:#334155">
|
||||
<b>Jenis:</b> ${i.jenis}<br>
|
||||
<b>Alamat:</b> ${i.alamat}<br>
|
||||
<b>Ketua:</b> ${i.ketua_pengurus}<br>
|
||||
<b>No HP:</b> ${i.no_hp}<br>
|
||||
<b>Radius:</b> <span style="color:#10b981;font-weight:bold">${i.radius} m</span>
|
||||
</div>
|
||||
${ibadahActions}
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
|
||||
// MISKIN
|
||||
miskin.forEach(m=>{
|
||||
let status="LUAR",icon=iconMerah;
|
||||
|
||||
ibadah.forEach(i=>{
|
||||
if(map.distance([m.lat,m.lng],[i.lat,i.lng])<=Number(i.radius||100)){
|
||||
status="DALAM";icon=iconHijau;
|
||||
}
|
||||
});
|
||||
|
||||
// Hanya tampilkan tombol jika admin atau pengguna
|
||||
let miskinActions = "";
|
||||
if(userRole === 'admin' || userRole === 'pengguna'){
|
||||
miskinActions = `
|
||||
<div style="display:flex;gap:6px;margin-top:10px;">
|
||||
<button onclick="editMiskin(miskin.find(x=>x.id==${m.id}))"
|
||||
style="flex:1;padding:6px;border:none;border-radius:8px;
|
||||
background:#0ea5e9;color:white;font-size:11px;cursor:pointer;">
|
||||
✏ Edit
|
||||
</button>
|
||||
|
||||
<button onclick="hapusMiskin(${m.id})"
|
||||
style="flex:1;padding:6px;border:none;border-radius:8px;
|
||||
background:#ef4444;color:white;font-size:11px;cursor:pointer;">
|
||||
🗑 Hapus
|
||||
</button>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
L.marker([m.lat,m.lng],{icon})
|
||||
.addTo(map)
|
||||
.bindPopup(`
|
||||
<div style="
|
||||
font-family:Segoe UI;
|
||||
min-width:220px;
|
||||
background:#ffffff;
|
||||
border-radius:12px;
|
||||
padding:10px;
|
||||
box-shadow:0 10px 20px rgba(0,0,0,0.15);
|
||||
">
|
||||
|
||||
<div style="font-weight:bold;font-size:14px;color:#10b981;margin-bottom:6px;">
|
||||
<b>👨👩👧 ${m.nama_kepala_keluarga || m.nama}</b><br>
|
||||
</div>
|
||||
|
||||
<div style="font-size:12px;line-height:1.6;color:#334155">
|
||||
<b>NIK:</b> ${m.nik}<br>
|
||||
<b>Alamat:</b> ${m.alamat}<br>
|
||||
<b>Penghasilan:</b> ${m.penghasilan_kategori || m.penghasilan}<br>
|
||||
<b>Prioritas:</b> ${m.prioritas}<br>
|
||||
<b>Status:</b> <span style="color:${status=='DALAM'?'#10b981':'#ef4444'};font-weight:bold">
|
||||
${status}
|
||||
</span>
|
||||
</div>
|
||||
${miskinActions}
|
||||
</div>
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user