diff --git a/frontend/src/composables/useFlujoPrincipal.ts b/frontend/src/composables/useFlujoPrincipal.ts index 3354a58..646edab 100644 --- a/frontend/src/composables/useFlujoPrincipal.ts +++ b/frontend/src/composables/useFlujoPrincipal.ts @@ -4,7 +4,6 @@ import { useDirectionsRoute } from './useDirectionsRoute' import { useParadaCercana } from './useParadaCercana' import type { BusStop } from '@/types' import { useRouteStore } from '@/stores/route' -import { useGoogleMaps } from './useGoogleMaps' export const useFlujoPrincipal = () => { const { limpiarMapa } = useMapState() @@ -30,6 +29,7 @@ export const useFlujoPrincipal = () => { _ruta: { id: string }, paradas: BusStop[], map: google.maps.Map | undefined, + addCleanMarker: Function, skipGuidedZoom = false ) => { if (!map) return @@ -40,7 +40,6 @@ export const useFlujoPrincipal = () => { cargando.value = true // ── PASO 2: Obtener ubicación ── - // Paradas ya vienen precargadas desde store para evitar doble fetch let ubicacion: { lat: number, lng: number } | null = null; try { ubicacion = await obtenerUbicacion(); @@ -48,7 +47,6 @@ export const useFlujoPrincipal = () => { console.warn('SIBU | No se pudo obtener ubicación', err); } - // Format Paradas for trazarRuta const paradasFormateadas = paradas.map((p, i) => ({ id: typeof p.id === 'string' ? parseInt(p.id) || i : p.id || i, nombre: p.name, @@ -57,11 +55,9 @@ export const useFlujoPrincipal = () => { orden: i })); - // Si no hay paradas o muy pocas, abortar if (paradasFormateadas.length < 2) return; if (!ubicacion) { - // Fallback: solo dibujar la ruta sin parada cercana (o podríamos no hacer zoom guiado) await trazarRuta(paradasFormateadas, map, false); return; } @@ -71,7 +67,6 @@ export const useFlujoPrincipal = () => { // ── PASO 4: Calcular parada más cercana (Omitir si skipGuidedZoom) ─────────────── if (skipGuidedZoom) { - // Si omitimos el zoom guiado, solo hacemos un zoom general a la ruta 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 }) @@ -79,21 +74,13 @@ export const useFlujoPrincipal = () => { } await encontrarParadaCercana(ubicacion, paradas, map) - const paradaCercanaFound = paradaCercana.value - - if (!paradaCercanaFound) { - return; - } + if (!paradaCercanaFound) return; const routeStore = useRouteStore() - if (routeStore.selectedRouteId !== _ruta.id) { - console.log('Abortando flujo: el mapa fue limpiado o cambió de ruta.') - return; - } + if (routeStore.selectedRouteId !== _ruta.id) return; // ── PASO 5: Dibujar tramo relevante (Amarillo Vivo) ─────── - // Usar una comparación más robusta que incluya proximidad o nombre const idx = paradasFormateadas.findIndex(p => { const samePos = Math.abs(p.longitud - paradaCercanaFound.longitude) < 0.0001 && Math.abs(p.latitud - paradaCercanaFound.latitude) < 0.0001; @@ -107,8 +94,7 @@ export const useFlujoPrincipal = () => { } } - // ── PASO 6: Dibujar marcadores de todas las paradas (Restaurado) ────────── - const { addCleanMarker } = useGoogleMaps() + // ── PASO 6: Dibujar marcadores de todas las paradas ────────── paradasFormateadas.forEach((p, i) => { const esCercana = i === idx; const esPasada = idx !== -1 && i < idx; @@ -123,10 +109,7 @@ export const useFlujoPrincipal = () => { ); }); - // ── PASO 7: Pulso animado en ubicación del usuario ──── - dibujarPulsoUsuario(ubicacion, map) - - // ── PASO 8: Zoom centrado en usuario + parada cercana ─ + // ── PASO 7: Zoom centrado en usuario + parada cercana ─ hacerZoomAlTramoRelevante(ubicacion, paradaCercanaFound, map) } catch (error) { @@ -137,47 +120,6 @@ export const useFlujoPrincipal = () => { } } - // PULSO ANIMADO EN LA UBICACIÓN DEL USUARIO: - const dibujarPulsoUsuario = ( - ubicacion: { lat: number, lng: number }, - map: google.maps.Map - ) => { - const { registrarCircle, registrarMarker } = useMapState() - - // Círculo exterior pulsante (efecto ripple) - registrarCircle( - new google.maps.Circle({ - map, - center: ubicacion, - radius: 80, // metros - fillColor: '#3B82F6', - fillOpacity: 0.15, - strokeColor: '#3B82F6', - strokeOpacity: 0.4, - strokeWeight: 1, - zIndex: 1 - }) - ) - - // Punto central sólido del usuario - registrarMarker( - new google.maps.Marker({ - position: ubicacion, - map, - icon: { - path: google.maps.SymbolPath.CIRCLE, - fillColor: '#3B82F6', // azul - fillOpacity: 1, - strokeColor: '#FFFFFF', - strokeWeight: 3, - scale: 9 - }, - title: 'Tu ubicación', - zIndex: 20 // encima de todo - }) - ) - } - // ZOOM QUE MUESTRA USUARIO Y PARADA CERCANA: const hacerZoomAlTramoRelevante = ( ubicacion: { lat: number, lng: number }, diff --git a/frontend/src/views/MapView.vue b/frontend/src/views/MapView.vue index 3fa33b2..77d0136 100644 --- a/frontend/src/views/MapView.vue +++ b/frontend/src/views/MapView.vue @@ -32,7 +32,7 @@ const mapStore = useMapStore(); const couponStore = useCouponStore(); const authStore = useAuthStore(); -const { map, isLoaded, error: mapsError, initMap, addHtmlMarker, setCenter, setZoom, addMarker } = useGoogleMaps(); +const { map, isLoaded, error: mapsError, initMap, addHtmlMarker, setCenter, setZoom, addMarker, addCleanMarker } = useGoogleMaps(); const { estasCargando: estasCargandoRuta, errorRuta } = useDirectionsRoute(); const { encontrarParadaCercana, paradaCercana, distanciaMetros, duracionCaminata } = useParadaCercana(); const { calcularETA, busesActivos, cargando: etaCargando } = useETA(); @@ -202,7 +202,7 @@ async function updateMapMarkers(skipZoom = false) { } const selectedRouteObj = routeStore.allRoutes.find(r => r.id === currentRequestRouteId) || { id: currentRequestRouteId, short_name: currentRequestRouteId }; - await procesarSeleccionDeRuta(selectedRouteObj, stops as BusStop[], map.value, skipZoom); + await procesarSeleccionDeRuta(selectedRouteObj, stops as BusStop[], map.value, addCleanMarker, skipZoom); reDrawUserMarker(); if (routeStore.selectedRouteId !== currentRequestRouteId) return; @@ -553,6 +553,7 @@ watch(() => authStore.userProfile?.auto_location, (canLocate) => { flex-direction: column; gap: 16px; z-index: 1001; + align-items: flex-end; /* Alinea botones a la derecha */ } .offers-fab {