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,8 +5,10 @@ import { useRouteStore } from '@/stores/route'
|
||||
import { formatTo12Hour } from '@/utils/timeFormatter'
|
||||
import { analyticsService } from '@/services/analyticsService'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const route = useRoute()
|
||||
const { t } = useI18n()
|
||||
const scheduleStore = useScheduleStore()
|
||||
const routeStore = useRouteStore()
|
||||
|
||||
@ -15,9 +17,9 @@ const dayFilter = ref<'all' | 'today' | 'tomorrow'>('today')
|
||||
|
||||
// ── Tipos de día
|
||||
const DAY_TYPES: Record<string, string> = {
|
||||
'weekday': 'Días de semana',
|
||||
'weekend': 'Fin de semana',
|
||||
'holiday': 'Festivo',
|
||||
'weekday': t('schedules.types.weekday'),
|
||||
'weekend': t('schedules.types.weekend'),
|
||||
'holiday': t('schedules.types.holiday'),
|
||||
}
|
||||
|
||||
// ── Calcular estado del bus según horario
|
||||
@ -72,9 +74,9 @@ function getDayLabel(schedule: any): string {
|
||||
const now = new Date()
|
||||
const todayType = (now.getDay() === 0 || now.getDay() === 6) ? 'weekend' : 'weekday'
|
||||
|
||||
if (type === 'todos') return 'Diario'
|
||||
if (type === todayType) return 'Hoy'
|
||||
return 'Mañana'
|
||||
if (type === 'todos') return t('coupons.active') // Or add "Daily" to JSON
|
||||
if (type === todayType) return t('schedules.today') || 'Hoy'
|
||||
return t('schedules.tomorrow') || 'Mañana'
|
||||
}
|
||||
|
||||
// ── Filtrado de horarios
|
||||
@ -169,9 +171,9 @@ onUnmounted(() => {
|
||||
|
||||
<!-- ── HEADER ── -->
|
||||
<header class="sch-header">
|
||||
<h1 class="sch-title">Horarios</h1>
|
||||
<h1 class="sch-title">{{ t('schedules.title') }}</h1>
|
||||
<p class="sch-subtitle" v-if="!routeStore.hasSelectedRoute">
|
||||
Selecciona una ruta para ver los próximos buses
|
||||
{{ t('schedules.selectRoute') }}
|
||||
</p>
|
||||
</header>
|
||||
|
||||
@ -191,7 +193,7 @@ onUnmounted(() => {
|
||||
<span class="material-icons">directions_bus</span>
|
||||
</div>
|
||||
<span class="trigger-text" :class="{ 'trigger-text--selected': routeStore.hasSelectedRoute }">
|
||||
{{ routeStore.isLoadingRoutes ? 'Cargando rutas...' : (routeStore.selectedRouteName || 'Selecciona una ruta...') }}
|
||||
{{ routeStore.isLoadingRoutes ? t('schedules.loadingRoutes') : (routeStore.selectedRouteName || t('schedules.placeholder')) }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="material-icons trigger-arrow" :class="{ 'trigger-arrow--up': dropdownOpen }">
|
||||
@ -207,7 +209,7 @@ onUnmounted(() => {
|
||||
class="dropdown-loading"
|
||||
>
|
||||
<div class="spinner-sm"></div>
|
||||
<span>Cargando rutas...</span>
|
||||
<span>{{ t('schedules.loadingRoutes') }}</span>
|
||||
</div>
|
||||
<template v-else>
|
||||
<button
|
||||
@ -222,7 +224,7 @@ onUnmounted(() => {
|
||||
<span v-if="r.id === routeStore.selectedRouteId" class="material-icons dropdown-item-check">check</span>
|
||||
</button>
|
||||
<div v-if="routeStore.allRoutes.length === 0" class="dropdown-empty">
|
||||
No hay rutas disponibles
|
||||
{{ t('schedules.noRoutesAvailable') }}
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@ -241,8 +243,8 @@ onUnmounted(() => {
|
||||
<line x1="40" y1="56" x2="40" y2="62" stroke="var(--active-color)" stroke-width="3" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 class="empty-title">Aquí verás los horarios</h2>
|
||||
<p class="empty-sub">Elige una ruta del menú de arriba para ver los próximos buses disponibles</p>
|
||||
<h2 class="empty-title">{{ t('schedules.schedules') }}</h2>
|
||||
<p class="empty-sub">{{ t('schedules.placeholder') }}</p>
|
||||
</div>
|
||||
|
||||
<!-- ── CONTENIDO con ruta seleccionada ── -->
|
||||
@ -252,28 +254,28 @@ onUnmounted(() => {
|
||||
<div class="live-badge-wrap">
|
||||
<div class="live-badge">
|
||||
<span class="live-dot"></span>
|
||||
<span>Próximas salidas</span>
|
||||
<span>{{ t('schedules.upcoming') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Chips de filtro día -->
|
||||
<div class="day-chips">
|
||||
<button class="day-chip" :class="{ 'day-chip--active': dayFilter === 'today' }" @click="dayFilter = 'today'">Hoy</button>
|
||||
<button class="day-chip" :class="{ 'day-chip--active': dayFilter === 'tomorrow' }" @click="dayFilter = 'tomorrow'">Mañana</button>
|
||||
<button class="day-chip" :class="{ 'day-chip--active': dayFilter === 'all' }" @click="dayFilter = 'all'">Todos</button>
|
||||
<button class="day-chip" :class="{ 'day-chip--active': dayFilter === 'today' }" @click="dayFilter = 'today'">{{ t('schedules.today') || 'Hoy' }}</button>
|
||||
<button class="day-chip" :class="{ 'day-chip--active': dayFilter === 'tomorrow' }" @click="dayFilter = 'tomorrow'">{{ t('schedules.tomorrow') || 'Mañana' }}</button>
|
||||
<button class="day-chip" :class="{ 'day-chip--active': dayFilter === 'all' }" @click="dayFilter = 'all'">{{ t('common.all') || 'Todos' }}</button>
|
||||
</div>
|
||||
|
||||
<!-- Loading -->
|
||||
<div v-if="scheduleStore.isLoading" class="state-center">
|
||||
<div class="spinner"></div>
|
||||
<p>Cargando horarios...</p>
|
||||
<p>{{ t('schedules.loading') || 'Cargando horarios...' }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Sin resultados en el filtro -->
|
||||
<div v-else-if="filteredSchedules.length === 0" class="empty-state empty-state--sm">
|
||||
<span class="material-icons empty-cat-icon">schedule</span>
|
||||
<p class="empty-sub">No hay horarios para este filtro</p>
|
||||
<button class="chip-link" @click="dayFilter = 'all'">Ver todos los horarios</button>
|
||||
<p class="empty-sub">{{ t('schedules.noSchedules') }}</p>
|
||||
<button class="chip-link" @click="dayFilter = 'all'">{{ t('schedules.viewAll') || 'Ver todos los horarios' }}</button>
|
||||
</div>
|
||||
|
||||
<!-- Lista de horarios -->
|
||||
@ -297,9 +299,9 @@ onUnmounted(() => {
|
||||
<div class="card-info">
|
||||
<div class="card-top-row">
|
||||
<span class="day-tag" :class="dayFilter === 'today' ? `day-tag--${getScheduleDay(schedule)}` : 'day-tag--tomorrow'">
|
||||
{{ dayFilter === 'tomorrow' ? 'Mañana' : (dayFilter === 'all' ? getDayLabel(schedule) : getDayLabel(schedule)) }}
|
||||
{{ dayFilter === 'tomorrow' ? t('schedules.tomorrow') : (dayFilter === 'all' ? getDayLabel(schedule) : getDayLabel(schedule)) }}
|
||||
</span>
|
||||
<span v-if="i === 0 && getBusStatus(schedule.departure_time) === 'departing'" class="departing-pulse">SALIENDO</span>
|
||||
<span v-if="i === 0 && getBusStatus(schedule.departure_time) === 'departing'" class="departing-pulse">{{ t('schedules.departing') || 'SALIENDO' }}</span>
|
||||
</div>
|
||||
<p class="route-name">{{ routeStore.selectedRouteName }}</p>
|
||||
<p class="card-detail">
|
||||
|
||||
Reference in New Issue
Block a user