fix all bug

This commit is contained in:
naukyy
2026-06-13 02:10:51 +07:00
parent d9cff90874
commit d18baa80e0
19 changed files with 818 additions and 149 deletions
+36
View File
@@ -299,6 +299,42 @@ body::before {
}
.leaflet-control-zoom a:hover { background: var(--primary-deep) !important; color: white !important; }
/* Custom Leaflet Layer Control style to match theme */
.leaflet-control-layers {
background: var(--bg-glass) !important;
backdrop-filter: blur(24px) !important;
-webkit-backdrop-filter: blur(24px) !important;
border: 1px solid var(--border-glass) !important;
border-radius: 14px !important;
box-shadow: var(--shadow) !important;
color: var(--text-main) !important;
font-family: var(--font) !important;
padding: 10px 14px !important;
transition: var(--transition);
}
.leaflet-control-layers-expanded {
min-width: 140px;
}
.leaflet-control-layers label {
margin-bottom: 6px !important;
font-size: 0.85rem !important;
cursor: pointer !important;
display: flex !important;
align-items: center !important;
gap: 8px !important;
color: var(--text-main) !important;
font-weight: 500;
}
.leaflet-control-layers label:last-child {
margin-bottom: 0 !important;
}
.leaflet-control-layers input[type="checkbox"] {
cursor: pointer !important;
width: 15px !important;
height: 15px !important;
accent-color: var(--primary-deep) !important;
}
.leaflet-popup-content-wrapper {
background: var(--bg-glass) !important;
backdrop-filter: blur(16px) !important;
+52 -1
View File
@@ -10,6 +10,38 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<link rel="stylesheet" href="css/main.css">
<script>
// Global error interceptor to assist in visual debugging
window.onerror = function(message, source, lineno, colno, error) {
const errorMsg = `JS Error: ${message} (at ${source ? source.split('/').pop() : 'unknown'}:${lineno}:${colno})`;
console.error(errorMsg, error);
const showInterval = setInterval(() => {
const toastContainer = document.getElementById('toast-container');
if (toastContainer) {
clearInterval(showInterval);
const t = document.createElement('div');
t.className = 'toast error';
t.innerHTML = errorMsg;
toastContainer.appendChild(t);
}
}, 100);
return false;
};
window.onunhandledrejection = function(event) {
const errorMsg = `Promise Error: ${event.reason?.message || event.reason}`;
console.error(errorMsg, event.reason);
const showInterval = setInterval(() => {
const toastContainer = document.getElementById('toast-container');
if (toastContainer) {
clearInterval(showInterval);
const t = document.createElement('div');
t.className = 'toast error';
t.innerHTML = errorMsg;
toastContainer.appendChild(t);
}
}, 100);
};
</script>
</head>
<body>
@@ -38,6 +70,25 @@
<p>Sistem Informasi Geografis — CRUD spasial titik, garis, dan area.</p>
</div>
<!-- Layer Peta (Centang) -->
<div class="menu-group">
<div class="menu-title">Layer Peta</div>
<div class="form-panel" style="gap: 10px;">
<label class="checkbox-group">
<input type="checkbox" id="layer-spbu" checked>
<span>Stasiun SPBU</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-jalan" checked>
<span>Jalur Jalan</span>
</label>
<label class="checkbox-group">
<input type="checkbox" id="layer-kavling" checked>
<span>Kavling Tanah</span>
</label>
</div>
</div>
<!-- Spatial tools -->
<div class="menu-group">
<div class="menu-title">Alat Spasial</div>
@@ -85,7 +136,7 @@
icon.className = t === 'dark' ? 'fas fa-sun' : 'fas fa-moon';
}
</script>
<script type="module" src="js/app.js"></script>
<script type="module" src="js/app.js?v=20260613-9"></script>
</body>
</html>
+109 -16
View File
@@ -6,6 +6,13 @@ import { spbuService, jalanService, kavlingService } from './services/api.servic
let appMap;
let drawControl;
// Global layer object tracker
const mapLayers = {
spbu: null,
jalan: null,
kavling: null
};
// Custom SVG Icons Generator
export const createIcon = (svgPath, color) => {
return L.divIcon({
@@ -29,30 +36,96 @@ window.showToast = (msg, type='success') => {
setTimeout(() => { t.style.transform='translateX(100%)'; t.style.opacity=0; setTimeout(()=>t.remove(),300); }, 3000);
};
document.addEventListener('DOMContentLoaded', async () => {
appMap = initMap('map');
drawControl = setupDrawControls(appMap, handleGeometryCreated);
await loadAllData();
});
const setupCheckboxListeners = () => {
const layerConfigs = [
{ id: 'layer-spbu', key: 'spbu' },
{ id: 'layer-jalan', key: 'jalan' },
{ id: 'layer-kavling', key: 'kavling' }
];
const loadAllData = async () => {
layerConfigs.forEach(({ id, key }) => {
const checkbox = document.getElementById(id);
if (checkbox) {
checkbox.addEventListener('change', (e) => {
const layer = mapLayers[key];
if (layer) {
if (e.target.checked) {
if (!appMap.hasLayer(layer)) {
appMap.addLayer(layer);
}
} else {
if (appMap.hasLayer(layer)) {
appMap.removeLayer(layer);
}
}
}
});
}
});
};
const loadSPBUData = async () => {
try {
const spbu = await spbuService.getAll();
L.geoJSON(spbu, {
mapLayers.spbu = L.geoJSON(spbu, {
pointToLayer: (f, latlng) => L.marker(latlng, { icon: iconSPBU(f.properties.buka_24_jam) }),
onEachFeature: (f, l) => bindPopup(l, 'spbu', f.properties)
}).addTo(appMap);
const jalan = await jalanService.getAll();
L.geoJSON(jalan, { style: { color: '#F59E0B', weight: 4 }, onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties) }).addTo(appMap);
const kavling = await kavlingService.getAll();
L.geoJSON(kavling, { style: { color: '#3B82F6', weight: 2, fillColor: '#3B82F6', fillOpacity: 0.3 }, onEachFeature: (f, l) => bindPopup(l, 'kavling', f.properties) }).addTo(appMap);
});
const checkbox = document.getElementById('layer-spbu');
if (checkbox && checkbox.checked) {
mapLayers.spbu.addTo(appMap);
}
} catch (e) {
window.showToast("Gagal meload data: "+e.message, 'error');
console.error("Gagal meload data SPBU:", e);
window.showToast("Gagal meload data SPBU: " + e.message, 'error');
}
};
const loadJalanData = async () => {
try {
const jalan = await jalanService.getAll();
mapLayers.jalan = L.geoJSON(jalan, {
style: { color: '#F59E0B', weight: 4 },
onEachFeature: (f, l) => bindPopup(l, 'jalan', f.properties)
});
const checkbox = document.getElementById('layer-jalan');
if (checkbox && checkbox.checked) {
mapLayers.jalan.addTo(appMap);
}
} catch (e) {
console.error("Gagal meload data Jalan:", e);
window.showToast("Gagal meload data Jalan: " + e.message, 'error');
}
};
const loadKavlingData = async () => {
try {
const kavling = await kavlingService.getAll();
mapLayers.kavling = L.geoJSON(kavling, {
style: { color: '#3B82F6', weight: 2, fillColor: '#3B82F6', fillOpacity: 0.3 },
onEachFeature: (f, l) => bindPopup(l, 'kavling', f.properties)
});
const checkbox = document.getElementById('layer-kavling');
if (checkbox && checkbox.checked) {
mapLayers.kavling.addTo(appMap);
}
} catch (e) {
console.error("Gagal meload data Kavling:", e);
window.showToast("Gagal meload data Kavling: " + e.message, 'error');
}
};
const loadAllData = async () => {
await Promise.allSettled([
loadSPBUData(),
loadJalanData(),
loadKavlingData()
]);
};
const bindPopup = (layer, type, props) => {
const ext = props.buka_24_jam !== undefined ? `<p>Buka 24 Jam: <strong style="color:${props.buka_24_jam?'#10B981':'#EF4444'}">${props.buka_24_jam ? 'Ya' : 'Tidak'}</strong></p>` : '';
layer.bindPopup(`
@@ -82,7 +155,14 @@ const handleGeometryCreated = (type, geometry, layer) => {
try {
if(type==='spbu') await spbuService.create(payload);
if(type==='jalan') await jalanService.create(payload);
if(type==='kavling') await kavlingService.create(payload);
if(type==='kavling') {
const kavlingPayload = {
nama_pemilik: payload.nama,
luas: payload.luas || 0,
geometry: payload.geometry
};
await kavlingService.create(kavlingPayload);
}
window.showToast('Berhasil disimpan');
setTimeout(()=>location.reload(), 800);
} catch(e) { window.showToast('Gagal simpan', 'error'); }
@@ -90,3 +170,16 @@ const handleGeometryCreated = (type, geometry, layer) => {
appMap.removeLayer(tempLayer);
});
};
const init = async () => {
appMap = initMap('map');
setupCheckboxListeners();
drawControl = setupDrawControls(appMap, handleGeometryCreated);
await loadAllData();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
+18 -8
View File
@@ -2,14 +2,23 @@ export const renderForm = (type, geometry, onSubmit, onCancel) => {
const container = document.getElementById('form-container');
container.style.display = 'flex';
const extraFields = type === 'spbu' ? `
<div class="form-group">
<label class="checkbox-group">
<input type="checkbox" id="input-24jam">
<span>Buka 24 Jam</span>
</label>
</div>
` : '';
let extraFields = '';
if (type === 'spbu') {
extraFields = `
<div class="form-group">
<label class="checkbox-group">
<input type="checkbox" id="input-24jam">
<span>Buka 24 Jam</span>
</label>
</div>
`;
} else if (type === 'kavling') {
extraFields = `
<div class="form-group">
<input type="number" id="input-luas" class="form-control" placeholder="Luas (m²)" required min="1">
</div>
`;
}
container.innerHTML = `
<div class="form-panel">
@@ -36,6 +45,7 @@ export const renderForm = (type, geometry, onSubmit, onCancel) => {
deskripsi: document.getElementById('input-deskripsi').value,
};
if (type === 'spbu') payload.buka_24_jam = document.getElementById('input-24jam').checked;
if (type === 'kavling') payload.luas = document.getElementById('input-luas').value;
onSubmit(payload);
container.style.display = 'none';