Coba Commit
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../core_config/database.php';
|
||||
require_once __DIR__ . '/../core_config/middleware_auth.php';
|
||||
requireRole('user');
|
||||
|
||||
$pdo = Database::getConnection();
|
||||
// Fetch user's own reports
|
||||
$stmt = $pdo->prepare("SELECT id, kategori, deskripsi, status, created_at FROM laporan_warga WHERE user_id = ? ORDER BY id DESC");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$rows = $stmt->fetchAll();
|
||||
|
||||
$pageTitle = 'Laporan Warga';
|
||||
$activeNav = 'laporan';
|
||||
$extraHead = '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">';
|
||||
require_once __DIR__ . '/partials/header.php';
|
||||
|
||||
function badgeStatus($status) {
|
||||
if($status === 'menunggu') return 'badge-warning';
|
||||
if($status === 'diproses') return 'badge-info';
|
||||
if($status === 'selesai') return 'badge-success';
|
||||
if($status === 'ditolak') return 'badge-danger';
|
||||
return 'badge-primary';
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="page-header">
|
||||
<div class="breadcrumb"><span>User</span><span class="sep">/</span><span>Laporan Warga</span></div>
|
||||
<h1>📢 Laporan Fasilitas & Infrastruktur</h1>
|
||||
<p>Laporkan masalah infrastruktur seperti jalan rusak, banjir, atau fasilitas umum yang terbengkalai.</p>
|
||||
</div>
|
||||
|
||||
<div class="page-toolbar">
|
||||
<div class="search-box">
|
||||
<i class="fas fa-search search-icon"></i>
|
||||
<input type="text" id="searchInput" placeholder="Cari laporan saya..." oninput="filterTable('searchInput','lapTable')">
|
||||
</div>
|
||||
<button class="btn btn-primary" onclick="openModal('modalTambah')">
|
||||
<i class="fas fa-plus"></i> Buat Laporan Baru
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="table-wrap">
|
||||
<table class="data-table" id="lapTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Kategori</th>
|
||||
<th>Deskripsi Singkat</th>
|
||||
<th>Status</th>
|
||||
<th>Tanggal</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $i => $r): ?>
|
||||
<tr>
|
||||
<td style="color:var(--text-muted)"><?= $i+1 ?></td>
|
||||
<td><strong><?= htmlspecialchars($r['kategori']) ?></strong></td>
|
||||
<td style="color:var(--text-secondary); max-width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
|
||||
<?= htmlspecialchars($r['deskripsi']) ?>
|
||||
</td>
|
||||
<td><span class="badge <?= badgeStatus($r['status']) ?>"><?= ucfirst($r['status']) ?></span></td>
|
||||
<td style="color:var(--text-muted); font-size:0.8rem;"><?= date('d M Y, H:i', strtotime($r['created_at'])) ?></td>
|
||||
<td>
|
||||
<div class="actions">
|
||||
<?php if($r['status'] === 'menunggu'): ?>
|
||||
<button class="btn btn-danger btn-sm btn-icon" onclick="hapus(<?= $r['id'] ?>)" title="Batalkan Laporan"><i class="fas fa-trash"></i></button>
|
||||
<?php else: ?>
|
||||
<span style="font-size:0.75rem; color:var(--text-muted);">Dikunci</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (!$rows): ?>
|
||||
<tr>
|
||||
<td colspan="6" style="text-align:center;padding:40px;color:var(--text-muted);">
|
||||
Anda belum pernah membuat laporan.
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Modal Tambah Laporan -->
|
||||
<div class="modal-overlay" id="modalTambah">
|
||||
<div class="modal">
|
||||
<div class="modal-header">
|
||||
<span class="modal-title">📢 Buat Laporan Baru</span>
|
||||
<button class="modal-close" onclick="closeModal('modalTambah')">×</button>
|
||||
</div>
|
||||
<form id="formTambah">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Kategori Masalah *</label>
|
||||
<select name="kategori" class="form-control" required>
|
||||
<option value="Jalan Rusak">Jalan Rusak</option>
|
||||
<option value="Banjir">Banjir</option>
|
||||
<option value="Fasilitas Terbengkalai">Fasilitas Terbengkalai</option>
|
||||
<option value="Lampu Jalan Mati">Lampu Jalan Mati</option>
|
||||
<option value="Lainnya">Lainnya</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Deskripsi Lengkap *</label>
|
||||
<textarea name="deskripsi" class="form-control" placeholder="Jelaskan detail masalahnya..." required rows="3"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Pilih Lokasi di Peta *</label>
|
||||
<div id="miniMapTambah" style="height:200px;border-radius:8px;border:1px solid #E5E7EB;margin-bottom:10px;z-index:1;"></div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
|
||||
<input type="number" name="lat" id="latTambah" class="form-control" placeholder="Latitude" step="any" required readonly style="background:#F9FAFB;">
|
||||
<input type="number" name="lng" id="lngTambah" class="form-control" placeholder="Longitude" step="any" required readonly style="background:#F9FAFB;">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-ghost" onclick="closeModal('modalTambah')">Batal</button>
|
||||
<button class="btn btn-primary" onclick="simpan()"><i class="fas fa-paper-plane"></i> Kirim Laporan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php $extraScript = <<<'JS'
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script>
|
||||
const API = APP_BASE + '/api/laporan.php';
|
||||
|
||||
let miniMap = null, miniMarker = null;
|
||||
const originalOpenModal = window.openModal;
|
||||
window.openModal = function(id) {
|
||||
originalOpenModal(id);
|
||||
if(id === 'modalTambah') {
|
||||
setTimeout(() => {
|
||||
if(!miniMap) {
|
||||
miniMap = L.map('miniMapTambah').setView([-0.0583, 109.3448], 13);
|
||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png').addTo(miniMap);
|
||||
miniMap.on('click', function(e) {
|
||||
const lat = e.latlng.lat;
|
||||
const lng = e.latlng.lng;
|
||||
if(!miniMarker) miniMarker = L.marker([lat, lng]).addTo(miniMap);
|
||||
else miniMarker.setLatLng([lat, lng]);
|
||||
document.getElementById('latTambah').value = lat.toFixed(6);
|
||||
document.getElementById('lngTambah').value = lng.toFixed(6);
|
||||
});
|
||||
} else {
|
||||
miniMap.invalidateSize();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
async function simpan() {
|
||||
const f = document.getElementById('formTambah');
|
||||
const lat = parseFloat(f.lat.value), lng = parseFloat(f.lng.value);
|
||||
if (!f.kategori.value || !f.deskripsi.value || isNaN(lat) || isNaN(lng)) {
|
||||
showToast('Lengkapi kategori, deskripsi, dan pilih lokasi!','error');
|
||||
return;
|
||||
}
|
||||
const res = await fetch(API, {
|
||||
method:'POST',
|
||||
headers:{'Content-Type':'application/json'},
|
||||
body: JSON.stringify({
|
||||
kategori: f.kategori.value,
|
||||
deskripsi: f.deskripsi.value,
|
||||
geometry: { type:'Point', coordinates:[lng, lat] }
|
||||
})
|
||||
});
|
||||
const d = await res.json();
|
||||
if(d.status === 'success') {
|
||||
showToast('Laporan berhasil dikirim!');
|
||||
setTimeout(() => location.reload(), 900);
|
||||
} else {
|
||||
showToast(d.message,'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function hapus(id) {
|
||||
if(!confirm('Apakah Anda yakin ingin membatalkan laporan ini?')) return;
|
||||
const res = await fetch(API + '?id=' + id, { method:'DELETE' });
|
||||
const d = await res.json();
|
||||
if(d.status === 'success') {
|
||||
showToast('Laporan dibatalkan!');
|
||||
setTimeout(() => location.reload(), 900);
|
||||
} else {
|
||||
showToast(d.message,'error');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
JS; ?>
|
||||
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../core_config/database.php';
|
||||
require_once __DIR__ . '/../core_config/middleware_auth.php';
|
||||
requireRole('user');
|
||||
|
||||
$pdo = Database::getConnection();
|
||||
$stats = $pdo->query("SELECT
|
||||
(SELECT COUNT(*) FROM spbu) as spbu,
|
||||
(SELECT COUNT(*) FROM jalan) as jalan,
|
||||
(SELECT COUNT(*) FROM kavling) as kavling,
|
||||
(SELECT COUNT(*) FROM rumah_ibadah) as rumah_ibadah,
|
||||
(SELECT COUNT(*) FROM warga_miskin) as warga_miskin,
|
||||
(SELECT COUNT(*) FROM kawasan_kumuh) as kawasan_kumuh,
|
||||
(SELECT COUNT(*) FROM spbu WHERE buka_24_jam=1) as spbu_24jam
|
||||
")->fetch();
|
||||
|
||||
// Hitung kawasan merah (rawan)
|
||||
$merahResult = $pdo->query("SELECT COUNT(*) as cnt FROM (
|
||||
SELECT k.id FROM kawasan_kumuh k
|
||||
LEFT JOIN warga_miskin w ON ST_Contains(k.geom, w.geom)
|
||||
GROUP BY k.id HAVING COUNT(w.id) > 3
|
||||
) sub")->fetch();
|
||||
$kawasanMerah = (int)($merahResult['cnt'] ?? 0);
|
||||
|
||||
// Hitung blank spot
|
||||
$blankCount = $pdo->query("
|
||||
SELECT COUNT(*) as cnt
|
||||
FROM warga_miskin w
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM rumah_ibadah ri
|
||||
WHERE ST_Distance_Sphere(ST_GeomFromText(ST_AsText(w.geom), 4326), ST_GeomFromText(ST_AsText(ri.geom), 4326)) <= ri.radius_bantuan_meter
|
||||
)
|
||||
")->fetch();
|
||||
$blankSpot = (int)($blankCount['cnt'] ?? 0);
|
||||
|
||||
$pageTitle = 'Beranda';
|
||||
$activeNav = 'dashboard';
|
||||
require_once __DIR__ . '/partials/header.php';
|
||||
?>
|
||||
|
||||
<div class="card" style="background: #FFFFFF; border: 1px solid #E5E7EB; border-radius: var(--radius-lg); padding: 24px; margin-bottom: 24px; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">
|
||||
<h2 style="font-size:1.4rem;font-weight:700;margin-bottom:6px;color:var(--text-primary);">👋 Selamat Datang, <?= htmlspecialchars(currentUser()['nama_lengkap'] ?: currentUser()['username']) ?>!</h2>
|
||||
<p style="color:var(--text-secondary);font-size:0.9rem;max-width:600px;">
|
||||
Anda masuk sebagai <strong>Pengguna</strong>. Anda dapat melihat seluruh data spasial, analisis, dan berpartisipasi dengan mengirim Laporan Warga atau memberikan ulasan fasilitas.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card primary">
|
||||
<div class="stat-icon"><i class="fas fa-gas-pump"></i></div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-label">Total SPBU</div>
|
||||
<div class="stat-value"><?= $stats['spbu'] ?></div>
|
||||
<div class="stat-change"><?= $stats['spbu_24jam'] ?> buka 24 jam</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card info">
|
||||
<div class="stat-icon"><i class="fas fa-road"></i></div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-label">Ruas Jalan</div>
|
||||
<div class="stat-value"><?= $stats['jalan'] ?></div>
|
||||
<div class="stat-change">Segmen terpetakan</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card success">
|
||||
<div class="stat-icon"><i class="fas fa-mosque"></i></div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-label">Rumah Ibadah</div>
|
||||
<div class="stat-value"><?= $stats['rumah_ibadah'] ?></div>
|
||||
<div class="stat-change">Lokasi tercatat</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card warning">
|
||||
<div class="stat-icon"><i class="fas fa-users"></i></div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-label">Warga Miskin</div>
|
||||
<div class="stat-value"><?= $stats['warga_miskin'] ?></div>
|
||||
<div class="stat-change"><?= $blankSpot ?> blank spot</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card danger">
|
||||
<div class="stat-icon"><i class="fas fa-exclamation-triangle"></i></div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-label">Kawasan Rawan</div>
|
||||
<div class="stat-value"><?= $kawasanMerah ?></div>
|
||||
<div class="stat-change">dari <?= $stats['kawasan_kumuh'] ?> kawasan</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card violet">
|
||||
<div class="stat-icon"><i class="fas fa-vector-square"></i></div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-label">Kavling / Parsil</div>
|
||||
<div class="stat-value"><?= $stats['kavling'] ?></div>
|
||||
<div class="stat-change">Bidang tanah</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="background: #FFFFFF; border: 1px solid #E5E7EB; border-radius: var(--radius-lg); padding: 24px; box-shadow: 0 1px 3px rgba(0,0,0,0.05);">
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:16px;">
|
||||
<div>
|
||||
<h3 style="font-size:1.1rem; font-weight:700; margin-bottom:6px;">🗺️ Buka Peta Interaktif</h3>
|
||||
<p style="color:var(--text-secondary); font-size:0.88rem; max-width:500px;">
|
||||
Lihat semua layer data spasial: SPBU, jalan, kavling, rumah ibadah, warga miskin, kawasan kumuh, dan analisis spasial.
|
||||
</p>
|
||||
</div>
|
||||
<div style="display:flex; gap:10px;">
|
||||
<a href="<?= app_url('panel_user/peta_user.php') ?>" class="btn btn-success">
|
||||
<i class="fas fa-map-marked-alt"></i> Buka Peta
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||
@@ -0,0 +1,119 @@
|
||||
</div><!-- /admin-content -->
|
||||
</main><!-- /admin-main -->
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div class="toast-container" id="toastContainer"></div>
|
||||
|
||||
<script>
|
||||
// ── Clock ──
|
||||
function updateClock() {
|
||||
const now = new Date();
|
||||
document.getElementById('clockText').textContent =
|
||||
now.toLocaleTimeString('id-ID', { hour:'2-digit', minute:'2-digit', second:'2-digit' });
|
||||
}
|
||||
updateClock();
|
||||
setInterval(updateClock, 1000);
|
||||
|
||||
// ── Toast utility ──
|
||||
window.showToast = function(msg, type = 'success') {
|
||||
const t = document.createElement('div');
|
||||
t.className = `toast ${type}`;
|
||||
const icons = { success: 'check-circle', error: 'exclamation-circle', info: 'info-circle' };
|
||||
t.innerHTML = `<i class="fas fa-${icons[type]||'info-circle'}" style="margin-right:8px;"></i>${msg}`;
|
||||
document.getElementById('toastContainer').appendChild(t);
|
||||
setTimeout(() => { t.style.opacity = '0'; setTimeout(() => t.remove(), 400); }, 3000);
|
||||
};
|
||||
|
||||
// ── Modal helpers ──
|
||||
window.openModal = function(id) {
|
||||
document.getElementById(id)?.classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
};
|
||||
window.closeModal = function(id) {
|
||||
document.getElementById(id)?.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
};
|
||||
|
||||
// Close modal on overlay click
|
||||
document.querySelectorAll('.modal-overlay').forEach(overlay => {
|
||||
overlay.addEventListener('click', e => {
|
||||
if (e.target === overlay) closeModal(overlay.id);
|
||||
});
|
||||
});
|
||||
|
||||
// ── Search filter ──
|
||||
window.filterTable = function(inputId, tableId) {
|
||||
const q = document.getElementById(inputId)?.value.toLowerCase() || '';
|
||||
document.querySelectorAll(`#${tableId} tbody tr`).forEach(row => {
|
||||
row.style.display = row.textContent.toLowerCase().includes(q) ? '' : 'none';
|
||||
});
|
||||
};
|
||||
|
||||
// Realtime SPBU snackbar
|
||||
(function initSpbuRealtimeSnackbar() {
|
||||
const API_URL = APP_BASE + '/api/spbu_status.php';
|
||||
const REFRESH_MS = 60000;
|
||||
const SHOW_MS = 7000;
|
||||
let lastOpen = null;
|
||||
let hideTimer = null;
|
||||
|
||||
function ensureSnackbar() {
|
||||
let el = document.getElementById('spbuRealtimeSnackbar');
|
||||
if (el) return el;
|
||||
|
||||
el = document.createElement('div');
|
||||
el.id = 'spbuRealtimeSnackbar';
|
||||
el.className = 'spbu-snackbar';
|
||||
el.innerHTML = `
|
||||
<div class="spbu-snackbar-icon"><i class="fas fa-gas-pump"></i></div>
|
||||
<div>
|
||||
<div class="spbu-snackbar-title" id="spbuSnackbarTitle">SPBU sedang buka</div>
|
||||
<div class="spbu-snackbar-meta" id="spbuSnackbarMeta">Memuat status terbaru...</div>
|
||||
</div>
|
||||
<div class="spbu-snackbar-count" id="spbuSnackbarCount">-</div>
|
||||
`;
|
||||
document.body.appendChild(el);
|
||||
return el;
|
||||
}
|
||||
|
||||
function showSnackbar(data) {
|
||||
const el = ensureSnackbar();
|
||||
const open = Number(data.spbu_buka || 0);
|
||||
const total = Number(data.total_spbu || 0);
|
||||
const closed = Number(data.spbu_tutup || Math.max(0, total - open));
|
||||
const time = data.server_time ? data.server_time.slice(11, 16) : new Date().toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit' });
|
||||
|
||||
document.getElementById('spbuSnackbarTitle').textContent = `${open} SPBU sedang buka`;
|
||||
document.getElementById('spbuSnackbarMeta').textContent = `${closed} tutup/terbatas dari ${total} total - update ${time} WIB`;
|
||||
document.getElementById('spbuSnackbarCount').textContent = open;
|
||||
|
||||
el.classList.add('show');
|
||||
clearTimeout(hideTimer);
|
||||
hideTimer = setTimeout(() => el.classList.remove('show'), SHOW_MS);
|
||||
}
|
||||
|
||||
async function refreshStatus(forceShow = false) {
|
||||
try {
|
||||
const res = await fetch(API_URL, { cache: 'no-store' });
|
||||
const json = await res.json();
|
||||
if (json.status !== 'success' || !json.data) return;
|
||||
|
||||
const open = Number(json.data.spbu_buka || 0);
|
||||
if (forceShow || lastOpen === null || open !== lastOpen) {
|
||||
showSnackbar(json.data);
|
||||
}
|
||||
lastOpen = open;
|
||||
} catch (e) {
|
||||
// Snackbar is informational; keep the page quiet if polling fails.
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
refreshStatus(true);
|
||||
setInterval(() => refreshStatus(false), REFRESH_MS);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<?= $extraScript ?? '' ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* User Layout — sidebar + topbar (read-only mode, beda style dari admin)
|
||||
* Variables expected from parent: $pageTitle, $activeNav
|
||||
*/
|
||||
$user = currentUser();
|
||||
$initial = strtoupper(substr($user['nama_lengkap'] ?: $user['username'], 0, 1));
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= htmlspecialchars($pageTitle ?? 'User Portal') ?> — WebGIS Smart City</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;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="<?= app_url('public_assets/css/global.css') ?>?v=20260610-spbu-snackbar">
|
||||
<link rel="stylesheet" href="<?= app_url('public_assets/css/panel.css') ?>">
|
||||
<script>const APP_BASE = '<?= app_url() ?>';</script>
|
||||
<?= $extraHead ?? '' ?>
|
||||
</head>
|
||||
<body class="admin-page user-portal <?= $bodyClass ?? '' ?>">
|
||||
|
||||
<!-- ══ SIDEBAR ══ -->
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<div class="sidebar-brand">
|
||||
<div class="brand-icon" style="background:linear-gradient(135deg,#10B981,#059669);">🗺️</div>
|
||||
<div class="brand-text">
|
||||
<span class="brand-name">WebGIS</span>
|
||||
<span class="brand-sub">Pengguna</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<div class="nav-section-title">Menu</div>
|
||||
<a href="<?= app_url('panel_user/index.php') ?>"
|
||||
class="nav-item <?= ($activeNav==='dashboard') ? 'active' : '' ?>">
|
||||
<span class="nav-icon"><i class="fas fa-chart-pie"></i></span> Beranda
|
||||
</a>
|
||||
<a href="<?= app_url('panel_user/peta_user.php') ?>"
|
||||
class="nav-item <?= ($activeNav==='peta') ? 'active' : '' ?>">
|
||||
<span class="nav-icon"><i class="fas fa-map-marked-alt"></i></span> Peta Interaktif
|
||||
</a>
|
||||
<a href="<?= app_url('panel_user/buat_laporan.php') ?>"
|
||||
class="nav-item <?= ($activeNav==='laporan') ? 'active' : '' ?>">
|
||||
<span class="nav-icon"><i class="fas fa-bullhorn"></i></span> Laporan Warga
|
||||
</a>
|
||||
|
||||
<div class="nav-section-title">Informasi</div>
|
||||
<div class="user-info" style="background:rgba(16,185,129,0.08);border-color:rgba(16,185,129,0.2);">
|
||||
<i class="fas fa-info-circle" style="color:#059669;font-size:1.1rem;"></i>
|
||||
<div style="font-size:0.78rem;color:var(--text-secondary);line-height:1.4;">
|
||||
Anda masuk sebagai <strong style="color:#059669">Pengguna</strong>. Data hanya dapat dilihat, tidak dapat diubah.
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-footer">
|
||||
<div class="user-info">
|
||||
<div class="user-avatar" style="background:linear-gradient(135deg,#10B981,#059669);"><?= $initial ?></div>
|
||||
<div class="user-details">
|
||||
<div class="user-name"><?= htmlspecialchars($user['nama_lengkap'] ?: $user['username']) ?></div>
|
||||
<div class="user-role">Pengguna</div>
|
||||
</div>
|
||||
<a href="<?= app_url('logout.php') ?>" class="user-logout" title="Keluar">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- ══ MAIN CONTENT ══ -->
|
||||
<main class="admin-main">
|
||||
<div class="topbar">
|
||||
<span class="topbar-title"><?= htmlspecialchars($pageTitle ?? 'Beranda') ?></span>
|
||||
<div class="topbar-actions">
|
||||
<div class="topbar-time" id="clock">
|
||||
<i class="fas fa-clock"></i> <span id="clockText"></span>
|
||||
</div>
|
||||
<span class="badge badge-success" style="font-size:0.7rem;padding:5px 10px;">
|
||||
<i class="fas fa-eye"></i> Mode Baca
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admin-content">
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../core_config/database.php';
|
||||
require_once __DIR__ . '/../core_config/middleware_auth.php';
|
||||
requireRole('user');
|
||||
|
||||
$pageTitle = 'Peta Interaktif';
|
||||
$activeNav = 'peta';
|
||||
$bodyClass = 'admin-map-page map-page';
|
||||
$extraHead = '
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
|
||||
<link rel="stylesheet" href="' . app_url('public_assets/css/map.css') . '?v=20260610-2">
|
||||
';
|
||||
require_once __DIR__ . '/partials/header.php';
|
||||
?>
|
||||
|
||||
<div class="map-wrap">
|
||||
<div id="user-map"></div>
|
||||
|
||||
<div class="read-only-badge">
|
||||
<i class="fas fa-eye"></i> Mode Baca
|
||||
</div>
|
||||
|
||||
<aside class="map-sidebar">
|
||||
<div class="map-panel-header">
|
||||
<div class="map-panel-icon"><i class="fas fa-layer-group"></i></div>
|
||||
<div>
|
||||
<h3>Layer Peta</h3>
|
||||
<p>Kontrol data yang tampil di peta</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layer-section">
|
||||
<div class="layer-section-title">Infrastruktur</div>
|
||||
|
||||
<label class="layer-item">
|
||||
<input type="checkbox" id="ly-spbu" checked>
|
||||
<span class="layer-color layer-point" style="--layer-color:#F59E0B"><i class="fas fa-gas-pump"></i></span>
|
||||
<span class="layer-text">
|
||||
<span class="layer-name">SPBU</span>
|
||||
<span class="layer-meta">Stasiun pengisian bahan bakar</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="layer-item">
|
||||
<input type="checkbox" id="ly-jalan" checked>
|
||||
<span class="layer-color layer-line" style="--layer-color:#3B82F6"></span>
|
||||
<span class="layer-text">
|
||||
<span class="layer-name">Jalan</span>
|
||||
<span class="layer-meta">Ruas jalan utama dan lokal</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="layer-item">
|
||||
<input type="checkbox" id="ly-kavling" checked>
|
||||
<span class="layer-color layer-area" style="--layer-color:#7C3AED"></span>
|
||||
<span class="layer-text">
|
||||
<span class="layer-name">Kavling / Parsil</span>
|
||||
<span class="layer-meta">Batas bidang tanah</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layer-section">
|
||||
<div class="layer-section-title">Sosial</div>
|
||||
|
||||
<label class="layer-item">
|
||||
<input type="checkbox" id="ly-rumah" checked>
|
||||
<span class="layer-color layer-point" style="--layer-color:#8B5CF6"><i class="fas fa-mosque"></i></span>
|
||||
<span class="layer-text">
|
||||
<span class="layer-name">Rumah Ibadah</span>
|
||||
<span class="layer-meta">Fasilitas keagamaan</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="layer-item">
|
||||
<input type="checkbox" id="ly-warga" checked>
|
||||
<span class="layer-color layer-point" style="--layer-color:#EF4444"><i class="fas fa-users"></i></span>
|
||||
<span class="layer-text">
|
||||
<span class="layer-name">Warga Miskin</span>
|
||||
<span class="layer-meta">Sebaran keluarga penerima bantuan</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="layer-item">
|
||||
<input type="checkbox" id="ly-kawasan">
|
||||
<span class="layer-color layer-area layer-hatch" style="--layer-color:#DC2626"></span>
|
||||
<span class="layer-text">
|
||||
<span class="layer-name">Kawasan Kumuh</span>
|
||||
<span class="layer-meta">Area prioritas penanganan</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layer-section">
|
||||
<div class="layer-section-title">Analisis</div>
|
||||
|
||||
<label class="layer-item">
|
||||
<input type="checkbox" id="ly-choropleth">
|
||||
<span class="layer-color layer-gradient"></span>
|
||||
<span class="layer-text">
|
||||
<span class="layer-name">Choropleth Kepadatan</span>
|
||||
<span class="layer-meta">Kepadatan warga miskin per kawasan</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="layer-item">
|
||||
<input type="checkbox" id="ly-blankspot">
|
||||
<span class="layer-color layer-point" style="--layer-color:#F97316"><i class="fas fa-location-dot"></i></span>
|
||||
<span class="layer-text">
|
||||
<span class="layer-name">Blank Spot Bansos</span>
|
||||
<span class="layer-meta">Titik jauh dari fasilitas bantuan</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="map-quickstats">
|
||||
<div class="qs-item"><div class="qs-value" id="qs-spbu" style="color:#F59E0B">-</div><div class="qs-label">SPBU</div></div>
|
||||
<div class="qs-item"><div class="qs-value" id="qs-jalan" style="color:#3B82F6">-</div><div class="qs-label">Jalan</div></div>
|
||||
<div class="qs-item"><div class="qs-value" id="qs-kavling" style="color:#7C3AED">-</div><div class="qs-label">Kavling</div></div>
|
||||
<div class="qs-item"><div class="qs-value" id="qs-warga" style="color:#EF4444">-</div><div class="qs-label">Warga</div></div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="map-analysis">
|
||||
<button id="btn-find-spbu" class="map-tool-accent" title="Cari SPBU terdekat dari pusat peta">
|
||||
<i class="fas fa-search-location"></i> SPBU Terdekat
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="spbu-panel" id="spbuPanel" style="display:none;">
|
||||
<div class="spbu-panel-title">
|
||||
<i class="fas fa-search-location"></i> SPBU Terdekat
|
||||
<button class="modal-close" id="btn-close-spbu" style="margin-left:auto;background:none;border:none;color:var(--text-muted);cursor:pointer;font-size:1.2rem;">×</button>
|
||||
</div>
|
||||
<div id="spbuPanelResult"></div>
|
||||
</div>
|
||||
|
||||
<div class="map-legend">
|
||||
<div class="map-legend-title"><i class="fas fa-list-ul"></i> Legenda</div>
|
||||
<div class="legend-grid">
|
||||
<div class="legend-item"><span class="legend-symbol legend-dot" style="--legend-color:#10B981"></span><span>SPBU 24 Jam</span></div>
|
||||
<div class="legend-item"><span class="legend-symbol legend-dot" style="--legend-color:#F59E0B"></span><span>SPBU Terbatas</span></div>
|
||||
<div class="legend-item"><span class="legend-symbol legend-line" style="--legend-color:#3B82F6"></span><span>Jalan</span></div>
|
||||
<div class="legend-item"><span class="legend-symbol legend-area" style="--legend-color:#7C3AED"></span><span>Kavling</span></div>
|
||||
<div class="legend-item"><span class="legend-symbol legend-dot" style="--legend-color:#8B5CF6"></span><span>Rumah Ibadah</span></div>
|
||||
<div class="legend-item"><span class="legend-symbol legend-dot" style="--legend-color:#EF4444"></span><span>Warga Miskin</span></div>
|
||||
<div class="legend-item"><span class="legend-symbol legend-hatch" style="--legend-color:#DC2626"></span><span>Kawasan Kumuh</span></div>
|
||||
<div class="legend-item"><span class="legend-symbol legend-dot" style="--legend-color:#F97316"></span><span>Blank Spot</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="map-loading" id="loadingOverlay" style="display:none;">
|
||||
<div class="spinner"></div>
|
||||
<span>Memuat data...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script src="<?= app_url('public_assets/js/peta-user.js') ?>?v=20260612-fix"></script>
|
||||
<?php $extraScript = ''; ?>
|
||||
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||
Reference in New Issue
Block a user