diff --git a/AceJobAgency.client/src/components/ChangePasswordView.tsx b/AceJobAgency.client/src/components/ChangePasswordView.tsx
new file mode 100644
index 0000000..efa79b4
--- /dev/null
+++ b/AceJobAgency.client/src/components/ChangePasswordView.tsx
@@ -0,0 +1,77 @@
+import { useState } from "react";
+import { Button, Divider, Input } from "@heroui/react";
+import { toast } from "react-toastify";
+import http from "../http";
+import { validatePassword } from "./SignupView";
+
+export default function ChangePasswordView({
+ onClose,
+}: {
+ onClose: () => void;
+}) {
+ const [oldPassword, setOldPassword] = useState("");
+ const [newPassword, setNewPassword] = useState("");
+ const [confirmNewPassword, setConfirmNewPassword] = useState("");
+
+ const handleChangePassword = async () => {
+ if (newPassword !== confirmNewPassword) {
+ toast.error("New password and confirm new password do not match.");
+ return;
+ }
+
+ if (!validatePassword(newPassword)) {
+ toast.error(
+ "Password must be at least 12 characters long and include uppercase, lowercase, number, and special character."
+ );
+ return;
+ }
+
+ const changePasswordRequest = {
+ currentPassword: oldPassword,
+ newPassword: newPassword,
+ };
+
+ try {
+ const response = await http.put(
+ "/User/change-password",
+ changePasswordRequest
+ );
+ toast.success(response.data);
+ onClose();
+ } catch (error) {
+ toast.error(
+ (error as any).response?.data ||
+ "Something went wrong! Please try again."
+ );
+ }
+ };
+
+ return (
+
+
Change password
+
+
+
+
+ );
+}
diff --git a/AceJobAgency.client/src/components/SignupView.tsx b/AceJobAgency.client/src/components/SignupView.tsx
index e1cadf5..296f8cd 100644
--- a/AceJobAgency.client/src/components/SignupView.tsx
+++ b/AceJobAgency.client/src/components/SignupView.tsx
@@ -4,6 +4,12 @@ import { useState } from "react";
import { toast } from "react-toastify";
import http, { login } from "../http";
+export const validatePassword = (password: string): boolean => {
+ const passwordComplexityRegex =
+ /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z\d])[A-Za-z\d@$!%*?&\\]{12,}$/;
+ return passwordComplexityRegex.test(password);
+};
+
export default function SignupView({
onLogin,
email = "",
@@ -21,12 +27,6 @@ export default function SignupView({
const [confirmPassword, setConfirmPassword] = useState("");
const [signupEnabled, setSignupEnabled] = useState(true);
- const validatePassword = (password: string): boolean => {
- const passwordComplexityRegex =
- /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z\d])[A-Za-z\d@$!%*?&\\]{12,}$/;
- return passwordComplexityRegex.test(password);
- };
-
const validateFields = () => {
if (
!firstName ||
diff --git a/AceJobAgency.client/src/pages/MemberPage.tsx b/AceJobAgency.client/src/pages/MemberPage.tsx
index 0eef687..21c97c2 100644
--- a/AceJobAgency.client/src/pages/MemberPage.tsx
+++ b/AceJobAgency.client/src/pages/MemberPage.tsx
@@ -2,15 +2,28 @@ import { useEffect, useState } from "react";
import http, { getAccessToken, logout } from "../http";
import { useNavigate } from "react-router-dom";
import { UserProfile } from "../models/user-profile";
-import { Button, Card, Divider, Input } from "@heroui/react";
+import {
+ Button,
+ Card,
+ Divider,
+ Input,
+ Modal,
+ ModalBody,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ useDisclosure,
+} from "@heroui/react";
import Markdown from "react-markdown";
import remarkGfm from "remark-gfm";
-import { IconDownload, IconUpload } from "@tabler/icons-react";
+import { IconDownload, IconEdit, IconUpload } from "@tabler/icons-react";
import { toast } from "react-toastify";
+import ChangePasswordView from "../components/ChangePasswordView";
export default function MemberPage() {
const accessToken = getAccessToken();
const navigate = useNavigate();
+ const { isOpen, onOpen, onOpenChange } = useDisclosure();
const [userProfile, setUserProfile] = useState(null);
@@ -137,7 +150,20 @@ export default function MemberPage() {
-
Who am I
+
+
Who am I
+
}
+ onPress={() => {
+ navigate("edit");
+ }}
+ >
+ Edit bio
+
+
{userProfile.whoAmI.length > 0 ? (
Log out
-
)}
+
+
+ {(onClose) => (
+ <>
+
+
+
+
+
+ >
+ )}
+
+
);
}