From 319ac5f58646c6a1a849c8ea75a048a0cd5eef67 Mon Sep 17 00:00:00 2001 From: Nora Date: Mon, 22 Jun 2026 15:12:43 -0600 Subject: [PATCH] feat(auth): RequireAuth route guard --- src/auth/RequireAuth.tsx | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/auth/RequireAuth.tsx diff --git a/src/auth/RequireAuth.tsx b/src/auth/RequireAuth.tsx new file mode 100644 index 0000000..040de56 --- /dev/null +++ b/src/auth/RequireAuth.tsx @@ -0,0 +1,43 @@ +import { Navigate, useLocation } from "react-router-dom"; +import { useAuth } from "./useAuth"; +import type { ReactNode } from "react"; + +/** + * Route guard. Wrap any subtree that requires a logged-in operator: + * + * }> + * } /> + * ... + * + * + * Three branches, in priority order: + * + * 1. `status === "loading"` → render a centered "Loading…" + * placeholder so we don't bounce the user to /login before the + * cookie has had a chance to prove itself via /api/auth/me. + * 2. `status === "unauthenticated"` → redirect to + * `/login?next=`. The Login page reads + * `next` and bounces the operator back here on success. + * 3. otherwise → render children (status is + * "authenticated"). + */ +export function RequireAuth({ children }: { children: ReactNode }) { + const { status } = useAuth(); + const location = useLocation(); + if (status === "loading") { + return ( +
+ Loading… +
+ ); + } + if (status === "unauthenticated") { + return ( + + ); + } + return <>{children}; +}