ISSUE 4: add recaptcha before submission in sign up form and email validation
This commit is contained in:
@@ -8,6 +8,7 @@ import { useSignUpContext } from "./signUpContext";
|
||||
import { callCustomAPI, oauthLoginApi } from "@/utils/callCustomAPI";
|
||||
import { LoadingButton } from "@/components/frontend";
|
||||
import TLDs from "@/assets/json/email-tlds.json";
|
||||
import ReCAPTCHA from "react-google-recaptcha";
|
||||
|
||||
const SignUpForm = () => {
|
||||
const navigate = useNavigate();
|
||||
@@ -15,9 +16,18 @@ const SignUpForm = () => {
|
||||
const role = signUpData.role;
|
||||
const schema = yup.object({
|
||||
email: yup
|
||||
.string(),
|
||||
.string()
|
||||
.required("Email is required")
|
||||
.email("Invalid email address")
|
||||
.test("tld-check", "Invalid email TLD", (value) => {
|
||||
if (!value) return false;
|
||||
const tld = value.split(".").pop();
|
||||
return TLDs.includes(tld);
|
||||
}),
|
||||
});
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [recaptchaValue, setRecaptchaValue] = useState(null);
|
||||
const [recaptchaError, setRecaptchaError] = useState("");
|
||||
|
||||
const {
|
||||
register,
|
||||
@@ -32,12 +42,20 @@ const SignUpForm = () => {
|
||||
});
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
setRecaptchaError("");
|
||||
if (!recaptchaValue) {
|
||||
setRecaptchaError("Please complete the recaptcha.");
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await callCustomAPI("email-exist", "post", { email: data.email }, "");
|
||||
|
||||
const result = await callCustomAPI(
|
||||
"email-exist",
|
||||
"post",
|
||||
{ email: data.email },
|
||||
""
|
||||
);
|
||||
if (result.error || result.exist) throw new Error("User already exists");
|
||||
|
||||
dispatch({ type: "SET_EMAIL", payload: data.email });
|
||||
navigate("/signup/details" + "?role=" + role);
|
||||
} catch (err) {
|
||||
@@ -61,77 +79,87 @@ const SignUpForm = () => {
|
||||
window.open(result.data, "_self");
|
||||
};
|
||||
|
||||
|
||||
if (!signUpData.role) return <Navigate to={"/signup/select-role"} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="flex w-full flex-col items-center justify-center bg-white md:w-1/2">
|
||||
<section className='flex w-full flex-col items-center justify-center bg-white md:w-1/2'>
|
||||
<form
|
||||
className="flex w-full max-w-md flex-col px-6"
|
||||
className='flex w-full max-w-md flex-col px-6'
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
autoComplete="off"
|
||||
autoComplete='off'
|
||||
>
|
||||
<h1 className="mb-8 text-center text-3xl font-semibold md:text-5xl md:font-bold">{role == "host" ? "Become a host" : "Sign up"}</h1>
|
||||
<h1 className='mb-8 text-center text-3xl font-semibold md:text-5xl md:font-bold'>
|
||||
{role == "host" ? "Become a host" : "Sign up"}
|
||||
</h1>
|
||||
<input
|
||||
autoComplete="off"
|
||||
autoComplete='off'
|
||||
{...register("email")}
|
||||
type="text"
|
||||
className="mb-8 resize-none rounded-sm border-2 bg-transparent p-2 px-4 focus:outline-none active:outline-none"
|
||||
placeholder="Email"
|
||||
type='text'
|
||||
className='mb-8 resize-none rounded-sm border-2 bg-transparent p-2 px-4 focus:outline-none active:outline-none'
|
||||
placeholder='Email'
|
||||
/>
|
||||
{Object.entries(errors).length > 0 ? (
|
||||
<p className="error-vibrate my-3 rounded-md border border-[#C42945] bg-white py-2 px-3 text-center text-sm normal-case text-[#C42945]">{Object.values(errors)[0].message}</p>
|
||||
<p className='error-vibrate my-3 rounded-md border border-[#C42945] bg-white px-3 py-2 text-center text-sm normal-case text-[#C42945]'>
|
||||
{Object.values(errors)[0].message}
|
||||
</p>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<div className='mb-4 flex justify-center'>
|
||||
<ReCAPTCHA
|
||||
sitekey={import.meta.env.VITE_RECAPTCHA_SITE_KEY}
|
||||
onChange={(val) => {
|
||||
setRecaptchaValue(val);
|
||||
setRecaptchaError("");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{recaptchaError && (
|
||||
<p className='mb-2 text-center text-xs italic text-red-500'>
|
||||
{recaptchaError}
|
||||
</p>
|
||||
)}
|
||||
<LoadingButton
|
||||
loading={loading}
|
||||
type="submit"
|
||||
className={`login-btn-gradient rounded tracking-wide text-white outline-none focus:outline-none ${loading ? "py-1" : "py-2"}`}
|
||||
type='submit'
|
||||
className={`login-btn-gradient rounded tracking-wide text-white outline-none focus:outline-none ${
|
||||
loading ? "py-1" : "py-2"
|
||||
}`}
|
||||
disabled={!recaptchaValue}
|
||||
>
|
||||
Continue
|
||||
</LoadingButton>
|
||||
|
||||
</form>
|
||||
<div className="hr my-6 text-center">OR</div>
|
||||
<div className="oauth flex w-full max-w-md flex-col gap-4 px-6 text-[#344054]">
|
||||
<div className='hr my-6 text-center'>OR</div>
|
||||
<div className='oauth flex w-full max-w-md flex-col gap-4 px-6 text-[#344054]'>
|
||||
<button
|
||||
onClick={() => handleGoogleLogin()}
|
||||
className="flex items-center justify-center gap-2 border-2 py-[10px]"
|
||||
className='flex items-center justify-center gap-2 border-2 py-[10px]'
|
||||
>
|
||||
<img
|
||||
src="/google-icon.png"
|
||||
className="h-[18px] w-[18px]"
|
||||
/>
|
||||
<img src='/google-icon.png' className='h-[18px] w-[18px]' />
|
||||
<span>Sign Up With Google</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleFacebookLogin()}
|
||||
className="flex items-center justify-center gap-2 border-2 py-[10px]"
|
||||
className='flex items-center justify-center gap-2 border-2 py-[10px]'
|
||||
>
|
||||
<img
|
||||
src="/facebook-icon.png"
|
||||
className="h-[16px] w-[16px]"
|
||||
/>
|
||||
<img src='/facebook-icon.png' className='h-[16px] w-[16px]' />
|
||||
<span>Sign Up With Facebook</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleAppleLogin()}
|
||||
className="flex items-center justify-center gap-2 border-2 py-[10px]"
|
||||
className='flex items-center justify-center gap-2 border-2 py-[10px]'
|
||||
>
|
||||
<img
|
||||
src="/apple-icon.png"
|
||||
className="h-[16px] w-[16px]"
|
||||
/>
|
||||
<img src='/apple-icon.png' className='h-[16px] w-[16px]' />
|
||||
<span>Sign Up With Apple</span>
|
||||
</button>
|
||||
<div>
|
||||
<h3 className="text-center text-sm normal-case text-gray-800">
|
||||
<h3 className='text-center text-sm normal-case text-gray-800'>
|
||||
Already have an account?{" "}
|
||||
<Link
|
||||
to={"/login" + "?role=" + role}
|
||||
className="my-text-gradient mb-8 self-end text-sm font-semibold"
|
||||
className='my-text-gradient mb-8 self-end text-sm font-semibold'
|
||||
>
|
||||
Log In
|
||||
</Link>{" "}
|
||||
@@ -140,8 +168,15 @@ const SignUpForm = () => {
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
style={{ backgroundImage: `url(${role == "host" ? "/jumbotron1.jpg" : "/sign-up-bg.jpg"})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center" }}
|
||||
className="hidden w-1/2 md:block bg-contain"
|
||||
style={{
|
||||
backgroundImage: `url(${
|
||||
role == "host" ? "/jumbotron1.jpg" : "/sign-up-bg.jpg"
|
||||
})`,
|
||||
backgroundSize: "cover",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center",
|
||||
}}
|
||||
className='hidden w-1/2 bg-contain md:block'
|
||||
></section>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user