Yasin #23

Merged
Siddhesh.More merged 10 commits from Yasin into Sprint-9 2024-12-10 13:35:07 +00:00
25 changed files with 485 additions and 365 deletions

View File

@@ -1,16 +1,16 @@
import { Box, Spinner, Text } from "@chakra-ui/react";
import React from "react";
import './FullscreenLoaders.css'
import "./FullscreenLoaders.css";
const FullscreenLoaders = ({height}) => {
const FullscreenLoaders = ({ height }) => {
return (
<Box
display={"flex"}
justifyContent={"center"}
flexDirection={'column'}
flexDirection={"column"}
alignItems={"center"}
w={"100%"}
h={height ? height: "100vh"}
h={height ? height : "100vh"}
gap={4}
>
{/* <div className="dot-spinner">
@@ -23,8 +23,16 @@ const FullscreenLoaders = ({height}) => {
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
</div> */}
{/* <Text color='#004717' fontSize={'md'} fontWeight={500}>Loading...</Text> */}
<Spinner />
{/* <Text color='#004717' fontSize={'md'} fontWeight={500}>Loading...</Text> */}
{/* <div className="spinner-grow" style={{backgroundColor:"#004118"}} role="status" /> */}
<Spinner
thickness="4px"
speed="0.65s"
emptyColor="#fff"
color="#004118"
size="lg"
/>
</Box>
);
};

View File

@@ -4,6 +4,16 @@ import { Spinner } from "@chakra-ui/react";
const Loader01 = () => {
return (
// <div className="dot-spinner">
// <div className="dot-spinner__dot"></div>
// <div className="dot-spinner__dot"></div>
// <div className="dot-spinner__dot"></div>
// <div className="dot-spinner__dot"></div>
// <div className="dot-spinner__dot"></div>
// <div className="dot-spinner__dot"></div>
// <div className="dot-spinner__dot"></div>
// <div className="dot-spinner__dot"></div>
// </div>
// <div className="dot-spinner">
// <div className="dot-spinner__dot"></div>

View File

@@ -1,6 +1,7 @@
import dns from "node:dns"
import * as XLSX from 'xlsx';
import CryptoJS from "crypto-js";
export const generateSerialNumber = (index, currentPage, pageSize) => {
@@ -218,4 +219,18 @@ export function formatDateToYYYYMMDD(dateString) {
// Combine the formatted parts
return `${year}-${month}-${day}`;
}
}
// Encrypt a string
export const encryptString = (text) => {
const ciphertext = CryptoJS.AES.encrypt(text, import.meta.env.VITE_ROLE_ENCRYPTION_KEY).toString();
return ciphertext;
};
// Decrypt a string
export const decryptString = (ciphertext) => {
const bytes = CryptoJS.AES.decrypt(ciphertext, import.meta.env.VITE_ROLE_ENCRYPTION_KEY);
const originalText = bytes.toString(CryptoJS.enc.Utf8);
return originalText;
};

View File

@@ -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 }) => {
<RiMoneyDollarBoxLine className="h4 m-0" /> Sponsor
</span>
);
case path.startsWith("/email"):
return (
<span className="d-flex align-items-end gap-2">
<AtSignIcon className="h4 m-0" /> Email Notifiation
</span>
);
case path.startsWith("/email"):
return (
<span className="d-flex align-items-end gap-2">
<AtSignIcon className="h4 m-0" /> Email Notifiation
</span>
);
case path.startsWith("/investment-type"):
return (
<span className="d-flex align-items-end gap-2">
<VscSymbolClass className="h4 m-0" /> Investment Type
</span>
);
case path.startsWith("/profile"):
return (
<span className="d-flex align-items-end gap-2">
<CgProfile className="h4 m-0" /> Profile
</span>
);
case path.startsWith("/profile"):
return (
<span className="d-flex align-items-end gap-2">
<CgProfile className="h4 m-0" /> Profile
</span>
);
case path.startsWith("/exchange-rate"):
return (
<span className="d-flex align-items-end gap-2">
@@ -241,7 +247,7 @@ const DashboardLayout = ({ isOnline }) => {
Deposite Request
</span>
);
case path.startsWith("/fawateer"):
return (
<span className="d-flex align-items-end gap-2">
@@ -249,13 +255,13 @@ const DashboardLayout = ({ isOnline }) => {
Fawateer Deposit
</span>
);
case path.startsWith("/fawateer-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Fawateer Deposit
</span>
);
case path.startsWith("/fawateer-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Fawateer Deposit
</span>
);
case path.startsWith("/withdraw-request"):
return (
@@ -398,6 +404,19 @@ const DashboardLayout = ({ isOnline }) => {
return <SplashScreen />;
}
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 (
<Box
style={{
@@ -515,7 +534,7 @@ const DashboardLayout = ({ isOnline }) => {
index={openIndex}
onChange={handleAccordionChange}
>
{nav.map(({ title, type, Icon, submenu, path }, index) => {
{filteredNav.map(({ title, type, Icon, submenu, path }, index) => {
if (type === "accordion") {
return (
<AccordionItem key={index} border={"none"}>
@@ -788,6 +807,7 @@ const AppContent = ({ data }) => {
)
}
/>
<Route path="*" element={<NotFound />} />
</Routes>
);

View File

@@ -5,6 +5,8 @@ import {
FormErrorMessage,
FormLabel,
Input,
InputGroup,
InputRightElement,
Modal,
ModalBody,
ModalCloseButton,
@@ -15,23 +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 = ({
@@ -40,124 +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 [showCurrentPassword, setShowCurrentPassword] = useState(false);
const [showNewPassword, setShowNewPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const toast = useToast();
const [showPassword, setShowPassword] = useState(false);
const [subject, setSubject] = useState("");
const togglePasswordVisibility = () => setShowPassword(!showPassword);
// ======================[ Cotext Api ]
const { IODetails } = useContext(GlobalStateContext);
const found = data?.find((item) => item?.id === actionId);
// const [addNavDetails] = useAddNavDetailsMutation()
// 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 addNavDetails({ data, id });
// if (res?.data?.statusCode === 201) {
// setIsLoading(false);
// toast({
// render: () => <ToastBox message={res?.data?.message} />,
// });
// handleClose();
// } else if (res?.error?.status === 400) {
// toast({
// render: () => (
// <ToastBox message={res?.error?.data?.message} status={"error"} />
// ),
// });
// handleClose();
// }
// } catch (error) {
// console.log(error);
// }
// };
const handleSave = () => {
handleSubmit(onSubmit)();
// 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: () => <ToastBox message={res?.data?.message} />,
});
handleClose();
} else if (res?.error) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
});
}
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
};
// Handle modal close
const handleClose = () => {
setIsLoading(false);
setAlert(false);
onClose();
reset();
};
return (
<>
<Modal
// closeOnOverlayClick={false}
isOpen={isOpen}
onClose={onClose}
initialFocusRef={firstField}
>
<Modal isOpen={isOpen} onClose={onClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent>
<ModalHeader fontSize={"md"}>Change Password</ModalHeader>
<ModalHeader fontSize="md">Change Password</ModalHeader>
<ModalCloseButton />
<ModalBody pb={6}>
<Stack spacing={4}>
<FormControl isInvalid={errors.ChangePassword} isRequired>
<FormLabel fontSize={"sm"} mb={1} fontWeight={500}>Current Password</FormLabel>
<Input
size={"sm"}
onChange={(e) => setSubject(e.target.value)}
{/* Current Password */}
<FormControl isInvalid={errors.oldPassword}>
<FormLabel fontSize="sm" mb={1} fontWeight={500}>
Current Password
</FormLabel>
<InputGroup size="sm">
<Input
{...register("oldPassword")}
fontSize="sm"
type={showCurrentPassword ? "text" : "password"}
focusBorderColor="forestGreen.300"
rounded={4}
type={showPassword ? "text" : "password"}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.ChangePassword?.message}
/>
<InputRightElement width="4.5rem">
<Button
h="1.5rem"
size="xs"
onClick={() => setShowCurrentPassword((prev) => !prev)}
>
{showCurrentPassword ? "Hide" : "Show"}
</Button>
</InputRightElement>
</InputGroup>
<FormErrorMessage>
{errors.oldPassword?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.newPassword} isRequired>
<FormLabel fontSize={"sm"} mb={1}>New Password</FormLabel>
<Input
size={"sm"}
onChange={(e) => setSubject(e.target.value)}
{/* New Password */}
<FormControl isInvalid={errors.newPassword}>
<FormLabel fontSize="sm" mb={1}>
New Password
</FormLabel>
<InputGroup size="sm">
<Input
{...register("newPassword")}
fontSize="sm"
type={showNewPassword ? "text" : "password"}
focusBorderColor="forestGreen.300"
rounded={4}
type="text"
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
/>
<InputRightElement width="4.5rem">
<Button
h="1.5rem"
size="xs"
onClick={() => setShowNewPassword((prev) => !prev)}
>
{showNewPassword ? "Hide" : "Show"}
</Button>
</InputRightElement>
</InputGroup>
<FormErrorMessage>
{errors.newPassword?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.conformPassword} isRequired>
<FormLabel fontSize={"sm"} mb={1}>Re-Type New Password</FormLabel>
<Input
size={"sm"}
onChange={(e) => setSubject(e.target.value)}
{/* Confirm Password */}
<FormControl isInvalid={errors.confirmNewPassword}>
<FormLabel fontSize="sm" mb={1}>
Confirm New Password
</FormLabel>
<InputGroup size="sm">
<Input
{...register("confirmNewPassword")}
fontSize="sm"
type={showConfirmPassword ? "text" : "password"}
focusBorderColor="forestGreen.300"
rounded={4}
type="text"
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.conformPassword?.message}
/>
<InputRightElement width="4.5rem">
<Button
h="1.5rem"
size="xs"
onClick={() => setShowConfirmPassword((prev) => !prev)}
>
{showConfirmPassword ? "Hide" : "Show"}
</Button>
</InputRightElement>
</InputGroup>
<FormErrorMessage>
{errors.confirmNewPassword?.message}
</FormErrorMessage>
</FormControl>
</Stack>
@@ -165,22 +198,20 @@ const ChangePassword = ({
<DrawerFooter mb={5}>
<Button
// variant="outline"
bg={"#e0ebeb"}
rounded={"sm"}
size={"sm"}
mr={3}
onClick={handleClose}
bg="#e0ebeb"
size="sm"
mr={3}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
colorScheme="forestGreen"
size="sm"
onClick={() => setAlert(true)}
fontWeight={400}
isLoading={isLoading}
>
Save
</Button>
@@ -191,8 +222,8 @@ const ChangePassword = ({
<CustomAlertDialog
isOpen={alert}
onClose={() => 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}
/>
</>

View File

@@ -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: () => <ToastBox message={res?.data?.message} />,
// });
// handleClose();
// } else if (res?.error?.status === 400) {
// toast({
// render: () => (
// <ToastBox message={res?.error?.data?.message} status={"error"} />
// ),
// });
// handleClose();
// }
// } catch (error) {
// console.log(error);
// }
// };
const handleSave = () => {
handleSubmit(onSubmit)();
};
const handleClose = () => {
setIsLoading(false);
setAlert(false);
onClose();
};
const onSubmit = async (formData) => {
return (
<>
<Modal
// closeOnOverlayClick={false}
isOpen={isOpen}
onClose={onClose}
initialFocusRef={firstField}
>
<ModalOverlay />
<ModalContent>
<ModalHeader fontSize={"md"}>Forget Password</ModalHeader>
<ModalCloseButton />
<ModalBody pb={4}>
<Stack spacing={4}>
<FormControl isInvalid={errors.ChangePassword}>
<FormLabel fontSize={"sm"} mb={3} fontWeight={500}>Email, Phone, or UserName</FormLabel>
<Input
size={"md"}
onChange={(e) => setSubject(e.target.value)}
focusBorderColor="forestGreen.300"
rounded={4}
// type={showPassword ? "text" : "password"}
type="text"
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.ChangePassword?.message}
</FormErrorMessage>
</FormControl>
</Stack>
</ModalBody>
<DrawerFooter mb={5}>
{/* <Button
// variant="outline"
bg={"#e0ebeb"}
rounded={"sm"}
size={"sm"}
mr={3}
onClick={handleClose}
>
Cancel
</Button> */}
<Button
w={"100%"}
colorScheme={"forestGreen"}
rounded={"md"}
size={"md"}
onClick={() => setAlert(true)}
fontWeight={400}
>
Send Login Link
</Button>
</DrawerFooter>
</ModalContent>
</Modal>
<CustomAlertDialog
isOpen={alert}
onClose={() => 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: () => <ToastBox message={res?.data?.message} />,
});
handleClose();
} else if (res?.error?.status === 401) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status="error" />
),
});
handleClose();
}
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
};
export default ForgetPassword;
const handleClose = () => {
setIsLoading(false);
onClose();
};
return (
<Modal
isCentered
isOpen={isOpen}
onClose={handleClose}
initialFocusRef={firstField}
>
<ModalOverlay />
<ModalContent>
<form onSubmit={handleSubmit(onSubmit)}>
<ModalHeader fontSize="md">Forget Password</ModalHeader>
<ModalCloseButton />
<ModalBody pb={4}>
<Stack spacing={4}>
<FormControl isInvalid={errors.emailAddress}>
<FormLabel fontSize="sm" mb={3} fontWeight={500}>
Email, Phone, or Username
</FormLabel>
<Controller
name="emailAddress"
control={control}
render={({ field }) => (
<Input
{...field}
size="md"
fontSize="sm"
focusBorderColor="forestGreen.300"
rounded={4}
type="text"
/>
)}
/>
<FormErrorMessage fontSize="xs" fontWeight={500}>
{errors.emailAddress?.message}
</FormErrorMessage>
</FormControl>
</Stack>
</ModalBody>
<DrawerFooter mb={5}>
<Button
w="100%"
colorScheme="forestGreen"
rounded="md"
size="md"
type="submit"
isLoading={isLoading}
fontWeight={400}
fontSize="sm"
>
Send Login Link
</Button>
</DrawerFooter>
</form>
</ModalContent>
</Modal>
);
};
export default ForgetPassword;

View File

@@ -20,6 +20,7 @@ import AddCaseDetails from "./AddCaseDetails";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox";
import { useParams } from "react-router-dom";
import { encryptString } from "../../../../Constants/Constants";
const IOCashDetails = () => {
const params = useParams();
@@ -105,7 +106,7 @@ const IOCashDetails = () => {
</Tab>
</TabList>
{IODetails?.isInvestedAmount
? localStorage?.getItem("role") === "Maker" && (
? localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) && (
<Button
onClick={handleAdd}
leftIcon={<AddIcon />}

View File

@@ -38,6 +38,7 @@ import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal";
import AddCaseDetails from "./AddCaseDetails";
import { encryptString } from "../../../../Constants/Constants";
const formatDate = (date) => new Date(date).toLocaleDateString();
@@ -104,7 +105,7 @@ const Pending = () => {
"Comments",
"Update By",
"Update On",
...(localStorage?.getItem('role')!=="Maker" ? ["Actions"] : []),
...(localStorage?.getItem('role')!==encryptString(import.meta.env.VITE_VITE_MAKER) ? ["Actions"] : []),
];
@@ -166,7 +167,7 @@ const Pending = () => {
),
Actions: (
<Box display={"flex"} justifyContent={"center"}>
{localStorage?.getItem("role") !== "Maker" ? <Box>
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) ? <Box>
{index===0&&<Box display={"flex"} justifyContent={"center"} gap={2}>
<Tooltip
rounded={"sm"}

View File

@@ -75,6 +75,7 @@ import ToastBox from "../../../../Components/ToastBox";
import { useParams } from "react-router-dom";
import AddNavDetails from "./AddNavDetails";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import { encryptString } from "../../../../Constants/Constants";
const IONAVDetails = () => {
const params = useParams();
@@ -152,7 +153,7 @@ const IONAVDetails = () => {
</Tab>
</TabList>
{IODetails?.isInvestedAmount
? localStorage?.getItem("role") === "Maker" && (
? localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) && (
<Button
onClick={handleAdd}
leftIcon={<AddIcon />}

View File

@@ -22,6 +22,7 @@ import ToastBox from "../../../../Components/ToastBox";
import AddNavDetails from "./AddNavDetails";
import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal";
import { encryptString } from "../../../../Constants/Constants";
const formatDate = (date) => new Date(date).toLocaleDateString();
@@ -90,7 +91,7 @@ const Pending = () => {
"Investment Closed",
"Comments",
"Updated By",
...(localStorage?.getItem("role") !== "Maker" ? ["Status"] : []),
...(localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) ? ["Status"] : []),
];
const extractedArray = filteredData?.map((item, index) => ({

View File

@@ -27,6 +27,7 @@ import ViewAmountInvested from "./ViewAmountInvested";
import ViewDistributionInvestor from "./ViewDistributionInvestor";
import ViewExit from "./ViewExit";
import ViewCancel from "./ViewCancel";
import { encryptString } from "../../../../Constants/Constants";
const formatDate = (date) => new Date(date).toLocaleDateString();
@@ -195,7 +196,7 @@ const Pending = () => {
}
}}
>
{localStorage?.getItem("role") === "Maker" ? <ViewIcon me={"4px"} /> : null} {localStorage?.getItem("role") === "Maker" ? "View" : "Approve / Reject"}
{localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) ? <ViewIcon me={"4px"} /> : null} {localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) ? "View" : "Approve / Reject"}
</Button>
</Box>
),

View File

@@ -27,6 +27,7 @@ import CurrencyInput from "../../../../Components/CurrencyInput";
import RequestRejectModal from "./RequestRejectModal";
import ApproveInvestedModal from "./ApproveInvestedModal";
import { formatDate } from "../../../Master/Sponser/Sponsers";
import { encryptString } from "../../../../Constants/Constants";
// Validation schema
const validationSchema = yup.object().shape({
@@ -236,7 +237,7 @@ const ViewAmountInvested = ({ isOpen, onClose, id: investorId }) => {
/>
</FormControl>
{localStorage?.getItem("role") !== "Maker" && <ModalFooter>
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) && <ModalFooter>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
rounded={"sm"}

View File

@@ -35,6 +35,7 @@ import {
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import ApprovedCancelTransaction from "./ApprovedCancelTransaction";
import RequestRejectModal from "./RequestRejectModal";
import { encryptString } from "../../../../Constants/Constants";
const ViewCancel = ({ isOpen, onClose,id:cancleId }) => {
const params = useParams();
@@ -311,7 +312,7 @@ import RequestRejectModal from "./RequestRejectModal";
data={extractedArray}
/>
</ModalBody>
{localStorage?.getItem("role") !== "Maker" && <ModalFooter pt={0}>
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) && <ModalFooter pt={0}>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
rounded={"sm"}

View File

@@ -23,6 +23,7 @@ import { yupResolver } from "@hookform/resolvers/yup";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import ApproveDistrubationModal from "./ApproveDistrubationModal";
import RequestRejectModal from "./RequestRejectModal";
import { encryptString } from "../../../../Constants/Constants";
const ViewDistributionInvestor = ({ isOpen, onClose,id:exitId }) => {
const params = useParams();
@@ -218,7 +219,7 @@ const ViewDistributionInvestor = ({ isOpen, onClose,id:exitId }) => {
/>
</ModalBody>
{/* ...(localStorage?.getItem("role") !== "Maker" ? ["Status"] : []), */}
{localStorage?.getItem("role") !== "Maker" &&<ModalFooter pt={0}>
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) &&<ModalFooter pt={0}>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
rounded={"sm"}

View File

@@ -43,6 +43,7 @@ import {
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import ApprovedExit from "./ApprovedExit";
import RequestRejectModal from "./RequestRejectModal";
import { encryptString } from "../../../../Constants/Constants";
const ViewExit = ({ isOpen, onClose ,id:investerId}) => {
const params = useParams();
@@ -273,7 +274,7 @@ import RequestRejectModal from "./RequestRejectModal";
/>
{/* ) } */}
</ModalBody>
{localStorage?.getItem("role") !== "Maker" && <ModalFooter pt={0}>
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) && <ModalFooter pt={0}>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
rounded={"sm"}

View File

@@ -44,6 +44,7 @@ import { GrGallery } from "react-icons/gr";
import Loader01 from "../../../Components/Loaders/Loader01";
import { useUpdateTransactionMutation } from "../../../Services/io.service";
import ToastBox from "../../../Components/ToastBox";
import { encryptString } from "../../../Constants/Constants";
// import { formatCurrency } from "../../../Components/CurrencyInput";
// import { removeTrailingZeros } from "../../../Constants/Constants";
@@ -532,7 +533,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
alignItems={"start"}
height={"95px"}
>
{localStorage?.getItem("role") === "Maker" && <Menu>
{localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) && <Menu>
<MenuButton
className="link p-1 rounded-1 "
bg={"#fff"}

View File

@@ -256,6 +256,8 @@ const Login = () => {
color={"whitesmoke"}
colorScheme="green.500"
size="lg"
fontWeight={500}
fontSize={"md"}
>
Log In
</Button>

View File

@@ -93,10 +93,11 @@ const SubAdmin = () => {
const handleToggleStatus = async (isMaker, id) => {
console.log("hit");
const data = {
role_xid: isMaker ? 1 : 2,
role_xid: isMaker ? "2" : "1",
};
console.log("=======================",data)
try {
const res = await toggleStatus(id, data).unwrap();
const res = await toggleStatus({id, data});
if (res?.error) {
toast({
render: () => (
@@ -179,12 +180,13 @@ const SubAdmin = () => {
</Box>
),
Role: (
<Box minW={24} isTruncated={true}>
<Box isTruncated={true} >
<Badge
py={"2px"}
px={"5px"}
me={2}
fontWeight={600}
bg={item?.role[0]?.role === "Maker" ? "#00ffcc" : "#b3ff99"}
px={item?.role[0]?.role === "Maker" ? "12px" : "5px"}
>
{item?.role[0]?.role}
</Badge>

View File

@@ -18,6 +18,7 @@ import {
useUpdateSubAdminMutation,
} from "../../Services/subadmin.service";
import { useGetSponserByIdQuery } from "../../Services/io.service";
import { encryptString } from "../../Constants/Constants";
// ======================= [validation] =========================
export const addSubAdmin = yup.object().shape({
@@ -28,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
@@ -94,29 +93,30 @@ const SubAdminUpdateCreate = () => {
lastName: subAdminByIdData?.data?.lastName,
emailAddress: subAdminByIdData?.data?.emailAddress,
});
setIsSwitchOn(subAdminByIdData?.data?.role[0]?.role==="Maker");
setIsSwitchOn(
subAdminByIdData?.data?.role[0]?.role ===
encryptString(import.meta.env.VITE_VITE_MAKER)
);
console.log(subAdminByIdData?.data?.role);
}
}, [subAdminByIdData, reset]);
if (false) {
return <FullscreenLoaders />;
}
// ============================ [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) {
@@ -150,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);
@@ -206,8 +206,6 @@ const SubAdminUpdateCreate = () => {
type: "text",
isRequired: true,
section: "",
arabic: true,
right: true,
maxLength: 55,
helperText: `Maximum length should be 55 characters. You have entered ${
watch()?.lastName?.length || 0
@@ -245,7 +243,6 @@ const SubAdminUpdateCreate = () => {
type: "text",
isRequired: true,
section: "",
arabic: true,
maxLength: 55,
helperText: `Maximum length should be 55 characters. You have entered ${
watch()?.lastName?.length || 0
@@ -284,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);
@@ -316,10 +313,14 @@ console.log(errors);
<ArrowBackIcon fontSize={"xl"} me={2} />
Add Details
</Text>
<RoleSwitchButton
isSwitchOn={isSwitchOn}
setIsSwitchOn={setIsSwitchOn}
/>
{params?.id ? (
""
) : (
<RoleSwitchButton
isSwitchOn={isSwitchOn}
setIsSwitchOn={setIsSwitchOn}
/>
)}
</Box>
{/* ====================== [Form Input] ====================== */}

View File

@@ -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: [

View File

@@ -0,0 +1,30 @@
// Need to use the React-specific entry point to import createApi
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./token.serivce";
// Define a service using a base URL and expected endpoints
export const changePasswordMake = createApi({
reducerPath: "changePassword",
baseQuery: baseQuery,
tagTypes: ["getPassword"],
endpoints: (builder) => ({
// // ========[ update ]========
updatePassword: builder.mutation({
query: (data) => ({
url: `/auth/admin/update-password`,
method: "POST",
body: data,
}),
invalidatesTags: ["getPassword"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useUpdatePasswordMutation
} = changePasswordMake;

View File

@@ -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;

View File

@@ -50,7 +50,7 @@ export const sabAdminMaster = createApi({
// // ========[Toggle Status]========
toggleStatus: builder.mutation({
query: (id, data) => ({
query: ({id, data}) => ({
url: `/subadmin/admin/toggle-role/${id}`,
method: "PATCH",
body: data,

View File

@@ -1,4 +1,5 @@
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { encryptString } from '../Constants/Constants'
// Define a base query function with RTK Query
// export const baseQuery = fetchBaseQuery({
@@ -100,7 +101,7 @@ export const apiSlice = createApi({
localStorage.setItem("refreshToken", data?.data?.refresh?.token);
// localStorage.setItem('refreshTokenExp', data?.data?.refresh?.expires);
localStorage.setItem("accessTokenExp", data?.data?.access?.expires);
localStorage.setItem("role", data?.data?.role);
localStorage.setItem("role", encryptString(data?.data?.role));
} catch (error) {
console.error("Login failed:", error);
}
@@ -126,6 +127,6 @@ export const apiSlice = createApi({
}),
});
});
export const { useLoginMutation, useRefreshTokenMutation, useLogoutMutation } = apiSlice;

View File

@@ -18,6 +18,8 @@ import { banInvestorDetails } from "../Services/ban.investor.service";
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: {
@@ -37,6 +39,8 @@ export const store = configureStore({
[fawateerRequest.reducerPath]: fawateerRequest.reducer,
[fawateerMaker.reducerPath]: fawateerMaker.reducer,
[sabAdminMaster.reducerPath]: sabAdminMaster.reducer,
[changePasswordMake.reducerPath]: changePasswordMake.reducer,
[forgetPasswordMake.reducerPath]: forgetPasswordMake.reducer,
// Add other reducers as needed
},
@@ -62,6 +66,8 @@ export const store = configureStore({
fawateerRequest.middleware,
fawateerMaker.middleware,
sabAdminMaster.middleware,
changePasswordMake.middleware,
forgetPasswordMake.middleware,
),
});