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 { callCustomAPI, oauthLoginApi } from "@/utils/callCustomAPI";
|
||||||
import { LoadingButton } from "@/components/frontend";
|
import { LoadingButton } from "@/components/frontend";
|
||||||
import TLDs from "@/assets/json/email-tlds.json";
|
import TLDs from "@/assets/json/email-tlds.json";
|
||||||
|
import ReCAPTCHA from "react-google-recaptcha";
|
||||||
|
|
||||||
const SignUpForm = () => {
|
const SignUpForm = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -15,9 +16,18 @@ const SignUpForm = () => {
|
|||||||
const role = signUpData.role;
|
const role = signUpData.role;
|
||||||
const schema = yup.object({
|
const schema = yup.object({
|
||||||
email: yup
|
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 [loading, setLoading] = useState(false);
|
||||||
|
const [recaptchaValue, setRecaptchaValue] = useState(null);
|
||||||
|
const [recaptchaError, setRecaptchaError] = useState("");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
@@ -32,12 +42,20 @@ const SignUpForm = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = async (data) => {
|
const onSubmit = async (data) => {
|
||||||
|
setRecaptchaError("");
|
||||||
|
if (!recaptchaValue) {
|
||||||
|
setRecaptchaError("Please complete the recaptcha.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
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");
|
if (result.error || result.exist) throw new Error("User already exists");
|
||||||
|
|
||||||
dispatch({ type: "SET_EMAIL", payload: data.email });
|
dispatch({ type: "SET_EMAIL", payload: data.email });
|
||||||
navigate("/signup/details" + "?role=" + role);
|
navigate("/signup/details" + "?role=" + role);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -61,77 +79,87 @@ const SignUpForm = () => {
|
|||||||
window.open(result.data, "_self");
|
window.open(result.data, "_self");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if (!signUpData.role) return <Navigate to={"/signup/select-role"} />;
|
if (!signUpData.role) return <Navigate to={"/signup/select-role"} />;
|
||||||
|
|
||||||
return (
|
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
|
<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)}
|
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
|
<input
|
||||||
autoComplete="off"
|
autoComplete='off'
|
||||||
{...register("email")}
|
{...register("email")}
|
||||||
type="text"
|
type='text'
|
||||||
className="mb-8 resize-none rounded-sm border-2 bg-transparent p-2 px-4 focus:outline-none active:outline-none"
|
className='mb-8 resize-none rounded-sm border-2 bg-transparent p-2 px-4 focus:outline-none active:outline-none'
|
||||||
placeholder="Email"
|
placeholder='Email'
|
||||||
/>
|
/>
|
||||||
{Object.entries(errors).length > 0 ? (
|
{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
|
<LoadingButton
|
||||||
loading={loading}
|
loading={loading}
|
||||||
type="submit"
|
type='submit'
|
||||||
className={`login-btn-gradient rounded tracking-wide text-white outline-none focus:outline-none ${loading ? "py-1" : "py-2"}`}
|
className={`login-btn-gradient rounded tracking-wide text-white outline-none focus:outline-none ${
|
||||||
|
loading ? "py-1" : "py-2"
|
||||||
|
}`}
|
||||||
|
disabled={!recaptchaValue}
|
||||||
>
|
>
|
||||||
Continue
|
Continue
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
<div className="hr my-6 text-center">OR</div>
|
<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='oauth flex w-full max-w-md flex-col gap-4 px-6 text-[#344054]'>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleGoogleLogin()}
|
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
|
<img src='/google-icon.png' className='h-[18px] w-[18px]' />
|
||||||
src="/google-icon.png"
|
|
||||||
className="h-[18px] w-[18px]"
|
|
||||||
/>
|
|
||||||
<span>Sign Up With Google</span>
|
<span>Sign Up With Google</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleFacebookLogin()}
|
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
|
<img src='/facebook-icon.png' className='h-[16px] w-[16px]' />
|
||||||
src="/facebook-icon.png"
|
|
||||||
className="h-[16px] w-[16px]"
|
|
||||||
/>
|
|
||||||
<span>Sign Up With Facebook</span>
|
<span>Sign Up With Facebook</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => handleAppleLogin()}
|
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
|
<img src='/apple-icon.png' className='h-[16px] w-[16px]' />
|
||||||
src="/apple-icon.png"
|
|
||||||
className="h-[16px] w-[16px]"
|
|
||||||
/>
|
|
||||||
<span>Sign Up With Apple</span>
|
<span>Sign Up With Apple</span>
|
||||||
</button>
|
</button>
|
||||||
<div>
|
<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?{" "}
|
Already have an account?{" "}
|
||||||
<Link
|
<Link
|
||||||
to={"/login" + "?role=" + role}
|
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
|
Log In
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
@@ -140,8 +168,15 @@ const SignUpForm = () => {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
style={{ backgroundImage: `url(${role == "host" ? "/jumbotron1.jpg" : "/sign-up-bg.jpg"})`, backgroundSize: "cover", backgroundRepeat: "no-repeat", backgroundPosition: "center" }}
|
style={{
|
||||||
className="hidden w-1/2 md:block bg-contain"
|
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>
|
></section>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user