From fc5f44ebe45e75f6dd3a6f37a1a0f063a67a93a4 Mon Sep 17 00:00:00 2001 From: Lukas Date: Thu, 30 Apr 2026 21:02:49 +0200 Subject: [PATCH] Add session validation UI and expose isValidating in auth context - LoginPage now shows a loading spinner while validating the session - Redirect to dashboard automatically once validation completes and session is valid - Expose isValidating state through AuthProvider for components to track validation status - Update useAuth hook to return isValidating along with isAuthenticated Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- frontend/src/pages/LoginPage.tsx | 31 +++++++++++++++++++++++-- frontend/src/providers/AuthProvider.tsx | 6 +++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index 09178f2..5a079cd 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -6,7 +6,7 @@ * parameter) or the dashboard. */ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { Button, Field, @@ -75,7 +75,7 @@ export function LoginPage(): React.JSX.Element { const styles = useStyles(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); - const { login } = useAuth(); + const { login, isAuthenticated, isValidating } = useAuth(); const [password, setPassword] = useState(""); const [error, setError] = useState(null); @@ -84,6 +84,33 @@ export function LoginPage(): React.JSX.Element { const next = searchParams.get("next") ?? ""; const safePath = /^\/(?!\/)/.test(next) ? next : "/"; + // Redirect to dashboard if session is valid and validation is complete + useEffect(() => { + if (isAuthenticated && !isValidating) { + navigate(safePath, { replace: true }); + } + }, [isAuthenticated, isValidating, navigate, safePath]); + + // Show loading state while validating session + if (isValidating) { + return ( +
+
+
+ +
+
+
+ ); + } + function handlePasswordChange(ev: ChangeEvent): void { setPassword(ev.target.value); setError(null); diff --git a/frontend/src/providers/AuthProvider.tsx b/frontend/src/providers/AuthProvider.tsx index efb7c16..bb69f88 100644 --- a/frontend/src/providers/AuthProvider.tsx +++ b/frontend/src/providers/AuthProvider.tsx @@ -62,6 +62,8 @@ import { useSessionValidation } from "../hooks/useSessionValidation"; export interface AuthContextValue { /** `true` when the backend considers the session valid. */ isAuthenticated: boolean; + /** `true` while the session is being validated on app mount. */ + isValidating: boolean; /** * Authenticate with the master password. * Throws an `ApiError` on failure. @@ -216,8 +218,8 @@ export function AuthProvider({ }, []); const value = useMemo( - () => ({ isAuthenticated, login, logout }), - [isAuthenticated, login, logout], + () => ({ isAuthenticated, isValidating, login, logout }), + [isAuthenticated, isValidating, login, logout], ); // Show loading spinner while validating session on mount.