Refactor code structure for improved readability and maintainability
This commit is contained in:
+141
-245
@@ -8,15 +8,10 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WebGIS SPBU - Layer Control</title>
|
||||
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/latin-400-normal.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/latin-500-normal.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/latin-600-normal.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/latin-700-normal.css">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body { font-family: 'Inter', sans-serif; }
|
||||
#map { height: 100%; width: 100%; z-index: 1; }
|
||||
@@ -26,144 +21,36 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
.custom-scrollbar::-webkit-scrollbar-track { background: #f1f5f9; border-radius: 10px; }
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 10px; }
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
|
||||
.glass-panel { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); }
|
||||
.fade-in { animation: fadeIn 0.3s ease-in-out; }
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } }
|
||||
|
||||
.admin-mode .leaflet-marker-draggable { cursor: grab; }
|
||||
.admin-mode .leaflet-marker-draggable:active { cursor: grabbing; }
|
||||
|
||||
@keyframes pulse {
|
||||
0% { box-shadow: 0 0 0 0 rgba(13, 148, 136, 0.5); }
|
||||
70% { box-shadow: 0 0 0 10px rgba(13, 148, 136, 0); }
|
||||
100% { box-shadow: 0 0 0 0 rgba(13, 148, 136, 0); }
|
||||
}
|
||||
.pulse-ring { animation: pulse 2s infinite; }
|
||||
|
||||
/* Google Maps Style Panel + Handle */
|
||||
.gm-panel-wrapper {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
z-index: 20;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.gm-panel-wrapper-left {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.gm-panel-wrapper-right {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.gm-panel-content {
|
||||
background: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1), min-width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.gm-panel-content-left {
|
||||
width: 384px;
|
||||
min-width: 384px;
|
||||
border-right: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.gm-panel-content-right {
|
||||
width: 320px;
|
||||
min-width: 320px;
|
||||
border-left: 1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.gm-panel-content.collapsed {
|
||||
width: 0 !important;
|
||||
min-width: 0 !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.gm-handle {
|
||||
width: 23px;
|
||||
background: white;
|
||||
border: 1px solid #e2e8f0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.2s;
|
||||
box-shadow: 0 1px 2px rgba(60,64,67,0.3), 0 2px 6px 2px rgba(60,64,67,0.15);
|
||||
flex-shrink: 0;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
height: 48px;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.gm-handle:hover {
|
||||
background: #f1f3f4;
|
||||
}
|
||||
|
||||
.gm-handle-left {
|
||||
border-radius: 0 8px 8px 0;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.gm-handle-right {
|
||||
border-radius: 8px 0 0 8px;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.gm-handle svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: #5f6368;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.layer-card {
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
.gm-panel-wrapper { display: flex; align-items: stretch; z-index: 20; flex-shrink: 0; }
|
||||
.gm-panel-wrapper-left { flex-direction: row; }
|
||||
.gm-panel-wrapper-right { flex-direction: row-reverse; }
|
||||
.gm-panel-content { background: white; display: flex; flex-direction: column; overflow: hidden; transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1), min-width 0.3s cubic-bezier(0.4, 0, 0.2, 1); }
|
||||
.gm-panel-content-left { width: 384px; min-width: 384px; border-right: 1px solid #e2e8f0; }
|
||||
.gm-panel-content-right { width: 320px; min-width: 320px; border-left: 1px solid #e2e8f0; }
|
||||
.gm-panel-content.collapsed { width: 0 !important; min-width: 0 !important; border: none !important; }
|
||||
.gm-handle { width: 23px; background: white; border: 1px solid #e2e8f0; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.2s; box-shadow: 0 1px 2px rgba(60,64,67,0.3), 0 2px 6px 2px rgba(60,64,67,0.15); flex-shrink: 0; margin-top: auto; margin-bottom: auto; height: 48px; z-index: 30; }
|
||||
.gm-handle:hover { background: #f1f3f4; }
|
||||
.gm-handle-left { border-radius: 0 8px 8px 0; border-left: none; }
|
||||
.gm-handle-right { border-radius: 8px 0 0 8px; border-right: none; }
|
||||
.gm-handle svg { width: 20px; height: 20px; color: #5f6368; transition: transform 0.3s; }
|
||||
.layer-card { cursor: pointer; transition: all 0.2s ease; border: 2px solid transparent; }
|
||||
.layer-card:hover { border-color: #cbd5e1; }
|
||||
.layer-card.active {
|
||||
border-color: #0d9488;
|
||||
background: #f0fdfa;
|
||||
}
|
||||
|
||||
.layer-preview {
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
border: 2px solid #e2e8f0;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.layer-card.active { border-color: #0d9488; background: #f0fdfa; }
|
||||
.layer-preview { width: 100%; height: 45px; border-radius: 8px; overflow: hidden; border: 2px solid #e2e8f0; transition: all 0.2s; }
|
||||
.layer-card.active .layer-preview { border-color: #0d9488; }
|
||||
|
||||
.toggle-switch {
|
||||
width: 40px;
|
||||
height: 22px;
|
||||
background: #cbd5e1;
|
||||
border-radius: 11px;
|
||||
position: relative;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.toggle-switch { width: 40px; height: 22px; background: #cbd5e1; border-radius: 11px; position: relative; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); cursor: pointer; flex-shrink: 0; }
|
||||
.toggle-switch.active { background: #0d9488; }
|
||||
.toggle-switch::after {
|
||||
content: '';
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
||||
}
|
||||
.toggle-switch::after { content: ''; width: 18px; height: 18px; background: white; border-radius: 50%; position: absolute; top: 2px; left: 2px; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 1px 3px rgba(0,0,0,0.2); }
|
||||
.toggle-switch.active::after { left: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
@@ -183,7 +70,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
<p class="text-xs text-teal-200">Sistem Informasi Lokasi Stasiun Pengisian Bahan Bakar Umum</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="relative z-10 flex items-center gap-4">
|
||||
<div class="relative hidden md:block">
|
||||
<input type="text" id="searchInput" placeholder="Cari nama SPBU..." class="w-64 pl-10 pr-4 py-2 rounded-full bg-white/20 border border-white/30 text-white placeholder-teal-200 focus:outline-none focus:ring-2 focus:ring-teal-400 focus:bg-white/30 transition-all text-sm">
|
||||
@@ -191,13 +77,11 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div id="authContainer"></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="flex flex-1 overflow-hidden relative">
|
||||
|
||||
<div class="gm-panel-wrapper gm-panel-wrapper-left" id="panelWrapperLeft">
|
||||
<aside class="gm-panel-content gm-panel-content-left shadow-xl" id="sidebarLeft">
|
||||
<div class="p-4 border-b border-slate-100 bg-slate-50">
|
||||
@@ -212,7 +96,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border-b border-slate-100 md:hidden">
|
||||
<div class="relative">
|
||||
<input type="text" id="searchInputMobile" placeholder="Cari nama SPBU..." class="w-full pl-10 pr-4 py-2 rounded-lg bg-slate-100 text-slate-800 placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-teal-500 text-sm">
|
||||
@@ -221,7 +104,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-4 py-3 flex items-center justify-between bg-white border-b border-slate-100">
|
||||
<h2 class="font-semibold text-slate-700 text-sm uppercase tracking-wider">Daftar SPBU</h2>
|
||||
<button id="btnAddSpbu" class="bg-teal-600 hover:bg-teal-700 text-white text-xs font-medium px-3 py-1.5 rounded-lg shadow-sm transition-colors flex items-center gap-1" style="display: <?php echo $isAdmin ? 'flex' : 'none'; ?>">
|
||||
@@ -231,10 +113,8 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
Tambah
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="spbuList" class="flex-1 overflow-y-auto custom-scrollbar p-3 space-y-2"></div>
|
||||
</aside>
|
||||
|
||||
<button class="gm-handle gm-handle-left" id="handleLeft" onclick="toggleLeftPanel()" title="Ciutkan panel samping">
|
||||
<svg id="handleLeftIcon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
@@ -244,11 +124,9 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
|
||||
<div class="flex-1 relative" id="mapContainer">
|
||||
<div id="map"></div>
|
||||
|
||||
<div id="mapHint" class="absolute bottom-4 left-1/2 -translate-x-1/2 z-[1000] bg-white/90 backdrop-blur px-4 py-2 rounded-lg shadow-md text-xs text-slate-600 border border-slate-200 pointer-events-none" style="display: none;">
|
||||
💡 Klik pada peta untuk memilih lokasi SPBU baru
|
||||
</div>
|
||||
|
||||
<div id="modeIndicator" class="absolute top-20 left-4 z-[1000] bg-teal-600 text-white px-4 py-2 rounded-lg shadow-md text-xs font-medium hidden pulse-ring">
|
||||
🎯 Mode Pilih Titik - Klik pada peta
|
||||
</div>
|
||||
@@ -259,7 +137,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
<div class="p-4 border-b border-slate-100 bg-slate-50">
|
||||
<h3 class="text-sm font-semibold text-slate-700">Pengaturan Peta</h3>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-y-auto custom-scrollbar p-4 space-y-5">
|
||||
<div>
|
||||
<label class="text-xs font-bold text-slate-500 uppercase tracking-wider mb-3 block">Tipe Peta Dasar</label>
|
||||
@@ -272,7 +149,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</div>
|
||||
<span class="text-[11px] font-semibold text-slate-700">Ringan</span>
|
||||
</div>
|
||||
|
||||
<div class="layer-card p-2 rounded-lg" onclick="switchBaseMap('satellite')" id="layerSatellite">
|
||||
<div class="layer-preview mb-1.5" style="background: linear-gradient(135deg, #064e3b 0%, #065f46 30%, #047857 60%, #059669 100%); position: relative; overflow: hidden;">
|
||||
<div style="position: absolute; top: 20%; left: 30%; width: 40%; height: 15%; background: rgba(255,255,255,0.3); border-radius: 2px;"></div>
|
||||
@@ -280,14 +156,12 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</div>
|
||||
<span class="text-[11px] font-semibold text-slate-700">Satelit</span>
|
||||
</div>
|
||||
|
||||
<div class="layer-card p-2 rounded-lg" onclick="switchBaseMap('terrain')" id="layerTerrain">
|
||||
<div class="layer-preview mb-1.5" style="background: linear-gradient(135deg, #fef3c7 0%, #d4a574 40%, #8b6914 70%, #4a7c59 100%); position: relative; overflow: hidden;">
|
||||
<div style="position: absolute; bottom: 0; left: 0; right: 0; height: 40%; background: linear-gradient(to top, #4a7c59, transparent);"></div>
|
||||
</div>
|
||||
<span class="text-[11px] font-semibold text-slate-700">Topografi</span>
|
||||
</div>
|
||||
|
||||
<div class="layer-card p-2 rounded-lg" onclick="switchBaseMap('dark')" id="layerDark">
|
||||
<div class="layer-preview mb-1.5" style="background: linear-gradient(135deg, #1e293b 0%, #334155 30%, #1e293b 60%, #0f172a 100%); position: relative; overflow: hidden;">
|
||||
<div style="position: absolute; top: 25%; left: 15%; width: 35%; height: 1.5px; background: #64748b;"></div>
|
||||
@@ -298,7 +172,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="text-xs font-bold text-slate-500 uppercase tracking-wider mb-3 block">Layer SPBU</label>
|
||||
<div class="space-y-2">
|
||||
@@ -316,7 +189,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</div>
|
||||
<div class="toggle-switch active" onclick="toggleLayer('24jam', event)" id="toggle24Jam"></div>
|
||||
</div>
|
||||
|
||||
<div class="layer-card active p-3 rounded-lg flex items-center justify-between" id="layerTerbatasCard">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-amber-500 flex items-center justify-center shadow-md">
|
||||
@@ -333,16 +205,33 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-xs font-bold text-slate-500 uppercase tracking-wider mb-3 block">Choropleth</label>
|
||||
<div class="space-y-2">
|
||||
<div class="layer-card active p-3 rounded-lg flex items-center justify-between" id="layerChoroplethCard">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-purple-500 flex items-center justify-center shadow-md">
|
||||
<svg class="w-4 h-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-sm font-semibold text-slate-700">Kecamatan</p>
|
||||
<p class="text-[10px] text-slate-400" id="countChoropleth">-</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toggle-switch active" onclick="toggleChoropleth(event)" id="toggleChoropleth"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<button class="gm-handle gm-handle-right" id="handleRight" onclick="toggleRightPanel()" title="Ciutkan panel lapisan">
|
||||
<svg id="handleRightIcon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
<div id="loginOverlay" class="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-50 hidden flex items-center justify-center p-4">
|
||||
@@ -353,19 +242,10 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<form id="loginForm" class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Username</label>
|
||||
<input type="text" id="loginUsername" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm" placeholder="admin">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Password</label>
|
||||
<input type="password" id="loginPassword" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm" placeholder="••••••••">
|
||||
</div>
|
||||
<div><label for="loginUsername" class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Username</label><input type="text" id="loginUsername" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm" placeholder="admin"></div>
|
||||
<div><label for="loginPassword" class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Password</label><input type="password" id="loginPassword" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm" placeholder="••••••••"></div>
|
||||
<div id="loginError" class="text-red-500 text-xs hidden">Username atau password salah!</div>
|
||||
<div class="flex gap-3 pt-2">
|
||||
<button type="button" id="btnCancelLogin" class="flex-1 px-4 py-2 border border-slate-300 text-slate-700 rounded-lg hover:bg-slate-50 font-medium text-sm transition-colors">Batal</button>
|
||||
<button type="submit" class="flex-1 px-4 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 font-medium text-sm transition-colors shadow-md shadow-teal-200">Masuk</button>
|
||||
</div>
|
||||
<div class="flex gap-3 pt-2"><button type="button" id="btnCancelLogin" class="flex-1 px-4 py-2 border border-slate-300 text-slate-700 rounded-lg hover:bg-slate-50 font-medium text-sm transition-colors">Batal</button><button type="submit" class="flex-1 px-4 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 font-medium text-sm transition-colors shadow-md shadow-teal-200">Masuk</button></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -373,50 +253,14 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
|
||||
<div id="modalOverlay" class="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-50 hidden flex items-center justify-center p-4">
|
||||
<div class="bg-white rounded-2xl shadow-2xl w-full max-w-md overflow-hidden fade-in">
|
||||
<div class="bg-gradient-to-r from-teal-600 to-teal-500 px-6 py-4 flex items-center justify-between">
|
||||
<h3 class="text-lg font-bold text-white" id="modalTitle">Tambah SPBU Baru</h3>
|
||||
<button id="btnCloseModal" class="text-white/80 hover:text-white transition-colors">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="bg-gradient-to-r from-teal-600 to-teal-500 px-6 py-4 flex items-center justify-between"><h3 class="text-lg font-bold text-white" id="modalTitle">Tambah SPBU Baru</h3><button id="btnCloseModal" class="text-white/80 hover:text-white transition-colors"><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg></button></div>
|
||||
<form id="spbuForm" class="p-6 space-y-4">
|
||||
<input type="hidden" id="spbuId">
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Nama SPBU</label>
|
||||
<input type="text" id="inputNama" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm" placeholder="Contoh: SPBU Pertamina Tebet">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">No. SPBU</label>
|
||||
<input type="text" id="inputNo" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm" placeholder="Contoh: 34.101.01">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Status Operasional</label>
|
||||
<select id="inputStatus" class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm bg-white">
|
||||
<option value="24jam">Buka 24 Jam</option>
|
||||
<option value="terbatas">Jam Terbatas</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Latitude</label>
|
||||
<input type="number" step="any" id="inputLat" required readonly class="w-full px-3 py-2 border border-slate-200 bg-slate-100 rounded-lg text-sm text-slate-600 cursor-not-allowed">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Longitude</label>
|
||||
<input type="number" step="any" id="inputLng" required readonly class="w-full px-3 py-2 border border-slate-200 bg-slate-100 rounded-lg text-sm text-slate-600 cursor-not-allowed">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pt-2 flex gap-3">
|
||||
<button type="button" id="btnCancelModal" class="flex-1 px-4 py-2 border border-slate-300 text-slate-700 rounded-lg hover:bg-slate-50 font-medium text-sm transition-colors">Batal</button>
|
||||
<button type="submit" class="flex-1 px-4 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 font-medium text-sm transition-colors shadow-md shadow-teal-200">Simpan</button>
|
||||
</div>
|
||||
<div><label for="inputNama" class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Nama SPBU</label><input type="text" id="inputNama" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm" placeholder="Contoh: SPBU Pertamina Tebet"></div>
|
||||
<div><label for="inputNo" class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">No. SPBU</label><input type="text" id="inputNo" required class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm" placeholder="Contoh: 34.101.01"></div>
|
||||
<div><label for="inputStatus" class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Status Operasional</label><select id="inputStatus" class="w-full px-3 py-2 border border-slate-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent text-sm bg-white"><option value="24jam">Buka 24 Jam</option><option value="terbatas">Jam Terbatas</option></select></div>
|
||||
<div class="grid grid-cols-2 gap-3"><div><label for="inputLat" class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Latitude</label><input type="number" step="any" id="inputLat" required readonly class="w-full px-3 py-2 border border-slate-200 bg-slate-100 rounded-lg text-sm text-slate-600 cursor-not-allowed"></div><div><label for="inputLng" class="block text-xs font-semibold text-slate-600 mb-1 uppercase tracking-wide">Longitude</label><input type="number" step="any" id="inputLng" required readonly class="w-full px-3 py-2 border border-slate-200 bg-slate-100 rounded-lg text-sm text-slate-600 cursor-not-allowed"></div></div>
|
||||
<div class="pt-2 flex gap-3"><button type="button" id="btnCancelModal" class="flex-1 px-4 py-2 border border-slate-300 text-slate-700 rounded-lg hover:bg-slate-50 font-medium text-sm transition-colors">Batal</button><button type="submit" class="flex-1 px-4 py-2 bg-teal-600 text-white rounded-lg hover:bg-teal-700 font-medium text-sm transition-colors shadow-md shadow-teal-200">Simpan</button></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -434,6 +278,82 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
let layer24Jam, layerTerbatas;
|
||||
let isLeftPanelOpen = true;
|
||||
let isRightPanelOpen = true;
|
||||
let choroplethLayer = L.layerGroup();
|
||||
let choroplethGeoJsonLayer = null;
|
||||
|
||||
function pointInPolygon(lng, lat, polygonCoords) {
|
||||
if (lng == null || lat == null) return false;
|
||||
let inside = false;
|
||||
for (let i = 0, j = polygonCoords.length - 1; i < polygonCoords.length; j = i++) {
|
||||
const xi = polygonCoords[i][0], yi = polygonCoords[i][1];
|
||||
const xj = polygonCoords[j][0], yj = polygonCoords[j][1];
|
||||
const intersect = ((yi > lat) !== (yj > lat)) && (lng < (xj - xi) * (lat - yi) / (yj - yi) + xi);
|
||||
if (intersect) inside = !inside;
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
function getChoroplethColor(jumlah) {
|
||||
return jumlah > 8 ? '#4a1486' :
|
||||
jumlah > 5 ? '#6a51a3' :
|
||||
jumlah > 2 ? '#9e9ac8' :
|
||||
jumlah > 0 ? '#cbc9e2' :
|
||||
'#f2f0f7';
|
||||
}
|
||||
|
||||
async function loadChoropleth() {
|
||||
try {
|
||||
const response = await fetch('./json/batas.geojson');
|
||||
const geoJsonData = await response.json();
|
||||
if (choroplethGeoJsonLayer) {
|
||||
choroplethLayer.removeLayer(choroplethGeoJsonLayer);
|
||||
}
|
||||
choroplethGeoJsonLayer = L.geoJSON(geoJsonData, {
|
||||
style: function(feature) {
|
||||
const coords = feature.geometry.type === 'Polygon' ? feature.geometry.coordinates[0] : feature.geometry.coordinates[0][0];
|
||||
const count = spbuData.filter(spbu => {
|
||||
const lat = spbu.latitude || spbu.lat;
|
||||
const lng = spbu.longitude || spbu.lng;
|
||||
return pointInPolygon(lng, lat, coords);
|
||||
}).length;
|
||||
return {
|
||||
fillColor: getChoroplethColor(count),
|
||||
weight: 1.5,
|
||||
opacity: 1,
|
||||
color: '#666',
|
||||
fillOpacity: 0.6
|
||||
};
|
||||
},
|
||||
onEachFeature: function(feature, layer) {
|
||||
const coords = feature.geometry.type === 'Polygon' ? feature.geometry.coordinates[0] : feature.geometry.coordinates[0][0];
|
||||
const count = spbuData.filter(spbu => {
|
||||
const lat = spbu.latitude || spbu.lat;
|
||||
const lng = spbu.longitude || spbu.lng;
|
||||
return pointInPolygon(lng, lat, coords);
|
||||
}).length;
|
||||
layer.bindTooltip(`<strong>${feature.properties.name}</strong><br>Jumlah SPBU: ${count}`, { sticky: true });
|
||||
layer.on('mouseover', function(e) {
|
||||
layer.setStyle({ weight: 3, fillOpacity: 0.85, color: '#000' });
|
||||
layer.bringToFront();
|
||||
});
|
||||
layer.on('mouseout', function(e) {
|
||||
layer.setStyle({ weight: 1.5, fillOpacity: 0.6, color: '#666' });
|
||||
});
|
||||
layer.on('click', function(e) {
|
||||
map.fitBounds(layer.getBounds());
|
||||
});
|
||||
}
|
||||
});
|
||||
choroplethLayer.addLayer(choroplethGeoJsonLayer);
|
||||
if (document.getElementById('toggleChoropleth').classList.contains('active')) {
|
||||
choroplethLayer.addTo(map);
|
||||
}
|
||||
document.getElementById('countChoropleth').textContent = geoJsonData.features.length + ' kecamatan';
|
||||
} catch (error) {
|
||||
console.error('Gagal memuat choropleth:', error);
|
||||
document.getElementById('countChoropleth').textContent = 'gagal';
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchSpbuData() {
|
||||
try {
|
||||
@@ -594,13 +514,13 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
renderList();
|
||||
updateStats();
|
||||
updateLayerCounts();
|
||||
loadChoropleth();
|
||||
}
|
||||
|
||||
function toggleLeftPanel() {
|
||||
isLeftPanelOpen = !isLeftPanelOpen;
|
||||
const sidebar = document.getElementById('sidebarLeft');
|
||||
const icon = document.getElementById('handleLeftIcon');
|
||||
|
||||
if (isLeftPanelOpen) {
|
||||
sidebar.classList.remove('collapsed');
|
||||
icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />';
|
||||
@@ -616,7 +536,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
isRightPanelOpen = !isRightPanelOpen;
|
||||
const sidebar = document.getElementById('sidebarRight');
|
||||
const icon = document.getElementById('handleRightIcon');
|
||||
|
||||
if (isRightPanelOpen) {
|
||||
sidebar.classList.remove('collapsed');
|
||||
icon.innerHTML = '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />';
|
||||
@@ -630,7 +549,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
|
||||
function initMap() {
|
||||
map = L.map('map', { zoomControl: true }).setView([-0.0263, 109.3425], 13);
|
||||
|
||||
baseMaps = {
|
||||
light: L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OSM</a> © <a href="https://carto.com/">CARTO</a>',
|
||||
@@ -651,41 +569,34 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
maxZoom: 19
|
||||
})
|
||||
};
|
||||
|
||||
baseMaps.light.addTo(map);
|
||||
|
||||
layer24Jam = L.layerGroup();
|
||||
layerTerbatas = L.layerGroup();
|
||||
|
||||
map.on('click', function(e) {
|
||||
if (isSelectingLocation && isAdminMode) {
|
||||
selectLocation(e.latlng);
|
||||
}
|
||||
});
|
||||
|
||||
refreshData().then(() => {
|
||||
renderAuthContainer();
|
||||
updateAdminUI();
|
||||
updateLayerCounts();
|
||||
loadChoropleth();
|
||||
});
|
||||
}
|
||||
|
||||
function switchBaseMap(type) {
|
||||
map.removeLayer(baseMaps[currentBaseMap]);
|
||||
baseMaps[type].addTo(map);
|
||||
|
||||
document.querySelectorAll('#sidebarRight .layer-card').forEach(card => card.classList.remove('active'));
|
||||
document.getElementById(`layer${type.charAt(0).toUpperCase() + type.slice(1)}`).classList.add('active');
|
||||
|
||||
currentBaseMap = type;
|
||||
}
|
||||
|
||||
function toggleLayer(type, event) {
|
||||
event.stopPropagation();
|
||||
|
||||
const toggle = document.getElementById(`toggle${type === '24jam' ? '24Jam' : 'Terbatas'}`);
|
||||
const card = document.getElementById(`layer${type === '24jam' ? '24Jam' : 'Terbatas'}Card`);
|
||||
|
||||
if (type === '24jam') {
|
||||
if (map.hasLayer(layer24Jam)) {
|
||||
map.removeLayer(layer24Jam);
|
||||
@@ -709,6 +620,21 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
}
|
||||
}
|
||||
|
||||
function toggleChoropleth(event) {
|
||||
event.stopPropagation();
|
||||
const toggle = document.getElementById('toggleChoropleth');
|
||||
const card = document.getElementById('layerChoroplethCard');
|
||||
if (map.hasLayer(choroplethLayer)) {
|
||||
map.removeLayer(choroplethLayer);
|
||||
toggle.classList.remove('active');
|
||||
card.classList.remove('active');
|
||||
} else {
|
||||
choroplethLayer.addTo(map);
|
||||
toggle.classList.add('active');
|
||||
card.classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
function getMarkerIcon(status) {
|
||||
const color = status === '24jam' ? '#10b981' : '#f59e0b';
|
||||
return L.divIcon({
|
||||
@@ -727,33 +653,28 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
function refreshLayers() {
|
||||
layer24Jam.clearLayers();
|
||||
layerTerbatas.clearLayers();
|
||||
|
||||
spbuData.forEach(spbu => {
|
||||
const lat = spbu.latitude || spbu.lat;
|
||||
const lng = spbu.longitude || spbu.lng;
|
||||
|
||||
const marker = L.marker([lat, lng], {
|
||||
icon: getMarkerIcon(spbu.status),
|
||||
draggable: isAdminMode
|
||||
});
|
||||
|
||||
marker.on('dragend', function(e) {
|
||||
const newPos = e.target.getLatLng();
|
||||
updatePosition(spbu.id, newPos.lat, newPos.lng);
|
||||
spbu.latitude = newPos.lat;
|
||||
spbu.longitude = newPos.lng;
|
||||
marker.setPopupContent(createPopupContent(spbu));
|
||||
loadChoropleth();
|
||||
});
|
||||
|
||||
marker.bindPopup(createPopupContent(spbu), { maxWidth: 300 });
|
||||
|
||||
if (spbu.status === '24jam') {
|
||||
layer24Jam.addLayer(marker);
|
||||
} else {
|
||||
layerTerbatas.addLayer(marker);
|
||||
}
|
||||
});
|
||||
|
||||
if (document.getElementById('toggle24Jam') && document.getElementById('toggle24Jam').classList.contains('active')) {
|
||||
layer24Jam.addTo(map);
|
||||
}
|
||||
@@ -767,7 +688,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
const no = spbu.no_spbu || spbu.no || '';
|
||||
const lat = spbu.latitude || spbu.lat || 0;
|
||||
const lng = spbu.longitude || spbu.lng || 0;
|
||||
|
||||
return `
|
||||
<div class="min-w-[200px]">
|
||||
<div class="flex items-start justify-between mb-2">
|
||||
@@ -800,7 +720,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
function selectLocation(latlng) {
|
||||
selectedLatLng = latlng;
|
||||
removeTempMarker();
|
||||
|
||||
tempMarker = L.marker([latlng.lat, latlng.lng], {
|
||||
icon: L.divIcon({
|
||||
className: 'custom-temp-icon',
|
||||
@@ -813,7 +732,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
iconAnchor: [16, 16]
|
||||
})
|
||||
}).addTo(map);
|
||||
|
||||
openModalForNewLocation(latlng);
|
||||
}
|
||||
|
||||
@@ -828,13 +746,11 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
const modal = document.getElementById('modalOverlay');
|
||||
const title = document.getElementById('modalTitle');
|
||||
const form = document.getElementById('spbuForm');
|
||||
|
||||
form.reset();
|
||||
document.getElementById('spbuId').value = '';
|
||||
title.textContent = 'Tambah SPBU Baru';
|
||||
document.getElementById('inputLat').value = latlng.lat.toFixed(7);
|
||||
document.getElementById('inputLng').value = latlng.lng.toFixed(7);
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
}
|
||||
|
||||
@@ -844,7 +760,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
(spbu.nama && spbu.nama.toLowerCase().includes(searchQuery.toLowerCase())) ||
|
||||
((spbu.no_spbu || spbu.no) && (spbu.no_spbu || spbu.no).toLowerCase().includes(searchQuery.toLowerCase()))
|
||||
);
|
||||
|
||||
if (filteredData.length === 0) {
|
||||
listContainer.innerHTML = `
|
||||
<div class="flex flex-col items-center justify-center py-10 text-slate-400">
|
||||
@@ -855,7 +770,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
listContainer.innerHTML = filteredData.map(spbu => `
|
||||
<div class="bg-white border border-slate-200 rounded-xl p-3 hover:border-teal-400 hover:shadow-md transition-all cursor-pointer group" onclick="zoomToSpbu(${spbu.id})">
|
||||
<div class="flex items-start justify-between mb-1">
|
||||
@@ -915,7 +829,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
const btnAddSpbu = document.getElementById('btnAddSpbu');
|
||||
const mapHint = document.getElementById('mapHint');
|
||||
const mapContainer = document.getElementById('mapContainer');
|
||||
|
||||
if (isAdminMode) {
|
||||
btnAddSpbu.style.display = 'flex';
|
||||
mapHint.style.display = 'block';
|
||||
@@ -928,7 +841,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
removeTempMarker();
|
||||
document.getElementById('modeIndicator').classList.add('hidden');
|
||||
}
|
||||
|
||||
refreshLayers();
|
||||
renderList();
|
||||
updateStats();
|
||||
@@ -941,7 +853,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
const lat = spbu.latitude || spbu.lat;
|
||||
const lng = spbu.longitude || spbu.lng;
|
||||
map.flyTo([lat, lng], 16, { duration: 1.5 });
|
||||
|
||||
setTimeout(() => {
|
||||
[layer24Jam, layerTerbatas].forEach(layer => {
|
||||
layer.eachLayer(marker => {
|
||||
@@ -961,7 +872,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
const modal = document.getElementById('modalOverlay');
|
||||
const title = document.getElementById('modalTitle');
|
||||
const form = document.getElementById('spbuForm');
|
||||
|
||||
form.reset();
|
||||
document.getElementById('spbuId').value = spbu.id;
|
||||
title.textContent = 'Edit Data SPBU';
|
||||
@@ -970,7 +880,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
document.getElementById('inputStatus').value = spbu.status;
|
||||
document.getElementById('inputLat').value = spbu.latitude || spbu.lat;
|
||||
document.getElementById('inputLng').value = spbu.longitude || spbu.lng;
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
@@ -989,19 +898,15 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
notification.className = 'fixed bottom-4 left-1/2 -translate-x-1/2 bg-teal-600 text-white px-4 py-2 rounded-lg shadow-lg z-[9999] text-sm font-medium fade-in';
|
||||
notification.textContent = message;
|
||||
document.body.appendChild(notification);
|
||||
setTimeout(() => {
|
||||
notification.remove();
|
||||
}, 3000);
|
||||
setTimeout(() => { notification.remove(); }, 3000);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initMap();
|
||||
|
||||
document.getElementById('searchInput').addEventListener('input', (e) => {
|
||||
searchQuery = e.target.value;
|
||||
renderList();
|
||||
});
|
||||
|
||||
document.getElementById('authContainer').addEventListener('click', (e) => {
|
||||
if (e.target.closest('#btnShowLogin')) {
|
||||
document.getElementById('loginOverlay').classList.remove('hidden');
|
||||
@@ -1013,7 +918,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
logout();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('loginForm').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const username = document.getElementById('loginUsername').value;
|
||||
@@ -1028,7 +932,6 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
document.getElementById('loginOverlay').classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('btnAddSpbu').addEventListener('click', () => {
|
||||
if (isAdminMode) {
|
||||
isSelectingLocation = true;
|
||||
@@ -1036,38 +939,31 @@ $isAdmin = isset($_SESSION['is_admin']) && $_SESSION['is_admin'] === true;
|
||||
showNotification('Silakan klik pada peta untuk memilih lokasi SPBU');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('btnCloseModal').addEventListener('click', closeModal);
|
||||
document.getElementById('btnCancelModal').addEventListener('click', closeModal);
|
||||
document.getElementById('modalOverlay').addEventListener('click', (e) => {
|
||||
if (e.target === document.getElementById('modalOverlay')) closeModal();
|
||||
});
|
||||
|
||||
document.getElementById('spbuForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
if (!isAdminMode) return;
|
||||
|
||||
const id = document.getElementById('spbuId').value;
|
||||
const nama = document.getElementById('inputNama').value;
|
||||
const no_spbu = document.getElementById('inputNo').value;
|
||||
const status = document.getElementById('inputStatus').value;
|
||||
const latitude = parseFloat(document.getElementById('inputLat').value);
|
||||
const longitude = parseFloat(document.getElementById('inputLng').value);
|
||||
|
||||
const data = { nama, no_spbu, status, latitude, longitude };
|
||||
|
||||
if (id) {
|
||||
data.id = parseInt(id);
|
||||
await updateSpbu(data);
|
||||
} else {
|
||||
await addSpbu(data);
|
||||
}
|
||||
|
||||
closeModal();
|
||||
isSelectingLocation = false;
|
||||
removeTempMarker();
|
||||
document.getElementById('modeIndicator').classList.add('hidden');
|
||||
|
||||
map.flyTo([latitude, longitude], 16, { duration: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user