fix: implementar manejo correcto de modo offline
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:
2025-10-17 04:21:31 -06:00
parent 40945dc634
commit eedff715d4
2 changed files with 89 additions and 11 deletions

View File

@@ -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,