diff --git a/frontend/src/main-page/settings/ChangePasswordModal.tsx b/frontend/src/main-page/settings/ChangePasswordModal.tsx
new file mode 100644
index 0000000..2d2c9ef
--- /dev/null
+++ b/frontend/src/main-page/settings/ChangePasswordModal.tsx
@@ -0,0 +1,152 @@
+import { useState } from "react";
+import {
+ PasswordField,
+ PasswordRequirements,
+ isPasswordValid,
+} from "../../sign-up";
+
+
+export type ChangePasswordFormValues = {
+ currentPassword: string;
+ newPassword: string;
+};
+
+type ChangePasswordModalProps = {
+ isOpen: boolean;
+ onClose: () => void;
+
+ onSubmit?: (values: ChangePasswordFormValues) => void;
+ error?: string | null;
+};
+
+function CloseIcon({ className }: { className?: string }) {
+ return (
+
+ );
+}
+
+export default function ChangePasswordModal({
+ isOpen,
+ onClose,
+ onSubmit,
+ error = null,
+}: ChangePasswordModalProps) {
+ const [currentPassword, setCurrentPassword] = useState("");
+ const [newPassword, setNewPassword] = useState("");
+ const [reEnterPassword, setReEnterPassword] = useState("");
+
+ if (!isOpen) return null;
+
+ const newPasswordValid = isPasswordValid(newPassword);
+ const passwordsMatch = newPassword !== "" && newPassword === reEnterPassword;
+ const allFilled =
+ currentPassword.trim() !== "" &&
+ newPassword !== "" &&
+ reEnterPassword !== "";
+ const canSave =
+ allFilled && newPasswordValid && passwordsMatch;
+
+ const handleClose = () => {
+ setCurrentPassword("");
+ setNewPassword("");
+ setReEnterPassword("");
+ onClose();
+ };
+
+ const handleSave = () => {
+ if (!canSave) return;
+ onSubmit?.({
+ currentPassword: currentPassword.trim(),
+ newPassword,
+ });
+ handleClose();
+ };
+
+ return (
+
+
+
+
+ Change Password
+
+
+
+
+
+
setCurrentPassword(e.target.value)}
+ error={!!error}
+ />
+
+ setNewPassword(e.target.value)}
+ />
+
+ setReEnterPassword(e.target.value)}
+ />
+
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/main-page/settings/Settings.tsx b/frontend/src/main-page/settings/Settings.tsx
index 1c76c69..3b81592 100644
--- a/frontend/src/main-page/settings/Settings.tsx
+++ b/frontend/src/main-page/settings/Settings.tsx
@@ -1,31 +1,56 @@
+import { useState } from "react";
import Button from "../../components/Button";
import InfoCard from "./components/InfoCard";
import logo from "../../images/logo.svg";
import { faPenToSquare } from "@fortawesome/free-solid-svg-icons";
+import ChangePasswordModal from "./ChangePasswordModal";
+
+const initialPersonalInfo = {
+ firstName: "John",
+ lastName: "Doe",
+ email: "john.doe@gmail.com",
+};
export default function Settings() {
+ const [personalInfo, setPersonalInfo] = useState(initialPersonalInfo);
+ const [isEditingPersonalInfo, setIsEditingPersonalInfo] = useState(false);
+ const [editForm, setEditForm] = useState(initialPersonalInfo);
+ const [isChangePasswordModalOpen, setIsChangePasswordModalOpen] = useState(false);
+ const [changePasswordError, setChangePasswordError] = useState(null);
+
+ const handleStartEdit = () => {
+ setEditForm(personalInfo);
+ setIsEditingPersonalInfo(true);
+ };
+
+ const handleCancelEdit = () => {
+ setEditForm(personalInfo);
+ setIsEditingPersonalInfo(false);
+ };
+
+ const handleSaveEdit = () => {
+ setPersonalInfo(editForm);
+ setIsEditingPersonalInfo(false);
+ };
+
return (
Settings
- {/* Avatar */}

- {/* Buttons + helper text */}
Profile Picture
-
-
alert("edit personal info")}
- className="bg-white text-black border-2 border-grey-500"
- logo={faPenToSquare}
- logoPosition="right"
- />
- }
- fields={[
- { label: "First Name", value: "John" },
- { label: "Last Name", value: "Doe" },
- { label: "Email Address", value: "john.doe@gmail.com" },
- ]}
- />
+ {isEditingPersonalInfo ? (
+
+
Personal Information
+
+
+
+
+
+
+ ) : (
+
+ }
+ fields={[
+ { label: "First Name", value: personalInfo.firstName },
+ { label: "Last Name", value: personalInfo.lastName },
+ { label: "Email Address", value: personalInfo.email },
+ ]}
+ />
+ )}
@@ -70,10 +142,23 @@ export default function Settings() {
alert("change password")}
+ onClick={() => {
+ setChangePasswordError(null);
+ setIsChangePasswordModalOpen(true);
+ }}
className="bg-white text-black border-2 border-grey-500"
/>
+
+
setIsChangePasswordModalOpen(false)}
+ error={changePasswordError}
+ onSubmit={(values) => {
+ // Backend: call API with values.currentPassword and values.newPassword
+ void values;
+ }}
+ />
);
}
diff --git a/frontend/src/sign-up/PasswordField.tsx b/frontend/src/sign-up/PasswordField.tsx
index 671389a..081c57a 100644
--- a/frontend/src/sign-up/PasswordField.tsx
+++ b/frontend/src/sign-up/PasswordField.tsx
@@ -90,9 +90,9 @@ export default function PasswordField({
tabIndex={-1}
>
{visible ? (
-
- ) : (
+ ) : (
+
)}
diff --git a/frontend/src/sign-up/PasswordRequirements.tsx b/frontend/src/sign-up/PasswordRequirements.tsx
index 69c32d2..69fa543 100644
--- a/frontend/src/sign-up/PasswordRequirements.tsx
+++ b/frontend/src/sign-up/PasswordRequirements.tsx
@@ -21,6 +21,11 @@ export const PASSWORD_REQUIREMENTS: PasswordRequirement[] = [
{ id: "lower", label: "1 Lowercase", check: (p) => /[a-z]/.test(p) },
];
+/** Returns true if the password meets all requirements (same logic as sign-up). */
+export function isPasswordValid(password: string): boolean {
+ return PASSWORD_REQUIREMENTS.every((r) => r.check(password));
+}
+
type PasswordRequirementsProps = {
password: string;
};
diff --git a/frontend/src/sign-up/index.ts b/frontend/src/sign-up/index.ts
index 39dca3d..752f1a3 100644
--- a/frontend/src/sign-up/index.ts
+++ b/frontend/src/sign-up/index.ts
@@ -2,7 +2,7 @@ export { default as BrandingPanel } from "./BrandingPanel";
export { default as InputField } from "../components/InputField";
export { default as LoginPrompt } from "./LoginPrompt";
export { default as PasswordField } from "./PasswordField";
-export { default as PasswordRequirements } from "./PasswordRequirements";
+export { default as PasswordRequirements, isPasswordValid } from "./PasswordRequirements";
export { default as SignUpButton } from "./SignUpButton";
export { default as SignUpForm } from "./SignUpForm";
export type { SignUpFormProps, SignUpFormValues } from "./SignUpForm";