Skip to content

Commit

Permalink
Add SignedOutOrRedirect
Browse files Browse the repository at this point in the history
  • Loading branch information
jcao49 committed Jul 24, 2023
1 parent 095042f commit 4a36317
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 0 deletions.
59 changes: 59 additions & 0 deletions packages/react/spec/components/auth/SignedOutOrRedirect.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import "@testing-library/jest-dom";
import { render } from "@testing-library/react";
import React from "react";
import { superAuthApi } from "../../apis";
import { TestWrapper } from "../../testWrapper";
import { expectMockDeletedUser, expectMockSignedInUser, expectMockSignedOutUser } from "../../utils";
import { SignedOutOrRedirect } from "../../../src/components/auth/SignedOutOrRedirect";

describe("SignedOutOrRedirect", () => {
const { location } = window;
const mockAssign = jest.fn();

beforeAll(() => {
// @ts-expect-error mock
delete window.location;
// @ts-expect-error mock
window.location = { assign: mockAssign, origin: "https://test-app.gadget.app", pathname: "/" };
});

afterEach(() => {
mockAssign.mockClear();
});

afterAll(() => {
window.location = location;
});

test("redirects when signed in", () => {
const component = (
<h1>
<SignedOutOrRedirect>Hello, Jane!</SignedOutOrRedirect>
</h1>
);

const { rerender } = render(component, { wrapper: TestWrapper(superAuthApi) });

expectMockSignedInUser();
rerender(component);

expect(mockAssign).toHaveBeenCalledTimes(1);
expect(mockAssign).toHaveBeenCalledWith("https://test-app.gadget.app/?redirectTo=%2F");
});

test("renders when signed out", () => {
const component = (
<h1>
<SignedOutOrRedirect>Hello, Jane!</SignedOutOrRedirect>
</h1>
);

const { container, rerender } = render(component, { wrapper: TestWrapper(superAuthApi) });

expectMockSignedOutUser();
rerender(component);

expect(mockAssign).not.toBeCalled();
expect(container.outerHTML).toMatchInlineSnapshot(`"<div><h1>Hello, Jane!</h1></div>"`);
});
});
30 changes: 30 additions & 0 deletions packages/react/src/components/auth/SignedOutOrRedirect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { ReactNode } from "react";
import React, { useContext, useEffect, useState } from "react";
import { GadgetConfigurationContext } from "../../../src/GadgetProvider";
import { useAuth } from "../../auth/useAuth";

/**
* Renders its `children` if the current `Session` is signed out, otherwise redirects the browser to the `signOutPath` configured in the `Provider`. Uses `window.location.assign` to perform the redirect.
*/
export const SignedOutOrRedirect = (props: { children: ReactNode }) => {
const [redirected, setRedirected] = useState(false);

const { user, isSignedIn } = useAuth();
const context = useContext(GadgetConfigurationContext);
const { auth } = context ?? {};

useEffect(() => {
if (auth && !redirected && (isSignedIn || user)) {
setRedirected(true);
const redirectUrl = new URL(auth.signInPath, window.location.origin);
redirectUrl.searchParams.set("redirectTo", window.location.pathname);
window.location.assign(redirectUrl.toString());
}
}, [redirected, isSignedIn, auth]);

if (!user && !isSignedIn) {
return <>{props.children}</>;
} else {
return null;
}
};

0 comments on commit 4a36317

Please sign in to comment.