refactor(map): fix race conditions and async issues with atomic GPS/Data fetch

This commit is contained in:
2026-03-02 19:22:58 -05:00
parent 4f8096f425
commit 767667b1b6
3 changed files with 61 additions and 37 deletions

View File

@ -27,7 +27,7 @@ export const useFlujoPrincipal = () => {
const procesarSeleccionDeRuta = async (
_ruta: { id: string },
paradas: BusStop[],
paradasExistentes: BusStop[],
map: google.maps.Map | undefined,
addCleanMarker: Function,
skipGuidedZoom = false,
@ -36,16 +36,32 @@ export const useFlujoPrincipal = () => {
if (!map) return
try {
// ── PASO 1: Limpiar todo lo que había antes ──────────
limpiarMapa()
// ── PASO 1: Inicio Atómico ──
cargando.value = true
limpiarMapa()
const routeStore = useRouteStore()
// ── PASO 2: Obtener ubicación ──
// ── PASO 2: Sincronización (Promise.all) ──
// Disparamos Supabase (paradas) y GPS al mismo tiempo
console.log('SIBU | Iniciando carga síncrona de Datos + GPS...');
const [ubicacionRes, paradasRes] = await Promise.allSettled([
obtenerUbicacion(),
paradasExistentes.length > 0 ? Promise.resolve(paradasExistentes) : routeStore.loadRouteStops(_ruta.id)
]);
// ── PASO 3: Asignación Segura ──
let ubicacion: { lat: number, lng: number } | null = null;
try {
ubicacion = await obtenerUbicacion();
} catch (err) {
console.warn('SIBU | No se pudo obtener ubicación', err);
if (ubicacionRes.status === 'fulfilled') {
ubicacion = ubicacionRes.value;
} else {
console.warn('SIBU | GPS falló o fue denegado');
}
let paradas: BusStop[] = [];
if (paradasRes.status === 'fulfilled') {
// Si loadRouteStops no devolviera los datos directamente, los tomamos del store
paradas = paradasRes.value || routeStore.selectedRouteStops;
}
const paradasFormateadas = paradas.map((p, i) => ({
@ -56,17 +72,24 @@ export const useFlujoPrincipal = () => {
orden: i
}));
if (paradasFormateadas.length < 2) return;
if (!ubicacion) {
await trazarRuta(paradasFormateadas, map, false);
if (paradasFormateadas.length < 2) {
console.warn('SIBU | No hay suficientes paradas para trazar ruta');
return;
}
// ── PASO 3: Dibujar ruta completa (fondo, gris tenue) ─
// Si no detectamos GPS, trazamos la ruta completa sin zoom guiado
if (!ubicacion) {
await trazarRuta(paradasFormateadas, map, false);
const bounds = new google.maps.LatLngBounds()
paradasFormateadas.forEach(p => bounds.extend(new google.maps.LatLng(p.latitud, p.longitud)))
map.fitBounds(bounds, { top: 100, bottom: 100, left: 60, right: 60 })
return;
}
// ── PASO 4: Dibujar y Renderizar ──
// Dibujar ruta completa (fondo)
await trazarRuta(paradasFormateadas, map, true);
// ── PASO 4: Calcular parada más cercana (Omitir si skipGuidedZoom) ───────────────
if (skipGuidedZoom) {
const bounds = new google.maps.LatLngBounds()
paradasFormateadas.forEach(p => bounds.extend(new google.maps.LatLng(p.latitud, p.longitud)))
@ -78,10 +101,7 @@ export const useFlujoPrincipal = () => {
const paradaCercanaFound = paradaCercana.value
if (!paradaCercanaFound) return;
const routeStore = useRouteStore()
if (routeStore.selectedRouteId !== _ruta.id) return;
// ── PASO 5: Dibujar tramo relevante (Amarillo Vivo) ───────
// Dibujar tramo relevante
const idx = paradasFormateadas.findIndex(p => {
const samePos = Math.abs(p.longitud - paradaCercanaFound.longitude) < 0.0001 &&
Math.abs(p.latitud - paradaCercanaFound.latitude) < 0.0001;
@ -95,7 +115,7 @@ export const useFlujoPrincipal = () => {
}
}
// ── PASO 6: Dibujar marcadores de todas las paradas ──────────
// Renderizado Condicional de Marcadores
paradasFormateadas.forEach((p, i) => {
const esCercana = i === idx;
const esPasada = idx !== -1 && i < idx;
@ -112,13 +132,13 @@ export const useFlujoPrincipal = () => {
);
});
// ── PASO 7: Zoom centrado en usuario + parada cercana ─
hacerZoomAlTramoRelevante(ubicacion, paradaCercanaFound, map)
} catch (error) {
console.error('SIBU | Error procesando ruta:', error)
errorMsg.value = 'No se pudo cargar la ruta'
} finally {
// Apagar estado de carga
cargando.value = false
}
}