From 85e3c3412068773154605d1a4908b7ecf4679e2a Mon Sep 17 00:00:00 2001
From: YasinShaikh123 <123150391+YasinShaikh123@users.noreply.github.com>
Date: Tue, 19 Nov 2024 19:19:45 +0530
Subject: [PATCH] update transaction status modal
---
src/Pages/Fawateer/CreateRequest.jsx | 287 +++++++----
.../CreateIO/IOCashDetails/Approved.jsx | 26 +-
.../CreateIO/IOCashDetails/Pending.jsx | 2 +-
.../CreateIO/IOCashDetails/Rejected.jsx | 2 +-
.../CreateIO/IONAVDetails/Approved.jsx | 2 +-
.../CreateIO/IONAVDetails/Pending.jsx | 31 +-
.../CreateIO/IONAVDetails/Rejected.jsx | 2 +-
.../ApproveDistrubationModal.jsx | 178 +++++++
.../IOTransaction/ApproveInvestedModal.jsx | 176 +++++++
.../CreateIO/IOTransaction/Approved.jsx | 22 +-
.../ApprovedCancelTransaction.jsx | 160 ++++++
.../CreateIO/IOTransaction/ApprovedExit.jsx | 174 +++++++
.../CreateIO/IOTransaction/Pending.jsx | 476 +++++++++---------
.../CreateIO/IOTransaction/Rejected.jsx | 4 +-
.../IOTransaction/RequestRejectModal.jsx | 44 +-
.../IOTransaction/ViewAmountInvested.jsx | 304 +++++++++++
.../CreateIO/IOTransaction/ViewCancel.jsx | 363 +++++++++++++
.../ViewDistributionInvestor.jsx | 267 ++++++++++
.../CreateIO/IOTransaction/ViewExit.jsx | 324 ++++++++++++
.../IO_Management/CreateIO/Investors.jsx | 2 +-
.../ViewIO/HeaderModal/AmountInvested.jsx | 2 +-
src/Services/io.service.js | 45 +-
22 files changed, 2510 insertions(+), 383 deletions(-)
create mode 100644 src/Pages/IO_Management/CreateIO/IOTransaction/ApproveDistrubationModal.jsx
create mode 100644 src/Pages/IO_Management/CreateIO/IOTransaction/ApproveInvestedModal.jsx
create mode 100644 src/Pages/IO_Management/CreateIO/IOTransaction/ApprovedCancelTransaction.jsx
create mode 100644 src/Pages/IO_Management/CreateIO/IOTransaction/ApprovedExit.jsx
create mode 100644 src/Pages/IO_Management/CreateIO/IOTransaction/ViewAmountInvested.jsx
create mode 100644 src/Pages/IO_Management/CreateIO/IOTransaction/ViewCancel.jsx
create mode 100644 src/Pages/IO_Management/CreateIO/IOTransaction/ViewDistributionInvestor.jsx
create mode 100644 src/Pages/IO_Management/CreateIO/IOTransaction/ViewExit.jsx
diff --git a/src/Pages/Fawateer/CreateRequest.jsx b/src/Pages/Fawateer/CreateRequest.jsx
index 3bd9e39..0529ef9 100644
--- a/src/Pages/Fawateer/CreateRequest.jsx
+++ b/src/Pages/Fawateer/CreateRequest.jsx
@@ -1,17 +1,27 @@
import React, { useState } from "react";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
-import { Box, Button, HStack, Input, InputGroup, InputRightAddon, Textarea, useDisclosure, Image, Icon, VStack, Text, useToast } from "@chakra-ui/react";
import {
- FormControl,
- FormLabel,
- FormHelperText,
+ Box,
+ Button,
+ HStack,
+ Input,
+ InputGroup,
+ InputRightAddon,
+ Textarea,
+ useDisclosure,
+ Image,
+ Icon,
+ VStack,
+ Text,
+ useToast,
} from "@chakra-ui/react";
+import { FormControl, FormLabel, FormHelperText } from "@chakra-ui/react";
import { DeleteIcon, Search2Icon } from "@chakra-ui/icons";
import SelectInvestorModal from "./SelectInvestorModal";
import { Controller, useForm } from "react-hook-form"; // Import useForm
import { yupResolver } from "@hookform/resolvers/yup"; // Import resolver for Yup
import * as Yup from "yup"; // Import Yup for validation
-import { motion } from 'framer-motion'; // Import Framer Motion for animations
+import { motion } from "framer-motion"; // Import Framer Motion for animations
import { bytesToMB } from "../../Constants/Constants";
import { useCreateFawateerRequestMutation } from "../../Services/fawateer.maker.service";
import ToastBox from "../../Components/ToastBox";
@@ -23,60 +33,66 @@ const validationSchema = Yup.object().shape({
investorName: Yup.string().required("Investor name is required"),
clientId: Yup.string().required("Client ID is required"),
transaction_date: Yup.date()
- .required('Date is required')
- .transform((value, originalValue) => {
- return originalValue === "" ? null : value; // Convert empty strings to null
- })
- .typeError('Please enter a valid date').max(new Date(), "Date cannot be in the future"),
+ .required("Date is required")
+ .transform((value, originalValue) => {
+ return originalValue === "" ? null : value; // Convert empty strings to null
+ })
+ .typeError("Please enter a valid date")
+ .max(new Date(), "Date cannot be in the future"),
transaction_amount: Yup.number()
- .required("Transaction amount is required")
- .transform((value, originalValue) => originalValue === "" ? null : value) // Convert empty strings to null
- .typeError('Transaction amount must be a number') // Custom error message if it's not a number
- .positive('Transaction amount must be greater than zero'),
+ .required("Transaction amount is required")
+ .transform((value, originalValue) => (originalValue === "" ? null : value)) // Convert empty strings to null
+ .typeError("Transaction amount must be a number") // Custom error message if it's not a number
+ .positive("Transaction amount must be greater than zero"),
spportFile_path: Yup.mixed().required("Support file is required"),
makerComment: Yup.string(),
});
const CreateRequest = () => {
- const toast = useToast()
- const navigate=useNavigate()
+ const toast = useToast();
+ const navigate = useNavigate();
const { isOpen, onOpen, onClose } = useDisclosure();
const [selectedInvestor, setSelectorInvestor] = useState({});
const [filePreview, setFilePreview] = useState(null); // State for previewing the file
const [fileType, setFileType] = useState(null); // State to store file type for conditional rendering
- const[ isLoading, setIsLoading ] = useState(false)
- const [id, setId ] = useState(null)
+ const [isLoading, setIsLoading] = useState(false);
+ const [id, setId] = useState(null);
// Initialize useForm with the resolver for Yup validation
- const {control, register, handleSubmit, setValue,reset, formState: { errors } } = useForm({
+ const {
+ control,
+ register,
+ handleSubmit,
+ setValue,
+ reset,
+ formState: { errors },
+ } = useForm({
resolver: yupResolver(validationSchema),
});
-
- const [ creatFawaateerRequest ] = useCreateFawateerRequestMutation()
-
+ const [creatFawaateerRequest] = useCreateFawateerRequestMutation();
const onSubmit = async (data) => {
console.log(data);
- setIsLoading(true)
-
+ setIsLoading(true);
+
// Convert data to FormData
const formData = new FormData();
-
- // Append each field from the data object to the FormData
- Object.keys(data).forEach((key) => {
- if (key === "spportFile_path" && data[key] instanceof FileList) {
- // Append the first file from FileList (assuming single file input)
- formData.append(key, data[key][0]); // Append the file
- } else {
- formData.append(key, data[key]); // Append other fields
- }
- });
-
+
+ // Append each field from the data object to the FormData
+ Object.keys(data).forEach((key) => {
+ if (key === "spportFile_path" && data[key] instanceof FileList) {
+ // Append the first file from FileList (assuming single file input)
+ formData.append(key, data[key][0]); // Append the file
+ } else {
+ formData.append(key, data[key]); // Append other fields
+ }
+ });
+
try {
// Make the API call with formData
const res = await creatFawaateerRequest({ data: formData, id });
-
+
if (res?.error) {
toast({
render: () => (
@@ -84,39 +100,35 @@ const CreateRequest = () => {
),
});
setIsLoading(false);
- reset()
- return
+ reset();
+ return;
} else if (res?.data) {
toast({
- render: () => (
-
- ),
+ render: () => ,
});
setIsLoading(false);
- navigate('/fawateer-history')
- return
+ navigate("/fawateer-history");
+ return;
} else {
toast({
render: () => (
-
+
),
});
setIsLoading(false);
- return
+ return;
}
-
} catch (error) {
console.error("Error:", error);
toast({
render: () => (
-
+
),
});
setIsLoading(false);
- return
+ return;
}
};
-
// Handle file change and preview
const handleFileChange = (e) => {
@@ -137,15 +149,12 @@ const CreateRequest = () => {
}
};
-
-
-
return (
{
onSubmit={handleSubmit(onSubmit)}
>
{/* Investor Name Field */}
-
+
Investor name
-
+
{
{...register("investorName")}
_placeholder={{ fontSize: "sm" }}
/>
-
+
Search
- {errors.investorName?.message}
+
+ {errors.investorName?.message}
+
{/* Client ID Field */}
@@ -193,7 +220,13 @@ const CreateRequest = () => {
placeholder={"Client ID"}
{...register("clientId")}
/>
- {errors.clientId?.message}
+
+ {errors.clientId?.message}
+
{/* Date Field */}
@@ -208,10 +241,21 @@ const CreateRequest = () => {
fontSize={"sm"}
rounded={"sm"}
type={"date"}
- max={new Date().toISOString().split("T")[0]} // Disable future dates
- {...register("transaction_date")}
+ max={new Date().toLocaleDateString("en-CA")} // Ensures max is in local timezone
+ {...register("transaction_date", {
+ setValueAs: (value) => {
+ // Convert date string to local timezone Date object
+ return value ? new Date(value) : undefined;
+ },
+ })}
/>
- {errors.transaction_date?.message}
+
+ {errors.transaction_date?.message}
+
{/* Amount Field */}
@@ -220,19 +264,35 @@ const CreateRequest = () => {
Amount (BHD)
(
-
- )}
- />
-
+ name="transaction_amount"
+ control={control}
+ render={({ field }) => (
+
+ )}
+ />
+
{errors.transaction_amount?.message}
-
+
{/* Support File Field with Preview */}
-
+
Support file
@@ -249,7 +309,13 @@ const CreateRequest = () => {
{...register("spportFile_path")}
// onChange={handleFileChange}
/>
- {errors.spportFile_path?.message}
+
+ {errors.spportFile_path?.message}
+
{/* Animated Preview */}
{filePreview && fileType?.type.startsWith("image/") && (
@@ -259,14 +325,55 @@ const CreateRequest = () => {
transition={{ duration: 0.5 }}
style={{ marginTop: "10px" }}
>
-
-
- setFilePreview(null)} className="link" rounded={'md'} color={'red.700'} cursor={'pointer'} p={1.5} position={'absolute'} top={0} right={0} as={DeleteIcon} boxSize={7} />
-
- File Name: {fileType?.name}
- File Size: {bytesToMB(fileType?.size)} Mb
- File Type: {fileType?.type}
-
+
+
+ setFilePreview(null)}
+ className="link"
+ rounded={"md"}
+ color={"red.700"}
+ cursor={"pointer"}
+ p={1.5}
+ position={"absolute"}
+ top={0}
+ right={0}
+ as={DeleteIcon}
+ boxSize={7}
+ />
+
+
+ File Name:{" "}
+
+ {" "}
+ {fileType?.name}
+
+
+
+ File Size:{" "}
+
+ {" "}
+ {bytesToMB(fileType?.size)} Mb
+
+
+
+ File Type:{" "}
+
+ {" "}
+ {fileType?.type}
+
+
@@ -274,7 +381,7 @@ const CreateRequest = () => {
{/* Description Field */}
-
+
Description
@@ -287,12 +394,18 @@ const CreateRequest = () => {
placeholder={"Description"}
{...register("makerComment")}
/>
- {errors.makerComment?.message}
+
+ {errors.makerComment?.message}
+
{/* Submit Button */}
-
-
-
+
);
};
diff --git a/src/Pages/IO_Management/CreateIO/IOCashDetails/Approved.jsx b/src/Pages/IO_Management/CreateIO/IOCashDetails/Approved.jsx
index 8e474a7..b0f2014 100644
--- a/src/Pages/IO_Management/CreateIO/IOCashDetails/Approved.jsx
+++ b/src/Pages/IO_Management/CreateIO/IOCashDetails/Approved.jsx
@@ -86,7 +86,7 @@ const Approved = () => {
"Transaction Type",
"Amount",
"Comments",
- // "Update by",
+ "Update by",
"Update On",
];
@@ -184,7 +184,7 @@ const Approved = () => {
{
| {
wordBreak="normal"
overflowWrap="normal"
>
- {"48,000.00"}
+ {" "}
|
+
+ $
+
+ {IODetails?.ioCash}
+ |
+ {
Add
*/}
{IODetails?.isInvestedAmount ? (
- localStorage?.getItem('role') ==="Maker"&& }
colorScheme="forestGreen"
diff --git a/src/Pages/IO_Management/CreateIO/IOCashDetails/Pending.jsx b/src/Pages/IO_Management/CreateIO/IOCashDetails/Pending.jsx
index fd89eea..30047b3 100644
--- a/src/Pages/IO_Management/CreateIO/IOCashDetails/Pending.jsx
+++ b/src/Pages/IO_Management/CreateIO/IOCashDetails/Pending.jsx
@@ -102,7 +102,7 @@ const Pending = () => {
"Transaction Type",
"Amount",
"Comments",
- // "Update by",
+ "Update by",
"Update On",
...(localStorage?.getItem('role')!=="Maker" ? ["Status"] : []),
];
diff --git a/src/Pages/IO_Management/CreateIO/IOCashDetails/Rejected.jsx b/src/Pages/IO_Management/CreateIO/IOCashDetails/Rejected.jsx
index 88c7ec1..7f18cc6 100644
--- a/src/Pages/IO_Management/CreateIO/IOCashDetails/Rejected.jsx
+++ b/src/Pages/IO_Management/CreateIO/IOCashDetails/Rejected.jsx
@@ -81,7 +81,7 @@ import AddCaseDetails from "./AddCaseDetails";
"Transaction Type",
"Amount",
"Comments",
- // "Update by",
+ "Update by",
"Update On",
];
diff --git a/src/Pages/IO_Management/CreateIO/IONAVDetails/Approved.jsx b/src/Pages/IO_Management/CreateIO/IONAVDetails/Approved.jsx
index b3b1a2e..354da90 100644
--- a/src/Pages/IO_Management/CreateIO/IONAVDetails/Approved.jsx
+++ b/src/Pages/IO_Management/CreateIO/IONAVDetails/Approved.jsx
@@ -84,7 +84,7 @@ import AddNavDetails from "./AddNavDetails";
"Last Nav Update",
"Investment Closed",
"Comments",
- // "Updated By",
+ "Updated By",
];
const extractedArray = filteredData?.map((item, index) => ({
diff --git a/src/Pages/IO_Management/CreateIO/IONAVDetails/Pending.jsx b/src/Pages/IO_Management/CreateIO/IONAVDetails/Pending.jsx
index c4bfe4d..39a0218 100644
--- a/src/Pages/IO_Management/CreateIO/IONAVDetails/Pending.jsx
+++ b/src/Pages/IO_Management/CreateIO/IONAVDetails/Pending.jsx
@@ -53,7 +53,6 @@ const Pending = () => {
onClose: onRejectClose,
} = useDisclosure();
-
useEffect(() => {
// Simulate loading
const timer = setTimeout(() => {
@@ -90,8 +89,8 @@ const Pending = () => {
"Last Nav Update",
"Investment Closed",
"Comments",
- // "Updated By",
- ...(localStorage?.getItem('role')!=="Maker" ? ["Status"] : []),
+ "Updated By",
+ ...(localStorage?.getItem("role") !== "Maker" ? ["Status"] : []),
];
const extractedArray = filteredData?.map((item, index) => ({
@@ -273,18 +272,20 @@ const Pending = () => {
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
- {IODetails?.isInvestedAmount ? (
- localStorage?.getItem('role') ==="Maker"&& }
- colorScheme="forestGreen"
- size={"sm"}
- rounded={"sm"}
- fontSize={"xs"}
- >
- Add
-
- ) : null}
+ {IODetails?.isInvestedAmount
+ ? localStorage?.getItem("role") === "Maker" && (
+ }
+ colorScheme="forestGreen"
+ size={"sm"}
+ rounded={"sm"}
+ fontSize={"xs"}
+ >
+ Add
+
+ )
+ : null}
diff --git a/src/Pages/IO_Management/CreateIO/IONAVDetails/Rejected.jsx b/src/Pages/IO_Management/CreateIO/IONAVDetails/Rejected.jsx
index 351e5dc..8b69230 100644
--- a/src/Pages/IO_Management/CreateIO/IONAVDetails/Rejected.jsx
+++ b/src/Pages/IO_Management/CreateIO/IONAVDetails/Rejected.jsx
@@ -82,7 +82,7 @@ import AddNavDetails from "./AddNavDetails";
"Last Nav Update",
"Investment Closed",
"Comments",
- // "Updated By",
+ "Updated By",
];
const extractedArray = filteredData?.map((item, index) => ({
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/ApproveDistrubationModal.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/ApproveDistrubationModal.jsx
new file mode 100644
index 0000000..c54738d
--- /dev/null
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/ApproveDistrubationModal.jsx
@@ -0,0 +1,178 @@
+import {
+ Box,
+ Button,
+ FormControl,
+ FormHelperText,
+ FormLabel,
+ Input,
+ Modal,
+ ModalBody,
+ ModalCloseButton,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ ModalOverlay,
+ Text,
+ Textarea,
+ useDisclosure,
+ useToast,
+ } from "@chakra-ui/react";
+ import React, { useEffect, useState } from "react";
+ import * as yup from "yup";
+ import { yupResolver } from "@hookform/resolvers/yup";
+ import { useForm } from "react-hook-form";
+ import ToastBox from "../../../../Components/ToastBox";
+ import { useApproveDistributedMutation } from "../../../../Services/io.service";
+
+ export const conformModalSchema = yup.object().shape({
+ // checkerComment: yup.string().required("Comment is required")
+ // .max(50, "Investment name cannot be more than 50 characters"),
+ checkerComment: yup
+ .string()
+ .required("Comment is required")
+ .max(200, "Approve Comment cannot be more than 200 characters"),
+ });
+
+ const ApproveDistrubationModal = ({ isOpen, onClose, firstField ,id}) => {
+ const [isBtnLoading , setIsBtnLoading] = useState(false)
+
+ const toast = useToast()
+
+
+
+ const {
+ register,
+ reset,
+ watch,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ resolver: yupResolver(conformModalSchema),
+ });
+
+ const [ approveDistributed ] = useApproveDistributedMutation()
+
+
+ const onSubmit = async(data) => {
+ setIsBtnLoading(true)
+ try {
+ const res = await approveDistributed({data,id})
+ if (res?.error) {
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsBtnLoading(false)
+ }else if(res?.data){
+ toast({
+ render: () => (
+
+ ),
+ });
+ onClose()
+ setIsBtnLoading(false)
+ }else{
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsBtnLoading(false)
+ }
+ } catch (error) {
+
+ }
+ };
+
+ const handleFileChange = (event) => {
+ const selectedFile = event.target.files[0];
+ setFile(selectedFile);
+ };
+
+
+ const { data, isLoading } =
+ (id, {
+ skip: !id,
+ });
+
+ useEffect(() => {
+ if (data) {
+ reset({
+ investorAmount: data?.data?.investorAmount,
+ });
+ }
+ }, [data, reset]);
+
+ const heandleOnClose = () =>{
+ reset()
+ onClose()
+ }
+
+ return (
+
+
+
+ Approve Comment
+
+ {isLoading ? (
+
+ ) : (
+
+
+
+ Comment
+
+ {errors.checkerComment && (
+
+ {errors.checkerComment.message}
+
+ )}
+
+ Maximum length should be 200 characters. You have entered
+ {watch("checkerComment")?.length || 0} characters.
+
+
+
+
+
+ Cancel
+
+
+ Send
+
+
+
+ )}
+
+
+ );
+ };
+
+ export default ApproveDistrubationModal;
+
\ No newline at end of file
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/ApproveInvestedModal.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/ApproveInvestedModal.jsx
new file mode 100644
index 0000000..a165034
--- /dev/null
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/ApproveInvestedModal.jsx
@@ -0,0 +1,176 @@
+import {
+ Box,
+ Button,
+ FormControl,
+ FormHelperText,
+ FormLabel,
+ Input,
+ Modal,
+ ModalBody,
+ ModalCloseButton,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ ModalOverlay,
+ Text,
+ Textarea,
+ useDisclosure,
+ useToast,
+ } from "@chakra-ui/react";
+ import React, { useEffect, useState } from "react";
+ import * as yup from "yup";
+ import { yupResolver } from "@hookform/resolvers/yup";
+ import { useForm } from "react-hook-form";
+ import ToastBox from "../../../../Components/ToastBox";
+ import { useApproveInvestedMutation } from "../../../../Services/io.service";
+
+ export const conformModalSchema = yup.object().shape({
+ // checkerComment: yup.string().required("Comment is required")
+ // .max(50, "Investment name cannot be more than 50 characters"),
+ checkerComment: yup
+ .string()
+ .required("Comment is required")
+ .max(200, "Approve Comment cannot be more than 200 characters"),
+ });
+
+ const ApproveInvestedModal = ({ isOpen, onClose, firstField ,id}) => {
+ const [isBtnLoading , setIsBtnLoading] = useState(false)
+
+ const toast = useToast()
+
+ const {
+ register,
+ reset,
+ watch,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ resolver: yupResolver(conformModalSchema),
+ });
+
+ const [ approveInvested ] = useApproveInvestedMutation()
+
+
+ const onSubmit = async(data) => {
+ setIsBtnLoading(true)
+ try {
+ const res = await approveInvested({data,id})
+ if (res?.error) {
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsBtnLoading(false)
+ }else if(res?.data){
+ toast({
+ render: () => (
+
+ ),
+ });
+ onClose()
+ setIsBtnLoading(false)
+ }else{
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsBtnLoading(false)
+ }
+ } catch (error) {
+
+ }
+ };
+
+ const handleFileChange = (event) => {
+ const selectedFile = event.target.files[0];
+ setFile(selectedFile);
+ };
+
+
+ const { data, isLoading } =
+ (id, {
+ skip: !id,
+ });
+
+ useEffect(() => {
+ if (data) {
+ reset({
+ investorAmount: data?.data?.investorAmount,
+ });
+ }
+ }, [data, reset]);
+
+ const heandleOnClose = () =>{
+ reset()
+ onClose()
+ }
+
+ return (
+
+
+
+ Approve Comment
+
+ {isLoading ? (
+
+ ) : (
+
+
+
+ Comment
+
+ {errors.checkerComment && (
+
+ {errors.checkerComment.message}
+
+ )}
+
+ Maximum length should be 200 characters. You have entered
+ {watch("checkerComment")?.length || 0} characters.
+
+
+
+
+
+ Cancel
+
+
+ Send
+
+
+
+ )}
+
+
+ );
+ };
+
+ export default ApproveInvestedModal;
+
\ No newline at end of file
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/Approved.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/Approved.jsx
index b27c5ef..86b65d6 100644
--- a/src/Pages/IO_Management/CreateIO/IOTransaction/Approved.jsx
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/Approved.jsx
@@ -75,7 +75,7 @@ import {
"Amount",
"Created By",
"Created On",
- // "Approved By",
+ "Approved By",
"Approved On",
];
@@ -132,14 +132,32 @@ import {
),
"Approved By": (
+ <>
- {item?.modifier ? item?.modifier : "---" }
+ {item?.modifier ? formatDate(item?.updatedAt) : "---" }
+ {/*
+
+ {item?.creator?.firstName}
+ */}
+ >
),
"Approved On": (
{
+ const [isBtnLoading , setIsBtnLoading] = useState(false)
+
+ const toast = useToast()
+
+ const {
+ register,
+ reset,
+ watch,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ resolver: yupResolver(),
+ });
+
+ const [ approveCancleTransaction ] = useApproveCancleTransactionMutation()
+
+
+ const onSubmit = async(data) => {
+ setIsBtnLoading(true)
+ try {
+ const res = await approveCancleTransaction({data,id})
+ if (res?.error) {
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsBtnLoading(false)
+ }else if(res?.data){
+ toast({
+ render: () => (
+
+ ),
+ });
+ onClose()
+ setIsBtnLoading(false)
+ }else{
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsBtnLoading(false)
+ }
+ } catch (error) {
+
+ }
+ };
+
+
+ const { data, isLoading } =
+ (id, {
+ skip: !id,
+ });
+
+ useEffect(() => {
+ if (data) {
+ reset({
+ investorAmount: data?.data?.investorAmount,
+ });
+ }
+ }, [data, reset]);
+
+ const heandleOnClose = () =>{
+ reset()
+ onClose()
+ }
+
+ return (
+
+
+
+ Approve Comment
+
+ {isLoading ? (
+
+ ) : (
+
+
+
+ Comment
+
+ {errors.checkerComment && (
+
+ {errors.checkerComment.message}
+
+ )}
+
+ Maximum length should be 200 characters. You have entered
+ {watch("checkerComment")?.length || 0} characters.
+
+
+
+
+
+ Cancel
+
+
+ Send
+
+
+
+ )}
+
+
+ );
+ };
+
+ export default ApprovedCancelTransaction;
+
\ No newline at end of file
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/ApprovedExit.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/ApprovedExit.jsx
new file mode 100644
index 0000000..0c9a50d
--- /dev/null
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/ApprovedExit.jsx
@@ -0,0 +1,174 @@
+import {
+ Box,
+ Button,
+ FormControl,
+ FormHelperText,
+ FormLabel,
+ Input,
+ Modal,
+ ModalBody,
+ ModalCloseButton,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ ModalOverlay,
+ Text,
+ Textarea,
+ useToast,
+ } from "@chakra-ui/react";
+ import React, { useEffect, useState } from "react";
+ import * as yup from "yup";
+ import { yupResolver } from "@hookform/resolvers/yup";
+ import { useForm } from "react-hook-form";
+ import ToastBox from "../../../../Components/ToastBox";
+ import { useApproveExitTransactionMutation } from "../../../../Services/io.service";
+
+ export const conformModalSchema = yup.object().shape({
+ checkerComment: yup
+ .string()
+ .required("Comment is required")
+ .max(200, "Approve Comment cannot be more than 200 characters"),
+ });
+
+ const ApprovedExit = ({ isOpen, onClose, firstField ,id}) => {
+ const [isBtnLoading , setIsBtnLoading] = useState(false)
+
+ const toast = useToast()
+
+ const {
+ register,
+ reset,
+ watch,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ resolver: yupResolver(conformModalSchema),
+ });
+
+ const [ approveExitTransaction ] = useApproveExitTransactionMutation()
+
+
+ const onSubmit = async(data) => {
+ setIsBtnLoading(true)
+ try {
+ const res = await approveExitTransaction({data,id})
+ if (res?.error) {
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsBtnLoading(false)
+ }else if(res?.data){
+ toast({
+ render: () => (
+
+ ),
+ });
+ onClose()
+ setIsBtnLoading(false)
+ }else{
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsBtnLoading(false)
+ }
+ } catch (error) {
+
+ }
+ };
+
+ const handleFileChange = (event) => {
+ const selectedFile = event.target.files[0];
+ setFile(selectedFile);
+ };
+
+
+ const { data, isLoading } =
+ (id, {
+ skip: !id,
+ });
+
+ useEffect(() => {
+ if (data) {
+ reset({
+ investorAmount: data?.data?.investorAmount,
+ });
+ }
+ }, [data, reset]);
+
+ const heandleOnClose = () =>{
+ reset()
+ onClose()
+ }
+
+
+ return (
+
+
+
+ Approve Comment
+
+ {isLoading ? (
+
+ ) : (
+
+
+
+ Comment
+
+ {errors.checkerComment && (
+
+ {errors.checkerComment.message}
+
+ )}
+
+ Maximum length should be 200 characters. You have entered
+ {watch("checkerComment")?.length || 0} characters.
+
+
+
+
+
+ Cancel
+
+
+ Send
+
+
+
+ )}
+
+
+ );
+ };
+
+ export default ApprovedExit;
+
\ No newline at end of file
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/Pending.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/Pending.jsx
index 66af682..cd9a771 100644
--- a/src/Pages/IO_Management/CreateIO/IOTransaction/Pending.jsx
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/Pending.jsx
@@ -1,122 +1,137 @@
import {
- Avatar,
- Badge,
- Box,
- Button,
- HStack,
- Input,
- Table,
- Tag,
- Tbody,
- Text,
- Th,
- Tooltip,
- Tr,
- useDisclosure,
- useToast,
- } from "@chakra-ui/react";
- import React, { useContext, useEffect, useRef, useState } from "react";
- import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
- import NormalTable from "../../../../Components/DataTable/NormalTable";
- import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
- import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
-import { CheckIcon, CloseIcon } from "@chakra-ui/icons";
+ Avatar,
+ Badge,
+ Box,
+ Button,
+ HStack,
+ Input,
+ Table,
+ Tag,
+ Tbody,
+ Text,
+ Th,
+ Tooltip,
+ Tr,
+ useDisclosure,
+ useToast,
+} from "@chakra-ui/react";
+import React, { useContext, useEffect, useRef, useState } from "react";
+import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
+import NormalTable from "../../../../Components/DataTable/NormalTable";
+import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
+import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
+import { CheckIcon, CloseIcon, ViewIcon } from "@chakra-ui/icons";
import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal";
-
- const formatDate = (date) => new Date(date).toLocaleDateString();
-
- const Pending = () => {
- const toast = useToast();
- const firstField = useRef();
- const { isOpen, onOpen, onClose } = useDisclosure();
- const { IODetails, iOTransaction, setIOTransaction } =
- useContext(GlobalStateContext);
- const [searchTerm, setSearchTerm] = useState("");
- const [isLoading, setIsLoading] = useState(true);
- const [deleteAlert, setDeleteAlert] = useState(false);
- const [actionId, setActionId] = useState(false);
- const [mouseEntered, setMouseEntered] = useState(false);
- const [mouseEnteredId, setMouseEnteredId] = useState("");
+import ViewAmountInvested from "./ViewAmountInvested";
+import ViewDistributionInvestor from "./ViewDistributionInvestor";
+import ViewExit from "./ViewExit";
+import ViewCancel from "./ViewCancel";
- const {
- isOpen: isConfirmOpen,
- onOpen: onConfirmOpen,
- onClose: onConfirmClose,
- } = useDisclosure();
- const {
- isOpen: isRejectOpen,
- onOpen: onRejectOpen,
- onClose: onRejectClose,
- } = useDisclosure();
-
- useEffect(() => {
- // Simulate loading
- const timer = setTimeout(() => {
- setIsLoading(false);
- }, 1500);
-
- // Cleanup the timer on component unmount
- return () => clearTimeout(timer);
- }, []);
-
- const formatDate = (date) => {
- return new Date(date).toLocaleDateString("en-GB", {
- day: "2-digit",
- month: "2-digit",
- year: "numeric",
- });
- };
-
- console.log("==============panding",IODetails?.ioTransactionRecords?.Pending);
-
-
- // Table filter
- // const filteredData = IODetails?.ioTransactionRecords?.Pending?.filter((item) => {
- // // Filter by name (case insensitive)
- // const name = item.transactionName;
- // const searchLower = searchTerm?.toLowerCase();
- // const nameMatches = name?.toLowerCase().includes(searchLower);
- // return nameMatches;
- // });
-
- const tableHeadRow = [
- "Sr No.",
- "Transaction Name",
- "Amount",
- "Created By",
- "Created On",
- // "Approved By",
- "Approved On",
- "Status"
- ];
-
- const extractedArray = IODetails?.ioTransactionRecords?.Pending?.map((item, index) => ({
+const formatDate = (date) => new Date(date).toLocaleDateString();
+
+const Pending = () => {
+ const toast = useToast();
+ const firstField = useRef();
+ const { isOpen, onOpen, onClose } = useDisclosure();
+ const { IODetails, iOTransaction, setIOTransaction } =
+ useContext(GlobalStateContext);
+ const [searchTerm, setSearchTerm] = useState("");
+ const [isLoading, setIsLoading] = useState(true);
+ const [deleteAlert, setDeleteAlert] = useState(false);
+ const [actionId, setActionId] = useState(false);
+ const [mouseEntered, setMouseEntered] = useState(false);
+ const [mouseEnteredId, setMouseEnteredId] = useState("");
+
+ const {
+ isOpen: isConfirmOpen,
+ onOpen: onConfirmOpen,
+ onClose: onConfirmClose,
+ } = useDisclosure();
+ const {
+ isOpen: isRejectOpen,
+ onOpen: onRejectOpen,
+ onClose: onRejectClose,
+ } = useDisclosure();
+ const {
+ isOpen: isInvestmentOpen,
+ onOpen: onInvestmentOpen,
+ onClose: onInvestmentClose,
+ } = useDisclosure();
+ const {
+ isOpen: isDistInvestorOpen,
+ onOpen: onDistInvestorOpen,
+ onClose: onDistInvestorClose,
+ } = useDisclosure();
+ const {
+ isOpen: isExitOpen,
+ onOpen: onExitOpen,
+ onClose: onExitClose,
+ } = useDisclosure();
+ const {
+ isOpen: isCancelOpen,
+ onOpen: onCancelOpen,
+ onClose: onCancelClose,
+ } = useDisclosure();
+
+ useEffect(() => {
+ // Simulate loading
+ const timer = setTimeout(() => {
+ setIsLoading(false);
+ }, 1500);
+
+ // Cleanup the timer on component unmount
+ return () => clearTimeout(timer);
+ }, []);
+
+ const formatDate = (date) => {
+ return new Date(date).toLocaleDateString("en-GB", {
+ day: "2-digit",
+ month: "2-digit",
+ year: "numeric",
+ });
+ };
+
+ console.log(
+ "==============panding",
+ IODetails?.ioTransactionRecords?.Pending
+ );
+
+ // Table filter
+ // const filteredData = IODetails?.ioTransactionRecords?.Pending?.filter((item) => {
+ // // Filter by name (case insensitive)
+ // const name = item.transactionName;
+ // const searchLower = searchTerm?.toLowerCase();
+ // const nameMatches = name?.toLowerCase().includes(searchLower);
+ // return nameMatches;
+ // });
+
+ const tableHeadRow = [
+ "Sr No.",
+ "Transaction Name",
+ "Amount",
+ "Created By",
+ "Created On",
+ "Approved By",
+ "Approved On",
+ "Status",
+ ];
+
+ const extractedArray = IODetails?.ioTransactionRecords?.Pending?.map(
+ (item, index) => ({
id: item?.id,
"Sr No.": (
-
+
{index + 1}.
),
"Transaction Name": (
-
+
{item?.transactionType}
),
- "Amount": (
-
+ Amount: (
+
$
@@ -124,160 +139,128 @@ import RequestRejectModal from "./RequestRejectModal";
),
"Created By": (
-
+
{item?.createdBy}
),
"Created On": (
-
+
{formatDate(item?.createdAt)}
),
"Approved By": (
-
- {item?.modifier ? item?.modifier : "---" }
+
+ {item?.modifier ? item?.modifier : "---"}
),
"Approved On": (
-
- {item?.modifier ? formatDate(item?.updatedAt) : "---" }
- {}
+
+ {item?.modifier ? formatDate(item?.updatedAt) : "---"}
),
- "Status": (
+ Status: (
- {
+ setActionId(item.id); // Set the action ID for all cases
+ if (item?.transactionType === "Amount Invested") {
+ onInvestmentOpen();
+ } else if (item?.transactionType === "Distribution To Investor") {
+ onDistInvestorOpen();
+ } else if (item?.transactionType === "Exit") {
+ onExitOpen();
+ } else if (item?.transactionType === "Cancel") {
+ onCancelOpen();
+ }
+ }}
>
- {
- setActionId(item.id);
- onConfirmOpen();
- }}
- colorScheme="green"
- variant={"solid"}
- cursor={"pointer"}
- >
-
-
-
-
- {
- setActionId(item.id);
- onRejectOpen();
- }}
- py={1}
- // variant={"solid"}
- >
-
-
-
+ View
+
),
- }));
-
- const handleDelete = () => {
- const updatedSponsors = sponser.filter(
- (sponsor) => sponsor.id !== actionId
- );
-
- setTimeout(() => {
- setCaseDetails(updatedSponsors);
- setDeleteAlert(false);
- setIsLoading(false);
- }, 100);
- setIsLoading(true);
- };
-
- return (
-
-
-
- setSearchTerm(e.target.value)}
- />
-
-
-
-
-
- setDeleteAlert(false)}
- isOpen={deleteAlert}
- message={"Are you sure you want to delete sponers?"}
- alertHandler={handleDelete}
- isLoading={isLoading}
- />
+ })
+ );
+ const handleDelete = () => {
+ const updatedSponsors = sponser.filter(
+ (sponsor) => sponsor.id !== actionId
+ );
+
+ setTimeout(() => {
+ setCaseDetails(updatedSponsors);
+ setDeleteAlert(false);
+ setIsLoading(false);
+ }, 100);
+ setIsLoading(true);
+ };
+
+ return (
+
+
+
+ setSearchTerm(e.target.value)}
+ />
+
+
+
+
+
+ setDeleteAlert(false)}
+ isOpen={deleteAlert}
+ message={"Are you sure you want to delete sponers?"}
+ alertHandler={handleDelete}
+ isLoading={isLoading}
+ />
+
+
+
+
+
-
- );
- };
-
- export default Pending;
-
\ No newline at end of file
+
+ );
+};
+
+export default Pending;
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/Rejected.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/Rejected.jsx
index 21f09ab..ef5420d 100644
--- a/src/Pages/IO_Management/CreateIO/IOTransaction/Rejected.jsx
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/Rejected.jsx
@@ -75,7 +75,7 @@ import {
"Amount",
"Created By",
"Created On",
- // "Approved By",
+ "Approved By",
"Approved On",
];
@@ -138,7 +138,7 @@ import {
color={"gray.800"}
fontWeight={"500"}
>
- {item?.modifier ? item?.modifier : "---" }
+ {item?.modifier ? formatDate(item?.updatedAt) : "---" }
),
"Approved On": (
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/RequestRejectModal.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/RequestRejectModal.jsx
index 3a44d26..561150e 100644
--- a/src/Pages/IO_Management/CreateIO/IOTransaction/RequestRejectModal.jsx
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/RequestRejectModal.jsx
@@ -44,11 +44,25 @@ const RequestRejectModal = ({ isOpen, onClose, firstField ,id}) => {
const [ rejectIOCase ] = useRejectIOCaseMutation()
+ const handleFileChange = (event) => {
+ const selectedFile = event.target.files[0];
+ setFile(selectedFile);
+ };
+
+
+ const { data, isLoading } =
+ (id, {
+ skip: !id,
+ });
+
+ console.log("============data",data);
+
+
const onSubmit = async(data) => {
console.log(data, "tewxttttt");
setIsBtnLoading(true)
try {
- const res = await rejectIOCase({data,id})
+ const res = await rejectIOCase({data, id})
if (res?.error) {
toast({
render: () => (
@@ -77,24 +91,14 @@ const RequestRejectModal = ({ isOpen, onClose, firstField ,id}) => {
}
};
- const handleFileChange = (event) => {
- const selectedFile = event.target.files[0];
- setFile(selectedFile);
- };
-
- const { data, isLoading } =
- (id, {
- skip: !id,
- });
-
- useEffect(() => {
- if (data) {
- reset({
- investorAmount: data?.data?.investorAmount,
- });
- }
- }, [data, reset]);
+ // useEffect(() => {
+ // if (data) {
+ // reset({
+ // investorAmount: data?.data?.investorAmount,
+ // });
+ // }
+ // }, [data, reset]);
const heandleOnClose = () =>{
reset()
@@ -138,7 +142,7 @@ const RequestRejectModal = ({ isOpen, onClose, firstField ,id}) => {
colorScheme="gray"
mr={3}
onClick={onClose}
- size={"sm"}
+ size={"xs"}
rounded={"sm"}
>
Cancel
@@ -146,7 +150,7 @@ const RequestRejectModal = ({ isOpen, onClose, firstField ,id}) => {
{
+ if (isNaN(value)) return "";
+ const formatted = parseFloat(value).toFixed(2).toString();
+ const [integer, decimal] = formatted.split(".");
+ const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+ return decimal ? `${formattedInteger}.${decimal}` : formattedInteger;
+};
+
+const ViewAmountInvested = ({ isOpen, onClose, id:investorId }) => {
+ const params = useParams();
+ const toast = useToast();
+ const id = params?.id;
+ const {
+ control,
+ register,
+ handleSubmit,
+ reset,
+ watch,
+ formState: { errors },
+ } = useForm({
+ resolver: yupResolver(validationSchema),
+ });
+ const [isLoading, setIsLoading] = useState(false);
+ const { IODetails } = useContext(GlobalStateContext);
+ const [amountInvested] = useAmountIvestmentMutation();
+ const [actionId, setActionId] = useState(false);
+
+ const {
+ isOpen: isConfirmOpen,
+ onOpen: onConfirmOpen,
+ onClose: onConfirmClose,
+ } = useDisclosure();
+ const {
+ isOpen: isRejectOpen,
+ onOpen: onRejectOpen,
+ onClose: onRejectClose,
+ } = useDisclosure();
+
+ useEffect(() => {
+ if (IODetails?.totalAmtInvestmentInUSD) {
+ const totalAmount = parseFloat(IODetails.totalAmtInvestmentInUSD);
+ const ioCashUpdate = parseFloat(IODetails.totalAmtInvestmentInUSD);
+ reset({
+ Total_Amount: totalAmount,
+ IoCash: ioCashUpdate,
+ });
+ }
+ }, [IODetails, reset]);
+
+ const onSubmit = async (data) => {
+ console.log(data);
+ setIsLoading(true);
+
+ try {
+ const res = await amountInvested({ data, id });
+ console.log(res);
+ if (res?.data?.statusCode === 200) {
+ toast({
+ render: () => ,
+ });
+ setIsLoading(false);
+ onClose();
+ } else if (res?.error?.status === 400) {
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsLoading(false);
+ }
+ } catch (error) {
+ setIsLoading(false);
+ }
+ };
+
+ const handleAmountChange = (e) => {
+ // e might be an object or just a value, handle both cases
+ const amount =
+ typeof e === "object" && e.target
+ ? parseFloat(e.target.value) || 0
+ : parseFloat(e) || 0;
+ const totalAmount = parseFloat(IODetails?.totalAmtInvestmentInUSD) || 0;
+ const ioCash = (totalAmount - amount).toFixed(2);
+
+ reset({
+ amountInvested: parseFloat(amount),
+ IoCash: parseFloat(ioCash),
+ Total_Amount: IODetails?.totalAmtInvestmentInUSD,
+ });
+ };
+
+ return (
+
+
+
+ Amount Invested
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ViewAmountInvested;
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/ViewCancel.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/ViewCancel.jsx
new file mode 100644
index 0000000..1b89458
--- /dev/null
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/ViewCancel.jsx
@@ -0,0 +1,363 @@
+import {
+ Badge,
+ Box,
+ Button,
+ HStack,
+ Modal,
+ ModalBody,
+ ModalCloseButton,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ ModalOverlay,
+ Table,
+ Tbody,
+ Text,
+ Th,
+ Tr,
+ useDisclosure,
+ useToast,
+ } from "@chakra-ui/react";
+ import NormalData from "../../../../Components/DataTable/NormalTable";
+ import { useContext, useState } from "react";
+ import {
+ useExitIOTransactionMutation,
+ useGetDistributedToInvestorMutation,
+ useGetDistributionInvestorMutation,
+ useGetIOByIdQuery,
+ } from "../../../../Services/io.service";
+ import { useParams } from "react-router-dom";
+ import { useEffect } from "react";
+ import { useForm } from "react-hook-form";
+ import * as yup from "yup";
+ import { yupResolver } from "@hookform/resolvers/yup";
+ import ToastBox from "../../../../Components/ToastBox";
+ import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
+import ApprovedCancelTransaction from "./ApprovedCancelTransaction";
+import RequestRejectModal from "./RequestRejectModal";
+
+ const ViewCancel = ({ isOpen, onClose,id:cancleId }) => {
+ const params = useParams();
+ const toast = useToast();
+ const id = params?.id;
+ const [isCalculateLoading, setIsCalculateLoading] = useState(false);
+ const [isFinalCalculateLoading, setIsFinalCalculateLoading] = useState(false);
+ const [calcualtedData, setCalculatedDate] = useState(null);
+ const [isCalcualtedData, setIsCalcualtedData] = useState(false);
+ const { investors, setInvestors, slideFromRight, IODetails } =
+ useContext(GlobalStateContext);
+
+ const [actionId, setActionId] = useState(false);
+
+ const {
+ isOpen: isConfirmOpen,
+ onOpen: onConfirmOpen,
+ onClose: onConfirmClose,
+ } = useDisclosure();
+ const {
+ isOpen: isRejectOpen,
+ onOpen: onRejectOpen,
+ onClose: onRejectClose,
+ } = useDisclosure();
+
+ const investorExit = yup.object().shape({
+ amount: yup
+ .string()
+ .required("Amount is required")
+ .test(
+ "max",
+ `Distribution amount should not be greater than IO cash amount ${IODetails?.ioCash}`,
+ function (value) {
+ const { ioCash } = IODetails || {}; // Safely get ioCash
+ if (value && ioCash) {
+ return parseFloat(value) <= parseFloat(ioCash); // Ensure both are compared as numbers
+ }
+ return true; // If ioCash is not available, skip validation
+ }
+ ),
+ });
+
+ const {
+ control,
+ handleSubmit,
+ formState: { errors },
+ reset,
+ } = useForm({
+ resolver: yupResolver(investorExit),
+ });
+
+ useEffect(() => {
+ console.log("hiit useEffectc");
+ handleCalculate(id, {
+ amount: IODetails?.ioMVNAV,
+ });
+ reset({
+ amount: IODetails?.ioMVNAV,
+ });
+ }, [IODetails, id]);
+
+ const handleCalculate = async (id, data) => {
+ try {
+ const res = await getDistributionInvestment({ id, data });
+ console.log(res?.data?.data);
+
+ if (res?.error?.status === 401) {
+ setIsCalculateLoading(false);
+ setIsCalcualtedData(false);
+ } else if (res?.data?.statusCode === 200) {
+ setCalculatedDate(res?.data?.data);
+ setIsCalculateLoading(false);
+ setIsCalcualtedData(true);
+ }
+ } catch (error) {}
+ };
+
+ const [getDistributionInvestment] = useGetDistributionInvestorMutation();
+
+ const investor = yup.object().shape({
+ amount: yup.string().required("Amount is required"),
+ });
+
+ // ====================================================[Table Setup]================================================================
+ const tableHeadRow = [
+ "Client ID",
+ "First name",
+ "Last name",
+ "Investment amount",
+ "Percentage",
+ "Market Value",
+ "Return on Investment",
+ "Distribution",
+ "Distribution Percent",
+ "Total Return",
+ "Total return on Investment",
+ ];
+
+ const extractedArray = IODetails?.investors?.map((item, index) => ({
+ id: item?.id,
+ "Client ID": (
+
+ {item?.clientReference_id}
+
+ ),
+ "First name": (
+
+ {item.firstName}
+
+ ),
+ "Last name": (
+
+ {item.lastName}
+
+ ),
+ "Investment amount": (
+
+
+ $
+
+ {/* {`$${formatCurrency(item.InvestedAmount_USD)}`} */}
+ {`${parseFloat(item.InvestedAmount_USD || 0).toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}`}
+
+ ),
+ Percentage: (
+
+ {item.Investor_Holidings} %
+
+ ),
+ "Market Value": (
+
+
+ $
+
+ {`${parseFloat(item.Market_Value || 0).toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}`}
+
+ ),
+ "Return on Investment": (
+
+ {item.Return_On_Investment || 0} %
+
+ ),
+ Distribution: (
+
+
+ $
+
+ {/* {`$${item.Distribution_Amt}`} */}
+ {`${parseFloat(item.Distribution_Amt || 0).toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}`}
+
+ ),
+ "Distribution Percent": (
+
+ {/* {`$${item.Distribution_Amt}`} */}
+ {`${parseFloat(item.Distribution_Per || 0).toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })} %`}
+
+ ),
+ "Total Return": (
+
+
+ $
+
+ {/* {`$${formatCurrency(item.Total_Return) || 0}`} */}
+ {`${parseFloat(item.Total_Return || 0).toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}`}
+
+ ),
+ "Total return on Investment": (
+
+ {item.Total_Return_On_Investment || 0} %
+
+ ),
+ }));
+
+ const handleClose = () => {
+ onClose();
+ setIsFinalCalculateLoading(false);
+ setIsCalcualtedData(false);
+ };
+
+ return (
+
+
+
+ Cancel Transaction
+
+
+
+
+
+
+ {
+ setActionId(id); // Use the `id` variable from params
+ onConfirmOpen();
+ }}
+ colorScheme="forestGreen"
+ variant={"solid"}
+ cursor={"pointer"}
+ >
+ Approve
+
+ {
+ setActionId(id); // Use the `id` variable from params
+ onRejectOpen();
+ }}
+ >
+ Reject
+
+
+
+
+
+
+
+ );
+ };
+
+ export default ViewCancel;
+
\ No newline at end of file
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/ViewDistributionInvestor.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/ViewDistributionInvestor.jsx
new file mode 100644
index 0000000..591ace7
--- /dev/null
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/ViewDistributionInvestor.jsx
@@ -0,0 +1,267 @@
+import {
+ Box,
+ Button,
+ Modal,
+ ModalBody,
+ ModalCloseButton,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ ModalOverlay,
+ Text,
+ useDisclosure,
+ useToast,
+} from "@chakra-ui/react";
+import NormalData from "../../../../Components/DataTable/NormalTable";
+import { useContext, useState } from "react";
+import { useGetDistributionInvestorMutation } from "../../../../Services/io.service";
+import { useParams } from "react-router-dom";
+import { useEffect } from "react";
+import { useForm } from "react-hook-form";
+import * as yup from "yup";
+import { yupResolver } from "@hookform/resolvers/yup";
+import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
+import ApproveDistrubationModal from "./ApproveDistrubationModal";
+import RequestRejectModal from "./RequestRejectModal";
+
+const ViewDistributionInvestor = ({ isOpen, onClose,id:exitId }) => {
+ const params = useParams();
+ const toast = useToast();
+ const id = params?.id;
+ const [isCalculateLoading, setIsCalculateLoading] = useState(false);
+ const [isFinalCalculateLoading, setIsFinalCalculateLoading] = useState(false);
+ const [calcualtedData, setCalculatedDate] = useState(null);
+ const [isCalcualtedData, setIsCalcualtedData] = useState(false);
+ const { IODetails } = useContext(GlobalStateContext);
+ const [actionId, setActionId] = useState(false);
+
+ const investorExit = yup.object().shape({
+ amount: yup
+ .string()
+ .required("Amount is required")
+ .test(
+ "max",
+ `Distribution amount should not be greater than IO cash amount ${IODetails?.ioCash}`,
+ function (value) {
+ const { ioCash } = IODetails || {}; // Safely get ioCash
+ if (value && ioCash) {
+ return parseFloat(value) <= parseFloat(ioCash); // Ensure both are compared as numbers
+ }
+ return true; // If ioCash is not available, skip validation
+ }
+ ),
+ });
+
+ const {
+ isOpen: isConfirmOpen,
+ onOpen: onConfirmOpen,
+ onClose: onConfirmClose,
+ } = useDisclosure();
+ const {
+ isOpen: isRejectOpen,
+ onOpen: onRejectOpen,
+ onClose: onRejectClose,
+ } = useDisclosure();
+
+ const {
+ formState: { errors },
+ reset,
+ } = useForm({
+ resolver: yupResolver(investorExit),
+ });
+
+ useEffect(() => {
+ console.log("hiit useEffectc");
+ handleCalculate(id, {
+ amount: IODetails?.ioMVNAV,
+ });
+ reset({
+ amount: IODetails?.ioMVNAV,
+ });
+ }, [IODetails, id]);
+
+ const handleCalculate = async (id, data) => {
+ try {
+ const res = await getDistributionInvestment({ id, data });
+ console.log(res?.data?.data);
+
+ if (res?.error?.status === 401) {
+ setIsCalculateLoading(false);
+ setIsCalcualtedData(false);
+ } else if (res?.data?.statusCode === 200) {
+ setCalculatedDate(res?.data?.data);
+ setIsCalculateLoading(false);
+ setIsCalcualtedData(true);
+ }
+ } catch (error) {}
+ };
+
+ const [getDistributionInvestment] = useGetDistributionInvestorMutation();
+
+ // ====================================================[Table Setup]================================================================
+ const tableHeadRow = [
+ "Sr No.",
+ "Client Id",
+ "First name",
+ "Last Name",
+ "Amount",
+ "Holding (%)",
+ "Distriution Amt($)",
+ "Yeild (%)",
+ ];
+
+ const extractedArray = calcualtedData?.data?.map((item, index) => ({
+ id: item?.id,
+ "Sr No.": (
+
+
+ {index + 1}
+
+
+ ),
+ "Client Id": (
+
+
+ {item?.clientId}
+
+
+ ),
+ "First name": (
+
+
+ {item?.firstName}
+
+
+ ),
+ "Last Name": (
+
+
+ {item?.lastName}
+
+
+ ),
+ Amount: (
+
+
+ {item?.amount?.toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}
+
+
+ ),
+ "Holding (%)": (
+
+
+ {item?.investor_holidings?.toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}
+ %
+
+
+ ),
+ "Distriution Amt($)": (
+
+
+ {item?.distribution_amt?.toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}
+
+
+ ),
+ "Yeild (%)": (
+
+
+ {item?.distribution_per?.toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}
+ %
+
+
+ ),
+ }));
+
+ const handleClose = () => {
+ onClose();
+ setIsFinalCalculateLoading(false);
+ setIsCalcualtedData(false);
+ };
+
+ console.log(exitId);
+
+
+ return (
+
+
+
+
+ Distribution To Investor Transaction
+
+
+
+
+
+
+
+ {
+ setActionId(id); // Use the `id` variable from params
+ onConfirmOpen();
+ }}
+ colorScheme="forestGreen"
+ variant={"solid"}
+ cursor={"pointer"}
+ >
+ Approve
+
+ {
+ setActionId(id); // Use the `id` variable from params
+ onRejectOpen();
+ }}
+ >
+ Reject
+
+
+
+
+
+
+
+ );
+};
+
+export default ViewDistributionInvestor;
diff --git a/src/Pages/IO_Management/CreateIO/IOTransaction/ViewExit.jsx b/src/Pages/IO_Management/CreateIO/IOTransaction/ViewExit.jsx
new file mode 100644
index 0000000..262adcf
--- /dev/null
+++ b/src/Pages/IO_Management/CreateIO/IOTransaction/ViewExit.jsx
@@ -0,0 +1,324 @@
+import {
+ Alert,
+ AlertIcon,
+ Box,
+ Button,
+ FormControl,
+ FormErrorMessage,
+ FormLabel,
+ HStack,
+ Input,
+ Modal,
+ ModalBody,
+ ModalCloseButton,
+ ModalContent,
+ ModalFooter,
+ ModalHeader,
+ ModalOverlay,
+ Switch,
+ Table,
+ Tbody,
+ Text,
+ Textarea,
+ Th,
+ Tr,
+ useDisclosure,
+ useToast,
+ } from "@chakra-ui/react";
+ import NormalData from "../../../../Components/DataTable/NormalTable";
+ import { useContext, useState } from "react";
+ import { AddIcon } from "@chakra-ui/icons";
+ import {
+ useExitIOTransactionMutation,
+ useGetDistributedToInvestorMutation,
+ useGetDistributionInvestorMutation,
+ useUpdateExitToInvestorMutation,
+ } from "../../../../Services/io.service";
+ import { useParams } from "react-router-dom";
+ import { useEffect } from "react";
+ import { Controller, useForm } from "react-hook-form";
+ import * as yup from "yup";
+ import { yupResolver } from "@hookform/resolvers/yup";
+ import ToastBox from "../../../../Components/ToastBox";
+ import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
+import ApprovedExit from "./ApprovedExit";
+import RequestRejectModal from "./RequestRejectModal";
+
+ const ViewExit = ({ isOpen, onClose ,id:investerId}) => {
+ const params = useParams();
+ const toast = useToast();
+ const id = params?.id;
+ const [isCalculateLoading, setIsCalculateLoading] = useState(false);
+ const [isFinalCalculateLoading, setIsFinalCalculateLoading] = useState(false);
+ const [calcualtedData, setCalculatedDate] = useState(null);
+ const [isCalcualtedData, setIsCalcualtedData] = useState(false);
+ const { IODetails } = useContext(GlobalStateContext);
+ const [actionId, setActionId] = useState(false);
+
+ const {
+ isOpen: isConfirmOpen,
+ onOpen: onConfirmOpen,
+ onClose: onConfirmClose,
+ } = useDisclosure();
+ const {
+ isOpen: isRejectOpen,
+ onOpen: onRejectOpen,
+ onClose: onRejectClose,
+ } = useDisclosure();
+
+
+ const {
+ control,
+ handleSubmit,
+ formState: { errors },
+ reset,
+ } = useForm({
+ resolver: yupResolver(),
+ });
+
+ useEffect(() => {
+ console.log("hiit useEffectc");
+ handleCalculate(id, {
+ amount: IODetails?.ioMVNAV,
+ });
+ reset({
+ amount: IODetails?.ioMVNAV,
+ });
+ }, [IODetails, id]);
+
+ const handleCalculate = async (id, data) => {
+ try {
+ const res = await getDistributionInvestment({ id, data });
+ console.log(res?.data?.data);
+
+ if (res?.error?.status === 401) {
+ setIsCalculateLoading(false);
+ setIsCalcualtedData(false);
+ } else if (res?.data?.statusCode === 200) {
+ setCalculatedDate(res?.data?.data);
+ setIsCalculateLoading(false);
+ setIsCalcualtedData(true);
+ }
+ } catch (error) {}
+ };
+
+ const [getDistributionInvestment] = useGetDistributionInvestorMutation();
+
+ const investor = yup.object().shape({
+ amount: yup.string().required("Amount is required"),
+ });
+
+ // ====================================================[Table Setup]================================================================
+ const tableHeadRow = [
+ "Sr No.",
+ "Client Id",
+ "First name",
+ "Last Name",
+ "Amount",
+ "Holding (%)",
+ "Exit Amt($)",
+ ];
+
+
+
+ const extractedArray = calcualtedData?.data?.map((item, index) => ({
+ id: item?.id,
+ "Sr No.": (
+
+
+ {index + 1}
+
+
+ ),
+ "Client Id": (
+
+
+ {item?.clientId}
+
+
+ ),
+ "First name": (
+
+
+ {item?.firstName}
+
+
+ ),
+ "Last Name": (
+
+
+ {item?.lastName}
+
+
+ ),
+ Amount: (
+
+
+ {item?.amount?.toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}
+
+
+ ),
+ "Holding (%)": (
+
+
+ {item?.investor_holidings?.toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}%
+
+
+ ),
+ "Exit Amt($)": (
+
+
+ {item?.distribution_amt?.toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}
+
+
+ ),
+ }));
+
+ const onSubmit = async (data) => {
+ setIsCalculateLoading(true);
+
+ try {
+ const res = await getDistributionInvestment({ id, data });
+ console.log(res?.data?.data);
+
+ if (res?.error?.status === 401) {
+ toast({
+ render: () => (
+
+ ),
+ });
+ setIsCalculateLoading(false);
+ setIsCalcualtedData(false);
+ } else if (res?.data?.statusCode === 200) {
+ setCalculatedDate(res?.data?.data);
+ toast({
+ render: () => ,
+ });
+ setIsCalculateLoading(false);
+ setIsCalcualtedData(true);
+ }
+ } catch (error) {}
+ };
+
+ const handleClose = () => {
+ onClose();
+ setIsFinalCalculateLoading(false);
+ setIsCalcualtedData(false);
+ };
+
+ console.log(id);
+
+
+ return (
+
+
+
+ Exit Transaction
+
+
+ {/*
+ Amount to Distribute
+ */}
+
+ {/* */}
+ {/* */}
+
+ Exit Amount :
+
+
+ ${" "}
+ {parseFloat(IODetails?.ioMVNAV || 0).toLocaleString(undefined, {
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 2,
+ })}
+
+
+ {/* */}
+
+
+ {/* {calcualtedData && ( */}
+ }
+ // isLoading={isLoading}
+ />
+ {/* ) } */}
+
+
+
+ {
+ setActionId(id); // Use the `id` variable from params
+ onConfirmOpen();
+ }}
+ colorScheme="forestGreen"
+ variant={"solid"}
+ cursor={"pointer"}
+ >
+ Approve
+
+ {
+ setActionId(id); // Use the `id` variable from params
+ onRejectOpen();
+ }}
+ >
+ Reject
+
+
+
+
+
+
+
+ );
+ };
+
+ export default ViewExit;
+
\ No newline at end of file
diff --git a/src/Pages/IO_Management/CreateIO/Investors.jsx b/src/Pages/IO_Management/CreateIO/Investors.jsx
index b30466a..36f0955 100644
--- a/src/Pages/IO_Management/CreateIO/Investors.jsx
+++ b/src/Pages/IO_Management/CreateIO/Investors.jsx
@@ -100,7 +100,7 @@ const Investors = ({ data }) => {
0
);
- // Table setup
+ // Table setup
const tableHeadRow = [
"Client ID",
"First name",
diff --git a/src/Pages/IO_Management/ViewIO/HeaderModal/AmountInvested.jsx b/src/Pages/IO_Management/ViewIO/HeaderModal/AmountInvested.jsx
index 7025d12..ecbff24 100644
--- a/src/Pages/IO_Management/ViewIO/HeaderModal/AmountInvested.jsx
+++ b/src/Pages/IO_Management/ViewIO/HeaderModal/AmountInvested.jsx
@@ -46,7 +46,7 @@ const AmountInvested = ({ isOpen, onClose }) => {
const toast = useToast();
const id = params?.id;
const {
- control,
+ control,
register,
handleSubmit,
reset,
diff --git a/src/Services/io.service.js b/src/Services/io.service.js
index 79d765d..efb5a21 100644
--- a/src/Services/io.service.js
+++ b/src/Services/io.service.js
@@ -540,6 +540,45 @@ export const ioService = createApi({
invalidatesTags: ["getIOById"],
}),
+ approveInvested: builder.mutation({
+ query: ({id,data}) => ({
+ url: `/io/admin/checker-transaction/approved/amount-invested/${id}`,
+ method: "PATCH",
+ body:data,
+ }),
+
+ invalidatesTags: ["getIOById"],
+ }),
+
+ approveDistributed: builder.mutation({
+ query: ({id,data}) => ({
+ url: `/io/admin/checker-transaction/approved/distributed-to-investor/${id}`,
+ method: "PATCH",
+ body:data,
+ }),
+
+ invalidatesTags: ["getIOById"],
+ }),
+
+ approveExitTransaction: builder.mutation({
+ query: ({id,data}) => ({
+ url: `/io/admin/checker-transaction/approved/exit/${id}`,
+ method: "PATCH",
+ body:data,
+ }),
+
+ invalidatesTags: ["getIOById"],
+ }),
+
+ approveCancleTransaction: builder.mutation({
+ query: ({id,data}) => ({
+ url: `/io/admin/checker-transaction/approved/cancel/${id}`,
+ method: "PATCH",
+ body:data,
+ }),
+
+ invalidatesTags: ["getIOById"],
+ }),
rejectIOCase: builder.mutation({
@@ -634,6 +673,10 @@ export const {
useSaveIOTransactionMutation,
useApproveDistributionMutation,
useExitIOTransactionMutation,
- useApproveExitMutation
+ useApproveExitMutation,
+ useApproveInvestedMutation,
+ useApproveDistributedMutation,
+ useApproveExitTransactionMutation,
+ useApproveCancleTransactionMutation
} = ioService;
|