mirror of
https://github.com/stefanpejcic/openpanel
synced 2025-06-26 18:28:26 +00:00
fork refine
This commit is contained in:
522
packages/core/src/components/authenticated/index.spec.tsx
Normal file
522
packages/core/src/components/authenticated/index.spec.tsx
Normal file
@@ -0,0 +1,522 @@
|
||||
import React from "react";
|
||||
import { act, waitFor } from "@testing-library/react";
|
||||
|
||||
import {
|
||||
MockJSONServer,
|
||||
mockLegacyRouterProvider,
|
||||
render,
|
||||
TestWrapper,
|
||||
} from "@test";
|
||||
|
||||
import { Authenticated } from "./";
|
||||
import { AuthProvider } from "src/interfaces";
|
||||
|
||||
const legacyMockAuthProvider = {
|
||||
login: () => Promise.resolve(),
|
||||
logout: () => Promise.resolve(),
|
||||
checkError: () => Promise.resolve(),
|
||||
checkAuth: () => Promise.resolve(),
|
||||
getPermissions: () => Promise.resolve(["admin"]),
|
||||
getUserIdentity: () => Promise.resolve(),
|
||||
};
|
||||
|
||||
const mockReplace = jest.fn();
|
||||
|
||||
const mockLegacyRouter = {
|
||||
...mockLegacyRouterProvider(),
|
||||
useHistory: () => ({
|
||||
replace: mockReplace,
|
||||
}),
|
||||
useLocation: () => ({
|
||||
pathname: "/posts",
|
||||
search: "",
|
||||
}),
|
||||
};
|
||||
|
||||
const mockAuthProvider: AuthProvider = {
|
||||
login: () =>
|
||||
Promise.resolve({
|
||||
success: true,
|
||||
}),
|
||||
logout: () => Promise.resolve({ success: true }),
|
||||
onError: () => Promise.resolve({}),
|
||||
check: () => Promise.resolve({ authenticated: true }),
|
||||
getPermissions: () => Promise.resolve(),
|
||||
};
|
||||
|
||||
describe("v3LegacyAuthProviderCompatible Authenticated", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(console, "error").mockImplementation((message) => {
|
||||
if (typeof message !== "undefined") console.warn(message);
|
||||
});
|
||||
});
|
||||
|
||||
it("should render children successfully", async () => {
|
||||
const { getByText } = render(
|
||||
<Authenticated
|
||||
key="should-render-children-legacy"
|
||||
v3LegacyAuthProviderCompatible={true}
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
legacyAuthProvider: legacyMockAuthProvider,
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => getByText("Custom Authenticated"));
|
||||
});
|
||||
|
||||
it("not authenticated test", async () => {
|
||||
const { queryByText } = render(
|
||||
<Authenticated
|
||||
key="not-authenticated-legacy"
|
||||
v3LegacyAuthProviderCompatible={true}
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
legacyAuthProvider: {
|
||||
...legacyMockAuthProvider,
|
||||
checkAuth: () => Promise.reject(),
|
||||
},
|
||||
legacyRouterProvider: mockLegacyRouter,
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByText("Custom Authenticated")).toBeNull();
|
||||
expect(mockReplace).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
it("not authenticated fallback component test", async () => {
|
||||
legacyMockAuthProvider.checkAuth = jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.reject());
|
||||
|
||||
const { queryByText } = render(
|
||||
<Authenticated
|
||||
key="fallback-component-test"
|
||||
fallback={<div>Error fallback</div>}
|
||||
v3LegacyAuthProviderCompatible={true}
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
legacyAuthProvider: legacyMockAuthProvider,
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("Error fallback"));
|
||||
});
|
||||
});
|
||||
|
||||
it("loading test", async () => {
|
||||
legacyMockAuthProvider.checkAuth = jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.reject());
|
||||
|
||||
const { queryByText } = render(
|
||||
<Authenticated
|
||||
key="loading-test"
|
||||
loading={<div>loading</div>}
|
||||
v3LegacyAuthProviderCompatible={true}
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
legacyAuthProvider: legacyMockAuthProvider,
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("loading"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Authenticated", () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(console, "error").mockImplementation((message) => {
|
||||
if (typeof message !== "undefined") console.warn(message);
|
||||
});
|
||||
});
|
||||
|
||||
it("should render children successfully", async () => {
|
||||
const { getByText } = render(
|
||||
<Authenticated key="render-children-successfully">
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: mockAuthProvider,
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => getByText("Custom Authenticated"));
|
||||
});
|
||||
|
||||
it("not authenticated test", async () => {
|
||||
const { queryByText } = render(
|
||||
<Authenticated key="not-authenticated-test">
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: {
|
||||
...mockAuthProvider,
|
||||
check: () => Promise.resolve({ authenticated: false }),
|
||||
},
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
legacyRouterProvider: mockLegacyRouter,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(queryByText("Custom Authenticated")).toBeNull();
|
||||
expect(mockReplace).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
it("not authenticated fallback component test", async () => {
|
||||
mockAuthProvider.check = jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
authenticated: false,
|
||||
error: new Error("Not authenticated"),
|
||||
}),
|
||||
);
|
||||
|
||||
const { queryByText } = render(
|
||||
<Authenticated
|
||||
key="not-authenticated-fallback-component-test"
|
||||
fallback={<div>Error fallback</div>}
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: mockAuthProvider,
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("Error fallback"));
|
||||
});
|
||||
});
|
||||
|
||||
it("loading test", async () => {
|
||||
const { queryByText } = render(
|
||||
<Authenticated key="loading-test" loading={<div>loading</div>}>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: mockAuthProvider,
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("loading"));
|
||||
});
|
||||
});
|
||||
|
||||
it("should redirect to `/my-path` if not authenticated (authProvider's check)", async () => {
|
||||
const mockGo = jest.fn();
|
||||
|
||||
const { queryByText } = render(
|
||||
<Authenticated key="should-redirect-custom-provider-check">
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: {
|
||||
...mockAuthProvider,
|
||||
check: async () => {
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/my-path",
|
||||
};
|
||||
},
|
||||
},
|
||||
routerProvider: {
|
||||
go: () => mockGo,
|
||||
},
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("Custom Authenticated")).toBeNull();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockGo).toBeCalledWith(
|
||||
expect.objectContaining({ to: "/my-path", type: "replace" }),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("should redirect to `/my-path` if not authenticated (`redirectOnFail` prop)", async () => {
|
||||
const mockGo = jest.fn();
|
||||
|
||||
const { queryByText } = render(
|
||||
<Authenticated
|
||||
key="should-redirect-custom-on-fail"
|
||||
redirectOnFail="/my-path"
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: {
|
||||
...mockAuthProvider,
|
||||
check: async () => {
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/other-path",
|
||||
};
|
||||
},
|
||||
},
|
||||
routerProvider: {
|
||||
go: () => mockGo,
|
||||
},
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("Custom Authenticated")).toBeNull();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockGo).toBeCalledWith(
|
||||
expect.objectContaining({ to: "/my-path", type: "replace" }),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("should redirect to `/my-path` if not authenticated (navigate in fallback)", async () => {
|
||||
const mockGo = jest.fn();
|
||||
|
||||
const NavigateComp = ({ to }: { to: string }) => {
|
||||
React.useEffect(() => {
|
||||
mockGo({ to, type: "replace" });
|
||||
}, [to]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const { queryByText } = render(
|
||||
<Authenticated
|
||||
key="should-redirect-fallback"
|
||||
fallback={<NavigateComp to="/my-path" />}
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: {
|
||||
...mockAuthProvider,
|
||||
check: async () => {
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/other-path",
|
||||
};
|
||||
},
|
||||
},
|
||||
routerProvider: {
|
||||
go: () => mockGo,
|
||||
},
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("Custom Authenticated")).toBeNull();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockGo).toBeCalledWith(
|
||||
expect.objectContaining({ to: "/my-path", type: "replace" }),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("should redirect to `/my-path?to=/dashboard?current=1&pageSize=2` if not authenticated (`redirectOnFail` with append query)", async () => {
|
||||
const mockGo = jest.fn();
|
||||
|
||||
const currentQuery = {
|
||||
current: 1,
|
||||
pageSize: 2,
|
||||
};
|
||||
|
||||
const currentPathname = "dashboard";
|
||||
|
||||
const { queryByText } = render(
|
||||
<Authenticated
|
||||
key="should-redirect-with-to"
|
||||
redirectOnFail="/my-path"
|
||||
appendCurrentPathToQuery
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: {
|
||||
...mockAuthProvider,
|
||||
check: async () => {
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/other-path",
|
||||
};
|
||||
},
|
||||
},
|
||||
routerProvider: {
|
||||
go: () => {
|
||||
return (config) => {
|
||||
if (config.type === "path") {
|
||||
const params = new URLSearchParams(
|
||||
currentQuery as any,
|
||||
);
|
||||
return `/${config.to}?${params.toString()}`;
|
||||
} else {
|
||||
return mockGo(config);
|
||||
}
|
||||
};
|
||||
},
|
||||
parse: () => {
|
||||
return () => ({
|
||||
pathname: currentPathname,
|
||||
params: currentQuery,
|
||||
});
|
||||
},
|
||||
},
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("Custom Authenticated")).toBeNull();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockGo).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
to: "/my-path",
|
||||
query: {
|
||||
to: "/dashboard?current=1&pageSize=2",
|
||||
},
|
||||
type: "replace",
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it("should redirect to `/my-path?to=/dashboard?current=1&pageSize=2` if not authenticated (authProvider's check with append query)", async () => {
|
||||
const mockGo = jest.fn();
|
||||
|
||||
const currentQuery = {
|
||||
current: 1,
|
||||
pageSize: 2,
|
||||
};
|
||||
|
||||
const currentPathname = "dashboard";
|
||||
|
||||
const { queryByText } = render(
|
||||
<Authenticated
|
||||
key="should-redirect-path-from-provider"
|
||||
appendCurrentPathToQuery
|
||||
>
|
||||
Custom Authenticated
|
||||
</Authenticated>,
|
||||
{
|
||||
wrapper: TestWrapper({
|
||||
dataProvider: MockJSONServer,
|
||||
authProvider: {
|
||||
...mockAuthProvider,
|
||||
check: async () => {
|
||||
return {
|
||||
authenticated: false,
|
||||
redirectTo: "/my-path",
|
||||
};
|
||||
},
|
||||
},
|
||||
routerProvider: {
|
||||
go: () => {
|
||||
return (config) => {
|
||||
if (config.type === "path") {
|
||||
const params = new URLSearchParams(
|
||||
currentQuery as any,
|
||||
);
|
||||
return `/${config.to}?${params.toString()}`;
|
||||
} else {
|
||||
return mockGo(config);
|
||||
}
|
||||
};
|
||||
},
|
||||
parse: () => {
|
||||
return () => ({
|
||||
pathname: currentPathname,
|
||||
params: currentQuery,
|
||||
});
|
||||
},
|
||||
},
|
||||
resources: [{ name: "posts", route: "posts" }],
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(queryByText("Custom Authenticated")).toBeNull();
|
||||
});
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockGo).toBeCalledWith(
|
||||
expect.objectContaining({
|
||||
to: "/my-path",
|
||||
query: {
|
||||
to: "/dashboard?current=1&pageSize=2",
|
||||
},
|
||||
type: "replace",
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
222
packages/core/src/components/authenticated/index.tsx
Normal file
222
packages/core/src/components/authenticated/index.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
useGo,
|
||||
useNavigation,
|
||||
useParsed,
|
||||
useRouterContext,
|
||||
useRouterType,
|
||||
useIsAuthenticated,
|
||||
} from "@hooks";
|
||||
import { useActiveAuthProvider } from "@definitions/index";
|
||||
import { GoConfig } from "src/interfaces";
|
||||
|
||||
export type AuthenticatedCommonProps = {
|
||||
/**
|
||||
* Unique key to identify the component.
|
||||
* This is required if you have multiple `Authenticated` components at the same level.
|
||||
* @required
|
||||
*/
|
||||
key: React.Key;
|
||||
/**
|
||||
* Whether to redirect user if not logged in or not.
|
||||
* If not set, user will be redirected to `redirectTo` property of the `check` function's response.
|
||||
* This behavior is only available for new auth providers.
|
||||
* Legacy auth providers will redirect to `/login` by default if this property is not set.
|
||||
* If set to a string, user will be redirected to that string.
|
||||
*
|
||||
* This property only works if `fallback` is **not set**.
|
||||
*/
|
||||
redirectOnFail?: string | true;
|
||||
/**
|
||||
* Whether to append current path to search params of the redirect url at `to` property.
|
||||
*
|
||||
* By default, `to` parameter is used by successful invocations of the `useLogin` hook.
|
||||
* If `to` present, it will be used as the redirect url after successful login.
|
||||
*/
|
||||
appendCurrentPathToQuery?: boolean;
|
||||
/**
|
||||
* Content to show if user is not logged in.
|
||||
*/
|
||||
fallback?: React.ReactNode;
|
||||
/**
|
||||
* Content to show while checking whether user is logged in or not.
|
||||
*/
|
||||
loading?: React.ReactNode;
|
||||
/**
|
||||
* Content to show if user is logged in
|
||||
*/
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
export type LegacyAuthenticatedProps = {
|
||||
v3LegacyAuthProviderCompatible: true;
|
||||
} & AuthenticatedCommonProps;
|
||||
|
||||
export type AuthenticatedProps = {
|
||||
v3LegacyAuthProviderCompatible?: false;
|
||||
} & AuthenticatedCommonProps;
|
||||
|
||||
/**
|
||||
* `<Authenticated>` is the component form of {@link https://refine.dev/docs/api-reference/core/hooks/auth/useAuthenticated `useAuthenticated`}. It internally uses `useAuthenticated` to provide it's functionality.
|
||||
*
|
||||
* @requires {@link https://react.dev/learn/rendering-lists#why-does-react-need-keys `key`} prop if you have multiple components at the same level.
|
||||
* In React, components don't automatically unmount and remount with prop changes, which is generally good for performance. However, for specific cases this can cause issues like unwanted content rendering (`fallback` or `children`). To solve this, assigning unique `key` values to each instance of component is necessary, forcing React to unmount and remount the component, rather than just updating its props.
|
||||
* @example
|
||||
*```tsx
|
||||
* <Authenticated key="dashboard">
|
||||
* <h1>Dashboard Page</h1>
|
||||
* </Authenticated>
|
||||
*```
|
||||
*
|
||||
* @see {@link https://refine.dev/docs/core/components/auth/authenticated `<Authenticated>`} component for more details.
|
||||
*/
|
||||
export function Authenticated(
|
||||
props: LegacyAuthenticatedProps,
|
||||
): JSX.Element | null;
|
||||
|
||||
/**
|
||||
* `<Authenticated>` is the component form of {@link https://refine.dev/docs/api-reference/core/hooks/auth/useAuthenticated `useAuthenticated`}. It internally uses `useAuthenticated` to provide it's functionality.
|
||||
*
|
||||
* @requires {@link https://react.dev/learn/rendering-lists#why-does-react-need-keys `key`} prop if you have multiple components at the same level.
|
||||
* In React, components don't automatically unmount and remount with prop changes, which is generally good for performance. However, for specific cases this can cause issues like unwanted content rendering (`fallback` or `children`). To solve this, assigning unique `key` values to each instance of component is necessary, forcing React to unmount and remount the component, rather than just updating its props.
|
||||
* @example
|
||||
*```tsx
|
||||
* <Authenticated key="dashboard">
|
||||
* <h1>Dashboard Page</h1>
|
||||
* </Authenticated>
|
||||
*```
|
||||
*
|
||||
* @see {@link https://refine.dev/docs/core/components/auth/authenticated `<Authenticated>`} component for more details.
|
||||
*/
|
||||
export function Authenticated(props: AuthenticatedProps): JSX.Element | null;
|
||||
|
||||
export function Authenticated({
|
||||
redirectOnFail = true,
|
||||
appendCurrentPathToQuery = true,
|
||||
children,
|
||||
fallback: fallbackContent,
|
||||
loading: loadingContent,
|
||||
}: AuthenticatedProps | LegacyAuthenticatedProps): JSX.Element | null {
|
||||
const activeAuthProvider = useActiveAuthProvider();
|
||||
const routerType = useRouterType();
|
||||
|
||||
const hasAuthProvider = Boolean(activeAuthProvider?.isProvided);
|
||||
const isLegacyAuth = Boolean(activeAuthProvider?.isLegacy);
|
||||
const isLegacyRouter = routerType === "legacy";
|
||||
|
||||
const parsed = useParsed();
|
||||
const go = useGo();
|
||||
const { useLocation } = useRouterContext();
|
||||
const legacyLocation = useLocation();
|
||||
|
||||
const {
|
||||
isFetching,
|
||||
isSuccess,
|
||||
data: {
|
||||
authenticated: isAuthenticatedStatus,
|
||||
redirectTo: authenticatedRedirect,
|
||||
} = {},
|
||||
} = useIsAuthenticated({
|
||||
v3LegacyAuthProviderCompatible: isLegacyAuth,
|
||||
});
|
||||
|
||||
// Authentication status
|
||||
const isAuthenticated = hasAuthProvider
|
||||
? isLegacyAuth
|
||||
? isSuccess
|
||||
: isAuthenticatedStatus
|
||||
: true;
|
||||
|
||||
// when there is no auth provider
|
||||
if (!hasAuthProvider) {
|
||||
return <>{children ?? null}</>;
|
||||
}
|
||||
|
||||
// when checking authentication status
|
||||
if (isFetching) {
|
||||
return <>{loadingContent ?? null}</>;
|
||||
}
|
||||
|
||||
// when user is authenticated return children
|
||||
if (isAuthenticated) {
|
||||
return <>{children ?? null}</>;
|
||||
}
|
||||
// when user is not authenticated redirect or render fallbackContent
|
||||
else {
|
||||
// render fallbackContent if it is exist
|
||||
if (typeof fallbackContent !== "undefined") {
|
||||
return <>{fallbackContent ?? null}</>;
|
||||
}
|
||||
// if there is no fallbackContent, redirect page
|
||||
|
||||
// Redirect url to use. use redirectOnFail if it is set.
|
||||
// Otherwise use redirectTo property of the check function's response.
|
||||
// If both are not set, use `/login` as the default redirect url. (only for legacy auth providers)
|
||||
const appliedRedirect = isLegacyAuth
|
||||
? typeof redirectOnFail === "string"
|
||||
? redirectOnFail
|
||||
: "/login"
|
||||
: typeof redirectOnFail === "string"
|
||||
? redirectOnFail
|
||||
: (authenticatedRedirect as string | undefined);
|
||||
|
||||
// Current pathname to append to the redirect url.
|
||||
// User will be redirected to this url after successful mutation. (like login)
|
||||
const pathname = `${
|
||||
isLegacyRouter ? legacyLocation?.pathname : parsed.pathname
|
||||
}`.replace(/(\?.*|#.*)$/, "");
|
||||
// Redirect if appliedRedirect is set, otherwise return null.
|
||||
// Uses `replace` for legacy router and `go` for new router.
|
||||
if (appliedRedirect) {
|
||||
if (isLegacyRouter) {
|
||||
const toQuery = appendCurrentPathToQuery
|
||||
? `?to=${encodeURIComponent(pathname)}`
|
||||
: "";
|
||||
return <RedirectLegacy to={`${appliedRedirect}${toQuery}`} />;
|
||||
} else {
|
||||
return (
|
||||
<Redirect
|
||||
config={{
|
||||
to: appliedRedirect,
|
||||
query: appendCurrentPathToQuery
|
||||
? {
|
||||
to: parsed.params?.to
|
||||
? parsed.params.to
|
||||
: go({
|
||||
to: pathname,
|
||||
options: { keepQuery: true },
|
||||
type: "path",
|
||||
}),
|
||||
}
|
||||
: undefined,
|
||||
type: "replace",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const Redirect = ({ config }: { config: GoConfig }) => {
|
||||
const go = useGo();
|
||||
|
||||
React.useEffect(() => {
|
||||
go(config);
|
||||
}, [go, config]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const RedirectLegacy = ({ to }: { to: string }) => {
|
||||
const { replace } = useNavigation();
|
||||
|
||||
React.useEffect(() => {
|
||||
replace(to);
|
||||
}, [replace, to]);
|
||||
|
||||
return null;
|
||||
};
|
||||
Reference in New Issue
Block a user