Skip to content

Commit 0c3458d

Browse files
author
Owen Evans
committed
Merged in feature/GFW-1038_reset_password (pull request #134)
Normal: Reset password page (small) Approved-by: Kevin Borrill Approved-by: Uchenna Okafor
2 parents 85213cc + 209fca8 commit 0c3458d

File tree

5 files changed

+152
-83
lines changed

5 files changed

+152
-83
lines changed

src/locales/en.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@
4242
"signUp.success.message": "Thank you for registering",
4343
"signUp.success.message.extra": "Please check your emails and confirm your account",
4444
"signUp.error": "Sign up failed",
45+
"resetPW.title": "Forgot Password",
46+
"resetPW.subTitle": "To reset your password, enter your email and follow the instructions.",
47+
"resetPW.input.submit": "Reset password",
48+
"resetPW.success.message": "Reset password request sent",
49+
"resetPW.success.message.extra": "Please check your emails to reset your password",
50+
"resetPW.error": "Reset password failed",
4551
"common.create": "Create",
4652
"common.edit": "Edit",
4753
"common.add": "Add",

src/pages/login/SignUp.tsx

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/pages/login/SignUpAndReset.tsx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { FC, useState } from "react";
2+
import * as yup from "yup";
3+
import Input from "components/ui/Form/Input";
4+
import Button from "components/ui/Button/Button";
5+
import { FormattedMessage, useIntl } from "react-intl";
6+
import { SubmitHandler, useForm } from "react-hook-form";
7+
import { yupResolver } from "@hookform/resolvers/yup/dist/yup";
8+
import { TSignUpBody, userService } from "services/user";
9+
import { TErrorResponse } from "constants/api";
10+
import { toastr } from "react-redux-toastr";
11+
import LoginLayout from "components/layouts/Login";
12+
import { Link, useHistory } from "react-router-dom";
13+
14+
type TSignUpAndResetForm = TSignUpBody;
15+
16+
const signUpAndResetSchema = yup
17+
.object()
18+
.shape({
19+
email: yup.string().email().required()
20+
})
21+
.required();
22+
23+
interface IProps {
24+
isResetPassword: boolean;
25+
}
26+
27+
const resetPasswordConfig = {
28+
title: "resetPW.title",
29+
text: "resetPW.subTitle",
30+
inputLabel: "signIn.input.email",
31+
inputPlaceholder: "signIn.input.email.placeholder",
32+
submitBtn: "resetPW.input.submit",
33+
alreadyJoinedText: "signUp.link.already.joined",
34+
alreadyJoinedLink: "signUp.link.signIn",
35+
successMessage: "resetPW.success.message",
36+
successMessageInfo: "resetPW.success.message.extra",
37+
errorMessage: "resetPW.error"
38+
};
39+
40+
const signUpConfig = {
41+
title: "signUp.title",
42+
text: "signUp.subTitle",
43+
inputLabel: "signIn.input.email",
44+
inputPlaceholder: "signIn.input.email.placeholder",
45+
submitBtn: "signUp.input.submit",
46+
alreadyJoinedText: "signUp.link.already.joined",
47+
alreadyJoinedLink: "signUp.link.signIn",
48+
successMessage: "signUp.success.message",
49+
successMessageInfo: "signUp.success.message.extra",
50+
errorMessage: "signUp.error"
51+
};
52+
53+
const SignUpAndReset: FC<IProps> = ({ isResetPassword = false }) => {
54+
const config = isResetPassword ? resetPasswordConfig : signUpConfig;
55+
const {
56+
register,
57+
handleSubmit,
58+
reset,
59+
formState: { isDirty, errors }
60+
} = useForm<TSignUpAndResetForm>({ resolver: yupResolver(signUpAndResetSchema) });
61+
const intl = useIntl();
62+
const history = useHistory();
63+
const [isLoading, setIsLoading] = useState(false);
64+
65+
const onSubmit: SubmitHandler<TSignUpAndResetForm> = async data => {
66+
setIsLoading(true);
67+
try {
68+
if (isResetPassword) {
69+
await userService.resetPassword(data);
70+
} else {
71+
await userService.signUp(data);
72+
}
73+
history.push("/login");
74+
toastr.success(
75+
intl.formatMessage({ id: config.successMessage }),
76+
intl.formatMessage({ id: config.successMessageInfo })
77+
);
78+
} catch (e: any) {
79+
const error = JSON.parse(e.message) as TErrorResponse;
80+
toastr.error(
81+
intl.formatMessage({ id: config.errorMessage }),
82+
error?.errors?.length ? error.errors[0].detail : ""
83+
);
84+
console.error(e);
85+
reset();
86+
setIsLoading(false);
87+
}
88+
};
89+
90+
return (
91+
<LoginLayout isLoading={isLoading} title={config.title} text={config.text}>
92+
<form className="c-login-form" onSubmit={handleSubmit(onSubmit)}>
93+
<Input
94+
id="login-email"
95+
htmlInputProps={{
96+
label: intl.formatMessage({ id: config.inputLabel }),
97+
placeholder: intl.formatMessage({ id: config.inputPlaceholder }),
98+
type: "text"
99+
}}
100+
error={errors.email}
101+
registered={register("email")}
102+
/>
103+
<Button disabled={!isDirty} className="c-login-form__submit-btn" type="submit">
104+
<FormattedMessage id={config.submitBtn} />
105+
</Button>
106+
</form>
107+
<p className="c-login-form__link c-login-form__link--larger-font">
108+
<FormattedMessage id={config.alreadyJoinedText} />
109+
<Link className="u-margin-left-tiny" to="/login">
110+
<FormattedMessage id={config.alreadyJoinedLink} />
111+
</Link>
112+
</p>
113+
</LoginLayout>
114+
);
115+
};
116+
117+
export default SignUpAndReset;

src/routes.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import TeamDetail from "./pages/teams-detail/TeamDetailContainer";
1212
import Settings from "./pages/settings/SettingsContainer";
1313
import Reports from "./pages/reports/ReportsContainer";
1414
import Login from "./pages/login/Login";
15-
import SignUp from "./pages/login/SignUp";
15+
import SignUpAndReset from "./pages/login/SignUpAndReset";
1616

1717
const getLoginComponent = ({ user, location }) => {
1818
const search = location.search || "";
@@ -43,7 +43,16 @@ const Routes = props => {
4343
<Switch>
4444
<Route exact path="/" render={defaultComponent} />
4545
<Route path={`${match.url}login`} render={() => getLoginComponent({ user, location })} />
46-
{!user.loggedIn && <Route exact path={`${match.url}sign-up`} component={SignUp} />}
46+
{!user.loggedIn && (
47+
<Switch>
48+
<Route exact path={`${match.url}sign-up`} component={SignUpAndReset} />
49+
<Route
50+
exact
51+
path={`${match.url}forgotten-password`}
52+
render={args => <SignUpAndReset isResetPassword {...args} />}
53+
/>
54+
</Switch>
55+
)}
4756
{user.loggedIn ? (
4857
<Switch>
4958
<Route exact path={`${match.url}areas`} component={Areas} />

src/services/user.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ export type TSignUpResponse = {
2121
email: string;
2222
};
2323

24+
export type TResetPasswordBody = {
25+
email: string;
26+
};
27+
export type TResetPasswordResponse = {
28+
email: string;
29+
};
30+
2431
export class UserService extends BaseService {
2532
checkLogged(token: string) {
2633
this.token = token;
@@ -55,6 +62,17 @@ export class UserService extends BaseService {
5562
});
5663
}
5764

65+
resetPassword(body: TResetPasswordBody): Promise<TResetPasswordResponse> {
66+
return this.fetchJSON(`/auth/reset-password?callbackUrl=${API_CALLBACK_URL}`, {
67+
headers: {
68+
"Content-Type": "application/json",
69+
Authorization: ""
70+
},
71+
method: "POST",
72+
body: JSON.stringify(body)
73+
});
74+
}
75+
5876
logout(token: string) {
5977
this.token = token;
6078
return this.fetchJSON("/auth/logout");

0 commit comments

Comments
 (0)