From 9c0b231e620d366f552a34e3b991f98184701cdc Mon Sep 17 00:00:00 2001 From: YasinShaikh123 <123150391+YasinShaikh123@users.noreply.github.com> Date: Mon, 9 Dec 2024 20:10:47 +0530 Subject: [PATCH] update changes --- src/Layout/DefaultLayout.jsx | 64 +++-- src/Pages/ChangePassword.jsx | 193 ++++++------- src/Pages/ForgetPassword.jsx | 304 +++++++++----------- src/Pages/Login.jsx | 2 + src/Pages/SubAdmin/SubAdminUpdateCreate.jsx | 35 +-- src/Routes/Nav.js | 36 ++- src/Services/change.password.service.js | 3 - src/Services/forget.password.service.js | 30 ++ src/Services/token.serivce.js | 2 +- src/Store/Store.js | 3 + 10 files changed, 329 insertions(+), 343 deletions(-) create mode 100644 src/Services/forget.password.service.js diff --git a/src/Layout/DefaultLayout.jsx b/src/Layout/DefaultLayout.jsx index 7afc70a..0ec59c7 100644 --- a/src/Layout/DefaultLayout.jsx +++ b/src/Layout/DefaultLayout.jsx @@ -15,7 +15,12 @@ import { TbTransactionDollar, } from "react-icons/tb"; import { TbArrowBadgeRightFilled } from "react-icons/tb"; -import { ArrowBackIcon, ArrowLeftIcon, ArrowRightIcon, AtSignIcon } from "@chakra-ui/icons"; +import { + ArrowBackIcon, + ArrowLeftIcon, + ArrowRightIcon, + AtSignIcon, +} from "@chakra-ui/icons"; import { Link, NavLink, @@ -83,6 +88,7 @@ import ApproveRequest from "../Pages/FawateerChecker/ApproveRequest/ApproveReque import ApproveHistoryMaker from "../Pages/FawateerChecker/ApproveHistory/ApproveHistoryMaker"; import ApproveHistory from "../Pages/FawateerChecker/ApproveHistory/ApproveHistoryChecker"; import { useProfileQuery } from "../Services/io.service"; +import SubAdmin from "../Pages/SubAdmin/SubAdmin"; const DashboardLayout = ({ isOnline }) => { const userRole = localStorage.getItem("role"); @@ -165,24 +171,24 @@ const DashboardLayout = ({ isOnline }) => { Sponsor ); - case path.startsWith("/email"): - return ( - - Email Notifiation - - ); + case path.startsWith("/email"): + return ( + + Email Notifiation + + ); case path.startsWith("/investment-type"): return ( Investment Type ); - case path.startsWith("/profile"): - return ( - - Profile - - ); + case path.startsWith("/profile"): + return ( + + Profile + + ); case path.startsWith("/exchange-rate"): return ( @@ -241,7 +247,7 @@ const DashboardLayout = ({ isOnline }) => { Deposite Request ); - + case path.startsWith("/fawateer"): return ( @@ -249,13 +255,13 @@ const DashboardLayout = ({ isOnline }) => { Fawateer Deposit ); - case path.startsWith("/fawateer-history"): - return ( - - - Fawateer Deposit - - ); + case path.startsWith("/fawateer-history"): + return ( + + + Fawateer Deposit + + ); case path.startsWith("/withdraw-request"): return ( @@ -398,6 +404,19 @@ const DashboardLayout = ({ isOnline }) => { return ; } + const filteredNav = nav.map((item) => { + if (item.submenu) { + return { + ...item, + submenu: item.submenu.filter( + (submenuItem) => + !(!data?.data?.superAdmin && submenuItem.title === "Sub Admin") + ), + }; + } + return item; + }); + return ( { index={openIndex} onChange={handleAccordionChange} > - {nav.map(({ title, type, Icon, submenu, path }, index) => { + {filteredNav.map(({ title, type, Icon, submenu, path }, index) => { if (type === "accordion") { return ( @@ -788,6 +807,7 @@ const AppContent = ({ data }) => { ) } /> + } /> ); diff --git a/src/Pages/ChangePassword.jsx b/src/Pages/ChangePassword.jsx index d33954b..fa6a898 100644 --- a/src/Pages/ChangePassword.jsx +++ b/src/Pages/ChangePassword.jsx @@ -17,24 +17,33 @@ import { useToast, } from "@chakra-ui/react"; import * as yup from "yup"; -import React, { useState, useEffect, useContext } from "react"; -import { useForm, Controller } from "react-hook-form"; +import React, { useState, useContext } from "react"; +import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; -import { v4 as uuidv4 } from "uuid"; -import { useParams } from "react-router-dom"; import CustomAlertDialog from "../Components/CustomAlertDialog"; import ToastBox from "../Components/ToastBox"; -import GlobalStateContext from "../Contexts/GlobalStateContext"; -import CurrencyInput from "../Components/CurrencyInput"; import { useUpdatePasswordMutation } from "../Services/change.password.service"; +import { all } from "axios"; -const ioNav = yup.object().shape({ - transactionDate: yup.string().required("Date is required"), - transactionAmount: yup.string().required("New NAV is required"), - comments: yup +// Validation schema +const passwordSchema = yup.object().shape({ + oldPassword: yup.string().required("Current Password is required"), + newPassword: yup .string() - .notRequired() - .max(200, "Approve Comment cannot be more than 200 characters"), + .required("New Password is required") + .min(8, "Password must be at least 8 characters long") + .max(16, "Password must be at most 50 characters long") + .matches(/[A-Z]/, "Password must contain at least one uppercase letter") + .matches(/[a-z]/, "Password must contain at least one lowercase letter") + .matches(/[0-9]/, "Password must contain at least one number") + .matches( + /[@$!%*?&#]/, + "Password must contain at least one special character" + ), + confirmNewPassword: yup + .string() + .required("Confirm Password is required") + .oneOf([yup.ref("newPassword")], "Passwords must match"), }); const ChangePassword = ({ @@ -43,175 +52,145 @@ const ChangePassword = ({ firstField, actionId, setActionId, - data, }) => { - const params = useParams(); - const id = params?.id; - const [file, setFile] = useState(""); - const [fileName, setFileName] = useState(""); const [isLoading, setIsLoading] = useState(false); const [alert, setAlert] = useState(false); - const toast = useToast(); const [showCurrentPassword, setShowCurrentPassword] = useState(false); const [showNewPassword, setShowNewPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false); - // ======================[ Cotext Api ] - const { IODetails } = useContext(GlobalStateContext); - const found = data?.find((item) => item?.id === actionId); + const toast = useToast(); - const [updatePassword] = useUpdatePasswordMutation() - // const { - // data - // } = useGetArtifactsQuery(id) + const [updatePassword] = useUpdatePasswordMutation(); + // Form handling const { - control, + register, handleSubmit, - watch, reset, formState: { errors }, } = useForm({ - resolver: yupResolver(ioNav), + resolver: yupResolver(passwordSchema), + mode: "all", }); - const onSubmit = async (data) => { - setIsLoading(true); - - try { - const res = await updatePassword({ data}); - if (res?.data?.statusCode === 201) { - setIsLoading(false); - toast({ - render: () => , - }); - handleClose(); - } else if (res?.error?.status === 400) { - toast({ - render: () => ( - - ), - }); - handleClose(); - } - } catch (error) { - console.log(error); + // Form submit handler + const onSubmit = async (data) => { + setIsLoading(true); + try { + const res = await updatePassword(data); // Assuming API request works as expected + if (res?.data?.statusCode === 200) { + toast({ + render: () => , + }); + handleClose(); + } else if (res?.error) { + toast({ + render: () => ( + + ), + }); } - }; - - const handleSave = () => { - handleSubmit(onSubmit)(); + } catch (error) { + console.error(error); + } finally { + setIsLoading(false); + } }; + // Handle modal close const handleClose = () => { - setIsLoading(false); setAlert(false); onClose(); + reset(); }; return ( <> - + - Change Password + Change Password - - + {/* Current Password */} + + Current Password setSubject(e.target.value)} + {...register("oldPassword")} + fontSize="sm" + type={showCurrentPassword ? "text" : "password"} focusBorderColor="forestGreen.300" - rounded={4} - type={showCurrentPassword ? "text" : "password"} // Toggles between "text" and "password" based on the `show` state /> - - {errors.ChangePassword?.message} + + {errors.oldPassword?.message} - - + {/* New Password */} + + New Password setSubject(e.target.value)} + {...register("newPassword")} + fontSize="sm" + type={showNewPassword ? "text" : "password"} focusBorderColor="forestGreen.300" - rounded={4} - type={showNewPassword ? "text" : "password"} // Toggles between "text" and "password" based on the `show` state /> - + {errors.newPassword?.message} - - - Re-Type New Password + {/* Confirm Password */} + + + Confirm New Password setSubject(e.target.value)} + {...register("confirmNewPassword")} + fontSize="sm" + type={showConfirmPassword ? "text" : "password"} focusBorderColor="forestGreen.300" - rounded={4} - type={showConfirmPassword ? "text" : "password"} // Toggles between "text" and "password" based on the `show` state /> - - {errors.conformPassword?.message} + + {errors.confirmNewPassword?.message} @@ -219,22 +198,20 @@ const ChangePassword = ({ - @@ -245,8 +222,8 @@ const ChangePassword = ({ setAlert(false)} - alertHandler={handleSave} - message={"Are you sure you want to change password?"} + alertHandler={handleSubmit(onSubmit)} + message={"Are you sure you want to change the password?"} isLoading={isLoading} /> diff --git a/src/Pages/ForgetPassword.jsx b/src/Pages/ForgetPassword.jsx index 8b78aba..23ed47b 100644 --- a/src/Pages/ForgetPassword.jsx +++ b/src/Pages/ForgetPassword.jsx @@ -1,178 +1,134 @@ import { - Button, - DrawerFooter, - FormControl, - FormErrorMessage, - FormLabel, - Input, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalHeader, - ModalOverlay, - Stack, - useToast, - } from "@chakra-ui/react"; - import * as yup from "yup"; - import React, { useState, useEffect, useContext } from "react"; - import { useForm, Controller } from "react-hook-form"; - import { yupResolver } from "@hookform/resolvers/yup"; - import { v4 as uuidv4 } from "uuid"; - import { useParams } from "react-router-dom"; - import CustomAlertDialog from "../Components/CustomAlertDialog"; - import ToastBox from "../Components/ToastBox"; - import GlobalStateContext from "../Contexts/GlobalStateContext"; - import CurrencyInput from "../Components/CurrencyInput"; - - const ioNav = yup.object().shape({ - transactionDate: yup.string().required("Date is required"), - transactionAmount: yup.string().required("New NAV is required"), - comments: yup - .string() - .notRequired() - .max(200, "Approve Comment cannot be more than 200 characters"), + Button, + DrawerFooter, + FormControl, + FormErrorMessage, + FormLabel, + Input, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalHeader, + ModalOverlay, + Stack, + useToast, +} from "@chakra-ui/react"; +import * as yup from "yup"; +import React, { useState} from "react"; +import { useForm, Controller } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { useForgetPasswordMutation } from "../Services/forget.password.service"; +import ToastBox from "../Components/ToastBox"; + +const validationSchema = yup.object().shape({ + emailAddress: yup + .string() + .email("Invalid email format") + .required("Email, Phone, or Username is required"), +}); + +const ForgetPassword = ({ isOpen, onClose, firstField }) => { + const toast = useToast(); + const [isLoading, setIsLoading] = useState(false); + + const [forgetPassword] = useForgetPasswordMutation(); + + const { + control, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: yupResolver(validationSchema), }); - - const ForgetPassword = ({ - isOpen, - onClose, - firstField, - actionId, - setActionId, - data, - }) => { - const params = useParams(); - const id = params?.id; - const [file, setFile] = useState(""); - const [fileName, setFileName] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [alert, setAlert] = useState(false); - const toast = useToast(); - - const [showPassword, setShowPassword] = useState(false); - const [subject, setSubject] = useState(""); - // ======================[ Cotext Api ] - const { IODetails } = useContext(GlobalStateContext); - const found = data?.find((item) => item?.id === actionId); - - // const [addNavDetails] = useAddNavDetailsMutation() - // const { - // data - // } = useGetArtifactsQuery(id) - - const { - control, - handleSubmit, - watch, - reset, - formState: { errors }, - } = useForm({ - resolver: yupResolver(ioNav), - }); - - // const onSubmit = async (data) => { - // setIsLoading(true); - - // try { - // const res = await addNavDetails({ data, id }); - // if (res?.data?.statusCode === 201) { - // setIsLoading(false); - // toast({ - // render: () => , - // }); - // handleClose(); - // } else if (res?.error?.status === 400) { - // toast({ - // render: () => ( - // - // ), - // }); - // handleClose(); - // } - // } catch (error) { - // console.log(error); - // } - // }; - - const handleSave = () => { - handleSubmit(onSubmit)(); - }; - - const handleClose = () => { - setIsLoading(false); - setAlert(false); - onClose(); - }; + + const onSubmit = async (formData) => { - - return ( - <> - - - - Forget Password - - - - - Email, Phone, or UserName - setSubject(e.target.value)} - focusBorderColor="forestGreen.300" - rounded={4} - // type={showPassword ? "text" : "password"} - type="text" - /> - - {errors.ChangePassword?.message} - - - - - - - {/* */} - - - - - - - setAlert(false)} - alertHandler={handleSave} - message={"Are you sure you want to change password?"} - isLoading={isLoading} - /> - - ); + setIsLoading(true); + try { + const res = await forgetPassword(formData); + if (res?.data?.statusCode === 200) { + toast({ + render: () => , + }); + handleClose(); + } else if (res?.error?.status === 401) { + toast({ + render: () => ( + + ), + }); + handleClose(); + } + } catch (error) { + console.error(error); + } finally { + setIsLoading(false); + } }; - - export default ForgetPassword; - \ No newline at end of file + + const handleClose = () => { + setIsLoading(false); + onClose(); + }; + + return ( + + + +
+ Forget Password + + + + + + Email, Phone, or Username + + ( + + )} + /> + + {errors.emailAddress?.message} + + + + + + + + + +
+
+ ); +}; + +export default ForgetPassword; diff --git a/src/Pages/Login.jsx b/src/Pages/Login.jsx index c871975..2eef3aa 100644 --- a/src/Pages/Login.jsx +++ b/src/Pages/Login.jsx @@ -256,6 +256,8 @@ const Login = () => { color={"whitesmoke"} colorScheme="green.500" size="lg" + fontWeight={500} + fontSize={"md"} > Log In diff --git a/src/Pages/SubAdmin/SubAdminUpdateCreate.jsx b/src/Pages/SubAdmin/SubAdminUpdateCreate.jsx index 948e78a..c483125 100644 --- a/src/Pages/SubAdmin/SubAdminUpdateCreate.jsx +++ b/src/Pages/SubAdmin/SubAdminUpdateCreate.jsx @@ -29,10 +29,8 @@ export const addSubAdmin = yup.object().shape({ .max(50, "First Name cannot exceed 50 characters") .matches(/^[^\d]+$/, "First Name cannot contain numbers"), - lastName: yup - .string() - .required("Last Name name in arabic is required"), - emailAddress: yup.string().email("Invalid email address").notRequired(), + lastName: yup.string().required("Last Name name in arabic is required"), + emailAddress: yup.string().email("Invalid email address").notRequired(), // .test("emailValidity", "Email address is invalid", async function (value) { // if (!value) { // return true; // Allow if the field is empty @@ -95,29 +93,30 @@ const SubAdminUpdateCreate = () => { lastName: subAdminByIdData?.data?.lastName, emailAddress: subAdminByIdData?.data?.emailAddress, }); - setIsSwitchOn(subAdminByIdData?.data?.role[0]?.role===encryptString(import.meta.env.VITE_VITE_MAKER)); + setIsSwitchOn( + subAdminByIdData?.data?.role[0]?.role === + encryptString(import.meta.env.VITE_VITE_MAKER) + ); console.log(subAdminByIdData?.data?.role); } }, [subAdminByIdData, reset]); - if (false) { return ; } // ============================ [API]=============================== - const handleConfirm = async () => { setIsLoadingBtn(true); const id = params?.id; console.log(isSwitchOn); - + if (id) { try { const formData = { ...form, - role_xid: isSwitchOn?2:1, + // role_xid: !isSwitchOn ? 1 : 2, }; await updateSubAdmin({ data: formData, id }).then((response) => { if (response?.data?.statusCode) { @@ -151,7 +150,7 @@ const SubAdminUpdateCreate = () => { try { const formData = { ...form, - role_xid: isSwitchOn?2:1, + role_xid: isSwitchOn ? 1 : 2, }; await createSubAdmin(formData).then((response) => { console.log(response); @@ -282,11 +281,11 @@ const SubAdminUpdateCreate = () => { }, {}); // ==================== [On Submit] ======================== -console.log(errors); + console.log(errors); const onSubmit = async (data) => { console.log("Hit"); - + if (Object.keys(errors).length === 0) { setForm(data); setAlert(true); @@ -314,10 +313,14 @@ console.log(errors); Add Details - + {params?.id ? ( + "" + ) : ( + + )}
{/* ====================== [Form Input] ====================== */} diff --git a/src/Routes/Nav.js b/src/Routes/Nav.js index 58996f4..76bf644 100644 --- a/src/Routes/Nav.js +++ b/src/Routes/Nav.js @@ -104,25 +104,23 @@ export const nav = [ title: "INVESTORS REQUEST", type: "title", }, -{ - title: "Fawateer Deposit", - submenu: [ - { - title: "Aprover Request", - path: "/fawateer", - icon: RiMoneyDollarBoxLine, - }, - { - title: "View History", - path: "/fawateer-history", - icon: RiExchangeBoxLine, - }, - ], - type: "accordion", - Icon: HiOutlineBanknotes, -} -, - + { + title: "Fawateer Deposit", + submenu: [ + { + title: "Aprover Request", + path: "/fawateer", + icon: RiMoneyDollarBoxLine, + }, + { + title: "View History", + path: "/fawateer-history", + icon: RiExchangeBoxLine, + }, + ], + type: "accordion", + Icon: HiOutlineBanknotes, + }, { title: "Bank Deposit", submenu: [ diff --git a/src/Services/change.password.service.js b/src/Services/change.password.service.js index 4c8adc3..1d82772 100644 --- a/src/Services/change.password.service.js +++ b/src/Services/change.password.service.js @@ -11,10 +11,7 @@ export const changePasswordMake = createApi({ baseQuery: baseQuery, tagTypes: ["getPassword"], endpoints: (builder) => ({ - - // // ========[ update ]======== - updatePassword: builder.mutation({ query: (data) => ({ url: `/auth/admin/update-password`, diff --git a/src/Services/forget.password.service.js b/src/Services/forget.password.service.js new file mode 100644 index 0000000..9af9f54 --- /dev/null +++ b/src/Services/forget.password.service.js @@ -0,0 +1,30 @@ + +// Need to use the React-specific entry point to import createApi +import { createApi} from "@reduxjs/toolkit/query/react"; +import { baseQuery } from "./token.serivce"; + + + +// Define a service using a base URL and expected endpoints +export const forgetPasswordMake = createApi({ + reducerPath: "forgetPassword", + baseQuery: baseQuery, + tagTypes: ["getPassword"], + endpoints: (builder) => ({ + // // ========[ update ]======== + forgetPassword: builder.mutation({ + query: (data) => ({ + url: `/auth/admin/forget-password`, + method: "POST", + body: data, + }), + invalidatesTags: ["getPassword"], + }), + + }), +}); + +// Export hooks for usage in functional components +export const { + useForgetPasswordMutation +} = forgetPasswordMake; diff --git a/src/Services/token.serivce.js b/src/Services/token.serivce.js index 1b2b827..9b0cc29 100644 --- a/src/Services/token.serivce.js +++ b/src/Services/token.serivce.js @@ -127,6 +127,6 @@ export const apiSlice = createApi({ }), -}); +}); export const { useLoginMutation, useRefreshTokenMutation, useLogoutMutation } = apiSlice; diff --git a/src/Store/Store.js b/src/Store/Store.js index 42f2add..8d1bc65 100644 --- a/src/Store/Store.js +++ b/src/Store/Store.js @@ -19,6 +19,7 @@ import { fawateerRequest } from "../Services/fawateer.request.service"; import { fawateerMaker } from "../Services/fawateer.maker.service"; import { sabAdminMaster } from "../Services/subadmin.service"; import { changePasswordMake } from "../Services/change.password.service"; +import { forgetPasswordMake } from "../Services/forget.password.service"; export const store = configureStore({ reducer: { @@ -39,6 +40,7 @@ export const store = configureStore({ [fawateerMaker.reducerPath]: fawateerMaker.reducer, [sabAdminMaster.reducerPath]: sabAdminMaster.reducer, [changePasswordMake.reducerPath]: changePasswordMake.reducer, + [forgetPasswordMake.reducerPath]: forgetPasswordMake.reducer, // Add other reducers as needed }, @@ -65,6 +67,7 @@ export const store = configureStore({ fawateerMaker.middleware, sabAdminMaster.middleware, changePasswordMake.middleware, + forgetPasswordMake.middleware, ), });