Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1644 login redirect functionality #1725

Merged
merged 9 commits into from
Jun 28, 2023
42 changes: 35 additions & 7 deletions app/components/Layout/Navigation.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can do a bit of refactoring on lines 37 through 54, something like:

  let rightSide = isLoggedIn ? (
    <>
      {userProfileComponent}
      <LogoutForm />
    </>
  ) : (
    router.pathname !== "/" && (
      <div
        style={{
          display: "flex",
          flexDirection: "row",
          gap: "1.25em",
        }}
      >
        <LoginForm />
        {showExternalOperatorsLogin && <LoginForm isExternal={true} />}
      </div>
    )
  );

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! Changed!

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import LogoutForm from "components/Session/LogoutForm";
import SubHeader from "./SubHeader";
import { useRouter } from "next/router";

import LoginForm from "components/Session/LoginForm";
import useShowGrowthbookFeature from "lib/growthbookWrapper";

interface Props {
isLoggedIn?: boolean;
alwaysShowSubheader?: boolean;
Expand All @@ -24,15 +27,38 @@ const Navigation: React.FC<Props> = ({
title = "CleanBC Industry Fund",
userProfileComponent,
links,
hideLoginButton,
}) => {
let rightSide = isLoggedIn && (
<>
{userProfileComponent}
<LogoutForm />
</>
);
// Growthbook - external-operators
const showExternalOperatorsLogin =
useShowGrowthbookFeature("external-operators");

const router = useRouter();

let rightSide = null;

if (isLoggedIn) {
rightSide = (
<>
{userProfileComponent}
<LogoutForm />
</>
);
} else if (!hideLoginButton) {
rightSide = router.pathname !== "/" && (
<div
style={{
display: "flex",
flexDirection: "row",
gap: "1.25em",
}}
>
<LoginForm />
{showExternalOperatorsLogin && <LoginForm isExternal={true} />}
</div>
);
}

const unauthorizedIdir = title === "Access required";

return (
Expand All @@ -46,7 +72,9 @@ const Navigation: React.FC<Props> = ({
*/}
<a
href={
router.pathname.includes("/cif-external")
!isLoggedIn
? "/"
: router.pathname.includes("/cif-external")
? "/cif-external"
: "/cif"
}
Expand Down
32 changes: 21 additions & 11 deletions app/components/Session/LoginForm.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can also simplify things here a little bit and have less code to maintain:

      <form id="login-buttons" action={loginURI} method="post">
        <Button
          type="submit"
          variant={
            router.pathname.includes("login-redirect")
              ? "secondary-inverse"
              : isExternal && "secondary"
          }
        >
          {isExternal ? "External User Login" : "Administrator Login"}
        </Button>
      </form>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! Changed!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we need to tweak loginURI too, currently, this part of the AC is not in place:
Then I am redirected back to the page I was trying to get to.
I've played with the code and something like this could be a solution:

  let loginURI = "/login";

  if (router.query.redirectTo)
    loginURI += `?redirectTo=${encodeURIComponent(
      router.query.redirectTo as string
    )}`;
  else if (isExternal)
    loginURI += `?redirectTo=${encodeURIComponent(
      getExternalUserLandingPageRoute().pathname as string
    )}`;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch I tested mostly with the admin login! Changed!

Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,36 @@ interface Props {

const LoginForm: React.FC<Props> = ({ isExternal }) => {
const router = useRouter();
let loginURI = isExternal
? `/login?redirectTo=${getExternalUserLandingPageRoute().pathname}`
: "/login";
let loginURI = "/login";

if (router.query.redirectTo)
loginURI += `?redirectTo=${encodeURIComponent(
router.query.redirectTo as string
)}`;
else if (isExternal)
loginURI += `?redirectTo=${encodeURIComponent(
getExternalUserLandingPageRoute().pathname as string
)}`;

return (
<>
<form action={loginURI} method="post">
{isExternal ? (
<Button type="submit" variant="secondary">
External User Login
</Button>
) : (
<Button type="submit">Administrator Login</Button>
)}
<form id="login-buttons" action={loginURI} method="post">
<Button
type="submit"
variant={
router.pathname.includes("login-redirect")
? "secondary-inverse"
: isExternal && "secondary"
}
>
{isExternal ? "External User Login" : "Administrator Login"}
</Button>
</form>
<style jsx>{`
#login-buttons {
margin: 0px;
}
`}</style>
</>
);
};
Expand Down
1 change: 1 addition & 0 deletions app/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ function Index({ preloadedQuery }: RelayProps<{}, pagesQuery>) {
display: flex;
justify-content: center;
flex-direction: column;
gap: 1em;
}
`}
</style>
Expand Down
2 changes: 1 addition & 1 deletion app/tests/unit/components/Layout/ExternalLayout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe("The DefaultLayout component", () => {
beforeEach(() => {
componentTestingHelper.reinit();
jest.spyOn(require("next/router"), "useRouter").mockImplementation(() => {
return { pathname: "/cif-external" };
return { pathname: "/cif-external", query: testQuery };
});
});

Expand Down
34 changes: 34 additions & 0 deletions app/tests/unit/components/Layout/Navigation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Navigation from "components/Layout/Navigation";
import { render, screen } from "@testing-library/react";
import { mocked } from "jest-mock";
import { useRouter } from "next/router";
import userEvent from "@testing-library/user-event";

const links = [
{
Expand All @@ -13,6 +14,16 @@ const links = [
},
];

const linksHomepage = [
{
name: "Homepage",
href: {
pathname: "/",
},
highlightOn: ["/(.*)"],
},
];

jest.mock("next/router", () => ({
useRouter: jest.fn(),
}));
Expand Down Expand Up @@ -47,4 +58,27 @@ describe("The Navigation Component", () => {
expect(screen.getByText("Home")).toBeVisible();
expect(screen.getByText("Projects")).toBeVisible();
});

it("should not render the login buttons if the user is logged in", () => {
render(<Navigation isLoggedIn={true} links={links} />);

expect(screen.queryByText("Administrator Login")).toBeNull();
expect(screen.queryByText("External User Login")).toBeNull();
});

it("should not render the login buttons if the user is logged out but on the homepage", () => {
render(<Navigation isLoggedIn={false} links={linksHomepage} />);

expect(screen.queryByText("Administrator Login")).toBeNull();
expect(screen.queryByText("External User Login")).toBeNull();
});

it("redirects to the homepage when the user clicks the CleanBC logo", () => {
render(<Navigation isLoggedIn={false} links={links} />);

userEvent.click(
screen.getByAltText(/logo for Province of British Columbia CleanBC/i)
);
expect(window.location.pathname).toEqual("/");
});
});
38 changes: 33 additions & 5 deletions app/tests/unit/pages/login-redirect.test.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it would be advantageous to conduct a test here on the redirect functionality for external users.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After discussion with @Sepehr-Sobhani it was determined that it does not make sense to test this for now until we add more external user functionality.

Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
/**
* @jest-environment node
*/

import { getUserGroups } from "server/helpers/userGroupAuthentication";
import { withRelayOptions } from "pages/login-redirect";
import loginRedirect, { withRelayOptions } from "pages/login-redirect";
import { mocked } from "jest-mock";
import { screen } from "@testing-library/react";
import PageTestingHelper from "tests/helpers/pageTestingHelper";
import compiledLoginRedirectQuery, {
loginRedirectQuery,
} from "__generated__/loginRedirectQuery.graphql";
jest.mock("server/helpers/userGroupAuthentication");
jest.mock("lib/relay/server");

const defaultMockResolver = {
Query() {
return {
session: null,
};
},
};

const pageTestingHelper = new PageTestingHelper<loginRedirectQuery>({
pageComponent: loginRedirect,
compiledQuery: compiledLoginRedirectQuery,
defaultQueryResolver: defaultMockResolver,
});

describe("The login-redirect page", () => {
beforeEach(() => {
pageTestingHelper.reinit();
});

it("redirects a logged in cif_admin to the requested route", async () => {
mocked(getUserGroups).mockReturnValue(["cif_admin"]);
const ctx = {
Expand Down Expand Up @@ -42,4 +61,13 @@ describe("The login-redirect page", () => {
redirect: { destination: "/" },
});
});

it("renders the login buttons for a logged out user", () => {
pageTestingHelper.setMockRouterValues({ pathname: "/cif/projects" });
pageTestingHelper.loadQuery();
pageTestingHelper.renderPage();

expect(screen.getByText(/Administrator Login/i)).toBeVisible();
expect(screen.getByText(/External User Login/i)).toBeVisible();
});
});
Loading