299 lines
12 KiB
PHP
299 lines
12 KiB
PHP
<?php
|
|
session_start();
|
|
if (!isset($_SESSION['login'])) {
|
|
header("Location: ../portal/login.php");
|
|
exit;
|
|
}
|
|
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>
|
|
</a>
|
|
<a href="../portal/logout.php" title="Logout" style="color: #fff; background: rgba(239, 68, 68, 0.8); padding: 8px 12px; border-radius: 8px; text-decoration: none; font-size: 0.9rem; transition: 0.3s;" onmouseover="this.style.background='rgba(220, 38, 38, 1)'" onmouseout="this.style.background='rgba(239, 68, 68, 0.8)'">
|
|
<i class="fas fa-sign-out-alt"></i>
|
|
</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>
|