diff --git a/src/Components/CurrencyInput.jsx b/src/Components/CurrencyInput.jsx index c972aee..573c341 100644 --- a/src/Components/CurrencyInput.jsx +++ b/src/Components/CurrencyInput.jsx @@ -1,36 +1,32 @@ import React, { forwardRef } from 'react'; import { Input } from "@chakra-ui/react"; -// export const formatCurrency = (value) => { -// if (!value) return ''; -// const [integer, decimal] = value.split('.'); -// const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ','); -// return decimal ? `${formattedInteger}.${decimal}` : formattedInteger; -// }; - export const formatCurrency = (value) => { - if (value === undefined || value === null) return ''; // Handle undefined or null values - const [integer, decimal] = String(value).split('.'); // Convert value to string before splitting + if (value === undefined || value === null) return ''; + const [integer, decimal] = String(value).split('.'); const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ','); - return decimal ? `${formattedInteger}.${decimal}` : formattedInteger; + return decimal !== undefined ? `${formattedInteger}.${decimal}` : formattedInteger; }; const CurrencyInput = forwardRef(({ value, onChange, ...props }, ref) => { - - const handleChange = (event) => { let { value } = event?.target; // Remove non-numeric characters except decimal point - value = value?.replace(/[^0-9.]/g, ''); + value = value.replace(/[^0-9.]/g, ''); // Ensure only one decimal point - const parts = value?.split('.'); + const parts = value.split('.'); if (parts.length > 2) { - value = parts[0] + '.' + parts?.slice(1)?.join(''); + value = parts[0] + '.' + parts.slice(1).join(''); } - onChange(value); // Pass the raw value to parent or use it directly + // Restrict to two decimal places + if (parts[1]?.length > 2) { + value = parts[0] + '.' + parts[1].slice(0, 2); + } + + onChange(value); // Pass the raw value to parent }; return ( @@ -45,3 +41,50 @@ const CurrencyInput = forwardRef(({ value, onChange, ...props }, ref) => { }); export default CurrencyInput; + + + + +// import React, { forwardRef } from 'react'; +// import { Input } from "@chakra-ui/react"; + +// export const formatCurrency = (value) => { +// if (value === undefined || value === null) return ''; // Handle undefined or null values +// const [integer, decimal] = String(value).split('.'); // Convert value to string before splitting +// const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ','); +// return decimal ? `${formattedInteger}.${decimal}` : formattedInteger; +// }; + +// const CurrencyInput = forwardRef(({ value, onChange, ...props }, ref) => { + +// const handleChange = (event) => { +// let { value } = event?.target; + +// // Remove non-numeric characters except decimal point +// value = value?.replace(/[^0-9.]/g, ''); + +// // Ensure only one decimal point and restrict to two decimal places +// const parts = value?.split('.'); +// if (parts.length > 2) { +// value = parts[0] + '.' + parts?.slice(1)?.join(''); +// } + +// if (parts[1]?.length > 2) { +// value = parts[0] + '.' + parts[1]?.slice(0, 2); +// } + +// onChange(value); // Pass the raw value to parent or use it directly +// }; + +// return ( +// +// ); +// }); + +// export default CurrencyInput; diff --git a/src/Components/FormField.jsx b/src/Components/FormField.jsx index abf6817..c18c14f 100644 --- a/src/Components/FormField.jsx +++ b/src/Components/FormField.jsx @@ -477,8 +477,8 @@ const FormField = ({ placeholder={placeHolder ? placeHolder : label} textAlign={arabic ? "right" : align ? align : "left"} _placeholder={{ fontSize: "sm" }} - min={type === "date" ? today : undefined} - maxLength={maxLength} + // min={type === "date" ? today : undefined} + // maxLength={maxLength} // defaultValue={type === "date" && "2023-07-26" : undefined} // defaultValue={value} // value={dateValue} diff --git a/src/Constants/Constants.js b/src/Constants/Constants.js index 6031b55..9d4b34a 100644 --- a/src/Constants/Constants.js +++ b/src/Constants/Constants.js @@ -1,5 +1,6 @@ import dns from "node:dns" +import * as XLSX from 'xlsx'; export const generateSerialNumber = (index, currentPage, pageSize) => { @@ -145,4 +146,53 @@ export function calculatePercentage(part, total) { return 0; // To avoid division by zero } return (part / total) * 100; -} \ No newline at end of file +} + +export const exportToExcel = (data, customHeaders, fileName = 'exported-data.xlsx') => { + // Map your data to include only the fields that match your custom headers + const mappedData = data.map(item => + customHeaders.map(header => item[header.key] || '') + ); + + // Prepend the headers row + const sheetData = [customHeaders.map(header => header.label), ...mappedData]; + + // Create a worksheet from the data array + const worksheet = XLSX.utils.aoa_to_sheet(sheetData); + + // Apply styles to header cells + customHeaders.forEach((header, index) => { + const cellAddress = XLSX.utils.encode_cell({ r: 0, c: index }); // r: row, c: column + if (!worksheet[cellAddress]) return; // Skip if cell doesn't exist + + worksheet[cellAddress].s = { + fill: { + fgColor: { rgb: "FFFF00" } // Set header background color (Yellow in this case) + }, + font: { + bold: true, // Make header text bold + color: { rgb: "000000" } // Set header text color (Black in this case) + } + }; + }); + + // Create a new workbook and append the worksheet + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); + + // Generate a buffer from the workbook + const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' }); + + // Create a Blob object from the buffer + const dataBlob = new Blob([excelBuffer], { type: 'application/octet-stream' }); + + // Create a link element to trigger the download + const link = document.createElement('a'); + link.href = URL.createObjectURL(dataBlob); + link.download = fileName; + + // Append the link to the document body, trigger the download, and remove the link + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +}; diff --git a/src/Pages/Deposit/DepositRequest/DepositRequest.jsx b/src/Pages/Deposit/DepositRequest/DepositRequest.jsx index 25f144a..750a6f8 100644 --- a/src/Pages/Deposit/DepositRequest/DepositRequest.jsx +++ b/src/Pages/Deposit/DepositRequest/DepositRequest.jsx @@ -161,7 +161,7 @@ const DepositRequest = () => { ), "First Name": ( - + {item?.firstName} diff --git a/src/Pages/IO_Management/CreateIO/AddIONav.jsx b/src/Pages/IO_Management/CreateIO/AddIONav.jsx index 98acdf5..84d91c0 100644 --- a/src/Pages/IO_Management/CreateIO/AddIONav.jsx +++ b/src/Pages/IO_Management/CreateIO/AddIONav.jsx @@ -11,10 +11,13 @@ import { FormControl, FormErrorMessage, FormLabel, + HStack, Input, Select, Stack, + Text, Textarea, + VStack, useToast, } from "@chakra-ui/react"; import * as yup from "yup"; @@ -123,7 +126,15 @@ import { formatDatee } from "../../../Components/FormField"; -const today = formatDatee(new Date(), 'yyyy-MM-dd'); +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)); @@ -162,7 +173,7 @@ const today = formatDatee(new Date(), 'yyyy-MM-dd'); - Transaction Amount + New NAV - + + + + + Current nav + {parseFloat(IODetails?.ioNAV || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + + + + + Live return % + {calculatePercentage(watch()?.transactionAmount||IODetails?.ioNAV,IODetails?.ioNAV)} + + + diff --git a/src/Pages/IO_Management/CreateIO/Destribution.jsx b/src/Pages/IO_Management/CreateIO/Destribution.jsx index c53d1e2..4b031a3 100644 --- a/src/Pages/IO_Management/CreateIO/Destribution.jsx +++ b/src/Pages/IO_Management/CreateIO/Destribution.jsx @@ -1,6 +1,6 @@ import React, { useContext, useEffect, useRef, useState } from 'react' import GlobalStateContext from '../../../Contexts/GlobalStateContext'; -import { Box, HStack, Input,Text, Table, Tbody, Th, Tr, Avatar, useDisclosure,Button } from '@chakra-ui/react'; +import { Box, HStack, Input,Text, Table, Tbody, Th, Tr, Avatar, useDisclosure,Button, Badge } from '@chakra-ui/react'; import { OPACITY_ON_LOAD } from '../../../Layout/animations'; import Pagination from '../../../Components/Pagination'; import NormalTable from '../../../Components/DataTable/NormalTable'; @@ -86,9 +86,7 @@ const Destribution = () => { fontWeight={"500"} className="d-flex align-items-center web-text-small" > - {/* {`${item.transactionAmount}`} */} - - {/* {`$${parseFloat(item.transactionAmount||0).toLocaleString()}`} */} + $ {`${parseFloat(item.transactionAmount || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, diff --git a/src/Pages/IO_Management/CreateIO/IOCashDetails.jsx b/src/Pages/IO_Management/CreateIO/IOCashDetails.jsx index 6f471c4..a1423fc 100644 --- a/src/Pages/IO_Management/CreateIO/IOCashDetails.jsx +++ b/src/Pages/IO_Management/CreateIO/IOCashDetails.jsx @@ -121,7 +121,7 @@ const IOCashDetails = () => { ), Amount: ( { @@ -166,21 +168,90 @@ const IODetails = ({ enableNextTab, index, data }) => { } ); + console.log(IObyID?.data?.minInvestmentAmt); - const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, country_xid,id })=>{ + + const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, currencyCode, country_xid,id })=>{ + console.log(currencyCode); return{ _id:id, id:country_xid, country: country?.countryName, value: removeTrailingZeros(minInvestmentAmt), logo: country?.flagIcon, - curr: country?.countryCode, + curr: currencyCode, } }) + + const schemaEdit = yup.object().shape({ + investmentNameEnglish: yup + .string() + .required("IO name in English is required") + .min(3, "IO name in English must be at least 3 characters long") + .max(150, "IO name in English must be at most 150 characters long"), + + investmentNameArabic: yup + .string() + .required("IO name in Arabic is required") + .min(3, "IO name in Arabic must be at least 3 characters long") + .max(50, "IO name in Arabic must be at most 50 characters long"), + + descriptionEnglish: yup + .string() + .required("Description in English is required") + .min(10, "Description in English must be at least 10 characters long") + .max(1000, "Description in English must be at most 1000 characters long"), + + descriptionArabic: yup + .string() + .required("Description in Arabic is required") + .min(10, "Description in Arabic must be at least 10 characters long") + .max(2000, "Description in Arabic must be at most 500 characters long"), + expectedReturnArabic: yup + .string() + .required("Expected return in Arabic is required"), + + goalAmount: yup + .number() + .typeError("Goal Amount is must be number") + .required('Goal amount is required') + .positive('Goal amount must be a positive number') + .min(IObyID?.data?.totalAmtInvestmentInUSD, `Goal amount should not be lesser then amount raised ${IObyID?.data?.totalAmtInvestmentInUSD}`), + closingDate: yup + .date() + .notRequired("Closing date is required") + .min(new Date(), "Closing date cannot be in the past"), + + holdingPeriod: yup.string().required("Holding period is required"), + holdingPeriodArabic: yup.string().required("Holding period is required"), + + // minInvestmentAmount: yup + // .number() + // .required("Minimum investment is required") + // .positive("Minimum investment must be a positive number") + // .min(1, "Minimum investment must be at least 1"), + + ISIN: yup.string().notRequired(), + + InvestmentDetails: yup.string().notRequired(), + + comment: yup.string().notRequired() + .min(10, "Comment must be at least 10 characters long") + .max(100, "Comment must be at most 100 characters long"), + + expectedReturn: yup + .string() + .required("Expected return is required"), + }); + + + const [values, setValues] = useState(id?minInvestmentById:miniValue); + + console.log(values); const formatNumber = (num) => { // Remove non-numeric characters and format with commas @@ -198,7 +269,7 @@ const IODetails = ({ enableNextTab, index, data }) => { handleSubmit, formState: { errors }, } = useForm({ - resolver: yupResolver(schema), + resolver: yupResolver(id ? schemaEdit : schema), }); useEffect(() => { diff --git a/src/Pages/IO_Management/CreateIO/IONAVDetails.jsx b/src/Pages/IO_Management/CreateIO/IONAVDetails.jsx index b518724..7ba16cf 100644 --- a/src/Pages/IO_Management/CreateIO/IONAVDetails.jsx +++ b/src/Pages/IO_Management/CreateIO/IONAVDetails.jsx @@ -22,6 +22,8 @@ import { formatDatee } from "../../../Components/FormField"; import { AddIcon } from "@chakra-ui/icons"; import AddIONav from "./AddIONav"; import { formatDate } from "../../Master/Sponser/Sponsers"; +import { LuFileSpreadsheet } from "react-icons/lu"; +import { exportToExcel } from "../../../Constants/Constants"; const IONAVDetails = () => { const { navDetails, setNavDetails, IODetails } = @@ -80,7 +82,7 @@ const IONAVDetails = () => { fontWeight={"500"} className="d-flex align-items-center web-text-small" > - {/* {formatDatee(item.transactionDate)} */} + {/* {/ {formatDatee(item.transactionDate)} /} */} {formatDate(item?.transactionDate)} ), @@ -90,17 +92,11 @@ const IONAVDetails = () => { as={"span"} color={"teal.900"} fontWeight={"500"} - className="d-flex align-items-left web-text-small" + className="d-flex align-items-center web-text-small" > - {/* {`${item.transactionAmount}`} */} - - - $ - - {parseFloat(item.transactionAmount || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} + {/* {/ {`${item.transactionAmount}`} /} */} + $ + {`${parseFloat(item.transactionAmount || 0).toLocaleString()}`} ), "Last NAV update": ( @@ -162,6 +158,23 @@ const IONAVDetails = () => { ), })); + const customHeaders = [ + { label: "ID", key: "id" }, + { label: "Valuation Date", key: "transactionDate" }, + { label: "NAV", key: "transactionAmount" }, + { label: "Last NAV update", key: "previousNAVvalue" }, + + { label: "Investment Closed", key: "initialNAVvalue" }, + { label: "Comments", key: "comments" }, + + { label: "Update by", key: "creator" }, + { label: "Transaction Type", key: "transactionType" }, + { label: "Comments", key: "comments" }, + // Add more headers as needed + ]; + + console.log(IODetails?.ioNAVHistory); + const handleDelete = () => { const updatedNav = navDetails.filter((sponsor) => sponsor.id !== actionId); @@ -173,6 +186,8 @@ const IONAVDetails = () => { setIsLoading(true); }; + const handleExport = () => {}; + return ( @@ -193,24 +208,34 @@ const IONAVDetails = () => { onChange={(e) => setSearchTerm(e.target.value)} /> - {/* - - */} - - {/* {IODetails?.isInvestedAmount ? :null} */} - - {IODetails?.isInvestedAmount ? ( + - ) : null} + + {IODetails?.isInvestedAmount ? ( + + ) : null} + diff --git a/src/Pages/IO_Management/CreateIO/Investors.jsx b/src/Pages/IO_Management/CreateIO/Investors.jsx index fedf87e..6bf12e7 100644 --- a/src/Pages/IO_Management/CreateIO/Investors.jsx +++ b/src/Pages/IO_Management/CreateIO/Investors.jsx @@ -39,8 +39,6 @@ import { FiRefreshCw } from "react-icons/fi"; import { useGetIOByIdQuery } from "../../../Services/io.service"; import { RepeatIcon } from "@chakra-ui/icons"; - - const rotate = keyframes` from { transform: rotate(0deg); @@ -52,21 +50,18 @@ const rotate = keyframes` const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter -const Investors = ({data}) => { - const params = useParams() - const id = params?.id +const Investors = ({ data }) => { + const params = useParams(); + const id = params?.id; const toast = useToast(); const { investors, setInvestors, slideFromRight, IODetails } = useContext(GlobalStateContext); - - const [ isRefetchLoading, setIsRefetchLoading ] = useState(false) - - const { - isLoading: IObyIDisLoading, - refetch - } = useGetIOByIdQuery(id, { skip: !id }); - + const [isRefetchLoading, setIsRefetchLoading] = useState(false); + + const { isLoading: IObyIDisLoading, refetch } = useGetIOByIdQuery(id, { + skip: !id, + }); const [searchTerm, setSearchTerm] = useState(""); const [isLoading, setIsLoading] = useState(true); @@ -137,9 +132,6 @@ const Investors = ({data}) => { return nameMatches; }); - - - const extractedArray = filteredData?.map((item, index) => ({ id: item?.id, "Client ID": ( @@ -177,17 +169,23 @@ const Investors = ({data}) => { ), "Investment amount": ( + + $ + {/* {`$${formatCurrency(item.InvestedAmount_USD)}`} */} - {`$${parseFloat(item.InvestedAmount_USD||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`} + {`${parseFloat(item.InvestedAmount_USD || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })}`} ), - "Percentage": ( + Percentage: ( { ), "Market Value": ( - {`$${parseFloat(item.Market_Value ||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`} + + $ + + {`${parseFloat(item.Market_Value || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })}`} ), "Return on Investment": ( @@ -221,16 +225,20 @@ const Investors = ({data}) => { {item.Return_On_Investment || 0} % ), - "Distribution": ( + Distribution: ( + $ {/* {`$${item.Distribution_Amt}`} */} - {`$${parseFloat(item.Distribution_Amt||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`} + {`$${parseFloat(item.Distribution_Amt || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })}`} ), "Distribution Percent": ( @@ -242,19 +250,26 @@ const Investors = ({data}) => { className="d-flex align-items-center web-text-small" > {/* {`$${item.Distribution_Amt}`} */} - {`${parseFloat(item.Distribution_Per||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} %`} + {`${parseFloat(item.Distribution_Per || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} %`} ), "Total Return": ( + $ {/* {`$${formatCurrency(item.Total_Return) || 0}`} */} - {`$${parseFloat(item.Total_Return||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`} + {`${parseFloat(item.Total_Return || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })}`} ), "Total return on Investment": ( @@ -265,7 +280,7 @@ const Investors = ({data}) => { fontWeight={"500"} className="d-flex align-items-center web-text-small" > - {item.Total_Return_On_Investment||0} % + {item.Total_Return_On_Investment || 0} % ), })); @@ -287,7 +302,7 @@ const Investors = ({data}) => { return ( - +
{ ); }; - - const handleRefresh = async() =>{ - setIsRefetchLoading(true) - await refetch() - setIsRefetchLoading(false) - } + const handleRefresh = async () => { + setIsRefetchLoading(true); + await refetch(); + setIsRefetchLoading(false); + }; return ( @@ -419,27 +433,60 @@ const Investors = ({data}) => { justifyContent={"space-between"} pb={3} spacing="24px" - > - setSearchTerm(e.target.value)} - /> - + setSearchTerm(e.target.value)} + /> + - - $ {parseFloat(IODetails?.totalAmtInvestmentInUSD).toLocaleString()} - Total Investment Amount ( USD ) - + + + Total Investment Amount ( USD ) + + $ + + {parseFloat(IODetails?.totalAmtInvestmentInUSD).toLocaleString()} + @@ -448,7 +495,7 @@ const Investors = ({data}) => { centered={true} emptyMessage={`We don't have any Sponers `} tableHeadRow={tableHeadRow} - data={extractedArray} + data={extractedArray} isLoading={isLoading} viewActionId={actionId} setViewActionId={setActionId} diff --git a/src/Pages/IO_Management/ViewIO/HeaderModal/DistributionInvestor.jsx b/src/Pages/IO_Management/ViewIO/HeaderModal/DistributionInvestor.jsx index 7444c44..483fd2f 100644 --- a/src/Pages/IO_Management/ViewIO/HeaderModal/DistributionInvestor.jsx +++ b/src/Pages/IO_Management/ViewIO/HeaderModal/DistributionInvestor.jsx @@ -25,7 +25,7 @@ import { useToast, } from "@chakra-ui/react"; import NormalData from "../../../../Components/DataTable/NormalTable"; -import { useState } from "react"; +import { useContext, useState } from "react"; import { AddIcon } from "@chakra-ui/icons"; import { useGetDistributedToInvestorMutation, @@ -41,19 +41,19 @@ import ToastBox from "../../../../Components/ToastBox"; import CurrencyInput from "../../../../Components/CurrencyInput"; import { IoCalculator } from "react-icons/io5"; import { debounce } from "../../../Master/Sponser/AddSponser"; +import GlobalStateContext from "../../../../Contexts/GlobalStateContext"; + -export const investor = yup.object().shape({ - amount: yup.string().required("Amount is required"), -}); const DistributionInvestor = ({ isOpen, onClose, exit }) => { 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 [ isCalculateLoading, setIsCalculateLoading ] = useState(false) + const [ isFinalCalculateLoading, setIsFinalCalculateLoading ] = useState(false) + const [ calcualtedData, setCalculatedDate ] = useState(null) + const [ isCalcualtedData, setIsCalcualtedData ] = useState(false) + const { IODetails } = useContext(GlobalStateContext); // const { // data:IObyID, @@ -66,13 +66,35 @@ const DistributionInvestor = ({ isOpen, onClose, exit }) => { useGetDistributedToInvestorMutation(); const [updateExitToInvestor] = useUpdateExitToInvestorMutation(); + 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 investor = yup.object().shape({ + amount: yup.string().required("Amount is required"), + }); + + const { control, handleSubmit, formState: { errors }, reset, } = useForm({ - resolver: yupResolver(investor), + resolver: yupResolver(!exit? investorExit: investor), }); // useEffect(()=>{ @@ -391,13 +413,7 @@ const DistributionInvestor = ({ isOpen, onClose, exit }) => { Calculate */} - + {errors.amount?.message} diff --git a/src/Pages/IO_Management/ViewIO/ViewIOdetails.jsx b/src/Pages/IO_Management/ViewIO/ViewIOdetails.jsx index dfbdaa8..7a40dd9 100644 --- a/src/Pages/IO_Management/ViewIO/ViewIOdetails.jsx +++ b/src/Pages/IO_Management/ViewIO/ViewIOdetails.jsx @@ -125,7 +125,7 @@ const ViewIOdetails = () => { country: country?.countryName, value: removeTrailingZeros(minInvestmentAmt), logo: country?.flagIcon, - curr: country?.countryCode, + curr: currencyCode, } }) diff --git a/src/Pages/Investor_Management/InvestorDetails/Transaction.jsx b/src/Pages/Investor_Management/InvestorDetails/Transaction.jsx index 813e450..b177f4a 100644 --- a/src/Pages/Investor_Management/InvestorDetails/Transaction.jsx +++ b/src/Pages/Investor_Management/InvestorDetails/Transaction.jsx @@ -1,365 +1,308 @@ import { - Avatar, - Badge, - Box, - Button, - HStack, - Input, - Menu, - MenuButton, - MenuItem, - MenuList, - Portal, - Select, - Switch, - Table, - Tag, - Tbody, - Text, - Th, - Tooltip, - Tr, - useToast, - } from "@chakra-ui/react"; - import React, { useContext, useEffect, useState } from "react"; - import { OPACITY_ON_LOAD } from "../../../Layout/animations"; - import DataTable from "../../../Components/DataTable/DataTable"; - import Pagination from "../../../Components/Pagination"; - import GlobalStateContext from "../../../Contexts/GlobalStateContext"; - import CustomAlertDialog from "../../../Components/CustomAlertDialog"; - import ToastBox from "../../../Components/ToastBox"; - import { debounce } from "../../Master/Sponser/AddSponser"; - - const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter - - const Transaction = () => { - const toast = useToast(); - const { transaction, setTransaction, slideFromRight, InvestorWallet, } = - 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 Setup]================================================================ - const tableHeadRow = [ - // "Sr N/O", - "Date", - "Transaction", - "Amount in investors currency", - // "Currency", - "TO USD", - "From USD", - "USD amount", - "IO Name", - "Payment Method", - ]; - -console.log(transaction); + Avatar, + Badge, + Box, + Button, + HStack, + Input, + Menu, + MenuButton, + MenuItem, + MenuList, + Portal, + Select, + Switch, + Table, + Tag, + Tbody, + Text, + Th, + Tooltip, + Tr, + useToast, +} from "@chakra-ui/react"; +import React, { useContext, useEffect, useState } from "react"; +import { OPACITY_ON_LOAD } from "../../../Layout/animations"; +import NormalTable from "../../../Components/DataTable/NormalTable"; +import Pagination from "../../../Components/Pagination"; +import GlobalStateContext from "../../../Contexts/GlobalStateContext"; +import CustomAlertDialog from "../../../Components/CustomAlertDialog"; +import ToastBox from "../../../Components/ToastBox"; +import { debounce } from "../../Master/Sponser/AddSponser"; - // ====================================================[Table Filter]================================================================ - const filteredData = transaction?.filter((item) => { - // Filter by name (case insensitive) - console.log(item?.investorTransaction?.transactionName); - - const name = item?.investorTransaction?.transactionName; - const searchLower = searchTerm?.toLowerCase(); - const nameMatches = name?.toLowerCase().includes(searchLower); - - // Filter by status - // const status = item.status; - // const statusLower = status ? "active" : "inactive"; - - // const statusMatches = - // statusFilter === "all" || - // (statusFilter === "active" && status === true) || - // (statusFilter === "inactive" && status === false); - - return nameMatches; +const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter + +const Transaction = () => { + const toast = useToast(); + const { transaction, setTransaction, slideFromRight, InvestorWallet } = + 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(filteredData); - - - const extractedArray = filteredData?.map((item) => ({ - id: item?.id, - "Sr N/O": ( - - {item.id} + console.log(transaction); + + // ====================================================[Table Filter]================================================================ + const filteredData = transaction?.filter((item) => { + // Filter by name (case insensitive) + console.log(item?.investorTransaction?.transactionName); + + const name = item?.investorTransaction?.transactionName; + const searchLower = searchTerm?.toLowerCase(); + const nameMatches = name?.toLowerCase().includes(searchLower); + + // Filter by status + // const status = item.status; + // const statusLower = status ? "active" : "inactive"; + + // const statusMatches = + // statusFilter === "all" || + // (statusFilter === "active" && status === true) || + // (statusFilter === "inactive" && status === false); + + return nameMatches; + }); + + console.log(filteredData); + + // ====================================================[Table Setup]================================================================ + const tableHeadRow = [ + // "Sr N/O", + "Date", + "Transaction", + "Amount in investors currency", + // "Currency", + "TO USD", + "From USD", + "USD amount", + "IO Name", + "Payment Method", + ]; + const extractedArray = filteredData?.map((item) => ({ + id: item?.id, + "Sr N/O": ( + + {item.id} + + ), + Date: ( + + + {formatDate(item.transactionDate)} - ), - "Date": ( - - - {formatDate(item.transactionDate)} - - - ), - "Transaction": ( - - - {item.investorTransaction?.transactionName} - - - ), - "Currency": ( - - - {item.investorCurrency} - - - ), - "Amount in investors currency": ( - - - {/* {item.investorAmount} */} - {parseFloat(item?.investorAmount || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} - {item?.investorCurrency} - - - ), - "From USD": ( - - - {item.USDToInvCur_Rate} - - - ), - "TO USD": ( - - - {item.invCurToUSD_Rate} - - - ), - "USD amount": ( - - - {/* {item.USDAmount} */} - {parseFloat(item?.USDAmount || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} - {/* $ */} - USD - - - ), - "IO Name": ( - - - {item.io && item.io?.investmentNameEnglish} - - - ), - "Payment Method": ( - - - {item.paymentMethod && item.paymentMethod?.paymentMethodName} - - - ), - })); - - const handleDelete = () => { - const updatedInvestorDetails = InvestorDetails.filter( - (sponsor) => sponsor.id !== actionId - ); - - setTimeout(() => { - setInvestorDetails(updatedInvestorDetails); - setDeleteAlert(false); - setIsLoading(false); - }, 100); - setIsLoading(true); - }; + + ), + Transaction: ( + + + {item.investorTransaction?.transactionName} + + + ), + Currency: ( + + + {item.investorCurrency} + + + ), + "Amount in investors currency": ( + + + {/* {item.investorAmount} */} + {parseFloat(item?.investorAmount || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + + {item?.investorCurrency} + + + + ), + "From USD": ( + + {item.USDToInvCur_Rate} + + ), + "TO USD": ( + + {item.invCurToUSD_Rate} + + ), + "USD amount": ( + + + {/* {item.USDAmount} */} + {parseFloat(item?.USDAmount || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + + $ + + + + ), + "IO Name": ( + + + {item.io && item.io?.investmentNameEnglish} + + + ), + "Payment Method": ( + + + {item.paymentMethod && item.paymentMethod?.paymentMethodName} + + + ), + })); - const Total = () => { - return ( - - - - - - - - - - - - - -
- Balance: - - {" "} - - - {parseFloat(InvestorWallet?.WalletBalance_InInvCur).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} - {InvestorWallet?.currencyCode_InCur} - - - {" "} - - {" "} - - - {parseFloat(InvestorWallet?.WalletBalance_InUSD).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} - USD - - - {" "} - - {" "} -
- ); - }; - - return ( - - - - setSearchTerm(e.target.value)} - /> - - {/* + const totalRow = { + // id: "total", // or any unique ID + // "Sr N/O": ( + // Total + // ), + Date: ( + + + Total + + + ), + Transaction: null, + // "Currency": null, + "Amount in investors currency": ( + + + {parseFloat(InvestorWallet?.WalletBalance_InInvCur).toLocaleString( + undefined, + { minimumFractionDigits: 2, maximumFractionDigits: 2 } + )} + + {InvestorWallet?.currencyCode_InCur} + + + + ), + "TO USD": null, + "From USD": null, + "USD amount": ( + + + {parseFloat(InvestorWallet?.WalletBalance_InUSD).toLocaleString( + undefined, + { minimumFractionDigits: 2, maximumFractionDigits: 2 } + )} + + $ + + + + ), + "IO Name": null, + "Payment Method": null, + }; + + extractedArray?.push(totalRow); + + const handleDelete = () => { + const updatedInvestorDetails = InvestorDetails.filter( + (sponsor) => sponsor.id !== actionId + ); + + setTimeout(() => { + setInvestorDetails(updatedInvestorDetails); + setDeleteAlert(false); + setIsLoading(false); + }, 100); + setIsLoading(true); + }; + + return ( + + + + setSearchTerm(e.target.value)} + /> + + {/* */} - - - - } - setMouseEntered={setMouseEntered} - /> - - setDeleteAlert(false)} - isOpen={deleteAlert} - message={"Are you sure you want to delete sponers?"} - alertHandler={handleDelete} - isLoading={isLoading} - /> - + - ); - }; - - export default Transaction; - \ No newline at end of file + + + + setDeleteAlert(false)} + isOpen={deleteAlert} + message={"Are you sure you want to delete sponers?"} + alertHandler={handleDelete} + isLoading={isLoading} + /> + + ); +}; + +export default Transaction; diff --git a/src/Pages/Investor_Management/InvestorDetails/ViewInvestorDetails.jsx b/src/Pages/Investor_Management/InvestorDetails/ViewInvestorDetails.jsx index f871af0..7e0f0d3 100644 --- a/src/Pages/Investor_Management/InvestorDetails/ViewInvestorDetails.jsx +++ b/src/Pages/Investor_Management/InvestorDetails/ViewInvestorDetails.jsx @@ -19,7 +19,7 @@ import { } from "@chakra-ui/react"; import React, { useContext, useEffect, useState } from "react"; import { OPACITY_ON_LOAD } from "../../../Layout/animations"; -import DataTable from "../../../Components/DataTable/DataTable"; +import NormalTable from "../../../Components/DataTable/NormalTable"; import { HiDotsVertical } from "react-icons/hi"; import { Link, Navigate, Link as RouterLink } from "react-router-dom"; import { @@ -47,7 +47,7 @@ const ViewInvestorDetails = () => { const [actionId, setActionId] = useState(false); const [mouseEntered, setMouseEntered] = useState(false); const [mouseEnteredId, setMouseEnteredId] = useState(""); - + useEffect(() => { // Simulate loading const timer = setTimeout(() => { @@ -75,8 +75,7 @@ const ViewInvestorDetails = () => { // "Action", ]; -console.log(viewInvestor); - + console.log(viewInvestor); // ====================================================[Table Filter]================================================================ const filteredData = viewInvestor?.filter((item) => { @@ -99,10 +98,11 @@ console.log(viewInvestor); console.log(filteredData); - const extractedArray = filteredData?.map((item,index) => ({ + const extractedArray = filteredData?.map((item, index) => ({ id: item?.id, "Sr N/O": ( - ), "Sponsor Name": ( - + {item.sponsorName} @@ -128,15 +128,15 @@ console.log(viewInvestor); "Investment Amount": ( - {/* {item.investedAmount} */} - $ {parseFloat(item?.investedAmount || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} + $ + {parseFloat(item?.investedAmount || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} ), - "Percentage": ( + Percentage: ( {item?.Investor_Holidings} % @@ -145,11 +145,12 @@ console.log(viewInvestor); ), "Market Value": ( - - $ {parseFloat(item?.MarketValue || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} + + $ + {parseFloat(item?.MarketValue || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} ), @@ -160,13 +161,17 @@ console.log(viewInvestor); ), - "Distribution": ( + Distribution: ( - $ {parseFloat(item?.DistributionAmountReceived || 0).toLocaleString(undefined, { + $ + {parseFloat(item?.DistributionAmountReceived || 0).toLocaleString( + undefined, + { minimumFractionDigits: 2, maximumFractionDigits: 2, - })} + } + )} ), @@ -180,10 +185,11 @@ console.log(viewInvestor); "Total return": ( - $ {parseFloat(item?.TotalReturn || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} + $ + {parseFloat(item?.TotalReturn || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} ), @@ -195,23 +201,35 @@ console.log(viewInvestor); ), Status: ( - - - {item.statusAdmin} - - + + {item?.statusAdmin} + ), Action: ( @@ -279,7 +297,7 @@ console.log(viewInvestor); - - ); }; diff --git a/src/Services/api.service.js b/src/Services/api.service.js index 0cbd46d..e69de29 100644 --- a/src/Services/api.service.js +++ b/src/Services/api.service.js @@ -1,66 +0,0 @@ -import axios from "axios"; - -// Create an Axios instance for API calls -export const api = axios.create({ - // baseURL: `https://tanami.betadelivery.com/api/v1`, - baseURL: import.meta.env.VITE_BAS_URL, // Replace with your API base URL - timeout: 10000, // Adjust timeout as needed - headers: { - "Content-Type": "application/json", - }, -}); - -// Add Axios request interceptor to refresh token if expired -api.interceptors.request.use( - (config) => { - console.log(config); - // Modify headers or add tokens as needed - // const token = localStorage.getItem("accessToken"); - // if (token) { - // config.headers.Authorization = `Bearer ${token}`; - // } - return config; - }, - (error) => { - return Promise.reject(error); - } -); - -// // Add Axios response interceptor to handle token refreshing -api.interceptors.response.use( - (response) => { - return response; - }, - async (error) => { - const originalRequest = error.config; - - // Example logic for handling token expiration and refreshing - if ( - error.response.status === 401 && - !originalRequest._retry && - localStorage.getItem("refreshToken") - ) { - originalRequest._retry = true; - - try { - const response = await api.post("/refresh_token", { - refreshToken: localStorage.getItem("refreshToken"), - }); - - if (response.status === 200) { - // Update tokens in local storage - localStorage.setItem("accessTokenn", response.data.accessToken); - localStorage.setItem("refreshTokenn", response.data.refreshToken); - - // Retry the original request with the new tokens - return api(originalRequest); - } - } catch (error) { - console.error("Failed to refresh token:", error); - // Handle token refresh failure (e.g., redirect to login) - } - } - - return Promise.reject(error); - } -);