Preview:
import Apis from "../../APIs";
import React, { useState } from "react";
import axios from "axios";
import emailjs from "@emailjs/browser";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import { useNavigate } from "react-router-dom";

const RegisterForm = () => {
  const [email, setEmail] = useState("");
  const [name, setName] = useState("");
  const [phone, setPhone] = useState("");
  const [emailError, setEmailError] = useState("");
  const [nameError, setNameError] = useState("");
  const [phoneError, setPhoneError] = useState("");
  const [loading, setLoading] = useState(false); 

  const navigate = useNavigate();

  const loadScript = (src) => {
    return new Promise((resolve) => {
      const script = document.createElement("script");
      script.src = src;
      script.onload = () => resolve(true);
      script.onerror = () => resolve(false);
      document.body.appendChild(script);
    });
  };

  const createRazorpayOrder = async (amount) => {
    setLoading(true); // Start loading before order creation
    const data = {
      amount: amount * 100,
      currency: "INR",
    };

    try {
      const response = await axios.post(Apis.PAYMENT_API.CREATE_ORDER, data);
      handleRazorpayScreen(response.data.amount, response.data.order_id);
    } catch (error) {
      console.error("Error creating order:", error);
      toast.error("Payment failed. Please try again.");
      setLoading(false); // Stop loading on error
    }
  };

  const handleRazorpayScreen = async (amount, orderId) => {
    const res = await loadScript(
      "https://checkout.razorpay.com/v1/checkout.js"
    );
  
    if (!res) {
      alert("Failed to load Razorpay SDK. Are you online?");
      setLoading(false); // Stop loading if script fails to load
      return;
    }
  
    const options = {
      key: "rzp_test_GcZZFDPP0jHtC4",
      amount: amount,
      currency: "INR",
      name: name,
      description: "Payment for Registration",
      image: "https://papayacoders.com/demo.png",
      order_id: orderId,
      handler: async function (response) {
        setLoading(false); // Stop loading after payment
        if (response && response.razorpay_payment_id) {
          await registerUser(response); // Pass the response object to registerUser
        } else {
          console.error("Payment response is missing or invalid.");
          toast.error("Payment verification failed. Please try again.");
        }
      },
      prefill: {
        name: name,
        email: email,
      },
      theme: {
        color: "#F4C430",
      },
      modal: {
        ondismiss: function () {
          setLoading(false); // Stop loading when Razorpay modal is dismissed
        },
      },
    };
  
    const paymentObject = new window.Razorpay(options);
    setLoading(false); // Stop showing the loader once the payment interface is ready to open
    paymentObject.open();
  };
  

  const generateRandomPassword = () => {
    return Math.random().toString(36).slice(-8);
  };

  const sendEmail = (password) => {
    emailjs
      .send(
        import.meta.env.VITE_APP_EMAILJS_SERVICE_ID,
        import.meta.env.VITE_APP_EMAILJS_TEMPLATE_ID,
        {
          from_name: "See Change",
          to_name: name,
          from_email: "rishirri108@gmail.com",
          to_email: email,
          phoneNumber: phone,
          message: "Thank you for registering on SEE CHANGE",
          password: password,
        },
        import.meta.env.VITE_APP_EMAILJS_PUBLIC_KEY
      )
      .then((result) => {
        console.log("Email successfully sent:", result.text);
      })
      .catch((error) => {
        console.error("Error sending email:", error);
      });
  };

  const registerUser = async (paymentResponse) => {
    if (!paymentResponse || !paymentResponse.razorpay_payment_id) {
      toast.error("Payment response is missing or invalid.");
      return;
    }

    const password = generateRandomPassword();

    const userData = {
      fullName: name,
      email: email,
      phoneNumber: phone,
      password: password,
    };

    try {
      const response = await axios.post(Apis.USER_API, userData);

      if (response.status === 201 || response.status === 200) {
        const paymentData = {
          paymentId: paymentResponse.razorpay_payment_id,
          user: response.data._id,
          amount: 100,
          currency: "INR",
          status: "captured",
          method: "razorpay",
        };

        await axios.post(Apis.PAYMENT_API.SAVE_PAYMENT, paymentData);

        setEmail("");
        setName("");
        setPhone("");
        sendEmail(password);
        navigate("/login", {
          state: { message: "User registered successfully!" },
        });
      } else {
        toast.error("Failed to register user. Please try again.");
      }
    } catch (error) {
      toast.error("This Email or Phone already in use");
      console.error("Error while registering user:", error);
    }
  };

  const handleSubmit = async (e) => {
    e.preventDefault();

    if (!name) setNameError("Please enter your name");
    if (!email) setEmailError("Please enter your email");
    if (!phone) setPhoneError("Please enter your phone number");

    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email))
      setEmailError("Please enter a valid email address");

    if (phone.length !== 10) setPhoneError("Phone number must be 10 digits");

    if (name && emailRegex.test(email) && phone.length === 10) {
      createRazorpayOrder(100);
    }
  };

  return (
    <>
    {loading && (
        <div className="min-h-screen w-full flex items-center justify-center bg-primary-gradient fixed inset-0 z-50">
          <l-infinity
            size="200"
            stroke="4"
            stroke-length="0.15"
            bg-opacity="0.1"
            speed="1.3"
            color="white"
          ></l-infinity>
        </div>
      )}
      <form className="mt-[25px]" onSubmit={handleSubmit}>
        <label className="relative">
          <input
            value={name}
            onChange={(e) => {
              setName(e.target.value.toUpperCase());
              setNameError("");
            }}
            type="text"
            placeholder="Enter Full Name"
            className="w-full h-[55px]   bg-secondary2 pl-4 text-[22px] font-Roboto font-light rounded-lg outline-none border-[0.5px] border-[#1e1e1e] placeholder-gray-600"
          />
          <p className="absolute text-white mix-blend-difference top-[-40px] left-2 text-sm animate-pulse">
            {nameError}
          </p>
        </label>

        <label className="relative">
          <input
            value={email}
            onChange={(e) => {
              setEmail(e.target.value);
              setEmailError("");
            }}
            type="email"
            placeholder="Enter Email"
            className="w-full h-[55px]   bg-secondary2 pl-4 text-[22px] font-Roboto font-light rounded-lg mt-[22px] outline-none border-[0.5px] border-[#1e1e1e] placeholder-gray-600"
          />
          <p className="absolute text-white mix-blend-difference top-[-40px] left-2 text-sm animate-pulse">
            {emailError}
          </p>
        </label>

        <label className="relative">
          <input
            value={phone}
            onChange={(e) => {
              setPhone(e.target.value.replace(/[^0-9]/g, ""));
              setPhoneError("");
            }}
            type="text"
            placeholder="Enter Phone Number"
            maxLength={10}
            className="w-full h-[55px]   bg-secondary2 pl-4 text-[22px] font-Roboto font-light rounded-lg mt-[22px] outline-none border-[0.5px] border-[#1e1e1e] placeholder-gray-600"
          />
          <p className="absolute text-white mix-blend-difference top-[-40px] left-2 text-sm animate-pulse">
            {phoneError}
          </p>
        </label>

        <button
          className="w-full h-[50px] bg-secondary1 hover:bg-sky-300  outline-none rounded-lg mt-5 font-black font-Roboto text-lg border-[2px] border-[#1e1e1e]"
          type="submit"
        >
          Pay and Register
        </button>
      </form>

      <ToastContainer />
    </>
  );
};

export default RegisterForm;
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter