feat: simplify map by removing all stop markers and manual clear button

This commit is contained in:
2026-02-28 13:56:56 -05:00
parent 4a0a507ec0
commit 0fdb727875
2 changed files with 21 additions and 254 deletions

View File

@ -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<any[]>([]);
const promoMarkers = ref<any[]>([]);
const userMarker = ref<any>(null);
const polyline = ref<google.maps.Polyline | null>(null);
const walkingPolyline = ref<google.maps.Polyline | null>(null);
const walkingPolylineBorder = ref<google.maps.Polyline | null>(null); // Borde blanco estilo Google Maps
const optimalStopPulse = ref<any>(null); // Radar para la parada óptima
const showRouteDropdown = ref(false);
const routeCardRef = ref<HTMLElement | null>(null);
const currentMarkerMode = ref<'dot' | 'pin' | null>(null);
const isUpdatingMarkers = ref(false);
const unitMarkers = ref<Map<string, google.maps.Marker>>(new Map());
const unitFetchInterval = ref<any>(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<google.maps.Polyline | null>(null);
const walkingPolyline = ref<google.maps.Polyline | null>(null);
const walkingPolylineBorder = ref<google.maps.Polyline | null>(null);
const optimalStopPulse = ref<any>(null);
const showRouteDropdown = ref(false);
const routeCardRef = ref<HTMLElement | null>(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<BusStop | null>(null);
const showPromoModal = ref(false);
const selectedPromo = ref<any>(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
</script>
@ -886,14 +675,7 @@ async function calculateWalkingPath(origin: { lat: number, lng: number }, target
<!-- Inputs and Toggle removed per request -->
<div class="search-actions-header">
<button
v-if="routeStore.selectedRouteId || markers.length > 0"
class="clear-map-btn"
@click="clearAllMapData"
>
<span class="material-icons text-sm">layers_clear</span>
Limpiar Mapa
</button>
<!-- Limpiar Mapa button removed per request -->
</div>
<!-- Results -->
@ -1004,13 +786,7 @@ async function calculateWalkingPath(origin: { lat: number, lng: number }, target
</div>
</div>
<!-- Modal for details -->
<BusStopInfoModal
:is-open="showBusStopModal"
:bus-stop="selectedBusStop"
@close="closeBusStopModal"
@navigate="drawInternalWalkingRoute"
/>
<!-- Modal for details removed as per request to eliminate extra markings -->
<Transition name="modal-fade">

View File

@ -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(() => {
<span class="live-dot"></span>
<span>Próximas salidas</span>
</div>
<!-- Botón ver en mapa -->
<button class="map-btn" @click="goToMap">
<span class="material-icons">map</span>
Ver en mapa
</button>
</div>
<!-- Chips de filtro día -->