fix(map): add generation token to hard-cancel in-flight marker draws on banner close
This commit is contained in:
@ -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,35 +301,50 @@ 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) => {
|
||||||
|
// Solo actualizar si aún somos la generación vigente
|
||||||
|
if (markerGenerationId.value === myGeneration) {
|
||||||
paradaCercana.value = stop;
|
paradaCercana.value = stop;
|
||||||
showETACard.value = true;
|
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 {
|
||||||
|
// Solo liberar el lock si somos la generación actual
|
||||||
|
if (markerGenerationId.value === myGeneration) {
|
||||||
isUpdatingMarkers.value = false;
|
isUpdatingMarkers.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function updatePromoMarkers() {
|
async function updatePromoMarkers() {
|
||||||
if (!isLoaded.value) return;
|
if (!isLoaded.value) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user