The web app grows its account surface: login (with next-redirect, unverified-hint + resend), signup (react-hook-form + shared Zod schemas, field-level api errors, closed-registration state fed by the new public GET /auth/registration), e-mail verification, forgot/reset password; a settings page with profile (locale applies immediately), password change, and active-session management; a Site-Admin page for instance name, default locale, and registration mode. AuthProvider holds /auth/me, applies the profile locale, and backs route guards (RequireAuth/RequireAnonymous/RequireSiteAdmin); the top bar gains a user menu. All strings ship in the new auth/settings namespaces (de+ en); the exception filter now preserves handler-specific error codes. Verified live: signup → Mailpit → verify → login → profile through the Vite proxy. Closes #16 Closes #17 Closes #18 Closes #19 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
31 lines
1011 B
TypeScript
31 lines
1011 B
TypeScript
import { Navigate, Outlet, useLocation } from 'react-router-dom';
|
|
|
|
import { useAuth } from './auth-context';
|
|
|
|
/** Wraps private routes: anonymous visitors land on /login and return after. */
|
|
export function RequireAuth(): React.JSX.Element {
|
|
const { user, isLoading } = useAuth();
|
|
const location = useLocation();
|
|
if (isLoading) return <></>;
|
|
if (!user) {
|
|
const next = encodeURIComponent(location.pathname + location.search);
|
|
return <Navigate to={`/login?next=${next}`} replace />;
|
|
}
|
|
return <Outlet />;
|
|
}
|
|
|
|
/** Wraps auth pages: signed-in users have no business on /login etc. */
|
|
export function RequireAnonymous(): React.JSX.Element {
|
|
const { user, isLoading } = useAuth();
|
|
if (isLoading) return <></>;
|
|
if (user) return <Navigate to="/" replace />;
|
|
return <Outlet />;
|
|
}
|
|
|
|
export function RequireSiteAdmin(): React.JSX.Element {
|
|
const { user, isLoading } = useAuth();
|
|
if (isLoading) return <></>;
|
|
if (!user?.isSiteAdmin) return <Navigate to="/" replace />;
|
|
return <Outlet />;
|
|
}
|