wait for the captcha to be fetched before allowing form submission
All checks were successful
Deploy / deploy (ubuntu-latest, 2.44.0) (push) Successful in 2m9s

This commit is contained in:
Braydon 2024-09-20 00:06:08 -04:00
parent a71502d0b2
commit 338ce3edf1

@ -1,7 +1,7 @@
"use client"; "use client";
import { z } from "zod"; import { z } from "zod";
import { ReactElement, useState } from "react"; import { ReactElement, useEffect, useState } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
@ -84,8 +84,14 @@ const inputAnimationVariants = {
* @return the form jsx * @return the form jsx
*/ */
const AuthForm = (): ReactElement => { const AuthForm = (): ReactElement => {
const turnstile: TurnstileObject = useTurnstile();
const cookies: Cookies = useCookies();
const router: AppRouterInstance = useRouter();
const [stage, setStage] = useState<"email" | "register" | "login">("email"); const [stage, setStage] = useState<"email" | "register" | "login">("email");
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const [awaitingCaptcha, setAwaitingCaptcha] = useState<boolean>(true);
const [captchaResponse, setCaptchaResponse] = useState<string | undefined>( const [captchaResponse, setCaptchaResponse] = useState<string | undefined>(
undefined undefined
); );
@ -94,9 +100,6 @@ const AuthForm = (): ReactElement => {
const [tfaPin, setTfaPin] = useState<string | undefined>(); const [tfaPin, setTfaPin] = useState<string | undefined>();
const [error, setError] = useState<string | undefined>(undefined); const [error, setError] = useState<string | undefined>(undefined);
const turnstile: TurnstileObject = useTurnstile();
const cookies: Cookies = useCookies();
const router: AppRouterInstance = useRouter();
// Build the form // Build the form
const { const {
@ -113,6 +116,12 @@ const AuthForm = (): ReactElement => {
), ),
}); });
// Received the captcha response
useEffect(() => {
console.log("Received new captcha response");
setAwaitingCaptcha(false);
}, [captchaResponse]);
/** /**
* Handle submitting the form. * Handle submitting the form.
*/ */
@ -122,6 +131,10 @@ const AuthForm = (): ReactElement => {
password, password,
passwordConfirmation, passwordConfirmation,
}: any) => { }: any) => {
// Prevent submitting when the captcha is being fetched
if (awaitingCaptcha) {
return;
}
setLoading(true); setLoading(true);
if (stage === "email") { if (stage === "email") {
const { data, error } = await apiRequest<{ exists: boolean }>({ const { data, error } = await apiRequest<{ exists: boolean }>({
@ -134,6 +147,7 @@ const AuthForm = (): ReactElement => {
} else { } else {
setStage(data?.exists ? "login" : "register"); setStage(data?.exists ? "login" : "register");
} }
setAwaitingCaptcha(true);
turnstile.reset(); turnstile.reset();
} else { } else {
const registering: boolean = stage === "register"; const registering: boolean = stage === "register";
@ -161,6 +175,7 @@ const AuthForm = (): ReactElement => {
setLoading(false); setLoading(false);
setBorderCrossing(true); setBorderCrossing(true);
setError(undefined); setError(undefined);
setAwaitingCaptcha(true);
turnstile.reset(); turnstile.reset();
return; return;
} }
@ -168,6 +183,7 @@ const AuthForm = (): ReactElement => {
// Reset the captcha if auth fails // Reset the captcha if auth fails
if (error) { if (error) {
setAwaitingCaptcha(true);
turnstile.reset(); turnstile.reset();
} else { } else {
// Otherwise store the session and redirect to the dashboard // Otherwise store the session and redirect to the dashboard
@ -240,6 +256,7 @@ const AuthForm = (): ReactElement => {
className="pl-8 rounded-lg" className="pl-8 rounded-lg"
type="password" type="password"
placeholder="Password" placeholder="Password"
disabled={awaitingCaptcha}
{...register("password")} {...register("password")}
/> />
</motion.div> </motion.div>
@ -303,7 +320,7 @@ const AuthForm = (): ReactElement => {
<Button <Button
className="h-11 flex gap-2.5 items-center text-white border border-secondary transition-all transform-gpu group" className="h-11 flex gap-2.5 items-center text-white border border-secondary transition-all transform-gpu group"
type="submit" type="submit"
disabled={loading} disabled={loading || awaitingCaptcha}
> >
{loading && <ArrowPathIcon className="w-4 h-4 animate-spin" />} {loading && <ArrowPathIcon className="w-4 h-4 animate-spin" />}
<span className="-translate-y-0.5"> <span className="-translate-y-0.5">