diff --git a/__tests__/app/containers/Authentication/__snapshots__/Login.test.tsx.snap b/__tests__/app/containers/Authentication/__snapshots__/Login.test.tsx.snap index efd2a5a7..c4db6d25 100644 --- a/__tests__/app/containers/Authentication/__snapshots__/Login.test.tsx.snap +++ b/__tests__/app/containers/Authentication/__snapshots__/Login.test.tsx.snap @@ -3,6 +3,7 @@ exports[`Login Container Should render 1`] = ` action(Type.SET_IS_LOGIN_LOADING, { isLoginLoading }); + + export const forgotPassword = (email: string) => action(Type.FORGOT_PASSWORD, { email }); } diff --git a/src/app/apiFetch/User.ts b/src/app/apiFetch/User.ts index da76a8f0..edea468e 100644 --- a/src/app/apiFetch/User.ts +++ b/src/app/apiFetch/User.ts @@ -102,6 +102,27 @@ export const userEditPassword = (body: UserInterfaces.EditUserPassword) => { }); }; +export const userForgotPassword = (body: UserInterfaces.ForgotPassword) => { + return fetch(`${API_BASE_URL}user/forgot-password`, { + body: JSON.stringify(body), + credentials: 'include', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + method: 'POST', + }) + .then((response) => { + return response.json(); + }) + .then((data) => { + return data; + }) + .catch((error) => { + console.error(error); + }); +}; + export const userGetDetails = () => { return fetch(`${API_BASE_URL}user/profile`, { credentials: 'include', diff --git a/src/app/components/Authentication/Login.tsx b/src/app/components/Authentication/Login.tsx index 15f1d0b2..c0de2c3a 100644 --- a/src/app/components/Authentication/Login.tsx +++ b/src/app/components/Authentication/Login.tsx @@ -12,11 +12,13 @@ import { Redirect } from 'react-router-dom'; export class Login extends React.Component { private loginRef = React.createRef(); + private forgotPasswordRef = React.createRef(); constructor(props: LoginInterfaces.Props) { super(props); this.state = { + isForgotPassword: false, password: '', username: '', }; @@ -52,138 +54,268 @@ export class Login extends React.Component; } - - return ( -
-
-

Welcome!

-

Log in to access your dashboard and profile

-
- You can use your{' '} - - Pragyan - {' '} - account credentials to login. + if (!isForgotPassword) { + return ( +
+
+

Welcome!

+

Log in to access your dashboard and profile

+
+ You can use your{' '} + + Pragyan + {' '} + account credentials to login. +
-
- -
-
-
-
-
Username
-
- - this.setState({ - username: e.target.value, - }) - } - /> -
- {' '} - Please enter a valid Email.{' '} + +
+ +
+
+
Username
+
+ + this.setState({ + username: e.target.value, + }) + } + /> +
+ {' '} + Please enter a valid Email.{' '} +
-
-
-
-
Password
-
- - this.setState({ - password: e.target.value, - }) - } - required - /> -
- Please enter the correct password. +
+
+
Password
+
+ + this.setState({ + password: e.target.value, + }) + } + required + /> +
+ Please enter the correct password. +
-
-
-
- {errorMessage} +
+
+ {errorMessage} +
-
-
-
- +
+
+ +
+ +
+ + + +
this.setState({ isForgotPassword: true })} + > + Forgot Your Password?{' '} +
+ +
+ + + - + + +
+ ); + } + return ( +
+
+
+

Forgot your password?

- - - -
- Don't have an account?{' '} - { - updateErrorMessage(''); - this.props.handleSelectPanel(AuthType.REGISTER); - }} + +
+
- Create one - +
+
+
Your Email:
+
+ + this.setState({ + username: e.target.value, + }) + } + /> +
+ {' '} + Please enter a valid Email.{' '} +
+
+
+
+ +
+
+ {errorMessage} +
+
+
+
+ +
+
+
- - + + + +
this.setState({ isForgotPassword: false })} + > + Back{' '} +
+ +
+ + + + + +
); } + private handleForgotPassword = (event: React.FormEvent) => { + const { username } = this.state; + const { forgotPassword } = this.props; + const form = this.forgotPasswordRef.current; + + event.preventDefault(); + if (form) { + if (form.checkValidity()) { + forgotPassword(username); + } + form.classList.add('was-validated'); + } + }; + private handleLogin = (event: React.FormEvent) => { const { login } = this.props; const { username, password } = this.state; diff --git a/src/app/containers/Authentication/Login.ts b/src/app/containers/Authentication/Login.ts index 7f3eee77..7d900daf 100644 --- a/src/app/containers/Authentication/Login.ts +++ b/src/app/containers/Authentication/Login.ts @@ -15,6 +15,7 @@ const mapStateToProps = (rootState: RootState) => { const loginContainer = connect( mapStateToProps, { + forgotPassword: UserActions.forgotPassword, login: UserActions.login, updateErrorMessage: UserActions.updateErrorMessage, }, diff --git a/src/app/sagas/User.ts b/src/app/sagas/User.ts index 0de6e9b6..e5ad5684 100644 --- a/src/app/sagas/User.ts +++ b/src/app/sagas/User.ts @@ -182,6 +182,17 @@ export function* checkUsernameExists(action: ActionType) { + try { + const res = yield call(UserFetch.userForgotPassword, { email: action.payload.email }); + + // Call returns error if username already exists, else empty + yield put(UserActions.updateErrorMessage(res.error)); + } catch (err) { + console.error(err); + } +} + export function* resetAppState(action: ActionType) { try { yield put(CodeActions.resetCodeState()); @@ -208,5 +219,6 @@ export function* userSagas() { takeEvery(UserActions.Type.CHECK_USERNAME_EXISTS, checkUsernameExists), takeEvery(UserActions.Type.GET_USER_DETAILS, getUserDetails), takeEvery(UserActions.Type.RESET_APP_STATE, resetAppState), + takeEvery(UserActions.Type.FORGOT_PASSWORD, forgotPassword), ]); } diff --git a/src/app/styles/Authentication.module.css b/src/app/styles/Authentication.module.css index 5b859418..19e5dc23 100755 --- a/src/app/styles/Authentication.module.css +++ b/src/app/styles/Authentication.module.css @@ -492,3 +492,11 @@ position: relative; left: 1%; } + +.forgot-your-password { + cursor: pointer; +} + +.forgot-your-password:hover { + color: #4630eb !important; +} diff --git a/src/app/types/Authentication/Login.ts b/src/app/types/Authentication/Login.ts index 2cbf9e8e..c2345b71 100644 --- a/src/app/types/Authentication/Login.ts +++ b/src/app/types/Authentication/Login.ts @@ -1,6 +1,7 @@ import { AuthType } from 'app/types/Authentication'; export interface State { + isForgotPassword: boolean; username: string; password: string; } @@ -15,7 +16,9 @@ export interface StateProps { } export interface DispatchProps { + forgotPassword: (email: string) => void; login: (username: string, password: string) => void; + updateErrorMessage: (errorMessage: string) => void; } diff --git a/src/app/types/User.ts b/src/app/types/User.ts index 04f5563b..6d393a55 100644 --- a/src/app/types/User.ts +++ b/src/app/types/User.ts @@ -35,9 +35,14 @@ export interface Login { password: string; } +export interface ForgotPassword { + email: string; +} + const actions = { editUserPassword: UserActions.editUserPassword, editUserProfile: UserActions.editUserProfile, + forgotPassword: UserActions.forgotPassword, getUserDetails: UserActions.getUserDetails, login: UserActions.login, logout: UserActions.logout,