updated forget password functionality with backend
This commit is contained in:
@@ -38,11 +38,13 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
|
||||
const handleCreateNewProject = async () => {
|
||||
const token = localStorage.getItem("token");
|
||||
const refreshToken = localStorage.getItem("refreshToken")
|
||||
console.log('refreshToken: ', refreshToken);
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
console.log("refreshToken: ", refreshToken);
|
||||
try {
|
||||
const projectId = generateProjectId();
|
||||
useSocketStore.getState().initializeSocket(email, organization, token, refreshToken);
|
||||
useSocketStore
|
||||
.getState()
|
||||
.initializeSocket(email, organization, token, refreshToken);
|
||||
|
||||
//API for creating new Project
|
||||
// const project = await createProject(
|
||||
@@ -59,12 +61,12 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
projectUuid: projectId,
|
||||
};
|
||||
|
||||
console.log('projectSocket: ', projectSocket);
|
||||
console.log("projectSocket: ", projectSocket);
|
||||
if (projectSocket) {
|
||||
const handleResponse = (data: any) => {
|
||||
if (data.message === "Project created successfully") {
|
||||
setLoadingProgress(1)
|
||||
navigate(`/${data.data.projectId}`);
|
||||
setLoadingProgress(1);
|
||||
navigate(`/projects/${data.data.projectId}`);
|
||||
}
|
||||
projectSocket.off("v1-project:response:add", handleResponse); // Clean up
|
||||
};
|
||||
@@ -88,7 +90,8 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
</div>
|
||||
<div className="user-name">
|
||||
{userName
|
||||
? userName.charAt(0).toUpperCase() + userName.slice(1).toLowerCase()
|
||||
? userName.charAt(0).toUpperCase() +
|
||||
userName.slice(1).toLowerCase()
|
||||
: "Anonymous"}
|
||||
</div>
|
||||
</div>
|
||||
@@ -162,10 +165,14 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
<SettingsIcon />
|
||||
Settings
|
||||
</div>
|
||||
<div className="option-list" style={{ cursor: "pointer" }} onClick={() => {
|
||||
localStorage.clear();
|
||||
navigate("/");
|
||||
}}>
|
||||
<div
|
||||
className="option-list"
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
localStorage.clear();
|
||||
navigate("/");
|
||||
}}
|
||||
>
|
||||
<LogoutIcon />
|
||||
Log out
|
||||
</div>
|
||||
@@ -179,4 +186,4 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default SidePannel;
|
||||
export default SidePannel;
|
||||
|
||||
@@ -1,30 +1,39 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
email: string;
|
||||
setEmail: (value: string) => void;
|
||||
onSubmit: () => void;
|
||||
email: string;
|
||||
setEmail: (value: string) => void;
|
||||
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
|
||||
}
|
||||
|
||||
const EmailInput: React.FC<Props> = ({ email, setEmail, onSubmit }) => {
|
||||
return (
|
||||
<div className='request-container'>
|
||||
<h1 className='header'>Forgot password</h1>
|
||||
<p className='sub-header'>
|
||||
Enter your email for the verification process, we will send a 4-digit code to your email.
|
||||
</p>
|
||||
<form className='auth-form' onSubmit={(e) => { e.preventDefault(); onSubmit(); }}>
|
||||
<input
|
||||
type='email'
|
||||
placeholder='Email'
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<button type='submit' className='continue-button'>Continue</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="request-container">
|
||||
<h1 className="header">Forgot password</h1>
|
||||
<p className="sub-header">
|
||||
Enter your email for the verification process, we will send a 4-digit
|
||||
code to your email.
|
||||
</p>
|
||||
<form
|
||||
className="auth-form"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
onSubmit(e);
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<button type="submit" className="continue-button">
|
||||
Continue
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmailInput;
|
||||
|
||||
@@ -1,10 +1,95 @@
|
||||
import React, { useState, useRef, useEffect } from 'react';
|
||||
// import React, { useState, useRef, useEffect } from "react";
|
||||
|
||||
const OTPInput: React.FC<{ length?: number; onComplete: (otp: string) => void }> = ({ length = 4, onComplete }) => {
|
||||
const [otpValues, setOtpValues] = useState<string[]>(Array(length).fill(''));
|
||||
// const OTPInput: React.FC<{
|
||||
// length?: number;
|
||||
// onComplete: (otp: string) => void;
|
||||
// code: string;
|
||||
// }> = ({ length = 4, onComplete, code }) => {
|
||||
// const [otpValues, setOtpValues] = useState<string[]>(Array(length).fill(""));
|
||||
// const inputsRef = useRef<(HTMLInputElement | null)[]>([]);
|
||||
// useEffect(() => {
|
||||
// if (code) {
|
||||
// console.log("code: ", code);
|
||||
|
||||
// const codeString = String(code); // convert number → string
|
||||
// setOtpValues(codeString.split(""));
|
||||
// onComplete(codeString);
|
||||
// }
|
||||
// }, [code, length]);
|
||||
// // Auto focus first input on mount
|
||||
// useEffect(() => {
|
||||
// inputsRef.current[0]?.focus();
|
||||
// }, []);
|
||||
|
||||
// const handleChange = (value: string, index: number) => {
|
||||
// if (/^[0-9]?$/.test(value)) {
|
||||
// const newOtp = [...otpValues];
|
||||
// newOtp[index] = value;
|
||||
// setOtpValues(newOtp);
|
||||
|
||||
// if (value && index < length - 1) {
|
||||
// inputsRef.current[index + 1]?.focus();
|
||||
// }
|
||||
|
||||
// if (newOtp.every((digit) => digit !== "")) {
|
||||
// console.log('newOtp.join(""): ', newOtp.join(""));
|
||||
// onComplete(newOtp.join(""));
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
// const handleKeyDown = (
|
||||
// e: React.KeyboardEvent<HTMLInputElement>,
|
||||
// index: number
|
||||
// ) => {
|
||||
// if (e.key === "Backspace" && !otpValues[index] && index > 0) {
|
||||
// inputsRef.current[index - 1]?.focus();
|
||||
// }
|
||||
// };
|
||||
|
||||
// return (
|
||||
// <div className="otp-container">
|
||||
// {otpValues.map((value, index) => (
|
||||
// <input
|
||||
// key={index}
|
||||
// type="text"
|
||||
// className="otp-input"
|
||||
// maxLength={1}
|
||||
// value={value}
|
||||
// onChange={(e) => handleChange(e.target.value, index)}
|
||||
// onKeyDown={(e) => handleKeyDown(e, index)}
|
||||
// ref={(el) => (inputsRef.current[index] = el)}
|
||||
// />
|
||||
// ))}
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export default OTPInput;
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
|
||||
const OTPInput: React.FC<{
|
||||
length?: number;
|
||||
onComplete: (otp: string) => void;
|
||||
code: string | number;
|
||||
}> = ({ length = 4, onComplete, code }) => {
|
||||
const [otpValues, setOtpValues] = useState<string[]>(Array(length).fill(""));
|
||||
const inputsRef = useRef<(HTMLInputElement | null)[]>([]);
|
||||
|
||||
// Auto focus first input on mount
|
||||
// ✅ Pre-fill inputs if code is passed
|
||||
useEffect(() => {
|
||||
if (code) {
|
||||
const codeString = String(code);
|
||||
const filled = codeString.split("").slice(0, length);
|
||||
const padded = filled.concat(Array(length - filled.length).fill(""));
|
||||
setOtpValues(padded);
|
||||
if (filled.length === length) {
|
||||
onComplete(filled.join(""));
|
||||
}
|
||||
}
|
||||
}, [code, length, onComplete]);
|
||||
|
||||
// ✅ Focus first input on mount
|
||||
useEffect(() => {
|
||||
inputsRef.current[0]?.focus();
|
||||
}, []);
|
||||
@@ -19,14 +104,18 @@ const OTPInput: React.FC<{ length?: number; onComplete: (otp: string) => void }>
|
||||
inputsRef.current[index + 1]?.focus();
|
||||
}
|
||||
|
||||
if (newOtp.every((digit) => digit !== '')) {
|
||||
onComplete(newOtp.join(''));
|
||||
// ✅ Only trigger onComplete when all digits are filled
|
||||
if (newOtp.every((digit) => digit !== "")) {
|
||||
onComplete(newOtp.join(""));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>, index: number) => {
|
||||
if (e.key === 'Backspace' && !otpValues[index] && index > 0) {
|
||||
const handleKeyDown = (
|
||||
e: React.KeyboardEvent<HTMLInputElement>,
|
||||
index: number
|
||||
) => {
|
||||
if (e.key === "Backspace" && !otpValues[index] && index > 0) {
|
||||
inputsRef.current[index - 1]?.focus();
|
||||
}
|
||||
};
|
||||
@@ -39,7 +128,7 @@ const OTPInput: React.FC<{ length?: number; onComplete: (otp: string) => void }>
|
||||
type="text"
|
||||
className="otp-input"
|
||||
maxLength={1}
|
||||
value={value}
|
||||
value={value ?? ""}
|
||||
onChange={(e) => handleChange(e.target.value, index)}
|
||||
onKeyDown={(e) => handleKeyDown(e, index)}
|
||||
ref={(el) => (inputsRef.current[index] = el)}
|
||||
|
||||
@@ -1,57 +1,77 @@
|
||||
import React, { useState } from 'react';
|
||||
import OTPInput from './OTPInput';
|
||||
import React, { FormEvent, useState } from "react";
|
||||
import OTPInput from "./OTPInput";
|
||||
|
||||
interface Props {
|
||||
email: string;
|
||||
timer: number;
|
||||
setCode: (value: string) => void;
|
||||
onSubmit: () => void;
|
||||
resendCode: () => void;
|
||||
email: string;
|
||||
code: string;
|
||||
timer: number;
|
||||
setCode: (value: string) => void;
|
||||
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
|
||||
resendCode: () => void;
|
||||
}
|
||||
|
||||
const OTPVerification: React.FC<Props> = ({ email, timer, setCode, onSubmit, resendCode }) => {
|
||||
const [otp, setOtp] = useState('');
|
||||
const OTPVerification: React.FC<Props> = ({
|
||||
email,
|
||||
timer,
|
||||
setCode,
|
||||
onSubmit,
|
||||
resendCode,
|
||||
code,
|
||||
}) => {
|
||||
const [otp, setOtp] = useState("");
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
console.log('otp.length: ', otp.length);
|
||||
if (otp.length === 4) {
|
||||
onSubmit();
|
||||
} else {
|
||||
alert('Please enter the 4-digit code');
|
||||
}
|
||||
};
|
||||
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
return (
|
||||
<div className='request-container'>
|
||||
<h1 className='header'>Verification</h1>
|
||||
<p className='sub-header'>
|
||||
Enter the 4-digit code sent to <strong>{email}</strong>.
|
||||
</p>
|
||||
<form className='auth-form' onSubmit={handleSubmit}>
|
||||
<OTPInput length={4} onComplete={(code) => { setOtp(code); setCode(code); }} />
|
||||
<div className="timing">
|
||||
{timer > 0
|
||||
? `${String(Math.floor(timer / 60)).padStart(2, '0')}:${String(timer % 60).padStart(2, '0')}`
|
||||
: ''}
|
||||
</div>
|
||||
<button
|
||||
type='submit'
|
||||
className='continue-button'
|
||||
disabled={otp.length < 4} // prevent clicking if not complete
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
</form>
|
||||
<div
|
||||
className={`resend ${timer > 0 ? 'disabled' : ''}`}
|
||||
onClick={timer === 0 ? resendCode : undefined}
|
||||
style={{ cursor: timer === 0 ? 'pointer' : 'not-allowed', opacity: timer === 0 ? 1 : 0.5 }}
|
||||
>
|
||||
If you didn’t receive a code, <span>Resend</span>
|
||||
</div>
|
||||
if (otp.length === 4) {
|
||||
onSubmit(e);
|
||||
} else {
|
||||
alert("Please enter the 4-digit code");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="request-container">
|
||||
<h1 className="header">Verification</h1>
|
||||
<p className="sub-header">
|
||||
Enter the 4-digit code sent to <strong>{email}</strong>.
|
||||
</p>
|
||||
<form className="auth-form" onSubmit={handleSubmit}>
|
||||
<OTPInput
|
||||
length={4}
|
||||
onComplete={(codes) => {
|
||||
setOtp(code);
|
||||
setCode(codes);
|
||||
}}
|
||||
code={code}
|
||||
/>
|
||||
<div className="timing">
|
||||
{timer > 0
|
||||
? `${String(Math.floor(timer / 60)).padStart(2, "0")}:${String(
|
||||
timer % 60
|
||||
).padStart(2, "0")}`
|
||||
: ""}
|
||||
</div>
|
||||
);
|
||||
<button
|
||||
type="submit"
|
||||
className="continue-button"
|
||||
// disabled={otp.length < 4} // prevent clicking if not complete
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
</form>
|
||||
<div
|
||||
className={`resend ${timer > 0 ? "disabled" : ""}`}
|
||||
onClick={timer === 0 ? resendCode : undefined}
|
||||
style={{
|
||||
cursor: timer === 0 ? "pointer" : "not-allowed",
|
||||
opacity: timer === 0 ? 1 : 0.5,
|
||||
}}
|
||||
>
|
||||
If you didn’t receive a code, <span>Resend</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OTPVerification;
|
||||
|
||||
@@ -1,77 +1,82 @@
|
||||
import React, { useState } from 'react';
|
||||
import { EyeIcon } from '../icons/ExportCommonIcons';
|
||||
import React, { useState } from "react";
|
||||
import { EyeIcon } from "../icons/ExportCommonIcons";
|
||||
|
||||
interface Props {
|
||||
newPassword: string;
|
||||
confirmPassword: string;
|
||||
setNewPassword: (value: string) => void;
|
||||
setConfirmPassword: (value: string) => void;
|
||||
onSubmit: () => void;
|
||||
newPassword: string;
|
||||
confirmPassword: string;
|
||||
setNewPassword: (value: string) => void;
|
||||
setConfirmPassword: (value: string) => void;
|
||||
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
|
||||
}
|
||||
|
||||
const PasswordSetup: React.FC<Props> = ({
|
||||
newPassword,
|
||||
confirmPassword,
|
||||
setNewPassword,
|
||||
setConfirmPassword,
|
||||
onSubmit
|
||||
newPassword,
|
||||
confirmPassword,
|
||||
setNewPassword,
|
||||
setConfirmPassword,
|
||||
onSubmit,
|
||||
}) => {
|
||||
const [showNewPassword, setShowNewPassword] = useState(false);
|
||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||
const [showNewPassword, setShowNewPassword] = useState(false);
|
||||
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
||||
|
||||
return (
|
||||
<div className='request-container'>
|
||||
<h1 className='header'>New Password</h1>
|
||||
<p className='sub-header'>Set the new password for your account so you can login and access all features.</p>
|
||||
<form
|
||||
className='auth-form'
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
if (newPassword !== confirmPassword) {
|
||||
alert('Passwords do not match');
|
||||
return;
|
||||
}
|
||||
onSubmit();
|
||||
}}
|
||||
>
|
||||
<div className="password-container">
|
||||
<input
|
||||
type={showNewPassword ? 'text' : 'password'}
|
||||
placeholder='Enter new password'
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="toggle-password"
|
||||
onClick={() => setShowNewPassword(prev => !prev)}
|
||||
>
|
||||
<EyeIcon isClosed={!showNewPassword} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="password-container">
|
||||
<input
|
||||
type={showConfirmPassword ? 'text' : 'password'}
|
||||
placeholder='Confirm password'
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="toggle-password"
|
||||
onClick={() => setShowConfirmPassword(prev => !prev)}
|
||||
>
|
||||
<EyeIcon isClosed={!showConfirmPassword} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type='submit' className='continue-button'>Update password</button>
|
||||
</form>
|
||||
return (
|
||||
<div className="request-container">
|
||||
<h1 className="header">New Password</h1>
|
||||
<p className="sub-header">
|
||||
Set the new password for your account so you can login and access all
|
||||
features.
|
||||
</p>
|
||||
<form
|
||||
className="auth-form"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
if (newPassword !== confirmPassword) {
|
||||
alert("Passwords do not match");
|
||||
return;
|
||||
}
|
||||
onSubmit(e);
|
||||
}}
|
||||
>
|
||||
<div className="password-container">
|
||||
<input
|
||||
type={showNewPassword ? "text" : "password"}
|
||||
placeholder="Enter new password"
|
||||
value={newPassword}
|
||||
onChange={(e) => setNewPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="toggle-password"
|
||||
onClick={() => setShowNewPassword((prev) => !prev)}
|
||||
>
|
||||
<EyeIcon isClosed={!showNewPassword} />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
<div className="password-container">
|
||||
<input
|
||||
type={showConfirmPassword ? "text" : "password"}
|
||||
placeholder="Confirm password"
|
||||
value={confirmPassword}
|
||||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="toggle-password"
|
||||
onClick={() => setShowConfirmPassword((prev) => !prev)}
|
||||
>
|
||||
<EyeIcon isClosed={!showConfirmPassword} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="submit" className="continue-button">
|
||||
Update password
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PasswordSetup;
|
||||
|
||||
@@ -1,92 +1,134 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { LogoIconLarge } from '../components/icons/Logo';
|
||||
import EmailInput from '../components/forgotPassword/EmailInput';
|
||||
import OTPVerification from '../components/forgotPassword/OTP_Verification';
|
||||
import PasswordSetup from '../components/forgotPassword/PasswordSetup';
|
||||
import ConfirmationMessage from '../components/forgotPassword/ConfirmationMessgae';
|
||||
import React, { useState, useEffect, FormEvent } from "react";
|
||||
import { LogoIconLarge } from "../components/icons/Logo";
|
||||
import EmailInput from "../components/forgotPassword/EmailInput";
|
||||
import OTPVerification from "../components/forgotPassword/OTP_Verification";
|
||||
import PasswordSetup from "../components/forgotPassword/PasswordSetup";
|
||||
import ConfirmationMessage from "../components/forgotPassword/ConfirmationMessgae";
|
||||
import { changePasswordApi } from "../services/factoryBuilder/signInSignUp/changePasswordApi";
|
||||
import { checkEmailApi } from "../services/factoryBuilder/signInSignUp/checkEmailApi";
|
||||
import { verifyOtpApi } from "../services/factoryBuilder/signInSignUp/verifyOtpApi";
|
||||
|
||||
const ForgotPassword: React.FC = () => {
|
||||
const [step, setStep] = useState(1);
|
||||
const [email, setEmail] = useState('');
|
||||
const [code, setCode] = useState('');
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
const [confirmPassword, setConfirmPassword] = useState('');
|
||||
const [timer, setTimer] = useState(30);
|
||||
const [step, setStep] = useState(1);
|
||||
const [email, setEmail] = useState("");
|
||||
const [code, setCode] = useState("");
|
||||
const [newPassword, setNewPassword] = useState("");
|
||||
const [confirmPassword, setConfirmPassword] = useState("");
|
||||
const [timer, setTimer] = useState(30);
|
||||
const [resetToken, setResetToken] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
let countdown: NodeJS.Timeout;
|
||||
if (step === 2 && timer > 0) {
|
||||
countdown = setTimeout(() => setTimer(prev => prev - 1), 1000);
|
||||
}
|
||||
return () => clearTimeout(countdown);
|
||||
}, [step, timer]);
|
||||
|
||||
const handleSubmitEmail = () => {
|
||||
setStep(2);
|
||||
setTimer(30);
|
||||
useEffect(() => {
|
||||
let countdown: NodeJS.Timeout;
|
||||
if (step === 2 && timer > 0) {
|
||||
countdown = setTimeout(() => setTimer((prev) => prev - 1), 1000);
|
||||
}
|
||||
const resendCode = () => {
|
||||
// TODO: call API to resend code
|
||||
setTimer(30);
|
||||
};
|
||||
return () => clearTimeout(countdown);
|
||||
}, [step, timer]);
|
||||
|
||||
return (
|
||||
<div className='forgot-password-page auth-container'>
|
||||
<div className='forgot-password-wrapper'>
|
||||
<div className='logo-icon'>
|
||||
<LogoIconLarge />
|
||||
</div>
|
||||
const resendCode = async () => {
|
||||
// TODO: call API to resend code
|
||||
setTimer(30);
|
||||
try {
|
||||
const emailResponse = await checkEmailApi(email);
|
||||
|
||||
if (emailResponse.message == "OTP sent Successfully") {
|
||||
setCode(emailResponse.OTP);
|
||||
}
|
||||
} catch {}
|
||||
};
|
||||
const handleEmailSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
setTimer(30);
|
||||
try {
|
||||
const emailResponse = await checkEmailApi(email);
|
||||
|
||||
{step === 1 && (
|
||||
<>
|
||||
<EmailInput
|
||||
email={email}
|
||||
setEmail={setEmail}
|
||||
onSubmit={handleSubmitEmail}
|
||||
/>
|
||||
<a href='/' className='login continue-button'>Login</a>
|
||||
</>
|
||||
if (emailResponse.message == "OTP sent Successfully") {
|
||||
setStep(2);
|
||||
setCode(emailResponse.OTP);
|
||||
}
|
||||
} catch {}
|
||||
};
|
||||
|
||||
)}
|
||||
const handleOTPSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
try {
|
||||
const otpResponse = await verifyOtpApi(email, Number(code));
|
||||
|
||||
if (otpResponse.message == "OTP verified successfully") {
|
||||
setResetToken(otpResponse.resetToken);
|
||||
setStep(3);
|
||||
} else {
|
||||
alert(otpResponse.message);
|
||||
}
|
||||
} catch {}
|
||||
};
|
||||
|
||||
{step === 2 && (
|
||||
<>
|
||||
<OTPVerification
|
||||
email={email}
|
||||
timer={timer}
|
||||
setCode={setCode}
|
||||
onSubmit={() => setStep(3)}
|
||||
resendCode={resendCode}
|
||||
/>
|
||||
<a href='/' className='login'>Login</a>
|
||||
</>
|
||||
const handlePasswordSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
try {
|
||||
const passwordResponse = await changePasswordApi(
|
||||
resetToken,
|
||||
newPassword,
|
||||
confirmPassword
|
||||
);
|
||||
if (passwordResponse.message === "Password reset successfull!!") {
|
||||
setStep(4);
|
||||
}
|
||||
} catch {}
|
||||
};
|
||||
|
||||
)}
|
||||
|
||||
|
||||
{step === 3 && (
|
||||
<>
|
||||
<PasswordSetup
|
||||
newPassword={newPassword}
|
||||
confirmPassword={confirmPassword}
|
||||
setNewPassword={setNewPassword}
|
||||
setConfirmPassword={setConfirmPassword}
|
||||
onSubmit={() => setStep(4)}
|
||||
/>
|
||||
<a href='/' className='login'>Login</a>
|
||||
</>
|
||||
|
||||
)}
|
||||
|
||||
|
||||
{step === 4 && <ConfirmationMessage />}
|
||||
|
||||
|
||||
</div>
|
||||
return (
|
||||
<div className="forgot-password-page auth-container">
|
||||
<div className="forgot-password-wrapper">
|
||||
<div className="logo-icon">
|
||||
<LogoIconLarge />
|
||||
</div>
|
||||
);
|
||||
|
||||
{step === 1 && (
|
||||
<>
|
||||
<EmailInput
|
||||
email={email}
|
||||
setEmail={setEmail}
|
||||
onSubmit={handleEmailSubmit}
|
||||
/>
|
||||
<a href="/" className="login continue-button">
|
||||
Login
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
|
||||
{step === 2 && (
|
||||
<>
|
||||
<OTPVerification
|
||||
code={code}
|
||||
email={email}
|
||||
timer={timer}
|
||||
setCode={setCode}
|
||||
onSubmit={handleOTPSubmit}
|
||||
resendCode={resendCode}
|
||||
/>
|
||||
<a href="/" className="login">
|
||||
Login
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
|
||||
{step === 3 && (
|
||||
<>
|
||||
<PasswordSetup
|
||||
newPassword={newPassword}
|
||||
confirmPassword={confirmPassword}
|
||||
setNewPassword={setNewPassword}
|
||||
setConfirmPassword={setConfirmPassword}
|
||||
onSubmit={handlePasswordSubmit}
|
||||
/>
|
||||
<a href="/" className="login">
|
||||
Login
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
|
||||
{step === 4 && <ConfirmationMessage />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ForgotPassword;
|
||||
|
||||
@@ -34,7 +34,7 @@ const UserAuth: React.FC = () => {
|
||||
|
||||
useEffect(() => {
|
||||
initializeFingerprint();
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
const { userId, organization } = getUserData();
|
||||
|
||||
@@ -47,7 +47,6 @@ const UserAuth: React.FC = () => {
|
||||
setError("");
|
||||
setOrganization(organization);
|
||||
setUserName(res.message.name);
|
||||
// console.log(' res.userId: ', res.message.userId);
|
||||
localStorage.setItem("userId", res.message.userId);
|
||||
localStorage.setItem("email", res.message.email);
|
||||
localStorage.setItem("userName", res.message.name);
|
||||
@@ -55,33 +54,46 @@ const UserAuth: React.FC = () => {
|
||||
localStorage.setItem("refreshToken", res.message.refreshToken);
|
||||
|
||||
try {
|
||||
const projects = await recentlyViewed(organization, res.message.userId);
|
||||
const projects = await recentlyViewed(
|
||||
organization,
|
||||
res.message.userId
|
||||
);
|
||||
if (res.message.isShare) {
|
||||
if (Object.values(projects.RecentlyViewed).length > 0) {
|
||||
const recent_opend_projectID = (Object.values(projects?.RecentlyViewed || {})[0] as any)?._id;
|
||||
if (Object.values(projects?.RecentlyViewed).filter((val: any) => val._id == recent_opend_projectID)) {
|
||||
setLoadingProgress(1)
|
||||
navigate(`/projects/${recent_opend_projectID}`)
|
||||
const recent_opend_projectID = (
|
||||
Object.values(projects?.RecentlyViewed || {})[0] as any
|
||||
)?._id;
|
||||
if (
|
||||
Object.values(projects?.RecentlyViewed).filter(
|
||||
(val: any) => val._id == recent_opend_projectID
|
||||
)
|
||||
) {
|
||||
setLoadingProgress(1);
|
||||
navigate(`/projects/${recent_opend_projectID}`);
|
||||
} else {
|
||||
navigate("/Dashboard")
|
||||
navigate("/Dashboard");
|
||||
}
|
||||
} else {
|
||||
setLoadingProgress(1);
|
||||
navigate("/Dashboard");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error fetching recent projects:", error);
|
||||
}
|
||||
} else if (res.message === "User Not Found!!! Kindly signup...") {
|
||||
setError("Account not found");
|
||||
} else if (res.message === "Email & Password is invalid...Check the credentials") {
|
||||
setError(res.message)
|
||||
} else if (res.message === "Already LoggedIn on another browser....Please logout!!!") {
|
||||
} else if (
|
||||
res.message === "Email & Password is invalid...Check the credentials"
|
||||
) {
|
||||
setError(res.message);
|
||||
} else if (
|
||||
res.message ===
|
||||
"Already LoggedIn on another browser....Please logout!!!"
|
||||
) {
|
||||
setError("Already logged in on another browser. Please logout first.");
|
||||
navigate("/");
|
||||
setError("")
|
||||
setError("");
|
||||
// setError("");
|
||||
// setOrganization(organization);
|
||||
// setUserName(res.ForceLogoutData.userName);
|
||||
@@ -179,6 +191,7 @@ const UserAuth: React.FC = () => {
|
||||
name="email"
|
||||
value={email}
|
||||
placeholder="Email"
|
||||
autoComplete="email"
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
/>
|
||||
@@ -188,6 +201,7 @@ const UserAuth: React.FC = () => {
|
||||
type={showPassword ? "text" : "password"}
|
||||
value={password}
|
||||
placeholder="Password"
|
||||
autoComplete="current-password"
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
@@ -201,7 +215,11 @@ const UserAuth: React.FC = () => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{isSignIn && <a href="forgot" className="forgot-password">Forgot password ?</a>}
|
||||
{isSignIn && (
|
||||
<a href="forgot" className="forgot-password">
|
||||
Forgot password ?
|
||||
</a>
|
||||
)}
|
||||
|
||||
{!isSignIn && (
|
||||
<div className="policy-checkbox">
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
export const changePasswordApi = async (
|
||||
resetToken: string,
|
||||
newPassword: string,
|
||||
confirmPassword: string
|
||||
) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${url_Backend_dwinzo}/api/V1/Auth/reset-password/${resetToken}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ newPassword, confirmPassword }),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
echo.error("Failed to create password");
|
||||
if (error instanceof Error) {
|
||||
return { error: error.message };
|
||||
} else {
|
||||
return { error: "An unknown error occurred" };
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
export const checkEmailApi = async (Email: string) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${url_Backend_dwinzo}/api/V1/Auth/forgetPassword`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ Email }),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
echo.error("Failed to create password");
|
||||
if (error instanceof Error) {
|
||||
return { error: error.message };
|
||||
} else {
|
||||
return { error: "An unknown error occurred" };
|
||||
}
|
||||
}
|
||||
};
|
||||
28
app/src/services/factoryBuilder/signInSignUp/verifyOtpApi.ts
Normal file
28
app/src/services/factoryBuilder/signInSignUp/verifyOtpApi.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_REST_API_BASE_URL}`;
|
||||
|
||||
export const verifyOtpApi = async (Email: string, Otp: number) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${url_Backend_dwinzo}/api/V1/Auth/validate-otp`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
Email,
|
||||
otp: Number(Otp),
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
echo.error("Failed to create password");
|
||||
if (error instanceof Error) {
|
||||
return { error: error.message };
|
||||
} else {
|
||||
return { error: "An unknown error occurred" };
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user