import "../Login/login.css";
import { React, useState } from "react";
import { NavLink, useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import { useRegisterUser } from "../../../apis/SignUp";
import { Spin } from "antd";
import VerifyModal from "./VerifyModal";
/**
* Page for the signup form.
* @module SignUpForm
*/
const SignupForm = () => {
/**
* State variable for the phone input.
* @type {string}
* @name phone
* @default ""
* @memberof SignUpForm
*/
const [phone, setPhone] = useState("");
/**
* State variable for the email input.
* @type {string}
*/
const [email, setEmail] = useState("");
/**
* State variable for the first name input.
* @type {string}
*/
const [first_name, setFirst_name] = useState("");
/**
* State variable for the last name input.
* @type {string}
*/
const [last_name, setLast_name] = useState("");
/**
* State variable for the first password input.
* @type {string}
*/
const [password_one, setPassword_one] = useState("");
/**
* State variable for the second password input.
* @type {string}
*/
const [password_two, setPassword_two] = useState("");
/**
* State variable for displaying the OTP modal.
* @type {boolean}
*/
const [otpModal, setOtpModal] = useState(false);
/**
* State variable for storing the registration token.
* @type {string}
*/
const [token, setToken] = useState(null);
/**
* State variable for toggling password visibility.
* @type {boolean}
*/
const [passwordShown, setPasswordShown] = useState(false);
/**
* State variable for toggling confirm password visibility.
* @type {boolean}
*/
const [confipasswordShown, setComfiPasswordShown] = useState(false);
/**
* State variable for validation errors.
* @type {object}
*/
const [validationErrors, setValidationErrors] = useState({});
/**
* Hook for registering a new user.
*/
const { mutate: registerMutate, isLoading: registerLoading } =
useRegisterUser();
/**
* Handles the form submission when signing up.
* @function handleSignUp
* @param {Event} event - The form submission event.
*/
const handleSignUp = (event) => {
event.preventDefault();
let data = {
phone,
email,
first_name,
last_name,
password_one,
password_two,
};
if (validateForm()) {
registerMutate(data, {
onSuccess: (res) => {
let temp_token = res?.data?.data?.token;
setToken(temp_token);
setOtpModal(true);
toast.success(
"User registered successfully, Please verify your otp."
);
},
});
}
};
/**
* Validates the form inputs and displays validation errors if any.
* @function validateForm
* @returns {boolean} True if the form is valid, false otherwise.
*/
const validateForm = () => {
const errors = {};
let isValid = true;
if (first_name.trim() === "") {
errors.firstname = "First name is required";
isValid = false;
}
if (last_name.trim() === "") {
errors.lastname = "Last name is required";
isValid = false;
}
if (phone.trim() === "") {
errors.phoneNumber = "Phone number is required";
isValid = false;
} else if (phone.length !== 10) {
errors.phoneNumber = "Phone number should contain 10 digits";
isValid = false;
}
if (email.trim() === "") {
errors.email = "Email address is required";
isValid = false;
} else if (!isValidEmail(email)) {
errors.email = "Invalid email address";
isValid = false;
}
if (password_one.trim() === "") {
errors.password = "Password is required";
isValid = false;
} else if (password_one.trim() !== "") {
errors.password = isValidPassword(password_one);
if (password_one !== password_two) {
errors.confirmPassword = "Passwords do not match";
isValid = false;
}
}
setValidationErrors(errors);
return isValid;
};
/**
* Checks if an email is valid based on a basic regex pattern.
* @function isValidEmail
* @param {string} email - The email address to validate.
* @returns {boolean} True if the email is valid, false otherwise.
*/
const isValidEmail = (email) => {
// Basic email validation regex
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
/**
* Validates a password based on certain criteria.
* @function isValidPassword
* @param {string} password - The password to validate.
* @returns {string|null} Validation error message or null if valid.
*/
const isValidPassword = (password) => {
let caps, small, num, specialSymbol;
if (password.length < 8) {
return "Password should contain minimum 8 characters.";
} else {
caps = (password.match(/[A-Z]/g) || []).length;
small = (password.match(/[a-z]/g) || []).length;
num = (password.match(/[0-9]/g) || []).length;
specialSymbol = (password.match(/\W/g) || []).length;
if (caps < 1) {
return "Must add one UPPERCASE letter";
} else if (small < 1) {
return "Must add one lowercase letter";
} else if (num < 1) {
return "Must add one number";
} else if (specialSymbol < 1) {
return "Must add one special symbol: @$! % * ? &";
}
}
};
return (
<div className="login_form_container">
<div className="register_form_card">
<VerifyModal
otpModal={otpModal}
setOtpModal={setOtpModal}
token={token}
/>
<form action="" onSubmit={handleSignUp}>
<div className="form_card_body">
<div className="register_wrapper">
<div className="register_left">
<img src="/register.png" alt="" className="auth_img" />
</div>
<div className="register_right">
<div className="form_card_heading">
<div className="logo_div">
<NavLink to="/">
<img src="./psmsLogo.png" alt="" />
</NavLink>
</div>
</div>
<div className="login_form_row">
<div className="login_form_group">
<label htmlFor="">Firstname</label>
<div className="form_input">
<input
type="text"
placeholder=""
onChange={(e) => setFirst_name(e.target.value)}
/>
</div>
{validationErrors.firstname && (
<span className="error">
{validationErrors.firstname}
</span>
)}
</div>
<div className="login_form_group">
<label htmlFor="">Lastname</label>
<div className="form_input">
<input
type="text"
placeholder=""
onChange={(e) => setLast_name(e.target.value)}
/>
</div>
{validationErrors.lastname && (
<span className="error">{validationErrors.lastname}</span>
)}
</div>
</div>
<div className="login_form_group">
<label htmlFor="">Phone number</label>
<div className="form_input">
<input
type="number"
placeholder=""
onChange={(e) => setPhone(e.target.value)}
/>
</div>
{validationErrors.phoneNumber && (
<span className="error">
{validationErrors.phoneNumber}
</span>
)}
</div>
<div className="login_form_group">
<label htmlFor="">Email address</label>
<div className="form_input">
<input
type="email"
placeholder=""
onChange={(e) => setEmail(e.target.value)}
/>
</div>
{validationErrors.email && (
<span className="error">{validationErrors.email}</span>
)}
</div>
<div className="login_form_group">
<label htmlFor="">Password</label>
<div className="form_input">
<input
type={passwordShown ? "text" : "password"}
placeholder=""
onChange={(e) => setPassword_one(e.target.value)}
/>
{passwordShown ? (
<ion-icon
name="eye"
onClick={() => setPasswordShown(!passwordShown)}
></ion-icon>
) : (
<ion-icon
name="eye-off"
onClick={() => setPasswordShown(!passwordShown)}
></ion-icon>
)}
{/* {error && <p style={{ color: 'red' }}>Password must include at least one lowercase letter, one digit, and one special character.</p>} */}
</div>
{validationErrors.password && (
<span className="error">{validationErrors.password}</span>
)}
</div>
<div className="login_form_group">
<label htmlFor="">Confirm Password</label>
<div className="form_input">
<input
type={confipasswordShown ? "text" : "password"}
placeholder=""
onChange={(e) => setPassword_two(e.target.value)}
/>
{confipasswordShown ? (
<ion-icon
name="eye"
onClick={() =>
setComfiPasswordShown(!confipasswordShown)
}
></ion-icon>
) : (
<ion-icon
name="eye-off"
onClick={() =>
setComfiPasswordShown(!confipasswordShown)
}
></ion-icon>
)}
</div>
{validationErrors.confirmPassword && (
<span className="error">
{validationErrors.confirmPassword}
</span>
)}
</div>
{/* {error && <p style={{ color: "red" }}>{error}</p>} */}
<div className="register_form_group">
<button className="register_btn" type="submit">
{registerLoading ? <Spin size="small" /> : "Sign Up"}
</button>
</div>
<div className="register_form_link">
<span>
Already have an account?
<NavLink to="/login" className={"ms-2"}>
Login
</NavLink>
</span>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
);
};
export default SignupForm;
Source