fix: simplify login flow - JWT role instant, no DB queries blocking navigation

This commit is contained in:
2026-02-25 22:47:21 -05:00
parent 963d255ea2
commit b9a1b6b57f
3 changed files with 24 additions and 49 deletions

View File

@ -20,22 +20,15 @@ const handleLogin = async () => {
try {
await authStore.login(email.value.trim().toLowerCase(), password.value)
// Esperar hasta que el perfil esté cargado (máx 3 segundos)
let attempts = 0
while (!authStore.role && attempts < 30) {
await new Promise(res => setTimeout(res, 100))
attempts++
}
// El rol ya está disponible en el store (del JWT), navegar directo
navigateByUserRole(authStore.role || 'PASSENGER')
} catch (error: any) {
console.error('Error Login detallado:', error)
if (error.message.includes('Invalid login credentials')) {
console.error('Error Login:', error)
if (error.message?.includes('Invalid login credentials')) {
errorMessage.value = 'Correo o contraseña incorrectos.'
} else {
errorMessage.value = `Error: ${error.message || 'Error en el servidor.'}`
errorMessage.value = `Error: ${error.message || 'Error desconocido.'}`
}
} finally {
isLoading.value = false

View File

@ -1,6 +1,7 @@
/** Vue Router configuration */
import { createRouter, createWebHistory } from 'vue-router'
import { supabase } from '@/supabase'
import { useAuthStore } from '@/stores/auth'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
@ -147,48 +148,34 @@ const router = createRouter({
})
router.beforeEach(async (to, _from, next) => {
// Rutas completamente públicas (splash, login)
const publicRoutes = ['/login', '/splash', '/']
if (publicRoutes.includes(to.path)) {
// Rutas sin protección → pasar directo
if (!to.meta.requiresAuth && !to.meta.role) {
return next()
}
// Leer sesión activa de Supabase
// Verificar sesión activa
const { data: { session } } = await supabase.auth.getSession()
// Ruta protegida sin sesión → redirige a login
if (to.meta.requiresAuth && !session) {
// Sin sesión en ruta protegida → login
if (!session) {
return next('/login')
}
// Si hay sesión, obtener el rol real del usuario
if (session) {
const { data: profile } = await supabase
.from('users')
.select('role')
.eq('id', session.user.id)
.single()
// Si la ruta requiere un rol específico, verificar usando el store
if (to.meta.role) {
// Usar el store de auth (ya tiene el rol cargado desde el JWT)
const authStore = useAuthStore()
const userRole = authStore.role?.toUpperCase() || 'PASSENGER'
const userRole = profile?.role?.toUpperCase() || 'PASSENGER'
const allowedRoles = Array.isArray(to.meta.role)
? (to.meta.role as string[]).map(r => r.toUpperCase())
: [(to.meta.role as string).toUpperCase()]
// Si el admin entra a rutas de pasajero → redirigir al panel admin
const passengerRoutes = ['/map', '/schedule', '/discover', '/transport', '/favorites', '/profile', '/coupons']
if (userRole === 'ADMIN' && passengerRoutes.some(r => to.path.startsWith(r))) {
return next('/admin')
}
// Ruta con restricción de rol → verificar permiso
if (to.meta.role) {
const allowedRoles = Array.isArray(to.meta.role)
? (to.meta.role as string[]).map(r => r.toUpperCase())
: [(to.meta.role as string).toUpperCase()]
if (!allowedRoles.includes(userRole)) {
if (userRole === 'ADMIN') return next('/admin')
else if (userRole === 'DRIVER') return next('/driver')
else if (userRole === 'PROMOTER') return next('/promoter')
else return next('/map')
}
if (!allowedRoles.includes(userRole)) {
if (userRole === 'ADMIN') return next('/admin')
else if (userRole === 'DRIVER') return next('/driver')
else if (userRole === 'PROMOTER') return next('/promoter')
else return next('/map')
}
}

View File

@ -40,19 +40,14 @@ export const useAuthStore = defineStore('auth', () => {
if (error) throw new Error(error.message)
if (data.user) {
// Establecer sesión y rol inmediatamente desde el JWT (sin esperar BD)
// Rol disponible al instante desde el JWT sin consultas BD bloqueantes
userSession.value = data.session
// Usar user_metadata como perfil temporal para que el rol esté listo al instante
userProfile.value = {
id: data.user.id,
email: data.user.email,
full_name: data.user.user_metadata?.full_name || data.user.email,
role: data.user.user_metadata?.role || 'PASSENGER'
}
// Cargar perfil completo de BD en background (sin bloquear navegación)
supabase.from('users').select('*').eq('id', data.user.id).single()
.then(({ data: profile }) => { if (profile) userProfile.value = profile })
.catch(() => { })
}
}