Implement Smart Location: auto-detect user location if preference is enabled, hide location button, and handle permission denial by resetting preference
This commit is contained in:
@ -6,6 +6,7 @@ import { useRouteStore } from "@/stores/route";
|
||||
import { useMapStore } from "@/stores/map";
|
||||
import { useBusStopStore } from "@/stores/busStop";
|
||||
import { useCouponStore } from "@/stores/coupon";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { useGoogleMaps } from "@/composables/useGoogleMaps";
|
||||
import { analyticsService } from "@/services/analyticsService";
|
||||
import { getImageUrl } from "@/utils/imageUrl";
|
||||
@ -25,6 +26,7 @@ const routeStore = useRouteStore();
|
||||
const mapStore = useMapStore();
|
||||
const busStopStore = useBusStopStore();
|
||||
const couponStore = useCouponStore();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
const { map, isLoaded, error: mapsError, initMap, addHtmlMarker, setCenter, setZoom, addMarker } = useGoogleMaps();
|
||||
const { estasCargando: estasCargandoRuta, errorRuta } = useDirectionsRoute();
|
||||
@ -248,6 +250,12 @@ async function initializeMap() {
|
||||
// Show promotions on the map
|
||||
updatePromoMarkers();
|
||||
|
||||
// Smart Location: Detect automatically if enabled in profile
|
||||
if (authStore.userProfile?.auto_location) {
|
||||
console.log('🤖 JARVIS: Smart Location detectado — localizando automaticamente...');
|
||||
locateUser();
|
||||
}
|
||||
|
||||
// Apply initial styles based on current zoom
|
||||
updateMarkersStyles();
|
||||
}
|
||||
@ -486,6 +494,14 @@ function locateUser(): Promise<void> {
|
||||
},
|
||||
(error) => {
|
||||
console.warn("SIBU | Geolocalización denegada:", error.message);
|
||||
|
||||
// Si el usuario tenía auto_location pero denegó el permiso del navegador,
|
||||
// lo desmarcamos para que no lo vuelva a intentar infinitamente.
|
||||
if (authStore.userProfile?.auto_location) {
|
||||
console.log('🤖 JARVIS: Permiso denegado — desactivando Smart Location.');
|
||||
authStore.updateProfile({ auto_location: false });
|
||||
}
|
||||
|
||||
resolve();
|
||||
},
|
||||
{
|
||||
@ -563,7 +579,7 @@ async function highlightOptimalStopForRoute() {
|
||||
<!-- Status overlay para SIBU Directions API -->
|
||||
<div v-if="estasCargandoRuta || errorRuta" class="status-indicator">
|
||||
<div v-if="estasCargandoRuta" class="loading-pill">
|
||||
Calculando ruta real...
|
||||
{{ t('map.calculatingRoute') }}
|
||||
</div>
|
||||
<div v-if="errorRuta" class="error-pill">
|
||||
{{ errorRuta }}
|
||||
@ -577,7 +593,7 @@ async function highlightOptimalStopForRoute() {
|
||||
<!-- Floating Offers Button at exact location -->
|
||||
<div v-if="mapsError" class="error">
|
||||
<div style="text-align: center; padding: 20px; max-width: 600px; margin: 0 auto;">
|
||||
<h3 style="color: var(--text-primary); margin-bottom: 15px;">⚠️ Error al cargar mapa</h3>
|
||||
<h3 style="color: var(--text-primary); margin-bottom: 15px;">⚠️ {{ t('map.mapLoadingError') }}</h3>
|
||||
<div style="color: var(--text-primary); margin-bottom: 15px; white-space: pre-line; text-align: left; background: var(--bg-secondary); padding: 15px; border-radius: 8px;">
|
||||
{{ mapsError }}
|
||||
</div>
|
||||
@ -603,9 +619,9 @@ async function highlightOptimalStopForRoute() {
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<!-- Location Button (Animated Pin) -->
|
||||
<!-- Location Button (Animated Pin) - Hidden if Smart Location is active -->
|
||||
<button
|
||||
v-if="isLoaded"
|
||||
v-if="isLoaded && !authStore.userProfile?.auto_location"
|
||||
class="location-loader-btn"
|
||||
@click="locateUser"
|
||||
:title="t('map.showMyLocation')"
|
||||
@ -625,7 +641,7 @@ async function highlightOptimalStopForRoute() {
|
||||
v-if="routeStore.selectedRouteId && wasSelectedFromMap"
|
||||
class="uber-search-trigger circular"
|
||||
@click="openUberSearch"
|
||||
title="Buscar"
|
||||
:title="t('map.search')"
|
||||
>
|
||||
<span class="material-icons">search</span>
|
||||
</div>
|
||||
@ -637,7 +653,7 @@ async function highlightOptimalStopForRoute() {
|
||||
@click="openUberSearch"
|
||||
>
|
||||
<span class="material-icons search-icon">directions_bus</span>
|
||||
<span class="trigger-label">ver rutas</span>
|
||||
<span class="trigger-label">{{ t('map.viewRoutes') }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Nuevo Banner de Parada Cercana Alineado (Redimensionado y con ETA) -->
|
||||
@ -651,7 +667,7 @@ async function highlightOptimalStopForRoute() {
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col flex-1 truncate ml-2" style="min-width: 0;">
|
||||
<span class="text-[9px] uppercase font-bold text-gray-500 dark:text-gray-400 leading-none">Tiempo de llegada</span>
|
||||
<span class="text-[9px] uppercase font-bold text-gray-500 dark:text-gray-400 leading-none">{{ t('map.arrivalTime') }}</span>
|
||||
<span class="trigger-text-compact truncate leading-tight">{{ paradaCercana?.name }}</span>
|
||||
</div>
|
||||
|
||||
@ -683,7 +699,7 @@ async function highlightOptimalStopForRoute() {
|
||||
<button class="back-btn" @click="closeUberSearch">
|
||||
<span class="material-icons">arrow_back</span>
|
||||
</button>
|
||||
<div class="search-title">Rutas Disponibles</div>
|
||||
<div class="search-title">{{ t('map.availableRoutes') }}</div>
|
||||
</div>
|
||||
|
||||
<!-- Inputs and Toggle removed per request -->
|
||||
@ -706,7 +722,7 @@ async function highlightOptimalStopForRoute() {
|
||||
</div>
|
||||
<div class="result-content">
|
||||
<div class="result-name">{{ route.name }}</div>
|
||||
<div class="result-address">Ruta de Autobús</div>
|
||||
<div class="result-address">{{ t('map.busRoute') }}</div>
|
||||
</div>
|
||||
<span class="material-icons check-icon">
|
||||
{{ route.id === routeStore.selectedRouteId ? 'check_circle' : 'chevron_right' }}
|
||||
@ -725,7 +741,7 @@ async function highlightOptimalStopForRoute() {
|
||||
<!-- Header -->
|
||||
<div class="sheet-header">
|
||||
<div class="sheet-title-group">
|
||||
<span class="sheet-title">Ofertas</span>
|
||||
<span class="sheet-title">{{ t('coupons.title') }}</span>
|
||||
</div>
|
||||
<button class="sheet-close" @click="showPromos = false">
|
||||
<span class="material-icons">close</span>
|
||||
@ -753,7 +769,7 @@ async function highlightOptimalStopForRoute() {
|
||||
<span class="sheet-biz-name">{{ currentPromo.business?.name || 'Local' }}</span>
|
||||
<h3 class="sheet-promo-title">{{ currentPromo.title }}</h3>
|
||||
<div class="sheet-actions">
|
||||
<button class="sheet-cta" @click="handlePromoClick(currentPromo)">Ver detalles</button>
|
||||
<button class="sheet-cta" @click="handlePromoClick(currentPromo)">{{ t('coupons.viewDetails') }}</button>
|
||||
<span v-if="currentPromo.discount_percentage" class="sheet-discount-tag">-{{ currentPromo.discount_percentage }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -791,7 +807,7 @@ async function highlightOptimalStopForRoute() {
|
||||
class="promo-img-modal"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
<div class="promo-badge-modal">PROMO</div>
|
||||
<div class="promo-badge-modal">{{ t('map.promo') }}</div>
|
||||
</div>
|
||||
<div class="promo-body-modal">
|
||||
<h2 class="promo-title-modal">{{ selectedPromo.title }}</h2>
|
||||
@ -799,7 +815,7 @@ async function highlightOptimalStopForRoute() {
|
||||
<p>{{ selectedPromo.description }}</p>
|
||||
</div>
|
||||
<div class="promo-actions-modal">
|
||||
<button class="business-detail-btn-modal" style="flex: 1; width: 100%;" @click="router.push('/business/' + selectedPromo.business_id)">Ver Negocio</button>
|
||||
<button class="business-detail-btn-modal" style="flex: 1; width: 100%;" @click="router.push('/business/' + selectedPromo.business_id)">{{ t('business.viewBusiness') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user