Compare commits

..

44 Commits

Author SHA1 Message Date
188c77c1e1 Merge pull request 'update investor' (#21) from Yasin into release/sprint-8
Reviewed-on: #21
2024-12-02 07:18:48 +00:00
YasinShaikh123
463325e603 update investor 2024-12-02 12:47:44 +05:30
606ac68d85 Merge pull request 'update bug' (#20) from Yasin into release/sprint-8
Reviewed-on: #20
2024-12-02 06:55:15 +00:00
YasinShaikh123
537304f0fb update bug 2024-12-02 12:23:27 +05:30
YasinShaikh123
3b83b625c3 update Investment Details KYC 2024-11-25 20:24:39 +05:30
Swapnil Bendal
694dde0f14 [fixed] - view io details 2024-11-25 19:03:42 +05:30
Swapnil Bendal
4f8916036e [update] - condition on pending request for checkers 2024-11-25 16:45:52 +05:30
YasinShaikh123
0c21e99732 update comment changes 2024-11-25 16:41:19 +05:30
YasinShaikh123
5900f637be Merge branch 'release/sprint-8' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into Yasin 2024-11-25 15:52:33 +05:30
YasinShaikh123
2453b24d91 Merge branch 'main' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into Yasin 2024-11-25 12:21:02 +05:30
Swapnil Bendal
3db9488444 [update] - counter in pending tab 2024-11-22 20:25:21 +05:30
bb30a71a60 Merge pull request 'modal api useEffect' (#19) from Yasin into release/sprint-8
Reviewed-on: #19
2024-11-22 14:27:49 +00:00
YasinShaikh123
526d2aecca modal api useEffect 2024-11-22 19:57:05 +05:30
e742f6c18d Merge pull request 'update modal view' (#18) from Yasin into release/sprint-8
Reviewed-on: #18
2024-11-22 14:24:42 +00:00
YasinShaikh123
d4c9a5521f update modal view 2024-11-22 19:54:12 +05:30
7a04ee0abb Merge pull request 'updaste' (#17) from Yasin into release/sprint-8
Reviewed-on: #17
2024-11-22 13:53:09 +00:00
YasinShaikh123
a12b2c9a2c updaste 2024-11-22 19:22:06 +05:30
0b2e48200a Merge pull request 'token change' (#16) from Yasin into release/sprint-8
Reviewed-on: #16
2024-11-22 13:35:11 +00:00
YasinShaikh123
bf7b3e1596 token change 2024-11-22 19:04:31 +05:30
059b711bc1 Merge branch 'release/sprint-8' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into release/sprint-8 2024-11-22 19:00:15 +05:30
b0c01f3a0c updaate role 2024-11-22 19:00:14 +05:30
973ec656d0 Merge pull request 'update modal close' (#15) from Yasin into release/sprint-8
Reviewed-on: #15
2024-11-22 13:22:09 +00:00
YasinShaikh123
29a49150b7 update modal close 2024-11-22 18:51:05 +05:30
7a908a3284 Merge pull request 'updated' (#14) from Yasin into release/sprint-8
Reviewed-on: #14
2024-11-22 11:28:53 +00:00
YasinShaikh123
23c3997d06 updated 2024-11-22 16:56:31 +05:30
6779fdd672 Merge pull request 'Yasin' (#13) from Yasin into release/sprint-8
Reviewed-on: #13
2024-11-22 10:50:46 +00:00
YasinShaikh123
0ab898a3da update new bugs 2024-11-22 16:19:59 +05:30
YasinShaikh123
f3a8a80f4d update action 2024-11-22 13:32:28 +05:30
d1cbeee294 Merge pull request 'update bugs' (#12) from Yasin into release/sprint-8
Reviewed-on: #12
2024-11-22 07:22:50 +00:00
YasinShaikh123
1c4f975781 update bugs 2024-11-22 12:48:02 +05:30
17ffb864a3 Merge pull request 'Yasin' (#11) from Yasin into release/sprint-8
Reviewed-on: #11
2024-11-21 12:14:25 +00:00
YasinShaikh123
6ffcff58a2 update tabs 2024-11-21 17:42:27 +05:30
82612fa7f2 Merge pull request 'update color bugs' (#10) from main into release/sprint-8
Reviewed-on: #10
2024-11-21 10:36:20 +00:00
YasinShaikh123
470ba49c00 UPDATE invest modal 2024-11-21 16:05:51 +05:30
b29478a939 Merge pull request 'transaction panding' (#9) from Yasin into release/sprint-8
Reviewed-on: #9
2024-11-21 10:22:35 +00:00
YasinShaikh123
7ba524d2e4 transaction panding 2024-11-21 15:51:01 +05:30
cc58cdc9b7 Merge pull request 'update invest amount' (#8) from Yasin into release/sprint-8
Reviewed-on: #8
2024-11-21 10:17:31 +00:00
YasinShaikh123
9f54bfbc65 update invest amount 2024-11-21 15:46:10 +05:30
992cb13e1e Merge pull request 'update transaction status modal' (#7) from Yasin into release/sprint-8
Reviewed-on: #7
2024-11-19 13:53:15 +00:00
YasinShaikh123
85e3c34120 update transaction status modal 2024-11-19 19:19:45 +05:30
46672a34e2 Merge pull request 'update Io Cash Nav Transaction' (#6) from Yasin into release/sprint-8
Reviewed-on: #6
2024-11-18 13:36:45 +00:00
YasinShaikh123
61e49393fe update Io Cash Nav Transaction 2024-11-18 17:54:23 +05:30
YasinShaikh123
5fc16b58ea working tabs👷‍♂️ 2024-11-14 16:04:20 +05:30
YasinShaikh123
06548abf1e update tabs 2024-11-14 12:08:17 +05:30
72 changed files with 8744 additions and 549 deletions

View File

@@ -12,7 +12,8 @@ const FullscreenLoaders = ({height}) => {
w={"100%"}
h={height ? height: "100vh"}
gap={4}
><div className="dot-spinner">
>
{/* <div className="dot-spinner">
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
@@ -21,8 +22,9 @@ const FullscreenLoaders = ({height}) => {
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
</div>
</div> */}
{/* <Text color='#004717' fontSize={'md'} fontWeight={500}>Loading...</Text> */}
<Spinner />
</Box>
);
};

View File

@@ -1,19 +1,21 @@
import React from "react";
import './FullscreenLoaders.css'
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>
// <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>
<Spinner color='green.900' />
);
};

View File

@@ -1557,6 +1557,123 @@ const GlobalStateProvider = ({ children }) => {
},
]);
const [approved, setApproved] = useState([
{
id: 1,
transactionDate: "02-Jan-24",
particulars: "Cash Reserve- Initated",
amount: "50,000.00",
Comments: "",
user: "Faisal",
entryDate: "02-Jan-24",
},
{
id: 2,
transactionDate: "12-Feb-24",
particulars: "Fees & Expense",
amount: "-22,000.00",
Comments: "",
user: "Faisal",
entryDate: "13-Feb-24",
},
{
id: 3,
transactionDate: "12-Feb-24",
particulars: "Distribution Received From Sponsor",
amount: "50,000.00",
Comments: "",
user: "Nawab",
entryDate: "24-Mar-24",
},
{
id: 4,
transactionDate: "28-Mar-24",
particulars: "Distribution Paid To Investors",
amount: "-40,000.00",
Comments: "",
user: "Faisal",
entryDate: "28-Mar-24",
},
{
id: 5,
transactionDate: "26-Jun-24",
particulars: "Distribution Received From Sponsor",
amount: "70,000.00",
Comments: "",
user: "Faisal",
entryDate: "27-Jun-24",
},
{
id: 6,
transactionDate: "28-Jun-24",
particulars: "Distribution Paid To Investors",
amount: "-60,000.00",
Comments: "",
user: "Nawab",
entryDate: "28-Jun-24",
},
]);
const [iONAVDetail, setIONAVDetail] = useState([
{
id: 1,
valuationDate: "01-Jul-24",
nav: "1,229,750.00 ",
lastUpdate: "12.56",
investmentClose: "29.45",
updatedBy: "Nawab",
updatedOn: "01-Jul-24",
},
{
id: 2,
valuationDate: "25-Apr-24",
nav: "1,092,500.00",
lastUpdate: "15.00",
investmentClose: "15.00",
updatedBy: "Faisal",
updatedOn: "25-Apr-24",
},
{
id: 3,
valuationDate: "02-Jan-24",
nav: "950,000.00",
lastUpdate: "",
investmentClose: "",
updatedBy: "Faisal",
updatedOn: "02-Jan-24",
},
]);
const [iOTransaction, setIOTransaction] = useState([
{
id: 1,
transactionName: "Amount Invested",
amount: "995,000",
createdBy: "Faisal",
createdOn: "27-Oct-24",
approvedBy: "Nawab",
approvedOn: "28-Oct-24",
},
{
id: 2,
transactionName: "Distribution To Sponser",
amount: "40,000",
createdBy: "Faisal",
createdOn: "30-Oct-24",
approvedBy: "Nawab",
approvedOn: "31-Oct-24",
},
{
id: 3,
transactionName: "Amount Invested",
amount: "995,000",
createdBy: "Faisal",
createdOn: "27-Oct-24",
approvedBy: "Nawab",
approvedOn: "28-Oct-24",
},
]);
const [InvestorWallet, setInvestorWallet] = useState(null);
// ==============[ prod state ]===============================
@@ -1643,7 +1760,13 @@ const GlobalStateProvider = ({ children }) => {
fawateerRequest,
setFawateerRequest,
approveHistory,
setApproveHistory
setApproveHistory,
approved,
setApproved,
iONAVDetail,
setIONAVDetail,
iOTransaction,
setIOTransaction,
}}
>
{children}

View File

@@ -231,14 +231,14 @@ const DashboardLayout = ({ isOnline }) => {
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Deposit pending request
Deposit Pending Request
</span>
);
case path.startsWith("/deposit-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Deposite request
Deposite Request
</span>
);

View File

@@ -49,7 +49,7 @@ const InvestorComment = ({ isOpen, onClose }) => {
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your comments...."}
placeholder={"Enter your comment...."}
rounded={"md"}
resize={"none"}
/>

View File

@@ -4,6 +4,7 @@ import {
Button,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
Input,
Modal,
@@ -35,7 +36,7 @@ const FILE_TYPES = ["image/jpeg", "image/png", "image/gif"];
export const conformModalSchema = yup.object().shape({
investorAmount: yup.string().required("Investor amount is required"),
comment: yup.string().notRequired(),
comment: yup.string().notRequired() .max(200, "Approve Comment cannot be more than 200 characters"),
supporting_FileName: yup.mixed().required("File is required"),
// .test("fileType", "Unsupported File Format", (value) => {
// return value && FILE_TYPES.includes(value.type);
@@ -192,7 +193,7 @@ const DepositRequestApprove = ({
)}
</FormControl>
<FormControl mb={4}>
<FormLabel fontSize="sm">Comments</FormLabel>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={5}
focusBorderColor="green.400"
@@ -201,14 +202,19 @@ const DepositRequestApprove = ({
fontSize="sm"
type="textarea"
size="sm"
placeholder={"Enter your comments...."}
placeholder={"Enter your comment...."}
resize={"none"}
maxLength={200}
/>
{errors.comment && (
<Text fontSize="xs" color="red">
{errors.comment.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered </Box>
{watch("comment")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>

View File

@@ -2,6 +2,7 @@ import {
Box,
Button,
FormControl,
FormHelperText,
FormLabel,
Input,
Modal,
@@ -24,7 +25,8 @@ import { useDepositRejectMutation } from "../../../Services/deposit.request.serv
import ToastBox from "../../../Components/ToastBox";
export const conformModalSchema = yup.object().shape({
comments: yup.string().required("Comment is required"),
comments: yup.string().required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const DepositRequestReject = ({ isOpen, onClose, firstField ,id}) => {
@@ -35,6 +37,7 @@ const DepositRequestReject = ({ isOpen, onClose, firstField ,id}) => {
const {
register,
reset,
watch,
handleSubmit,
formState: { errors },
} = useForm({
@@ -121,15 +124,20 @@ const DepositRequestReject = ({ isOpen, onClose, firstField ,id}) => {
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your comments...."}
placeholder={"Enter your comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered </Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>

View File

@@ -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,67 @@ 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(),
makerComment: Yup.string() .max(200, "Approve Comment cannot be more than 50 characters"),
});
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,
watch,
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 +101,35 @@ const CreateRequest = () => {
),
});
setIsLoading(false);
reset()
return
reset();
return;
} else if (res?.data) {
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
render: () => <ToastBox message={res?.data?.message} />,
});
setIsLoading(false);
navigate('/fawateer-history')
return
navigate("/fawateer-history");
return;
} else {
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
<ToastBox status={"error"} message={"Something went wrong"} />
),
});
setIsLoading(false);
return
return;
}
} catch (error) {
console.error("Error:", error);
toast({
render: () => (
<ToastBox status={'error'} message={"An error occurred"} />
<ToastBox status={"error"} message={"An error occurred"} />
),
});
setIsLoading(false);
return
return;
}
};
// Handle file change and preview
const handleFileChange = (e) => {
@@ -137,15 +150,12 @@ const CreateRequest = () => {
}
};
return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
<Box
display={"flex"}
justifyContent={"space-between"}
flexWrap={'wrap'}
flexWrap={"wrap"}
alignItems={"center"}
mt={5}
px={4}
@@ -153,11 +163,16 @@ const CreateRequest = () => {
onSubmit={handleSubmit(onSubmit)}
>
{/* Investor Name Field */}
<FormControl isRequired w={"49%"} mb={2} isInvalid={errors.investorName}>
<FormControl
isRequired
w={"49%"}
mb={2}
isInvalid={errors.investorName}
>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Investor name
</FormLabel>
<InputGroup size='sm'>
<InputGroup size="sm">
<Input
bg={"#F5F8F6"}
focusBorderColor="forestGreen.300"
@@ -170,11 +185,24 @@ const CreateRequest = () => {
{...register("investorName")}
_placeholder={{ fontSize: "sm" }}
/>
<InputRightAddon gap={2} color={'forestgreen.400'} onClick={onOpen} cursor={'pointer'} fontWeight={600} fontSize={'xs'}>
<InputRightAddon
gap={2}
color={"forestgreen.400"}
onClick={onOpen}
cursor={"pointer"}
fontWeight={600}
fontSize={"xs"}
>
<Search2Icon /> Search
</InputRightAddon>
</InputGroup>
<FormHelperText fontSize={'xs'} fontWeight={500} style={{ color: "red" }}>{errors.investorName?.message}</FormHelperText>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.investorName?.message}
</FormHelperText>
</FormControl>
{/* Client ID Field */}
@@ -193,7 +221,13 @@ const CreateRequest = () => {
placeholder={"Client ID"}
{...register("clientId")}
/>
<FormHelperText fontSize={'xs'} fontWeight={500} style={{ color: "red" }}>{errors.clientId?.message}</FormHelperText>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.clientId?.message}
</FormHelperText>
</FormControl>
{/* Date Field */}
@@ -208,10 +242,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;
},
})}
/>
<FormHelperText fontSize={'xs'} fontWeight={500} style={{ color: "red" }}>{errors.transaction_date?.message}</FormHelperText>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.transaction_date?.message}
</FormHelperText>
</FormControl>
{/* Amount Field */}
@@ -220,19 +265,35 @@ const CreateRequest = () => {
Amount (BHD)
</FormLabel>
<Controller
name="transaction_amount"
control={control}
render={({ field }) => (
<CurrencyInput bg={"#F5F8F6"} {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} />
)}
/>
<FormHelperText fontSize={'xs'} fontWeight={500} style={{ color: "red" }}>
name="transaction_amount"
control={control}
render={({ field }) => (
<CurrencyInput
bg={"#F5F8F6"}
{...field}
textAlign={"right"}
fontSize={"sm"}
type="number"
size={"sm"}
/>
)}
/>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.transaction_amount?.message}
</FormHelperText>
</FormHelperText>
</FormControl>
{/* Support File Field with Preview */}
<FormControl isRequired w={"49%"} mb={2} isInvalid={errors.spportFile_path}>
<FormControl
isRequired
w={"49%"}
mb={2}
isInvalid={errors.spportFile_path}
>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Support file
</FormLabel>
@@ -249,7 +310,13 @@ const CreateRequest = () => {
{...register("spportFile_path")}
// onChange={handleFileChange}
/>
<FormHelperText fontSize={'xs'} fontWeight={500} style={{ color: "red" }}>{errors.spportFile_path?.message}</FormHelperText>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.spportFile_path?.message}
</FormHelperText>
{/* Animated Preview */}
{filePreview && fileType?.type.startsWith("image/") && (
@@ -259,14 +326,55 @@ const CreateRequest = () => {
transition={{ duration: 0.5 }}
style={{ marginTop: "10px" }}
>
<Box position={'relative'} display={'flex'} alignContent={'flex-end'} gap={3} mt={2}>
<Image src={filePreview} alt="File preview" maxW={"150px"} borderRadius="md" boxShadow="md" />
<Icon onClick={()=> setFilePreview(null)} className="link" rounded={'md'} color={'red.700'} cursor={'pointer'} p={1.5} position={'absolute'} top={0} right={0} as={DeleteIcon} boxSize={7} />
<VStack justifyItems={'flex-end'} alignItems={'flex-start'}>
<Text as={'span'} color={'gray.600'} fontSize={'xs'}>File Name: <Text as={'span'} color={'GrayText'}> {fileType?.name}</Text></Text>
<Text as={'span'} color={'gray.600'} fontSize={'xs'}>File Size: <Text as={'span'} color={'GrayText'}> {bytesToMB(fileType?.size)} Mb</Text></Text>
<Text as={'span'} color={'gray.600'} fontSize={'xs'}>File Type: <Text as={'span'} color={'GrayText'}> {fileType?.type}</Text></Text>
<Box
position={"relative"}
display={"flex"}
alignContent={"flex-end"}
gap={3}
mt={2}
>
<Image
src={filePreview}
alt="File preview"
maxW={"150px"}
borderRadius="md"
boxShadow="md"
/>
<Icon
onClick={() => setFilePreview(null)}
className="link"
rounded={"md"}
color={"red.700"}
cursor={"pointer"}
p={1.5}
position={"absolute"}
top={0}
right={0}
as={DeleteIcon}
boxSize={7}
/>
<VStack justifyItems={"flex-end"} alignItems={"flex-start"}>
<Text as={"span"} color={"gray.600"} fontSize={"xs"}>
File Name:{" "}
<Text as={"span"} color={"GrayText"}>
{" "}
{fileType?.name}
</Text>
</Text>
<Text as={"span"} color={"gray.600"} fontSize={"xs"}>
File Size:{" "}
<Text as={"span"} color={"GrayText"}>
{" "}
{bytesToMB(fileType?.size)} Mb
</Text>
</Text>
<Text as={"span"} color={"gray.600"} fontSize={"xs"}>
File Type:{" "}
<Text as={"span"} color={"GrayText"}>
{" "}
{fileType?.type}
</Text>
</Text>
</VStack>
</Box>
</motion.div>
@@ -274,7 +382,7 @@ const CreateRequest = () => {
</FormControl>
{/* Description Field */}
<FormControl w={"100%"} mb={2} isInvalid={errors.makerComment}>
<FormControl w={"100%"} mb={2} isInvalid={errors.makerComment}>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Description
</FormLabel>
@@ -286,13 +394,26 @@ const CreateRequest = () => {
rounded={"sm"}
placeholder={"Description"}
{...register("makerComment")}
maxLength={200}
/>
<FormHelperText fontSize={'xs'} fontWeight={500} style={{ color: "red" }}>{errors.makerComment?.message}</FormHelperText>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.makerComment?.message}
</FormHelperText>
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>
Maximum length should be 200 characters. You have entered
</Box>
{watch("makerComment")?.length || 0} characters.
</FormHelperText>
</FormControl>
{/* Submit Button */}
<HStack mt={2} w={'100%'} justifyContent={'flex-end'}>
<Button
<HStack mt={2} w={"100%"} justifyContent={"flex-end"}>
<Button
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
@@ -305,7 +426,13 @@ const CreateRequest = () => {
</HStack>
</Box>
<SelectInvestorModal setId={setId} setValue={setValue} onClose={onClose} isOpen={isOpen} onOpen={onOpen}/>
<SelectInvestorModal
setId={setId}
setValue={setValue}
onClose={onClose}
isOpen={isOpen}
onOpen={onOpen}
/>
</Box>
);
};

View File

@@ -138,7 +138,7 @@ import RequestRejectModal from "./RequestRejectModal";
"Deposit Date",
"Deposit Amount (BHD)",
"Support Image",
"Action",
"Action",
];

View File

@@ -56,7 +56,7 @@ const AddCashDetails = ({ isOpen, onClose, firstField, actionId, setActionId, da
const [updateVideoArtifacts] = useUpdateVideoArtifactsMutation()
// const {
// data
// } = useGetArtifactsQuery(id)
// } = useGetArtifactsQuery(id)
const {
control,
@@ -90,12 +90,12 @@ const AddCashDetails = ({ isOpen, onClose, firstField, actionId, setActionId, da
toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />,
});
setAlert(false);
}
} catch (error) {
console.log(error);
setIsLoading(false);
}
};

View File

@@ -8,8 +8,8 @@ import IODetails from "./IODetails";
import KeyMerits from "./KeyMerits";
import IOArtifacts from "./IOArtifacts";
import Investors from "./Investors";
import IOCashDetails from "./IOCashDetails";
import IONAVDetails from "./IONAVDetails";
// import IOCashDetails from "./IOCashDetailsold";
// import IONAVDetails from "./IONAVDetailsOld";
import InvestmentDocument from "./InvestmentDocument"; // Ensure this is the correct import
import ViewIOdataHeader from "../ViewIO/ViewIOdataHeader";
import { useParams } from "react-router-dom";
@@ -17,6 +17,9 @@ import FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders";
import { useGetIOprepopulateDataQuery } from "../../../Services/io.service";
import UnderConstruction from "../../UnderConstruction";
import Destribution from "./Destribution";
import IOCashDetails from "./IOCashDetails/IOCashDetails";
import IONAVDetails from "./IONAVDetails/IONAVDetails";
import IOTransaction from "./IOTransaction/IOTransaction";
const CreateIO = () => {
const id = useParams()?.id;
@@ -75,6 +78,11 @@ const CreateIO = () => {
Content: Destribution,
isDisabled: id ? true : true,
},
{
label: "IO Transaction",
Content: IOTransaction,
isDisabled: id ? true : true,
},
];
const [tabs, setTabs] = useState(initialTabsState);
@@ -114,7 +122,8 @@ const CreateIO = () => {
<Tab
isDisabled={isDisabled}
key={index}
fontSize={"sm"}
fontSize={"xs"}
fontWeight={500}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",

View File

@@ -1,37 +1,49 @@
import React, { useContext, useEffect, useRef, useState } from 'react'
import GlobalStateContext from '../../../Contexts/GlobalStateContext';
import { Box, HStack, Input,Text, Table, Tbody, Th, Tr, Avatar, useDisclosure,Button, Badge } from '@chakra-ui/react';
import { OPACITY_ON_LOAD } from '../../../Layout/animations';
import Pagination from '../../../Components/Pagination';
import NormalTable from '../../../Components/DataTable/NormalTable';
import CustomAlertDialog from '../../../Components/CustomAlertDialog';
import { formatDatee } from '../../../Components/FormField';
import { AddIcon } from '@chakra-ui/icons';
import AddIONav from './AddIONav';
import React, { useContext, useEffect, useRef, useState } from "react";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import {
Box,
HStack,
Input,
Text,
Table,
Tbody,
Th,
Tr,
Avatar,
useDisclosure,
Button,
Badge,
} from "@chakra-ui/react";
import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import Pagination from "../../../Components/Pagination";
import NormalTable from "../../../Components/DataTable/NormalTable";
import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import { formatDatee } from "../../../Components/FormField";
import { AddIcon } from "@chakra-ui/icons";
import AddIONav from "./AddIONav";
const Destribution = () => {
const { navDetails, setNavDetails, IODetails } =
useContext(GlobalStateContext);
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
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 firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
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("");
console.log(IODetails?.ioNAVHistory);
const formatDate = (date) => {
return new Date(date).toLocaleDateString("en-GB", {
day: "2-digit",
month: "2-digit",
year: "numeric",
});
};
console.log(IODetails?.ioNAVHistory);
const formatDate = (date) => {
return new Date(date).toLocaleDateString('en-GB', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
});
};
useEffect(() => {
// Simulate loading
const timer = setTimeout(() => {
@@ -42,32 +54,38 @@ const Destribution = () => {
return () => clearTimeout(timer);
}, []);
// Table setup
const tableHeadRow = [
// "Sr.No",
"Date",
"Amount",
"% of Investment"
];
// Table setup
const tableHeadRow = [
// "Sr.No",
"Date",
"Amount",
"% of Investment",
];
// Table filter
const filteredData = IODetails?.distributionToInvestor?.filter((item) => {
const name = item?.transactionAmount;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches;
}).sort((b, a) => new Date(a.transactionDate) - new Date(b.transactionDate));
// Table filter
const filteredData = IODetails?.distributionToInvestor
?.filter((item) => {
const name = item?.transactionAmount;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches;
})
.sort((b, a) => new Date(a.transactionDate) - new Date(b.transactionDate));
const extractedArray=filteredData?.map((item, index) => ({
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id,
"Sr.No": <Text
justifyContent={"start"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-start web-text-small"
>{item?.id}</Text>,
"Date": (
"Sr.No": (
<Text
justifyContent={"start"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-start web-text-small"
>
{item?.id}
</Text>
),
Date: (
<Text
justifyContent={"center"}
as={"span"}
@@ -78,7 +96,7 @@ const Destribution = () => {
{formatDate(item.transactionDate)}
</Text>
),
"Amount": (
Amount: (
<Text
justifyContent={"center"}
as={"span"}
@@ -86,11 +104,13 @@ const Destribution = () => {
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
<Badge ms={1} colorScheme="green" me={1}>$</Badge>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{`${parseFloat(item.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
</Text>
),
"% of Investment": (
@@ -106,12 +126,8 @@ const Destribution = () => {
),
}));
const handleDelete = () => {
const updatedNav = navDetails.filter(
(sponsor) => sponsor.id !== actionId
);
const updatedNav = navDetails.filter((sponsor) => sponsor.id !== actionId);
setTimeout(() => {
setNavDetails(updatedNav);
@@ -121,12 +137,11 @@ const Destribution = () => {
setIsLoading(true);
};
const Total = () => {
return (
<Table size="sm">
<Tbody>
<Tr backgroundColor="gray.50">
<Tr backgroundColor="gray.50">
<Th
textAlign={"center"}
p={3}
@@ -147,8 +162,13 @@ const Destribution = () => {
wordBreak="normal"
overflowWrap="normal"
>
<Badge ms={1} colorScheme="green" me={1}>$</Badge>{IODetails?.total_distributeToInvestor_amt?.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{IODetails?.total_distributeToInvestor_amt?.toLocaleString(
undefined,
{ minimumFractionDigits: 2, maximumFractionDigits: 2 }
)}
</Th>
<Th
textAlign={"center"}
@@ -167,62 +187,52 @@ const Destribution = () => {
);
};
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</HStack>
</Box>
<NormalTable
centered={true}
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
total={<Total />}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
return (<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</HStack>
<AddIONav isOpen={isOpen} onClose={onClose} firstField={firstField} />
</Box>
);
};
<NormalTable
centered={true}
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
total={<Total/>}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
<AddIONav
isOpen={isOpen}
onClose={onClose}
firstField={firstField} />
</Box>
)
}
export default Destribution
export default Destribution;

View File

@@ -116,7 +116,7 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
setDeleteAlertVideo(false);
setIsLoadingBtn(false);
toast({
render: () => <ToastBox message={res?.data?.message} status="error" />,
render: () => <ToastBox message={res?.data?.message} status="success" />,
});
}
} catch (error) {
@@ -134,7 +134,7 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
setDeleteAlertImage(false);
setIsLoadingBtn(false);
toast({
render: () => <ToastBox message={res?.data?.message} status="error" />,
render: () => <ToastBox message={res?.data?.message} status="success" />,
});
}
@@ -372,7 +372,7 @@ const sortedDataVideo = [...(IObyID?.data?.artifactsVideo || [])]?.sort(
Manage IO Images
</Box>
<HStack>
{IObyID?.data?.artifactsImage?.length !== 0 &&<SetDisplayOrderIOArtifactsImages data={sortedDataImage} />}
<Button

View File

@@ -10,6 +10,7 @@ import {
DrawerOverlay,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
Input,
Stack,
@@ -26,7 +27,8 @@ import { useParams } from "react-router-dom";
import ToastBox from "../../../Components/ToastBox";
const investmentVideoSchema = yup.object().shape({
artifactName: yup.string().required("Artifact name is required"),
artifactName: yup.string().required("Artifact name is required")
.max(50, "Approve Comment cannot be more than 50 characters"),
artifactStreamingURL: yup.string()
.required("Artifact streaming URL is required")
.url("Invalid URL format"),
@@ -152,21 +154,25 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, da
<DrawerBody>
<Stack spacing={4}>
<FormControl isInvalid={errors.artifactName} isRequired={true}>
<FormControl isInvalid={errors.artifactName} isRequired>
<FormLabel fontSize={"sm"}>Artifact Name</FormLabel>
<Controller
name="artifactName"
control={control}
render={({ field }) => (
<Input {...field} fontSize={"sm"} type="text" size={"sm"} />
<Input {...field} fontSize={"sm"} type="text" size={"sm"} maxLength={50} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.artifactName?.message}
</FormErrorMessage>
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 50 characters. You have entered </Box>
{watch("artifactName")?.length || 0} characters.
</FormHelperText>
</FormControl>
<FormControl isInvalid={errors.artifactStreamingURL} isRequired={true}>
<FormControl isInvalid={errors.artifactStreamingURL} isRequired>
<FormLabel fontSize={"sm"}>Artifact Streaming URL</FormLabel>
<Controller
name="artifactStreamingURL"
@@ -211,7 +217,7 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, da
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleSave}
message={"Are you sure you want to add this artifact?"}
message={"Are you sure you want to update this artifact?"}
isLoading={isLoading}
/>
</>

View File

@@ -0,0 +1,263 @@
import {
Box,
Button,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
Input,
Select,
Stack,
Textarea,
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 { useCreateIoCashMutation, useCreateVideoArtifactsMutation, useUpdateVideoArtifactsMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CurrencyInput from "../../../../Components/CurrencyInput";
const cashDetails = yup.object().shape({
transactionDate: yup.string().required("Date is required"),
ioTransType_xid: yup.number().required("Cash transaction is required"),
transactionAmount: yup.number().required("Transaction Amount is required"),
comments: yup.string().notRequired()
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const AddCaseDetails = ({ isOpen, onClose, firstField, actionId, setActionId, data, setActiveTab }) => {
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();
console.log(isOpen);
// ======================[ Cotext Api ]
const { IODetails } = useContext(GlobalStateContext);
const found = data?.find((item) => item?.id === actionId);
const [createArtifactsVideo] = useCreateVideoArtifactsMutation()
const [updateVideoArtifacts] = useUpdateVideoArtifactsMutation()
// const {
// data
// } = useGetArtifactsQuery(id)
const {
control,
handleSubmit,
watch,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(cashDetails),
});
const [createIoCash] = useCreateIoCashMutation()
const onSubmit = async (data) => {
setIsLoading(true)
try {
const res = await createIoCash({ data, id })
if (res?.data) {
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
handleClose()
setActiveTab(1)
}else if(res?.error){
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />,
});
}
} catch (error) {
console.log(error);
setIsLoading(false);
}
};
const handleConfirm = () => {
handleSubmit(onSubmit)();
};
const handleSave = () => {
handleSubmit(onSubmit)();
};
const handleClose = () => {
setAlert(false)
onClose()
reset({
transactionAmount:""
})
}
return (
<>
<Drawer
size={"md"}
isOpen={isOpen}
placement="right"
initialFocusRef={firstField}
onClose={handleClose}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader fontSize={"sm"}>IO Cash Details</DrawerHeader>
<DrawerBody>
<Stack spacing={4}>
<FormControl isInvalid={errors.transactionDate} isRequired>
<FormLabel fontSize={"sm"}>Date Selection</FormLabel>
<Controller
name="transactionDate"
control={control}
render={({ field }) => (
<Input
focusBorderColor="forestGreen.300" {...field} fontSize={"sm"} type="date" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionDate?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.ioTransType_xid} isRequired>
<FormLabel fontSize={"sm"}>Cash transaction</FormLabel>
<Controller
name="ioTransType_xid"
control={control}
render={({ field }) => (
<Select
{...field}
placeholder="Select an option"
fontSize={"sm"}
size={"sm"}
focusBorderColor="forestGreen.300"
>
{IODetails?.ioCashTransaction?.map(({ id, transactionName }) => (
<option key={id} value={id}>
{transactionName}
</option>
))}
</Select>
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.ioTransType_xid?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.transactionAmount} isRequired>
<FormLabel fontSize={"sm"}>Transaction Amount</FormLabel>
<Controller
name="transactionAmount"
control={control}
render={({ field }) => (
<CurrencyInput {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionAmount?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.comments}>
<FormLabel fontSize={"sm"}>Comment</FormLabel>
<Controller
name="comments"
control={control}
render={({ field }) => (
<Textarea {...field} textAlign={'left'}
maxLength={200}
focusBorderColor="forestGreen.300" fontSize={"sm"} type="text" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.comments?.message}
</FormErrorMessage>
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered </Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</Stack>
</DrawerBody>
<DrawerFooter>
<Button
variant="outline"
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
mr={3}
onClick={handleClose}
>
Cancel
</Button>
<Button
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
onClick={() => setAlert(true)}
>
Save
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
<CustomAlertDialog
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleSave}
message={"Are you sure you want to add cash details?"}
isLoading={isLoading}
/>
</>
);
};
export default AddCaseDetails;

View File

@@ -0,0 +1,251 @@
import {
Box,
Button,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
FormControl,
FormErrorMessage,
FormLabel,
Input,
Select,
Stack,
Textarea,
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 { useCreateIoCashMutation, useCreateVideoArtifactsMutation, useUpdateVideoArtifactsMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CurrencyInput from "../../../../Components/CurrencyInput";
const cashDetails = yup.object().shape({
transactionDate: yup.string().required("Date is required"),
ioTransType_xid: yup.number().required("Cash transaction is required"),
transactionAmount: yup.number().required("Transaction Amount is required"),
comments: yup.string().notRequired(),
});
const AddPending = ({ 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();
// ======================[ Cotext Api ]
const { IODetails } = useContext(GlobalStateContext);
const found = data?.find((item) => item?.id === actionId);
const [createArtifactsVideo] = useCreateVideoArtifactsMutation()
const [updateVideoArtifacts] = useUpdateVideoArtifactsMutation()
// const {
// data
// } = useGetArtifactsQuery(id)
const {
control,
handleSubmit,
watch,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(cashDetails),
});
const [createIoCash] = useCreateIoCashMutation()
const onSubmit = async (data) => {
setIsLoading(true)
try {
const res = await createIoCash({ data, id })
if (res?.data?.statusCode === 200) {
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
handleClose()
}else if(res?.error?.status === 400){
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />,
});
}
} catch (error) {
console.log(error);
}
};
const handleConfirm = () => {
handleSubmit(onSubmit)();
};
const handleSave = () => {
handleSubmit(onSubmit)();
};
const handleClose = () => {
setAlert(false)
onClose()
reset({
transactionAmount:""
})
}
return (
<>
<Drawer
size={"md"}
isOpen={isOpen}
placement="right"
initialFocusRef={firstField}
onClose={handleClose}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader fontSize={"sm"}>IO Cash Details</DrawerHeader>
<DrawerBody>
<Stack spacing={4}>
<FormControl isInvalid={errors.transactionDate} isRequired>
<FormLabel fontSize={"sm"}>Date Selection</FormLabel>
<Controller
name="transactionDate"
control={control}
render={({ field }) => (
<Input
focusBorderColor="forestGreen.300" {...field} fontSize={"sm"} type="date" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionDate?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.ioTransType_xid} isRequired>
<FormLabel fontSize={"sm"}>Cash transaction</FormLabel>
<Controller
name="ioTransType_xid"
control={control}
render={({ field }) => (
<Select
{...field}
placeholder="Select an option"
fontSize={"sm"}
size={"sm"}
focusBorderColor="forestGreen.300"
>
{IODetails?.ioCashTransaction?.map(({ id, transactionName }) => (
<option key={id} value={id}>
{transactionName}
</option>
))}
</Select>
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.ioTransType_xid?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.transactionAmount} isRequired>
<FormLabel fontSize={"sm"}>Transaction Amount</FormLabel>
<Controller
name="transactionAmount"
control={control}
render={({ field }) => (
<CurrencyInput {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionAmount?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.comments}>
<FormLabel fontSize={"sm"}>Comments</FormLabel>
<Controller
name="comments"
control={control}
render={({ field }) => (
<Textarea {...field} textAlign={'left'}
focusBorderColor="forestGreen.300" fontSize={"sm"} type="text" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.comments?.message}
</FormErrorMessage>
</FormControl>
</Stack>
</DrawerBody>
<DrawerFooter>
<Button
variant="outline"
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
mr={3}
onClick={handleClose}
>
Cancel
</Button>
<Button
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
onClick={() => setAlert(true)}
>
Save
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
<CustomAlertDialog
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleSave}
message={"Are you sure you want to add cash details?"}
isLoading={isLoading}
/>
</>
);
};
export default AddPending;

View File

@@ -0,0 +1,251 @@
import {
Box,
Button,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
FormControl,
FormErrorMessage,
FormLabel,
Input,
Select,
Stack,
Textarea,
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 { useCreateIoCashMutation, useCreateVideoArtifactsMutation, useUpdateVideoArtifactsMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CurrencyInput from "../../../../Components/CurrencyInput";
const cashDetails = yup.object().shape({
transactionDate: yup.string().required("Date is required"),
ioTransType_xid: yup.number().required("Cash transaction is required"),
transactionAmount: yup.number().required("Transaction Amount is required"),
comments: yup.string().notRequired(),
});
const AddRejected = ({ 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();
// ======================[ Cotext Api ]
const { IODetails } = useContext(GlobalStateContext);
const found = data?.find((item) => item?.id === actionId);
const [createArtifactsVideo] = useCreateVideoArtifactsMutation()
const [updateVideoArtifacts] = useUpdateVideoArtifactsMutation()
// const {
// data
// } = useGetArtifactsQuery(id)
const {
control,
handleSubmit,
watch,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(cashDetails),
});
const [createIoCash] = useCreateIoCashMutation()
const onSubmit = async (data) => {
setIsLoading(true)
try {
const res = await createIoCash({ data, id })
if (res?.data?.statusCode === 200) {
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
handleClose()
}else if(res?.error?.status === 400){
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />,
});
}
} catch (error) {
console.log(error);
}
};
const handleConfirm = () => {
handleSubmit(onSubmit)();
};
const handleSave = () => {
handleSubmit(onSubmit)();
};
const handleClose = () => {
setAlert(false)
onClose()
reset({
transactionAmount:""
})
}
return (
<>
<Drawer
size={"md"}
isOpen={isOpen}
placement="right"
initialFocusRef={firstField}
onClose={handleClose}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader fontSize={"sm"}>IO Cash Details</DrawerHeader>
<DrawerBody>
<Stack spacing={4}>
<FormControl isInvalid={errors.transactionDate} isRequired>
<FormLabel fontSize={"sm"}>Date Selection</FormLabel>
<Controller
name="transactionDate"
control={control}
render={({ field }) => (
<Input
focusBorderColor="forestGreen.300" {...field} fontSize={"sm"} type="date" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionDate?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.ioTransType_xid} isRequired>
<FormLabel fontSize={"sm"}>Cash transaction</FormLabel>
<Controller
name="ioTransType_xid"
control={control}
render={({ field }) => (
<Select
{...field}
placeholder="Select an option"
fontSize={"sm"}
size={"sm"}
focusBorderColor="forestGreen.300"
>
{IODetails?.ioCashTransaction?.map(({ id, transactionName }) => (
<option key={id} value={id}>
{transactionName}
</option>
))}
</Select>
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.ioTransType_xid?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.transactionAmount} isRequired>
<FormLabel fontSize={"sm"}>Transaction Amount</FormLabel>
<Controller
name="transactionAmount"
control={control}
render={({ field }) => (
<CurrencyInput {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionAmount?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.comments}>
<FormLabel fontSize={"sm"}>Comments</FormLabel>
<Controller
name="comments"
control={control}
render={({ field }) => (
<Textarea {...field} textAlign={'left'}
focusBorderColor="forestGreen.300" fontSize={"sm"} type="text" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.comments?.message}
</FormErrorMessage>
</FormControl>
</Stack>
</DrawerBody>
<DrawerFooter>
<Button
variant="outline"
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
mr={3}
onClick={handleClose}
>
Cancel
</Button>
<Button
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
onClick={() => setAlert(true)}
>
Save
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
<CustomAlertDialog
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleSave}
message={"Are you sure you want to add cash details?"}
isLoading={isLoading}
/>
</>
);
};
export default AddRejected;

View File

@@ -0,0 +1,397 @@
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 { AddIcon, DeleteIcon, EditIcon, ViewIcon } from "@chakra-ui/icons";
import { LuFileSpreadsheet } from "react-icons/lu";
import * as XLSX from "xlsx";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import ToastBox from "../../../../Components/ToastBox";
import AddCashDetails from "../AddCashDetails";
import { debounce } from "../../../Admin/Contact";
import AddApproved from "./AddCaseDetails";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import { useParams } from "react-router-dom";
import AddCaseDetails from "./AddCaseDetails";
const formatDate = (date) => new Date(date).toLocaleDateString();
const Approved = () => {
const firstField = useRef();
const params = useParams();
const toast = useToast();
const id = params?.id;
const { isOpen, onOpen, onClose } = useDisclosure();
const { IODetails, approved, setApproved } = 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("");
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("==============", IODetails?.ioCashStatusHistory?.Approved);
// Table filter
const filteredData = IODetails?.ioCashStatusHistory?.Approved?.filter(
(item) => {
// Filter by name (case insensitive)
const name = item.transactionDate;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches;
}
);
const [updateIOCase] = useUpdateIOCaseMutation();
const tableHeadRow = [
"Sr No.",
"Transaction Date",
"Transaction Type",
"Amount",
"Comments",
"Update By",
"Update On",
];
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Text as={"span"} color={"gray.800"} fontWeight={"500"}>
{index + 1}.
</Text>
),
"Transaction Date": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{formatDate(item?.transactionDate)}
</Text>
),
"Transaction Type": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{item?.transactionType}
</Text>
),
Amount: (
<Text as={"span"} color={"gray.800"} fontWeight={"500"}>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
Comments: (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{item?.comments ? item?.comments : "---"}
</Text>
),
"Update By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
display={"flex"}
alignItems={"center"}
>
{/* <Avatar
mr={2}
size="sm"
name={item.creator?.firstName}
src={item.creator?.profilePhoto}
/> */}
{item?.modifier?.firstName}
</Text>
),
"Update On": (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{formatDate(item.updatedAt)}
</Text>
),
}));
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
const ioCashExporteDetails = IODetails?.ioCashStatusHistory?.Approved?.map(
(item, index) => ({
"Transaction date": item?.transactionDate,
"Transaction type": item?.transactionType,
Amount: parseFloat(item?.transactionAmount) || 0,
Comments: item?.comments,
})
);
const exportToExcelNew = (data, fileName) => {
const worksheet = XLSX.utils.json_to_sheet(data);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
// Export file
XLSX.writeFile(workbook, `${fileName}.xlsx`);
};
const Total = () => {
return (
<Table size="sm">
<Tbody backgroundColor="gray.50">
<Tr>
<Th
textAlign={"center"}
p={3}
width="200px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
Balance in IO Cash
</Th>
<Th
textAlign={"center"}
p={3}
width="120px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{" "}
</Th>
<Th
textAlign={"center"}
p={3}
width="120px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{" "}
</Th>
<Th
textAlign={"center"}
p={3}
width="140px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{/* {IODetails?.ioCash} */}
{parseFloat(IODetails?.ioCash || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Th>
<Th
textAlign={"center"}
p={3}
width="120px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{}
</Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{" "}
</Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
></Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
></Th>
</Tr>
</Tbody>
</Table>
);
};
const handleAdd = async () => {
try {
const res = await updateIOCase(id);
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
setIsLoading(false);
onOpen();
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
}
} catch (error) {}
};
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<HStack display={"flex"} alignItems={"center"}>
<Button
onClick={() =>
exportToExcelNew(ioCashExporteDetails, "IO Cash History")
}
leftIcon={<LuFileSpreadsheet />}
colorScheme="forestGreen"
size={"sm"}
variant={"outline"}
rounded={"sm"}
fontSize={"xs"}
isDisabled={ioCashExporteDetails?.length === 0}
>
Export xls
</Button>
{/* <Button
onClick={onOpen}
leftIcon={<AddIcon />}
colorScheme={"forestGreen"}
rounded={"sm"}
fontSize={"xs"}
size={"sm"}
fontWeight={500}
>
Add
</Button> */}
{/* {IODetails?.isInvestedAmount ? (
localStorage?.getItem('role') ==="Maker" && <Button
onClick={handleAdd}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add
</Button>
) : null} */}
</HStack>
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
total={<Total />}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
{/* <CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/> */}
<AddCaseDetails
isOpen={isOpen}
onClose={onClose}
firstField={firstField}
/>
</Box>
);
};
export default Approved;

View File

@@ -0,0 +1,144 @@
import {
Badge,
Box,
Button,
Tab,
TabList,
TabPanel,
TabPanels,
Tabs,
useDisclosure,
useToast,
} from "@chakra-ui/react";
import React, { useContext, useRef, useState } from "react";
import Approved from "./Approved";
import Pending from "./Pending";
import Rejected from "./Rejected";
import { AddIcon } from "@chakra-ui/icons";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import AddCaseDetails from "./AddCaseDetails";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox";
import { useParams } from "react-router-dom";
const IOCashDetails = () => {
const params = useParams();
const toast = useToast();
const id = params?.id;
const { IODetails } = useContext(GlobalStateContext);
const { isOpen, onOpen, onClose } = useDisclosure();
const firstField = useRef();
const [updateIOCase] = useUpdateIOCaseMutation();
const [activeTab, setActiveTab] = useState(0);
const handleAdd = async () => {
try {
const res = await updateIOCase(id);
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={"res?.data?.message"} />
// ),
// });
// setIsLoading(false);
onOpen();
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
}
} catch (error) {}
};
return (
<Box>
<Tabs
index={activeTab}
onChange={(index) => setActiveTab(index)}
variant="unstyled"
>
<Box
display={"flex"}
justifyContent={"space-between"}
alignItems={"center"}
borderBottom={"1px solid #ccc"}
>
<TabList>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Approved
</Tab>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Pending
{IODetails?.ioCashStatusHistory?.Pending.length > 0 && (
<Badge rounded={"sm"} colorScheme="forestGreen" ms={2}>
{IODetails?.ioCashStatusHistory?.Pending.length !== 0 && IODetails?.ioCashStatusHistory?.Pending.length}
</Badge>
)}
{/* <Badge rounded={"sm"} colorScheme="forestGreen" ms={2}>
{IODetails?.ioCashStatusHistory?.Pending.length || 0}
</Badge> */}
</Tab>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Rejected
</Tab>
</TabList>
{IODetails?.isInvestedAmount
? localStorage?.getItem("role") === "Maker" && (
<Button
onClick={handleAdd}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add
</Button>
)
: null}
</Box>
<TabPanels>
<TabPanel>
<Approved />
</TabPanel>
<TabPanel>
<Pending />
</TabPanel>
<TabPanel>
<Rejected />
</TabPanel>
</TabPanels>
</Tabs>
<AddCaseDetails
setActiveTab={setActiveTab}
isOpen={isOpen}
onClose={onClose}
firstField={firstField}
/>
</Box>
);
};
export default IOCashDetails;

View File

@@ -0,0 +1,465 @@
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 {
AddIcon,
CheckIcon,
CloseIcon,
DeleteIcon,
EditIcon,
ViewIcon,
} from "@chakra-ui/icons";
import { LuFileSpreadsheet } from "react-icons/lu";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import ToastBox from "../../../../Components/ToastBox";
import AddCashDetails from "../AddCashDetails";
import { debounce } from "../../../Admin/Contact";
import AddPending from "./AddPending";
import { useParams } from "react-router-dom";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal";
import AddCaseDetails from "./AddCaseDetails";
const formatDate = (date) => new Date(date).toLocaleDateString();
const Pending = () => {
const toast = useToast();
const params = useParams();
const id = params?.id;
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
const { IODetails, approved, setApproved } = 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 [updateIOCase] = useUpdateIOCaseMutation();
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",
});
};
// Table filter
const filteredData = IODetails?.ioCashStatusHistory?.Pending?.filter(
(item) => {
// Filter by name (case insensitive)
const name = item?.transactionDate;
const searchLower = searchTerm?.toLowerCase();
const nameMatches = name?.toLowerCase().includes(searchLower);
return nameMatches;
}
);
const tableHeadRow = [
"Sr No.",
"Transaction Date",
"Transaction Type",
"Amount",
"Comments",
"Update By",
"Update On",
...(localStorage?.getItem('role')!=="Maker" ? ["Actions"] : []),
];
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Text as={"span"} color={"gray.800"} fontWeight={"500"}>
{index + 1}.
</Text>
),
"Transaction Date": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{formatDate(item?.transactionDate)}
</Text>
),
"Transaction Type": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{item?.transactionType}
</Text>
),
Amount: (
<Text as={"span"} color={"gray.800"} fontWeight={"500"}>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
Comments: (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{item?.comments}
</Text>
),
"Update By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
display={"flex"}
alignItems={"center"}
>
{/* <Avatar
mr={2}
size="sm"
name={item?.creator?.firstName}
src={item?.creator?.profilePhoto}
/> */}
{item?.modifier?.firstName}
</Text>
),
"Update On": (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{formatDate(item.updatedAt)}
</Text>
),
Actions: (
<Box display={"flex"} justifyContent={"center"}>
{localStorage?.getItem("role") !== "Maker" ? <Box>
{index===0&&<Box display={"flex"} justifyContent={"center"} gap={2}>
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="Approve"
bg="#fff"
color={"green.500"}
placement="left-start"
>
<Button
// colorScheme="forestGreen"
// color="green.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
py={1}
onClick={() => {
setActionId(item.id);
onConfirmOpen();
}}
colorScheme="green"
variant={"solid"}
cursor={"pointer"}
>
<CheckIcon fontSize={"12px"} />
</Button>
</Tooltip>
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="Reject"
bg="#fff"
color={"red.500"}
placement="left-start"
>
<Button
colorScheme="red"
// color="red.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
onClick={() => {
setActionId(item.id);
onRejectOpen();
}}
py={1}
// variant={"solid"}
>
<CloseIcon fontSize={"10px"} />
</Button>
</Tooltip></Box>}
</Box> : <Button
colorScheme="green"
rounded={"sm"}
size={"xs"}
px={2}
py={1}
fontWeight={500}
onClick={() => {
setActionId(item.id);
}}
>
<ViewIcon me={"4px"} /> View
</Button>}
</Box>
),
}));
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
const ioCashExporteDetails = IODetails?.ioCashStatusHistory?.Approved?.map(
(item, index) => ({
"Transaction date": item?.transactionDate,
"Transaction type": item?.transactionType,
Amount: parseFloat(item?.transactionAmount) || 0,
Comments: item?.comments,
})
);
const Total = () => {
return (
<Table size="sm">
<Tbody backgroundColor="gray.50">
<Tr>
<Th
textAlign={"center"}
p={3}
width="130px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
Balance in IO Cash
</Th>
<Th
textAlign={"center"}
p={3}
width="150px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{" "}
</Th>
<Th
textAlign={"center"}
p={3}
width="150px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{}
</Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(IODetails?.ioCash || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{" "}
</Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
></Th>
<Th
textAlign={"center"}
p={3}
width="80px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
></Th>
<Th
textAlign={"center"}
p={3}
width="50px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
></Th>
</Tr>
</Tbody>
</Table>
);
};
const handleAdd = async () => {
try {
const res = await updateIOCase(id);
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
setIsLoading(false);
onOpen();
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
}
} catch (error) {}
};
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{/* <HStack display={"flex"} alignItems={"center"}>
{IODetails?.isInvestedAmount ? (
localStorage?.getItem('role') ==="Maker"&& <Button
onClick={handleAdd}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add
</Button>
) : null}
</HStack> */}
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
// total={<Total />}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
<AddCaseDetails
isOpen={isOpen}
onClose={onClose}
firstField={firstField}
/>
<RequestApproveModal
// data={data?.data?.rows}
isOpen={isConfirmOpen}
onClose={onConfirmClose}
id={actionId}
// firstField={firstField}
/>
<RequestRejectModal
isOpen={isRejectOpen}
onClose={onRejectClose}
id={actionId}
/>
</Box>
);
};
export default Pending;

View File

@@ -0,0 +1,357 @@
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 { AddIcon} from "@chakra-ui/icons";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import AddCashDetails from "../AddCashDetails";
import AddRejected from "./AddRejected";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import { useParams } from "react-router-dom";
import ToastBox from "../../../../Components/ToastBox";
import AddCaseDetails from "./AddCaseDetails";
const formatDate = (date) => new Date(date).toLocaleDateString();
const Rejected = () => {
const params = useParams()
const id = params?.id
const toast = useToast();
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
const { IODetails, approved, setApproved } =
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 [updateIOCase] = useUpdateIOCaseMutation()
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",
});
};
// Table filter
const filteredData = IODetails?.ioCashStatusHistory?.Reject?.filter((item) => {
// Filter by name (case insensitive)
const name = item.transactionDate;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches;
});
const tableHeadRow = [
"Sr No.",
"Transaction Date",
"Transaction Type",
"Amount",
"Comments",
"Update By",
"Update On",
];
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Text
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{index + 1}.
</Text>
),
"Transaction Date": (
<Text
as={"span"}
color={"gray.600"}
fontWeight={"500"}
>
{formatDate(item?.transactionDate)}
</Text>
),
"Transaction Type": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{item?.transactionType}
</Text>
),
"Amount": (
<Text
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(IODetails?.ioCash || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
"Comments": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{item?.comments}
</Text>
),
"Update By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
display={"flex"}
alignItems={"center"}
>
{/* <Avatar
mr={2}
size="sm"
name={item.creator?.firstName}
src={item.creator?.profilePhoto}
/> */}
{item?.modifier?.firstName}
</Text>
),
"Update On": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{formatDate(item.updatedAt)}
</Text>
),
}));
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
const Total = () => {
return (
<Table size="sm">
<Tbody backgroundColor="gray.50">
<Tr>
<Th
textAlign={"center"}
p={3}
width="130px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
Balance in IO Cash
</Th>
<Th
textAlign={"center"}
p={3}
width="150px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{" "}
</Th>
<Th
textAlign={"center"}
p={3}
width="150px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{}
</Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{"48,000.00"}
</Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
>
{" "}
</Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
></Th>
<Th
textAlign={"center"}
p={3}
width="100px"
color={"#004118"}
whiteSpace="normal"
wordBreak="normal"
overflowWrap="normal"
></Th>
</Tr>
</Tbody>
</Table>
);
};
const handleAdd = async () =>{
try {
const res = await updateIOCase(id)
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
setIsLoading(false);
onOpen()
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
}
} catch (error) {
}
}
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{/* <HStack display={"flex"} alignItems={"center"}>
{IODetails?.isInvestedAmount ? (
localStorage?.getItem('role') ==="Maker"&& <Button
onClick={handleAdd}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add
</Button>
) : null}
</HStack> */}
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
// total={<Total/>}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
<AddCaseDetails
isOpen={isOpen}
onClose={onClose}
firstField={firstField}
/>
</Box>
);
};
export default Rejected;

View File

@@ -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 { useApproveIOCaseMutation } from "../../../../Services/io.service";
export const conformModalSchema = yup.object().shape({
// comments: yup.string().required("Comment is required")
// .max(50, "Investment name cannot be more than 50 characters"),
comments: yup
.string()
.required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const RequestApproveModal = ({ isOpen, onClose, firstField ,id}) => {
const [isBtnLoading , setIsBtnLoading] = useState(false)
const toast = useToast()
const {
register,
reset,
watch,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const [ approveIOCase ] = useApproveIOCaseMutation()
const onSubmit = async(data) => {
console.log(data, "tewxttttt");
setIsBtnLoading(true)
try {
const res = await approveIOCase({data,id})
if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Approve Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your checker comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered </Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default RequestApproveModal;

View File

@@ -0,0 +1,172 @@
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 { useRejectIOCaseMutation } from "../../../../Services/io.service";
export const conformModalSchema = yup.object().shape({
comments: yup.string().required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const RequestRejectModal = ({ isOpen, onClose, firstField ,id}) => {
const [isBtnLoading , setIsBtnLoading] = useState(false)
const toast = useToast()
const {
register,
reset,
watch,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const [ rejectIOCase ] = useRejectIOCaseMutation()
const onSubmit = async(data) => {
console.log(data, "tewxttttt");
setIsBtnLoading(true)
try {
const res = await rejectIOCase({data,id})
if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Reject Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your comments...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered </Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default RequestRejectModal;

View File

@@ -29,7 +29,7 @@ import { exportToExcel, exportToExcelNew } from "../../../Constants/Constants";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
const IOCashDetails = () => {
const IOCashDetailsOld = () => {
const toast = useToast();
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
@@ -75,7 +75,7 @@ const IOCashDetails = () => {
"Update by ",
"Update On",
];
const handleUpdateStatus = debounce((id) => {
setCaseDetails((prevSponser) =>
prevSponser.map((sponsor) =>
@@ -134,9 +134,9 @@ const IOCashDetails = () => {
</Badge>
{/* {parseFloat(item.transactionAmount || 0).toLocaleString()} */}
{`${parseFloat(item.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
</Text>
),
Comments: (
@@ -180,8 +180,6 @@ const IOCashDetails = () => {
),
}));
const customHeaders = [
{ label: "Date", key: "transactionDate" },
{ label: "Transaction type", key: "transactionType" },
@@ -192,12 +190,12 @@ const IOCashDetails = () => {
// Add more headers as needed
];
const ioCashExporteDetails = IODetails?.ioCashHistory?.map((item, index) =>({
"Date": item?.transactionDate,
const ioCashExporteDetails = IODetails?.ioCashHistory?.map((item, index) => ({
Date: item?.transactionDate,
"Transaction type": item?.transactionType,
"Amount":parseFloat(item?.transactionAmount) || 0,
"Comments": item?.comments
}))
Amount: parseFloat(item?.transactionAmount) || 0,
Comments: item?.comments,
}));
console.log(ioCashExporteDetails);
@@ -312,8 +310,7 @@ const IOCashDetails = () => {
onChange={(e) => setSearchTerm(e.target.value)}
/>
<HStack display={"flex"} alignItems={"center"}>
<HStack display={"flex"} alignItems={"center"}>
<Button
onClick={() =>
exportToExcelNew(ioCashExporteDetails, "IO Cash History")
@@ -324,25 +321,24 @@ const IOCashDetails = () => {
variant={"outline"}
rounded={"sm"}
fontSize={"xs"}
isDisabled={ioCashExporteDetails?.length === 0}
>
Export xls
</Button>
{IODetails?.isInvestedAmount ? (
<Button
onClick={onOpen}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add IO Cash
</Button>
) : null}
</HStack>
{IODetails?.isInvestedAmount ? (
<Button
onClick={onOpen}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add IO Cash
</Button>
) : null}
</HStack>
</HStack>
</Box>
@@ -376,4 +372,4 @@ const IOCashDetails = () => {
);
};
export default IOCashDetails;
export default IOCashDetailsOld;

View File

@@ -0,0 +1,266 @@
import {
Box,
Button,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
HStack,
Input,
Select,
Stack,
Text,
Textarea,
VStack,
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";
import { useAddNavDetailsMutation } from "../../../../Services/io.service";
import { formatDatee } from "../../../../Components/FormField";
const ioNav = yup.object().shape({
transactionDate: yup.string().required("Date is required"),
transactionAmount: yup.number().required("New NAV is required"),
comments: yup.string().notRequired()
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const AddNavDetails = ({ 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();
// ======================[ 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 handleConfirm = () => {
handleSubmit(onSubmit)();
};
const handleSave = () => {
handleSubmit(onSubmit)();
};
const handleClose = () => {
setIsLoading(false);
setAlert(false)
onClose()
reset({
transactionDate:"",
transactionAmount:"",
comments:""
})
}
const today = formatDatee(new Date(), 'yyyy-MM-dd');
function calculatePercentage(newNav, currNav) {
const per = (newNav - currNav) / currNav * 100
return per.toFixed(2)
}
console.log(calculatePercentage(1092500, 976070));
return (
<>
<Drawer
size={"md"}
isOpen={isOpen}
placement="right"
initialFocusRef={firstField}
onClose={handleClose}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader fontSize={"sm"}>IO Nav Details</DrawerHeader>
<DrawerBody>
<Stack spacing={4}>
<FormControl isInvalid={errors.transactionDate} isRequired>
<FormLabel fontSize={"sm"}>Date Selection</FormLabel>
<Controller
name="transactionDate"
control={control}
render={({ field }) => (
<Input {...field}
max={today} // Set max attribute to todays date
fontSize={"sm"} type="date" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionDate?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.transactionAmount} isRequired>
<FormLabel fontSize={"sm"}>New NAV</FormLabel>
<Controller
name="transactionAmount"
control={control}
render={({ field }) => (
<CurrencyInput {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionAmount?.message}
</FormErrorMessage>
</FormControl>
<HStack justify={'start'} gap={10} bg={'green.100'} p={3} rounded={'md'} shadow={'md'}>
<VStack align={'start'}>
<Text as={'span'} fontSize={'sm'} fontWeight={500}>Current nav</Text>
<Text as={'span'} fontSize={'sm'}>
{parseFloat(IODetails?.ioNAV || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</VStack>
<VStack align={'start'}>
<Text as={'span'} fontSize={'sm'} fontWeight={500}>Live return %</Text>
<Text as={'span'} fontSize={'sm'}>{calculatePercentage(watch()?.transactionAmount||IODetails?.ioNAV,IODetails?.ioNAV)}</Text>
</VStack>
</HStack>
<FormControl isInvalid={errors.comments}>
<FormLabel fontSize={"sm"}>Comment</FormLabel>
<Controller
name="comments"
control={control}
render={({ field }) => (
<Textarea {...field} maxLength={200} fontSize={"sm"} type="text" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.comments?.message}
</FormErrorMessage>
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered </Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</Stack>
</DrawerBody>
<DrawerFooter>
<Button
variant="outline"
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
mr={3}
onClick={handleClose}
>
Cancel
</Button>
<Button
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
onClick={() => setAlert(true)}
>
Save
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
<CustomAlertDialog
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleSave}
message={"Are you sure you want to add NAV details?"}
isLoading={isLoading}
/>
</>
);
};
export default AddNavDetails;

View File

@@ -0,0 +1,298 @@
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 { AddIcon, DeleteIcon, EditIcon, ViewIcon } from "@chakra-ui/icons";
import { LuFileSpreadsheet } from "react-icons/lu";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import * as XLSX from "xlsx";
import ToastBox from "../../../../Components/ToastBox";
import AddCashDetails from "../AddCashDetails";
import { debounce } from "../../../Admin/Contact";
import { useParams } from "react-router-dom";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import AddApproved from "./AddNavDetails";
import AddNavDetails from "./AddNavDetails";
const formatDate = (date) => new Date(date).toLocaleDateString();
const Approved = () => {
const params = useParams();
const toast = useToast();
const id = params?.id;
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
const { IODetails, iONAVDetail, setIONAVDetail } =
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 [updateIOCase] = useUpdateIOCaseMutation();
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",
});
};
// Table filter
const filteredData = IODetails?.ioNAVStatusHistory?.Approved?.filter(
(item) => {
// Filter by name (case insensitive)
const name = item.transactionAmount;
const searchLower = searchTerm?.toLowerCase();
const nameMatches = name?.toLowerCase().includes(searchLower);
return nameMatches;
}
);
const tableHeadRow = [
"Sr No.",
"Valuation date",
"NAV",
"Last Nav Update",
"Investment Closed",
"Comments",
"Updated By",
];
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Text as={"span"} color={"gray.800"} fontWeight={"500"}>
{index + 1}.
</Text>
),
"Valuation date": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{formatDate(item?.transactionDate)}
</Text>
),
NAV: (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
"Last Nav Update": (
<Text
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.previousNAVvalue && `${item.previousNAVvalue}`}
</Text>
),
"Investment Closed": (
<Text
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item?.initialNAVvalue && `${item?.initialNAVvalue}`}
</Text>
),
Comments: (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{item?.comments ? item?.comments : "---"}
</Text>
),
"Updated By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
display={"flex"}
alignItems={"center"}
>
{/* <Avatar
mr={2}
size="sm"
name={item.creator?.firstName}
src={item.creator?.profilePhoto}
/> */}
{item?.modifier?.firstName}
</Text>
),
}));
const handleAdd = async () => {
try {
const res = await updateIOCase(id);
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
setIsLoading(false);
onOpen();
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
}
} catch (error) {}
};
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
const exportToExcelNew = (data, fileName) => {
const worksheet = XLSX.utils.json_to_sheet(data);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
// Export file
XLSX.writeFile(workbook, `${fileName}.xlsx`);
};
const ioNavExport = IODetails?.ioNAVStatusHistory?.Approved?.map(
(item, index) => ({
ID: item?.id, // Keep as integer if it's already a number
"Valuation date": formatDate(item?.transactionDate), // Assuming this is a date, no conversion needed
NAV: parseFloat(item?.transactionAmount) || 0, // Convert to float
"Last Nav Update": parseFloat(item?.previousNAVvalue) || 0, // Convert to float
"Investment Closed": parseFloat(item?.initialNAVvalue) || 0, // Convert to float
Comments: item?.comments, // Keep as string
// "Transaction Type": item?.transactionType,
"Updated By": item?.creator?.firstName, // Keep as string
// "Update On": formatDate(item?.updatedAt) // Assuming this is a date, no conversion needed
})
);
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<HStack display={"flex"} alignItems={"center"}>
<Button
onClick={() => exportToExcelNew(ioNavExport, "Io Nav details")}
leftIcon={<LuFileSpreadsheet />}
colorScheme="forestGreen"
size={"sm"}
variant={"outline"}
rounded={"sm"}
fontSize={"xs"}
isDisabled={ioNavExport?.length === 0}
>
Export xls
</Button>
{/* {IODetails?.isInvestedAmount
? localStorage?.getItem("role") === "Maker" && (
<Button
onClick={handleAdd}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add
</Button>
)
: null} */}
</HStack>
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
<AddNavDetails
isOpen={isOpen}
onClose={onClose}
firstField={firstField}
/>
</Box>
);
};
export default Approved;

View File

@@ -0,0 +1,190 @@
// import { Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react";
// import React from "react";
// import Approved from "./Approved";
// import Pending from "./Pending";
// import Rejected from "./Rejected";
// const IONAVDetails = () => {
// return (
// <Tabs>
// <TabList>
// <Tab
// fontSize={"sm"}
// _selected={{
// color: "#004118",
// borderBottom: "2px solid #38a169",
// }}
// >
// Approved
// </Tab>
// <Tab
// fontSize={"sm"}
// _selected={{
// color: "#004118",
// borderBottom: "2px solid #38a169",
// }}
// >
// Pending
// </Tab>
// <Tab
// fontSize={"sm"}
// _selected={{
// color: "#004118",
// borderBottom: "2px solid #38a169",
// }}
// >
// Rejected
// </Tab>
// </TabList>
// <TabPanels>
// <TabPanel>
// <Approved />
// </TabPanel>
// <TabPanel>
// <Pending />
// </TabPanel>
// <TabPanel>
// <Rejected />
// </TabPanel>
// </TabPanels>
// </Tabs>
// );
// };
// export default IONAVDetails;
import {
Badge,
Box,
Button,
Tab,
TabList,
TabPanel,
TabPanels,
Tabs,
useDisclosure,
useToast,
} from "@chakra-ui/react";
import React, { useContext, useRef } from "react";
import Approved from "./Approved";
import Pending from "./Pending";
import Rejected from "./Rejected";
import { AddIcon } from "@chakra-ui/icons";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import ToastBox from "../../../../Components/ToastBox";
import { useParams } from "react-router-dom";
import AddNavDetails from "./AddNavDetails";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
const IONAVDetails = () => {
const params = useParams();
const toast = useToast();
const id = params?.id;
const { IODetails } = useContext(GlobalStateContext);
const { isOpen, onOpen, onClose } = useDisclosure();
const firstField = useRef();
const [updateIOCase] = useUpdateIOCaseMutation();
const handleAdd = async () => {
try {
const res = await updateIOCase(id);
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
// setIsLoading(false);
onOpen();
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
}
} catch (error) {}
};
return (
<Box>
<Tabs variant="unstyled">
<Box
display={"flex"}
justifyContent={"space-between"}
alignItems={"center"}
borderBottom={"1px solid #ccc"}
>
<TabList>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Approved
</Tab>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Pending
{IODetails?.ioNAVStatusHistory?.Pending.length > 0 && (
<Badge rounded={"sm"} colorScheme="forestGreen" ms={2}>
{IODetails?.ioNAVStatusHistory?.Pending.length || 0}
</Badge>
)}
</Tab>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Rejected
</Tab>
</TabList>
{IODetails?.isInvestedAmount
? localStorage?.getItem("role") === "Maker" && (
<Button
onClick={handleAdd}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add
</Button>
)
: null}
</Box>
<TabPanels>
<TabPanel>
<Approved />
</TabPanel>
<TabPanel>
<Pending />
</TabPanel>
<TabPanel>
<Rejected />
</TabPanel>
</TabPanels>
</Tabs>
<AddNavDetails
isOpen={isOpen}
onClose={onClose}
firstField={firstField}
/>
</Box>
);
};
export default IONAVDetails;

View File

@@ -0,0 +1,338 @@
import {
Avatar,
Badge,
Box,
Button,
HStack,
Input,
Text,
Tooltip,
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 { AddIcon, CheckIcon, CloseIcon, ViewIcon } from "@chakra-ui/icons";
import { useParams } from "react-router-dom";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox";
import AddNavDetails from "./AddNavDetails";
import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal";
const formatDate = (date) => new Date(date).toLocaleDateString();
const Pending = () => {
const params = useParams();
const toast = useToast();
const id = params?.id;
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
const { IODetails, iONAVDetail, setIONAVDetail } =
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 [updateIOCase] = useUpdateIOCaseMutation();
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",
});
};
// Table filter
const filteredData = IODetails?.ioNAVStatusHistory?.Pending?.filter(
(item) => {
// Filter by name (case insensitive)
const name = item?.transactionDate;
const searchLower = searchTerm?.toLowerCase();
const nameMatches = name?.toLowerCase().includes(searchLower);
return nameMatches;
}
);
const tableHeadRow = [
"Sr No.",
"Valuation date",
"NAV",
"Last Nav Update",
"Investment Closed",
"Comments",
"Updated By",
...(localStorage?.getItem("role") !== "Maker" ? ["Status"] : []),
];
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Text as={"span"} color={"gray.800"} fontWeight={"500"}>
{index + 1}.
</Text>
),
"Valuation date": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{formatDate(item?.transactionDate)}
</Text>
),
NAV: (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
"Last Nav Update": (
<Text
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.previousNAVvalue && `${item.previousNAVvalue}`}
</Text>
),
"Investment Closed": (
<Text
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item?.initialNAVvalue && `${item?.initialNAVvalue}`}
</Text>
),
Comments: (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{item?.comments ? item?.comments : "---"}
</Text>
),
"Updated By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
display={"flex"}
alignItems={"center"}
>
{/* <Avatar
mr={2}
size="sm"
name={item.creator?.firstName}
src={item.creator?.profilePhoto}
/> */}
{item?.modifier?.firstName}
</Text>
),
Status: (
<Box display={"flex"} justifyContent={"center"}>
<Box>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="Approve"
bg="#fff"
color={"green.500"}
placement="left-start"
>
<Button
// colorScheme="forestGreen"
// color="green.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
py={1}
onClick={() => {
setActionId(item.id);
onConfirmOpen();
}}
colorScheme="green"
variant={"solid"}
cursor={"pointer"}
>
<CheckIcon fontSize={"12px"} />
</Button>
</Tooltip>
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="Reject"
bg="#fff"
color={"red.500"}
placement="left-start"
>
<Button
colorScheme="red"
// color="red.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
onClick={() => {
setActionId(item.id);
onRejectOpen();
}}
py={1}
// variant={"solid"}
>
<CloseIcon fontSize={"10px"} />
</Button>
</Tooltip>
</Box>
</Box>
</Box>
),
}));
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
const handleAdd = async () => {
try {
const res = await updateIOCase(id);
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
setIsLoading(false);
onOpen();
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
}
} catch (error) {}
};
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{/* {IODetails?.isInvestedAmount
? localStorage?.getItem("role") === "Maker" && (
<Button
onClick={handleAdd}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add
</Button>
)
: null} */}
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
<AddNavDetails
isOpen={isOpen}
onClose={onClose}
firstField={firstField}
/>
<RequestApproveModal
// data={data?.data?.rows}
isOpen={isConfirmOpen}
onClose={onConfirmClose}
id={actionId}
// firstField={firstField}
/>
<RequestRejectModal
isOpen={isRejectOpen}
onClose={onRejectClose}
id={actionId}
/>
</Box>
);
};
export default Pending;

View File

@@ -0,0 +1,257 @@
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 { AddIcon, DeleteIcon, EditIcon, ViewIcon } from "@chakra-ui/icons";
import { LuFileSpreadsheet } from "react-icons/lu";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import ToastBox from "../../../../Components/ToastBox";
import AddCashDetails from "../AddCashDetails";
import { debounce } from "../../../Admin/Contact";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import { useParams } from "react-router-dom";
import AddNavDetails from "./AddNavDetails";
const formatDate = (date) => new Date(date).toLocaleDateString();
const Rejected = () => {
const params = useParams();
const toast = useToast();
const id = params?.id;
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
const { IODetails, iONAVDetail, setIONAVDetail } =
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 [updateIOCase] = useUpdateIOCaseMutation();
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",
});
};
// Table filter
const filteredData = IODetails?.ioNAVStatusHistory?.Reject?.filter((item) => {
// Filter by name (case insensitive)
const name = item.transactionAmount;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches;
});
const tableHeadRow = [
"Sr No.",
"Valuation date",
"NAV",
"Last Nav Update",
"Investment Closed",
"Comments",
"Updated By",
];
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Text as={"span"} color={"gray.800"} fontWeight={"500"}>
{index + 1}.
</Text>
),
"Valuation date": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{formatDate(item?.transactionDate)}
</Text>
),
NAV: (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
"Last Nav Update": (
<Text
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.previousNAVvalue && `${item.previousNAVvalue}`}
</Text>
),
"Investment Closed": (
<Text
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item?.initialNAVvalue && `${item?.initialNAVvalue}`}
</Text>
),
Comments: (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{item?.comments ? item?.comments : "---"}
</Text>
),
"Updated By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
display={"flex"}
alignItems={"center"}
>
{/* <Avatar
mr={2}
size="sm"
name={item.creator?.firstName}
src={item.creator?.profilePhoto}
/> */}
{item?.modifier?.firstName}
</Text>
),
}));
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
const handleAdd = async () => {
try {
const res = await updateIOCase(id);
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
setIsLoading(false);
onOpen();
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsLoading(false);
}
} catch (error) {}
};
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{/* {IODetails?.isInvestedAmount
? localStorage?.getItem("role") === "Maker" && (
<Button
onClick={handleAdd}
leftIcon={<AddIcon />}
colorScheme="forestGreen"
size={"sm"}
rounded={"sm"}
fontSize={"xs"}
>
Add
</Button>
)
: null} */}
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
<AddNavDetails
isOpen={isOpen}
onClose={onClose}
firstField={firstField}
/>
</Box>
);
};
export default Rejected;

View File

@@ -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 { useApproveIOCaseMutation, useApproveIONavMutation } from "../../../../Services/io.service";
export const conformModalSchema = yup.object().shape({
// comments: yup.string().required("Comment is required")
// .max(50, "Investment name cannot be more than 50 characters"),
comments: yup
.string()
.required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const RequestApproveModal = ({ isOpen, onClose, firstField ,id}) => {
const [isBtnLoading , setIsBtnLoading] = useState(false)
const toast = useToast()
const {
register,
reset,
watch,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const [ approveIONav ] = useApproveIONavMutation()
const onSubmit = async(data) => {
console.log(data, "tewxttttt");
setIsBtnLoading(true)
try {
const res = await approveIONav({data,id})
if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Approve Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your checker comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered</Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default RequestApproveModal;

View File

@@ -0,0 +1,172 @@
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 { useRejectIOCaseMutation } from "../../../../Services/io.service";
export const conformModalSchema = yup.object().shape({
comments: yup.string().required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const RequestRejectModal = ({ isOpen, onClose, firstField ,id}) => {
const [isBtnLoading , setIsBtnLoading] = useState(false)
const toast = useToast()
const {
register,
reset,
watch,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const [ rejectIOCase ] = useRejectIOCaseMutation()
const onSubmit = async(data) => {
console.log(data, "tewxttttt");
setIsBtnLoading(true)
try {
const res = await rejectIOCase({data,id})
if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Reject Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your comments...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered </Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default RequestRejectModal;

View File

@@ -0,0 +1,179 @@
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({
// comments: yup.string().required("Comment is required")
// .max(50, "Investment name cannot be more than 50 characters"),
comments: yup
.string()
.required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const ApproveDistrubationModal = ({ isOpen, onClose, firstField ,id, onBigModalClose}) => {
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: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
onBigModalClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Approve Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your checker comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}> Maximum length should be 200 characters. You have entered</Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"xs"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"xs"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default ApproveDistrubationModal;

View File

@@ -0,0 +1,177 @@
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({
// comments: yup.string().required("Comment is required")
// .max(50, "Investment name cannot be more than 50 characters"),
comments: yup
.string()
.required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const ApproveInvestedModal = ({ isOpen, onClose, firstField ,id,onBigModalClose}) => {
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: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
onBigModalClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Approve Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your checker comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered</Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"xs"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"xs"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default ApproveInvestedModal;

View File

@@ -0,0 +1,249 @@
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 { AddIcon, DeleteIcon, EditIcon, ViewIcon } from "@chakra-ui/icons";
import { LuFileSpreadsheet } from "react-icons/lu";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import ToastBox from "../../../../Components/ToastBox";
import AddCashDetails from "../AddCashDetails";
import { debounce } from "../../../Admin/Contact";
const formatDate = (date) => new Date(date).toLocaleDateString();
const Approved = () => {
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("");
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",
});
};
// Table filter
const filteredData = IODetails?.ioTransactionRecords?.Approved?.filter((item) => {
// Filter by name (case insensitive)
const name = item?.transactionAmount;
const searchLower = searchTerm?.toLowerCase();
const nameMatches = name?.toLowerCase().includes(searchLower);
return nameMatches;
});
const tableHeadRow = [
"Sr No.",
"Transaction Date",
"Transaction Name",
"Amount",
"Created By",
"Created On",
"Approved By",
"Approved On",
];
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Text
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{index + 1}.
</Text>
),
"Transaction Date": (
<Text
as={"span"}
color={"gray.600"}
fontWeight={"500"}
>
{formatDate(item?.transactionDate)}
</Text>
),
"Transaction Name": (
<Text
as={"span"}
color={"gray.600"}
fontWeight={"500"}
>
{item?.transactionType}
</Text>
),
"Amount": (
<Text
as={"span"}
color={"gray.600"}
fontWeight={"500"}
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{/* {item?.transactionAmount} */}
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
"Created By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
textTransform={'capitalize'}
>
{item?.creator?.firstName}
</Text>
),
"Created On": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{formatDate(item?.createdAt)}
</Text>
),
"Approved By": (
<>
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
textTransform={'capitalize'}
>
{item?.modifier?.firstName}
</Text>
{/* <Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
display={"flex"}
alignItems={"center"}
>
<Avatar
mr={2}
size="sm"
name={item.creator?.firstName}
src={item.creator?.profilePhoto}
/>
{item?.creator?.firstName}
</Text> */}
</>
),
"Approved On": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{item?.modifier ? formatDate(item?.updatedAt) : "---" }
{}
</Text>
),
}));
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
</Box>
);
};
export default Approved;

View File

@@ -0,0 +1,161 @@
import {
Box,
Button,
FormControl,
FormHelperText,
FormLabel,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
Textarea,
useToast,
} from "@chakra-ui/react";
import React, { useEffect, useState } from "react";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
import ToastBox from "../../../../Components/ToastBox";
import {useApproveCancleTransactionMutation, useApproveExitTransactionMutation} from "../../../../Services/io.service";
const ApprovedCancelTransaction = ({ isOpen, onClose, firstField ,id,onBigModalClose}) => {
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: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
onBigModalClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Approve Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your checker comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered</Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"xs"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"xs"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default ApprovedCancelTransaction;

View File

@@ -0,0 +1,175 @@
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({
comments: yup
.string()
.required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const ApprovedExit = ({ isOpen, onClose, firstField ,id,onBigModalClose}) => {
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: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
onBigModalClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Approve Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your checker comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered</Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"xs"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"xs"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default ApprovedExit;

View File

@@ -0,0 +1,68 @@
import {
Badge,
Tab,
TabList,
TabPanel,
TabPanels,
Tabs,
} from "@chakra-ui/react";
import React, { useContext } from "react";
import Approved from "./Approved";
import Pending from "./Pending";
import Rejected from "./Rejected";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
const IOTransaction = () => {
const { IODetails } = useContext(GlobalStateContext);
return (
<Tabs>
<TabList>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Approved
</Tab>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Pending
{IODetails?.ioTransactionRecords?.Pending.length > 0 && (
<Badge rounded={"sm"} colorScheme="forestGreen" ms={2}>
{IODetails?.ioTransactionRecords?.Pending.length || 0}
</Badge>
)}
</Tab>
<Tab
fontSize={"sm"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
>
Rejected
</Tab>
</TabList>
<TabPanels>
<TabPanel>
<Approved />
</TabPanel>
<TabPanel>
<Pending />
</TabPanel>
<TabPanel>
<Rejected />
</TabPanel>
</TabPanels>
</Tabs>
);
};
export default IOTransaction;

View File

@@ -0,0 +1,295 @@
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, ViewIcon } from "@chakra-ui/icons";
import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal";
import ViewAmountInvested from "./ViewAmountInvested";
import ViewDistributionInvestor from "./ViewDistributionInvestor";
import ViewExit from "./ViewExit";
import ViewCancel from "./ViewCancel";
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 Date",
"Transaction Name",
"Amount",
"Created By",
"Created On",
"Approved By",
"Approved On",
"Actions",
];
const extractedArray = IODetails?.ioTransactionRecords?.Pending?.map(
(item, index) => ({
id: item?.id,
"Sr No.": (
<Text as={"span"} color={"gray.800"} fontWeight={"500"}>
{index + 1}.
</Text>
),
"Transaction Date": (
<Text
as={"span"}
color={"gray.600"}
fontWeight={"500"}
>
{formatDate(item?.transactionDate)}
</Text>
),
"Transaction Name": (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
{item?.transactionType}
</Text>
),
Amount: (
<Text as={"span"} color={"gray.600"} fontWeight={"500"}>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
"Created By": (
<Text
textTransform={'capitalize'} w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{item?.creator?.firstName}
</Text>
),
"Created On": (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{formatDate(item?.createdAt)}
</Text>
),
"Approved By": (
<Text
textTransform={'capitalize'} w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{item?.modifier?.firstName}
</Text>
),
"Approved On": (
<Text w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}>
{item?.modifier ? formatDate(item?.updatedAt) : "---"}
</Text>
),
Actions: (
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
colorScheme="forestGreen"
rounded={"sm"}
size={"xs"}
px={2}
py={1}
fontWeight={500}
onClick={() => {
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();
}
}}
>
{localStorage?.getItem("role") === "Maker" ? <ViewIcon me={"4px"} /> : null} {localStorage?.getItem("role") === "Maker" ? "View" : "Approve / Reject"}
</Button>
</Box>
),
})
);
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
<ViewAmountInvested
isOpen={isInvestmentOpen}
onClose={onInvestmentClose}
id={actionId}
/>
<ViewDistributionInvestor
isOpen={isDistInvestorOpen}
onClose={onDistInvestorClose}
id={actionId}
/>
<ViewExit
isOpen={isExitOpen}
onClose={onExitClose}
id={actionId}
/>
<ViewCancel
isOpen={isCancelOpen}
onClose={onCancelClose}
id={actionId}
/>
<RequestApproveModal
// data={data?.data?.rows}
isOpen={isConfirmOpen}
onClose={onConfirmClose}
id={actionId}
// firstField={firstField}
/>
<RequestRejectModal
isOpen={isRejectOpen}
onClose={onRejectClose}
id={actionId}
/>
</Box>
);
};
export default Pending;

View File

@@ -0,0 +1,219 @@
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 { AddIcon, DeleteIcon, EditIcon, ViewIcon } from "@chakra-ui/icons";
import { LuFileSpreadsheet } from "react-icons/lu";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import ToastBox from "../../../../Components/ToastBox";
import AddCashDetails from "../AddCashDetails";
import { debounce } from "../../../Admin/Contact";
const formatDate = (date) => new Date(date).toLocaleDateString();
const Rejected = () => {
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("");
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",
});
};
// Table filter
// const filteredData = IODetails?.ioTransactionRecords?.Reject?.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",
];
const extractedArray = IODetails?.ioTransactionRecords?.Reject?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Text
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{index + 1}.
</Text>
),
"Transaction Name": (
<Text
as={"span"}
color={"gray.600"}
fontWeight={"500"}
>
{item?.transactionType}
</Text>
),
"Amount": (
<Text
as={"span"}
color={"gray.600"}
fontWeight={"500"}
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
),
"Created By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
textTransform={'capitalize'}
>
{item?.creator?.firstName}
</Text>
),
"Created On": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{formatDate(item?.createdAt)}
</Text>
),
"Approved By": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
textTransform={'capitalize'}
>
{item?.modifier?.firstName}
</Text>
),
"Approved On": (
<Text
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{formatDate(item?.updatedAt)}
</Text>
),
}));
const handleDelete = () => {
const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => {
setCaseDetails(updatedSponsors);
setDeleteAlert(false);
setIsLoading(false);
}, 100);
setIsLoading(true);
};
return (
<Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
pb={3}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
focusBorderColor="green.500"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</HStack>
</Box>
<NormalTable
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
setMouseEnteredId={setMouseEnteredId}
setMouseEntered={setMouseEntered}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>
</Box>
);
};
export default Rejected;

View File

@@ -0,0 +1,175 @@
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 { useApproveDistributionMutation, useApproveIOCaseMutation, useApproveIONavMutation } from "../../../../Services/io.service";
export const conformModalSchema = yup.object().shape({
// comments: yup.string().required("Comment is required")
// .max(50, "Investment name cannot be more than 50 characters"),
comments: yup
.string()
.required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const RequestApproveModal = ({ isOpen, onClose, firstField ,id}) => {
const [isBtnLoading , setIsBtnLoading] = useState(false)
const toast = useToast()
const {
register,
reset,
watch,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const [ approveDistribution ] = useApproveDistributionMutation()
const onSubmit = async(data) => {
setIsBtnLoading(true)
try {
const res = await approveDistribution({data,id})
if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Approve Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your checker comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered</Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default RequestApproveModal;

View File

@@ -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 { useApproveDistributionMutation, useApproveExitMutation, useApproveIOCaseMutation, useApproveIONavMutation } from "../../../../Services/io.service";
export const conformModalSchema = yup.object().shape({
// comments: yup.string().required("Comment is required")
// .max(50, "Investment name cannot be more than 50 characters"),
comments: yup
.string()
.required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const RequestApproveModal = ({ isOpen, onClose, firstField ,id}) => {
const [isBtnLoading , setIsBtnLoading] = useState(false)
const toast = useToast()
const {
register,
reset,
watch,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const [ approveExit ] = useApproveExitMutation()
const onSubmit = async(data) => {
setIsBtnLoading(true)
try {
const res = await approveExit({data,id})
if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
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 (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Approve Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your checker comment...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered</Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default RequestApproveModal;

View File

@@ -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 { useRejectIOCaseMutation } from "../../../../Services/io.service";
export const conformModalSchema = yup.object().shape({
comments: yup.string().required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const RequestRejectModal = ({ isOpen, onClose, firstField ,id, onBigModalClose}) => {
const [isBtnLoading , setIsBtnLoading] = useState(false)
const toast = useToast()
const {
register,
reset,
watch,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
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})
if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
setIsBtnLoading(false)
}else if(res?.data){
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
onClose()
onBigModalClose()
setIsBtnLoading(false)
}else{
toast({
render: () => (
<ToastBox status={'error'} message={"Something went wrong"} />
),
});
setIsBtnLoading(false)
}
} catch (error) {
}
};
// useEffect(() => {
// if (data) {
// reset({
// investorAmount: data?.data?.investorAmount,
// });
// }
// }, [data, reset]);
const heandleOnClose = () =>{
reset()
onClose()
}
return (
<Modal isCentered isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Reject Comment</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your comments...."}
rounded={"md"}
resize={"none"}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 200 characters. You have entered</Box>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"xs"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"xs"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default RequestRejectModal;

View File

@@ -0,0 +1,293 @@
import React, { useContext, useEffect, useState } from "react";
import {
Box,
Button,
FormControl,
FormLabel,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
useDisclosure,
useToast,
} from "@chakra-ui/react";
import { Controller, useForm } from "react-hook-form";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { useParams } from "react-router-dom";
import { useAmountIvestmentMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox";
import CurrencyInput from "../../../../Components/CurrencyInput";
import RequestRejectModal from "./RequestRejectModal";
import ApproveInvestedModal from "./ApproveInvestedModal";
import { formatDate } from "../../../Master/Sponser/Sponsers";
// Validation schema
const validationSchema = yup.object().shape({
transactionDate: yup.date().required("Date is required"),
Total_Amount: yup.number().required("Amount is required"),
amountInvested: yup.number().required("Amount to invest is required"),
IoCash: yup
.number()
.positive("IO Cash must be positive")
.required("IO Cash is required"),
});
// Function to format currency
const formatCurrency = (value) => {
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: () => <ToastBox message={res?.data?.message} />,
});
setIsLoading(false);
onClose();
} else if (res?.error?.status === 400) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
});
setIsLoading(false);
}
} catch (error) {
setIsLoading(false);
}
};
// const formatDate = (date) => new Date(date).toLocaleDateString();
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,
});
};
console.log(
"=========hitttt",
IODetails?.ioTransactionRecords?.Pending?.[0]?.createdAt
);
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader fontSize={"md"}>Amount Invested</ModalHeader>
<ModalCloseButton />
<ModalBody>
<form onSubmit={handleSubmit(onSubmit)}>
<FormControl
mb={"15px"}
isInvalid={!!errors.transactionDate}
isRequired
>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
Date
</FormLabel>
<Input
type="text"
value={formatDate(
IODetails?.ioTransactionRecords?.Pending?.[0]?.createdAt
)}
// value={IODetails?.ioTransactionRecords?.Pending?.[0]?.createdAt}
size="sm"
rounded={"sm"}
textAlign={"end"}
focusBorderColor="forestGreen.300"
fontSize={"sm"}
readOnly
/>
{/* <Text>
{IODetails?.ioTransactionRecords?.Approved?.[0]?.createdAt} dccd
</Text> */}
</FormControl>
<FormControl
mb={"15px"}
isInvalid={!!errors.Total_Amount}
isReadOnly
>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
Amount
</FormLabel>
<Input
type="text"
value={formatCurrency(watch("Total_Amount") || 0)}
size="sm"
rounded={"sm"}
textAlign={"end"}
focusBorderColor="forestGreen.300"
fontSize={"sm"}
readOnly
/>
</FormControl>
<FormControl
mb={"15px"}
isInvalid={!!errors.amountInvested}
isRequired
>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
Amount to invest
</FormLabel>
<Input
type="text"
value={formatCurrency(
IODetails?.ioTransactionRecords?.Pending?.[0]
?.transactionAmount || 0
)}
size="sm"
rounded={"sm"}
textAlign={"end"}
focusBorderColor="forestGreen.300"
fontSize={"sm"}
readOnly
/>
</FormControl>
<FormControl mb={"15px"} isInvalid={!!errors.IoCash}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
IO Cash
</FormLabel>
<Input
type="text"
value={formatCurrency(
(watch("Total_Amount") || 0) -
(IODetails?.ioTransactionRecords?.Pending?.[0]
?.transactionAmount || 0)
)}
size="sm"
rounded={"sm"}
focusBorderColor="forestGreen.300"
fontSize={"sm"}
textAlign={"right"}
readOnly
/>
</FormControl>
{localStorage?.getItem("role") !== "Maker" && <ModalFooter>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={3}
py={2}
onClick={() => {
setActionId(id); // Use the `id` variable from params
onConfirmOpen();
}}
colorScheme="forestGreen"
variant={"solid"}
cursor={"pointer"}
>
Approve
</Button>
<Button
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={3}
py={2}
onClick={() => {
setActionId(id); // Use the `id` variable from params
onRejectOpen();
}}
>
Reject
</Button>
</Box>
</ModalFooter>}
</form>
</ModalBody>
</ModalContent>
<ApproveInvestedModal
isOpen={isConfirmOpen}
onClose={onConfirmClose}
onBigModalClose={onClose}
id={investorId}
/>
<RequestRejectModal
isOpen={isRejectOpen}
onClose={onRejectClose}
onBigModalClose={onClose}
id={investorId}
/>
</Modal>
);
};
export default ViewAmountInvested;

View File

@@ -0,0 +1,367 @@
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");
if (id && IODetails) {
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": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item?.clientReference_id}
</Text>
),
"First name": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.firstName}
</Text>
),
"Last name": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.lastName}
</Text>
),
"Investment amount": (
<Text
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{/* {`$${formatCurrency(item.InvestedAmount_USD)}`} */}
{`${parseFloat(item.InvestedAmount_USD || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
</Text>
),
Percentage: (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.Investor_Holidings} %
</Text>
),
"Market Value": (
<Text
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{`${parseFloat(item.Market_Value || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
</Text>
),
"Return on Investment": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
h={6}
className="d-flex align-items-center web-text-small"
>
{item.Return_On_Investment || 0} %
</Text>
),
Distribution: (
<Text
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{/* {`$${item.Distribution_Amt}`} */}
{`${parseFloat(item.Distribution_Amt || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
</Text>
),
"Distribution Percent": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{/* {`$${item.Distribution_Amt}`} */}
{`${parseFloat(item.Distribution_Per || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})} %`}
</Text>
),
"Total Return": (
<Text
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
<Badge ms={1} colorScheme="green" me={1}>
$
</Badge>
{/* {`$${formatCurrency(item.Total_Return) || 0}`} */}
{`${parseFloat(item.Total_Return || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}`}
</Text>
),
"Total return on Investment": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.Total_Return_On_Investment || 0} %
</Text>
),
}));
const handleClose = () => {
onClose();
setIsFinalCalculateLoading(false);
setIsCalcualtedData(false);
};
return (
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose} >
<ModalOverlay />
<ModalContent maxW={1000}>
<ModalHeader fontSize={"md"}>Cancel Transaction</ModalHeader>
<ModalCloseButton />
<ModalBody>
<NormalData
emptyMessage={`We don't have any Sponers `}
tableHeadRow={tableHeadRow}
data={extractedArray}
/>
</ModalBody>
{localStorage?.getItem("role") !== "Maker" && <ModalFooter pt={0}>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={3}
py={2}
onClick={() => {
setActionId(id); // Use the `id` variable from params
onConfirmOpen();
}}
colorScheme="forestGreen"
variant={"solid"}
cursor={"pointer"}
>
Approve
</Button>
<Button
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={3}
py={2}
onClick={() => {
setActionId(id); // Use the `id` variable from params
onRejectOpen();
}}
>
Reject
</Button>
</Box>
</ModalFooter>}
</ModalContent>
<ApprovedCancelTransaction
isOpen={isConfirmOpen}
onClose={onConfirmClose}
onBigModalClose={onClose}
id={cancleId}
/>
<RequestRejectModal
isOpen={isRejectOpen}
onClose={onRejectClose}
onBigModalClose={onClose}
id={cancleId}
/>
</Modal>
);
};
export default ViewCancel;

View File

@@ -0,0 +1,273 @@
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,
// });
if (id && IODetails) {
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(false);
}
} 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.": (
<Box
w={9}
display={"flex"}
alignItems={"center"}
isTruncated={true}
h={25}
>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{index + 1}
</Text>
</Box>
),
"Client Id": (
<Box w={90} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.clientId}
</Text>
</Box>
),
"First name": (
<Box w={90} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.firstName}
</Text>
</Box>
),
"Last Name": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.lastName}
</Text>
</Box>
),
Amount: (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.amount?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</Box>
),
"Holding (%)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.investor_holidings?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
%
</Text>
</Box>
),
"Distriution Amt($)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.distribution_amt?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</Box>
),
"Yeild (%)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.distribution_per?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
%
</Text>
</Box>
),
}));
const handleClose = () => {
onClose();
setIsFinalCalculateLoading(false);
setIsCalcualtedData(false);
};
return (
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose}>
<ModalOverlay />
<ModalContent maxW={1000}>
<ModalHeader fontSize={"md"}>
Distribution To Investor Transaction
</ModalHeader>
<ModalCloseButton />
<ModalBody>
<NormalData
emptyMessage={`We don't have any Sponers `}
tableHeadRow={tableHeadRow}
data={extractedArray}
/>
</ModalBody>
{/* ...(localStorage?.getItem("role") !== "Maker" ? ["Status"] : []), */}
{localStorage?.getItem("role") !== "Maker" &&<ModalFooter pt={0}>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={3}
py={2}
onClick={() => {
setActionId(id); // Use the `id` variable from params
onConfirmOpen();
}}
colorScheme="forestGreen"
variant={"solid"}
cursor={"pointer"}
>
Approve
</Button>
<Button
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={3}
py={2}
onClick={() => {
setActionId(id); // Use the `id` variable from params
onRejectOpen();
}}
>
Reject
</Button>
</Box>
</ModalFooter>}
</ModalContent>
<ApproveDistrubationModal
isOpen={isConfirmOpen}
onClose={onConfirmClose}
onBigModalClose={handleClose}
id={exitId}
/>
<RequestRejectModal
isOpen={isRejectOpen}
onClose={onRejectClose}
onBigModalClose={handleClose}
id={exitId}
/>
</Modal>
);
};
export default ViewDistributionInvestor;

View File

@@ -0,0 +1,329 @@
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");
if (id && IODetails) {
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.": (
<Box
w={9}
display={"flex"}
alignItems={"center"}
isTruncated={true}
h={25}
>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{index + 1}
</Text>
</Box>
),
"Client Id": (
<Box w={100} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.clientId}
</Text>
</Box>
),
"First name": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.firstName}
</Text>
</Box>
),
"Last Name": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.lastName}
</Text>
</Box>
),
Amount: (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.amount?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</Box>
),
"Holding (%)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.investor_holidings?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}%
</Text>
</Box>
),
"Exit Amt($)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.distribution_amt?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</Box>
),
}));
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: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
});
setIsCalculateLoading(false);
setIsCalcualtedData(false);
} else if (res?.data?.statusCode === 200) {
setCalculatedDate(res?.data?.data);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
setIsCalculateLoading(false);
setIsCalcualtedData(true);
}
} catch (error) {}
};
const handleClose = () => {
onClose();
setIsFinalCalculateLoading(false);
setIsCalcualtedData(false);
};
console.log(id);
return (
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose} >
<ModalOverlay />
<ModalContent maxW={1000}>
<ModalHeader fontSize={"md"}>Exit Transaction</ModalHeader>
<ModalCloseButton />
<ModalBody>
{/* <Text as="label" mb="5px" fontSize="sm" fontWeight={500}>
Amount to Distribute
</Text> */}
<HStack onSubmit={handleSubmit(onSubmit)} as={"form"} mb={4} alignItems={'center'}>
{/* <Input placeholder="$00.00" size={"sm"} className="col" /> */}
{/* <FormControl isInvalid={errors.amount} isRequired>*/}
<Text textAlign={"right"} fontSize={"sm"}>
Exit Amount :
</Text>
<Text
textAlign={"start"}
bg={"green.100"}
p={2}
rounded={"md"}
fontSize={"sm"}
pt={1}
pb={1}
fontWeight={600}
>
${" "}
{parseFloat(IODetails?.ioMVNAV || 0).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
{/* </FormControl> */}
</HStack>
{/* {calcualtedData && ( */}
<NormalData
emptyMessage={`We don't have any Sponers `}
tableHeadRow={tableHeadRow}
data={extractedArray}
// total={<Total />}
// isLoading={isLoading}
/>
{/* ) } */}
</ModalBody>
{localStorage?.getItem("role") !== "Maker" && <ModalFooter pt={0}>
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Button
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={3}
py={2}
onClick={() => {
setActionId(id); // Use the `id` variable from params
onConfirmOpen();
}}
colorScheme="forestGreen"
variant={"solid"}
cursor={"pointer"}
>
Approve
</Button>
<Button
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={3}
py={2}
onClick={() => {
setActionId(id); // Use the `id` variable from params
onRejectOpen();
}}
>
Reject
</Button>
</Box>
</ModalFooter>}
</ModalContent>
<ApprovedExit
isOpen={isConfirmOpen}
onClose={onConfirmClose}
onBigModalClose={onClose}
id={investerId}
/>
<RequestRejectModal
isOpen={isRejectOpen}
onClose={onRejectClose}
onBigModalClose={onClose}
id={investerId}
/>
</Modal>
);
};
export default ViewExit;

View File

@@ -363,7 +363,7 @@ const InvestmentDocument = ({ control, errors, enableNextTab, index, }) => {
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message="Are you sure you want to delete the sponsor?"
message="Are you sure you want to delete the Investment?"
alertHandler={handleDelete}
isLoading={isLoading}
/>

View File

@@ -100,19 +100,19 @@ const Investors = ({ data }) => {
0
);
// Table setup
// Table setup
const tableHeadRow = [
"Client ID",
"First name",
"Last name",
"Investment amount",
"First Name",
"Last Name",
"Investment Amount",
"Percentage",
"Market Value",
"Return on Investment",
"Distribution",
"Distribution Percent",
"Total Return",
"Total return on Investment",
"Total Return on Investment",
];
const handleUpdateStatus = debounce((id) => {
@@ -164,7 +164,7 @@ const Investors = ({ data }) => {
"Distribution": parseFloat(item?.Distribution_Amt) || 0, // Convert to float
"Distribution Percent": parseFloat(item?.Distribution_Per) || 0, // Convert to float
"Total Return": parseFloat(item?.Total_Return) || 0, // Convert to float
"Total return on Investment": parseFloat(item?.Total_Return_On_Investment) || 0, // Convert to float
"Total Return on Investment": parseFloat(item?.Total_Return_On_Investment) || 0, // Convert to float
}));
console.log(exportInvestorDetails);
@@ -182,7 +182,7 @@ const Investors = ({ data }) => {
{item?.clientReference_id}
</Text>
),
"First name": (
"First Name": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
@@ -193,7 +193,7 @@ const Investors = ({ data }) => {
{item.firstName}
</Text>
),
"Last name": (
"Last Name": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
@@ -204,7 +204,7 @@ const Investors = ({ data }) => {
{item.lastName}
</Text>
),
"Investment amount": (
"Investment Amount": (
<Text
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
@@ -313,7 +313,7 @@ const Investors = ({ data }) => {
})}`}
</Text>
),
"Total return on Investment": (
"Total Return on Investment": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
@@ -508,7 +508,7 @@ console.log(IODetails?.investors);
>
Export xls
</Button>
<Box as="span">
{/* <Box as="span">
<Icon
ms={0}
animation={
@@ -524,7 +524,7 @@ console.log(IODetails?.investors);
_hover={{ bg: "gray.100" }}
cursor={"pointer"}
/>
</Box>
</Box> */}
</Box>
<HStack

View File

@@ -89,7 +89,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
const res = await deleteKeyMerits(actionId);
if (res?.data?.statusCode === 200) {
toast({
render: () => <ToastBox message={res?.data?.message} />,
render: () => <ToastBox message={res?.data?.message} status={"success"} />,
});
setIsBtnLoading(false);
setDeleteAlert(false);

View File

@@ -297,7 +297,7 @@ const InvestmentEdit = ({ isOpen, onClose, thirdField, id, data }) => {
onClose={() => setAlert(false)}
alertHandler={handleConfirm}
isLoading={isLoading}
message="Are you sure you want to add this document?"
message="Are you sure you want to add this Investment?"
/>
</Drawer>
);

View File

@@ -10,6 +10,7 @@ import {
DrawerOverlay,
FormControl,
FormErrorMessage,
FormHelperText,
FormLabel,
Icon,
Image,
@@ -35,7 +36,7 @@ import { IoMdRemoveCircleOutline } from "react-icons/io";
const investmentImageSchema = yup.object().shape({
artifactName: yup.string().required("Artifact image name is required")
.max(25, "File name must be at most 25 characters"),
.max(50, "Approve Comment cannot be more than 50 characters"),
artifactPathName: yup.mixed().required("Artifact image is required"),
});
@@ -226,19 +227,24 @@ const IOArtifactsAdd = ({
<Controller
name="artifactName"
control={control}
// maxLength={50}
render={({ field }) => (
<Input
{...field}
fontSize={"sm"}
type="text"
size={"sm"}
maxLength={25}
maxLength={50}
/>
)}
/>
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.artifactName?.message}
</FormErrorMessage>
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 50 characters. You have entered </Box>
{watch("artifactName")?.length || 0} characters.
</FormHelperText>
</FormControl>
<FormControl
@@ -354,7 +360,7 @@ const IOArtifactsAdd = ({
isOpen={alert}
onClose={handleAlertClose}
alertHandler={handleSave}
message={"Are you sure you want to add this artifact?"}
message={"Are you sure you want to update this artifact?"}
isLoading={loading}
/>
</>

View File

@@ -60,7 +60,7 @@ export const investmentDocSchema = yup.object().shape({
// return value && value.size <= 2 * 1024 * 1024; // 2MB in bytes
// })
fileName: yup.string().required("File name is required")
.max(25, "File name must be at most 25 characters"), // Maximum length validation,
.max(30, "File name must be at most 30 characters"), // Maximum length validation,
documentNameArabic: yup.string().required("File name Arabic is required")
.max(25, "File name must be at most 30 characters"),
});
@@ -91,6 +91,7 @@ const InvestmentDocuments = ({
const {
register,
handleSubmit,
watch,
reset,
formState: { errors },
} = useForm({
@@ -210,13 +211,17 @@ const InvestmentDocuments = ({
fontSize="sm"
type="text"
size="sm"
maxLength={25} // Maximum length constraint in the input field
maxLength={30} // Maximum length constraint in the input field
/>
{errors.fileName && (
<Text mt={1} fontSize="xs" fontWeight={500} color="red">
{errors.fileName.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 30 characters. You have entered </Box>
{watch("fileName")?.length || 0} characters.
</FormHelperText>
</FormControl>
@@ -229,13 +234,17 @@ const InvestmentDocuments = ({
type="text"
size="sm"
textAlign={'right'}
maxLength={30} // Maximum length constraint in the input field
maxLength={35} // Maximum length constraint in the input field
/>
{errors.documentNameArabic && (
<Text mt={1} fontSize="xs" fontWeight={500} color="red">
{errors.documentNameArabic.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Box as="span" me={1}>Maximum length should be 35 characters. You have entered </Box>
{watch("documentNameArabic")?.length || 0} characters.
</FormHelperText>
</FormControl>

View File

@@ -360,7 +360,7 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
onClose={handleClose}
// alertHandler={handleSave}
alertHandler={handleConfirm}
message={"Are you sure you want to add this key merit?"}
message={"Are you sure you want to add this key merits?"}
isLoading={isLoading}
/>
</>

View File

@@ -367,7 +367,7 @@ const KeyMeritsEdit = ({
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleSave}
message={"Are you sure you want to add this key merit?"}
message={"Are you sure you want to update this key merits?"}
isLoading={isLoading}
/>
</>

View File

@@ -46,7 +46,7 @@ const AmountInvested = ({ isOpen, onClose }) => {
const toast = useToast();
const id = params?.id;
const {
control,
control,
register,
handleSubmit,
reset,
@@ -114,7 +114,7 @@ const AmountInvested = ({ isOpen, onClose }) => {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalOverlay />
<ModalContent>
<ModalHeader fontSize={"md"}>Amount Invested</ModalHeader>
<ModalCloseButton />

View File

@@ -28,8 +28,10 @@ import NormalData from "../../../../Components/DataTable/NormalTable";
import { useContext, useState } from "react";
import { AddIcon } from "@chakra-ui/icons";
import {
useAddIOTransactionMutation,
useGetDistributedToInvestorMutation,
useGetDistributionInvestorMutation,
useSaveIOTransactionMutation,
useUpdateExitToInvestorMutation,
} from "../../../../Services/io.service";
import { useParams } from "react-router-dom";
@@ -42,6 +44,7 @@ import CurrencyInput from "../../../../Components/CurrencyInput";
import { IoCalculator } from "react-icons/io5";
import { debounce } from "../../../Master/Sponser/AddSponser";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { validate } from "uuid";
@@ -74,11 +77,6 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
amount: yup
.string()
.required("Amount is required")
.test(
"is-positive",
"Amount should be greater than zero",
(value) => parseFloat(value) > 0 // Check if the amount is greater than zero
)
.test(
"max",
`Distribution amount should not be greater than IO cash amount ${IODetails?.ioCash}`,
@@ -91,7 +89,6 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
}
),
});
const investor = yup.object().shape({
amount: yup.string().required("Amount is required"),
@@ -107,6 +104,8 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
resolver: yupResolver(investorExit),
});
const [saveIOTransaction] = useSaveIOTransactionMutation();
// ====================================================[Table Setup]================================================================
@@ -320,45 +319,81 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
} catch (error) {}
};
// const onFinalSubmit = async (data) => {
// setIsFinalCalculateLoading(true);
// if (!isCalcualtedData) {
// setIsFinalCalculateLoading(false);
// return toast({
// render: () => (
// <ToastBox
// message={"Please calculate investment first."}
// status="warn"
// />
// ),
// });
// }
// const finalData = {
// transactionAmount: data?.amount,
// };
// try {
// const res = await getFinalDistributionInvestment({ id, data: finalData });
// console.log(finalData);
// if (res?.error?.status === 401) {
// toast({
// render: () => (
// <ToastBox message={res?.error?.data?.message} status="error" />
// ),
// });
// } else if (res?.data?.statusCode === 200) {
// toast({
// render: () => <ToastBox message={res?.data?.message} />,
// });
// handleClose();
// }
// } catch (error) {
// console.error("An error occurred:", error);
// } finally {
// handleClose();
// }
// };
const onFinalSubmit = async (data) => {
setIsFinalCalculateLoading(true);
if (!isCalcualtedData) {
setIsFinalCalculateLoading(false);
return toast({
render: () => (
<ToastBox
message={"Please calculate investment first."}
status="warn"
/>
),
});
}
const finalData = {
const currentDate = new Date();
const dataToSend = {
transactionDate: currentDate,
transactionAmount: data?.amount,
};
}
console.log("dataaaaaaa",dataToSend);
try {
const res = await getFinalDistributionInvestment({ id, data: finalData });
console.log(finalData);
if (res?.error?.status === 401) {
const res = await saveIOTransaction({ id,data: dataToSend });
console.log(res?.data?.data);
onClose();
if (!isCalcualtedData) {
setIsFinalCalculateLoading(false);
return toast({
render: () => (
<ToastBox
message={"Please calculate investment first."}
status="warn"
/>
),
});
} else if (res?.error) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status="error" />
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
} else if (res?.data?.statusCode === 200) {
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
handleClose();
// setIsLoading(false);
}
} catch (error) {
console.error("An error occurred:", error);
} finally {
handleClose();
}
} catch (error) {}
};
const handleClose = () => {

View File

@@ -28,6 +28,7 @@ import NormalData from "../../../../Components/DataTable/NormalTable";
import { useContext, useState } from "react";
import { AddIcon } from "@chakra-ui/icons";
import {
useExitIOTransactionMutation,
useGetDistributedToInvestorMutation,
useGetDistributionInvestorMutation,
useUpdateExitToInvestorMutation,
@@ -94,7 +95,7 @@ const Exit = ({ isOpen, onClose }) => {
const res = await getDistributionInvestment({ id, data });
console.log(res?.data?.data);
if (res?.error?.status === 401) {
if (res?.error?.status === 401) {
// toast({
// render: () => (
// <ToastBox message={res?.error?.data?.message} status={"error"} />
@@ -122,7 +123,7 @@ const Exit = ({ isOpen, onClose }) => {
const [getDistributionInvestment] = useGetDistributionInvestorMutation();
const [getFinalDistributionInvestment] =
useGetDistributedToInvestorMutation();
const [updateExitToInvestor] = useUpdateExitToInvestorMutation();
const [exitIOTransaction] = useExitIOTransactionMutation();
const investor = yup.object().shape({
amount: yup.string().required("Amount is required"),
@@ -340,46 +341,69 @@ const Exit = ({ isOpen, onClose }) => {
} catch (error) {}
};
const onFinalSubmit = async (data) => {
console.log("hit");
setIsFinalCalculateLoading(true);
// if (!isCalcualtedData) {
// setIsFinalCalculateLoading(false);
// return toast({
// render: () => (
// <ToastBox
// message={"Please calculate investment first."}
// status="warn"
// />
// ),
// });
// }
// const onFinalSubmit = async (data) => {
// console.log("hit");
// setIsFinalCalculateLoading(true);
// const finalData = {
// transactionAmount: IODetails?.ioMVNAV,
// };
const finalData = {
// try {
// const res = await exitIOTransaction({ id, data: finalData });
// console.log(finalData);
// if (res?.error?.status === 401) {
// toast({
// render: () => (
// <ToastBox message={res?.error?.data?.message} status="error" />
// ),
// });
// } else if (res?.data?.statusCode === 200) {
// toast({
// render: () => <ToastBox message={res?.data?.message} />,
// });
// handleClose();
// }
// } catch (error) {
// console.error("An error occurred:", error);
// } finally {
// handleClose();
// }
// };
const onFinalSubmit = async () => {
setIsCalculateLoading(true);
const currentDate = new Date();
const dataToSend = {
transactionDate: currentDate,
transactionAmount: IODetails?.ioMVNAV,
};
}
try {
const res = await updateExitToInvestor({ id, data: finalData });
console.log(finalData);
const res = await exitIOTransaction({ id,data: dataToSend });
console.log(res?.data?.data);
if (res?.error?.status === 401) {
toast({
onClose();
if (!isCalcualtedData) {
setIsFinalCalculateLoading(false);
return toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status="error" />
<ToastBox
message={"Please calculate investment first."}
status="warn"
/>
),
});
} else if (res?.data?.statusCode === 200) {
} else if (res?.error) {
toast({
render: () => <ToastBox message={res?.data?.message} />,
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
handleClose();
setIsLoading(false);
}
} catch (error) {
console.error("An error occurred:", error);
} finally {
handleClose();
}
} catch (error) {}
};
const handleClose = () => {
@@ -389,7 +413,7 @@ const Exit = ({ isOpen, onClose }) => {
};
return (
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose}>
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose} >
<ModalOverlay />
<ModalContent maxW={1000}>
<ModalHeader fontSize={"md"}>Exit Transaction</ModalHeader>
@@ -435,7 +459,7 @@ const Exit = ({ isOpen, onClose }) => {
{/* ) } */}
</ModalBody>
<ModalFooter pt={0}>
{isCalcualtedData ? (
{/* {isCalcualtedData ? ( */}
<>
<Button
bg={"hsla(139, 100%, 14%, 1)"}
@@ -455,9 +479,9 @@ const Exit = ({ isOpen, onClose }) => {
Close
</Button>
</>
) : (
{/* ) : (
""
)}
)} */}
</ModalFooter>
</ModalContent>
</Modal>

View File

@@ -55,7 +55,7 @@ const UpdateIONav = ({ isOpen, onClose }) => {
const [createIoNav] = useCreateIoNavMutation()
const onSubmit = async (data) => {
setIsLoading(true);
try {

View File

@@ -1,7 +1,10 @@
import {
Box,
Button,
Icon,
Input,
keyframes,
Stack,
Tab,
TabList,
TabPanel,
@@ -16,7 +19,7 @@ import { useContext, useEffect, useState } from "react";
import FormInputView from "../../../Components/FormInputView";
import { useForm } from "react-hook-form"; // assuming react-hook-form is used
import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import { ArrowBackIcon } from "@chakra-ui/icons";
import { ArrowBackIcon, RepeatIcon } from "@chakra-ui/icons";
import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import ViewIOdataHeader from "./ViewIOdataHeader";
import ViewIOdetails from "./ViewIOdetails";
@@ -32,21 +35,41 @@ import KeyMerits from "../CreateIO/KeyMerits";
import Investors from "../CreateIO/Investors";
import EditIO from "../EditIO/EditIO";
import IOArtifacts from "../CreateIO/IOArtifacts";
import IOCashDetails from "../CreateIO/IOCashDetails";
import IONAVDetails from "../CreateIO/IONAVDetails";
import { useGetIOprepopulateDataQuery } from "../../../Services/io.service";
// import IOCashDetails from "../CreateIO/IOCashDetailsold";
// import IONAVDetails from "../CreateIO/IONAVDetailsOld";
import { useGetIOByIdQuery, useGetIOprepopulateDataQuery } from "../../../Services/io.service";
import UnderConstruction from "../../UnderConstruction";
import Destribution from "../CreateIO/Destribution";
import IOCashDetails from "../CreateIO/IOCashDetails/IOCashDetails";
import IONAVDetails from "../CreateIO/IONAVDetails/IONAVDetails";
import IOTransaction from "../CreateIO/IOTransaction/IOTransaction";
import { GoDotFill } from "react-icons/go";
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const ViewIOdata = () => {
const params = useParams();
const id = params?.id;
const { data, error, isLoading } = useGetIOprepopulateDataQuery();
const { data, error, isLoading, refetch } = useGetIOprepopulateDataQuery();
const {
data: IObyID,
isLoading: IObyIDisLoading,
error: IObyIDerror,
refetch: IObyIDrefetch,
} = useGetIOByIdQuery(id, { skip: !id });
const { isOpen, onOpen, onClose } = useDisclosure();
const navigate = useNavigate();
const [isEditing, setIsEditing] = useState(false);
const [isRefetchLoading, setIsRefetchLoading] = useState(false);
const { IODetails, setIODetails } = useContext(GlobalStateContext);
console.log(IODetails?.isInvestedAmount);
console.log(IODetails?.isInvestedAmount);
const tabs = [
{ label: "IO Details", content: <ViewIOdetails data={data?.data} /> },
@@ -64,9 +87,22 @@ const ViewIOdata = () => {
label: "Distribution to Investors",
content: <Destribution data={data?.data} />,
},
{
label: "IO Transaction",
content: <IOTransaction data={data?.data} />,
},
// { label: "Distribution to Investors", content: <UnderConstruction h={'75vh'} /> },
];
const handleRefresh = async () => {
setIsRefetchLoading(true);
await IObyIDrefetch();
setIsRefetchLoading(false);
};
console.log(IODetails?.ioNAVHistory);
return (
<Box
{...OPACITY_ON_LOAD}
@@ -87,7 +123,7 @@ const ViewIOdata = () => {
<Tabs mt={4}>
<TabList justifyContent={"space-between"} pe={4} alignItems={"center"}>
<Box display={"flex"}>
<Box display={"flex"} position={"relative"} w={"100%"}>
{tabs.map(({ label }, index) => (
<Tab
px={3}
@@ -96,20 +132,80 @@ const ViewIOdata = () => {
index === 1 ||
index === 2 ||
index === 3 ||
index === 4
index === 4 ||
index === 8
? false
: !IODetails?.isInvestedAmount
}
// isDisabled={
// index === 0 ||
// index === 1 ||
// index === 2 ||
// index === 3 ||
// index === 4
// ? false
// : !IODetails?.isInvestedAmount
// }
key={index}
fontSize={"sm"}
fontSize={"xs"}
_selected={{
color: "#004118",
borderBottom: "2px solid #38a169",
}}
fontWeight={500}
position={"relative"}
>
{label}
{label}{" "}
{(index === 5 &&
IODetails?.ioCashStatusHistory?.Pending?.length !== 0) ||
(index === 6 &&
IODetails?.ioNAVStatusHistory?.Pending?.length !== 0) ||
(index === 8 &&
IODetails?.ioTransactionRecords?.Pending?.length !== 0) ? (
<Box
as="span"
right={0}
color={"forestGreen"}
top={1}
position={"absolute"}
>
<GoDotFill />
</Box>
) : (
""
)}
</Tab>
))}
{/* <Box as="span" position={"absolute"} right={2} bottom={1}>
<Icon
ms={0}
animation={
isRefetchLoading ? `${rotate} 1s linear infinite` : "none"
}
bg={"gray.50"}
onClick={handleRefresh}
fontWeight={600}
as={RepeatIcon}
boxSize={8}
p={2}
rounded={"full"}
_hover={{ bg: "gray.100" }}
cursor={"pointer"}
/>
</Box> */}
<Stack position={"absolute"} right={1} bottom={1} direction="row" spacing={4}>
<Button
isLoading={isRefetchLoading}
loadingText="Refresh"
colorScheme="forestGreen"
variant="solid"
size={'xs'}
onClick={handleRefresh}
fontWeight={400}
>
Refresh
</Button>
</Stack>
</Box>
</TabList>
<TabPanels>

View File

@@ -24,6 +24,7 @@ import {
Box,
Icon,
HStack,
useToast,
} from "@chakra-ui/react";
import header from "../../../assets/IOheader.png";
import { HiDotsVertical } from "react-icons/hi";
@@ -41,12 +42,15 @@ import Cancle from "./HeaderModal/Cancle";
import { AddIcon } from "@chakra-ui/icons";
import { GrGallery } from "react-icons/gr";
import Loader01 from "../../../Components/Loaders/Loader01";
import { useUpdateTransactionMutation } from "../../../Services/io.service";
import ToastBox from "../../../Components/ToastBox";
// import { formatCurrency } from "../../../Components/CurrencyInput";
// import { removeTrailingZeros } from "../../../Constants/Constants";
const ViewIOdataHeader = ({ data, isLoading }) => {
const params = useParams();
const id = params?.id;
const params = useParams()
const toast = useToast();
const id = params?.id
const { isOpen, onOpen, onClose } = useDisclosure();
const btnRef = useRef();
const { IODetails, isIOloading } = useContext(GlobalStateContext);
@@ -108,11 +112,95 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
IODetails?.artifactsImage?.[0]?.artifactPathName
);
const [updateTransaction] = useUpdateTransactionMutation()
const handleDistributionInvestors = async () =>{
try {
const res = await updateTransaction(id)
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
// setIsLoading(false);
onDistInvestorOpen()
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
// setIsLoading(false);
}
} catch (error) {
}
}
const handleExit = async () =>{
try {
const res = await updateTransaction(id)
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
// setIsLoading(false);
onExitOpen()
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
// setIsLoading(false);
}
} catch (error) {
}
}
const handleInvestment = async () =>{
try {
const res = await updateTransaction(id)
if (res?.data) {
// toast({
// render: () => (
// <ToastBox status={"success"} message={res?.data?.message} />
// ),
// });
// setIsLoading(false);
onInvestmentOpen()
} else if (res?.error) {
toast({
render: () => (
<ToastBox status={"error"} message={res?.error?.data?.message} />
),
});
// setIsLoading(false);
}
} catch (error) {
}
}
const menu = [
{
id: 1,
title: "Amount Invested",
onClickFunction: onInvestmentOpen,
onClickFunction: handleInvestment,
},
// {
// id:2,
@@ -127,8 +215,8 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
{
id: 6,
title: "Distribution To Investors",
onClickFunction: onDistInvestorOpen,
},
onClickFunction: handleDistributionInvestors,
},
{
id: 5,
title: "Update IO NAV",
@@ -137,7 +225,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
{
id: 8,
title: "Exit",
onClickFunction: onExitOpen,
onClickFunction: handleExit,
},
{
id: 9,
@@ -444,8 +532,8 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
alignItems={"start"}
height={"95px"}
>
<Menu>
<MenuButton
{localStorage?.getItem("role") === "Maker" && <Menu>
<MenuButton
className="link p-1 rounded-1 "
bg={"#fff"}
_hover={{ backgroundColor: "#fff !important" }}
@@ -476,7 +564,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
</MenuItem>
))}
</MenuList>
</Menu>
</Menu>}
{/* Modals */}
<AmountInvested isOpen={isInvestmentOpen} onClose={onInvestmentClose} />

View File

@@ -1,4 +1,4 @@
import { Box, Button } from "@chakra-ui/react";
import { Box, Button, Text } from "@chakra-ui/react";
import React, { useContext, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
@@ -240,11 +240,6 @@ const ViewIOdetails = () => {
width: "32.3%",
value: IObyID?.data?.isShariah,
},
{
label: "Investment Type",
placeHolder: "Select option",
@@ -351,19 +346,22 @@ const ViewIOdetails = () => {
return (
<Box position={"relative"}>
<Button
position={"absolute"}
top={"-62px"}
right={0}
onClick={() => navigate(`/create-io/${params?.id}`)}
ps={4}
pe={4}
colorScheme="forestGreen"
rounded={"sm"}
size={"xs"}
>
Edit IO
</Button>
<Box display={"flex"} justifyContent={"space-between"}>
<Text></Text>
<Button
// position={"absolute"}
// top={"-62px"}
right={0}
onClick={() => navigate(`/create-io/${params?.id}`)}
ps={4}
pe={4}
colorScheme="forestGreen"
rounded={"sm"}
size={"xs"}
>
Edit IO
</Button>
</Box>
<FormInputView groupedFields={groupedFields} />
</Box>
);

View File

@@ -6,8 +6,6 @@ import {
HStack,
Input,
Select,
Switch,
Tag,
Text,
Tooltip,
useDisclosure,
@@ -103,7 +101,6 @@ const InvestorDetails = () => {
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
"Sr No",
"Client ID",
"First Name",
"Last Name",
@@ -223,7 +220,7 @@ const InvestorDetails = () => {
>
{/* {item.KYCStatus ? "Completed" : "Not complete"} */}
{item?.KYCStatus === true ? "Completed" : "Not Completed"}
{item?.KYCStatus === true ? "Completed" : "NotCompleted"}
</Text>
</Box>
),

View File

@@ -49,7 +49,7 @@ const Kyc = () => {
<HStack spacing={4} mb={4}>
<FormControl>
<FormLabel mb={1} fontSize={"sm"}>
House/Unit
Address line 1
</FormLabel>
<Input
bg={"#ccc3"}
@@ -62,7 +62,7 @@ const Kyc = () => {
</FormControl>
<FormControl>
<FormLabel mb={1} fontSize={"sm"}>
Road/Street
Address line 2
</FormLabel>
<Input
bg={"#ccc3"}

View File

@@ -24,7 +24,7 @@ export const addInvestmentType = yup.object().shape({
.string()
.required("Investment type is required")
.max(50, "Investment name cannot be more than 50 characters"),
note: yup.string().optional().max(255, "Note cannot exceed 255 characters"),
// note: yup.string().optional().max(255, "Note cannot exceed 255 characters"),
investmentTypeNameArabic: yup
.string()
.required("Investment type in required"),
@@ -107,27 +107,23 @@ const AddInvestmentType = () => {
isActive: isSwitchOn,
};
await updateInvestmentType({ data: formData, id }).then((response) => {
if (response?.data) {
if (response?.data?.statusCode === 200) {
toast({
render: () => (
<ToastBox
status={"success"}
message={response?.data?.message}
/>
),
render: () => <ToastBox message={response?.data?.message} />,
});
setIsLoadingBtn(false);
setAlert(false);
navigate("/investment-type");
} else if (response?.error) {
} else {
toast({
render: () => (
<ToastBox
status={"error"}
message={response?.error?.data?.message}
/>
<ToastBox message={"Something Went Wrong"} status={"error"} />
),
});
setIsLoadingBtn(false);
navigate("/investment-type");
}
});
} catch (error) {
@@ -143,50 +139,22 @@ const AddInvestmentType = () => {
};
await createInvestmentType(formData).then((response) => {
// if (response?.data?.statusCode === 201) {
// toast({
// render: () => <ToastBox message={response?.data?.message} />,
// });
// setIsLoadingBtn(false);
// navigate("/investment-type");
// } else {
// toast({
// render: () => (
// <ToastBox message={"Something Went Wrong"} status={"error"} />
// ),
// });
// setIsLoadingBtn(false);
// navigate("/investment-type");
// }
if (response?.data) {
if (response?.data?.statusCode === 201) {
toast({
render: () => (
<ToastBox
status={"success"}
message={response?.data?.message}
/>
),
render: () => <ToastBox message={response?.data?.message} />,
});
setAlert(false);
setIsLoadingBtn(false);
navigate("/investment-type");
} else if (response?.error) {
} else {
toast({
render: () => (
<ToastBox
status={"error"}
message={response?.error.data.message}
/>
<ToastBox message={"Something Went Wrong"} status={"error"} />
),
});
setAlert(false);
setIsLoadingBtn(false);
// navigate("/investment-type");
navigate("/investment-type");
}
});
} catch (error) {
@@ -231,7 +199,7 @@ const AddInvestmentType = () => {
placeHolder: " ",
name: "note",
type: "textarea",
// isRequired: true,
isRequired: false,
section: "",
maxLength: 255,
helperText: `Maximum length should be 255 characters. You have entered ${
@@ -243,7 +211,7 @@ const AddInvestmentType = () => {
placeHolder: " ",
name: "noteArabic",
type: "textarea",
// isRequired: true,
isRequired: false,
arabic: true,
section: "",
maxLength: 255,
@@ -286,7 +254,7 @@ const AddInvestmentType = () => {
placeHolder: " ",
name: "note",
type: "textarea",
// isRequired: true,
isRequired: false,
section: "",
maxLength: 255,
helperText: `Maximum length should be 255 characters. You have entered ${
@@ -298,7 +266,7 @@ const AddInvestmentType = () => {
placeHolder: " ",
name: "noteArabic",
type: "textarea",
// isRequired: true,
isRequired: false,
arabic: true,
section: "",
maxLength: 255,
@@ -346,22 +314,9 @@ const AddInvestmentType = () => {
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={14}>
{/* ===================== [Switch Button] ======================== */}
<Box
display={"flex"}
justifyContent={"space-between"}
alignItems={"center"}
mt={5}
px={4}
mb={5}
>
<Text
fontSize={"sm"}
mb={0}
onClick={() => navigate(-1)}
cursor={"pointer"}
>
<ArrowBackIcon fontSize={"xl"} me={2} />
Add Details
<Box display={"flex"} justifyContent={"space-between"} alignItems={"center"} mt={5} px={4} mb={5}>
<Text fontSize={"sm"} mb={0} onClick={() => navigate(-1)} cursor={"pointer"}>
<ArrowBackIcon fontSize={"xl"} me={2} />Add Details
</Text>
<SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} />
</Box>
@@ -383,11 +338,7 @@ const AddInvestmentType = () => {
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleConfirm}
message={
id
? "Are you sure you want to update this document?"
: " Are you sure you want to add this document?"
}
message={id ? "Are you sure you want to update this Investment Type?" : " Are you sure you want to add this Investment Type?"}
isLoading={isLoadingBtn}
/>
</Box>

View File

@@ -232,16 +232,49 @@ const InvestmentType = () => {
// ==================== [Delete Function] =======================
// const handleDelete = async () => {
// console.log(actionId);
// setIsLoading(true);
// try {
// const response = await deleteInvestmentType(actionId);
// console.log(response);
// setIsLoading(false);
// setDeleteAlert(false);
// } catch (error) {}
// };
const handleDelete = async () => {
console.log(actionId);
setIsLoading(true);
try {
const response = await deleteInvestmentType(actionId);
console.log(response);
console.log(response?.data);
if (response?.error?.data?.code === 400) {
toast({
render: () => (
<ToastBox message={response?.error?.data?.message} status="error" />
),
});
} else if (
response?.data?.statusCode === 201 ||
response?.data?.statusCode === 200
) {
toast({
render: () => (
<ToastBox message={response?.data?.message} status="success" />
),
});
}
setIsLoading(false);
setDeleteAlert(false);
} catch (error) {}
} catch (error) {
console.error(error);
setIsLoading(false);
}
};
return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
@@ -315,7 +348,7 @@ const InvestmentType = () => {
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"}
message={"Are you sure you want to delete Investment Type?"}
alertHandler={handleDelete}
isLoading={isLoading}
/>

View File

@@ -187,13 +187,13 @@ const Sponser = () => {
console.log(response?.data);
if(response?.error?.data?.code === 400){
toast({
render: () => <ToastBox message={response?.error?.data?.message} status={'warn'} />,
render: () => <ToastBox message={response?.error?.data?.message} status={'error'} />,
});
setIsLoading(false);
setDeleteAlert(false);
} else if(response?.data?.statusCode === 201 || response?.data?.statusCode === 200){
toast({
render: () => <ToastBox message={response?.data?.message} status={'error'} />,
render: () => <ToastBox message={response?.data?.message} status={'success'} />,
});
setIsLoading(false);
setDeleteAlert(false);
@@ -201,7 +201,7 @@ const Sponser = () => {
}
} catch (error) {}
};
console.log(isSponserLoading);

View File

@@ -1,31 +1,31 @@
import { Box, Image, Spinner, Text } from '@chakra-ui/react'
import React from 'react'
import logo from '../assets/logo2.png'
import { Box, Image, Spinner, Text } from "@chakra-ui/react";
import React from "react";
import logo from "../assets/logo2.png";
const SplashScreen = () => {
return (
<Box
h={'100vh'}
display={'flex'}
justifyContent={'center'}
alignItems={'center'}
flexDirection={'column'}
gap={10}
h={"100vh"}
display={"flex"}
justifyContent={"center"}
alignItems={"center"}
flexDirection={"column"}
gap={10}
>
<Image src={logo} />
{/* <Spinner color='green.900' size='md' /> */}
<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>
<Image src={logo} />
<Spinner color='green.900' size='md' />
{/* <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> */}
</Box>
)
}
);
};
export default SplashScreen
export default SplashScreen;

View File

@@ -3,6 +3,7 @@ import {
Box,
Button,
FormControl,
FormHelperText,
FormLabel,
Heading,
HStack,
@@ -36,7 +37,8 @@ const FILE_TYPES = ["image/jpeg", "image/png", "image/gif"];
export const conformModalSchema = yup.object().shape({
investorAmount: yup.string().required("Investor amount is required"),
comment: yup.string().notRequired(),
comment: yup.string().notRequired()
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const DrawalRequestApprove = ({
@@ -59,6 +61,7 @@ const DrawalRequestApprove = ({
const {
control,
register,
watch,
reset,
handleSubmit,
formState: { errors },
@@ -259,12 +262,17 @@ const DrawalRequestApprove = ({
size="sm"
placeholder={"Enter your comments...."}
resize={"none"}
maxLength={200}
/>
{errors.comment && (
<Text fontSize="xs" color="red">
{errors.comment.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Text as={"span"} me={1}>Maximum length should be 200 characters. You have entered</Text>
{watch("checkerComment")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>

View File

@@ -2,6 +2,7 @@ import {
Box,
Button,
FormControl,
FormHelperText,
FormLabel,
Input,
Modal,
@@ -24,7 +25,8 @@ import {
import { useDepositRejectMutation } from "../../../Services/drawal.request.service";
export const conformModalSchema = yup.object().shape({
comments: yup.string().required("Comment is required"),
comments: yup.string().required("Comment is required")
.max(200, "Approve Comment cannot be more than 200 characters"),
});
const DrawalRequestReject = ({ isOpen, onClose, firstField ,id}) => {
@@ -34,6 +36,7 @@ import { useDepositRejectMutation } from "../../../Services/drawal.request.servi
const {
register,
watch,
reset,
handleSubmit,
formState: { errors },
@@ -101,16 +104,21 @@ import { useDepositRejectMutation } from "../../../Services/drawal.request.servi
placeholder={"Enter your comments...."}
rounded={"md"}
resize={"none"}
maxLength={200}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
<FormHelperText fontSize="xs" color="gray.500">
<Text as={"span"} me={1}>Maximum length should be 200 characters. You have entered</Text>
{watch("comments")?.length || 0} characters.
</FormHelperText>
</FormControl>
</ModalBody>
<ModalFooter>
<Button
<Button
colorScheme="gray"
mr={3}
onClick={onClose}

View File

@@ -15,9 +15,9 @@ export const ioService = createApi({
"getArtifactsVideo",
"getInvestmentDocuments",
"getIOById",
"getSponser",
"getInvestmentType",
"getInvestmentTypeID"
"getSponser",
"getInvestmentType",
"getInvestmentTypeID",
],
endpoints: (builder) => ({
// =====[get prepopulate data]
@@ -28,7 +28,8 @@ export const ioService = createApi({
// =====[get]
getIOs: builder.query({
query: ({ page, size, ioStatus_xid, search }) => `/io/admin?page=${page}&size=${size}&ioStatus_xid=${ioStatus_xid}&search=${search}`,
query: ({ page, size, ioStatus_xid, search }) =>
`/io/admin?page=${page}&size=${size}&ioStatus_xid=${ioStatus_xid}&search=${search}`,
providesTags: ["getIO"],
}),
@@ -224,7 +225,7 @@ export const ioService = createApi({
invalidatesTags: ["getIOById"],
}),
// ======== [ Distribution Transaction ] ========
// ======== [ Distribution Transaction ] ========
getDistributionInvestor: builder.mutation({
query: ({ id, data }) => ({
@@ -261,9 +262,7 @@ export const ioService = createApi({
invalidatesTags: ["getIOById"],
}),
// ==============[ Displaye Orders ]===============
// ==============[ Displaye Orders ]===============
setDisplayOrder: builder.mutation({
query: ({ data }) => ({
@@ -309,7 +308,7 @@ export const ioService = createApi({
method: "POST",
body: data,
}),
invalidatesTags: ["getSponser","prePopulate"],
invalidatesTags: ["getSponser", "prePopulate"],
}),
// ========[Update Sponser]========
@@ -320,12 +319,11 @@ export const ioService = createApi({
method: "PATCH",
body: data,
}),
invalidatesTags: ["getSponser","prePopulate"],
invalidatesTags: ["getSponser", "prePopulate"],
}),
// ======[Get All]=====
getSponserMaster: builder.query({
query: ({ page, size, searchTerm }) => {
let baseURL = `/sponsor/admin/?search=${searchTerm || ""}`;
@@ -336,10 +334,10 @@ export const ioService = createApi({
},
providesTags: ["getSponser"],
}),
// ========[Delete Sponser]========
deleteSponser: builder.mutation({
deleteSponser: builder.mutation({
query: (id) => ({
url: `/sponsor/admin/delete/${id}`,
method: "DELETE",
@@ -356,7 +354,7 @@ export const ioService = createApi({
getSponserMasterActive: builder.query({
query: () => "/sponsor/admin/active",
}),
// ======[Get ID]=====
getSponserById: builder.query({
@@ -369,12 +367,8 @@ export const ioService = createApi({
query: () => `/sponsor/admin/active`,
}),
// ===============================[ Investment Type ]===================================
// ===============================[ Investment Type ]===================================
// ========[Get All]=========
getInvestmentTypes: builder.query({
@@ -405,11 +399,15 @@ export const ioService = createApi({
updateInvestmentType: builder.mutation({
query: ({ data, id }) => ({
url: `/investmentType/admin/${id}`,
url: `/investmentType/admin/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getInvestmentTypeID", "getInvestmentType", "prePopulate"],
invalidatesTags: [
"getInvestmentTypeID",
"getInvestmentType",
"prePopulate",
],
}),
// ========[Delete Investment]=======
@@ -419,25 +417,181 @@ export const ioService = createApi({
url: `/investmentType/admin/delete/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getInvestmentType", 'prePopulate'],
invalidatesTags: ["getInvestmentType", "prePopulate"],
}),
profile: builder.query({
query: (id) => `/auth/admin/profile`,
}),
// ========Add Io Details========
updateIOCase: builder.mutation({
query: (id) => ({
url: `/io/admin/maker-transaction/${id}/verify-pending-transaction-for-cash-and-nav`,
method: "POST",
}),
invalidatesTags: ["getIOById"],
}),
updateTransaction: builder.mutation({
query: (id) => ({
// url: `/io/admin/maker-transaction/${id}/verify-pending-transaction-for-cash-and-nav`,
url: `/io/admin/maker-transaction/${id}/verify-pending-transaction`,
method: "POST",
}),
invalidatesTags: ["getIOById"],
}),
addNavDetails: builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/maker-transaction/${id}/io-nav`,
method: "POST",
body:data,
}),
invalidatesTags: ["getIOById"],
}),
addIOTransaction: builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/maker-transaction/${id}/io-nav`,
method: "POST",
body:data,
}),
invalidatesTags: ["getIOById"],
}),
saveIOTransaction: builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/maker-transaction/${id}/io-yeild`,
method: "POST",
body:data,
}),
invalidatesTags: ["getIOById"],
}),
exitIOTransaction: builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/maker-transaction/${id}/io-exit`,
method: "POST",
body:data,
}),
invalidatesTags: ["getIOById"],
}),
addIoCase: builder.mutation({
query: (id) => ({
url: `/io/admin/maker-transaction/${id}/verify-pending-transaction`,
method: "POST",
}),
invalidatesTags: ["getIOById"],
}),
approveIOCase: builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/checker-transaction/approved/io-cash/${id}`,
method: "PATCH",
body:data,
}),
invalidatesTags: ["getIOById"],
}),
approveIONav: builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/checker-transaction/approved/io-nav/${id}`,
method: "PATCH",
body:data,
}),
invalidatesTags: ["getIOById"],
}),
approveDistribution: builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/checker-transaction/approved/distributed-to-investor/${id}`,
method: "PATCH",
body:data,
}),
invalidatesTags: ["getIOById"],
}),
approveExit: builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/checker-transaction/approved/exit/${id}`,
method: "PATCH",
body:data,
}),
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({
query: ({id,data}) => ({
url: `/io/admin/checker-transaction/reject/${id}`,
method: "PATCH",
body:data,
}),
invalidatesTags: ["getIOById"],
}),
}),
});
@@ -470,7 +624,6 @@ export const {
useDeleteVideoArtifactsMutation,
useDeleteImageArtifactsMutation,
useSetDisplayOrderMutation,
useSetDisplayOrderIODocumentsMutation,
useSetDisplayOrderIOArtifactsImageMutation,
@@ -488,11 +641,9 @@ export const {
useGetDistributedToInvestorMutation,
useUpdateExitToInvestorMutation,
useUpdateCancleStatusMutation,
// ==============[ Sponser ]===============
// ==============[ Sponser ]===============
useGetSponserMasterQuery,
useGetSponserMasterActiveQuery,
useCreateSponserMutation,
@@ -501,7 +652,6 @@ export const {
useDeleteSponserMutation,
useGetActiveSponserMasterQuery,
// ============[ Investment Type ]========
useGetInvestmentTypesQuery,
@@ -509,6 +659,24 @@ export const {
useCreateInvestmentTypeMutation,
useUpdateInvestmentTypeMutation,
useDeleteInvestmentTypeMutation,
useProfileQuery
useProfileQuery,
// ========[ Add Io Details ]========
useUpdateIOCaseMutation,
useUpdateTransactionMutation,
useApproveIOCaseMutation,
useRejectIOCaseMutation,
useAddNavDetailsMutation,
useApproveIONavMutation,
useAddIOTransactionMutation,
useSaveIOTransactionMutation,
useApproveDistributionMutation,
useExitIOTransactionMutation,
useApproveExitMutation,
useApproveInvestedMutation,
useApproveDistributedMutation,
useApproveExitTransactionMutation,
useApproveCancleTransactionMutation
} = ioService;

View File

@@ -46,7 +46,7 @@ export const baseQuery = async (args, api, extraOptions) => {
if (refreshResult.data) {
// Save new tokens
localStorage.setItem("accessToken", refreshResult?.data?.data?.access?.token);
localStorage.setItem("role", refreshResult?.data?.data?.role);
// localStorage.setItem("role", refreshResult?.data?.data?.role);
// console.log(refreshResult?.data?.data?.role);