Files
UasSIGWebgis/warga/index.php
T
2026-06-09 18:34:28 +07:00

293 lines
12 KiB
PHP

<?php
session_start();
require_once '../api/db.php';
$username = $_SESSION['username'] ?? 'Warga';
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Portal Warga - WebGIS Poverty Mapping</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"/>
<link rel="stylesheet" href="style.css"/>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<style>
.header-warga {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10px);
padding: 10px 25px;
border-radius: 30px;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
display: flex;
align-items: center;
gap: 15px;
font-family: 'Inter', sans-serif;
border: 1px solid rgba(0,0,0,0.05);
}
.header-warga h3 { margin: 0; color: #1e293b; font-size: 1.2rem; }
.header-warga span { font-size: 0.85rem; color: #64748b; }
.btn-lapor-darurat {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
background: linear-gradient(135deg, #ef4444, #dc2626);
color: white;
border: none;
padding: 15px 30px;
border-radius: 30px;
font-size: 1.1rem;
font-weight: bold;
cursor: pointer;
box-shadow: 0 10px 25px rgba(239, 68, 68, 0.4);
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 10px;
animation: pulse 2s infinite;
}
.btn-lapor-darurat:hover {
transform: translateX(-50%) scale(1.05);
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7); }
70% { box-shadow: 0 0 0 15px rgba(239, 68, 68, 0); }
100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
}
.lapor-modal {
display: none;
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.5);
backdrop-filter: blur(5px);
z-index: 2000;
justify-content: center;
align-items: center;
}
.lapor-modal.active { display: flex; }
.lapor-content {
background: white;
padding: 30px;
border-radius: 20px;
width: 90%;
max-width: 400px;
box-shadow: 0 20px 40px rgba(0,0,0,0.2);
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from { transform: translateY(50px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.lapor-content input, .lapor-content textarea {
width: 100%;
padding: 12px;
margin-bottom: 15px;
border: 1px solid #cbd5e1;
border-radius: 10px;
box-sizing: border-box;
font-family: inherit;
}
.lapor-content textarea { resize: vertical; min-height: 100px; }
</style>
</head>
<body>
<div class="header-warga">
<i class="fas fa-map-marked-alt" style="color:#3b82f6; font-size: 1.5rem;"></i>
<div style="flex: 1;">
<h3>Portal Warga GIS</h3>
<span>Informasi Fasilitas & Pelaporan Darurat</span>
</div>
<div style="display: flex; gap: 8px;">
<a href="../portal/index.php" title="Kembali ke Portal Utama" style="color: #fff; background: rgba(59, 130, 246, 0.8); padding: 8px 12px; border-radius: 8px; text-decoration: none; font-size: 0.9rem; transition: 0.3s;" onmouseover="this.style.background='rgba(37, 99, 235, 1)'" onmouseout="this.style.background='rgba(59, 130, 246, 0.8)'">
<i class="fas fa-home"></i> Kembali ke Dashboard
</a>
</div>
</div>
<div id="map" style="height: 100vh; width: 100vw; position: absolute; top: 0; left: 0; z-index: 1;"></div>
<button class="btn-lapor-darurat" onclick="bukaLapor()">
<i class="fas fa-exclamation-triangle"></i> LAPOR DARURAT SEKARANG
</button>
<div class="lapor-modal" id="modalLapor">
<div class="lapor-content">
<h3 style="margin-top:0; color:#ef4444;"><i class="fas fa-bullhorn"></i> Form Lapor Darurat</h3>
<p style="font-size:0.85rem; color:#64748b; margin-bottom: 20px;">Pastikan lokasi Anda sudah sesuai di peta sebelum mengirim laporan ini.</p>
<input type="text" id="w_nama" value="<?php echo htmlspecialchars($username); ?>" readonly style="background:#f1f5f9; cursor:not-allowed;">
<textarea id="w_laporan" placeholder="Jelaskan situasi darurat (Misal: Jalan amblas, butuh ambulans)..." required></textarea>
<div style="display: flex; gap: 10px;">
<button onclick="tutupLapor()" style="flex:1; padding:12px; border:none; border-radius:10px; background:#e2e8f0; color:#475569; font-weight:bold; cursor:pointer;">Batal</button>
<button onclick="kirimLaporan()" style="flex:1; padding:12px; border:none; border-radius:10px; background:#ef4444; color:white; font-weight:bold; cursor:pointer;">Kirim Laporan</button>
</div>
</div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
var map = L.map('map', { zoomControl: false }).setView([-0.0263, 109.3425], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
L.control.zoom({ position: 'bottomright' }).addTo(map);
var layerMasjid = L.layerGroup().addTo(map);
var layerPelaporan = L.layerGroup().addTo(map);
var layerSpbu24 = L.layerGroup().addTo(map);
var layerSpbuNon24 = L.layerGroup().addTo(map);
var overlays = {
"🕌 Tempat Ibadah/Bantuan": layerMasjid,
"🚨 Titik Laporan": layerPelaporan,
"⛽ SPBU 24 Jam": layerSpbu24,
"⛽ SPBU Terbatas": layerSpbuNon24
};
L.control.layers(null, overlays, { collapsed: true, position: 'topright' }).addTo(map);
// Titik lokasi warga untuk lapor
var userMarker = null;
var userLat = -0.0263;
var userLng = 109.3425;
// Dapatkan lokasi pengguna otomatis
map.locate({setView: true, maxZoom: 15});
map.on('locationfound', function(e) {
userLat = e.latlng.lat;
userLng = e.latlng.lng;
if(userMarker) map.removeLayer(userMarker);
userMarker = L.marker(e.latlng, {draggable: true}).addTo(map)
.bindPopup("Geser pin ini ke lokasi persis kejadian!").openPopup();
userMarker.on('dragend', function(ev) {
var pos = ev.target.getLatLng();
userLat = pos.lat;
userLng = pos.lng;
});
});
// Jika map diklik, pindahkan marker
map.on('click', function(e) {
userLat = e.latlng.lat;
userLng = e.latlng.lng;
if(!userMarker) {
userMarker = L.marker(e.latlng, {draggable: true}).addTo(map)
.bindPopup("Lokasi laporan").openPopup();
userMarker.on('dragend', function(ev) {
var pos = ev.target.getLatLng();
userLat = pos.lat;
userLng = pos.lng;
});
} else {
userMarker.setLatLng(e.latlng);
}
});
function loadData() {
fetch('../api/api.php?data=all')
.then(r => r.json())
.then(data => {
renderMap(data);
});
}
function renderMap(data) {
layerMasjid.clearLayers();
layerPelaporan.clearLayers();
layerSpbu24.clearLayers();
layerSpbuNon24.clearLayers();
data.masjid.forEach(m => {
var popup = `<b>${m.jenis || 'Tempat Ibadah'}</b><br>${m.nama}<br><small>${m.alamat}</small>`;
var faClass = 'fa-mosque';
if(m.jenis === 'Gereja') faClass = 'fa-church';
else if(m.jenis === 'Vihara') faClass = 'fa-vihara';
else if(m.jenis === 'Pura') faClass = 'fa-torii-gate';
var mIcon = L.divIcon({
html: `<div style="width:30px; height:30px; background:#2563eb; border-radius:50% 50% 50% 0; transform:rotate(-45deg); display:flex; align-items:center; justify-content:center; border:2px solid white; box-shadow: 2px 2px 5px rgba(0,0,0,0.5);"><i class="fas ${faClass}" style="transform:rotate(45deg); color:white; font-size:12px;"></i></div>`,
className: '', iconSize: [30, 30], iconAnchor: [15, 30]
});
L.marker([m.latitude, m.longitude], { icon: mIcon }).addTo(layerMasjid).bindPopup(popup);
});
data.pelaporan.forEach(p => {
var popup = `<b>🚨 ${p.nama_pelapor} melapor:</b><br>${p.isi_laporan}<br><small><i class="far fa-clock"></i> ${p.waktu}</small>`;
var pIcon = L.divIcon({
html: `<div style="width:28px; height:28px; background:#f97316; border-radius:50% 50% 50% 0; transform:rotate(-45deg); display:flex; align-items:center; justify-content:center; border:2px solid white;"><i class="fas fa-exclamation" style="transform:rotate(45deg); color:white; font-size:12px; font-weight:bold;"></i></div>`,
className: '', iconSize: [28, 28], iconAnchor: [14, 28]
});
L.marker([p.latitude, p.longitude], { icon: pIcon }).addTo(layerPelaporan).bindPopup(popup);
});
data.spbu.forEach(s => {
var is24 = s.kategori === '24jam';
var iconUrl = is24 ? 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png' : 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png';
var targetLayer = is24 ? layerSpbu24 : layerSpbuNon24;
var popup = `<b>⛽ ${s.nama}</b><br>Kategori: ${s.kategori === '24jam' ? 'Buka 24 Jam' : 'Tidak 24 Jam'}`;
L.marker([s.latitude, s.longitude], { icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }) }).addTo(targetLayer).bindPopup(popup);
});
}
function bukaLapor() {
document.getElementById('modalLapor').classList.add('active');
if(!userMarker) {
Swal.fire('Perhatian', 'Pastikan Anda telah mengizinkan akses lokasi atau mengklik titik di peta untuk menentukan lokasi laporan.', 'info');
}
}
function tutupLapor() {
document.getElementById('modalLapor').classList.remove('active');
}
function kirimLaporan() {
var nama = document.getElementById('w_nama').value;
var laporan = document.getElementById('w_laporan').value;
if(!laporan) {
Swal.fire('Oops!', 'Mohon isi penjelasan daruratnya!', 'warning');
return;
}
var fd = new FormData();
fd.append('action', 'simpan_pelaporan');
fd.append('lat', userLat);
fd.append('lng', userLng);
fd.append('nama', nama || 'Anonim');
fd.append('laporan', laporan);
Swal.fire({ title: 'Mengirim...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
fetch('../api/api.php', { method: 'POST', body: fd })
.then(res => res.json())
.then((res) => {
if (res.status === 'error') {
Swal.fire('Gagal!', res.message, 'error');
} else {
tutupLapor();
document.getElementById('w_laporan').value = '';
Swal.fire({icon: 'success', title: 'Terkirim', text: 'Laporan darurat berhasil dikirim! Petugas akan segera memproses.', timer: 3000, showConfirmButton: false});
loadData(); // Refresh map
}
})
.catch(err => {
Swal.fire('Error', 'Terjadi kesalahan jaringan.', 'error');
});
}
loadData();
setInterval(loadData, 15000); // Poll every 15s to see other reports
</script>
</body>
</html>