diff --git a/src/App.tsx b/src/App.tsx
index 1ca9de4..e705983 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,5 +1,6 @@
import { createBrowserRouter, RouterProvider } from "react-router";
import NavBar from "./components/nav/NavBar";
+import AccountPage from "./pages/protected/AccountPage";
import AdminPage from "./pages/protected/AdminPage";
import GamePage from "./pages/protected/GamePage";
import GamesPage from "./pages/protected/GamesPage";
@@ -38,6 +39,10 @@ const routes = createBrowserRouter([
{
element: ,
children: [
+ {
+ path: "/account",
+ element:
+ },
{
path: "/logout",
element:
diff --git a/src/components/nav/ProtectedNavLinks.tsx b/src/components/nav/ProtectedNavLinks.tsx
index 78ff221..266f1bd 100644
--- a/src/components/nav/ProtectedNavLinks.tsx
+++ b/src/components/nav/ProtectedNavLinks.tsx
@@ -1,5 +1,6 @@
import { useAuth } from "@/providers/AuthProvider";
import { isSiteAdmin } from "@/util/PermissionUtil";
+import { BsFillPersonFill } from "react-icons/bs";
import { NavLink } from "react-router";
@@ -46,6 +47,16 @@ export default function ProtectedNavLinks(){
))
}
+ {
+ jwt &&
+
+
+
+ }
>
);
}
diff --git a/src/hooks/AccountHooks.ts b/src/hooks/AccountHooks.ts
index b0ab92a..860cd8a 100644
--- a/src/hooks/AccountHooks.ts
+++ b/src/hooks/AccountHooks.ts
@@ -3,6 +3,7 @@ import { AccountTutorialStatus } from "@/interface/AccountTutorialStatus";
import { RaidGroupPermissionType } from "@/interface/RaidGroup";
import { api } from "@/util/AxiosUtil";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import { AxiosError } from "axios";
export function useGetAccounts(page: number, pageSize: number, searchTerm?: string){
@@ -160,6 +161,28 @@ export function useUpdateTutorialsStatus(){
});
}
+export function useUpdatePassword(){
+ return useMutation({
+ mutationKey: ["updatePassword"],
+ mutationFn: async ({currentPassword, newPassword}:{currentPassword: string; newPassword: string;}) => {
+ try{
+ await api.post("/auth/resetPassword", {
+ currentPassword,
+ newPassword
+ });
+ }
+ catch(error){
+ if(error instanceof AxiosError && error.response?.data.errors){
+ throw new Error(error.response?.data.errors.join(", "));
+ }
+ else{
+ throw error;
+ }
+ }
+ }
+ });
+}
+
export function useForcePasswordReset(accountId: string){
diff --git a/src/pages/protected/AccountPage.tsx b/src/pages/protected/AccountPage.tsx
new file mode 100644
index 0000000..0090d18
--- /dev/null
+++ b/src/pages/protected/AccountPage.tsx
@@ -0,0 +1,29 @@
+import TabGroup, { Tab } from "@/components/tab/TabGroup";
+import PasswordResetDisplay from "@/ui/account/PasswordResetDisplay";
+
+
+export default function AccountPage(){
+ const tabs: Tab[] = [
+ {
+ tabId: "password",
+ tabHeader: "Password",
+ tabContent:
+ }
+ ];
+
+
+ return (
+
+
+ My Account
+
+
+
+ );
+}
diff --git a/src/pages/public/SignupPage.tsx b/src/pages/public/SignupPage.tsx
index 0dce6e9..decab24 100644
--- a/src/pages/public/SignupPage.tsx
+++ b/src/pages/public/SignupPage.tsx
@@ -22,7 +22,17 @@ export default function SignupPage(){
const signup = () => {
- if(password !== secondPassword){
+ if(username === ""){
+ addErrorMessage("Username cannot be empty");
+ return;
+ }
+ else if(email === ""){
+ addErrorMessage("Email cannot be empty");
+ }
+ else if(password === ""){
+ addErrorMessage("Password cannot be empty");
+ }
+ else if(password !== secondPassword){
addErrorMessage("Passwords do not match");
return;
}
diff --git a/src/ui/account/PasswordResetDisplay.tsx b/src/ui/account/PasswordResetDisplay.tsx
new file mode 100644
index 0000000..52f25de
--- /dev/null
+++ b/src/ui/account/PasswordResetDisplay.tsx
@@ -0,0 +1,90 @@
+import PrimaryButton from "@/components/button/PrimaryButton";
+import PasswordInput from "@/components/input/PasswordInput";
+import { useUpdatePassword } from "@/hooks/AccountHooks";
+import { useTimedModal } from "@/providers/TimedModalProvider";
+import { useEffect, useState } from "react";
+import { useNavigate } from "react-router";
+
+
+export default function PasswordResetDisplay(){
+ const [ currentPassword, setCurrentPassword ] = useState("");
+ const [ newPassword, setNewPassword ] = useState("");
+ const [ confirmPassword, setConfirmPassword ] = useState("");
+
+ const navigate = useNavigate();
+ const { addErrorMessage, addSuccessMessage } = useTimedModal();
+
+ const {mutate: updatePasswordMutate, status: updatePasswordStatus, error: updatePasswordError, reset: updatePasswordReset} = useUpdatePassword();
+
+
+ const updatePassword = () => {
+ if(newPassword !== confirmPassword){
+ addErrorMessage("Passwords do not match");
+ return;
+ }
+ else if(newPassword === ""){
+ addErrorMessage("Password cannot be empty");
+ return;
+ }
+ else{
+ updatePasswordMutate({
+ currentPassword,
+ newPassword
+ });
+ }
+ }
+
+
+ useEffect(() => {
+ if(updatePasswordStatus === "success"){
+ addSuccessMessage("Password updated successfully");
+ updatePasswordReset();
+ setCurrentPassword("");
+ setNewPassword("");
+ setConfirmPassword("");
+ }
+ else if(updatePasswordStatus === "error"){
+ addErrorMessage("Failed to update password: " + updatePasswordError.message);
+ updatePasswordReset();
+ }
+ }, [ updatePasswordMutate, updatePasswordStatus, updatePasswordError, updatePasswordReset, addSuccessMessage, addErrorMessage, navigate ]);
+
+
+ return (
+
+
+
setCurrentPassword(e.target.value)}
+ />
+
+
+
setNewPassword(e.target.value)}
+ />
+
+
+
setConfirmPassword(e.target.value)}
+ />
+
+
+
+ );
+}