Files
glchat/web/src/components/AuthGuard.tsx
T

49 lines
1.6 KiB
TypeScript
Raw Normal View History

import { Navigate, Outlet, useLocation } from 'react-router';
import { ErrorNotice, LoadingNotice } from '@/components/ui/ErrorNotice';
import { useCurrentUser } from '@/lib/hooks';
import { isUnauthorized } from '@/lib/http';
interface AuthGuardProps {
/**
* Если `true`, пользователей с незавершённым онбордингом пускаем внутрь
* (нужно для /onboarding и /settings).
*/
allowIncompleteOnboarding?: boolean;
}
/**
* Защита маршрутов: проверяет GET /users/@me.
* Неавторизованных отправляет на /login, не прошедших онбординг — на /onboarding.
*/
export function AuthGuard({ allowIncompleteOnboarding = false }: AuthGuardProps) {
const location = useLocation();
const currentUser = useCurrentUser();
if (currentUser.isPending) {
return (
<div className="flex min-h-full items-center justify-center p-6">
<LoadingNotice />
</div>
);
}
if (currentUser.isError) {
if (isUnauthorized(currentUser.error)) {
return <Navigate to="/login" replace state={{ from: location.pathname }} />;
}
return (
<div className="mx-auto flex min-h-full w-full max-w-md flex-col justify-center p-6">
<ErrorNotice error={currentUser.error} onRetry={() => void currentUser.refetch()} />
</div>
);
}
const user = currentUser.data;
if (!allowIncompleteOnboarding && !user.onboarding_completed) {
return <Navigate to="/onboarding" replace />;
}
return <Outlet context={{ user }} />;
}