diff --git a/src/components/nav/PublicNavLinks.tsx b/src/components/nav/PublicNavLinks.tsx index 2201f8a..66cb39d 100644 --- a/src/components/nav/PublicNavLinks.tsx +++ b/src/components/nav/PublicNavLinks.tsx @@ -28,11 +28,18 @@ export default function PublicNavLinks(){ } { !jwt && - + <> + Login - + + + Signup + + } ); diff --git a/src/hooks/AuthHooks.ts b/src/hooks/AuthHooks.ts new file mode 100644 index 0000000..ceb59a2 --- /dev/null +++ b/src/hooks/AuthHooks.ts @@ -0,0 +1,20 @@ +import { Account } from "@/interface/Account"; +import { api } from "@/util/AxiosUtil"; +import { useMutation } from "@tanstack/react-query"; + + +export function useSignup(){ + return useMutation({ + mutationKey: ["signup"], + mutationFn: async (account: Account) => { + const response = await api.post("/auth/signup", account); + + if(response.status !== 200){ + throw new Error("Failed to signup"); + } + else if(response.data.errors){ + throw new Error(response.data.errors.join(", ")); + } + } + }); +} diff --git a/src/hooks/GameHooks.ts b/src/hooks/GameHooks.ts index ac305a3..f726e3b 100644 --- a/src/hooks/GameHooks.ts +++ b/src/hooks/GameHooks.ts @@ -1,6 +1,7 @@ import { Game } from "@/interface/Game"; import { api } from "@/util/AxiosUtil"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { AxiosError } from "axios"; export function useGetGame(gameId: string, disabled: boolean){ @@ -33,16 +34,20 @@ export function useGetGames(page: number, pageSize: number, searchTerm?: string) params.append("searchTerm", searchTerm); } - const response = await api.get(`/game?${params}`); + //TODO: Change all queries to follow this pattern + try{ + const response = await api.get(`/game?${params}`); - if(response.status !== 200){ - throw new Error("Failed to get games"); + return response.data as Game[]; } - else if(response.data.errors){ - throw new Error(response.data.errors.join(", ")); + catch(error){ + if(error instanceof AxiosError && error.response?.data.errors){ + throw new Error(error.response?.data.errors.join(", ")); + } + else{ + throw error; + } } - - return response.data as Game[]; } }); } diff --git a/src/pages/public/SignupPage.tsx b/src/pages/public/SignupPage.tsx index 3da5b26..0dce6e9 100644 --- a/src/pages/public/SignupPage.tsx +++ b/src/pages/public/SignupPage.tsx @@ -1,7 +1,88 @@ +import PrimaryButton from "@/components/button/PrimaryButton"; +import PasswordInput from "@/components/input/PasswordInput"; +import TextInput from "@/components/input/TextInput"; +import { useSignup } from "@/hooks/AuthHooks"; +import { Account } from "@/interface/Account"; +import { useTimedModal } from "@/providers/TimedModalProvider"; +import { useState } from "react"; +import { useNavigate } from "react-router"; + + export default function SignupPage(){ + const navigate = useNavigate(); + const [ username, setUsername ] = useState(""); + const [ password, setPassword ] = useState(""); + const [ secondPassword, setSecondPassword ] = useState(""); + const [ email, setEmail ] = useState(""); + + const signupQuery = useSignup(); + + + const { addSuccessMessage, addErrorMessage } = useTimedModal(); + + + const signup = () => { + if(password !== secondPassword){ + addErrorMessage("Passwords do not match"); + return; + } + + const account = { + username, + password, + email + } as Account; + + signupQuery.mutate(account); + } + + if(signupQuery.status === "success"){ + addSuccessMessage("Signed up successfully"); + navigate("/login"); + } + else if(signupQuery.status === "error"){ + addErrorMessage("Failed to signup: " + signupQuery.error.message); + signupQuery.reset(); + } + + return ( -
- Signup Page -
+
+
+ setUsername(e.target.value)} + /> + setEmail(e.target.value)} + /> + setPassword(e.target.value)} + /> + setSecondPassword(e.target.value)} + /> + + Sign Up + +
+
); }