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:
@ -5,9 +5,11 @@ import { supabase } from '@/supabase'
|
||||
import type { Shuttle } from '@/types'
|
||||
import { getImageUrl } from '@/utils/imageUrl'
|
||||
import { analyticsService } from '@/services/analyticsService'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { t } = useI18n()
|
||||
const shuttle = ref<Shuttle | null>(null)
|
||||
const cargando = ref(true)
|
||||
const error = ref<string | null>(null)
|
||||
@ -27,7 +29,7 @@ onMounted(async () => {
|
||||
if (sbError) throw sbError
|
||||
shuttle.value = data
|
||||
} catch (e: any) {
|
||||
error.value = 'No se pudo cargar la información del viaje'
|
||||
error.value = t('shuttle.errorLoading')
|
||||
console.error('SIBU | Error cargando shuttle:', e)
|
||||
} finally {
|
||||
cargando.value = false
|
||||
@ -51,6 +53,13 @@ const volver = () => {
|
||||
router.push('/transporte/viajes-turisticos')
|
||||
}
|
||||
}
|
||||
|
||||
const getTripTypeLabel = (type: string) => {
|
||||
if (type === 'one_way') return t('shuttle.oneWay')
|
||||
if (type === 'round_trip') return t('shuttle.roundTrip')
|
||||
if (type === 'both') return t('shuttle.both')
|
||||
return type
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -61,14 +70,14 @@ const volver = () => {
|
||||
<span class="material-icons text-[var(--text-primary)]">arrow_back</span>
|
||||
</button>
|
||||
<h1 class="font-bold text-[var(--text-primary)] text-lg truncate flex-1">
|
||||
{{ shuttle?.company_name || 'Detalle del viaje' }}
|
||||
{{ shuttle?.company_name || t('shuttle.detailTitle') }}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<!-- Loading -->
|
||||
<div v-if="cargando" class="flex flex-col justify-center items-center h-64 gap-3">
|
||||
<span class="material-icons spin text-4xl" style="color: var(--active-color)">refresh</span>
|
||||
<p class="text-text-secondary font-medium animate-pulse">Cargando...</p>
|
||||
<p class="text-text-secondary font-medium animate-pulse">{{ t('common.loading') }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Error -->
|
||||
@ -76,7 +85,7 @@ const volver = () => {
|
||||
<span class="material-icons text-red-500 text-5xl mb-3">error_outline</span>
|
||||
<p class="text-red-500 font-medium">{{ error }}</p>
|
||||
<button @click="volver" class="mt-6 px-6 py-2 bg-text-primary text-surface font-bold rounded-full shadow hover:opacity-90 transition">
|
||||
Volver
|
||||
{{ t('common.back') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -100,7 +109,7 @@ const volver = () => {
|
||||
<div class="bg-[var(--bg-secondary)] rounded-2xl p-5 shadow-sm space-y-3 border border-border">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex flex-col flex-1">
|
||||
<span class="text-xs text-[var(--text-secondary)] font-semibold mb-1 uppercase tracking-wider">Origen</span>
|
||||
<span class="text-xs text-[var(--text-secondary)] font-semibold mb-1 uppercase tracking-wider">{{ t('shuttle.origin') }}</span>
|
||||
<span class="font-bold text-[var(--text-primary)] text-lg leading-tight break-words">
|
||||
{{ shuttle.origin }}
|
||||
</span>
|
||||
@ -114,7 +123,7 @@ const volver = () => {
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col flex-1 text-right">
|
||||
<span class="text-xs text-[var(--text-secondary)] font-semibold mb-1 uppercase tracking-wider">Destino</span>
|
||||
<span class="text-xs text-[var(--text-secondary)] font-semibold mb-1 uppercase tracking-wider">{{ t('shuttle.destination') }}</span>
|
||||
<span class="font-bold text-[var(--text-primary)] text-lg leading-tight break-words">
|
||||
{{ shuttle.destination }}
|
||||
</span>
|
||||
@ -131,19 +140,19 @@ const volver = () => {
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 pt-4 border-t border-border">
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="text-xs text-[var(--text-secondary)] uppercase tracking-wider font-semibold flex items-center gap-1"><span class="material-icons text-sm">schedule</span> Hora de salida</span>
|
||||
<span class="text-xs text-[var(--text-secondary)] uppercase tracking-wider font-semibold flex items-center gap-1"><span class="material-icons text-sm">schedule</span> {{ t('shuttle.departureTimes') }}</span>
|
||||
<span class="font-semibold text-[var(--text-primary)] bg-[var(--bg-primary)] p-2 rounded-lg text-sm text-center border border-border">
|
||||
{{ shuttle.departure_times }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="text-xs text-[var(--text-secondary)] uppercase tracking-wider font-semibold flex items-center gap-1"><span class="material-icons text-sm">swap_horiz</span> Tipo de viaje</span>
|
||||
<span class="font-semibold text-[var(--text-primary)] bg-[var(--bg-primary)] p-2 rounded-lg text-sm text-center border border-border capitalize">
|
||||
{{ shuttle.trip_type.replace('_', ' ') }}
|
||||
<span class="text-xs text-[var(--text-secondary)] uppercase tracking-wider font-semibold flex items-center gap-1"><span class="material-icons text-sm">swap_horiz</span> {{ t('shuttle.tripType') }}</span>
|
||||
<span class="font-semibold text-[var(--text-primary)] bg-[var(--bg-primary)] p-2 rounded-lg text-sm text-center border border-border">
|
||||
{{ getTripTypeLabel(shuttle.trip_type) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1" v-if="shuttle.english_speaking">
|
||||
<span class="text-xs text-[var(--text-secondary)] uppercase tracking-wider font-semibold flex items-center gap-1"><span class="material-icons text-sm">g_translate</span> Idiomas</span>
|
||||
<span class="text-xs text-[var(--text-secondary)] uppercase tracking-wider font-semibold flex items-center gap-1"><span class="material-icons text-sm">g_translate</span> {{ t('shuttle.languages') }}</span>
|
||||
<span class="font-semibold text-[var(--text-primary)] bg-[var(--bg-primary)] p-2 rounded-lg text-sm text-center border border-border">
|
||||
Español · English
|
||||
</span>
|
||||
@ -154,14 +163,14 @@ const volver = () => {
|
||||
<!-- Precio -->
|
||||
<div class="rounded-2xl p-6 shadow-sm flex items-center justify-between" style="background-color: var(--active-color); color: #101820;">
|
||||
<div class="text-left">
|
||||
<p class="text-sm font-semibold opacity-90 mb-1">Precio por pasajero</p>
|
||||
<p class="text-sm font-semibold opacity-90 mb-1">{{ t('shuttle.pricePerPerson') }}</p>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-lg font-bold opacity-80">$</span>
|
||||
<span class="text-4xl font-black tracking-tight">{{ parsePrice(shuttle.price_per_person) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3 rounded-xl bg-black/10 backdrop-blur-sm" v-if="shuttle.price_private_trip">
|
||||
<span class="text-xs font-bold uppercase tracking-wider opacity-90 block mb-1">Privado</span>
|
||||
<span class="text-xs font-bold uppercase tracking-wider opacity-90 block mb-1">{{ t('shuttle.private') }}</span>
|
||||
<span class="font-black text-lg">${{ parsePrice(shuttle.price_private_trip) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -169,8 +178,8 @@ const volver = () => {
|
||||
<!-- Contacto -->
|
||||
<div class="bg-[var(--bg-secondary)] rounded-2xl p-5 shadow-sm space-y-4 border border-border mb-8">
|
||||
<div>
|
||||
<h3 class="font-bold text-[var(--text-primary)] text-lg">Reserva e Información</h3>
|
||||
<p class="text-sm text-[var(--text-secondary)] mt-1">Contacta directamente al operador para confirmar disponibilidad.</p>
|
||||
<h3 class="font-bold text-[var(--text-primary)] text-lg">{{ t('shuttle.bookingInfo') }}</h3>
|
||||
<p class="text-sm text-[var(--text-secondary)] mt-1">{{ t('shuttle.contactOperator') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-3">
|
||||
@ -181,7 +190,7 @@ const volver = () => {
|
||||
@click="analyticsService.logEvent({ event_name: 'shuttle_contact', item_id: shuttle.id, properties: { action: 'whatsapp' } })"
|
||||
>
|
||||
<span class="material-icons">chat</span>
|
||||
Reservar por WhatsApp
|
||||
{{ t('shuttle.bookWhatsapp') }}
|
||||
</a>
|
||||
|
||||
<a v-if="shuttle.phone_number"
|
||||
@ -190,7 +199,7 @@ const volver = () => {
|
||||
@click="analyticsService.logEvent({ event_name: 'shuttle_contact', item_id: shuttle.id, properties: { action: 'call' } })"
|
||||
>
|
||||
<span class="material-icons">phone_in_talk</span>
|
||||
Llamar al Operador
|
||||
{{ t('shuttle.callOperator') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -95,7 +95,7 @@ function getShiftLabel(shift: string) {
|
||||
<p>{{ taxiStore.error }}</p>
|
||||
<button class="retry-btn" @click="taxiStore.loadTaxis()">
|
||||
<span class="material-icons">refresh</span>
|
||||
Reintentar
|
||||
{{ t('common.retry') || 'Reintentar' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user