feat: implement full authentication system and CRUD APIs for users, rumah ibadah, and penduduk miskin with database updates.

This commit is contained in:
Syariffullah
2026-06-11 08:10:42 +07:00
parent 5585c34c5c
commit b77d4f6869
48 changed files with 1439 additions and 1442 deletions
+156 -84
View File
@@ -15,8 +15,7 @@
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<!-- Leaflet Draw CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"/>
<!-- Custom CSS -->
<link rel="stylesheet" href="assets/css/style.css">
@@ -30,7 +29,7 @@
<div class="search-icon">
<i class="fas fa-search"></i>
</div>
<input type="text" class="search-input" id="searchInput" placeholder="Cari SPBU, jalan, parsil, rumah ibadah...">
<input type="text" class="search-input" id="searchInput" placeholder="Cari rumah ibadah...">
<button class="search-clear" id="searchClear">
<i class="fas fa-times"></i>
</button>
@@ -53,18 +52,7 @@
<!-- Left Sidebar Menu -->
<nav class="left-sidebar" id="leftSidebar" style="display:none;">
<button class="sidebar-btn" id="menuSpbu" data-panel="spbu" title="SPBU">
<span class="sidebar-emoji"></span>
<span class="sidebar-label">SPBU</span>
</button>
<button class="sidebar-btn" id="menuJalan" data-panel="jalan" title="Jalan">
<span class="sidebar-emoji">🛣️</span>
<span class="sidebar-label">Jalan</span>
</button>
<button class="sidebar-btn" id="menuParsil" data-panel="parsil" title="Parsil Tanah">
<span class="sidebar-emoji">🗺️</span>
<span class="sidebar-label">Parsil</span>
</button>
<button class="sidebar-btn" id="menuIbadah" data-panel="ibadah" title="Rumah Ibadah">
<span class="sidebar-emoji">🕌</span>
<span class="sidebar-label">Ibadah</span>
@@ -73,6 +61,12 @@
<span class="sidebar-emoji">🏠</span>
<span class="sidebar-label">Miskin</span>
</button>
<div class="sidebar-divider" id="sidebarAdminDivider" style="display:none;"></div>
<button class="sidebar-btn" id="menuUsers" style="display:none;" title="Manajemen Pengguna">
<span class="sidebar-emoji">👥</span>
<span class="sidebar-label">User</span>
</button>
</nav>
@@ -87,68 +81,9 @@
<div class="custom-layer-panel" id="layerPanel">
<h3>Daftar Layer</h3>
<!-- SPBU -->
<div class="layer-group-item">
<div class="layer-group-header">
<label class="layer-option" style="margin:0; flex:1;">
<input type="checkbox" id="layerSpbu" checked> SPBU
</label>
<span class="layer-toggle-icon collapsed" onclick="toggleSubLayer('subSpbu', this)"><i class="fas fa-chevron-down"></i></span>
</div>
<div id="subSpbu" class="sub-layer-list" style="display:none;">
<label class="layer-option sub-option">
<input type="checkbox" class="sub-spbu" value="1" checked onchange="applySubFilter('spbu')"> 24 Jam
</label>
<label class="layer-option sub-option">
<input type="checkbox" class="sub-spbu" value="0" checked onchange="applySubFilter('spbu')"> Tidak 24 Jam
</label>
</div>
</div>
<!-- Jalan -->
<div class="layer-group-item">
<div class="layer-group-header">
<label class="layer-option" style="margin:0; flex:1;">
<input type="checkbox" id="layerJalan" checked> Jalan
</label>
<span class="layer-toggle-icon collapsed" onclick="toggleSubLayer('subJalan', this)"><i class="fas fa-chevron-down"></i></span>
</div>
<div id="subJalan" class="sub-layer-list" style="display:none;">
<label class="layer-option sub-option">
<input type="checkbox" class="sub-jalan" value="Nasional" checked onchange="applySubFilter('jalan')"> Nasional
</label>
<label class="layer-option sub-option">
<input type="checkbox" class="sub-jalan" value="Provinsi" checked onchange="applySubFilter('jalan')"> Provinsi
</label>
<label class="layer-option sub-option">
<input type="checkbox" class="sub-jalan" value="Kabupaten" checked onchange="applySubFilter('jalan')"> Kabupaten
</label>
</div>
</div>
<!-- Parsil -->
<div class="layer-group-item">
<div class="layer-group-header">
<label class="layer-option" style="margin:0; flex:1;">
<input type="checkbox" id="layerParsil" checked> Parsil Tanah
</label>
<span class="layer-toggle-icon collapsed" onclick="toggleSubLayer('subParsil', this)"><i class="fas fa-chevron-down"></i></span>
</div>
<div id="subParsil" class="sub-layer-list" style="display:none;">
<label class="layer-option sub-option">
<input type="checkbox" class="sub-parsil" value="SHM" checked onchange="applySubFilter('parsil')"> SHM
</label>
<label class="layer-option sub-option">
<input type="checkbox" class="sub-parsil" value="HGB" checked onchange="applySubFilter('parsil')"> HGB
</label>
<label class="layer-option sub-option">
<input type="checkbox" class="sub-parsil" value="HGU" checked onchange="applySubFilter('parsil')"> HGU
</label>
<label class="layer-option sub-option">
<input type="checkbox" class="sub-parsil" value="HP" checked onchange="applySubFilter('parsil')"> HP
</label>
</div>
</div>
<div class="layer-section-title">Pemetaan Kemiskinan</div>
<!-- Rumah Ibadah -->
<label class="layer-option">
@@ -290,29 +225,166 @@
</div>
</div>
<!-- Floating Profile / Auth Control -->
<div id="authWidget" class="auth-widget">
<button class="btn-login" id="authLoginBtn"><i class="fas fa-sign-in-alt"></i> Login</button>
</div>
<!-- Login Modal -->
<div id="loginModal" class="unified-modal">
<div class="modal-content" style="width: 360px;">
<div class="modal-header">
<h3>Login Ke Sistem</h3>
<span class="modal-close" id="closeLoginModal">&times;</span>
</div>
<div class="modal-body">
<div class="form-group">
<label for="loginUsername">Username</label>
<input type="text" id="loginUsername" placeholder="Masukkan username">
</div>
<div class="form-group">
<label for="loginPassword">Password</label>
<input type="password" id="loginPassword" placeholder="Masukkan password">
</div>
<div id="loginErrorMsg" style="display:none; color:#ef4444; font-size:12px; font-weight:500;"></div>
</div>
<div class="modal-footer">
<button id="loginSubmitBtn" class="btn-save" style="width: 100%;">Masuk</button>
</div>
</div>
</div>
<!-- User Management Modal -->
<div id="userManagementModal" class="unified-modal">
<div class="modal-content" style="width: 700px; max-width: 95%;">
<div class="modal-header">
<h3>Manajemen Pengguna (Admin)</h3>
<span class="modal-close" id="closeUserManagementModal">&times;</span>
</div>
<div class="modal-body" style="gap: 15px;">
<!-- Form Tambah/Edit User -->
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 12px; display: flex; flex-direction: column; gap: 10px;">
<h4 id="userFormTitle" style="font-size: 13px; font-weight:700; color:#334155; margin-bottom: 2px;">Tambah User Baru</h4>
<input type="hidden" id="manageUserId" value="">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
<div class="form-group">
<label>Username</label>
<input type="text" id="manageUsername" placeholder="Username">
</div>
<div class="form-group">
<label>Password (Kosongkan jika tidak diubah)</label>
<input type="password" id="managePassword" placeholder="Password">
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
<div class="form-group">
<label>Role</label>
<select id="manageRole">
<option value="pengelola" selected>Pengelola Rumah Ibadah</option>
<option value="admin">Admin</option>
</select>
</div>
<div class="form-group" id="manageIbadahGroup">
<label>Rumah Ibadah yang Dikelola</label>
<select id="manageIbadahId">
<!-- Dikonstruksi dinamis dari data rumah ibadah -->
</select>
</div>
</div>
<div style="display: flex; gap: 8px; justify-content: flex-end; margin-top: 5px;">
<button id="btnCancelUserEdit" class="btn-cancel" style="padding: 6px 12px; display:none;">Batal</button>
<button id="btnSaveUser" class="btn-save" style="padding: 6px 16px;">Simpan User</button>
</div>
</div>
<!-- Tabel Daftar User -->
<div style="max-height: 200px; overflow-y: auto; border: 1px solid #cbd5e1; border-radius: 8px;">
<table style="width: 100%; border-collapse: collapse; font-size: 13px; text-align: left;">
<thead>
<tr style="background: #f1f5f9; border-bottom: 1px solid #cbd5e1; color:#475569; position: sticky; top: 0; z-index: 10;">
<th style="padding: 10px 12px;">Username</th>
<th style="padding: 10px 12px;">Role</th>
<th style="padding: 10px 12px;">Rumah Ibadah</th>
<th style="padding: 10px 12px; text-align: center;">Aksi</th>
</tr>
</thead>
<tbody id="userTableBody">
<!-- Diisi dinamis -->
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Toast Notification Container -->
<div id="toastContainer"></div>
<!-- Disclaimer Banner -->
<div id="disclaimerBanner" style="
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 2000;
background: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
color: #f1f5f9;
border: 1px solid #f59e0b;
border-left: 4px solid #f59e0b;
border-radius: 10px;
padding: 12px 16px;
max-width: 520px;
width: calc(100% - 40px);
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
display: flex;
align-items: flex-start;
gap: 12px;
font-family: 'Inter', sans-serif;
animation: slideUpBanner 0.4s ease;
">
<span style="font-size: 20px; flex-shrink:0; margin-top:1px;">⚠️</span>
<div style="flex:1;">
<div style="font-size: 13px; font-weight: 700; color: #fbbf24; margin-bottom: 4px; letter-spacing: 0.3px;">DISCLAIMER DATA DUMMY</div>
<div style="font-size: 12px; line-height: 1.6; color: #cbd5e1;">
Seluruh data pada aplikasi ini termasuk <strong style="color:#fde68a;">nama penduduk, foto rumah, dan foto Kartu Keluarga (KK)</strong> merupakan <strong style="color:#fde68a;">data fiktif / dummy</strong> yang hanya digunakan untuk keperluan demonstrasi dan pengujian sistem. Bukan data nyata.
</div>
</div>
<button onclick="document.getElementById('disclaimerBanner').style.display='none'" style="
background: transparent;
border: 1px solid #475569;
color: #94a3b8;
border-radius: 6px;
padding: 3px 8px;
cursor: pointer;
font-size: 11px;
flex-shrink: 0;
margin-top: 1px;
transition: all 0.2s;
" onmouseover="this.style.borderColor='#f59e0b';this.style.color='#f59e0b'" onmouseout="this.style.borderColor='#475569';this.style.color='#94a3b8'">Tutup</button>
</div>
<style>
@keyframes slideUpBanner {
from { opacity: 0; transform: translateX(-50%) translateY(20px); }
to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
</style>
<!-- Leaflet JS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<!-- Leaflet Draw JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
<!-- Leaflet TextPath JS (untuk teks diagonal) -->
<script src="https://cdn.jsdelivr.net/npm/leaflet-textpath@1.2.3/leaflet.textpath.min.js"></script>
<!-- Main Map Initialization -->
<script src="assets/js/map.js?v=<?= time() ?>"></script>
<!-- Fitur & Komponen -->
<script src="assets/js/features/spbu.js?v=<?= time() ?>"></script>
<script src="assets/js/features/jalan.js?v=<?= time() ?>"></script>
<script src="assets/js/features/parsil.js?v=<?= time() ?>"></script>
<script src="assets/js/features/draw_control.js?v=<?= time() ?>"></script>
<script src="assets/js/features/geolocation.js?v=<?= time() ?>"></script>
<script src="assets/js/features/kemiskinan.js?v=<?= time() ?>"></script>
<script src="assets/js/features/geojson.js?v=<?= time() ?>"></script>
<script src="assets/js/panel.js?v=<?= time() ?>"></script>
<!-- Core Auth Feature -->
<script src="assets/js/features/auth.js?v=<?= time() ?>"></script>
</body>
</html>