Source

pages/Authentication/Signup/SignupForm.jsx

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;