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>
This commit is contained in:
@@ -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<string | null>(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 (
|
||||
<div className={styles.root}>
|
||||
<div className={styles.card}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
minHeight: "200px",
|
||||
}}
|
||||
>
|
||||
<Spinner size="large" label="Checking session…" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function handlePasswordChange(ev: ChangeEvent<HTMLInputElement>): void {
|
||||
setPassword(ev.target.value);
|
||||
setError(null);
|
||||
|
||||
@@ -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<AuthContextValue>(
|
||||
() => ({ isAuthenticated, login, logout }),
|
||||
[isAuthenticated, login, logout],
|
||||
() => ({ isAuthenticated, isValidating, login, logout }),
|
||||
[isAuthenticated, isValidating, login, logout],
|
||||
);
|
||||
|
||||
// Show loading spinner while validating session on mount.
|
||||
|
||||
Reference in New Issue
Block a user