mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +01:00
refactor: simplify login redirect logic (#1987)
This commit is contained in:
parent
23e43b9114
commit
ae3d6c06cf
@ -5,7 +5,7 @@ import { LayoutPicker } from 'component/layout/LayoutPicker/LayoutPicker';
|
||||
import Loader from 'component/common/Loader/Loader';
|
||||
import NotFound from 'component/common/NotFound/NotFound';
|
||||
import { ProtectedRoute } from 'component/common/ProtectedRoute/ProtectedRoute';
|
||||
import SWRProvider from 'component/providers/SWRProvider/SWRProvider';
|
||||
import { SWRProvider } from 'component/providers/SWRProvider/SWRProvider';
|
||||
import ToastRenderer from 'component/common/ToastRenderer/ToastRenderer';
|
||||
import { routes } from 'component/menu/routes';
|
||||
import { useAuthDetails } from 'hooks/api/getters/useAuth/useAuthDetails';
|
||||
@ -21,7 +21,6 @@ export const App = () => {
|
||||
const { authDetails } = useAuthDetails();
|
||||
const { user } = useAuthUser();
|
||||
const { isOss } = useUiConfig();
|
||||
const isLoggedIn = Boolean(user?.id);
|
||||
const hasFetchedAuth = Boolean(authDetails || user);
|
||||
usePlausibleTracker();
|
||||
|
||||
@ -30,7 +29,7 @@ export const App = () => {
|
||||
: routes;
|
||||
|
||||
return (
|
||||
<SWRProvider isUnauthorized={!isLoggedIn}>
|
||||
<SWRProvider>
|
||||
<Suspense fallback={<Loader />}>
|
||||
<ConditionallyRender
|
||||
condition={!hasFetchedAuth}
|
||||
|
@ -1,78 +1,18 @@
|
||||
import { mutate, SWRConfig, useSWRConfig } from 'swr';
|
||||
import { useNavigate } from 'react-router';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { formatApiPath } from 'utils/formatPath';
|
||||
import { SWRConfig } from 'swr';
|
||||
import React from 'react';
|
||||
import { USER_ENDPOINT_PATH } from 'hooks/api/getters/useAuth/useAuthEndpoint';
|
||||
import { ResponseError } from 'utils/apiUtils';
|
||||
import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser';
|
||||
|
||||
interface ISWRProviderProps {
|
||||
isUnauthorized: boolean;
|
||||
}
|
||||
export const SWRProvider: React.FC = ({ children }) => {
|
||||
const { refetchUser } = useAuthUser();
|
||||
|
||||
const INVALID_TOKEN_ERROR = 'InvalidTokenError';
|
||||
|
||||
const SWRProvider: React.FC<ISWRProviderProps> = ({
|
||||
children,
|
||||
isUnauthorized,
|
||||
}) => {
|
||||
const { cache } = useSWRConfig();
|
||||
const navigate = useNavigate();
|
||||
const { setToastApiError } = useToast();
|
||||
|
||||
// @ts-expect-error
|
||||
const handleFetchError = error => {
|
||||
if (error.status === 401) {
|
||||
const path = location.pathname;
|
||||
// Only populate user with authDetails if 401 and
|
||||
// error is not invalid token
|
||||
if (error?.info?.name !== INVALID_TOKEN_ERROR) {
|
||||
mutate(USER_ENDPOINT_PATH, { ...error.info }, false);
|
||||
}
|
||||
|
||||
if (
|
||||
path === formatApiPath('login') ||
|
||||
path === formatApiPath('new-user') ||
|
||||
path === formatApiPath('reset-password') ||
|
||||
path === formatApiPath('forgotten-password')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
cache.clear();
|
||||
|
||||
navigate('/login');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isUnauthorized) {
|
||||
setToastApiError(error.message);
|
||||
const onError = (error: Error) => {
|
||||
if (error instanceof ResponseError && error.status === 401) {
|
||||
// Refetch the user's data if they appear to be logged out.
|
||||
// This may trigger a login page redirect in ProtectedRoute.
|
||||
refetchUser();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SWRConfig
|
||||
value={{
|
||||
onErrorRetry: (
|
||||
error,
|
||||
_key,
|
||||
_config,
|
||||
revalidate,
|
||||
{ retryCount }
|
||||
) => {
|
||||
// Never retry on 404 or 401.
|
||||
if (error.status < 499) {
|
||||
return error;
|
||||
}
|
||||
|
||||
setTimeout(() => revalidate({ retryCount }), 5000);
|
||||
},
|
||||
onError: handleFetchError,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SWRConfig>
|
||||
);
|
||||
return <SWRConfig value={{ onError }}>{children}</SWRConfig>;
|
||||
};
|
||||
|
||||
export default SWRProvider;
|
||||
|
@ -1,24 +1,23 @@
|
||||
import { ResponseError } from 'utils/apiUtils';
|
||||
|
||||
const handleErrorResponses = (target: string) => async (res: Response) => {
|
||||
if (!res.ok) {
|
||||
const error = new Error(
|
||||
`An error occurred while trying to get ${target}`
|
||||
throw new ResponseError(
|
||||
target,
|
||||
res.status,
|
||||
await parseErrorResponse(res)
|
||||
);
|
||||
// Try to resolve body, but don't rethrow res.json is not a function
|
||||
try {
|
||||
// @ts-expect-error
|
||||
error.info = await res.json();
|
||||
} catch (e) {
|
||||
// @ts-expect-error
|
||||
error.info = {};
|
||||
}
|
||||
// @ts-expect-error
|
||||
error.status = res.status;
|
||||
// @ts-expect-error
|
||||
error.statusText = res.statusText;
|
||||
throw error;
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
const parseErrorResponse = async (res: Response): Promise<unknown> => {
|
||||
try {
|
||||
return await res.json();
|
||||
} catch {
|
||||
return res.statusText;
|
||||
}
|
||||
};
|
||||
|
||||
export default handleErrorResponses;
|
||||
|
@ -57,6 +57,18 @@ export class NotFoundError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export class ResponseError extends Error {
|
||||
status: number;
|
||||
body: unknown;
|
||||
|
||||
constructor(target: string, status: number, body: unknown) {
|
||||
super(`An error occurred while trying to get ${target}.`);
|
||||
this.name = 'ResponseError';
|
||||
this.status = status;
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
export const headers = {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
|
Loading…
Reference in New Issue
Block a user