fix all bug
This commit is contained in:
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user