Files
WEBGISPOVERTYMAP/sig-bansos/ORANG BERKEBUTUHAN.html
T

274 lines
15 KiB
HTML

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SIG Bansos - Orang Berkebutuhan</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', sans-serif; background: #f0f2f5; }
#map { height: 70vh; width: 100%; border-radius: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
.sidebar { background: white; border-radius: 10px; padding: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); height: 70vh; overflow-y: auto; }
.form-group { margin-bottom: 12px; }
.form-group label { font-weight: 600; margin-bottom: 3px; display: block; color: #495057; font-size: 13px; }
.form-group input, .form-group select, .form-group textarea { width: 100%; padding: 8px 10px; border: 1px solid #ced4da; border-radius: 6px; font-size: 13px; }
.btn { padding: 8px 16px; font-size: 13px; border-radius: 6px; margin-right: 5px; }
.data-list { max-height: 300px; overflow-y: auto; margin-top: 15px; }
.data-item { background: #f8f9fa; padding: 10px; margin-bottom: 8px; border-radius: 8px; cursor: pointer; border-left: 4px solid #17a2b8; }
.data-item:hover { background: #e9ecef; }
.data-item strong { display: block; color: #17a2b8; font-size: 14px; }
.data-item small { color: #6c757d; font-size: 11px; display: block; }
.draw-controls { margin-top: 10px; padding: 10px; background: white; border-radius: 8px; }
.draw-status { background: #d1ecf1; padding: 10px; border-radius: 6px; margin-top: 10px; font-size: 13px; border-left: 4px solid #17a2b8; display: none; }
.toast-notification { position: fixed; top: 20px; right: 20px; z-index: 10000; min-width: 280px; }
.leaflet-popup-content-wrapper { border-radius: 12px; padding: 0; overflow: hidden; }
.leaflet-popup-content { margin: 0 !important; width: 260px; }
.popup-header { padding: 10px; color: white; font-weight: 600; font-size: 14px; }
.popup-body { padding: 10px 12px; font-size: 12px; }
.popup-row { display: flex; justify-content: space-between; margin-bottom: 3px; }
.popup-label { color: #888; }
.popup-value { font-weight: 500; }
.popup-footer { display: flex; border-top: 1px solid #eee; }
.popup-btn { flex: 1; padding: 8px; border: none; font-size: 11px; cursor: pointer; }
.popup-btn-edit { background: #fff3cd; color: #856404; }
.popup-btn-delete { background: #f8d7da; color: #842029; }
.search-box { margin-bottom: 10px; }
</style>
</head>
<body>
<script>
const user = JSON.parse(sessionStorage.getItem('user'));
if (!user || user.role !== 'admin') {
window.location.href = '/login.html';
}
</script>
<div class="container-fluid p-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h4><i class="fas fa-map-marked-alt"></i> SIG Bansos - Orang Berkebutuhan</h4>
<button class="btn btn-danger btn-sm" onclick="logout()"><i class="fas fa-sign-out-alt"></i> Logout</button>
</div>
<div class="row">
<div class="col-md-8">
<div id="map"></div>
<div class="draw-controls">
<button class="btn btn-info btn-sm" onclick="startDrawing()"><i class="fas fa-user-plus"></i> Tambah Orang</button>
<button class="btn btn-secondary btn-sm" onclick="cancelDrawing()"><i class="fas fa-times"></i> Batal</button>
</div>
<div id="drawStatus" class="draw-status"></div>
</div>
<div class="col-md-4">
<div class="sidebar">
<h5><i class="fas fa-user"></i> Form Orang Berkebutuhan</h5>
<form id="orangForm">
<input type="hidden" id="orangId">
<div class="form-group"><label>Nama Lengkap</label><input type="text" id="namaOrang" class="form-control" placeholder="Nama" required></div>
<div class="form-group"><label>Alamat</label><input type="text" id="alamatOrang" class="form-control" placeholder="Alamat"></div>
<div class="form-group"><label>Jenis Kebutuhan</label><select id="jenisKebutuhan" class="form-control"><option value="">-- Pilih --</option><option value="sembako">🍚 Sembako</option><option value="kesehatan">💊 Kesehatan</option><option value="pendidikan">📚 Pendidikan</option><option value="sandang">👕 Sandang</option><option value="uang">💰 Uang Tunai</option><option value="lainnya">📋 Lainnya</option></select></div>
<div class="form-group"><label>No HP</label><input type="text" id="noHpOrang" class="form-control" placeholder="No HP"></div>
<div class="form-group"><label>Koordinat</label><input type="text" id="koordinatOrang" class="form-control" readonly placeholder="Klik pada peta"></div>
<div class="form-group"><label>Keterangan</label><textarea id="keteranganOrang" class="form-control" rows="2" placeholder="Keterangan tambahan..."></textarea></div>
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Simpan</button>
<button type="button" class="btn btn-danger" onclick="resetForm()"><i class="fas fa-times"></i> Batal</button>
</form>
<hr>
<h6>Daftar Orang Berkebutuhan</h6>
<div class="search-box"><input type="text" id="searchOrang" class="form-control form-control-sm" placeholder="Cari nama..."></div>
<div id="orangList" class="data-list"></div>
</div>
</div>
</div>
</div>
<div class="toast-notification" id="toastNotification"></div>
<script>
function logout() {
sessionStorage.removeItem('user');
window.location.href = '/login.html';
}
const API_URL = '/sig-jalan/api_orang.php';
var map = L.map('map').setView([-0.026330, 109.342519], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(map);
let orangData = [];
let layersOrang = {};
let drawingMode = false;
let currentMarker = null;
let pendingCoord = null;
function showMsg(msg, type='success') {
const bg = type==='success'?'bg-success':'bg-danger';
const icon = type==='success'?'fa-check-circle':'fa-exclamation-circle';
const el = document.getElementById('toastNotification');
el.innerHTML = `<div class="alert ${bg} text-white alert-dismissible fade show mb-0"><i class="fas ${icon}"></i> ${msg}<button class="btn-close" data-bs-dismiss="alert"></button></div>`;
setTimeout(()=>el.innerHTML='',3000);
}
async function apiCall(url, method='GET', data=null) {
const opt = { method };
if(data && (method==='POST'||method==='PUT')) {
opt.headers = {'Content-Type':'application/json'};
opt.body = JSON.stringify(data);
}
const res = await fetch(url, opt);
return await res.json();
}
async function loadData() {
const result = await apiCall(API_URL+'?action=getAll');
if(result && result.success) { orangData = result.data; renderMarkers(); }
}
function renderMarkers() {
Object.values(layersOrang).forEach(l => map.removeLayer(l));
layersOrang = {};
orangData.forEach(o => {
const color = o.jenis_kebutuhan ? '#28a745' : '#dc3545';
const icon = L.divIcon({
html: `<i class="fas fa-user" style="font-size:28px;color:${color}"></i>`,
className: 'custom-marker', iconSize: [28,28], iconAnchor: [14,28], popupAnchor: [0,-28]
});
const marker = L.marker([parseFloat(o.latitude), parseFloat(o.longitude)], {icon}).addTo(map);
marker.bindPopup(`
<div>
<div class="popup-header" style="background:${color}"><i class="fas fa-user"></i> ${o.nama}</div>
<div class="popup-body">
<div class="popup-row"><span class="popup-label">Alamat</span><span class="popup-value">${o.alamat||'-'}</span></div>
<div class="popup-row"><span class="popup-label">Kebutuhan</span><span class="popup-value">${o.jenis_kebutuhan||'-'}</span></div>
<div class="popup-row"><span class="popup-label">Keterangan</span><span class="popup-value">${o.keterangan||'-'}</span></div>
</div>
<div class="popup-footer">
<button class="popup-btn popup-btn-edit" onclick="editData(${o.id})"><i class="fas fa-edit"></i></button>
<button class="popup-btn popup-btn-delete" onclick="deleteData(${o.id})"><i class="fas fa-trash"></i></button>
</div>
</div>
`);
layersOrang[o.id] = marker;
});
displayList();
}
function displayList(data=null) {
const list = data || orangData;
document.getElementById('orangList').innerHTML = list.length ? list.map(o => `
<div class="data-item" onclick="zoomTo(${o.id})">
<strong><i class="fas fa-user"></i> ${o.nama}</strong>
<small>${o.jenis_kebutuhan||'Belum diisi'} | ${o.alamat||'-'}</small>
</div>
`).join('') : '<p class="text-muted text-center">Tidak ada data</p>';
}
function startDrawing() {
drawingMode = true;
document.getElementById('drawStatus').style.display = 'block';
document.getElementById('drawStatus').innerHTML = '<i class="fas fa-info-circle"></i> Klik pada peta untuk menentukan lokasi';
map.on('click', onMapClick);
}
function onMapClick(e) {
if(!drawingMode) return;
if(currentMarker) map.removeLayer(currentMarker);
const lat = e.latlng.lat;
const lng = e.latlng.lng;
currentMarker = L.marker([lat,lng], {
icon: L.divIcon({html:'<i class="fas fa-user" style="font-size:28px;color:#dc3545"></i>',className:'custom-marker',iconSize:[28,28],iconAnchor:[14,28]}),
draggable: true
}).addTo(map);
pendingCoord = {lat, lng};
document.getElementById('koordinatOrang').value = lat.toFixed(6)+', '+lng.toFixed(6);
currentMarker.on('dragend', function() {
const p = currentMarker.getLatLng();
pendingCoord = {lat: p.lat, lng: p.lng};
document.getElementById('koordinatOrang').value = p.lat.toFixed(6)+', '+p.lng.toFixed(6);
});
}
function cancelDrawing() {
drawingMode = false;
map.off('click', onMapClick);
document.getElementById('drawStatus').style.display = 'none';
if(currentMarker) { map.removeLayer(currentMarker); currentMarker = null; }
}
function resetForm() {
document.getElementById('orangForm').reset();
document.getElementById('orangId').value = '';
document.getElementById('koordinatOrang').value = '';
pendingCoord = null;
cancelDrawing();
}
async function saveData(data) {
const action = data.id ? 'update&id='+data.id : 'create';
const result = await apiCall(API_URL+'?action='+action, data.id?'PUT':'POST', data);
if(result && result.success) { showMsg('Data berhasil disimpan'); resetForm(); loadData(); }
else { showMsg(result?.message||'Gagal menyimpan','error'); }
}
async function editData(id) {
const o = orangData.find(d => d.id === id);
if(!o) return;
document.getElementById('orangId').value = o.id;
document.getElementById('namaOrang').value = o.nama;
document.getElementById('alamatOrang').value = o.alamat||'';
document.getElementById('jenisKebutuhan').value = o.jenis_kebutuhan||'';
document.getElementById('noHpOrang').value = o.no_hp||'';
document.getElementById('koordinatOrang').value = o.latitude+', '+o.longitude;
document.getElementById('keteranganOrang').value = o.keterangan||'';
pendingCoord = {lat: parseFloat(o.latitude), lng: parseFloat(o.longitude)};
map.setView([o.latitude, o.longitude], 17);
}
async function deleteData(id) {
if(!confirm('Hapus data ini?')) return;
const result = await apiCall(API_URL+'?action=delete&id='+id, 'DELETE');
if(result && result.success) { showMsg('Data dihapus'); loadData(); }
else { showMsg('Gagal menghapus','error'); }
}
function zoomTo(id) {
const o = orangData.find(d => d.id === id);
if(o) map.flyTo([o.latitude, o.longitude], 17);
}
document.getElementById('searchOrang').addEventListener('input', function() {
const kw = this.value.toLowerCase();
displayList(orangData.filter(o => o.nama.toLowerCase().includes(kw)));
});
document.getElementById('orangForm').addEventListener('submit', function(e) {
e.preventDefault();
if(!pendingCoord && !document.getElementById('orangId').value) {
showMsg('Klik pada peta dulu!','error'); return;
}
saveData({
id: document.getElementById('orangId').value || null,
nama: document.getElementById('namaOrang').value,
alamat: document.getElementById('alamatOrang').value,
jenis_kebutuhan: document.getElementById('jenisKebutuhan').value,
no_hp: document.getElementById('noHpOrang').value,
keterangan: document.getElementById('keteranganOrang').value,
latitude: pendingCoord?.lat,
longitude: pendingCoord?.lng
});
});
loadData();
</script>
</body>
</html>