diff --git a/frontend/src/components/auth/SignupForm.tsx b/frontend/src/components/auth/SignupForm.tsx index 1a885299..d23791d8 100644 --- a/frontend/src/components/auth/SignupForm.tsx +++ b/frontend/src/components/auth/SignupForm.tsx @@ -1,9 +1,11 @@ +import { useEffect, useState } from "react"; import { SubmitHandler, useForm } from "react-hook-form"; import { Link, useNavigate } from "react-router-dom"; import ErrorMessage from "@/components/ui/ErrorMessage"; import { Input } from "@/components/ui/Input/Input"; import PasswordInput from "@/components/ui/Input/PasswordInput"; +import Spinner from "@/components/ui/Spinner"; import { Button } from "@/components/ui/button"; import { useAlertQueue } from "@/hooks/useAlertQueue"; import { useAuthentication } from "@/hooks/useAuth"; @@ -20,6 +22,7 @@ const SignupForm: React.FC = ({ signupTokenId }) => { const auth = useAuthentication(); const { addAlert, addErrorAlert } = useAlertQueue(); const navigate = useNavigate(); + const [isValidating, setIsValidating] = useState(true); const { register, @@ -34,6 +37,35 @@ const SignupForm: React.FC = ({ signupTokenId }) => { const confirmPassword = watch("confirmPassword") || ""; const passwordStrength = password.length > 0 ? zxcvbn(password).score : 0; + useEffect(() => { + const validateToken = async () => { + try { + const { error } = await auth.client.GET("/auth/email/signup/get/{id}", { + params: { + path: { id: signupTokenId }, + }, + }); + + if (error) { + addErrorAlert(error); + navigate(ROUTES.HOME.path); + } + } finally { + setIsValidating(false); + } + }; + + validateToken(); + }, [signupTokenId]); + + if (isValidating) { + return ( +
+ +
+ ); + } + const onSubmit: SubmitHandler = async (data: SignupType) => { // Exit account creation early if password too weak or not matching if (passwordStrength < 2) { @@ -92,19 +124,22 @@ const SignupForm: React.FC = ({ signupTokenId }) => { showStrength={false} /> {/* TOS Text */} -
+
By signing up, you agree to our
- + terms and conditions {" "} and{" "} - + privacy policy .
{/* Signup Button */} - + ); }; diff --git a/frontend/src/components/pages/EmailSignup.tsx b/frontend/src/components/pages/EmailSignup.tsx index 76d01f4e..dca29e62 100644 --- a/frontend/src/components/pages/EmailSignup.tsx +++ b/frontend/src/components/pages/EmailSignup.tsx @@ -5,6 +5,7 @@ import { useTypedParams } from "react-router-typesafe-routes/dom"; import SignupForm from "@/components/auth/SignupForm"; import { Card, CardContent, CardHeader } from "@/components/ui/Card"; import Header from "@/components/ui/Header"; +import Spinner from "@/components/ui/Spinner"; import { Button } from "@/components/ui/button"; import { paths } from "@/gen/api"; import { useAlertQueue } from "@/hooks/useAlertQueue"; @@ -19,12 +20,14 @@ const EmailSignup = () => { const auth = useAuthentication(); const { addErrorAlert } = useAlertQueue(); const { id } = useTypedParams(ROUTES.SIGNUP.EMAIL); + const [isLoading, setIsLoading] = useState(true); const [signupToken, setSignupToken] = useState(null); useEffect(() => { const fetchSignUpToken = async () => { if (id === undefined) { + setIsLoading(false); return; } @@ -39,19 +42,40 @@ const EmailSignup = () => { ); if (error) { addErrorAlert(error); + setSignupToken(null); } else { setSignupToken(data); } } catch (err) { addErrorAlert(err); + setSignupToken(null); + } finally { + setIsLoading(false); } }; fetchSignUpToken(); }, [id]); + if (isLoading) { + return ( +
+ + +
+ + +
+ +
+
+ +
+ ); + } + return (
- +
@@ -64,7 +88,7 @@ const EmailSignup = () => {

Invalid Sign Up Link