= ({
+ id,
+ placeholder,
+ register,
+ error,
+}) => {
+ const [showPassword, setShowPassword] = useState(false);
+
+ return (
+
+
+
+ {error &&
{error.message}
}
+
+ );
+};
+
+export default PasswordInput;
diff --git a/src/components/password/UpdateModal.tsx b/src/components/password/UpdateModal.tsx
new file mode 100644
index 0000000..57f585c
--- /dev/null
+++ b/src/components/password/UpdateModal.tsx
@@ -0,0 +1,102 @@
+import React, { useState } from "react";
+import { useForm } from "react-hook-form";
+import { yupResolver } from "@hookform/resolvers/yup";
+import { toast, ToastContainer } from "react-toastify";
+import { AxiosError } from "axios";
+import { useDispatch } from "react-redux";
+
+import updatePasswordSchema from "../../schemas/updatepasswordSchema";
+import { updatePassword } from "../../redux/api/updatePasswordApiSlice";
+import PasswordInput from "../common/auth/Password";
+
+interface UpdatePasswordProps {
+ setPasswordModal: (isOpen: boolean) => void;
+}
+
+const UpdatePasswordmod: React.FC
= ({
+ setPasswordModal,
+}) => {
+ const dispatch = useDispatch();
+ const [loading, setLoading] = useState(false);
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ resolver: yupResolver(updatePasswordSchema),
+ });
+
+ const onSubmit = async (data: {
+ oldPassword: string;
+ newPassword: string;
+ confirmPassword: string;
+ }) => {
+ try {
+ setLoading(true);
+ // @ts-ignore
+ const response = await dispatch(updatePassword(data)).unwrap();
+ setLoading(false);
+ toast.success(response.message);
+ setTimeout(() => {
+ setPasswordModal(false);
+ }, 3000);
+ } catch (err) {
+ setLoading(false);
+ const error = err as AxiosError;
+ toast.error(error.message);
+ }
+ };
+
+ return (
+
+
+
+
+ Update Password
+
+
+
+
+ );
+};
+
+export default UpdatePasswordmod;
diff --git a/src/components/password/passwordUpdate.tsx b/src/components/password/passwordUpdate.tsx
new file mode 100644
index 0000000..cbd2c95
--- /dev/null
+++ b/src/components/password/passwordUpdate.tsx
@@ -0,0 +1,74 @@
+import { SubmitHandler, useForm } from "react-hook-form";
+import { yupResolver } from "@hookform/resolvers/yup";
+
+import updatePasswordSchema from "../../schemas/updatepasswordSchema";
+import Button from "../common/auth/Button";
+import InputField from "../common/auth/InputField";
+
+interface UpdatePasswordFormInputs {
+ oldPassword: string;
+ newPassword: string;
+ confirmPassword: string;
+}
+
+interface PasswordUpdateFormProps {
+ onSubmit: SubmitHandler;
+ onCancel: () => void;
+ loading: boolean;
+}
+
+const PasswordUpdateForm: React.FC = ({
+ onSubmit,
+ onCancel,
+ loading,
+}) => {
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ resolver: yupResolver(updatePasswordSchema),
+ });
+
+ return (
+
+ );
+};
+
+export default PasswordUpdateForm;
diff --git a/src/pages/passwordUpdatePage.tsx b/src/pages/passwordUpdatePage.tsx
new file mode 100644
index 0000000..a3ccb2a
--- /dev/null
+++ b/src/pages/passwordUpdatePage.tsx
@@ -0,0 +1,25 @@
+import { useState } from "react";
+
+import UpdatePasswordmod from "../components/password/UpdateModal";
+
+const UpdatePasswordPage = () => {
+ const [PasswordModal, setPasswordModal] = useState(false);
+ return (
+
+
+ {PasswordModal && (
+
+ )}
+
+ );
+};
+
+export default UpdatePasswordPage;
diff --git a/src/redux/api/updatePasswordApiSlice.ts b/src/redux/api/updatePasswordApiSlice.ts
new file mode 100644
index 0000000..bea1167
--- /dev/null
+++ b/src/redux/api/updatePasswordApiSlice.ts
@@ -0,0 +1,67 @@
+import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
+import axios, { AxiosError } from "axios";
+
+interface UpdatePasswordState {
+ loading: boolean;
+ error: string | null;
+}
+
+const initialState: UpdatePasswordState = {
+ loading: false,
+ error: null,
+};
+
+interface UpdatePasswordPayload {
+ oldPassword: string;
+ newPassword: string;
+ confirmPassword: string;
+}
+
+interface UpdatePasswordResponse {
+ message: string;
+}
+
+interface UpdatePasswordError {
+ message: string;
+}
+const token = localStorage.getItem("accessToken");
+export const updatePassword = createAsyncThunk<
+UpdatePasswordResponse,
+UpdatePasswordPayload,
+{ rejectValue: UpdatePasswordError }
+>("updatePassword", async (payload, { rejectWithValue }) => {
+ try {
+ const response = await axios.put("/users/passwordupdate", payload, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+ return response.data;
+ } catch (error) {
+ const axiosError = error as AxiosError;
+ return rejectWithValue(axiosError.response?.data as UpdatePasswordError);
+ }
+});
+
+const updatePasswordApiSlice = createSlice({
+ name: "updatePassword",
+ initialState,
+ reducers: {},
+ extraReducers: (builder) => {
+ builder
+ .addCase(updatePassword.pending, (state) => {
+ state.loading = true;
+ state.error = null;
+ })
+ .addCase(updatePassword.fulfilled, (state) => {
+ state.loading = false;
+ state.error = null;
+ })
+ .addCase(updatePassword.rejected, (state, { payload }) => {
+ state.loading = false;
+ state.error = payload?.message || null;
+ });
+ },
+});
+
+export default updatePasswordApiSlice.reducer;
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 8509031..5142584 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -2,11 +2,13 @@ import { configureStore } from "@reduxjs/toolkit";
import loginReducer from "./api/loginApiSlice";
import registerReducer from "./reducers/registerSlice";
+import updatePasswordApiSlice from "./api/updatePasswordApiSlice";
const store = configureStore({
reducer: {
login: loginReducer,
register: registerReducer,
+ password: updatePasswordApiSlice,
},
});
diff --git a/src/routes/AppRoutes.tsx b/src/routes/AppRoutes.tsx
index 41f21d1..4f81760 100644
--- a/src/routes/AppRoutes.tsx
+++ b/src/routes/AppRoutes.tsx
@@ -4,6 +4,7 @@ import RootLayout from "../components/layouts/RootLayout";
import Homepage from "../pages/Homepage";
import Login from "../pages/Login";
import RegisterUser from "../pages/RegisterUser";
+import UpdatePasswordPage from "../pages/passwordUpdatePage";
const AppRoutes = () => (
@@ -12,6 +13,7 @@ const AppRoutes = () => (
} />
} />
+ } />
);
diff --git a/src/schemas/updatepasswordSchema.ts b/src/schemas/updatepasswordSchema.ts
new file mode 100644
index 0000000..6bfd0b1
--- /dev/null
+++ b/src/schemas/updatepasswordSchema.ts
@@ -0,0 +1,24 @@
+import { object, string, ref } from "yup";
+
+const updatePasswordSchema = object({
+ oldPassword: string().required("Old password is required"),
+ newPassword: string()
+ .required("New password is required")
+ .min(8, "Password must be at least 8 characters long")
+ .matches(/[a-z]/, "Password must contain at least one lowercase letter")
+ .matches(/[A-Z]/, "Password must contain at least one uppercase letter")
+ .matches(/[0-9]/, "Password must contain at least one number")
+ .matches(
+ /[!@#$%^&*(),.?":{}|<>]/,
+ "Password must contain at least one special character",
+ )
+ .notOneOf(
+ [ref("oldPassword")],
+ "New password must be different from old password",
+ ),
+ confirmPassword: string()
+ .required("Confirm password is required")
+ .oneOf([ref("newPassword")], "Confirm password must match new password"),
+});
+
+export default updatePasswordSchema;
diff --git a/vercel.json b/vercel.json
new file mode 100644
index 0000000..6a92648
--- /dev/null
+++ b/vercel.json
@@ -0,0 +1,5 @@
+{
+ "rewrites": [
+ { "source": "/(.*)", "destination": "/" }
+ ]
+}