Compare commits

...

44 Commits

Author SHA1 Message Date
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
5b2efcd292 update color bugs 2024-11-14 16:28:55 +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
YasinShaikh123
f2023cf7b3 update bugs 2024-11-11 12:48:06 +05:30
73 changed files with 8734 additions and 475 deletions

View File

@@ -12,7 +12,8 @@ const FullscreenLoaders = ({height}) => {
w={"100%"} w={"100%"}
h={height ? height: "100vh"} h={height ? height: "100vh"}
gap={4} 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> <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 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> */} {/* <Text color='#004717' fontSize={'md'} fontWeight={500}>Loading...</Text> */}
<Spinner />
</Box> </Box>
); );
}; };

View File

@@ -1,19 +1,21 @@
import React from "react"; import React from "react";
import './FullscreenLoaders.css' import './FullscreenLoaders.css'
import { Spinner } from "@chakra-ui/react";
const Loader01 = () => { const Loader01 = () => {
return ( return (
<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> // <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 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>
<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); const [InvestorWallet, setInvestorWallet] = useState(null);
// ==============[ prod state ]=============================== // ==============[ prod state ]===============================
@@ -1643,7 +1760,13 @@ const GlobalStateProvider = ({ children }) => {
fawateerRequest, fawateerRequest,
setFawateerRequest, setFawateerRequest,
approveHistory, approveHistory,
setApproveHistory setApproveHistory,
approved,
setApproved,
iONAVDetail,
setIONAVDetail,
iOTransaction,
setIOTransaction,
}} }}
> >
{children} {children}

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ import {
Button, Button,
FormControl, FormControl,
FormErrorMessage, FormErrorMessage,
FormHelperText,
FormLabel, FormLabel,
Input, Input,
Modal, Modal,
@@ -35,7 +36,7 @@ const FILE_TYPES = ["image/jpeg", "image/png", "image/gif"];
export const conformModalSchema = yup.object().shape({ export const conformModalSchema = yup.object().shape({
investorAmount: yup.string().required("Investor amount is required"), 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"), supporting_FileName: yup.mixed().required("File is required"),
// .test("fileType", "Unsupported File Format", (value) => { // .test("fileType", "Unsupported File Format", (value) => {
// return value && FILE_TYPES.includes(value.type); // return value && FILE_TYPES.includes(value.type);
@@ -192,7 +193,7 @@ const DepositRequestApprove = ({
)} )}
</FormControl> </FormControl>
<FormControl mb={4}> <FormControl mb={4}>
<FormLabel fontSize="sm">Comments</FormLabel> <FormLabel fontSize="sm">Comment</FormLabel>
<Textarea <Textarea
rows={5} rows={5}
focusBorderColor="green.400" focusBorderColor="green.400"
@@ -201,14 +202,19 @@ const DepositRequestApprove = ({
fontSize="sm" fontSize="sm"
type="textarea" type="textarea"
size="sm" size="sm"
placeholder={"Enter your comments...."} placeholder={"Enter your comment...."}
resize={"none"} resize={"none"}
maxLength={200}
/> />
{errors.comment && ( {errors.comment && (
<Text fontSize="xs" color="red"> <Text fontSize="xs" color="red">
{errors.comment.message} {errors.comment.message}
</Text> </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> </FormControl>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View File

@@ -2,6 +2,7 @@ import {
Box, Box,
Button, Button,
FormControl, FormControl,
FormHelperText,
FormLabel, FormLabel,
Input, Input,
Modal, Modal,
@@ -24,7 +25,8 @@ import { useDepositRejectMutation } from "../../../Services/deposit.request.serv
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
export const conformModalSchema = yup.object().shape({ 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}) => { const DepositRequestReject = ({ isOpen, onClose, firstField ,id}) => {
@@ -35,6 +37,7 @@ const DepositRequestReject = ({ isOpen, onClose, firstField ,id}) => {
const { const {
register, register,
reset, reset,
watch,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
} = useForm({ } = useForm({
@@ -121,15 +124,20 @@ const DepositRequestReject = ({ isOpen, onClose, firstField ,id}) => {
fontSize="sm" fontSize="sm"
type="textarea" type="textarea"
size="md" size="md"
placeholder={"Enter your comments...."} placeholder={"Enter your comment...."}
rounded={"md"} rounded={"md"}
resize={"none"} resize={"none"}
maxLength={200}
/> />
{errors.comments && ( {errors.comments && (
<Text fontSize="xs" color="red"> <Text fontSize="xs" color="red">
{errors.comments.message} {errors.comments.message}
</Text> </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> </FormControl>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View File

@@ -1,17 +1,27 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { OPACITY_ON_LOAD } from "../../Layout/animations"; 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 { import {
FormControl, Box,
FormLabel, Button,
FormHelperText, HStack,
Input,
InputGroup,
InputRightAddon,
Textarea,
useDisclosure,
Image,
Icon,
VStack,
Text,
useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { FormControl, FormLabel, FormHelperText } from "@chakra-ui/react";
import { DeleteIcon, Search2Icon } from "@chakra-ui/icons"; import { DeleteIcon, Search2Icon } from "@chakra-ui/icons";
import SelectInvestorModal from "./SelectInvestorModal"; import SelectInvestorModal from "./SelectInvestorModal";
import { Controller, useForm } from "react-hook-form"; // Import useForm import { Controller, useForm } from "react-hook-form"; // Import useForm
import { yupResolver } from "@hookform/resolvers/yup"; // Import resolver for Yup import { yupResolver } from "@hookform/resolvers/yup"; // Import resolver for Yup
import * as Yup from "yup"; // Import Yup for validation 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 { bytesToMB } from "../../Constants/Constants";
import { useCreateFawateerRequestMutation } from "../../Services/fawateer.maker.service"; import { useCreateFawateerRequestMutation } from "../../Services/fawateer.maker.service";
import ToastBox from "../../Components/ToastBox"; import ToastBox from "../../Components/ToastBox";
@@ -23,60 +33,67 @@ const validationSchema = Yup.object().shape({
investorName: Yup.string().required("Investor name is required"), investorName: Yup.string().required("Investor name is required"),
clientId: Yup.string().required("Client ID is required"), clientId: Yup.string().required("Client ID is required"),
transaction_date: Yup.date() transaction_date: Yup.date()
.required('Date is required') .required("Date is required")
.transform((value, originalValue) => { .transform((value, originalValue) => {
return originalValue === "" ? null : value; // Convert empty strings to null return originalValue === "" ? null : value; // Convert empty strings to null
}) })
.typeError('Please enter a valid date').max(new Date(), "Date cannot be in the future"), .typeError("Please enter a valid date")
.max(new Date(), "Date cannot be in the future"),
transaction_amount: Yup.number() transaction_amount: Yup.number()
.required("Transaction amount is required") .required("Transaction amount is required")
.transform((value, originalValue) => originalValue === "" ? null : value) // Convert empty strings to null .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 .typeError("Transaction amount must be a number") // Custom error message if it's not a number
.positive('Transaction amount must be greater than zero'), .positive("Transaction amount must be greater than zero"),
spportFile_path: Yup.mixed().required("Support file is required"), 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 CreateRequest = () => {
const toast = useToast() const toast = useToast();
const navigate=useNavigate() const navigate = useNavigate();
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const [selectedInvestor, setSelectorInvestor] = useState({}); const [selectedInvestor, setSelectorInvestor] = useState({});
const [filePreview, setFilePreview] = useState(null); // State for previewing the file const [filePreview, setFilePreview] = useState(null); // State for previewing the file
const [fileType, setFileType] = useState(null); // State to store file type for conditional rendering const [fileType, setFileType] = useState(null); // State to store file type for conditional rendering
const[ isLoading, setIsLoading ] = useState(false) const [isLoading, setIsLoading] = useState(false);
const [id, setId ] = useState(null) const [id, setId] = useState(null);
// Initialize useForm with the resolver for Yup validation // 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), resolver: yupResolver(validationSchema),
}); });
const [creatFawaateerRequest] = useCreateFawateerRequestMutation();
const [ creatFawaateerRequest ] = useCreateFawateerRequestMutation()
const onSubmit = async (data) => { const onSubmit = async (data) => {
console.log(data); console.log(data);
setIsLoading(true) setIsLoading(true);
// Convert data to FormData // Convert data to FormData
const formData = new FormData(); const formData = new FormData();
// Append each field from the data object to the FormData // Append each field from the data object to the FormData
Object.keys(data).forEach((key) => { Object.keys(data).forEach((key) => {
if (key === "spportFile_path" && data[key] instanceof FileList) { if (key === "spportFile_path" && data[key] instanceof FileList) {
// Append the first file from FileList (assuming single file input) // Append the first file from FileList (assuming single file input)
formData.append(key, data[key][0]); // Append the file formData.append(key, data[key][0]); // Append the file
} else { } else {
formData.append(key, data[key]); // Append other fields formData.append(key, data[key]); // Append other fields
} }
}); });
try { try {
// Make the API call with formData // Make the API call with formData
const res = await creatFawaateerRequest({ data: formData, id }); const res = await creatFawaateerRequest({ data: formData, id });
if (res?.error) { if (res?.error) {
toast({ toast({
render: () => ( render: () => (
@@ -84,39 +101,35 @@ const CreateRequest = () => {
), ),
}); });
setIsLoading(false); setIsLoading(false);
reset() reset();
return return;
} else if (res?.data) { } else if (res?.data) {
toast({ toast({
render: () => ( render: () => <ToastBox message={res?.data?.message} />,
<ToastBox message={res?.data?.message} />
),
}); });
setIsLoading(false); setIsLoading(false);
navigate('/fawateer-history') navigate("/fawateer-history");
return return;
} else { } else {
toast({ toast({
render: () => ( render: () => (
<ToastBox status={'error'} message={"Something went wrong"} /> <ToastBox status={"error"} message={"Something went wrong"} />
), ),
}); });
setIsLoading(false); setIsLoading(false);
return return;
} }
} catch (error) { } catch (error) {
console.error("Error:", error); console.error("Error:", error);
toast({ toast({
render: () => ( render: () => (
<ToastBox status={'error'} message={"An error occurred"} /> <ToastBox status={"error"} message={"An error occurred"} />
), ),
}); });
setIsLoading(false); setIsLoading(false);
return return;
} }
}; };
// Handle file change and preview // Handle file change and preview
const handleFileChange = (e) => { const handleFileChange = (e) => {
@@ -137,15 +150,12 @@ const CreateRequest = () => {
} }
}; };
return ( return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}> <Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
<Box <Box
display={"flex"} display={"flex"}
justifyContent={"space-between"} justifyContent={"space-between"}
flexWrap={'wrap'} flexWrap={"wrap"}
alignItems={"center"} alignItems={"center"}
mt={5} mt={5}
px={4} px={4}
@@ -153,11 +163,16 @@ const CreateRequest = () => {
onSubmit={handleSubmit(onSubmit)} onSubmit={handleSubmit(onSubmit)}
> >
{/* Investor Name Field */} {/* 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"}> <FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Investor name Investor name
</FormLabel> </FormLabel>
<InputGroup size='sm'> <InputGroup size="sm">
<Input <Input
bg={"#F5F8F6"} bg={"#F5F8F6"}
focusBorderColor="forestGreen.300" focusBorderColor="forestGreen.300"
@@ -170,11 +185,24 @@ const CreateRequest = () => {
{...register("investorName")} {...register("investorName")}
_placeholder={{ fontSize: "sm" }} _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 <Search2Icon /> Search
</InputRightAddon> </InputRightAddon>
</InputGroup> </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> </FormControl>
{/* Client ID Field */} {/* Client ID Field */}
@@ -193,7 +221,13 @@ const CreateRequest = () => {
placeholder={"Client ID"} placeholder={"Client ID"}
{...register("clientId")} {...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> </FormControl>
{/* Date Field */} {/* Date Field */}
@@ -208,10 +242,21 @@ const CreateRequest = () => {
fontSize={"sm"} fontSize={"sm"}
rounded={"sm"} rounded={"sm"}
type={"date"} type={"date"}
max={new Date().toISOString().split("T")[0]} // Disable future dates max={new Date().toLocaleDateString("en-CA")} // Ensures max is in local timezone
{...register("transaction_date")} {...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> </FormControl>
{/* Amount Field */} {/* Amount Field */}
@@ -220,19 +265,35 @@ const CreateRequest = () => {
Amount (BHD) Amount (BHD)
</FormLabel> </FormLabel>
<Controller <Controller
name="transaction_amount" name="transaction_amount"
control={control} control={control}
render={({ field }) => ( render={({ field }) => (
<CurrencyInput bg={"#F5F8F6"} {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} /> <CurrencyInput
)} bg={"#F5F8F6"}
/> {...field}
<FormHelperText fontSize={'xs'} fontWeight={500} style={{ color: "red" }}> textAlign={"right"}
fontSize={"sm"}
type="number"
size={"sm"}
/>
)}
/>
<FormHelperText
fontSize={"xs"}
fontWeight={500}
style={{ color: "red" }}
>
{errors.transaction_amount?.message} {errors.transaction_amount?.message}
</FormHelperText> </FormHelperText>
</FormControl> </FormControl>
{/* Support File Field with Preview */} {/* 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"}> <FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Support file Support file
</FormLabel> </FormLabel>
@@ -249,7 +310,13 @@ const CreateRequest = () => {
{...register("spportFile_path")} {...register("spportFile_path")}
// onChange={handleFileChange} // 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 */} {/* Animated Preview */}
{filePreview && fileType?.type.startsWith("image/") && ( {filePreview && fileType?.type.startsWith("image/") && (
@@ -259,14 +326,55 @@ const CreateRequest = () => {
transition={{ duration: 0.5 }} transition={{ duration: 0.5 }}
style={{ marginTop: "10px" }} style={{ marginTop: "10px" }}
> >
<Box position={'relative'} display={'flex'} alignContent={'flex-end'} gap={3} mt={2}> <Box
<Image src={filePreview} alt="File preview" maxW={"150px"} borderRadius="md" boxShadow="md" /> position={"relative"}
<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} /> display={"flex"}
<VStack justifyItems={'flex-end'} alignItems={'flex-start'}> alignContent={"flex-end"}
<Text as={'span'} color={'gray.600'} fontSize={'xs'}>File Name: <Text as={'span'} color={'GrayText'}> {fileType?.name}</Text></Text> gap={3}
<Text as={'span'} color={'gray.600'} fontSize={'xs'}>File Size: <Text as={'span'} color={'GrayText'}> {bytesToMB(fileType?.size)} Mb</Text></Text> mt={2}
<Text as={'span'} color={'gray.600'} fontSize={'xs'}>File Type: <Text as={'span'} color={'GrayText'}> {fileType?.type}</Text></Text> >
<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> </VStack>
</Box> </Box>
</motion.div> </motion.div>
@@ -274,7 +382,7 @@ const CreateRequest = () => {
</FormControl> </FormControl>
{/* Description Field */} {/* 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"}> <FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
Description Description
</FormLabel> </FormLabel>
@@ -286,13 +394,26 @@ const CreateRequest = () => {
rounded={"sm"} rounded={"sm"}
placeholder={"Description"} placeholder={"Description"}
{...register("makerComment")} {...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> </FormControl>
{/* Submit Button */} {/* Submit Button */}
<HStack mt={2} w={'100%'} justifyContent={'flex-end'}> <HStack mt={2} w={"100%"} justifyContent={"flex-end"}>
<Button <Button
colorScheme="forestGreen" colorScheme="forestGreen"
size={"sm"} size={"sm"}
rounded={"sm"} rounded={"sm"}
@@ -305,7 +426,13 @@ const CreateRequest = () => {
</HStack> </HStack>
</Box> </Box>
<SelectInvestorModal setId={setId} setValue={setValue} onClose={onClose} isOpen={isOpen} onOpen={onOpen}/> <SelectInvestorModal
setId={setId}
setValue={setValue}
onClose={onClose}
isOpen={isOpen}
onOpen={onOpen}
/>
</Box> </Box>
); );
}; };

View File

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

View File

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

View File

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

View File

@@ -1,37 +1,49 @@
import React, { useContext, useEffect, useRef, useState } from 'react' import React, { useContext, useEffect, useRef, useState } from "react";
import GlobalStateContext from '../../../Contexts/GlobalStateContext'; import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import { Box, HStack, Input,Text, Table, Tbody, Th, Tr, Avatar, useDisclosure,Button, Badge } from '@chakra-ui/react'; import {
import { OPACITY_ON_LOAD } from '../../../Layout/animations'; Box,
import Pagination from '../../../Components/Pagination'; HStack,
import NormalTable from '../../../Components/DataTable/NormalTable'; Input,
import CustomAlertDialog from '../../../Components/CustomAlertDialog'; Text,
import { formatDatee } from '../../../Components/FormField'; Table,
import { AddIcon } from '@chakra-ui/icons'; Tbody,
import AddIONav from './AddIONav'; 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 Destribution = () => {
const { navDetails, setNavDetails, IODetails } = const { navDetails, setNavDetails, IODetails } =
useContext(GlobalStateContext); useContext(GlobalStateContext);
const firstField = useRef(); const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [deleteAlert, setDeleteAlert] = useState(false); const [deleteAlert, setDeleteAlert] = useState(false);
const [actionId, setActionId] = useState(false); const [actionId, setActionId] = useState(false);
const [mouseEntered, setMouseEntered] = useState(false); const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState(""); 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(() => { useEffect(() => {
// Simulate loading // Simulate loading
const timer = setTimeout(() => { const timer = setTimeout(() => {
@@ -42,32 +54,38 @@ const Destribution = () => {
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, []); }, []);
// Table setup // Table setup
const tableHeadRow = [ const tableHeadRow = [
// "Sr.No", // "Sr.No",
"Date", "Date",
"Amount", "Amount",
"% of Investment" "% of Investment",
]; ];
// Table filter // Table filter
const filteredData = IODetails?.distributionToInvestor?.filter((item) => { const filteredData = IODetails?.distributionToInvestor
const name = item?.transactionAmount; ?.filter((item) => {
const searchLower = searchTerm.toLowerCase(); const name = item?.transactionAmount;
const nameMatches = name.toLowerCase().includes(searchLower); const searchLower = searchTerm.toLowerCase();
return nameMatches; const nameMatches = name.toLowerCase().includes(searchLower);
}).sort((b, a) => new Date(a.transactionDate) - new Date(b.transactionDate)); 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, id: item?.id,
"Sr.No": <Text "Sr.No": (
justifyContent={"start"} <Text
as={"span"} justifyContent={"start"}
color={"teal.900"} as={"span"}
fontWeight={"500"} color={"teal.900"}
className="d-flex align-items-start web-text-small" fontWeight={"500"}
>{item?.id}</Text>, className="d-flex align-items-start web-text-small"
"Date": ( >
{item?.id}
</Text>
),
Date: (
<Text <Text
justifyContent={"center"} justifyContent={"center"}
as={"span"} as={"span"}
@@ -78,7 +96,7 @@ const Destribution = () => {
{formatDate(item.transactionDate)} {formatDate(item.transactionDate)}
</Text> </Text>
), ),
"Amount": ( Amount: (
<Text <Text
justifyContent={"center"} justifyContent={"center"}
as={"span"} as={"span"}
@@ -86,11 +104,13 @@ const Destribution = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" 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, { {`${parseFloat(item.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})}`} })}`}
</Text> </Text>
), ),
"% of Investment": ( "% of Investment": (
@@ -106,12 +126,8 @@ const Destribution = () => {
), ),
})); }));
const handleDelete = () => { const handleDelete = () => {
const updatedNav = navDetails.filter( const updatedNav = navDetails.filter((sponsor) => sponsor.id !== actionId);
(sponsor) => sponsor.id !== actionId
);
setTimeout(() => { setTimeout(() => {
setNavDetails(updatedNav); setNavDetails(updatedNav);
@@ -121,12 +137,11 @@ const Destribution = () => {
setIsLoading(true); setIsLoading(true);
}; };
const Total = () => { const Total = () => {
return ( return (
<Table size="sm"> <Table size="sm">
<Tbody> <Tbody>
<Tr backgroundColor="gray.50"> <Tr backgroundColor="gray.50">
<Th <Th
textAlign={"center"} textAlign={"center"}
p={3} p={3}
@@ -147,8 +162,13 @@ const Destribution = () => {
wordBreak="normal" wordBreak="normal"
overflowWrap="normal" overflowWrap="normal"
> >
<Badge ms={1} colorScheme="green" me={1}>
<Badge ms={1} colorScheme="green" me={1}>$</Badge>{IODetails?.total_distributeToInvestor_amt?.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} $
</Badge>
{IODetails?.total_distributeToInvestor_amt?.toLocaleString(
undefined,
{ minimumFractionDigits: 2, maximumFractionDigits: 2 }
)}
</Th> </Th>
<Th <Th
textAlign={"center"} 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}> <AddIONav isOpen={isOpen} onClose={onClose} firstField={firstField} />
<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> </Box>
);
};
<NormalTable export default Destribution;
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

View File

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

View File

@@ -10,6 +10,7 @@ import {
DrawerOverlay, DrawerOverlay,
FormControl, FormControl,
FormErrorMessage, FormErrorMessage,
FormHelperText,
FormLabel, FormLabel,
Input, Input,
Stack, Stack,
@@ -26,7 +27,8 @@ import { useParams } from "react-router-dom";
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
const investmentVideoSchema = yup.object().shape({ 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() artifactStreamingURL: yup.string()
.required("Artifact streaming URL is required") .required("Artifact streaming URL is required")
.url("Invalid URL format"), .url("Invalid URL format"),
@@ -152,21 +154,25 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, da
<DrawerBody> <DrawerBody>
<Stack spacing={4}> <Stack spacing={4}>
<FormControl isInvalid={errors.artifactName}> <FormControl isInvalid={errors.artifactName} isRequired>
<FormLabel fontSize={"sm"}>Artifact Name</FormLabel> <FormLabel fontSize={"sm"}>Artifact Name</FormLabel>
<Controller <Controller
name="artifactName" name="artifactName"
control={control} control={control}
render={({ field }) => ( 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}> <FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.artifactName?.message} {errors.artifactName?.message}
</FormErrorMessage> </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>
<FormControl isInvalid={errors.artifactStreamingURL}> <FormControl isInvalid={errors.artifactStreamingURL} isRequired>
<FormLabel fontSize={"sm"}>Artifact Streaming URL</FormLabel> <FormLabel fontSize={"sm"}>Artifact Streaming URL</FormLabel>
<Controller <Controller
name="artifactStreamingURL" name="artifactStreamingURL"
@@ -211,7 +217,7 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, da
isOpen={alert} isOpen={alert}
onClose={() => setAlert(false)} onClose={() => setAlert(false)}
alertHandler={handleSave} alertHandler={handleSave}
message={"Are you sure you want to add this artifact?"} message={"Are you sure you want to update this artifact?"}
isLoading={isLoading} 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 formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
const IOCashDetails = () => { const IOCashDetailsOld = () => {
const toast = useToast(); const toast = useToast();
const firstField = useRef(); const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
@@ -134,9 +134,9 @@ const IOCashDetails = () => {
</Badge> </Badge>
{/* {parseFloat(item.transactionAmount || 0).toLocaleString()} */} {/* {parseFloat(item.transactionAmount || 0).toLocaleString()} */}
{`${parseFloat(item.transactionAmount || 0).toLocaleString(undefined, { {`${parseFloat(item.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})}`} })}`}
</Text> </Text>
), ),
Comments: ( Comments: (
@@ -180,8 +180,6 @@ const IOCashDetails = () => {
), ),
})); }));
const customHeaders = [ const customHeaders = [
{ label: "Date", key: "transactionDate" }, { label: "Date", key: "transactionDate" },
{ label: "Transaction type", key: "transactionType" }, { label: "Transaction type", key: "transactionType" },
@@ -192,12 +190,12 @@ const IOCashDetails = () => {
// Add more headers as needed // Add more headers as needed
]; ];
const ioCashExporteDetails = IODetails?.ioCashHistory?.map((item, index) =>({ const ioCashExporteDetails = IODetails?.ioCashHistory?.map((item, index) => ({
"Date": item?.transactionDate, Date: item?.transactionDate,
"Transaction type": item?.transactionType, "Transaction type": item?.transactionType,
"Amount":parseFloat(item?.transactionAmount) || 0, Amount: parseFloat(item?.transactionAmount) || 0,
"Comments": item?.comments Comments: item?.comments,
})) }));
console.log(ioCashExporteDetails); console.log(ioCashExporteDetails);
@@ -312,8 +310,7 @@ const IOCashDetails = () => {
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
/> />
<HStack display={"flex"} alignItems={"center"}>
<HStack display={"flex"} alignItems={"center"}>
<Button <Button
onClick={() => onClick={() =>
exportToExcelNew(ioCashExporteDetails, "IO Cash History") exportToExcelNew(ioCashExporteDetails, "IO Cash History")
@@ -324,25 +321,24 @@ const IOCashDetails = () => {
variant={"outline"} variant={"outline"}
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} fontSize={"xs"}
isDisabled={ioCashExporteDetails?.length === 0} isDisabled={ioCashExporteDetails?.length === 0}
> >
Export xls Export xls
</Button> </Button>
{IODetails?.isInvestedAmount ? ( {IODetails?.isInvestedAmount ? (
<Button <Button
onClick={onOpen} onClick={onOpen}
leftIcon={<AddIcon />} leftIcon={<AddIcon />}
colorScheme="forestGreen" colorScheme="forestGreen"
size={"sm"} size={"sm"}
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} fontSize={"xs"}
> >
Add IO Cash Add IO Cash
</Button> </Button>
) : null} ) : null}
</HStack> </HStack>
</HStack> </HStack>
</Box> </Box>
@@ -376,4 +372,4 @@ const IOCashDetails = () => {
); );
}; };
export default IOCashDetails; export default IOCashDetailsOld;

View File

@@ -70,7 +70,7 @@ const schema = yup.object().shape({
InvestmentDetails: yup.string().notRequired(), InvestmentDetails: yup.string().notRequired(),
comment: yup.string().notRequired() comment: yup.string().notRequired()
.min(10, "Comment must be at least 10 characters long") // .min(10, "Comment must be at least 10 characters long")
.max(100, "Comment must be at most 100 characters long"), .max(100, "Comment must be at most 100 characters long"),
expectedReturn: yup expectedReturn: yup

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 <CustomAlertDialog
onClose={() => setDeleteAlert(false)} onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert} isOpen={deleteAlert}
message="Are you sure you want to delete the sponsor?" message="Are you sure you want to delete the Investment?"
alertHandler={handleDelete} alertHandler={handleDelete}
isLoading={isLoading} isLoading={isLoading}
/> />

View File

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

View File

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

View File

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

View File

@@ -10,6 +10,7 @@ import {
DrawerOverlay, DrawerOverlay,
FormControl, FormControl,
FormErrorMessage, FormErrorMessage,
FormHelperText,
FormLabel, FormLabel,
Icon, Icon,
Image, Image,
@@ -35,7 +36,7 @@ import { IoMdRemoveCircleOutline } from "react-icons/io";
const investmentImageSchema = yup.object().shape({ const investmentImageSchema = yup.object().shape({
artifactName: yup.string().required("Artifact image name is required") 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"), artifactPathName: yup.mixed().required("Artifact image is required"),
}); });
@@ -226,19 +227,24 @@ const IOArtifactsAdd = ({
<Controller <Controller
name="artifactName" name="artifactName"
control={control} control={control}
// maxLength={50}
render={({ field }) => ( render={({ field }) => (
<Input <Input
{...field} {...field}
fontSize={"sm"} fontSize={"sm"}
type="text" type="text"
size={"sm"} size={"sm"}
maxLength={25} maxLength={50}
/> />
)} )}
/> />
<FormErrorMessage fontSize={"xs"} fontWeight={500}> <FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.artifactName?.message} {errors.artifactName?.message}
</FormErrorMessage> </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>
<FormControl <FormControl
@@ -354,7 +360,7 @@ const IOArtifactsAdd = ({
isOpen={alert} isOpen={alert}
onClose={handleAlertClose} onClose={handleAlertClose}
alertHandler={handleSave} alertHandler={handleSave}
message={"Are you sure you want to add this artifact?"} message={"Are you sure you want to update this artifact?"}
isLoading={loading} isLoading={loading}
/> />
</> </>

View File

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

View File

@@ -360,7 +360,7 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
onClose={handleClose} onClose={handleClose}
// alertHandler={handleSave} // alertHandler={handleSave}
alertHandler={handleConfirm} 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} isLoading={isLoading}
/> />
</> </>

View File

@@ -82,12 +82,16 @@ const KeyMeritsEdit = ({
meritsDescription: found?.meritsDescription, meritsDescription: found?.meritsDescription,
meritsHeaderArabic: found?.meritsHeaderArabic, meritsHeaderArabic: found?.meritsHeaderArabic,
meritsDescriptionArabic: found?.meritsDescriptionArabic, meritsDescriptionArabic: found?.meritsDescriptionArabic,
iconImage: null, icon_xid: found?.icon_xid,
}); });
console.log("==============",found);
} }
}, [found, reset]); }, [found, reset]);
const onSubmit = async (data) => { const onSubmit = async (data) => {
console.log(data);
setIsLoading(true); setIsLoading(true);
try { try {
const id = actionId; const id = actionId;
@@ -97,6 +101,9 @@ const KeyMeritsEdit = ({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
handleClose() handleClose()
reset({
meritsHeader: "",
});
return; return;
} }
if (res?.error?.data?.code === 400) { if (res?.error?.data?.code === 400) {
@@ -106,6 +113,7 @@ const KeyMeritsEdit = ({
), ),
}); });
handleClose() handleClose()
reset();
return; return;
} }
} catch (error) { } catch (error) {
@@ -288,7 +296,7 @@ const KeyMeritsEdit = ({
alt={selectedImageIcon} alt={selectedImageIcon}
boxSize="1rem" boxSize="1rem"
mr="12px" mr="12px"
/>}{" "} />}
<Text as={"span"} fontSize={"sm"} fontWeight={500}> <Text as={"span"} fontSize={"sm"} fontWeight={500}>
{selectedIcon} {selectedIcon}
</Text> </Text>
@@ -359,7 +367,7 @@ const KeyMeritsEdit = ({
isOpen={alert} isOpen={alert}
onClose={() => setAlert(false)} onClose={() => setAlert(false)}
alertHandler={handleSave} 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} isLoading={isLoading}
/> />
</> </>

View File

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

View File

@@ -28,8 +28,10 @@ import NormalData from "../../../../Components/DataTable/NormalTable";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { AddIcon } from "@chakra-ui/icons"; import { AddIcon } from "@chakra-ui/icons";
import { import {
useAddIOTransactionMutation,
useGetDistributedToInvestorMutation, useGetDistributedToInvestorMutation,
useGetDistributionInvestorMutation, useGetDistributionInvestorMutation,
useSaveIOTransactionMutation,
useUpdateExitToInvestorMutation, useUpdateExitToInvestorMutation,
} from "../../../../Services/io.service"; } from "../../../../Services/io.service";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
@@ -42,6 +44,7 @@ import CurrencyInput from "../../../../Components/CurrencyInput";
import { IoCalculator } from "react-icons/io5"; import { IoCalculator } from "react-icons/io5";
import { debounce } from "../../../Master/Sponser/AddSponser"; import { debounce } from "../../../Master/Sponser/AddSponser";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { validate } from "uuid";
@@ -101,6 +104,8 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
resolver: yupResolver(investorExit), resolver: yupResolver(investorExit),
}); });
const [saveIOTransaction] = useSaveIOTransactionMutation();
// ====================================================[Table Setup]================================================================ // ====================================================[Table Setup]================================================================
@@ -314,45 +319,81 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
} catch (error) {} } 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) => { const onFinalSubmit = async (data) => {
setIsFinalCalculateLoading(true); setIsFinalCalculateLoading(true);
if (!isCalcualtedData) { const currentDate = new Date();
setIsFinalCalculateLoading(false); const dataToSend = {
return toast({ transactionDate: currentDate,
render: () => (
<ToastBox
message={"Please calculate investment first."}
status="warn"
/>
),
});
}
const finalData = {
transactionAmount: data?.amount, transactionAmount: data?.amount,
}; }
console.log("dataaaaaaa",dataToSend);
try { try {
const res = await getFinalDistributionInvestment({ id, data: finalData }); const res = await saveIOTransaction({ id,data: dataToSend });
console.log(finalData); console.log(res?.data?.data);
onClose();
if (res?.error?.status === 401) { if (!isCalcualtedData) {
setIsFinalCalculateLoading(false);
return toast({
render: () => (
<ToastBox
message={"Please calculate investment first."}
status="warn"
/>
),
});
} else if (res?.error) {
toast({ toast({
render: () => ( render: () => (
<ToastBox message={res?.error?.data?.message} status="error" /> <ToastBox status={"error"} message={res?.error?.data?.message} />
), ),
}); });
} else if (res?.data?.statusCode === 200) { // setIsLoading(false);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
handleClose();
} }
} catch (error) { } catch (error) {}
console.error("An error occurred:", error);
} finally {
handleClose();
}
}; };
const handleClose = () => { const handleClose = () => {

View File

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

View File

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

View File

@@ -1,7 +1,10 @@
import { import {
Box, Box,
Button, Button,
Icon,
Input, Input,
keyframes,
Stack,
Tab, Tab,
TabList, TabList,
TabPanel, TabPanel,
@@ -16,7 +19,7 @@ import { useContext, useEffect, useState } from "react";
import FormInputView from "../../../Components/FormInputView"; import FormInputView from "../../../Components/FormInputView";
import { useForm } from "react-hook-form"; // assuming react-hook-form is used import { useForm } from "react-hook-form"; // assuming react-hook-form is used
import { OPACITY_ON_LOAD } from "../../../Layout/animations"; 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 CustomAlertDialog from "../../../Components/CustomAlertDialog";
import ViewIOdataHeader from "./ViewIOdataHeader"; import ViewIOdataHeader from "./ViewIOdataHeader";
import ViewIOdetails from "./ViewIOdetails"; import ViewIOdetails from "./ViewIOdetails";
@@ -32,21 +35,41 @@ import KeyMerits from "../CreateIO/KeyMerits";
import Investors from "../CreateIO/Investors"; import Investors from "../CreateIO/Investors";
import EditIO from "../EditIO/EditIO"; import EditIO from "../EditIO/EditIO";
import IOArtifacts from "../CreateIO/IOArtifacts"; import IOArtifacts from "../CreateIO/IOArtifacts";
import IOCashDetails from "../CreateIO/IOCashDetails"; // import IOCashDetails from "../CreateIO/IOCashDetailsold";
import IONAVDetails from "../CreateIO/IONAVDetails"; // import IONAVDetails from "../CreateIO/IONAVDetailsOld";
import { useGetIOprepopulateDataQuery } from "../../../Services/io.service"; import { useGetIOByIdQuery, useGetIOprepopulateDataQuery } from "../../../Services/io.service";
import UnderConstruction from "../../UnderConstruction"; import UnderConstruction from "../../UnderConstruction";
import Destribution from "../CreateIO/Destribution"; 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 ViewIOdata = () => {
const params = useParams(); const params = useParams();
const id = params?.id; 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 { isOpen, onOpen, onClose } = useDisclosure();
const navigate = useNavigate(); const navigate = useNavigate();
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [isRefetchLoading, setIsRefetchLoading] = useState(false);
const { IODetails, setIODetails } = useContext(GlobalStateContext); const { IODetails, setIODetails } = useContext(GlobalStateContext);
console.log(IODetails?.isInvestedAmount); console.log(IODetails?.isInvestedAmount);
const tabs = [ const tabs = [
{ label: "IO Details", content: <ViewIOdetails data={data?.data} /> }, { label: "IO Details", content: <ViewIOdetails data={data?.data} /> },
@@ -64,9 +87,22 @@ const ViewIOdata = () => {
label: "Distribution to Investors", label: "Distribution to Investors",
content: <Destribution data={data?.data} />, content: <Destribution data={data?.data} />,
}, },
{
label: "IO Transaction",
content: <IOTransaction data={data?.data} />,
},
// { label: "Distribution to Investors", content: <UnderConstruction h={'75vh'} /> }, // { label: "Distribution to Investors", content: <UnderConstruction h={'75vh'} /> },
]; ];
const handleRefresh = async () => {
setIsRefetchLoading(true);
await IObyIDrefetch();
setIsRefetchLoading(false);
};
console.log(IODetails?.ioNAVHistory);
return ( return (
<Box <Box
{...OPACITY_ON_LOAD} {...OPACITY_ON_LOAD}
@@ -87,7 +123,7 @@ const ViewIOdata = () => {
<Tabs mt={4}> <Tabs mt={4}>
<TabList justifyContent={"space-between"} pe={4} alignItems={"center"}> <TabList justifyContent={"space-between"} pe={4} alignItems={"center"}>
<Box display={"flex"}> <Box display={"flex"} position={"relative"} w={"100%"}>
{tabs.map(({ label }, index) => ( {tabs.map(({ label }, index) => (
<Tab <Tab
px={3} px={3}
@@ -96,20 +132,80 @@ const ViewIOdata = () => {
index === 1 || index === 1 ||
index === 2 || index === 2 ||
index === 3 || index === 3 ||
index === 4 index === 4 ||
index === 8
? false ? false
: !IODetails?.isInvestedAmount : !IODetails?.isInvestedAmount
} }
// isDisabled={
// index === 0 ||
// index === 1 ||
// index === 2 ||
// index === 3 ||
// index === 4
// ? false
// : !IODetails?.isInvestedAmount
// }
key={index} key={index}
fontSize={"sm"} fontSize={"xs"}
_selected={{ _selected={{
color: "#004118", color: "#004118",
borderBottom: "2px solid #38a169", 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> </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> </Box>
</TabList> </TabList>
<TabPanels> <TabPanels>

View File

@@ -24,6 +24,7 @@ import {
Box, Box,
Icon, Icon,
HStack, HStack,
useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import header from "../../../assets/IOheader.png"; import header from "../../../assets/IOheader.png";
import { HiDotsVertical } from "react-icons/hi"; import { HiDotsVertical } from "react-icons/hi";
@@ -41,12 +42,15 @@ import Cancle from "./HeaderModal/Cancle";
import { AddIcon } from "@chakra-ui/icons"; import { AddIcon } from "@chakra-ui/icons";
import { GrGallery } from "react-icons/gr"; import { GrGallery } from "react-icons/gr";
import Loader01 from "../../../Components/Loaders/Loader01"; import Loader01 from "../../../Components/Loaders/Loader01";
import { useUpdateTransactionMutation } from "../../../Services/io.service";
import ToastBox from "../../../Components/ToastBox";
// import { formatCurrency } from "../../../Components/CurrencyInput"; // import { formatCurrency } from "../../../Components/CurrencyInput";
// import { removeTrailingZeros } from "../../../Constants/Constants"; // import { removeTrailingZeros } from "../../../Constants/Constants";
const ViewIOdataHeader = ({ data, isLoading }) => { const ViewIOdataHeader = ({ data, isLoading }) => {
const params = useParams(); const params = useParams()
const id = params?.id; const toast = useToast();
const id = params?.id
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const btnRef = useRef(); const btnRef = useRef();
const { IODetails, isIOloading } = useContext(GlobalStateContext); const { IODetails, isIOloading } = useContext(GlobalStateContext);
@@ -108,11 +112,95 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
IODetails?.artifactsImage?.[0]?.artifactPathName 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 = [ const menu = [
{ {
id: 1, id: 1,
title: "Amount Invested", title: "Amount Invested",
onClickFunction: onInvestmentOpen, onClickFunction: handleInvestment,
}, },
// { // {
// id:2, // id:2,
@@ -127,8 +215,8 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
{ {
id: 6, id: 6,
title: "Distribution To Investors", title: "Distribution To Investors",
onClickFunction: onDistInvestorOpen, onClickFunction: handleDistributionInvestors,
}, },
{ {
id: 5, id: 5,
title: "Update IO NAV", title: "Update IO NAV",
@@ -137,7 +225,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
{ {
id: 8, id: 8,
title: "Exit", title: "Exit",
onClickFunction: onExitOpen, onClickFunction: handleExit,
}, },
{ {
id: 9, id: 9,
@@ -444,8 +532,8 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
alignItems={"start"} alignItems={"start"}
height={"95px"} height={"95px"}
> >
<Menu> {localStorage?.getItem("role") === "Maker" && <Menu>
<MenuButton <MenuButton
className="link p-1 rounded-1 " className="link p-1 rounded-1 "
bg={"#fff"} bg={"#fff"}
_hover={{ backgroundColor: "#fff !important" }} _hover={{ backgroundColor: "#fff !important" }}
@@ -476,7 +564,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
</MenuItem> </MenuItem>
))} ))}
</MenuList> </MenuList>
</Menu> </Menu>}
{/* Modals */} {/* Modals */}
<AmountInvested isOpen={isInvestmentOpen} onClose={onInvestmentClose} /> <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 React, { useContext, useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
@@ -240,11 +240,6 @@ const ViewIOdetails = () => {
width: "32.3%", width: "32.3%",
value: IObyID?.data?.isShariah, value: IObyID?.data?.isShariah,
}, },
{ {
label: "Investment Type", label: "Investment Type",
placeHolder: "Select option", placeHolder: "Select option",
@@ -351,19 +346,22 @@ const ViewIOdetails = () => {
return ( return (
<Box position={"relative"}> <Box position={"relative"}>
<Button <Box display={"flex"} justifyContent={"space-between"}>
position={"absolute"} <Text></Text>
top={"-62px"} <Button
right={0} // position={"absolute"}
onClick={() => navigate(`/create-io/${params?.id}`)} // top={"-62px"}
ps={4} right={0}
pe={4} onClick={() => navigate(`/create-io/${params?.id}`)}
colorScheme="forestGreen" ps={4}
rounded={"sm"} pe={4}
size={"xs"} colorScheme="forestGreen"
> rounded={"sm"}
Edit IO size={"xs"}
</Button> >
Edit IO
</Button>
</Box>
<FormInputView groupedFields={groupedFields} /> <FormInputView groupedFields={groupedFields} />
</Box> </Box>
); );

View File

@@ -6,8 +6,6 @@ import {
HStack, HStack,
Input, Input,
Select, Select,
Switch,
Tag,
Text, Text,
Tooltip, Tooltip,
useDisclosure, useDisclosure,
@@ -103,7 +101,6 @@ const InvestorDetails = () => {
// ====================================================[Table Setup]================================================================ // ====================================================[Table Setup]================================================================
const tableHeadRow = [ const tableHeadRow = [
"Sr No", "Sr No",
"Client ID", "Client ID",
"First Name", "First Name",
"Last Name", "Last Name",
@@ -216,13 +213,14 @@ const InvestorDetails = () => {
as={'span'} as={'span'}
fontWeight={"700"} fontWeight={"700"}
textTransform={"none"} textTransform={"none"}
color={item.ioStatus ? "gray.500":item.kycStatus ? "blue.500" : "red.500"} color={item?.KYCStatus === true ? "green" : "yellow.500"}
px={2} px={2}
py={0.5} py={0.5}
variant={'solid'} variant={'solid'}
> >
{item.KYCStatus ? "Completed" : "Not complete"} {/* {item.KYCStatus ? "Completed" : "Not complete"} */}
{item?.KYCStatus === true ? "Completed" : "NotCompleted"}
</Text> </Text>
</Box> </Box>
), ),

View File

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

View File

@@ -24,7 +24,7 @@ export const addInvestmentType = yup.object().shape({
.string() .string()
.required("Investment type is required") .required("Investment type is required")
.max(50, "Investment name cannot be more than 50 characters"), .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 investmentTypeNameArabic: yup
.string() .string()
.required("Investment type in required"), .required("Investment type in required"),
@@ -199,7 +199,7 @@ const AddInvestmentType = () => {
placeHolder: " ", placeHolder: " ",
name: "note", name: "note",
type: "textarea", type: "textarea",
// isRequired: true, isRequired: false,
section: "", section: "",
maxLength: 255, maxLength: 255,
helperText: `Maximum length should be 255 characters. You have entered ${ helperText: `Maximum length should be 255 characters. You have entered ${
@@ -211,7 +211,7 @@ const AddInvestmentType = () => {
placeHolder: " ", placeHolder: " ",
name: "noteArabic", name: "noteArabic",
type: "textarea", type: "textarea",
// isRequired: true, isRequired: false,
arabic: true, arabic: true,
section: "", section: "",
maxLength: 255, maxLength: 255,
@@ -254,7 +254,7 @@ const AddInvestmentType = () => {
placeHolder: " ", placeHolder: " ",
name: "note", name: "note",
type: "textarea", type: "textarea",
// isRequired: true, isRequired: false,
section: "", section: "",
maxLength: 255, maxLength: 255,
helperText: `Maximum length should be 255 characters. You have entered ${ helperText: `Maximum length should be 255 characters. You have entered ${
@@ -266,7 +266,7 @@ const AddInvestmentType = () => {
placeHolder: " ", placeHolder: " ",
name: "noteArabic", name: "noteArabic",
type: "textarea", type: "textarea",
// isRequired: true, isRequired: false,
arabic: true, arabic: true,
section: "", section: "",
maxLength: 255, maxLength: 255,
@@ -338,7 +338,7 @@ const AddInvestmentType = () => {
isOpen={alert} isOpen={alert}
onClose={() => setAlert(false)} onClose={() => setAlert(false)}
alertHandler={handleConfirm} 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} isLoading={isLoadingBtn}
/> />
</Box> </Box>

View File

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

View File

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

View File

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

View File

@@ -3,6 +3,7 @@ import {
Box, Box,
Button, Button,
FormControl, FormControl,
FormHelperText,
FormLabel, FormLabel,
Heading, Heading,
HStack, HStack,
@@ -36,7 +37,8 @@ const FILE_TYPES = ["image/jpeg", "image/png", "image/gif"];
export const conformModalSchema = yup.object().shape({ export const conformModalSchema = yup.object().shape({
investorAmount: yup.string().required("Investor amount is required"), 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 = ({ const DrawalRequestApprove = ({
@@ -59,6 +61,7 @@ const DrawalRequestApprove = ({
const { const {
control, control,
register, register,
watch,
reset, reset,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
@@ -259,12 +262,17 @@ const DrawalRequestApprove = ({
size="sm" size="sm"
placeholder={"Enter your comments...."} placeholder={"Enter your comments...."}
resize={"none"} resize={"none"}
maxLength={200}
/> />
{errors.comment && ( {errors.comment && (
<Text fontSize="xs" color="red"> <Text fontSize="xs" color="red">
{errors.comment.message} {errors.comment.message}
</Text> </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> </FormControl>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View File

@@ -2,6 +2,7 @@ import {
Box, Box,
Button, Button,
FormControl, FormControl,
FormHelperText,
FormLabel, FormLabel,
Input, Input,
Modal, Modal,
@@ -24,7 +25,8 @@ import {
import { useDepositRejectMutation } from "../../../Services/drawal.request.service"; import { useDepositRejectMutation } from "../../../Services/drawal.request.service";
export const conformModalSchema = yup.object().shape({ 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}) => { const DrawalRequestReject = ({ isOpen, onClose, firstField ,id}) => {
@@ -34,6 +36,7 @@ import { useDepositRejectMutation } from "../../../Services/drawal.request.servi
const { const {
register, register,
watch,
reset, reset,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
@@ -101,16 +104,21 @@ import { useDepositRejectMutation } from "../../../Services/drawal.request.servi
placeholder={"Enter your comments...."} placeholder={"Enter your comments...."}
rounded={"md"} rounded={"md"}
resize={"none"} resize={"none"}
maxLength={200}
/> />
{errors.comments && ( {errors.comments && (
<Text fontSize="xs" color="red"> <Text fontSize="xs" color="red">
{errors.comments.message} {errors.comments.message}
</Text> </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> </FormControl>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button
colorScheme="gray" colorScheme="gray"
mr={3} mr={3}
onClick={onClose} onClick={onClose}

View File

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

View File

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