password reset first phase done

This commit was merged in pull request #378.
This commit is contained in:
victorAnumudu
2023-08-05 05:41:46 +01:00
parent 8d3dca96b4
commit cab5ed0ece
5 changed files with 253 additions and 149 deletions
@@ -0,0 +1,35 @@
import React from 'react'
const ForgetPwdResponse = ({title, message, type}) => {
return (
<>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className={`${type ? 'text-black' : 'text-red-500'}text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]`}>
{title}
</h1>
</div>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
{/* <img src='' /> */}
<p className='rounded-full border w-[50px] h-[50px] flex items-center justify-center'>Icon</p>
</div>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<p className={`${type ? 'text-sky-blue' : 'text-red-500'} font-semibold dark:text-white mb-3 leading-[27.3px] text-[18px]`}>
{message}
</p>
</div>
<div className="signin-area mb-3.5">
<div className="flex justify-center items-center gap-2">
<button
type="button"
onClick={() => navigate("/login")}
className={`rounded-[0.475rem] mb-6 text-[15px] font-semibold text-white flex justify-center bg-[#4687ba] hover:bg-[#009ef7] transition-all duration-300 items-center py-[0.8875rem] px-[1.81rem]`}
>
<span>Home</span>
</button>
</div>
</div>
</>
)
}
export default ForgetPwdResponse
@@ -4,6 +4,8 @@ import WrenchBoard from "../../../assets/images/wrenchboard-logo-text.png";
import usersService from "../../../services/UsersService"; import usersService from "../../../services/UsersService";
import InputCom from "../../Helpers/Inputs/InputCom"; import InputCom from "../../Helpers/Inputs/InputCom";
import AuthLayout from "../AuthLayout"; import AuthLayout from "../AuthLayout";
import EmailValidator from "../../../lib/EmailValidator";
import ForgetPwdResponse from "../ForgetPwdResponse";
export default function ForgotPassword() { export default function ForgotPassword() {
const [checked, setValue] = useState(false); const [checked, setValue] = useState(false);
@@ -11,7 +13,7 @@ export default function ForgotPassword() {
// email // email
const [email, setMail] = useState(""); const [email, setMail] = useState("");
const [msgError, setMsgError] = useState(""); const [msgError, setMsgError] = useState("");
const [msgSuccess, setMsgSuccess] = useState(false); const [msgSuccess, setMsgSuccess] = useState(null);
const navigate = useNavigate(); const navigate = useNavigate();
const userApi = new usersService(); const userApi = new usersService();
@@ -27,8 +29,22 @@ export default function ForgotPassword() {
const resetHandler = async () => { const resetHandler = async () => {
if (email == "") { if (email == "") {
setMsgError("An email is required"); setMsgError("An email is required");
} else if (!checked) { return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if (!checked) {
setMsgError("Check if you are human"); setMsgError("Check if you are human");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(!EmailValidator(email)){ // CHECKS IF EMAIL IS VALID
setMsgError("Invalid Email");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
} }
if (email !== "" && checked) { if (email !== "" && checked) {
@@ -41,8 +57,11 @@ export default function ForgotPassword() {
setMail(""); setMail("");
setValue(false); setValue(false);
setResetLoading(false); setResetLoading(false);
}else{
setMsgSuccess(false);
} }
} catch (error) { } catch (error) {
setMsgSuccess(false);
setResetLoading(false); setResetLoading(false);
setMail(""); setMail("");
setMsgError("An error occurred"); setMsgError("An error occurred");
@@ -53,9 +72,6 @@ export default function ForgotPassword() {
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT); }, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
} }
} }
setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}; };
return ( return (
@@ -73,6 +89,8 @@ export default function ForgotPassword() {
</div> </div>
<div className="content-wrapper login shadow-md w-full lg:max-w-[500px] mx-auto flex justify-center items-center xl:bg-white dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5"> <div className="content-wrapper login shadow-md w-full lg:max-w-[500px] mx-auto flex justify-center items-center xl:bg-white dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5">
<div className="flex flex-col justify-center w-full h-full px-5"> <div className="flex flex-col justify-center w-full h-full px-5">
{msgSuccess == null ?
<>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7"> <div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]"> <h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Forget Password Forget Password
@@ -136,7 +154,7 @@ export default function ForgotPassword() {
{msgError} {msgError}
</div> </div>
)} )}
{msgSuccess && ( {/* {msgSuccess && (
<div className="relative p-4 text-[#44228c] bg-[#e3d7fb] border-[#d5c4f9] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]"> <div className="relative p-4 text-[#44228c] bg-[#e3d7fb] border-[#d5c4f9] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]">
If we find your email, you will receive a link to reset your If we find your email, you will receive a link to reset your
password. Please use or{" "} password. Please use or{" "}
@@ -148,7 +166,7 @@ export default function ForgotPassword() {
</Link>{" "} </Link>{" "}
if you did not get our message after few minutes. if you did not get our message after few minutes.
</div> </div>
)} )} */}
<div className="signin-area mb-3.5"> <div className="signin-area mb-3.5">
<div className="flex justify-center items-center gap-2"> <div className="flex justify-center items-center gap-2">
@@ -173,6 +191,14 @@ export default function ForgotPassword() {
</div> </div>
</div> </div>
</div> </div>
</>
:
<ForgetPwdResponse
title={msgSuccess? 'Password Reset Complete' : 'Password Reset Error'}
message={msgSuccess? `Check your email for the link to continue password reset. Note the reset link will expire short time` : 'We are unable to continue with your request. Please try another username or contact us for help'}
type={msgSuccess}
/>
}
</div> </div>
</div> </div>
</div> </div>
@@ -1,16 +1,18 @@
import { useState } from "react"; import { useEffect, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom"; import { Link, useLocation, useNavigate } from "react-router-dom";
import WrenchBoard from "../../../assets/images/wrenchboard-logo-text.png"; import WrenchBoard from "../../../assets/images/wrenchboard-logo-text.png";
import usersService from "../../../services/UsersService"; import usersService from "../../../services/UsersService";
import InputCom from "../../Helpers/Inputs/InputCom"; import InputCom from "../../Helpers/Inputs/InputCom";
import AuthLayout from "../AuthLayout"; import AuthLayout from "../AuthLayout";
import ForgetPwdResponse from "../ForgetPwdResponse";
import PasswordValidator from "../../../lib/PasswordValidator";
const VerifyPassword = () => { const VerifyPassword = () => {
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState("");
const [msgError, setMsgError] = useState(""); const [msgError, setMsgError] = useState("");
const [linkLoader, setLinkLoader] = useState(false); const [linkLoader, setLinkLoader] = useState(false);
const [linkSuccess, setLinkSuccess] = useState(true); const [linkSuccess, setLinkSuccess] = useState(null);
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const location = useLocation(); const location = useLocation();
@@ -23,11 +25,6 @@ const VerifyPassword = () => {
setShowPassword(!showPassword); setShowPassword(!showPassword);
}; };
// little checker for the validity of the token
if (token?.length != 64) {
setLinkSuccess(false);
}
// Password // Password
const handlePassword = (e) => { const handlePassword = (e) => {
let { name, value } = e?.target; let { name, value } = e?.target;
@@ -36,9 +33,31 @@ const VerifyPassword = () => {
}; };
const completeReset = async () => { const completeReset = async () => {
if(!password || !confirmPassword){ // CHECKS IF PASSWORD IS EMPTY
setMsgError("Please fill in fields");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(password != confirmPassword){ // CHECKS IF PASSWORD EQUALS CONFIRM PASSWORD
setMsgError("Passwords does not match");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(password.length < 6){ // CHECKS IF PASSWORD LENGTH IS UPTO 6 CHARACTERS
setMsgError("Password must be upto six characters");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
if(!PasswordValidator(password)){ // CHECKS IF PASSWORD IS VALID
setMsgError("Invalid Password: eg: Password1@");
return setTimeout(() => {
setMsgError(null);
}, process.env.REACT_APP_RESET_START_ERROR_TIMEOUT);
}
try { try {
if (password !== "" && confirmPassword !== "") {
if (password === confirmPassword) {
setLinkLoader(true); setLinkLoader(true);
var reqData = { var reqData = {
sessionid: "DUMMY-CANNOT_BE_EMPTY", sessionid: "DUMMY-CANNOT_BE_EMPTY",
@@ -47,34 +66,29 @@ const VerifyPassword = () => {
step: 300, step: 300,
action: 730, action: 730,
}; };
const res = await userApi?.CompleteResetPassword(reqData); const res = await userApi?.CompleteResetPassword(reqData);
if (res.status === 200) { if (res.status === 200) {
const { data } = res; const { data } = res;
console.log('RESPONSE', res)
if (data?.status > 0 && data?.email) { if (data?.status > 0 && data?.email) {
setTimeout(() => { // setTimeout(() => {
navigate("/login", { replace: true }); // navigate("/login", { replace: true });
setLinkLoader(false); // setLinkLoader(false);
}, 2000); // }, 2000);
setLinkSuccess(true);
} else if (data && data?.status == "Invalid Request") { } else if (data && data?.status == "Invalid Request") {
setLinkLoader(false); setLinkLoader(false);
setLinkSuccess(false); setLinkSuccess(false);
} else { } else {
setLinkLoader(false); setLinkLoader(false);
setMsgError("An error occurred"); setMsgError("An error occurred");
}
} else {
setLinkLoader(false);
setLinkSuccess(false); setLinkSuccess(false);
} }
} else { } else {
setLinkLoader(false); setLinkLoader(false);
setMsgError("Passwords does not match"); setLinkSuccess(false);
}
} else {
setMsgError("Please fill in fields");
} }
} catch (error) { } catch (error) {
setLinkLoader(false); setLinkLoader(false);
@@ -87,6 +101,12 @@ const VerifyPassword = () => {
} }
}; };
useEffect(()=>{
// little checker for the validity of the token
if (token==null || token?.length != 64) {
setLinkSuccess(false);
}
},[])
return ( return (
<> <>
<AuthLayout slogan="Welcome to WrenchBoard"> <AuthLayout slogan="Welcome to WrenchBoard">
@@ -102,23 +122,19 @@ const VerifyPassword = () => {
</div> </div>
<div className="content-wrapper login shadow-md w-full lg:max-w-[500px] mx-auto flex justify-center items-center dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5"> <div className="content-wrapper login shadow-md w-full lg:max-w-[500px] mx-auto flex justify-center items-center dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5">
<div className="w-full"> <div className="w-full">
{linkSuccess == null ?
<>
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7"> <div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
<h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]"> <h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
{linkSuccess ? "Password Reset" : "Invalid verification link"} Password Reset
</h1> </h1>
{linkSuccess && (
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]"> <span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
Enter a new password to reset Enter a new password to reset
</span> </span>
)}
{linkSuccess && (
<span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]"> <span className="text-gray-400 font-medium text-[16.25px] leading-[24.375px]">
We'll send an email to confirm reset We'll send an email to confirm reset
</span> </span>
)}
</div> </div>
{/* If the verification was a success */}
{linkSuccess ? (
<SuccessfulComponent <SuccessfulComponent
password={password} password={password}
confirmPassword={confirmPassword} confirmPassword={confirmPassword}
@@ -130,9 +146,18 @@ const VerifyPassword = () => {
onClick={togglePasswordVisibility} onClick={togglePasswordVisibility}
navigateHandler={() => navigate("/login")} navigateHandler={() => navigate("/login")}
/> />
) : ( </>
<ErrorComponent onClick={() => navigate("/login")} /> :
)} <ForgetPwdResponse
title={linkSuccess? 'Password Reset Complete' : (linkSuccess==false && token==null) ? 'Forget Password' : 'Password Reset Error'}
message={linkSuccess?
'Password Reset Complete. You can login now with your new credentials' :
(linkSuccess==false && token==null) ? 'We are unable to continue to reset process. This error is usually due to expired links. Please start all over or contact us' :
'Password Reset Error. Please get in touch with support for further support'
}
type={linkSuccess}
/>
}
</div> </div>
</div> </div>
</div> </div>
@@ -159,7 +184,7 @@ const SuccessfulComponent = ({
<div className="mb-5"> <div className="mb-5">
<InputCom <InputCom
fieldClass="sm:px-6 px-2 tracking-[0.25em] text-2xl" fieldClass="sm:px-6 px-2 tracking-[0.25em] text-2xl"
value={password?.replace(/./g, "●")} value={password}
inputHandler={handlePassword} inputHandler={handlePassword}
placeholder="● ● ● ● ● ●" placeholder="● ● ● ● ● ●"
label="Password" label="Password"
@@ -172,7 +197,7 @@ const SuccessfulComponent = ({
<div className="mb-5"> <div className="mb-5">
<InputCom <InputCom
fieldClass="sm:px-6 px-2 tracking-[0.25em] text-2xl" fieldClass="sm:px-6 px-2 tracking-[0.25em] text-2xl"
value={confirmPassword?.replace(/./g, "●")} value={confirmPassword}
inputHandler={handlePassword} inputHandler={handlePassword}
placeholder="● ● ● ● ● ●" placeholder="● ● ● ● ● ●"
label="Confirm Password" label="Confirm Password"
+9
View File
@@ -0,0 +1,9 @@
export default function EmailValidator(email) {
let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/;
if (regEx.test(email) == false) {
return false
}else{
return true
}
}
+9
View File
@@ -0,0 +1,9 @@
export default function PasswordValidator(password) {
const regEx = /^[a-zA-Z0-9!@#$%^&*()_+{}\[\]:;<>,.?~\\/\-='"`|]+$/;
if (/[!@#$%^&*()_+{}\[\]:;<>,.?~\\/\-='"`|]/.test(password) == false || /[0-9]/.test(password)==false || /[A-Z]/.test(password)==false || /[a-z]/.test(password)==false) {
return false
}else{
return true
}
}