fix(map): add generation token to hard-cancel in-flight marker draws on banner close

This commit is contained in:
2026-03-04 11:49:52 -05:00
parent abba5389f9
commit 6c197ba1f8

View File

@ -47,6 +47,8 @@ const routePhase = ref<'idle' | 'eta' | 'navigating'>('idle');
const promoMarkers = shallowRef<any[]>([]); const promoMarkers = shallowRef<any[]>([]);
const userMarker = shallowRef<any>(null); const userMarker = shallowRef<any>(null);
const isUpdatingMarkers = ref(false); const isUpdatingMarkers = ref(false);
// Cancellation token: increment to invalidate any in-flight marker draw
const markerGenerationId = ref(0);
const unitMarkers = shallowRef<Map<string, any>>(new Map()); const unitMarkers = shallowRef<Map<string, any>>(new Map());
const unitFetchInterval = ref<any>(null); const unitFetchInterval = ref<any>(null);
const userCoords = ref<{ lat: number; lng: number } | null>(null); const userCoords = ref<{ lat: number; lng: number } | null>(null);
@ -99,7 +101,10 @@ function closeUberSearch() {
async function animateAndReload() { async function animateAndReload() {
isBannerClosing.value = true; isBannerClosing.value = true;
// 🔥 CRÍTICO // 🔥 CRÍTICO: Invalidar cualquier dibujado de markers en vuelo
markerGenerationId.value++;
isUpdatingMarkers.value = false; // liberar el lock para que no quede bloqueado
routeStore.setWasSelectedFromMap(false); routeStore.setWasSelectedFromMap(false);
clearMapMarkers(); clearMapMarkers();
@ -111,8 +116,11 @@ async function animateAndReload() {
showETACard.value = false; showETACard.value = false;
routePhase.value = 'idle'; routePhase.value = 'idle';
// No es necesario recargar TODO el objeto del mapa, consume cuota innecesariamente. // Limpieza extra garantizada después de un tick, por si algún await en vuelo
// Limpiamos y reseteamos el estado visual // terminó justo antes e intentó redibujar markers
await nextTick();
clearMapMarkers();
if (map.value) { if (map.value) {
setCenter(mapStore.center.lat, mapStore.center.lng); setCenter(mapStore.center.lat, mapStore.center.lng);
setZoom(mapStore.zoom); setZoom(mapStore.zoom);
@ -293,33 +301,48 @@ async function updateMapMarkers(skipZoom = false) {
return; return;
} }
// Capturar el token de generación ANTES de cualquier await
const myGeneration = markerGenerationId.value;
isUpdatingMarkers.value = true; isUpdatingMarkers.value = true;
try { try {
const selectedRouteObj = routeStore.allRoutes.find(r => r.id === currentRequestRouteId) || { id: currentRequestRouteId, short_name: currentRequestRouteId }; const selectedRouteObj = routeStore.allRoutes.find(r => r.id === currentRequestRouteId) || { id: currentRequestRouteId, short_name: currentRequestRouteId };
// ── PASO ATÓMICO: Procesar con carga paralela de GPS y Paradas ── // Guard de generación: si se canceló mientras esperábamos, abortar
// Pasamos [] a paradasExistentes para forzar que procesarSeleccionDeRuta maneje el Promise.all if (markerGenerationId.value !== myGeneration) return;
await procesarSeleccionDeRuta( await procesarSeleccionDeRuta(
selectedRouteObj, selectedRouteObj,
routeStore.selectedRouteStops, // El composable decidirá si necesita recargar en paralelo routeStore.selectedRouteStops,
map.value, map.value,
addCleanMarker, addCleanMarker,
skipZoom, skipZoom,
(stop: BusStop) => { (stop: BusStop) => {
paradaCercana.value = stop; // Solo actualizar si aún somos la generación vigente
showETACard.value = true; if (markerGenerationId.value === myGeneration) {
paradaCercana.value = stop;
showETACard.value = true;
}
} }
); );
reDrawUserMarker();
if (routeStore.selectedRouteId !== currentRequestRouteId) return; // Guard final: verificar que no se canceló durante el await largo
if (markerGenerationId.value !== myGeneration || routeStore.selectedRouteId !== currentRequestRouteId) {
clearMapMarkers();
return;
}
reDrawUserMarker();
if (routeStore.wasSelectedFromMap && !skipZoom) { if (routeStore.wasSelectedFromMap && !skipZoom) {
await highlightOptimalStopForRoute(); await highlightOptimalStopForRoute();
} }
} finally { } finally {
isUpdatingMarkers.value = false; // Solo liberar el lock si somos la generación actual
if (markerGenerationId.value === myGeneration) {
isUpdatingMarkers.value = false;
}
} }
} }