Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c2ad91b

Browse files
authored
fix: Redirect to '?redirect' query parameter after successful login (#307)
Fixes #304 Unblocks #298 After logging in, the login flow should redirect to a whatever path is specified by the `?redirect` query parameter. This is important for cases like #298 - where we need to set `?redirect=%2Fcli_auth`, but also really any case where the user is linked and might have to go back to the login screen. The fix is simple - just check if the `redirect` query parameter is set, and if it is, use that as the path to redirect to on success. Also adds a test case - we had one checking that we redirect to the default (root `/`) url, but not one of the `?redirect` param
1 parent d436993 commit c2ad91b

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

site/components/SignIn/SignInForm.test.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,29 @@ describe("SignInForm", () => {
5555
act(() => elem.click())
5656

5757
// Then
58-
// Should redirect because login was successfully
58+
// Should redirect because login was successful
5959
await waitFor(() => expect(singletonRouter).toMatchObject({ asPath: "/" }))
6060
})
61+
62+
it("respects ?redirect query parameter when complete", async () => {
63+
// Given
64+
const loginHandler = (_email: string, _password: string) => Promise.resolve()
65+
// Set a path to redirect to after login is successful
66+
mockRouter.setCurrentUrl("/login?redirect=%2Fsome%2Fother%2Fpath")
67+
68+
// When
69+
// Render the component
70+
const { container } = render(<SignInForm loginHandler={loginHandler} />)
71+
// Set user / password
72+
const inputs = container.querySelectorAll("input")
73+
fireEvent.change(inputs[0], { target: { value: "[email protected]" } })
74+
fireEvent.change(inputs[1], { target: { value: "password" } })
75+
// Click sign-in
76+
const elem = await screen.findByText("Sign In")
77+
act(() => elem.click())
78+
79+
// Then
80+
// Should redirect to /some/other/path because ?redirect was specified and login was successful
81+
await waitFor(() => expect(singletonRouter).toMatchObject({ asPath: "/some/other/path" }))
82+
})
6183
})

site/components/SignIn/SignInForm.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { makeStyles } from "@material-ui/core/styles"
22
import { FormikContextType, useFormik } from "formik"
3-
import { useRouter } from "next/router"
3+
import { NextRouter, useRouter } from "next/router"
44
import React from "react"
55
import { useSWRConfig } from "swr"
66
import * as Yup from "yup"
@@ -9,6 +9,7 @@ import { Welcome } from "./Welcome"
99
import { FormTextField } from "../Form"
1010
import * as API from "./../../api"
1111
import { LoadingButton } from "./../Button"
12+
import { firstOrItem } from "../../util/array"
1213

1314
/**
1415
* BuiltInAuthFormValues describes a form using built-in (email/password)
@@ -61,7 +62,9 @@ export const SignInForm: React.FC<SignInProps> = ({
6162
await loginHandler(email, password)
6263
// Tell SWR to invalidate the cache for the user endpoint
6364
await mutate("/api/v2/users/me")
64-
await router.push("/")
65+
66+
const redirect = getRedirectFromRouter(router)
67+
await router.push(redirect)
6568
} catch (err) {
6669
helpers.setFieldError("password", "The username or password is incorrect.")
6770
}
@@ -117,3 +120,12 @@ export const SignInForm: React.FC<SignInProps> = ({
117120
</>
118121
)
119122
}
123+
124+
const getRedirectFromRouter = (router: NextRouter) => {
125+
const defaultRedirect = "/"
126+
if (router.query?.redirect) {
127+
return firstOrItem(router.query.redirect, defaultRedirect)
128+
} else {
129+
return defaultRedirect
130+
}
131+
}

0 commit comments

Comments
 (0)