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 { try {
await authStore.login(email.value.trim().toLowerCase(), password.value) await authStore.login(email.value.trim().toLowerCase(), password.value)
// El rol ya está disponible en el store (del JWT), navegar directo
// 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++
}
navigateByUserRole(authStore.role || 'PASSENGER') navigateByUserRole(authStore.role || 'PASSENGER')
} catch (error: any) { } catch (error: any) {
console.error('Error Login detallado:', error) console.error('Error Login:', error)
if (error.message.includes('Invalid login credentials')) { if (error.message?.includes('Invalid login credentials')) {
errorMessage.value = 'Correo o contraseña incorrectos.' errorMessage.value = 'Correo o contraseña incorrectos.'
} else { } else {
errorMessage.value = `Error: ${error.message || 'Error en el servidor.'}` errorMessage.value = `Error: ${error.message || 'Error desconocido.'}`
} }
} finally { } finally {
isLoading.value = false isLoading.value = false

View File

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

View File

@ -40,19 +40,14 @@ export const useAuthStore = defineStore('auth', () => {
if (error) throw new Error(error.message) if (error) throw new Error(error.message)
if (data.user) { 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 userSession.value = data.session
// Usar user_metadata como perfil temporal para que el rol esté listo al instante
userProfile.value = { userProfile.value = {
id: data.user.id, id: data.user.id,
email: data.user.email, email: data.user.email,
full_name: data.user.user_metadata?.full_name || data.user.email, full_name: data.user.user_metadata?.full_name || data.user.email,
role: data.user.user_metadata?.role || 'PASSENGER' 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(() => { })
} }
} }