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.