So that I tried to integrate the API for my mail verify page, and OTP code input field page. So that when I pass the props of email of user from the mail verify page, with this <VerifyAccount email={email} profileId={profileId} />
to OTP input field page, the props works finely and we can see the email as I am putting it in the text
<p>Privacy and security is our top priority. Kindly confirm your account by entering the verification code sent to your email
<p className='text-blue-500'> {email}</p>
</p>
but the problem is, the OTP page is showing in my mail input verify page, as it shown in the picture:
which I don't want this happen.
And if I make a ternary logic {showVerifyAccount && <VerifyAccount email={email} profileId={profileId} />} *
the props does not show, I can't see the email and also can not integrate the API for finding the profileId which should be match to the OTP code that is being input by the user.
Here is my mail verify page code :
import React, { useState } from 'react'
import Logo from '../../asset/bb1.png';
import { FcGoogle } from 'react-icons/fc';
import { AiFillApple, AiOutlineCheckCircle, AiOutlineCloseCircle } from 'react-icons/ai';
import { RiEyeOffFill } from 'react-icons/ri';
import { RiEyeFill } from 'react-icons/ri';
import { useNavigate } from 'react-router-dom';
import { TiTick } from 'react-icons/ti';
import VerifyAccount from './VerifyAccount';
import { Link } from 'react-router-dom';
const Register = () => {
const navigate = useNavigate();
const [showPassword, setShowPassword] = useState(false);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [emailError, setEmailError] = useState('');
const [passwordError, setPasswordError] = useState('');
const [confirmPasswordError, setConfirmPasswordError] = useState('');
const [fillOutError, setFillOutError] = useState('');
const [hasCapitalLetter, setHasCapitalLetter] = useState(false);
const [hasNumber, setHasNumber] = useState(false);
const [hasSymbol, setHasSymbol] = useState(false);
const [isMinLength, setIsMinLength] = useState(false);
const [passwordErrorVisible, setPasswordErrorVisible] = useState(true);
const [profileId, setProfileId] = useState(null);
const [showVerifyAccount, setShowVerifyAccount] = useState(false);
const validateEmail = () => {
const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
if (!email.match(emailRegex)) {
setEmailError(
<div className='flex flex-row items-center mr-1'>
<AiOutlineCloseCircle /> Invalid email format
</div>
);
} else {
setEmailError('');
}
};
const validatePassword = () => {
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
if (!password.match(passwordRegex)) {
setPasswordError('At least 8 characters, one uppercase letter, one lowercase letter, one number, and one special character.');
setIsMinLength(false);
setHasCapitalLetter(false);
setHasNumber(false);
setHasSymbol(false);
setPasswordErrorVisible(true); // Show the error message
} else {
setPasswordError('');
setIsMinLength(true);
setPasswordErrorVisible(false); // Hide the error message
}
if (/[A-Z]/.test(password)) {
setHasCapitalLetter(true);
} else {
setHasCapitalLetter(false);
}
if (/\d/.test(password)) {
setHasNumber(true);
} else {
setHasNumber(false);
}
if (/[!@#$%^&*]/.test(password)) {
setHasSymbol(true);
} else {
setHasSymbol(false);
}
setTimeout(() => {
setPasswordErrorVisible(false);
}, 300000);
};
const validateConfirmPassword = () => {
if (password !== confirmPassword) {
setConfirmPasswordError(
<div className='flex flex-row items-center mr-1'>
<AiOutlineCloseCircle /> Password does not match
</div>
);
} else {
setConfirmPasswordError('');
}
};
const handleCreateAccount = (e) => {
e.preventDefault();
if (!email || !password || !confirmPassword) {
setFillOutError('You should fill out all of the registration form.');
return;
}
// If any error messages are set, return early
if (emailError || passwordError || confirmPasswordError) {
return;
}
let objMailVerify = {email, password}
console.log(objMailVerify)
fetch('https://api.backend.ca/api/v1/auth/verify-email', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(objMailVerify),
}).then((res)=> {
alert('succes')
navigate('/verify');
}).catch((err)=>{
alert('failed'+ err.message)
})
}
const togglePasswordVisibility = () => {
setShowPassword(!showPassword);
};
return (
<div className='w-full relative h-screen flex items-start bg-[#0066f6] '>
<div className='relative w-1/2 h-full flex flex-col'>
<div className='absolute top-[116.06px] left-[110px] flex flex-col'>
<img src={Logo} alt='logo ini' className='w-[539px] h-[311.87px] '/>
</div>
</div>
{/* <div className='relative md:w-1/2 h-auto flex flex-col '> */}
<div className='md:w-[498px] w-80 h-auto md:left-[720px] bg-white flex flex-col p-3 md:p-10
rounded-md md:absolute md:mr-4 my-3 mr-10
items-center'>
<h1 className='text-[21px] md:-mt-5 mt-3 text-[#001533] font-semibold'>Welcome!</h1>
<h1 className='text-[21px] -mt-4 text-[#001533] font-semibold
mb-1'>Time to create an account</h1>
<div className='border-gray-400 border rounded-lg
py-1 px-4 w-full h-[35px] mb-2 items-center
justify-center cursor-pointer
flex flex-row'>
<FcGoogle className='w-[30px] h-[30px]'/>
<p className='text-sm md:text-[13px] font-bold ml-9'> Sign Up With Google</p>
</div>
<div className='border-gray-400 border rounded-lg
py-1 px-4 w-full h-[35px] mb-2 items-center
justify-center
flex flex-row cursor-pointer'>
<AiFillApple className='w-[30px] h-[30px]'/>
<p className='text-sm md:text-[13px] font-bold ml-9'>Sign Up With Apple</p>
</div>
<div className="mt-1 w-full flex items-center">
<hr className="flex-grow md:w-[115px] w-[115px] border-gray-400" />
<span className="text-[#41618E] md:text-[15px]
text-center mx-2">Sign Up With Email</span>
<hr className="flex-grow md:w-[115px] w-[115px] border-gray-400" />
</div>
<form onSubmit={handleCreateAccount}>
<div className='w-full flex flex-col mb-3 text-left'>
<label htmlFor="email" className="text-black">Email Address</label>
<input
type='email'
id="email"
placeholder='ricahrdchau@gmail.com'
className='w-full text-[#666666] text-[16.26px] bg-gray-200 p-3 my-2 border-none outline-none focus:outline-none '
value={email}
onChange={(e) =>{
setEmail(e.target.value)
setFillOutError('');
setEmailError('');
}}
onBlur={validateEmail}
/>
{emailError && <p className='text-red-500 text-sm'>{emailError}</p>}
<label htmlFor='password' className='text-black'>
Password
</label>
<div className='relative'>
<div className='relative w-full'>
<input
type={showPassword ? 'text' : 'password'}
id='password'
placeholder='******'
className='w-full text-black text-sm bg-gray-200 p-3 my-2 border-none outline-none focus:outline-none'
value={password}
onChange={(e) => { setPassword(e.target.value)
// setFillOutError('')
validatePassword(e.target.value);
// setIsMinLength(false);
// setIsMinLength(false);
// setHasCapitalLetter(false);
// setHasNumber(false);
// setHasSymbol(false);
}}
onBlur={validatePassword}
/>
<span
className='absolute right-4 top-1/2 transform -translate-y-1/2 cursor-pointer'
onClick={togglePasswordVisibility}
>
{showPassword ? <RiEyeOffFill /> : <RiEyeFill />}
</span>
</div>
<div className='text-sm text-red-500'>
{passwordErrorVisible && passwordError && (
<p className='flex flex-row items-center'>
{isMinLength ? <span className='text-green-500 text-[8px] flex flex-row'> <TiTick /> 8 characters, </span> : <span className='text-red-500 text-[10px] flex flex-row items-center'> <AiOutlineCloseCircle/> 8 characters,</span>}{' '}
{hasCapitalLetter ? <span className='text-green-500 text-[8px] flex flex-row items-center'> <AiOutlineCheckCircle/> 1 uppercase letter, </span> : <span className='text-red-500 text-[10px] flex flex-row items-center'> <AiOutlineCloseCircle/> 1 uppercase letter,</span>}{' '}
{hasNumber ? <span className='text-green-500 flex text-[8px] flex-row items-center'><AiOutlineCheckCircle/> 1 number, </span> : <span className='text-red-500 text-[10px] flex flex-row items-center'> <AiOutlineCloseCircle/> 1 number,</span>}{' '}
{hasSymbol ? <span className='text-green-500 flex text-[8px] flex-row items-center'><AiOutlineCheckCircle/> 1 symbol </span> : <span className='text-red-500 text-[10px] flex flex-row items-center'> <AiOutlineCloseCircle/> 1 symbol</span>}
</p>
)}
</div>
</div>
<label htmlFor='confirmPassword' className='text-black'>
Confirm Password
</label>
<div className='relative'>
<div className='relative w-full'>
<input
type={showPassword ? 'text' : 'password'}
id='confirmPassword'
placeholder='******'
className='w-full text-black text-sm bg-gray-200 p-3 my-2 border-none outline-none focus:outline-none'
value={confirmPassword}
onChange={(e) => {
setConfirmPassword(e.target.value)
setFillOutError('')
setConfirmPasswordError('')
}}
onBlur={validateConfirmPassword}
/>
<span
className='absolute right-4 top-1/2 transform -translate-y-1/2 cursor-pointer'
onClick={togglePasswordVisibility}
>
{showPassword ? <RiEyeOffFill /> : <RiEyeFill />}
</span>
</div>
{confirmPasswordError && (
<p className='text-red-500 text-sm'>{confirmPasswordError}</p>
)}
{fillOutError && (
<p className='text-red-500 text-sm'>
{fillOutError}
</p>
)}
</div>
</div>
<div className='w-full flex flex-col '>
<button type='submit'
className='w-full hover:bg-blue-800 text-white bg-blue-950 rounded-md p-2 text-center flex items-center justify-center'
onClick={() => setShowVerifyAccount(true)}
>
Create Your Account
</button>
{/* {showVerifyAccount && <VerifyAccount email={email} profileId={profileId} />} */}
<VerifyAccount email={email} profileId={profileId} />
</div>
<div className='w-full flex items-center justify-center
mt-2'>
<p className='text-sm font-normal text-black'>
Alread have an account here?
<span className='font-semibold
underline underline-offset-2
hover:cursor-pointer'> Login Here</span>
</p>
</div>
</form>
</div>
</div>
)
}
export default Register
and below is my OTP page code:
import React, { useState, useRef } from 'react';
import Logo from '../../asset/bb1.png';
import { FcGoogle } from 'react-icons/fc';
import { AiFillApple } from 'react-icons/ai';
import { RiEyeOffFill } from 'react-icons/ri';
import { RiEyeFill } from 'react-icons/ri';
import { useNavigate } from "react-router-dom";
import { useLocation } from 'react-router-dom';
const VerifyAccount = ({email, profileId }) => {
const { state } = useLocation();
// const email = state ? state.email : '';
const navigate = useNavigate();
const [otp, setOtp] = useState(['', '', '', '']);
const [loading, setLoading] = useState(false);
const otpInputs = useRef([]);
const handleInputChange = (index, value) => {
const newOtp = [...otp];
newOtp[index] = value;
setOtp(newOtp);
if (index < 3 && value !== '') {
otpInputs.current[index + 1].focus();
}
};
const isOtpIncomplete = otp.some((digit) => digit === '');
const handleCreateAccount = async () => {
if (isOtpIncomplete || !profileId) {
alert('Please enter the complete OTP code and ensure you have a valid profileId.');
return;
}
try {
setLoading(true);
const response = await fetch('https://api.borrow4less.ca/api/v1/auth/verify-email-otp'+profileId, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
profileId,
otp: otp.join(''),
}),
});
if (response.ok) {
// API call was successful, navigate to the next page
navigate('/details-register');
} else {
// Handle error cases
console.error('OTP verification failed:', response.status, response.statusText);
const responseBody = await response.json();
console.error('Error details:', responseBody);
}
} catch (error) {
// Handle network or other errors
console.error('Error verifying OTP:', error);
// You might want to show an error message to the user
// For example: setError('An error occurred. Please try again.');
} finally {
setLoading(false);
}
};
return (
<div className='w-full relative h-screen flex items-start bg-[#0066f6] '>
<div className='relative md:w-1/2 md:h-full flex md:flex-col'>
<div className='absolute top-[30%] left-[20%] flex flex-col'>
<img src={Logo} alt='logo ini' className='w-[500px] h-[311.87px] '/>
</div>
</div>
<div className='relative w-1/2 h-auto flex flex-col mt-2'>
<div className='md:w-3/4 md:h-auto bg-white md:flex md:flex-col p-10 md:p-10 rounded absolute md:right-[30%] ml-12 mt-8 items-center'>
<h1 className='mb-4 text-xl text-black font-semibold'>Verify your account!</h1>
<p>
Privacy and security is our top priority. Kindly confirm your account by entering the verification code sent to your email
<p className='text-blue-500'> {email}</p>
</p>
<div className='flex flex-row items-center mt-20 mb-20'>
{otp.map((digit, index) => (
<input
key={index}
ref={(input) => (otpInputs.current[index] = input)}
className='border border-black w-12 h-16 p-4 mx-2 rounded-sm text-center'
type='text'
maxLength='1'
value={digit}
onChange={(e) => handleInputChange(index, e.target.value)}
/>
))}
</div>
<div className='w-full flex flex-col'>
<div className='w-full'>
<button
className='w-full hover:bg-blue-800 text-white bg-blue-950 rounded-md p-3 text-center flex items-center justify-center'
onClick={handleCreateAccount}
disabled={loading}
>
{loading ? 'Verifying...' : 'Create Your Account'}
</button>
</div>
</div>
<div className='w-full flex items-center justify-center mt-2'>
<p className='text-sm font-normal text-black'>
Didn’t get a code?
<span className='font-semibold text-blue-500 hover:cursor-pointer'> Resend</span>
</p>
</div>
</div>
</div>
</div>
);
}
export default VerifyAccount;
Any help here could be really appreciated, about how to make the OTP input field page does not show in my mail verify page, but the prop is working finely when user moved from mail verify to the OTP input field page.
There is solution for this, to pass the props for displaying the email and make a request body to get the profileId properties, we can use localStorage
.