From f8b33e3eb563500cb17ab5c48501f29e325afb1f Mon Sep 17 00:00:00 2001 From: "Siddhesh.More" Date: Wed, 2 Oct 2024 13:32:35 +0530 Subject: [PATCH 1/8] update --- src/Components/FormField.jsx | 3 +- src/Constants/Constants.js | 60 +++----- .../Investor/BankInvestor/BankInvestor.jsx | 36 +++-- .../Investor/BankInvestor/ReasonBanModal.jsx | 8 +- .../Investor/UnbanInvestor/ReasonBanModal.jsx | 12 +- .../Investor/UnbanInvestor/UnbanInvestor.jsx | 12 +- .../ViewIO/HeaderModal/UpdateIOStatus.jsx | 138 ++++++++++-------- .../IO_Management/ViewIO/ViewIOTable.jsx | 2 +- .../InvestorDetails/InvestorDetails.jsx | 37 ++++- src/Services/ban.investor.service.js | 4 +- src/Services/io.service.js | 11 ++ src/Services/token.serivce.js | 13 +- 12 files changed, 200 insertions(+), 136 deletions(-) diff --git a/src/Components/FormField.jsx b/src/Components/FormField.jsx index c18c14f..109e62d 100644 --- a/src/Components/FormField.jsx +++ b/src/Components/FormField.jsx @@ -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" diff --git a/src/Constants/Constants.js b/src/Constants/Constants.js index 697df27..73a6068 100644 --- a/src/Constants/Constants.js +++ b/src/Constants/Constants.js @@ -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"); }; diff --git a/src/Pages/Admin/Investor/BankInvestor/BankInvestor.jsx b/src/Pages/Admin/Investor/BankInvestor/BankInvestor.jsx index e7cd5ce..ef94156 100644 --- a/src/Pages/Admin/Investor/BankInvestor/BankInvestor.jsx +++ b/src/Pages/Admin/Investor/BankInvestor/BankInvestor.jsx @@ -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": ( - {formatDate(item?.principal?.createdAt)} + {formatDate(item?.date)} ), @@ -142,14 +147,14 @@ const BankInvestor = () => { "First Name": ( - {item?.principal?.firstName} + {item?.firstName} ), "Last Name": ( - {item?.principal?.lastName} + {item?.lastName} ), @@ -170,21 +175,22 @@ const BankInvestor = () => { "E-mail ID": ( - {item?.principal?.emailAddress} + {item?.emailAddress} ), "KYC Status": ( - - {item?.KYCStatus} - + + {item?.KYCStatus === true ? "Completed" : "Incompleted"} + ), Action: ( @@ -196,7 +202,9 @@ const BankInvestor = () => { colorScheme={"red"} px={2} py={0.5} - onClick={onOpen} + onClick={()=>{ + setActionId(item?.id) + onOpen()}} > Ban Investor diff --git a/src/Pages/Admin/Investor/BankInvestor/ReasonBanModal.jsx b/src/Pages/Admin/Investor/BankInvestor/ReasonBanModal.jsx index 366d6bd..5049b92 100644 --- a/src/Pages/Admin/Investor/BankInvestor/ReasonBanModal.jsx +++ b/src/Pages/Admin/Investor/BankInvestor/ReasonBanModal.jsx @@ -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 - Reason for Ban + Reason for Unban diff --git a/src/Pages/Admin/Investor/UnbanInvestor/ReasonBanModal.jsx b/src/Pages/Admin/Investor/UnbanInvestor/ReasonBanModal.jsx index d247f6b..934d47d 100644 --- a/src/Pages/Admin/Investor/UnbanInvestor/ReasonBanModal.jsx +++ b/src/Pages/Admin/Investor/UnbanInvestor/ReasonBanModal.jsx @@ -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 ] = useUpdateBanMutation() - 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: () => ( diff --git a/src/Pages/Admin/Investor/UnbanInvestor/UnbanInvestor.jsx b/src/Pages/Admin/Investor/UnbanInvestor/UnbanInvestor.jsx index f947a78..9c42c4a 100644 --- a/src/Pages/Admin/Investor/UnbanInvestor/UnbanInvestor.jsx +++ b/src/Pages/Admin/Investor/UnbanInvestor/UnbanInvestor.jsx @@ -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 = () => { - {item?.KYCStatus ? "True" : "False"} + {item?.KYCStatus === true ? "Completed" : "Incompleted"} ), @@ -184,7 +185,10 @@ const UnbanInvestor = () => { colorScheme={"red"} px={2} py={0.5} - onClick={onOpen} + onClick={()=>{ + setActionId(item?.id) + onOpen() + }} > Ban Investor diff --git a/src/Pages/IO_Management/ViewIO/HeaderModal/UpdateIOStatus.jsx b/src/Pages/IO_Management/ViewIO/HeaderModal/UpdateIOStatus.jsx index 0bf865c..57bf2c0 100644 --- a/src/Pages/IO_Management/ViewIO/HeaderModal/UpdateIOStatus.jsx +++ b/src/Pages/IO_Management/ViewIO/HeaderModal/UpdateIOStatus.jsx @@ -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 ( @@ -94,7 +108,7 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => { textAlign={"left"} > {selectedItem ? ( - { ? "green" : selectedItem === "Exited" ? "red" - : selectedItem === "Canclled" + : selectedItem === "Cancelled" ? "orange" : "purple" - } - py={"3px"} px={"8px"} + } + py={"3px"} + px={"8px"} > {selectedItem} - ) : "Select Item"} + ) : ( + "Select Item" + )} - {status?.length > 0 ? - {status?.map(({ id, statusAdmin }) => ( - handleMenuItemClick(statusAdmin, id)} - > - 0 ? ( + + {status?.map(({ id, statusAdmin }) => ( + handleMenuItemClick(statusAdmin, id)} > - {statusAdmin} - - - ))} - :""} + + {statusAdmin} + + + ))} + + ) : ( + "" + )} - {error} + + {error} + diff --git a/src/Pages/IO_Management/ViewIO/ViewIOTable.jsx b/src/Pages/IO_Management/ViewIO/ViewIOTable.jsx index 4c28d0e..b2889c8 100644 --- a/src/Pages/IO_Management/ViewIO/ViewIOTable.jsx +++ b/src/Pages/IO_Management/ViewIO/ViewIOTable.jsx @@ -429,7 +429,7 @@ const ViewIOTable = () => { setMouseEntered={setMouseEntered} /> - + {/* */} setDeleteAlert(false)} diff --git a/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx b/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx index fd07db7..c194dde 100644 --- a/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx +++ b/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx @@ -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 @@ -127,6 +128,21 @@ const InvestorDetails = () => { }); + + 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 = filteredData?.map((item, idx) => ({ id: item?.id, "Sr No": ( @@ -270,6 +286,7 @@ const InvestorDetails = () => { }; console.log(investorDetails?.data?.totalItems); + return ( @@ -381,7 +398,25 @@ const InvestorDetails = () => { totalItems={investorDetails?.data?.totalItems} /> + + + + ({ + url: `/io/admin/transaction/${id}/cancel`, + method: "POST", + }), + invalidatesTags: ["getIOById"], + }), + // ==============[ Displaye Orders ]=============== @@ -471,6 +479,9 @@ export const { useUpdateExitToInvestorMutation, + useUpdateCancleStatusMutation, + + // ==============[ Sponser ]=============== useGetSponserMasterQuery, useGetSponserMasterActiveQuery, diff --git a/src/Services/token.serivce.js b/src/Services/token.serivce.js index a543760..0719560 100644 --- a/src/Services/token.serivce.js +++ b/src/Services/token.serivce.js @@ -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,7 +63,10 @@ export const baseQuery = async (args, api, extraOptions) => { }, })(args, api, extraOptions); }else{ + console.log('refresh failed'); + localStorage.clear(); + } } catch (err) { console.error("Failed to refresh token:", err); From 7b24db3e00459d98fc705ec0d59de5bff09b24f3 Mon Sep 17 00:00:00 2001 From: "Siddhesh.More" Date: Wed, 2 Oct 2024 14:01:31 +0530 Subject: [PATCH 2/8] WFH update 0.1 --- src/App.jsx | 8 ++++++++ src/Layout/DefaultLayout.jsx | 10 ++++++++++ .../Admin/Investor/UnbanInvestor/ReasonBanModal.jsx | 2 +- src/Services/ban.investor.service.js | 4 ++-- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 22af93e..3190ccd 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -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); }; diff --git a/src/Layout/DefaultLayout.jsx b/src/Layout/DefaultLayout.jsx index ca459f1..183a614 100644 --- a/src/Layout/DefaultLayout.jsx +++ b/src/Layout/DefaultLayout.jsx @@ -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() + navigate('/login') + } + + + }, []) + + useEffect(() => { const savedIndex = localStorage.getItem("openAccordionIndex"); if (savedIndex !== null) { diff --git a/src/Pages/Admin/Investor/UnbanInvestor/ReasonBanModal.jsx b/src/Pages/Admin/Investor/UnbanInvestor/ReasonBanModal.jsx index 934d47d..3e7d9d2 100644 --- a/src/Pages/Admin/Investor/UnbanInvestor/ReasonBanModal.jsx +++ b/src/Pages/Admin/Investor/UnbanInvestor/ReasonBanModal.jsx @@ -42,7 +42,7 @@ import { useUpdateBanMutation, useUpdateUnbanMutation } from "../../../../Servic resolver: yupResolver(conformModalSchema), }); - const [ updateBan ] = useUpdateBanMutation() + const [ updateBan ] = useUpdateUnbanMutation() diff --git a/src/Services/ban.investor.service.js b/src/Services/ban.investor.service.js index c859cc1..3e4aa84 100644 --- a/src/Services/ban.investor.service.js +++ b/src/Services/ban.investor.service.js @@ -30,7 +30,7 @@ export const banInvestorDetails = createApi({ updateUnban: builder.mutation({ query: ({ id, data }) => ({ - url: `/investorDetails/admin/unBanById/${id}`, + url: `/investorDetails/admin/banById/${id}`, method: "PATCH", body: data, }), @@ -40,7 +40,7 @@ export const banInvestorDetails = createApi({ updateBan: builder.mutation({ query: ({ id, data }) => ({ - url: `/investorDetails/admin/banById/${id}`, + url: `/investorDetails/admin/unBanById/${id}`, method: "PATCH", body: data, }), From 084641c56130b1c2e2eac807477562b49123b75f Mon Sep 17 00:00:00 2001 From: "Siddhesh.More" Date: Wed, 2 Oct 2024 14:02:14 +0530 Subject: [PATCH 3/8] 0.2 --- src/Layout/DefaultLayout.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Layout/DefaultLayout.jsx b/src/Layout/DefaultLayout.jsx index 183a614..bf8cdc0 100644 --- a/src/Layout/DefaultLayout.jsx +++ b/src/Layout/DefaultLayout.jsx @@ -95,7 +95,7 @@ const DashboardLayout = ({ isOnline }) => { useEffect(() => { if(!localStorage.getItem('accessToken') && !localStorage.getItem('refreshToken')){ logOutHandler() - navigate('/login') + return navigate('/login') } From 10221c03d9eae6e09abab4203c6bd2df64a1bacd Mon Sep 17 00:00:00 2001 From: "Siddhesh.More" Date: Wed, 2 Oct 2024 14:21:26 +0530 Subject: [PATCH 4/8] 0.3 --- src/Services/token.serivce.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Services/token.serivce.js b/src/Services/token.serivce.js index 0719560..c739d96 100644 --- a/src/Services/token.serivce.js +++ b/src/Services/token.serivce.js @@ -66,6 +66,7 @@ export const baseQuery = async (args, api, extraOptions) => { console.log('refresh failed'); localStorage.clear(); + window.location.href = '/login'; // Redirect to login page } } catch (err) { From 2ae81ef0325d8516ff7c50c1689a0d609f071dac Mon Sep 17 00:00:00 2001 From: "Siddhesh.More" Date: Wed, 2 Oct 2024 18:41:38 +0530 Subject: [PATCH 5/8] upated --- src/Components/DataTable/NormalTable.jsx | 100 ++++++++--- src/Layout/DefaultLayout.jsx | 4 +- src/Pages/Admin/Notification.jsx | 169 +++++++++++++++++- .../IO_Management/ViewIO/ViewIOdataHeader.jsx | 10 +- .../InvestorDetails/InvestorDetails.jsx | 27 ++- src/Pages/Master/Sponser/Sponsers.jsx | 34 ++-- src/Services/investor.details.service.js | 19 +- src/Services/io.service.js | 11 +- src/Services/token.serivce.js | 2 + 9 files changed, 327 insertions(+), 49 deletions(-) diff --git a/src/Components/DataTable/NormalTable.jsx b/src/Components/DataTable/NormalTable.jsx index 97abfe4..d1dd2c1 100644 --- a/src/Components/DataTable/NormalTable.jsx +++ b/src/Components/DataTable/NormalTable.jsx @@ -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 ( - + {data?.length === 0 ? ( ) : ( @@ -37,26 +62,42 @@ const DataTable = ({ {total ? total : "Tanami v1.0.0"} - + + {showRadioButton && ( + + + + )} {tableHeadRow.map((heading, index) => ( - {isLoading ? : heading} - {/* {heading} */} ))} @@ -65,17 +106,18 @@ const DataTable = ({ {isLoading ? Array.from({ length: TABLE_PAGINATION?.size }).map( (_, index) => ( - + {tableHeadRow.map((_, i) => ( @@ -84,9 +126,26 @@ const DataTable = ({ ) ) : data?.map((item, index) => ( - + + {showRadioButton && ( + + handleCheckboxChange(item.id)} + /> + + )} {tableHeadRow.map((heading, i) => ( - { // dispach(loginUser(false)); setIsAuthenticate(false); Cookies.remove("isAuthenticated"); - localStorage.removeItem('refreshToken') - localStorage.removeItem('accessToken') - localStorage.removeItem('refreshTokenExp') + localStorage.clear(); navigate("/login"); }; diff --git a/src/Pages/Admin/Notification.jsx b/src/Pages/Admin/Notification.jsx index d4aaef1..5507eb9 100644 --- a/src/Pages/Admin/Notification.jsx +++ b/src/Pages/Admin/Notification.jsx @@ -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: () => , @@ -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": ( + + {/* {item.id} */} + {generateSerialNumber(idx,currentPage, pageSize )} + + + ), + "Client ID": ( + + + {item.clientReference_id} + + + ), + "First Name": ( + + + {item?.principal?.firstName} + + + ), + "Last Name": ( + + + {item?.principal?.lastName} + + + ), + Country: ( + + + {item?.country?.countryName} + + + ), + "Phone Number": ( + + + {item?.principal?.mobileNumber} + + + ), + "E-mail ID": ( + + + {item?.principal?.emailAddress} + + + ), + "Type": ( + + + + {item?.investor_type?.investorTypeName} + + + + ), + Status: ( + + + {item.ioStatus ? "Ban" : "Unban"} + + + ), + "KYC Status": ( + + + {item.KYCStatus ? "Completed" : "Not complete"} + + + ), + })); + return ( { errors={errors} onSubmit={handleSubmit(onSubmit)} btnLoading={isLoading} + > + + + + + + + + ); }; diff --git a/src/Pages/IO_Management/ViewIO/ViewIOdataHeader.jsx b/src/Pages/IO_Management/ViewIO/ViewIOdataHeader.jsx index 0e0bb9d..e41b1f9 100644 --- a/src/Pages/IO_Management/ViewIO/ViewIOdataHeader.jsx +++ b/src/Pages/IO_Management/ViewIO/ViewIOdataHeader.jsx @@ -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 }) => { - + { ? "green" : IODetails?.ioStatus?.statusAdmin === "Exited" ? "red" - : IODetails?.ioStatus?.statusAdmin === "Canclled" - ? "orange" + : IODetails?.ioStatus?.statusAdmin === "Cancelled" + ? "purple" : "purple" } > diff --git a/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx b/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx index c194dde..c654d91 100644 --- a/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx +++ b/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx @@ -49,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); @@ -62,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 + searchTerm: debouncedSearchTerm, + }, + { + skip: debouncedSearchTerm === "" && searchTerm !== "", // Skip if search is empty and it's not the initial request + } +); useEffect(() => { @@ -143,7 +164,7 @@ const InvestorDetails = () => { ]; - const extractedArray = filteredData?.map((item, idx) => ({ + const extractedArray = investorDetails?.data?.rows?.map((item, idx) => ({ id: item?.id, "Sr No": ( { 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": ( ({ + getInvestors: builder.query({ - query: ({ page, size }) => - `/investorDetails/admin?page=${page}&size=${size}`, - providesTags: ["getInvestors"], - }), + query: ({ page, size, searchTerm }) => { + // Start with the base URL, including searchTerm + let baseURL = `/investorDetails/admin/?search_data=${searchTerm || ""}`; + + // 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({ diff --git a/src/Services/io.service.js b/src/Services/io.service.js index 885a49c..c557548 100644 --- a/src/Services/io.service.js +++ b/src/Services/io.service.js @@ -325,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({ diff --git a/src/Services/token.serivce.js b/src/Services/token.serivce.js index c739d96..4e63ec8 100644 --- a/src/Services/token.serivce.js +++ b/src/Services/token.serivce.js @@ -71,6 +71,8 @@ export const baseQuery = async (args, api, extraOptions) => { } } 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) } } From 663072309245c1db425f6478ea3c54bd37174680 Mon Sep 17 00:00:00 2001 From: "Siddhesh.More" Date: Wed, 2 Oct 2024 18:55:32 +0530 Subject: [PATCH 6/8] 0.5 --- src/Components/FormInputView.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/FormInputView.jsx b/src/Components/FormInputView.jsx index ff0c467..dd95abe 100644 --- a/src/Components/FormInputView.jsx +++ b/src/Components/FormInputView.jsx @@ -62,7 +62,7 @@ const FormInputView = ({ w={6} h={6} src={ - " https://tanami.betadelivery.com/" + + import.meta.env.VITE_IMAGE_URL+ item?.logo } /> From cfd811708a2bb227063b5b23241c65415f7ffd0d Mon Sep 17 00:00:00 2001 From: "Siddhesh.More" Date: Wed, 2 Oct 2024 18:59:42 +0530 Subject: [PATCH 7/8] 0.6 --- src/Pages/Admin/Notification.jsx | 2 +- .../Investor_Management/InvestorDetails/InvestorDetails.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Pages/Admin/Notification.jsx b/src/Pages/Admin/Notification.jsx index 5507eb9..28a94ca 100644 --- a/src/Pages/Admin/Notification.jsx +++ b/src/Pages/Admin/Notification.jsx @@ -258,7 +258,7 @@ const Notification = () => { "Type": ( - + {item?.investor_type?.investorTypeName} diff --git a/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx b/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx index c654d91..e9ef3f9 100644 --- a/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx +++ b/src/Pages/Investor_Management/InvestorDetails/InvestorDetails.jsx @@ -224,7 +224,7 @@ const InvestorDetails = () => { "Type": ( - + {item?.investor_type?.investorTypeName} From c51ae9081f15a2242feb8278e6bd694a4e1ae4bb Mon Sep 17 00:00:00 2001 From: "Siddhesh.More" Date: Thu, 3 Oct 2024 13:48:09 +0530 Subject: [PATCH 8/8] 0.7 --- src/Components/DataTable/NormalTable.jsx | 2 +- .../IO_Management/CreateIO/Investors.jsx | 45 +++++++++++++++++-- .../InvestorDetails/InvestorDetails.jsx | 21 ++++----- src/Services/investor.details.service.js | 4 +- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/Components/DataTable/NormalTable.jsx b/src/Components/DataTable/NormalTable.jsx index d1dd2c1..aafab00 100644 --- a/src/Components/DataTable/NormalTable.jsx +++ b/src/Components/DataTable/NormalTable.jsx @@ -75,7 +75,7 @@ const NormalTable = ({ textTransform={"none"} > { }); }, 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 ( @@ -439,7 +462,7 @@ const Investors = ({ data }) => { pb={3} spacing="24px" > - + { value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} /> + + { cursor={"pointer"} /> - + { } = useGetInvestorsQuery({ page: debouncedSearchTerm ? undefined : currentPage, // Omit pagination for search size: debouncedSearchTerm ? undefined : pageSize, // Omit pagination for search - searchTerm: debouncedSearchTerm, + search: debouncedSearchTerm, }, { skip: debouncedSearchTerm === "" && searchTerm !== "", // Skip if search is empty and it's not the initial request @@ -335,7 +335,7 @@ const InvestorDetails = () => { /> - + */} - + */} @@ -386,10 +386,10 @@ const InvestorDetails = () => { fontSize={"xs"} cursor={"pointer"} > - - + @@ -400,9 +400,10 @@ const InvestorDetails = () => { fontSize={"xs"} cursor={"pointer"} > - + diff --git a/src/Services/investor.details.service.js b/src/Services/investor.details.service.js index f30d04e..f1ed90e 100644 --- a/src/Services/investor.details.service.js +++ b/src/Services/investor.details.service.js @@ -13,9 +13,9 @@ export const investorDetails = createApi({ endpoints: (builder) => ({ getInvestors: builder.query({ - query: ({ page, size, searchTerm }) => { + query: ({ page, size, search }) => { // Start with the base URL, including searchTerm - let baseURL = `/investorDetails/admin/?search_data=${searchTerm || ""}`; + let baseURL = `/investorDetails/admin/?search=${search || ""}`; // Conditionally append page and size parameters if they are defined if (page !== undefined && size !== undefined) {