fix: refactor logout to use synchronous flow with full page redirect

- Rewrite logout() from async to synchronous to prevent React re-renders with stale state
- Replace router.push('/login') with redirectToLogin() (window.location.replace) in all page auth guards for reliable navigation in Edge/Safari
- Add performFullLogout() helper that clears auth state, feature stores, and localStorage
- Fix persist middleware partialize to return {} when not authenticated, preventing state resurrection
- Use keepalive fetch for background cookie/token cleanup so redirect fires immediately
- Remove unused useRouter imports from page.tsx and contacts/page.tsx
- Simplify all page logout handlers to directly call logout()

Fixes #63
This commit is contained in:
Linus Rath
2026-03-21 20:45:17 +01:00
parent c73940e22a
commit 4c2d185be4
7 changed files with 104 additions and 233 deletions
+5 -5
View File
@@ -44,7 +44,7 @@ import { FilesSettingsComponent } from '@/components/settings/files-settings';
import { ContactsSettings } from '@/components/settings/contacts-settings';
import { SmimeSettings } from '@/components/settings/smime-settings';
import { SidebarAppsSettings } from '@/components/settings/sidebar-apps-settings';
import { useAuthStore } from '@/stores/auth-store';
import { useAuthStore, redirectToLogin } from '@/stores/auth-store';
import { useEmailStore } from '@/stores/email-store';
import { useIsDesktop } from '@/hooks/use-media-query';
import { NavigationRail } from '@/components/layout/navigation-rail';
@@ -122,9 +122,9 @@ export default function SettingsPage() {
useEffect(() => {
if (initialCheckDone && !isAuthenticated && !authLoading) {
try { sessionStorage.setItem('redirect_after_login', window.location.pathname); } catch { /* ignore */ }
router.push('/login');
redirectToLogin();
}
}, [initialCheckDone, isAuthenticated, authLoading, router]);
}, [initialCheckDone, isAuthenticated, authLoading]);
if (!isAuthenticated) {
return null;
@@ -286,7 +286,7 @@ export default function SettingsPage() {
{/* Logout */}
<div className="border-t border-border px-5 py-3">
<button
onClick={() => { logout(); if (!useAuthStore.getState().isAuthenticated) router.push('/login'); }}
onClick={logout}
className="w-full flex items-center gap-3 py-2.5 text-sm text-destructive hover:bg-muted rounded-md px-2 transition-colors duration-150"
>
<LogOut className="w-4 h-4" />
@@ -317,7 +317,7 @@ export default function SettingsPage() {
collapsed
quota={quota}
isPushConnected={isPushConnected}
onLogout={() => { logout(); if (!useAuthStore.getState().isAuthenticated) router.push('/login'); }}
onLogout={logout}
onManageApps={handleManageApps}
onInlineApp={handleInlineApp}
onCloseInlineApp={closeInlineApp}