Files
lib-auth/react/AuthGuard.tsx

63 lines
1.4 KiB
TypeScript

import { useEffect, useState } from "react";
import { Center, Spinner } from "./chakra-compat";
import { Navigate } from "react-router";
type AuthGuardProps = {
children: React.ReactNode;
fetchCurrentUser: () => Promise<unknown>;
redirectTo?: string;
loadingFallback?: React.ReactNode;
authenticatedWrapper?: (children: React.ReactNode) => React.ReactNode;
};
export function AuthGuard({
children,
fetchCurrentUser,
redirectTo = "/login",
loadingFallback,
authenticatedWrapper
}: AuthGuardProps) {
const [state, setState] = useState<{ loading: boolean; authenticated: boolean }>({
loading: true,
authenticated: false
});
useEffect(() => {
let cancelled = false;
fetchCurrentUser()
.then(() => {
if (!cancelled) {
setState({ loading: false, authenticated: true });
}
})
.catch(() => {
if (!cancelled) {
setState({ loading: false, authenticated: false });
}
});
return () => {
cancelled = true;
};
}, [fetchCurrentUser]);
if (state.loading) {
return (
<>
{loadingFallback ?? (
<Center h="var(--app-height)">
<Spinner size="xl" />
</Center>
)}
</>
);
}
if (!state.authenticated) {
return <Navigate to={redirectTo} replace />;
}
return <>{authenticatedWrapper ? authenticatedWrapper(children) : children}</>;
}