From 91ef07b3ed69a3fba27d600fa44c31e139348ba7 Mon Sep 17 00:00:00 2001 From: Hanzo_dev <2002samudiojohan@gmail.com> Date: Sat, 28 Feb 2026 22:38:59 -0500 Subject: [PATCH] Fix: map singleton state, schedules view sync, and carousel image error handling --- frontend/src/composables/useMapState.ts | 29 ++++++++++--------------- frontend/src/views/MapView.vue | 24 ++++++++++++++------ frontend/src/views/SchedulesView.vue | 2 ++ 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/frontend/src/composables/useMapState.ts b/frontend/src/composables/useMapState.ts index 45926f7..21fb3b1 100644 --- a/frontend/src/composables/useMapState.ts +++ b/frontend/src/composables/useMapState.ts @@ -1,10 +1,11 @@ import { ref } from 'vue' -// Registro global de todo lo que está en el mapa const markers = ref([]) const polylines = ref([]) const infoWindows = ref([]) const circles = ref([]) +// Callback para sincronización externa (ej. useGoogleMaps globalOverlays) +const onLimpiarCallback = ref<(() => void) | null>(null) // Singleton pattern using composable export const useMapState = () => { @@ -14,8 +15,6 @@ export const useMapState = () => { return marker } - - // Registrar una polyline const registrarPolyline = (polyline: google.maps.Polyline) => { if (polyline) polylines.value.push(polyline) @@ -34,9 +33,6 @@ export const useMapState = () => { return infoWindow } - // Callback para sincronización externa (ej. useGoogleMaps globalOverlays) - const onLimpiarCallback = ref<(() => void) | null>(null) - const registrarCallbackLimpieza = (fn: () => void) => { onLimpiarCallback.value = fn } @@ -46,14 +42,15 @@ export const useMapState = () => { console.log(`SIBU | Iniciando limpieza de ${markers.value.length} markers, ${polylines.value.length} polylines...`) // Eliminar markers y overlays HTML - markers.value.forEach(m => { + markers.value.forEach((m: any) => { try { if (m) { if (typeof m.setMap === 'function') m.setMap(null); - if (typeof (m as any).remove === 'function') (m as any).remove(); - if (typeof (m as any).onRemove === 'function') (m as any).onRemove(); - if (google?.maps?.event?.clearInstanceListeners) { - google.maps.event.clearInstanceListeners(m); + if (typeof m.remove === 'function') m.remove(); + if (typeof m.onRemove === 'function') m.onRemove(); + + if (typeof (window as any).google !== 'undefined' && (window as any).google.maps?.event?.clearInstanceListeners) { + (window as any).google.maps.event.clearInstanceListeners(m); } } } catch (e) { @@ -62,10 +59,8 @@ export const useMapState = () => { }) markers.value = [] - - // Eliminar polylines - polylines.value.forEach(p => { + polylines.value.forEach((p: any) => { try { if (p && typeof p.setMap === 'function') p.setMap(null) } catch (e) { @@ -75,7 +70,7 @@ export const useMapState = () => { polylines.value = [] // Cerrar y limpiar infoWindows - infoWindows.value.forEach(iw => { + infoWindows.value.forEach((iw: any) => { try { if (iw && typeof iw.close === 'function') iw.close() } catch (e) { @@ -85,10 +80,10 @@ export const useMapState = () => { infoWindows.value = [] // Eliminar circles - circles.value.forEach(c => { + circles.value.forEach((c: any) => { try { if (c && typeof c.setMap === 'function') c.setMap(null) - if (c && typeof (c as any).remove === 'function') (c as any).remove() + if (c && typeof c.remove === 'function') c.remove() } catch (e) { console.warn('Error limpiando circle', e) } diff --git a/frontend/src/views/MapView.vue b/frontend/src/views/MapView.vue index db15e9a..99d8a75 100644 --- a/frontend/src/views/MapView.vue +++ b/frontend/src/views/MapView.vue @@ -45,7 +45,6 @@ const unitFetchInterval = ref(null); const userCoords = ref<{ lat: number; lng: number } | null>(null); const optimalStopPulse = ref(null); const showRouteDropdown = ref(false); -const routeCardRef = ref(null); const wasSelectedFromMap = ref(false); const isInternalSelection = ref(false); @@ -129,6 +128,13 @@ async function claimPromo() { } } +function handleImageError(event: Event) { + const target = event.target as HTMLImageElement; + if (target) { + target.src = getImageUrl(null, 'coupon'); + } +} + onMounted(async () => { const navbar = document.querySelector('#navbar-admin') ?? document.querySelector('nav') ?? document.querySelector('header'); if (navbar) { @@ -468,6 +474,10 @@ function locateUser(): Promise { if (userMarker.value) { if (typeof userMarker.value.setMap === 'function') { userMarker.value.setMap(null); + // Clear listeners for the old marker + if (typeof (window as any).google !== 'undefined' && (window as any).google.maps?.event?.clearInstanceListeners) { + (window as any).google.maps.event.clearInstanceListeners(userMarker.value); + } } } @@ -525,6 +535,10 @@ async function highlightOptimalStopForRoute() { // Añadir el PULSO NARANJA if (optimalStopPulse.value && typeof optimalStopPulse.value.setMap === 'function') { optimalStopPulse.value.setMap(null); + // Clear listeners for the old pulse marker + if (typeof (window as any).google !== 'undefined' && (window as any).google.maps?.event?.clearInstanceListeners) { + (window as any).google.maps.event.clearInstanceListeners(optimalStopPulse.value); + } } optimalStopPulse.value = addHtmlMarker( @@ -548,10 +562,6 @@ async function highlightOptimalStopForRoute() { } } - - -// walking route functions removed -