diff --git a/frontend/src/views/MapView.vue b/frontend/src/views/MapView.vue index 482fe40..8f9c1e9 100644 --- a/frontend/src/views/MapView.vue +++ b/frontend/src/views/MapView.vue @@ -13,7 +13,6 @@ import { getImageUrl } from "@/utils/imageUrl"; import { useDirectionsRoute } from "@/composables/useDirectionsRoute"; import { useParadaCercana } from "@/composables/useParadaCercana"; import { useETA } from "@/composables/useETA"; -const BusStopInfoModal = defineAsyncComponent(() => import("@/components/BusStopInfoModal.vue")); const ETACard = defineAsyncComponent(() => import("@/components/ETACard.vue")); import type { BusStop } from '@/types' import { useFlujoPrincipal } from "@/composables/useFlujoPrincipal"; @@ -27,7 +26,7 @@ const mapStore = useMapStore(); const busStopStore = useBusStopStore(); const couponStore = useCouponStore(); -const { map, isLoaded, error: mapsError, initMap, addCleanMarker, addHtmlMarker, setCenter, setZoom, addMarker } = useGoogleMaps(); +const { map, isLoaded, error: mapsError, initMap, addHtmlMarker, setCenter, setZoom, addMarker } = useGoogleMaps(); const { estasCargando: estasCargandoRuta, errorRuta } = useDirectionsRoute(); const { encontrarParadaCercana, paradaCercana, distanciaMetros, duracionCaminata } = useParadaCercana(); const { calcularETA, busesActivos, cargando: etaCargando } = useETA(); @@ -41,18 +40,18 @@ const showETACard = ref(false); const markers = ref([]); const promoMarkers = ref([]); const userMarker = ref(null); -const polyline = ref(null); -const walkingPolyline = ref(null); -const walkingPolylineBorder = ref(null); // Borde blanco estilo Google Maps -const optimalStopPulse = ref(null); // Radar para la parada óptima -const showRouteDropdown = ref(false); -const routeCardRef = ref(null); +const currentMarkerMode = ref<'dot' | 'pin' | null>(null); const isUpdatingMarkers = ref(false); const unitMarkers = ref>(new Map()); const unitFetchInterval = ref(null); -const userCoords = ref<{ lat: number; lng: number } | null>(null); // Store last user location for internal navigation -const currentMarkerMode = ref<'dot' | 'pin' | null>(null); -const mappingSequenceId = ref(0); // Atomic ID to prevent race conditions +const userCoords = ref<{ lat: number; lng: number } | null>(null); +const polyline = ref(null); +const walkingPolyline = ref(null); +const walkingPolylineBorder = ref(null); +const optimalStopPulse = ref(null); +const showRouteDropdown = ref(false); +const routeCardRef = ref(null); +const mappingSequenceId = ref(0); const alturaNavbar = ref(64); // Search state @@ -90,59 +89,16 @@ function closeUberSearch() { destinationQuery.value = ""; } -async function clearAllMapData() { - console.log('🤖 JARVIS: Iniciando PURGA nuclear centralizada...'); - // 1. UI inmediata - showUberSearch.value = false; - showRoutesToggle.value = false; - destinationQuery.value = ""; - stopSearchQuery.value = ""; - showETACard.value = false; - paradaCercana.value = null; // Borrar banner superior +// clearAllMapData removed per request - // 2. Invalidar hilos en curso - mappingSequenceId.value++; - try { - // 3. Resetear stores - routeStore.clearSelection(); - lastProcessedRouteId.value = null; +// Modal state removed per request (no more stop markers to click) - // 4. LIMPIEZA CENTRALIZADA (useMapState) - // Esto limpia markers, renderers, polylines, overlays HTML, etc. - limpiarTodoCentralizado(); - - // 5. Limpiar referencias locales del componente (aunque no tengan mapa asignado ya) - markers.value = []; - promoMarkers.value = []; - unitMarkers.value.clear(); - polyline.value = null; - walkingPolyline.value = null; - walkingPolylineBorder.value = null; - optimalStopPulse.value = null; - - // 6. Restaurar SOLO el marcador del usuario si tenemos ubicación - await nextTick(); - if (userCoords.value) { - const { lat, lng } = userCoords.value; - userMarker.value = addHtmlMarker( - { lat, lng }, - sonarHtml, - { x: -30, y: -30 } - ); - } - - console.log('🤖 JARVIS: Purga completada ✓'); - } catch (err) { - console.error('❌ JARVIS: Error en purga:', err); - } +function reloadPage() { + window.location.reload(); } -// Modal state -const showBusStopModal = ref(false); -const selectedBusStop = ref(null); - const showPromoModal = ref(false); const selectedPromo = ref(null); const isBannerClosing = ref(false); @@ -154,27 +110,6 @@ function animateAndReload() { }, 450); // Mismo tiempo que la transición } -// Close dropdown when clicking outside -function handleClickOutside(event: MouseEvent) { - if (routeCardRef.value && !routeCardRef.value.contains(event.target as Node)) { - showRouteDropdown.value = false; - } -} - -function handleBusStopClick(stop: BusStop) { - selectedBusStop.value = stop; - showBusStopModal.value = true; -} - -function closeBusStopModal() { - showBusStopModal.value = false; - selectedBusStop.value = null; -} - -function reloadPage() { - window.location.reload(); -} - function handlePromoClick(promo: any) { selectedPromo.value = promo; showPromoModal.value = true; @@ -207,8 +142,6 @@ onMounted(async () => { } analyticsService.logEvent({ event_name: 'screen_view', properties: { screen_name: 'Map' } }) - // Add click outside listener - document.addEventListener('click', handleClickOutside); // Load routes, bus stops and promos in parallel await Promise.all([ @@ -226,19 +159,6 @@ onMounted(async () => { } } - // Handle stopId if present - const queryStopId = router.currentRoute.value.query.stopId as string; - if (queryStopId) { - await busStopStore.loadBusStops(); - const foundStop = busStopStore.busStops.find(s => s.id === queryStopId); - if (foundStop) { - selectedBusStop.value = foundStop; - showBusStopModal.value = true; - setCenter(foundStop.latitude, foundStop.longitude); - setZoom(17); - } - } - // Wait for Google Maps to load if (isLoaded.value) { await initializeMap(); @@ -294,7 +214,6 @@ function prevPromo() { } onUnmounted(() => { - document.removeEventListener('click', handleClickOutside); if (unitFetchInterval.value) clearInterval(unitFetchInterval.value); if (carouselTimer.value) clearInterval(carouselTimer.value); // Clear all markers when component unmounts @@ -426,18 +345,7 @@ async function updateMapMarkers() { return; } - // Agregar todos los stops como marcadores 'normales' para que se vean en el mapa - stops.forEach(stop => { - // Evitar sobre dibujar si es la cercana (useFlujoPrincipal ya se encargó) - if (paradaCercana.value && stop.id === paradaCercana.value.id) return; - - addCleanMarker( - { lat: stop.latitude, lng: stop.longitude }, - stop.name, - 'normal', - () => handleBusStopClick(stop) - ); - }); + // All stop markers loop removed per request to avoid marking stops on map } finally { isUpdatingMarkers.value = false; } @@ -625,128 +533,9 @@ async function highlightOptimalStopForRoute() { } } -/** - * Dibuja la ruta caminando en el mapa interno sin abrir apps externas - */ -function drawInternalWalkingRoute(targetStop: BusStop, originOverride?: { lat: number, lng: number }) { - const origin = originOverride || userCoords.value; - - if (!origin) { - // Si no tenemos ubicación, la pedimos - navigator.geolocation.getCurrentPosition((pos) => { - userCoords.value = { lat: pos.coords.latitude, lng: pos.coords.longitude }; - calculateWalkingPath(userCoords.value, targetStop); - }, (_err) => { - alert("Necesitamos tu ubicación para trazar la ruta a pie."); - }); - } else { - calculateWalkingPath(origin, targetStop); - } -} -async function calculateWalkingPath(origin: { lat: number, lng: number }, targetStop: BusStop) { - // 1. Limpiar pulso anterior si existe - if (optimalStopPulse.value) { - if (typeof optimalStopPulse.value.setMap === 'function') { - optimalStopPulse.value.setMap(null); - } - optimalStopPulse.value = null; - } - // 2. Añadir el PULSO NARANJA de "Parada Óptima" - optimalStopPulse.value = addHtmlMarker( - { lat: targetStop.latitude, lng: targetStop.longitude }, - optimalSonarHtml, - { x: -30, y: -30 } - ); - - // 3. Resaltar la parada en verde (marcador estándar) - const targetStops = routeStore.selectedRouteId ? routeStore.selectedRouteStops : busStopStore.busStops; - const stopIndex = targetStops.findIndex(s => s.id === targetStop.id); - - if (stopIndex !== -1 && markers.value[stopIndex]) { - const marker = markers.value[stopIndex]; - marker.setIcon({ - path: currentMarkerMode.value === 'pin' - ? "M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z" - : google.maps.SymbolPath.CIRCLE, - fillColor: '#4CAF50', - fillOpacity: 1, - strokeColor: '#FFFFFF', - strokeWeight: 2, - scale: currentMarkerMode.value === 'pin' ? 2.5 : 9, - anchor: currentMarkerMode.value === 'pin' ? new google.maps.Point(12, 22) : null - }); - } - - // 2. Trazar línea de puntos verde siguiendo RED VIAL PRINCIPAL - try { - const { RoutesService } = await google.maps.importLibrary("routes") as any; - const routeService = new RoutesService(); - const response = await routeService.computeRoutes({ - origin: { - location: { - latLng: { lat: origin.lat, lng: origin.lng } - } - }, - destination: { - location: { - latLng: { lat: targetStop.latitude, lng: targetStop.longitude } - } - }, - travelMode: 'DRIVE', - routingPreference: 'TRAFFIC_UNAWARE', - polylineQuality: 'HIGH_QUALITY', - polylineEncoding: 'ENCODED_POLYLINE', - }); - - if (response.routes && response.routes.length > 0) { - const route = response.routes[0]; - - if (route.polyline && route.polyline.encodedPolyline) { - const path = google.maps.geometry.encoding.decodePath(route.polyline.encodedPolyline); - - if (walkingPolyline.value) walkingPolyline.value.setMap(null); - if (walkingPolylineBorder.value) walkingPolylineBorder.value.setMap(null); - - const { registrarPolyline: regPoly } = useMapState(); - - // CAPA 1: Borde blanco (Para dar contraste estilo Google Maps) - walkingPolylineBorder.value = new google.maps.Polyline({ - path: path, - geodesic: true, - strokeColor: '#FFFFFF', - strokeOpacity: 0.9, - strokeWeight: 10, - map: map.value, - zIndex: 5 - }); - regPoly(walkingPolylineBorder.value); - - // CAPA 2: Línea Indigo Central (La ruta principal) - walkingPolyline.value = new google.maps.Polyline({ - path: path, - geodesic: true, - strokeColor: '#4285F4', // Azul Google Maps - strokeOpacity: 1.0, - strokeWeight: 5, - map: map.value, - zIndex: 10 - }); - regPoly(walkingPolyline.value); - - // Ajustar zoom para mostrar toda la ruta de caminata - if (map.value) { - const bounds = new google.maps.LatLngBounds(); - path.forEach(p => bounds.extend(p)); - map.value.fitBounds(bounds, { top: 100, bottom: 200, left: 50, right: 50 }); - } - } - } - } catch (error) { - console.warn('SIBU | Error trazando ruta a pie con Routes API:', error); - } -} +// walking route functions removed @@ -886,14 +675,7 @@ async function calculateWalkingPath(origin: { lat: number, lng: number }, target
- +
@@ -1004,13 +786,7 @@ async function calculateWalkingPath(origin: { lat: number, lng: number }, target - - + diff --git a/frontend/src/views/SchedulesView.vue b/frontend/src/views/SchedulesView.vue index ddb74bb..d3dce3f 100644 --- a/frontend/src/views/SchedulesView.vue +++ b/frontend/src/views/SchedulesView.vue @@ -4,10 +4,9 @@ import { useScheduleStore } from '@/stores/schedule' import { useRouteStore } from '@/stores/route' import { formatTo12Hour } from '@/utils/timeFormatter' import { analyticsService } from '@/services/analyticsService' -import { useRouter, useRoute } from 'vue-router' +import { useRoute } from 'vue-router' const route = useRoute() -const router = useRouter() const scheduleStore = useScheduleStore() const routeStore = useRouteStore() @@ -126,11 +125,8 @@ function pickRoute(id: string, name: string) { scheduleStore.loadRouteSchedules(id) } -function goToMap() { - if (routeStore.selectedRouteId) { - router.push({ path: '/map', query: { routeId: routeStore.selectedRouteId } }) - } -} +// goToMap removed per request + // ── Cierre del dropdown al hacer clic fuera function handleOutsideClick(e: MouseEvent) { @@ -256,11 +252,6 @@ onUnmounted(() => { Próximas salidas - -