fix: Map tab initialization (H1, H2)
- Added global let map/heatLayer/heatVisible declarations - Leaflet map initializes on first visit to Map tab (OSM tiles) - Implemented loadAssetPins() - fetches assets with coords from API, creates Leaflet markers with popups, auto-fits bounds - Guard toggleHeatmap() with proper declared globals - Closes #31 H1, #32 H2 Also confirmed M1 (empty asset list) is not a bug: API returns [] because DB has no assets yet. Empty state renders correctly.
This commit is contained in:
+53
-3
@@ -1595,10 +1595,22 @@
|
||||
|
||||
// Map tab lifecycle
|
||||
if (tabId === 'tabMap') {
|
||||
if (map) {
|
||||
setTimeout(() => map.invalidateSize(), 150);
|
||||
loadAssetPins(); // Refresh pins on every tab visit
|
||||
if (!map) {
|
||||
const tileUrl = document.querySelector('meta[name="map-tile-url"]')?.content
|
||||
|| 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
|
||||
const tileAttr = document.querySelector('meta[name="map-tile-attribution"]')?.content
|
||||
|| '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>';
|
||||
map = L.map('mapContainer', {
|
||||
center: [39.8283, -98.5795],
|
||||
zoom: 4,
|
||||
zoomControl: true,
|
||||
});
|
||||
L.tileLayer(tileUrl, { attribution: tileAttr, maxZoom: 19 }).addTo(map);
|
||||
// Restore heatmap layer if it was active
|
||||
if (heatVisible) setTimeout(() => loadHeatmapData(), 300);
|
||||
}
|
||||
setTimeout(() => map.invalidateSize(), 150);
|
||||
loadAssetPins(); // Refresh pins on every tab visit
|
||||
startVisitTracking();
|
||||
} else {
|
||||
stopVisitTracking();
|
||||
@@ -1681,6 +1693,9 @@
|
||||
let manualPhotoBlob = null;
|
||||
let manKeysCounter = 0;
|
||||
let settingsCache = {};
|
||||
let map = null;
|
||||
let heatLayer = null;
|
||||
let heatVisible = false;
|
||||
|
||||
// ── Mode Switching ──────────────────────────────────────────────────────
|
||||
function setAddAssetMode(mode) {
|
||||
@@ -3405,6 +3420,41 @@
|
||||
showToast('Import complete: ' + created + ' created, ' + skipped + ' skipped, ' + errors.length + ' errors');
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// MAP PINS
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
async function loadAssetPins() {
|
||||
// Store markers on a namespace so we can clear them
|
||||
if (!window._assetPins) window._assetPins = [];
|
||||
// Clear existing markers
|
||||
window._assetPins.forEach(function(m) { if (map) map.removeLayer(m); });
|
||||
window._assetPins = [];
|
||||
|
||||
try {
|
||||
const assets = await api('/api/assets?limit=1000');
|
||||
assets.forEach(function(a) {
|
||||
if (a.latitude != null && a.longitude != null) {
|
||||
var icon = catIcon(a.category);
|
||||
var popupHtml = '<b>' + esc(a.name) + '</b><br>' + esc(a.machine_id || '') +
|
||||
'<br><button class="btn btn-outline btn-sm" style="margin-top:6px;" ' +
|
||||
'onclick="switchTab(\'tabAssets\');viewAsset(' + a.id + ');">View Details</button>';
|
||||
var marker = L.marker([a.latitude, a.longitude])
|
||||
.addTo(map)
|
||||
.bindPopup(popupHtml);
|
||||
window._assetPins.push(marker);
|
||||
}
|
||||
});
|
||||
// If we have assets with coords, zoom to fit them
|
||||
if (window._assetPins.length > 0) {
|
||||
var group = L.featureGroup(window._assetPins);
|
||||
map.fitBounds(group.getBounds().pad(0.1));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load asset pins:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// HEATMAP
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user