fix: implementar manejo correcto de modo offline
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 24s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 24s
Problema crítico anterior: Cuando se perdía conexión, el sistema marcaba como "no autenticado" y DESREGISTRABA el Service Worker, destruyendo todo el contenido cacheado y volviendo la PWA inútil offline. Solución implementada: 1. useAuth.ts: - Agregar estado isOffline con listeners de navigator.onLine - Detectar offline ANTES de marcar como no autenticado - En checkAuth: si offline, mantener último estado conocido - En markUnauthenticated: NO ejecutar si estamos offline - Nuevo authStatus: 'offline' cuando sin conexión - NO desregistrar SW cuando estamos offline 2. AuthIndicator.client.vue: - Importar isOffline del composable - Agregar icono WifiOff para estado offline - Agregar textos: "Offline" / "Sin conexión. Puedes usar contenido guardado" - Estilos naranja para estado offline - En watchers: NO llamar markUnauthenticated si offline - handleClick: ignorar clicks en modo offline Ahora offline funciona correctamente: ✅ Mantiene último estado de autenticación conocido ✅ NO desregistra Service Worker ✅ Contenido cacheado permanece accesible ✅ Indicador visual claro (naranja) de modo offline ✅ La PWA es totalmente funcional sin conexión
This commit is contained in:
@@ -5,6 +5,7 @@ const authChecked = ref(true) // Iniciamos como chequeado
|
||||
const isAuthenticated = ref(true) // Asumimos autenticado al inicio (si la página cargó, es porque pasamos Authentik)
|
||||
const isCheckingAuth = ref(false)
|
||||
const lastCheckTime = ref(0)
|
||||
const isOffline = ref(false) // Estado de conexión
|
||||
|
||||
// Estado de información del usuario
|
||||
const userInfo = ref(null)
|
||||
@@ -14,7 +15,34 @@ let visibilityChangeListener: (() => void) | null = null
|
||||
let focusListener: (() => void) | null = null
|
||||
|
||||
export const useAuth = () => {
|
||||
// Detectar cambios en el estado de conexión
|
||||
if (import.meta.client) {
|
||||
const updateOnlineStatus = () => {
|
||||
const wasOffline = isOffline.value
|
||||
isOffline.value = !navigator.onLine
|
||||
|
||||
if (wasOffline && !isOffline.value) {
|
||||
console.log('[Auth] Connection restored - back online')
|
||||
} else if (!wasOffline && isOffline.value) {
|
||||
console.log('[Auth] Connection lost - now offline')
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializar estado
|
||||
updateOnlineStatus()
|
||||
|
||||
// Escuchar eventos de conexión
|
||||
window.addEventListener('online', updateOnlineStatus)
|
||||
window.addEventListener('offline', updateOnlineStatus)
|
||||
}
|
||||
|
||||
const checkAuth = async (force = false) => {
|
||||
// Si estamos offline, no hacer requests
|
||||
if (isOffline.value && !force) {
|
||||
console.log('[Auth] Skipping check - offline')
|
||||
return
|
||||
}
|
||||
|
||||
// Si ya sabemos que NO estamos autenticados, no hacer más requests
|
||||
// (evita loops innecesarios)
|
||||
if (!isAuthenticated.value && !force) {
|
||||
@@ -54,16 +82,22 @@ export const useAuth = () => {
|
||||
} catch (error: any) {
|
||||
console.warn('[Auth] Check failed:', error.message || error)
|
||||
|
||||
const wasAuthenticated = isAuthenticated.value
|
||||
// Verificar si estamos offline AHORA (pudo cambiar durante el request)
|
||||
if (!navigator.onLine) {
|
||||
console.log('[Auth] Offline detected - maintaining current auth state')
|
||||
isOffline.value = true
|
||||
// NO cambiar isAuthenticated cuando estamos offline
|
||||
// Mantener el último estado conocido
|
||||
} else {
|
||||
// Online pero el fetch falló = problema de autenticación
|
||||
const wasAuthenticated = isAuthenticated.value
|
||||
console.log('[Auth] Online but fetch failed - marking as unauthenticated')
|
||||
isAuthenticated.value = false
|
||||
authChecked.value = true
|
||||
|
||||
// Si el fetch falla completamente (CORS, redirect, etc), asumir no autenticado
|
||||
// Esto pasa cuando Authentik redirige antes de que el endpoint pueda responder
|
||||
console.log('[Auth] Fetch failed - marking as unauthenticated')
|
||||
isAuthenticated.value = false
|
||||
authChecked.value = true
|
||||
|
||||
if (wasAuthenticated) {
|
||||
console.log('[Auth] Status changed: authenticated → unauthenticated')
|
||||
if (wasAuthenticated) {
|
||||
console.log('[Auth] Status changed: authenticated → unauthenticated')
|
||||
}
|
||||
}
|
||||
|
||||
lastCheckTime.value = now
|
||||
@@ -129,6 +163,14 @@ export const useAuth = () => {
|
||||
|
||||
const markUnauthenticated = async () => {
|
||||
// Helper para marcar como no autenticado (útil cuando detectamos 401/403)
|
||||
// IMPORTANTE: NO llamar esto si estamos offline, solo si hay un error real de auth
|
||||
|
||||
// Si estamos offline, NO marcar como no autenticado
|
||||
if (isOffline.value || !navigator.onLine) {
|
||||
console.log('[Auth] Skipping markUnauthenticated - offline mode')
|
||||
return
|
||||
}
|
||||
|
||||
console.log('[Auth] Marking as unauthenticated')
|
||||
isAuthenticated.value = false
|
||||
authChecked.value = true
|
||||
@@ -198,6 +240,8 @@ export const useAuth = () => {
|
||||
}
|
||||
|
||||
const authStatus = computed(() => {
|
||||
// Si estamos offline, mostrar estado offline
|
||||
if (isOffline.value) return 'offline'
|
||||
if (!authChecked.value) return 'unknown'
|
||||
return isAuthenticated.value ? 'authenticated' : 'unauthenticated'
|
||||
})
|
||||
@@ -206,6 +250,7 @@ export const useAuth = () => {
|
||||
isAuthenticated,
|
||||
authChecked,
|
||||
isCheckingAuth,
|
||||
isOffline,
|
||||
authStatus,
|
||||
userInfo,
|
||||
checkAuth,
|
||||
|
||||
Reference in New Issue
Block a user