From e95906926a16f7143acb0b3c1c6aa9ef79247a60 Mon Sep 17 00:00:00 2001 From: Hossein Date: Mon, 28 Aug 2023 17:11:25 +0330 Subject: [PATCH] #30, Add forgetPassword & verifyEmail page --- public/assets/locales/en/translation.json | 8 +- src/main/Mobile/Pages/Login/Login.module.css | 45 ++--- .../EmailVerification/EmailVerification.js | 2 +- .../ForgetPassword/ForgetPassword.js | 2 +- src/main/Mobile/Pages/User/User.module.css | 15 +- .../ForgetPassword/ForgetPassword.js | 175 +++++++++++++++++- .../Pages/User/components/Verify/Verify.js | 48 ++++- 7 files changed, 249 insertions(+), 46 deletions(-) diff --git a/public/assets/locales/en/translation.json b/public/assets/locales/en/translation.json index c8304cd..e04442a 100644 --- a/public/assets/locales/en/translation.json +++ b/public/assets/locales/en/translation.json @@ -31,7 +31,7 @@ "submit": "Submit", "username": "Username", "password": "Password", - "confirmPassword": "Confirm Password", + "confirmPassword": "Confirm", "otp": "OTP", "firstName": "First Name", "lastName": "Last Name", @@ -402,13 +402,13 @@ "ChangePassword": { "title": "Change Password", "newPassword": "New Password", - "confirmation": "New Password Confirmation", + "confirmation": "Confirm", "currentPassword": "Current Password", "success": "Password changed successfully.", "error": "Password change failed.", "minInput": "{{name}} must be at least {{min}} characters.", "emptyInput": "You must enter the {{name}} field.", - "confirmationError": "New password and confirm password don't match.", + "confirmationError": "New password and confirm new password don't match.", "currentPasswordError": "Current password has been entered incorrectly." }, "SetTwoStepVerification": { @@ -547,7 +547,7 @@ "register": "Register", "wrongEmail": "The entered email is invalid!", "emptyEmail": "Enter your email.", - "emptyInput": "Username and Password field is required.", + "emptyInput": "{{name}} field is required.", "emptyCredentialError": "Entering username and password is required.", "minInput": "{{name}} must be at least {{min}} characters.", "finishedWithError": "Error creating new user!", diff --git a/src/main/Mobile/Pages/Login/Login.module.css b/src/main/Mobile/Pages/Login/Login.module.css index a383f98..a4d4a96 100644 --- a/src/main/Mobile/Pages/Login/Login.module.css +++ b/src/main/Mobile/Pages/Login/Login.module.css @@ -23,10 +23,6 @@ background-color: var(--cardHeaderAlpha); } -.forgetPasswordInput{ - width: 75%; -} - .loginInput { width: 93%; margin-bottom: 2vh; @@ -39,29 +35,39 @@ background-color: var(--cardHeader); border-color: var(--cardHeader); color: var(--textColor); - width: 40%; } -.loginInput :global(input){ + + +.loginInput :global(.lead) { + width: 40% !important; +} +.loginInput :global(input) { width: 60% !important; } - +.loginInput.passwordInput :global(.lead) { + width: 40% !important; +} +.loginInput.passwordInput :global(input) { + width: 43% !important; +} +.loginInput.passwordInput :global(.after) { + width: 17% !important; +} .loginInput.captcha :global(.lead){ - width: 40%; + width: 40% !important; } - .loginInput.captcha :global(input){ width: 43% !important; } - - .loginInput.captcha :global(.after){ - width: 17%; + width: 17% !important; } + .thisLoading{ width: 9vw; } @@ -133,21 +139,6 @@ } - - - -.loginInput.passwordInput :global(.before){ - width: 40% !important; -} - -.loginInput.passwordInput :global(input){ - width: 43% !important; -} -.loginInput.passwordInput :global(.after){ - width: 17% !important; -} - - .ltrInput :global(input) { direction: ltr !important; } diff --git a/src/main/Mobile/Pages/Login/components/EmailVerification/EmailVerification.js b/src/main/Mobile/Pages/Login/components/EmailVerification/EmailVerification.js index 901d89b..fa07bcd 100644 --- a/src/main/Mobile/Pages/Login/components/EmailVerification/EmailVerification.js +++ b/src/main/Mobile/Pages/Login/components/EmailVerification/EmailVerification.js @@ -142,7 +142,7 @@ const EmailVerification = ({returnFunc, email, disable, returnFuncDisableFalse, type="text" data-name="email" data-type="email" - customClass={`${classes.forgetPasswordInput} ${classes.loginInput}`} + customClass={`${classes.loginInput}`} value={activeEmail.email.value} onchange={(e) => setActiveEmail({...activeEmail, email: {value: e.target.value, error: []}}) diff --git a/src/main/Mobile/Pages/Login/components/ForgetPassword/ForgetPassword.js b/src/main/Mobile/Pages/Login/components/ForgetPassword/ForgetPassword.js index 3494d87..ed46c38 100644 --- a/src/main/Mobile/Pages/Login/components/ForgetPassword/ForgetPassword.js +++ b/src/main/Mobile/Pages/Login/components/ForgetPassword/ForgetPassword.js @@ -119,7 +119,7 @@ const ForgetPassword = ({returnFunc}) => { type="text" data-name="email" data-type="email" - customClass={`${classes.forgetPasswordInput} ${classes.loginInput}`} + customClass={`${classes.loginInput}`} value={forgetPass.email.value} onchange={(e) => setForgetPass({...forgetPass, email: { value: e.target.value , error: []}}) diff --git a/src/main/Mobile/Pages/User/User.module.css b/src/main/Mobile/Pages/User/User.module.css index 823bf43..eb0d5ce 100644 --- a/src/main/Mobile/Pages/User/User.module.css +++ b/src/main/Mobile/Pages/User/User.module.css @@ -7,10 +7,8 @@ } .content{ - position: fixed; top: 27.5%; - left: 37.5%; - width: 25%; + width: 90%; height: 45%; background-color: var(--cardBodyAlpha); z-index: 7; @@ -42,13 +40,18 @@ width: 100%; } .passwordInput :global(.lead) { - width: 45%; + width: 40%; cursor: pointer; } .passwordInput :global(.after) { - width: 12.5%; + width: 17%; cursor: pointer; } .passwordInput :global(input) { - width: 42.5% !important; + width: 43% !important; +} + +.content img{ + width: 25%; } + diff --git a/src/main/Mobile/Pages/User/components/ForgetPassword/ForgetPassword.js b/src/main/Mobile/Pages/User/components/ForgetPassword/ForgetPassword.js index a9fd0eb..521c3ff 100644 --- a/src/main/Mobile/Pages/User/components/ForgetPassword/ForgetPassword.js +++ b/src/main/Mobile/Pages/User/components/ForgetPassword/ForgetPassword.js @@ -1,11 +1,180 @@ -import React from 'react' +import React, {useEffect, useState} from 'react' +import {useLocation, useNavigate} from "react-router-dom"; +import {Trans, useTranslation} from "react-i18next"; +import {useSelector} from "react-redux"; +import classes from '../../User.module.css' +import TextInput from "../../../../../../components/TextInput/TextInput"; +import Icon from "../../../../../../components/Icon/Icon"; +import LoginFormLoading from "../../../Login/components/LoginLoading/LoginFormLoading"; +import {images} from "../../../../../../assets/images"; +import {Login} from "../../../../Routes/routes"; +import {forgotPassword} from "js-api-client"; +import Button from "../../../../../../components/Button/Button"; const ForgetPassword = () => { - return ( -
+ const {t} = useTranslation(); + let navigate = useNavigate(); + const isLogin = useSelector((state) => state.auth.isLogin) + const [loading, setLoading] = useState(false); + const [error, setError] = useState(false); + const [response, setResponse] = useState(""); + + const [changePassword, setChangePassword] = useState({ + newPassword: {value: "", error: []}, + confirmation: {value: "", error: []} + }); + + const [isInputVisible, setIsInputVisible] = useState({ + newPassword: false, + confirmation: false + }); + + useEffect(() =>{ + if (isLogin) navigate("/", {replace: true}); + }) + + const key = new URLSearchParams(useLocation().search).get("key"); + + const inputHandler = (e) => { + let errorMessage = [] + if( typeof e.target.dataset.min !== undefined && e.target.value.length < e.target.dataset.min ) { + errorMessage.push( ) + } + + if (e.target.dataset?.name === "confirmation" && e.target.value !== changePassword.newPassword.value) { + errorMessage.push([t('ChangePassword.confirmationError')]) + } + + let prevState = { + ...changePassword, + [e.target.dataset.name]: {value: e.target.value, error: errorMessage} + } + if (e.target.dataset?.name === "newPassword") { + prevState.confirmation.error = (e.target.value === changePassword.confirmation.value || changePassword.confirmation.value.length === 0) ? [] : [t('login.wrongPasswordConfirmation')] + } + setChangePassword(prevState) + + } + const isFormValid = () => { + let inputs = {...changePassword} + + const hasError = Object.values(changePassword).find( input => input.error.length > 0 ) + if( hasError ) return false + let isEmpty = false + + for (const key in inputs) { + if (inputs[key].value.length === 0 ){ + isEmpty = true + inputs = { + ...inputs, + [key] : { + ...inputs[key], + error : [] + } + } + } + } + setChangePassword(inputs); + return !isEmpty; + } + + const content = () => { + if (loading) return + if (response === "done") return
+ kyc-accepted + {t("ChangePassword.success")}
+ + return <> + setIsInputVisible({ ...isInputVisible, newPassword: !isInputVisible.newPassword })} + /> + } + autocomplete="new-password" + type={isInputVisible.newPassword ? "text" : "password"} + value={changePassword.newPassword.value} + data-name="newPassword" + data-type="input" + data-min={8} + onchange={(e) => inputHandler(e)} + alerts={changePassword.newPassword.error} + /> + setIsInputVisible({ ...isInputVisible, confirmation: !isInputVisible.confirmation })} + /> + } + autocomplete="off" + type={isInputVisible.confirmation ? "text" : "password"} + value={changePassword.confirmation.value} + data-name="confirmation" + data-type="input" + //data-min={8} + onchange={(e) => inputHandler(e)} + alerts={changePassword.confirmation.error} + /> + {error && {t("userPage.serverError")}} + + + } + + const buttonClickHandler = async (e) => { + e.preventDefault(); + if (response === "done") navigate(Login) + if ( !isFormValid() ){ + return false + } + setLoading(true) + forgotPassword(key, changePassword.newPassword.value, changePassword.confirmation.value) + .then(() => { + setResponse("done") + }) + .catch(() => { + setError(true) + }) + .finally(() => { + setLoading(false); + }); + } + + return ( +
+
+

{t("ChangePassword.title")}

+
+
+ {content()} +
+
+
+
); }; diff --git a/src/main/Mobile/Pages/User/components/Verify/Verify.js b/src/main/Mobile/Pages/User/components/Verify/Verify.js index 4750868..2479364 100644 --- a/src/main/Mobile/Pages/User/components/Verify/Verify.js +++ b/src/main/Mobile/Pages/User/components/Verify/Verify.js @@ -1,11 +1,51 @@ -import React from 'react'; +import React, {useEffect, useState} from 'react'; +import classes from '../../User.module.css' +import {images} from "../../../../../../assets/images"; +import {Link, useLocation, useNavigate} from "react-router-dom"; +import {Login} from "../../../../Routes/routes"; +import Button from "../../../../../../components/Button/Button"; +import {useTranslation} from "react-i18next"; +import {useSelector} from "react-redux"; const Verify = () => { - return ( -
+ const {t} = useTranslation() + + let navigate = useNavigate(); + const isLogin = useSelector((state) => state.auth.isLogin) + if (isLogin) navigate("/", {replace: true}); + + const result = new URLSearchParams(useLocation().search).get("result"); + + const [status, setStatus] = useState() -
+ useEffect(() => { + + if (result === "SUCCEED") { + setStatus(true) + } + if (result === "FAILED") { + setStatus(false) + } + if (result !== "SUCCEED" && result !== "FAILED") { + navigate("/", {replace: true}); + } + + }, []); + + return ( +
+ {result} +
+ {status ? t("userPage.success") : t("userPage.failed")} +
+ {status && +
); };