Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
Routes,
|
||||
Route,
|
||||
Navigate,
|
||||
useNavigate,
|
||||
} from "react-router-dom";
|
||||
import "./App.css"; // Import CSS file
|
||||
import DefaultLayout from "./Layout/DefaultLayout";
|
||||
@@ -26,6 +27,13 @@ const App = () => {
|
||||
const [isOnline, setIsOnline] = useState(navigator.onLine);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const handleOnlineStatusChange = () => {
|
||||
setIsOnline(navigator.onLine);
|
||||
};
|
||||
|
||||
@@ -9,27 +9,52 @@ import {
|
||||
Tr,
|
||||
Skeleton,
|
||||
TableCaption,
|
||||
Tfoot,
|
||||
Checkbox,
|
||||
} from "@chakra-ui/react";
|
||||
import EmptySearchList from "../EmptySearchList";
|
||||
import { TABLE_PAGINATION } from "../../Constants/Paginations";
|
||||
|
||||
const DataTable = ({
|
||||
const NormalTable = ({
|
||||
data,
|
||||
isLoading,
|
||||
tableHeadRow,
|
||||
emptyMessage,
|
||||
centered,
|
||||
total,
|
||||
showRadioButton, // Prop for showing the checkboxes
|
||||
selectedRadio,
|
||||
setSelectedRadio, // State for managing selected checkboxes
|
||||
}) => {
|
||||
console.log(data);
|
||||
|
||||
const columnWidth =
|
||||
data && data[0]
|
||||
? `${(100 / Object.keys(data[0]).length).toFixed(2)}%`
|
||||
: "auto";
|
||||
|
||||
// Toggle checkbox selection for individual rows
|
||||
const handleCheckboxChange = (value) => {
|
||||
setSelectedRadio((prev) => {
|
||||
if (prev.includes(value)) {
|
||||
// Remove if already selected
|
||||
return prev.filter((id) => id !== value);
|
||||
} else {
|
||||
// Add to selected
|
||||
return [...prev, value];
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Handle "Check All" checkbox
|
||||
const handleCheckAllChange = () => {
|
||||
if (selectedRadio.length === data.length) {
|
||||
setSelectedRadio([]); // Deselect all if already selected
|
||||
} else {
|
||||
const allIds = data.map((item) => item.id);
|
||||
setSelectedRadio(allIds); // Select all
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TableContainer overflowX={"auto"} className="h-auto mb-3 w-100 table-scroll">
|
||||
<TableContainer overflowX={"auto"} className="h-auto w-100 table-scroll">
|
||||
{data?.length === 0 ? (
|
||||
<EmptySearchList message={emptyMessage} />
|
||||
) : (
|
||||
@@ -37,26 +62,42 @@ const DataTable = ({
|
||||
<TableCaption p={total ? 0 : null}>
|
||||
{total ? total : "Tanami v1.0.0"}
|
||||
</TableCaption>
|
||||
<Thead backgroundColor="forestGreen.100">
|
||||
<Thead bg="forestGreen.100">
|
||||
<Tr>
|
||||
{showRadioButton && (
|
||||
<Th
|
||||
color={"purple.900"}
|
||||
textAlign={"center"}
|
||||
p={4}
|
||||
whiteSpace="normal"
|
||||
wordBreak="normal"
|
||||
overflowWrap="normal"
|
||||
textTransform={"none"}
|
||||
>
|
||||
<Checkbox
|
||||
isChecked={selectedRadio?.length === data?.length}
|
||||
onChange={handleCheckAllChange}
|
||||
colorScheme="forestGreen"
|
||||
|
||||
/>
|
||||
</Th>
|
||||
)}
|
||||
{tableHeadRow.map((heading, index) => (
|
||||
<Th
|
||||
<Th
|
||||
color={"purple.900"}
|
||||
textAlign={
|
||||
tableHeadRow.length - 1 === index || centered
|
||||
? "center"
|
||||
: "left"
|
||||
}
|
||||
key={index}
|
||||
p={3}
|
||||
width="20px" // Adjust width as needed
|
||||
color={"#004118"}
|
||||
whiteSpace="normal" // Allow text to wrap
|
||||
wordBreak="normal" // Ensure long words break properly
|
||||
overflowWrap="normal" // Break long words if necessary
|
||||
p={4}
|
||||
whiteSpace="normal"
|
||||
wordBreak="normal"
|
||||
overflowWrap="normal"
|
||||
textTransform={"none"}
|
||||
>
|
||||
{isLoading ? <Skeleton height="20px" /> : heading}
|
||||
{/* {heading} */}
|
||||
</Th>
|
||||
))}
|
||||
</Tr>
|
||||
@@ -65,17 +106,18 @@ const DataTable = ({
|
||||
{isLoading
|
||||
? Array.from({ length: TABLE_PAGINATION?.size }).map(
|
||||
(_, index) => (
|
||||
<Tr bg={index % 2 === 0 ? "" : "forestGreen.50"} key={index}>
|
||||
<Tr
|
||||
bg={index % 2 === 0 ? "white" : "forestGreen.50"}
|
||||
key={index}
|
||||
>
|
||||
{tableHeadRow.map((_, i) => (
|
||||
<Td
|
||||
width={"fit-content"}
|
||||
key={i}
|
||||
style={{
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
className="web-text-small"
|
||||
w={columnWidth}
|
||||
>
|
||||
<Skeleton height="20px" mb={1} mt={1} />
|
||||
</Td>
|
||||
@@ -84,9 +126,26 @@ const DataTable = ({
|
||||
)
|
||||
)
|
||||
: data?.map((item, index) => (
|
||||
<Tr bg={index % 2 === 0 ? "" : "forestGreen.50"} key={index}>
|
||||
<Tr
|
||||
cursor={"pointer"}
|
||||
transition={"0.2s all"}
|
||||
maxH={8}
|
||||
bg={index % 2 === 0 ? "" : "forestGreen.50"}
|
||||
key={index}
|
||||
>
|
||||
{showRadioButton && (
|
||||
<Td textAlign={"center"}>
|
||||
<Checkbox
|
||||
bg={"#fff"}
|
||||
colorScheme="forestGreen"
|
||||
value={item.id}
|
||||
isChecked={selectedRadio.includes(item.id)}
|
||||
onChange={() => handleCheckboxChange(item.id)}
|
||||
/>
|
||||
</Td>
|
||||
)}
|
||||
{tableHeadRow.map((heading, i) => (
|
||||
<Td
|
||||
<Td
|
||||
textAlign={
|
||||
tableHeadRow?.length - 1 === i || centered
|
||||
? "center"
|
||||
@@ -94,6 +153,7 @@ const DataTable = ({
|
||||
}
|
||||
color={"gray.600"}
|
||||
key={i}
|
||||
fontWeight={500}
|
||||
style={{
|
||||
whiteSpace: "nowrap",
|
||||
textOverflow: "ellipsis",
|
||||
@@ -112,4 +172,4 @@ const DataTable = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default DataTable;
|
||||
export default NormalTable;
|
||||
|
||||
@@ -404,8 +404,7 @@ const FormField = ({
|
||||
w={6}
|
||||
h={6}
|
||||
src={
|
||||
import.meta.env.VITE_IMAGE_URL +
|
||||
item?.logo
|
||||
import.meta.env.VITE_IMAGE_URL+item?.logo
|
||||
}
|
||||
/>
|
||||
{item.country === "United Arab Emirates"
|
||||
|
||||
@@ -62,7 +62,7 @@ const FormInputView = ({
|
||||
w={6}
|
||||
h={6}
|
||||
src={
|
||||
" https://tanami.betadelivery.com/" +
|
||||
import.meta.env.VITE_IMAGE_URL+
|
||||
item?.logo
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -148,51 +148,33 @@ export function calculatePercentage(part, total) {
|
||||
return (part / total) * 100;
|
||||
}
|
||||
|
||||
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);
|
||||
const getNestedValue = (obj, key) => {
|
||||
return key.split('.').reduce((value, part) => {
|
||||
return value && value[part] ? value[part] : null;
|
||||
}, obj);
|
||||
};
|
||||
|
||||
// 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
|
||||
export const exportToExcel = (data, headers) => {
|
||||
const flattenedData = data.map((item) => {
|
||||
const newItem = {};
|
||||
|
||||
// Loop through customHeaders and get the correct values
|
||||
headers.forEach((header) => {
|
||||
newItem[header.label] = getNestedValue(item, header.key); // Use the helper function
|
||||
});
|
||||
|
||||
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)
|
||||
}
|
||||
};
|
||||
return newItem; // Return the new flat object
|
||||
});
|
||||
|
||||
// Create a new workbook and append the worksheet
|
||||
// Now pass flattenedData to your Excel library to generate the file
|
||||
// Assuming you're using a library like `xlsx` for this part:
|
||||
|
||||
const worksheet = XLSX.utils.json_to_sheet(flattenedData);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
|
||||
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);
|
||||
// Generate file
|
||||
XLSX.writeFile(workbook, "exported_data.xlsx");
|
||||
};
|
||||
|
||||
@@ -92,6 +92,16 @@ const DashboardLayout = ({ isOnline }) => {
|
||||
const [isSplashVisible, setSplashVisible] = useState(true);
|
||||
const [openIndex, setOpenIndex] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if(!localStorage.getItem('accessToken') && !localStorage.getItem('refreshToken')){
|
||||
logOutHandler()
|
||||
return navigate('/login')
|
||||
}
|
||||
|
||||
|
||||
}, [])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const savedIndex = localStorage.getItem("openAccordionIndex");
|
||||
if (savedIndex !== null) {
|
||||
@@ -123,9 +133,7 @@ const DashboardLayout = ({ isOnline }) => {
|
||||
// dispach(loginUser(false));
|
||||
setIsAuthenticate(false);
|
||||
Cookies.remove("isAuthenticated");
|
||||
localStorage.removeItem('refreshToken')
|
||||
localStorage.removeItem('accessToken')
|
||||
localStorage.removeItem('refreshTokenExp')
|
||||
localStorage.clear();
|
||||
navigate("/login");
|
||||
};
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@ const BankInvestor = () => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
console.log(localStorage.getItem("refreshToken"));
|
||||
const {
|
||||
data,
|
||||
isLoading: unbanLoading,
|
||||
@@ -113,6 +115,9 @@ const BankInvestor = () => {
|
||||
return nameMatches;
|
||||
});
|
||||
|
||||
|
||||
console.log(filteredData);
|
||||
|
||||
const extractedArray = filteredData?.map((item) => ({
|
||||
id: item?.id,
|
||||
"Sr N/O": (
|
||||
@@ -128,7 +133,7 @@ const BankInvestor = () => {
|
||||
"Date": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{formatDate(item?.principal?.createdAt)}
|
||||
{formatDate(item?.date)}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
@@ -142,14 +147,14 @@ const BankInvestor = () => {
|
||||
"First Name": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item?.principal?.firstName}
|
||||
{item?.firstName}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
"Last Name": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item?.principal?.lastName}
|
||||
{item?.lastName}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
@@ -170,21 +175,22 @@ const BankInvestor = () => {
|
||||
"E-mail ID": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item?.principal?.emailAddress}
|
||||
{item?.emailAddress}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
"KYC Status": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Badge
|
||||
fontWeight={"500"}
|
||||
textTransform={"none"}
|
||||
color={item.status === "Completed" ? "blue" : "red"}
|
||||
px={2}
|
||||
py={0.5}
|
||||
>
|
||||
{item?.KYCStatus}
|
||||
</Badge>
|
||||
<Badge
|
||||
fontWeight={"500"}
|
||||
textTransform={"none"}
|
||||
color={item?.KYCStatus === false ? "red" : "blue"}
|
||||
px={2}
|
||||
py={0.5}
|
||||
variant={'ghost'}
|
||||
>
|
||||
{item?.KYCStatus === true ? "Completed" : "Incompleted"}
|
||||
</Badge>
|
||||
</Box>
|
||||
),
|
||||
Action: (
|
||||
@@ -196,7 +202,9 @@ const BankInvestor = () => {
|
||||
colorScheme={"red"}
|
||||
px={2}
|
||||
py={0.5}
|
||||
onClick={onOpen}
|
||||
onClick={()=>{
|
||||
setActionId(item?.id)
|
||||
onOpen()}}
|
||||
>
|
||||
Ban Investor
|
||||
</Badge>
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
import { useForm } from "react-hook-form";
|
||||
import ToastBox from "../../../../Components/ToastBox";
|
||||
import { useDepositRejectMutation } from "../../../../Services/drawal.request.service";
|
||||
import { useUpdateBanMutation } from "../../../../Services/ban.investor.service";
|
||||
|
||||
export const conformModalSchema = yup.object().shape({
|
||||
comments: yup.string().required("Comment is required"),
|
||||
@@ -41,13 +42,14 @@ import { useDepositRejectMutation } from "../../../../Services/drawal.request.se
|
||||
resolver: yupResolver(conformModalSchema),
|
||||
});
|
||||
|
||||
// const [ depositReject ] = useDepositRejectMutation()
|
||||
const [ updateBanMutation ] = useUpdateBanMutation()
|
||||
|
||||
|
||||
const onSubmit = async(data) => {
|
||||
setIsBtnLoading(true)
|
||||
try {
|
||||
const res = await depositReject({ id ,data})
|
||||
const res = await updateBanMutation({ id ,data})
|
||||
console.log(res);
|
||||
|
||||
if (res?.error) {
|
||||
toast({
|
||||
@@ -84,7 +86,7 @@ import { useDepositRejectMutation } from "../../../../Services/drawal.request.se
|
||||
<Modal isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
|
||||
<ModalOverlay />
|
||||
<ModalContent pb={4}>
|
||||
<ModalHeader fontSize={"md"}>Reason for Ban</ModalHeader>
|
||||
<ModalHeader fontSize={"md"}>Reason for Unban</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
|
||||
<ModalBody>
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
import { useForm } from "react-hook-form";
|
||||
import ToastBox from "../../../../Components/ToastBox";
|
||||
import { useDepositRejectMutation } from "../../../../Services/drawal.request.service";
|
||||
import { useUpdateUnbanMutation } from "../../../../Services/ban.investor.service";
|
||||
import { useUpdateBanMutation, useUpdateUnbanMutation } from "../../../../Services/ban.investor.service";
|
||||
|
||||
export const conformModalSchema = yup.object().shape({
|
||||
comments: yup.string().required("Comment is required"),
|
||||
@@ -42,16 +42,18 @@ import { useUpdateUnbanMutation } from "../../../../Services/ban.investor.servic
|
||||
resolver: yupResolver(conformModalSchema),
|
||||
});
|
||||
|
||||
const [ updateUnban ] = useUpdateUnbanMutation()
|
||||
const [ updateBan ] = useUpdateUnbanMutation()
|
||||
|
||||
console.log(updateUnban);
|
||||
|
||||
|
||||
|
||||
|
||||
const onSubmit = async(data) => {
|
||||
console.log(data);
|
||||
setIsBtnLoading(true)
|
||||
try {
|
||||
const res = await updateUnban({ id ,data})
|
||||
const res = await updateBan({ id ,data})
|
||||
console.log(res);
|
||||
|
||||
if (res?.error) {
|
||||
toast({
|
||||
@@ -61,7 +63,7 @@ import { useUpdateUnbanMutation } from "../../../../Services/ban.investor.servic
|
||||
});
|
||||
heandleOnClose()
|
||||
|
||||
}else if(res?.data?.statusCode === 200) {
|
||||
}else if(res?.data) {
|
||||
toast({
|
||||
render: () => (
|
||||
<ToastBox message={res?.data?.message} />
|
||||
|
||||
@@ -36,7 +36,7 @@ const UnbanInvestor = () => {
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [deleteAlert, setDeleteAlert] = useState(false);
|
||||
const [actionId, setActionId] = useState(false);
|
||||
const [actionId, setActionId] = useState("");
|
||||
const [mouseEntered, setMouseEntered] = useState(false);
|
||||
const [mouseEnteredId, setMouseEnteredId] = useState("");
|
||||
const { isOpen: isOpen, onOpen: onOpen, onClose: onClose } = useDisclosure();
|
||||
@@ -167,11 +167,12 @@ const UnbanInvestor = () => {
|
||||
<Badge
|
||||
fontWeight={"500"}
|
||||
textTransform={"none"}
|
||||
color={item?.KYCStatus === "False" ? "blue" : "red"}
|
||||
color={item?.KYCStatus === false ? "red" : "blue"}
|
||||
px={2}
|
||||
py={0.5}
|
||||
variant={'ghost'}
|
||||
>
|
||||
{item?.KYCStatus ? "True" : "False"}
|
||||
{item?.KYCStatus === true ? "Completed" : "Incompleted"}
|
||||
</Badge>
|
||||
</Box>
|
||||
),
|
||||
@@ -184,7 +185,10 @@ const UnbanInvestor = () => {
|
||||
colorScheme={"red"}
|
||||
px={2}
|
||||
py={0.5}
|
||||
onClick={onOpen}
|
||||
onClick={()=>{
|
||||
setActionId(item?.id)
|
||||
onOpen()
|
||||
}}
|
||||
>
|
||||
Ban Investor
|
||||
</Badge>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import {
|
||||
Badge,
|
||||
Box,
|
||||
Button,
|
||||
Text,
|
||||
Tooltip,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
import { useForm} from "react-hook-form";
|
||||
@@ -15,6 +19,12 @@ import {
|
||||
} from "../../Services/contact.service";
|
||||
import FullscreenLoaders from "../../Components/Loaders/FullscreenLoaders";
|
||||
import ToastBox from "../../Components/ToastBox";
|
||||
import NormalTable from "../../Components/DataTable/NormalTable";
|
||||
import GlobalStateContext from "../../Contexts/GlobalStateContext";
|
||||
import { useGetInvestorsQuery } from "../../Services/investor.details.service";
|
||||
import { TABLE_PAGINATION } from "../../Constants/Paginations";
|
||||
import { generateSerialNumber } from "../../Constants/Constants";
|
||||
import { ViewIcon } from "@chakra-ui/icons";
|
||||
|
||||
export const notification = yup.object().shape({
|
||||
investmentNameEnglish: yup
|
||||
@@ -47,6 +57,7 @@ const Notification = () => {
|
||||
const navigate = useNavigate();
|
||||
const [form, setForm] = useState({});
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [ selectedRadio, setSelectedRadio] = useState([])
|
||||
|
||||
const {
|
||||
control,
|
||||
@@ -64,6 +75,18 @@ const Notification = () => {
|
||||
isLoading: contactLoading,
|
||||
error,
|
||||
} = useGetContactQuery();
|
||||
|
||||
|
||||
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
|
||||
const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page);
|
||||
const {
|
||||
data: investorDetails,
|
||||
isLoading: investorDetailsLoading,
|
||||
// error,
|
||||
} = useGetInvestorsQuery({ page: currentPage, size: pageSize });
|
||||
console.log(investorDetails);
|
||||
|
||||
|
||||
const [updateContact] = useUpdateContactMutation();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -129,9 +152,20 @@ const Notification = () => {
|
||||
}, {});
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
|
||||
const dataToPass = {
|
||||
...data,
|
||||
principal_xid:selectedRadio
|
||||
}
|
||||
|
||||
console.log(dataToPass);
|
||||
|
||||
|
||||
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const res = await updateContact(data);
|
||||
const res = await updateContact(dataToPass);
|
||||
if (res?.data?.statusCode === 200) {
|
||||
toast({
|
||||
render: () => <ToastBox message={res?.data?.message} />,
|
||||
@@ -145,6 +179,122 @@ const Notification = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
console.log(selectedRadio);
|
||||
|
||||
|
||||
|
||||
// ====================================================[Table Setup]================================================================
|
||||
const tableHeadRow = [
|
||||
"Sr No",
|
||||
"Client ID",
|
||||
"First Name",
|
||||
"Last Name",
|
||||
"Country",
|
||||
"Phone Number",
|
||||
"E-mail ID",
|
||||
"Type",
|
||||
"KYC Status",
|
||||
// "Status",
|
||||
];
|
||||
|
||||
const extractedArray = investorDetails?.data?.rows?.map((item, idx) => ({
|
||||
id: item?.id,
|
||||
"Sr No": (
|
||||
<Text
|
||||
w={'24px'}
|
||||
justifyContent={"left"}
|
||||
as={"span"}
|
||||
color={"gray.600"}
|
||||
className="d-flex align-items-center fw-bold web-text-small"
|
||||
>
|
||||
{/* {item.id} */}
|
||||
{generateSerialNumber(idx,currentPage, pageSize )}
|
||||
|
||||
</Text>
|
||||
),
|
||||
"Client ID": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item.clientReference_id}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
"First Name": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item?.principal?.firstName}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
"Last Name": (
|
||||
<Box w={"70px"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item?.principal?.lastName}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
Country: (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item?.country?.countryName}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
"Phone Number": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item?.principal?.mobileNumber}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
"E-mail ID": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} color={"teal.900"}>
|
||||
{item?.principal?.emailAddress}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
"Type": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} >
|
||||
<Badge color={"forestGreen.500"} variant={'ghost'} fontWeight={"700"} px={2} py={0.5}>
|
||||
{item?.investor_type?.investorTypeName}
|
||||
</Badge>
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
Status: (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Badge
|
||||
fontWeight={"700"}
|
||||
textTransform={"none"}
|
||||
colorScheme={item.ioStatus ? "red" : "green"}
|
||||
px={2}
|
||||
py={0.5}
|
||||
>
|
||||
{item.ioStatus ? "Ban" : "Unban"}
|
||||
</Badge>
|
||||
</Box>
|
||||
),
|
||||
"KYC Status": (
|
||||
<Box w={"auto"} display={'flex'} alignItems={'center'} isTruncated={true}>
|
||||
<Text
|
||||
as={'span'}
|
||||
fontWeight={"700"}
|
||||
textTransform={"none"}
|
||||
color={item.ioStatus ? "gray.500":item.kycStatus ? "blue.500" : "red.500"}
|
||||
px={2}
|
||||
py={0.5}
|
||||
variant={'solid'}
|
||||
|
||||
>
|
||||
{item.KYCStatus ? "Completed" : "Not complete"}
|
||||
</Text>
|
||||
</Box>
|
||||
),
|
||||
}));
|
||||
|
||||
return (
|
||||
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={14}>
|
||||
<FormInputMain
|
||||
@@ -153,7 +303,24 @@ const Notification = () => {
|
||||
errors={errors}
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
btnLoading={isLoading}
|
||||
>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<NormalTable
|
||||
centered={true}
|
||||
emptyMessage={`We don't have any Sponers `}
|
||||
tableHeadRow={tableHeadRow}
|
||||
data={extractedArray}
|
||||
// isLoading={isLoading}
|
||||
setSelectedRadio={setSelectedRadio}
|
||||
selectedRadio={selectedRadio}
|
||||
showRadioButton={true}
|
||||
/>
|
||||
</FormInputMain>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -38,6 +38,8 @@ import { formatCurrency } from "../../../Components/CurrencyInput";
|
||||
import { FiRefreshCw } from "react-icons/fi";
|
||||
import { useGetIOByIdQuery } from "../../../Services/io.service";
|
||||
import { RepeatIcon } from "@chakra-ui/icons";
|
||||
import { exportToExcel } from "../../../Constants/Constants";
|
||||
import { LuFileSpreadsheet } from "react-icons/lu";
|
||||
|
||||
const rotate = keyframes`
|
||||
from {
|
||||
@@ -124,6 +126,8 @@ const Investors = ({ data }) => {
|
||||
});
|
||||
}, 300);
|
||||
|
||||
|
||||
|
||||
// Table filter
|
||||
const filteredData = IODetails?.investors?.filter((item) => {
|
||||
const name = item.firstName;
|
||||
@@ -132,6 +136,22 @@ const Investors = ({ data }) => {
|
||||
return nameMatches;
|
||||
});
|
||||
|
||||
|
||||
const customHeaders = [
|
||||
{ label: "Client ID", key: "clientReference_id" },
|
||||
{ label: "First Name", key: "firstName" }, // Nested property
|
||||
{ label: "Last Name", key: "lastName" }, // Nested property
|
||||
{ label: "Investment amount", key: "InvestedAmount_USD" }, // Nested property
|
||||
{ label: "Percentage", key: "Investor_Holidings" }, // Nested property
|
||||
{ label: "Market Value", key: "Market_Value" }, // Nested property
|
||||
{ label: "Return on Investment", key: "Return_On_Investment" }, // Nested property
|
||||
{ label: "Distribution", key: "Distribution_Amt" }, // Simple property
|
||||
{ label: "Distribution Percent", key: "Distribution_Per" }, // Simple property // Simple property
|
||||
{ label: "Total Return", key: "Total_Return" }, // Simple property
|
||||
{ label: "Total return on Investment", key: "Total_Return_On_Investment" },
|
||||
];
|
||||
|
||||
|
||||
const extractedArray = filteredData?.map((item, index) => ({
|
||||
id: item?.id,
|
||||
"Client ID": (
|
||||
@@ -430,6 +450,9 @@ const Investors = ({ data }) => {
|
||||
setIsRefetchLoading(false);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Box {...OPACITY_ON_LOAD} pb={0}>
|
||||
<Box bg="white.500">
|
||||
@@ -439,7 +462,7 @@ const Investors = ({ data }) => {
|
||||
pb={3}
|
||||
spacing="24px"
|
||||
>
|
||||
<span>
|
||||
<Box display={'flex'} gap={3}>
|
||||
<Input
|
||||
type="search"
|
||||
width={300}
|
||||
@@ -450,9 +473,25 @@ const Investors = ({ data }) => {
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={() =>
|
||||
exportToExcel(IODetails?.investors, customHeaders)
|
||||
}
|
||||
leftIcon={<LuFileSpreadsheet />}
|
||||
colorScheme="forestGreen"
|
||||
size={"sm"}
|
||||
variant={"outline"}
|
||||
rounded={"sm"}
|
||||
fontSize={"xs"}
|
||||
w={100}
|
||||
me={2}
|
||||
>
|
||||
Export xls
|
||||
</Button>
|
||||
<Box as="span">
|
||||
<Icon
|
||||
ms={3}
|
||||
ms={0}
|
||||
animation={
|
||||
isRefetchLoading ? `${rotate} 1s linear infinite` : "none"
|
||||
}
|
||||
@@ -467,7 +506,7 @@ const Investors = ({ data }) => {
|
||||
cursor={"pointer"}
|
||||
/>
|
||||
</Box>
|
||||
</span>
|
||||
</Box>
|
||||
|
||||
<HStack
|
||||
bg={"#C6F6D5"}
|
||||
|
||||
@@ -16,10 +16,11 @@ import {
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
FormErrorMessage
|
||||
FormErrorMessage,
|
||||
} from "@chakra-ui/react";
|
||||
import {
|
||||
useGetIOprepopulateDataQuery,
|
||||
useUpdateCancleStatusMutation,
|
||||
useUpdateStatusIoMutation,
|
||||
} from "../../../../Services/io.service";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -30,10 +31,11 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => {
|
||||
const [selectedItem, setSelectedItem] = useState();
|
||||
const [isLoadingg, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [selectedStatusId, setSelectedStatusId] = useState('');
|
||||
const [selectedStatusId, setSelectedStatusId] = useState("");
|
||||
|
||||
const { data } = useGetIOprepopulateDataQuery();
|
||||
const [updateStatusIo] = useUpdateStatusIoMutation();
|
||||
const [updateCancleStatus] = useUpdateCancleStatusMutation();
|
||||
|
||||
// useEffect(() => {
|
||||
// setSelectedStatusId(status?.[0]?.id);
|
||||
@@ -52,13 +54,25 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => {
|
||||
setError("");
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const res = await updateStatusIo({
|
||||
data: {
|
||||
ioStatus_xid: selectedStatusId,
|
||||
},
|
||||
id,
|
||||
});
|
||||
console.log(res);
|
||||
let res;
|
||||
|
||||
// If selectedItem is 'Cancelled', make the updateCancelStatus API call
|
||||
if (selectedItem === "Cancelled") {
|
||||
res = await updateCancleStatus({
|
||||
id
|
||||
});
|
||||
}
|
||||
// Otherwise, make the updateStatusIo API call
|
||||
else {
|
||||
res = await updateStatusIo({
|
||||
data: {
|
||||
ioStatus_xid: selectedStatusId,
|
||||
},
|
||||
id,
|
||||
});
|
||||
}
|
||||
|
||||
console.log("API Response:", res);
|
||||
setIsLoading(false);
|
||||
handleClose();
|
||||
} catch (error) {
|
||||
@@ -67,11 +81,11 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => {
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setSelectedItem(null)
|
||||
setSelectedStatusId(null)
|
||||
onClose()
|
||||
setError("")
|
||||
}
|
||||
setSelectedItem(null);
|
||||
setSelectedStatusId(null);
|
||||
onClose();
|
||||
setError("");
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onClose={handleClose}>
|
||||
@@ -94,7 +108,7 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => {
|
||||
textAlign={"left"}
|
||||
>
|
||||
{selectedItem ? (
|
||||
<Badge
|
||||
<Badge
|
||||
rounded={"full"}
|
||||
pt={1.5}
|
||||
pb={1.5}
|
||||
@@ -114,57 +128,67 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => {
|
||||
? "green"
|
||||
: selectedItem === "Exited"
|
||||
? "red"
|
||||
: selectedItem === "Canclled"
|
||||
: selectedItem === "Cancelled"
|
||||
? "orange"
|
||||
: "purple"
|
||||
}
|
||||
py={"3px"} px={"8px"}
|
||||
}
|
||||
py={"3px"}
|
||||
px={"8px"}
|
||||
>
|
||||
{selectedItem}
|
||||
</Badge>
|
||||
) : "Select Item"}
|
||||
) : (
|
||||
"Select Item"
|
||||
)}
|
||||
</MenuButton>
|
||||
|
||||
{status?.length > 0 ?<MenuList w={"400px"}>
|
||||
{status?.map(({ id, statusAdmin }) => (
|
||||
<MenuItem
|
||||
key={id}
|
||||
fontSize={"sm"}
|
||||
onClick={() => handleMenuItemClick(statusAdmin, id)}
|
||||
>
|
||||
<Badge
|
||||
rounded={"full"}
|
||||
pt={1.5}
|
||||
pb={1.5}
|
||||
ps={4}
|
||||
pe={4}
|
||||
mt={1.5}
|
||||
mb={1.5}
|
||||
textTransform={"none"}
|
||||
colorScheme={
|
||||
statusAdmin === "Draft"
|
||||
? "gray"
|
||||
: statusAdmin === "Processing"
|
||||
? "yellow"
|
||||
: statusAdmin === "Open"
|
||||
? "blue"
|
||||
: statusAdmin === "Closed"
|
||||
? "green"
|
||||
: statusAdmin === "Exited"
|
||||
? "red"
|
||||
: statusAdmin === "Canclled"
|
||||
? "orange"
|
||||
: "purple"
|
||||
}
|
||||
py={"1px"} px={"8px"}
|
||||
{status?.length > 0 ? (
|
||||
<MenuList w={"400px"}>
|
||||
{status?.map(({ id, statusAdmin }) => (
|
||||
<MenuItem
|
||||
key={id}
|
||||
fontSize={"sm"}
|
||||
onClick={() => handleMenuItemClick(statusAdmin, id)}
|
||||
>
|
||||
{statusAdmin}
|
||||
</Badge>
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>:""}
|
||||
<Badge
|
||||
rounded={"full"}
|
||||
pt={1.5}
|
||||
pb={1.5}
|
||||
ps={4}
|
||||
pe={4}
|
||||
mt={1.5}
|
||||
mb={1.5}
|
||||
textTransform={"none"}
|
||||
colorScheme={
|
||||
statusAdmin === "Draft"
|
||||
? "gray"
|
||||
: statusAdmin === "Processing"
|
||||
? "yellow"
|
||||
: statusAdmin === "Open"
|
||||
? "blue"
|
||||
: statusAdmin === "Closed"
|
||||
? "green"
|
||||
: statusAdmin === "Exited"
|
||||
? "red"
|
||||
: statusAdmin === "Cancelled"
|
||||
? "orange"
|
||||
: "purple"
|
||||
}
|
||||
py={"1px"}
|
||||
px={"8px"}
|
||||
>
|
||||
{statusAdmin}
|
||||
</Badge>
|
||||
</MenuItem>
|
||||
))}
|
||||
</MenuList>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Menu>
|
||||
<FormErrorMessage fontSize={'xs'} fontWeight={600} >{error}</FormErrorMessage>
|
||||
<FormErrorMessage fontSize={"xs"} fontWeight={600}>
|
||||
{error}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
|
||||
@@ -429,7 +429,7 @@ const ViewIOTable = () => {
|
||||
setMouseEntered={setMouseEntered}
|
||||
/>
|
||||
|
||||
<MobileView isOpen={isOpen} onClose={onClose} actionId={actionId} />
|
||||
{/* <MobileView isOpen={isOpen} onClose={onClose} actionId={actionId} /> */}
|
||||
|
||||
<CustomAlertDialog
|
||||
onClose={() => setDeleteAlert(false)}
|
||||
|
||||
@@ -182,8 +182,8 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
|
||||
? "#C6F6D5"
|
||||
: IODetails?.ioStatus?.statusAdmin === "Exited"
|
||||
? "#FED7D7"
|
||||
: IODetails?.ioStatus?.statusAdmin === "Canclled"
|
||||
? "orange.500"
|
||||
: IODetails?.ioStatus?.statusAdmin === "Cancelled"
|
||||
? "#E9D8FD"
|
||||
: IODetails?.ioStatus?.statusAdmin === "DeActivate"
|
||||
? "#E9D8FD"
|
||||
: null
|
||||
@@ -342,7 +342,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box gap={8} me={12} w={"140px"}>
|
||||
<Box gap={8} me={12} w={"180px"}>
|
||||
<Box display={"flex"} justifyContent={"space-between"} gap={2} pb={1}>
|
||||
<Text
|
||||
as={"span"}
|
||||
@@ -370,8 +370,8 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
|
||||
? "green"
|
||||
: IODetails?.ioStatus?.statusAdmin === "Exited"
|
||||
? "red"
|
||||
: IODetails?.ioStatus?.statusAdmin === "Canclled"
|
||||
? "orange"
|
||||
: IODetails?.ioStatus?.statusAdmin === "Cancelled"
|
||||
? "purple"
|
||||
: "purple"
|
||||
}
|
||||
>
|
||||
|
||||
@@ -38,7 +38,8 @@ import { debounce } from "../../Master/Sponser/AddSponser";
|
||||
import InvestmentDetailsEdit from "./InvestmentDetailsEdit";
|
||||
import { useGetInvestorsQuery } from "../../../Services/investor.details.service";
|
||||
import { TABLE_PAGINATION } from "../../../Constants/Paginations";
|
||||
import { generateSerialNumber } from "../../../Constants/Constants";
|
||||
import { exportToExcel, generateSerialNumber } from "../../../Constants/Constants";
|
||||
import { LuFileSpreadsheet } from "react-icons/lu";
|
||||
|
||||
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
|
||||
|
||||
@@ -48,7 +49,6 @@ const InvestorDetails = () => {
|
||||
const thirdField = useRef();
|
||||
const { InvestorDetails, setInvestorDetails, slideFromRight } =
|
||||
useContext(GlobalStateContext);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [deleteAlert, setDeleteAlert] = useState(false);
|
||||
const [actionId, setActionId] = useState(false);
|
||||
@@ -61,13 +61,35 @@ const InvestorDetails = () => {
|
||||
} = useDisclosure();
|
||||
const btnRef = React.useRef();
|
||||
|
||||
|
||||
// =========================== [Use State] =============================
|
||||
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
|
||||
const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
|
||||
|
||||
// Debounce the search term to avoid making a request on every keystroke
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedSearchTerm(searchTerm);
|
||||
}, 500); // Adjust delay as needed
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
};
|
||||
}, [searchTerm]);
|
||||
const {
|
||||
data: investorDetails,
|
||||
isLoading: investorDetailsLoading,
|
||||
error,
|
||||
} = useGetInvestorsQuery({ page: currentPage, size: pageSize });
|
||||
} = useGetInvestorsQuery({
|
||||
page: debouncedSearchTerm ? undefined : currentPage, // Omit pagination for search
|
||||
size: debouncedSearchTerm ? undefined : pageSize, // Omit pagination for search
|
||||
search: debouncedSearchTerm,
|
||||
},
|
||||
{
|
||||
skip: debouncedSearchTerm === "" && searchTerm !== "", // Skip if search is empty and it's not the initial request
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
@@ -127,7 +149,22 @@ const InvestorDetails = () => {
|
||||
});
|
||||
|
||||
|
||||
const extractedArray = filteredData?.map((item, idx) => ({
|
||||
|
||||
const customHeaders = [
|
||||
{ label: "ID", key: "id" },
|
||||
{ label: "Client ID", key: "clientReference_id" },
|
||||
{ label: "First Name", key: "principal.firstName" }, // Nested property
|
||||
{ label: "Last Name", key: "principal.lastName" }, // Nested property
|
||||
{ label: "Country", key: "country.countryName" }, // Nested property
|
||||
{ label: "Phone Number", key: "principal.mobileNumber" }, // Nested property
|
||||
{ label: "E-mail ID", key: "principal.emailAddress" }, // Nested property
|
||||
{ label: "Type", key: "investor_type.investorTypeName" }, // Nested property
|
||||
{ label: "Status", key: "ioStatus" }, // Simple property
|
||||
{ label: "KYC Status", key: "KYCStatus" }, // Simple property
|
||||
];
|
||||
|
||||
|
||||
const extractedArray = investorDetails?.data?.rows?.map((item, idx) => ({
|
||||
id: item?.id,
|
||||
"Sr No": (
|
||||
<Text
|
||||
@@ -187,7 +224,7 @@ const InvestorDetails = () => {
|
||||
"Type": (
|
||||
<Box w={"auto"} isTruncated={true}>
|
||||
<Text as={"span"} >
|
||||
<Badge colorScheme={item.ioStatus ? "gray" : "green"} variant={'outline'} fontWeight={"700"} px={2} py={0.5}>
|
||||
<Badge color={"forestGreen.500"} variant={'ghost'} fontWeight={"700"} px={2} py={0.5}>
|
||||
{item?.investor_type?.investorTypeName}
|
||||
</Badge>
|
||||
</Text>
|
||||
@@ -270,6 +307,7 @@ const InvestorDetails = () => {
|
||||
};
|
||||
|
||||
console.log(investorDetails?.data?.totalItems);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
@@ -297,7 +335,7 @@ const InvestorDetails = () => {
|
||||
/>
|
||||
|
||||
<HStack className="col" display={"flex"} alignItems={"center"}>
|
||||
<Select
|
||||
{/* <Select
|
||||
focusBorderColor="green.500"
|
||||
size={"sm"}
|
||||
fontSize={"xs"}
|
||||
@@ -310,9 +348,9 @@ const InvestorDetails = () => {
|
||||
<option value="all">All</option>
|
||||
<option value="ban">Ban</option>
|
||||
<option value="unban">UnBan</option>
|
||||
</Select>
|
||||
</Select> */}
|
||||
|
||||
<Select
|
||||
{/* <Select
|
||||
focusBorderColor="green.500"
|
||||
size={"sm"}
|
||||
fontSize={"xs"}
|
||||
@@ -325,7 +363,7 @@ const InvestorDetails = () => {
|
||||
<option value="all">All</option>
|
||||
<option value="ban">Ban</option>
|
||||
<option value="unban">UnBan</option>
|
||||
</Select>
|
||||
</Select> */}
|
||||
|
||||
<Select
|
||||
focusBorderColor="green.500"
|
||||
@@ -333,11 +371,11 @@ const InvestorDetails = () => {
|
||||
fontSize={"xs"}
|
||||
cursor={"pointer"}
|
||||
>
|
||||
<option value="" defaultValue={"all"} disabled hidden>
|
||||
<option value="all" defaultValue={"all"} disabled hidden>
|
||||
Status
|
||||
</option>
|
||||
|
||||
<option value="all">All</option>
|
||||
<option value="all">Status</option>
|
||||
<option value="ban">Ban</option>
|
||||
<option value="unban">UnBan</option>
|
||||
</Select>
|
||||
@@ -348,10 +386,10 @@ const InvestorDetails = () => {
|
||||
fontSize={"xs"}
|
||||
cursor={"pointer"}
|
||||
>
|
||||
<option value="" defaultValue={"all"} disabled hidden>
|
||||
<option value="all" defaultValue={"all"} disabled hidden>
|
||||
KYC Status
|
||||
</option>
|
||||
<option value="all">All</option>
|
||||
<option value="all">KYC Status</option>
|
||||
<option value="completed">Completed</option>
|
||||
<option value="incompleted">Incompleted</option>
|
||||
</Select>
|
||||
@@ -362,9 +400,10 @@ const InvestorDetails = () => {
|
||||
fontSize={"xs"}
|
||||
cursor={"pointer"}
|
||||
>
|
||||
<option value="" defaultValue={"all"} disabled hidden>
|
||||
<option value="all" defaultValue={"all"} disabled hidden>
|
||||
Country
|
||||
</option>
|
||||
<option value="all">All</option>
|
||||
<option value="behrain">Behrain</option>
|
||||
<option value="kuwait">Kuwait</option>
|
||||
<option value="oman">Oman</option>
|
||||
@@ -381,7 +420,25 @@ const InvestorDetails = () => {
|
||||
totalItems={investorDetails?.data?.totalItems}
|
||||
|
||||
/>
|
||||
|
||||
</HStack>
|
||||
|
||||
|
||||
<Button
|
||||
onClick={() =>
|
||||
exportToExcel(investorDetails?.data?.rows, customHeaders)
|
||||
}
|
||||
leftIcon={<LuFileSpreadsheet />}
|
||||
colorScheme="forestGreen"
|
||||
size={"sm"}
|
||||
variant={"outline"}
|
||||
rounded={"sm"}
|
||||
fontSize={"xs"}
|
||||
w={100}
|
||||
me={2}
|
||||
>
|
||||
Export xls
|
||||
</Button>
|
||||
</HStack>
|
||||
<InvestmentDetailsEdit
|
||||
id={actionId}
|
||||
|
||||
@@ -27,14 +27,6 @@ const Sponser = () => {
|
||||
|
||||
const navigate = useNavigate();
|
||||
const toast = useToast();
|
||||
|
||||
|
||||
|
||||
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
|
||||
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [deleteAlert, setDeleteAlert] = useState(false);
|
||||
const [actionId, setActionId] = useState(false);
|
||||
@@ -46,9 +38,29 @@ const Sponser = () => {
|
||||
// =========================== [Use State] =============================
|
||||
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
|
||||
const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page);
|
||||
const {data: sponsors,error,isLoading: isSponserLoading,} = useGetSponserMasterQuery({ page: currentPage, size: pageSize });
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
|
||||
|
||||
// console.log(sponsors?.data?.rows);
|
||||
// Debounce the search term to avoid making a request on every keystroke
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedSearchTerm(searchTerm);
|
||||
}, 500); // Adjust delay as needed
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
};
|
||||
}, [searchTerm]);
|
||||
const { data: sponsors, error, isLoading: isSponserLoading } = useGetSponserMasterQuery(
|
||||
{
|
||||
page: debouncedSearchTerm ? undefined : currentPage, // Omit pagination for search
|
||||
size: debouncedSearchTerm ? undefined : pageSize, // Omit pagination for search
|
||||
searchTerm: debouncedSearchTerm,
|
||||
},
|
||||
{
|
||||
skip: debouncedSearchTerm === "" && searchTerm !== "", // Skip if search is empty and it's not the initial request
|
||||
}
|
||||
);
|
||||
console.log(sponsors?.data?.rows);
|
||||
|
||||
// ==============================[Table Filter]========================
|
||||
|
||||
@@ -69,7 +81,7 @@ const Sponser = () => {
|
||||
"Action",
|
||||
];
|
||||
|
||||
const extractedArray = filteredData?.map((item, index) => ({
|
||||
const extractedArray = sponsors?.data?.rows?.map((item, index) => ({
|
||||
"Sr No": (
|
||||
<Text
|
||||
w={'24px'}
|
||||
|
||||
@@ -30,21 +30,21 @@ export const banInvestorDetails = createApi({
|
||||
|
||||
updateUnban: builder.mutation({
|
||||
query: ({ id, data }) => ({
|
||||
url: `/investorDetails/admin/unBanById/${id}`,
|
||||
url: `/investorDetails/admin/banById/${id}`,
|
||||
method: "PATCH",
|
||||
body: data,
|
||||
}),
|
||||
invalidatesTags: ["getBanInvestor"],
|
||||
invalidatesTags: ["getBanInvestor","getUnbanInvestor"],
|
||||
}),
|
||||
|
||||
|
||||
updateBan: builder.mutation({
|
||||
query: ({ id, data }) => ({
|
||||
url: `/investorDetails/admin/banById/${id}`,
|
||||
url: `/investorDetails/admin/unBanById/${id}`,
|
||||
method: "PATCH",
|
||||
body: data,
|
||||
}),
|
||||
invalidatesTags: ["getBanInvestor"],
|
||||
invalidatesTags: ["getBanInvestor", "getUnbanInvestor"],
|
||||
}),
|
||||
|
||||
}),
|
||||
|
||||
@@ -11,11 +11,22 @@ export const investorDetails = createApi({
|
||||
baseQuery: baseQuery,
|
||||
tagTypes: [],
|
||||
endpoints: (builder) => ({
|
||||
|
||||
getInvestors: builder.query({
|
||||
query: ({ page, size }) =>
|
||||
`/investorDetails/admin?page=${page}&size=${size}`,
|
||||
providesTags: ["getInvestors"],
|
||||
}),
|
||||
query: ({ page, size, search }) => {
|
||||
// Start with the base URL, including searchTerm
|
||||
let baseURL = `/investorDetails/admin/?search=${search || ""}`;
|
||||
|
||||
// Conditionally append page and size parameters if they are defined
|
||||
if (page !== undefined && size !== undefined) {
|
||||
baseURL += `&page=${page}&size=${size}`;
|
||||
}
|
||||
|
||||
return baseURL;
|
||||
},
|
||||
providesTags: ["getInvestors"],
|
||||
}),
|
||||
|
||||
|
||||
// =====[get investment details ]
|
||||
getInvestorsDetailsById: builder.query({
|
||||
|
||||
@@ -253,6 +253,14 @@ export const ioService = createApi({
|
||||
invalidatesTags: ["getIOById"],
|
||||
}),
|
||||
|
||||
updateCancleStatus: builder.mutation({
|
||||
query: ({ id, data }) => ({
|
||||
url: `/io/admin/transaction/${id}/cancel`,
|
||||
method: "POST",
|
||||
}),
|
||||
invalidatesTags: ["getIOById"],
|
||||
}),
|
||||
|
||||
|
||||
|
||||
// ==============[ Displaye Orders ]===============
|
||||
@@ -317,11 +325,18 @@ export const ioService = createApi({
|
||||
|
||||
// ======[Get All]=====
|
||||
|
||||
|
||||
getSponserMaster: builder.query({
|
||||
query: ({ page, size }) => `/sponsor/admin?page=${page}&size=${size}`,
|
||||
query: ({ page, size, searchTerm }) => {
|
||||
let baseURL = `/sponsor/admin/?search_data=${searchTerm || ""}`;
|
||||
if (page !== undefined && size !== undefined) {
|
||||
baseURL += `&page=${page}&size=${size}`; // Only add pagination if both are defined
|
||||
}
|
||||
return baseURL;
|
||||
},
|
||||
providesTags: ["getSponser"],
|
||||
}),
|
||||
|
||||
|
||||
// ========[Delete Sponser]========
|
||||
|
||||
deleteSponser: builder.mutation({
|
||||
@@ -471,6 +486,9 @@ export const {
|
||||
useUpdateExitToInvestorMutation,
|
||||
|
||||
|
||||
useUpdateCancleStatusMutation,
|
||||
|
||||
|
||||
// ==============[ Sponser ]===============
|
||||
useGetSponserMasterQuery,
|
||||
useGetSponserMasterActiveQuery,
|
||||
|
||||
@@ -28,6 +28,7 @@ export const baseQuery = async (args, api, extraOptions) => {
|
||||
if (result.error && result.error.status === 403) {
|
||||
// Handle token refresh
|
||||
const refreshToken = localStorage.getItem("refreshToken");
|
||||
console.log(refreshToken);
|
||||
if (refreshToken) {
|
||||
try {
|
||||
const refreshResult = await fetchBaseQuery({
|
||||
@@ -48,14 +49,7 @@ export const baseQuery = async (args, api, extraOptions) => {
|
||||
|
||||
// Save new tokens
|
||||
localStorage.setItem("accessToken", refreshResult?.data?.data?.access?.token);
|
||||
localStorage.setItem(
|
||||
"refreshToken",
|
||||
refreshResult?.data?.data?.refresh?.token
|
||||
);
|
||||
localStorage.setItem(
|
||||
"refreshTokenExp",
|
||||
refreshResult.data?.data?.refresh.expires
|
||||
);
|
||||
|
||||
|
||||
// Retry the original request with the new token
|
||||
result = await fetchBaseQuery({
|
||||
@@ -69,10 +63,16 @@ export const baseQuery = async (args, api, extraOptions) => {
|
||||
},
|
||||
})(args, api, extraOptions);
|
||||
}else{
|
||||
|
||||
console.log('refresh failed');
|
||||
localStorage.clear();
|
||||
window.location.href = '/login'; // Redirect to login page
|
||||
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to refresh token:", err);
|
||||
localStorage.clear();
|
||||
window.location.href = '/login'; // Redirect to login page
|
||||
// Handle refresh failure (e.g., redirect to login)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user