Compare commits

...

42 Commits

Author SHA1 Message Date
YasinShaikh123
69f76bbdce [fixed] - closing date 2024-12-31 16:06:13 +05:30
YasinShaikh123
25df0d6160 [fixed] - io Deatils 2024-12-31 15:47:48 +05:30
YasinShaikh123
51727d4de1 [test] 2024-12-31 13:48:50 +05:30
YasinShaikh123
1539493641 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-12-31 13:45:31 +05:30
YasinShaikh123
d63ac2eb2b bugs fix 2024-12-31 13:42:28 +05:30
Swapnil Bendal
9eca3ae9fc [update] - pagination on investor details 2024-12-27 15:22:34 +05:30
Swapnil Bendal
212f5d4d37 [fixed] - on IO Transaction 2024-12-24 18:08:15 +05:30
YasinShaikh123
b620cd410d update bugs👍 2024-12-24 17:56:55 +05:30
Swapnil Bendal
84298ff453 [update] - IO Transaction bug fix 2024-12-24 16:59:01 +05:30
Swapnil Bendal
8eae4222f4 [fixed] - pending action 2024-12-24 16:36:07 +05:30
52a987b616 Merge pull request '[fixed] - token service' (#28) from dev into main
Reviewed-on: #28
2024-12-23 14:48:38 +00:00
Swapnil Bendal
2a3c211b56 [fixed] - token service 2024-12-23 19:33:08 +05:30
4d6a8bb472 Merge pull request 'dev' (#27) from dev into main
Reviewed-on: #27
2024-12-20 14:49:35 +00:00
Swapnil Bendal
41a60c0892 [fixed] - change password 2024-12-20 20:18:26 +05:30
Swapnil Bendal
5c05a68bb0 [update] - readme 2024-12-20 20:10:43 +05:30
f02f9c8b7d Merge pull request '[update] - readme' (#26) from dev into main
Reviewed-on: #26
2024-12-20 14:39:43 +00:00
Swapnil Bendal
137912aa11 [update] - readme 2024-12-20 20:08:44 +05:30
e3fe5a1618 Merge pull request '[fixed] - changes password' (#25) from dev into main
Reviewed-on: #25
2024-12-20 14:30:54 +00:00
Swapnil Bendal
edcb4cd7b9 [fixed] - changes password 2024-12-20 20:00:13 +05:30
c72f3ece4e Merge pull request 'dev' (#24) from dev into main
Reviewed-on: #24
2024-12-20 12:26:22 +00:00
YasinShaikh123
85be7c891e update bugs 2024-12-20 17:17:18 +05:30
YasinShaikh123
e41d6b17b9 update env file ang bugs 2024-12-20 16:22:29 +05:30
3217605a0f Update README.md 2024-12-20 10:24:31 +00:00
b4d28387fa Update README.md 2024-12-20 09:36:28 +00:00
Swapnil Bendal
5411d4cd18 [fixed] - email message forget password 2024-12-12 17:47:57 +05:30
Swapnil Bendal
6a0aa17e2d [update]- profile page 2024-12-12 17:28:32 +05:30
Swapnil Bendal
471e4f32ab [fixed] - token server 2024-12-12 16:19:36 +05:30
YasinShaikh123
5d2c28f6ca update change password 2024-12-12 13:52:55 +05:30
YasinShaikh123
49f39e1c2c update subadmin 2024-12-12 13:39:19 +05:30
YasinShaikh123
f9c7bf9d5d update forget passsword 2024-12-12 13:20:12 +05:30
Swapnil Bendal
49beb9539a [fixed] - role 2024-12-11 20:30:52 +05:30
Swapnil Bendal
ed27ed6939 [update] - io cash, IO nav and pending 2024-12-11 19:36:06 +05:30
Swapnil Bendal
d84b3a0e35 [update] - role check 2024-12-11 18:47:43 +05:30
Swapnil Bendal
20c0c7840f [update] - constant 2024-12-11 15:45:56 +05:30
Swapnil Bendal
bbfd617b27 [update] - finalise 2024-12-11 14:54:13 +05:30
Swapnil Bendal
87e0716383 [added] - .env.exmple 2024-12-11 13:21:43 +05:30
Swapnil Bendal
c7d6a0fe36 [update] - token service 2024-12-11 12:59:19 +05:30
Swapnil Bendal
c83aaa411a Merge remote-tracking branch 'origin/Sprint-9' into audit-fix/swapnil 2024-12-11 11:42:24 +05:30
Swapnil Bendal
a2fe1435cb [update] - token service 2024-12-11 11:41:02 +05:30
6a9e0f9908 Merge pull request 'Yasin' (#23) from Yasin into Sprint-9
Reviewed-on: #23
2024-12-10 13:35:07 +00:00
Swapnil Bendal
4ca28fd910 [untested] - code checkout in remote 2024-12-06 20:25:12 +05:30
88dc9d14fe Merge pull request 'Yasin' (#22) from Yasin into Sprint-9
Reviewed-on: #22
2024-12-06 07:18:57 +00:00
42 changed files with 2078 additions and 1942 deletions

28
.env.example Normal file
View File

@@ -0,0 +1,28 @@
# Default Value Maker
VITE_MAKER="Maker"
# Default Value Checker
VITE_CHECKER="Checker"
# Role Encryption key
VITE_ROLE_ENCRYPTION_KEY="export"
# Super Admin
VITE_SUPER_ADMIN_ID=1
# BaseURL
VITE_BAS_URL="your_base_url"
# BaseURL for Images
VITE_IMAGE_URL="your_base_url"
# Max try re-genrate token
VITE_MAX_TRY_REGENRATE_TOKEN=3
VITE_STATUS_DRAFT="Draft"
VITE_STATUS_PROCESSING="Processing"
VITE_STATUS_OPEN="Open"
VITE_STATUS_CLOSED="Closed"
VITE_STATUS_EXITED="Exited"
VITE_STATUS_CANCELLED="Cancelled"
VITE_STATUS_DEACTIVATE="DeActivate"

117
README.md
View File

@@ -1,10 +1,113 @@
# React + Vite # **Tanami Capital**
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. **Tanami** is a cutting-edge fintech platform designed to streamline investment opportunities for users in the Gulf region. It features two main components:
Currently, two official plugins are available: - **Admin Panel:** A web-based dashboard for managing users, monitoring transactions, and overseeing investments efficiently.
- **Mobile Application:** A user-friendly app that empowers individuals to invest in diverse asset classes, including real estate, private equity, and other financial instruments located in Gulf countries.
---
## **Key Features**
- **Regional Focus:** Exclusively operational in Gulf countries, offering investment opportunities tailored to the region.
- **Diverse Investment Options:** Enables users to invest in financial instruments like real estate and private equity with ease and transparency.
- **Comprehensive Admin Tools:** The admin panel offers robust tools for tracking and managing platform activity.
---
## **Current Status**
The project is **live and operational**, catering specifically to the investment needs of users in the Gulf region.
---
## **Table of Contents**
- [Installation](#installation)
- [Usage](#usage)
- [Environment Variables](#environment-variables)
- [Scripts](#scripts)
- [License](#license)
---
## **Installation**
### **Prerequisites**
- [Node.js](https://nodejs.org/) (version 14 or higher recommended)
- [npm](https://www.npmjs.com/) (bundled with Node.js)
### **Steps**
1. Clone the repository:
```bash
git clone http://git.wdipl.com/Siddhesh.More/tanami-admin-panel.git
```
2. Navigate to the project directory:
```bash
cd tanami-admin-panel
```
3. Install dependencies:
```bash
npm install
```
---
## **Usage**
### **Development Mode**
1. Start the development server:
```bash
npm run dev
```
2. Open your browser and navigate to:
```
http://localhost:5173/
```
### **Production Mode**
1. Install [PM2](https://pm2.keymetrics.io/) globally for process management:
```bash
npm install pm2 -g
```
2. Build the application (if applicable):
```bash
npm run build
```
3. Serve the application using PM2:
```bash
pm2 serve ./dist <port_number> --spa --name=<application_name>
```
Replace:
- `./dist` with your build directory.
- `<port_number>` with the desired port (e.g., `3000`).
- `<application_name>` with the name of your application.
4. Save the PM2 process list and enable startup on system reboot:
```bash
pm2 save
pm2 startup
```
---
## **Environment Variables**
Create a `.env` file in the root directory based on the structure of [`.env.example`](.env.example).
---
## **Scripts**
| Script | Description |
|---------------------|-------------------------------------------------------------|
| `npm run dev` | Starts the app in development mode with `Vite` server. |
| `npm run build` | Builds the app for production. |
| `npm run lint` | Runs ESLint to check for code quality issues. |
| `npm run preview` | Previews the production build locally. |
---
## **License**
This project is licensed under the [MIT License](LICENSE).
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
# rubix-admin-panel
# tanami-admin-panel

View File

@@ -63,8 +63,8 @@ const App = () => {
path="/*" path="/*"
element={ element={
// isOnline ? ( // isOnline ? (
// isAuthenticate || isAuthenticatedInCookie === "true" ? ( isAuthenticate || isAuthenticatedInCookie === "true" ? (
localStorage.getItem('accessToken') && localStorage.getItem('refreshToken') ? ( // localStorage.getItem('accessToken') && localStorage.getItem('refreshToken') ? (
// true ? ( // true ? (
<DefaultLayout isOnline={isOnline} /> <DefaultLayout isOnline={isOnline} />
) : ( ) : (

View File

@@ -31,6 +31,7 @@ import Header from "../Header";
import ToastBox from "../ToastBox"; import ToastBox from "../ToastBox";
import BannerMainCard from "./BannerMainCard"; import BannerMainCard from "./BannerMainCard";
const AddBanner = ({ createApi, navigateLink, title, center }) => { const AddBanner = ({ createApi, navigateLink, title, center }) => {
const toast = useToast(); const toast = useToast();
const navigate = useNavigate(); const navigate = useNavigate();

View File

@@ -5,7 +5,7 @@ import { ChevronLeftIcon, ChevronRightIcon } from "@chakra-ui/icons";
const Pagination = ({ const Pagination = ({
pageSize, pageSize,
setPageSize, setPageSize,
totalItems, totalItems = 1,
isLoading, isLoading,
setCurrentPage, setCurrentPage,
currentPage, currentPage,
@@ -49,7 +49,7 @@ const Pagination = ({
value={pageSize} value={pageSize}
onChange={handlePageSizeChange} onChange={handlePageSizeChange}
> >
{[15, 20, 30]?.map((size) => ( {[15, 20, 30, 500]?.map((size) => (
<option key={size} value={size}> <option key={size} value={size}>
{size} {size}
</option> </option>
@@ -84,7 +84,7 @@ const Pagination = ({
onClick={paginationNext} onClick={paginationNext}
className="link pointer" className="link pointer"
isDisabled={currentPage === totalPages} isDisabled={currentPage === totalPages}
aria-label="Next Page" aria-label="Next Page"
/> />
</HStack> </HStack>
</HStack> </HStack>

View File

@@ -1,6 +1,5 @@
import { Box, Text } from "@chakra-ui/react"; import { Box, Text } from "@chakra-ui/react";
import React, { useRef } from "react"; import React from "react";
import audioClick from "../assets/click-151673.mp3";
const RoleSwitchButton = ({ isSwitchOn, setIsSwitchOn }) => { const RoleSwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {

View File

@@ -1,10 +1,9 @@
import dns from "node:dns" import dns from "node:dns"
import * as XLSX from 'xlsx'; import * as XLSX from 'xlsx';
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
export const generateSerialNumber = (index, currentPage, pageSize) => { export const generateSerialNumber = (index, currentPage = 1, pageSize = 1) => {
return (currentPage - 1) * pageSize + (index + 1); return (currentPage - 1) * pageSize + (index + 1);
}; };
@@ -12,7 +11,7 @@ export function getTomorrowDate() {
const today = new Date(); const today = new Date();
const tomorrow = new Date(today); const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1); tomorrow.setDate(today.getDate() + 1);
// Format the date as YYYY-MM-DD (ISO 8601) // Format the date as YYYY-MM-DD (ISO 8601)
return tomorrow.toISOString().split('T')[0]; return tomorrow.toISOString().split('T')[0];
} }
@@ -34,7 +33,7 @@ export function removeTrailingZeros(value) {
} }
export function getCountdownTimer(utcDateString) { export function getCountdownTimer(utcDateString) {
// Parse the UTC datetime string into a Date object // Parse the UTC datetime string into a Date object
const targetDate = new Date(utcDateString); const targetDate = new Date(utcDateString);
const now = new Date(); const now = new Date();
@@ -57,7 +56,7 @@ export function removeTrailingZeros(value) {
const remainingMinutes = minutes % 60; const remainingMinutes = minutes % 60;
const remainingSeconds = seconds % 60; const remainingSeconds = seconds % 60;
return `${remainingDays === 0 ? "": remainingDays+"d"} ${remainingHours === 0 ? "": remainingHours+"h"} ${remainingMinutes}m ${remainingSeconds}s `; return `${remainingDays === 0 ? "" : remainingDays + "d"} ${remainingHours === 0 ? "" : remainingHours + "h"} ${remainingMinutes}m ${remainingSeconds}s `;
} }
@@ -95,30 +94,33 @@ export function debounce(func, delay) {
async function resolveMx(domain, recordType) { async function resolveMx(domain) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
dns.resolveMx(domain, (err, mxRecords) => { dns.resolveMx(domain, (err, mxRecords) => {
if (err) { if (err) {
reject(err); reject(err);
return; return;
} }
const addresses = mxRecords.map((mxRecord) => mxRecord.exchange); const addresses = mxRecords.map((mxRecord) => mxRecord.exchange);
resolve(addresses); resolve(addresses);
}); });
}); });
} }
// Async function to check email address validity // Async function to check email address validity
export async function checkEmailValidity(email) { export async function checkEmailValidity(email) {
try { try {
const domain = email?.split("@")[1]; const domain = email?.split('@')[1];
const addresses = await resolveMx(domain, "MX"); const addresses = await resolveMx(domain, 'MX');
console.log(addresses);
if (addresses && addresses?.length > 0) { if (addresses && addresses?.length > 0) {
return true; return true;
} }
return false; // No MX record exists return false; // No MX record exists
} catch (err) { } catch (err) {
return false; // Error occurred console.log(err);
return false; // Error occurred
} }
} }
@@ -126,15 +128,15 @@ export async function checkEmailValidity(email) {
// Function to convert timestamp to readable date format in Gulf timezone // Function to convert timestamp to readable date format in Gulf timezone
export function formatTimestampInGulfTimezone(timestamp) { export function formatTimestampInGulfTimezone(timestamp) {
const date = new Date(timestamp); const date = new Date(timestamp);
const options = { const options = {
year: 'numeric', year: 'numeric',
month: 'long', month: 'long',
day: 'numeric', day: 'numeric',
hour: '2-digit', hour: '2-digit',
minute: '2-digit', minute: '2-digit',
second: '2-digit', second: '2-digit',
timeZone: 'Asia/Dubai', // Gulf Standard Time (GST) timezone timeZone: 'Asia/Dubai', // Gulf Standard Time (GST) timezone
timeZoneName: 'short' timeZoneName: 'short'
}; };
return date.toLocaleDateString('en-GB', options); return date.toLocaleDateString('en-GB', options);
} }
@@ -164,7 +166,7 @@ const getNestedValue = (obj, key) => {
export const exportToExcel = (data, headers) => { export const exportToExcel = (data, headers) => {
const flattenedData = data.map((item) => { const flattenedData = data.map((item) => {
const newItem = {}; const newItem = {};
// Loop through customHeaders and get the correct values // Loop through customHeaders and get the correct values
headers.forEach((header) => { headers.forEach((header) => {
newItem[header.label] = getNestedValue(item, header.key); // Use the helper function newItem[header.label] = getNestedValue(item, header.key); // Use the helper function
@@ -175,7 +177,7 @@ export const exportToExcel = (data, headers) => {
// Now pass flattenedData to your Excel library to generate the file // Now pass flattenedData to your Excel library to generate the file
// Assuming you're using a library like `xlsx` for this part: // Assuming you're using a library like `xlsx` for this part:
const worksheet = XLSX.utils.json_to_sheet(flattenedData); const worksheet = XLSX.utils.json_to_sheet(flattenedData);
const workbook = XLSX.utils.book_new(); const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1"); XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
@@ -233,4 +235,11 @@ export const decryptString = (ciphertext) => {
const bytes = CryptoJS.AES.decrypt(ciphertext, import.meta.env.VITE_ROLE_ENCRYPTION_KEY); const bytes = CryptoJS.AES.decrypt(ciphertext, import.meta.env.VITE_ROLE_ENCRYPTION_KEY);
const originalText = bytes.toString(CryptoJS.enc.Utf8); const originalText = bytes.toString(CryptoJS.enc.Utf8);
return originalText; return originalText;
}; };
export const SUPER_ADMIN_ID = Number(import.meta.env.VITE_SUPER_ADMIN_ID) || 1
export const MAKER_ID = import.meta.env.VITE_MAKER_ID || 1
export const CHECKER_ID = import.meta.env.VITE_CHECKER_ID || 2
export const isMaker = (role = decryptString(localStorage?.getItem("role"))) => role === import.meta.env.VITE_MAKER;
export const isChecker = (role = decryptString(localStorage?.getItem("role"))) => role === import.meta.env.VITE_CHECKER;

View File

@@ -1,2 +1,3 @@
export const TABLE_PAGINATION = { page: 1, size:20 } export const TABLE_PAGINATION = { page: 1, size: 20 }
export const IMAGE_URI = import.meta.env.VITE_API_IMAGE_URL export const IMAGE_URI = import.meta.env.VITE_API_IMAGE_URL
export const INVESTOR_TABLE_PAGINATION = { page: 1, size: 500 }

View File

@@ -1,26 +1,48 @@
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from "react";
import logo from "../assets/logo2.png";
import logoDark from "../assets/logo.png";
import logoMini from "../assets/logo-min.png";
import logoMiniDark from "../assets/favicon.png";
import { useDispatch } from "react-redux";
import { loginUser } from "../Redux/Slice/auth";
import Button02 from "../Components/Buttons/Button02";
import { CgProfile } from "react-icons/cg"; import { CgProfile } from "react-icons/cg";
import { useDispatch } from "react-redux";
import logoMiniDark from "../assets/favicon.png";
import logoMini from "../assets/logo-min.png";
import logoDark from "../assets/logo.png";
import logo from "../assets/logo2.png";
import {
TbArrowBadgeLeftFilled,
TbListDetails,
TbReportMoney,
TbTransactionDollar,
} from "react-icons/tb";
import { TbArrowBadgeRightFilled } from "react-icons/tb";
import { import {
ArrowBackIcon, ArrowBackIcon,
ArrowLeftIcon, ArrowLeftIcon,
ArrowRightIcon, ArrowRightIcon,
AtSignIcon, AtSignIcon,
} from "@chakra-ui/icons"; } from "@chakra-ui/icons";
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Alert,
AlertIcon,
Box,
Button,
Image,
Text,
Tooltip
} from "@chakra-ui/react";
import Cookies from "js-cookie"; // Import the Cookies library
import { GrManual } from "react-icons/gr";
import { HiOutlineChartSquareBar } from "react-icons/hi";
import { LuContact } from "react-icons/lu";
import { MdNotificationsNone, MdOutlineAddChart } from "react-icons/md";
import {
RiBankLine,
RiExchangeBoxLine,
RiFileUserLine,
RiMoneyDollarBoxLine,
} from "react-icons/ri";
import {
TbListDetails,
TbReportMoney,
TbTransactionDollar
} from "react-icons/tb";
import { VscSymbolClass } from "react-icons/vsc";
import { import {
Link, Link,
NavLink, NavLink,
@@ -29,71 +51,21 @@ import {
useLocation, useLocation,
useNavigate, useNavigate,
} from "react-router-dom"; } from "react-router-dom";
import { RouteLink } from "../Routes/Routes";
import NotFound from "../Pages/NotFound";
import { nav } from "../Routes/Nav";
import {
Avatar,
Box,
Button,
PopoverArrow,
PopoverBody,
PopoverCloseButton,
PopoverContent,
PopoverFooter,
PopoverHeader,
PopoverTrigger,
Portal,
Text,
WrapItem,
Popover,
Tag,
Accordion,
AccordionItem,
AccordionButton,
AccordionIcon,
AccordionPanel,
Image,
Alert,
AlertIcon,
Breadcrumb,
Divider,
Tooltip,
useRadio,
} from "@chakra-ui/react";
import GlobalStateContext from "../Contexts/GlobalStateContext";
import Cookies from "js-cookie"; // Import the Cookies library
import Header from "../Components/Header";
import HeaderMain from "../Components/HeaderMain"; import HeaderMain from "../Components/HeaderMain";
import { IoMdSwap } from "react-icons/io"; import GlobalStateContext from "../Contexts/GlobalStateContext";
import {
RiBankLine,
RiExchangeBoxLine,
RiFileUserLine,
RiMoneyDollarBoxLine,
} from "react-icons/ri";
import { VscSymbolClass } from "react-icons/vsc";
import { MdNotificationsNone, MdOutlineAddChart } from "react-icons/md";
import { HiOutlineChartSquareBar } from "react-icons/hi";
import { GrManual } from "react-icons/gr";
import { LuContact } from "react-icons/lu";
import shield from "../assets/shield.png";
import SplashScreen from "../Pages/SplashScreen";
import CutomBreadcrumb from "../Components/CutomBreadcrumb";
import CustomBreadcrumb from "../Components/CutomBreadcrumb";
import { getCountdownTimer } from "../Constants/Constants";
import { useLogoutMutation } from "../Services/token.serivce";
import CreateRequest from "../Pages/Fawateer/CreateRequest"; import CreateRequest from "../Pages/Fawateer/CreateRequest";
import ApproveRequest from "../Pages/FawateerChecker/ApproveRequest/ApproveRequest";
import ApproveHistoryMaker from "../Pages/FawateerChecker/ApproveHistory/ApproveHistoryMaker";
import ApproveHistory from "../Pages/FawateerChecker/ApproveHistory/ApproveHistoryChecker"; import ApproveHistory from "../Pages/FawateerChecker/ApproveHistory/ApproveHistoryChecker";
import ApproveHistoryMaker from "../Pages/FawateerChecker/ApproveHistory/ApproveHistoryMaker";
import ApproveRequest from "../Pages/FawateerChecker/ApproveRequest/ApproveRequest";
import NotFound from "../Pages/NotFound";
import SplashScreen from "../Pages/SplashScreen";
import { nav } from "../Routes/Nav";
import { RouteLink } from "../Routes/Routes";
import { useProfileQuery } from "../Services/io.service"; import { useProfileQuery } from "../Services/io.service";
import SubAdmin from "../Pages/SubAdmin/SubAdmin"; import { useLogoutMutation } from "../Services/token.serivce";
const DashboardLayout = ({ isOnline }) => { const DashboardLayout = ({ isOnline }) => {
const userRole = localStorage.getItem("role");
const navigate = useNavigate(); const navigate = useNavigate();
const dispach = useDispatch();
const location = useLocation(); const location = useLocation();
const path = location.pathname; const path = location.pathname;
const [isDrawerOpen, setIsDrawerOpen] = useState(false); const [isDrawerOpen, setIsDrawerOpen] = useState(false);
@@ -110,15 +82,15 @@ const DashboardLayout = ({ isOnline }) => {
const { data, refetch } = useProfileQuery(); const { data, refetch } = useProfileQuery();
useEffect(() => { // useEffect(() => {
if ( // if (
!localStorage.getItem("accessToken") && // !localStorage.getItem("accessToken") &&
!localStorage.getItem("refreshToken") // !localStorage.getItem("refreshToken")
) { // ) {
logOutHandler(); // logOutHandler();
return navigate("/login"); // return navigate("/login");
} // }
}, []); // }, []);
useEffect(() => { useEffect(() => {
const savedIndex = localStorage.getItem("openAccordionIndex"); const savedIndex = localStorage.getItem("openAccordionIndex");
@@ -157,7 +129,9 @@ const DashboardLayout = ({ isOnline }) => {
await logout(); await logout();
localStorage.clear(); localStorage.clear();
navigate("/login"); navigate("/login");
} catch (error) {} } catch (error) {
console.log(error);
}
}; };
// // Function to get the title based on the route // // Function to get the title based on the route
@@ -375,6 +349,13 @@ const DashboardLayout = ({ isOnline }) => {
Deletion request Deletion request
</span> </span>
); );
case path.startsWith("/subadmin"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Manage SubAdmin
</span>
);
default: default:
if (path.startsWith("/community/view/")) { if (path.startsWith("/community/view/")) {

View File

@@ -1,27 +1,25 @@
import { import {
Avatar,
Badge, Badge,
Box, Box,
HStack, HStack,
Input, Input,
Select, Select,
Switch,
Text, Text,
useDisclosure, useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useState, useRef } from "react"; import React, { useContext, useEffect, useRef, useState } from "react";
import { Link, Link as RouterLink, useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { debounce } from "../../../Master/Sponser/AddSponser";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import Pagination from "../../../../Components/Pagination"; import NormalTable from "../../../../Components/DataTable/NormalTable";
import ToastBox from "../../../../Components/ToastBox"; import ToastBox from "../../../../Components/ToastBox";
import ReasonBanModal from "./ReasonBanModal";
import { useGetbanInvestorQuery } from "../../../../Services/ban.investor.service";
import { TABLE_PAGINATION } from "../../../../Constants/Paginations"; import { TABLE_PAGINATION } from "../../../../Constants/Paginations";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import { useGetbanInvestorQuery } from "../../../../Services/ban.investor.service";
import { debounce } from "../../../Master/Sponser/AddSponser";
import ReasonBanModal from "./ReasonBanModal";
import Pagination from "../../../../Components/Pagination";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
@@ -233,8 +231,6 @@ const BankInvestor = () => {
), ),
})); }));
console.log(extractedArray);
const handleDelete = () => { const handleDelete = () => {
const updatedInvestorDetails = InvestorDetails.filter( const updatedInvestorDetails = InvestorDetails.filter(
(sponsor) => sponsor.id !== actionId (sponsor) => sponsor.id !== actionId
@@ -278,6 +274,14 @@ const BankInvestor = () => {
/> />
<HStack display={"flex"} alignItems={"center"}> <HStack display={"flex"} alignItems={"center"}>
<Pagination
isLoading={unbanLoading}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalItems={data?.data?.totalItems}
/>
{/* <Select {/* <Select
focusBorderColor="green.500" focusBorderColor="green.500"
size={"sm"} size={"sm"}

View File

@@ -1,31 +1,26 @@
import { import {
Avatar,
Badge, Badge,
Box, Box,
HStack, HStack,
Input, Input,
Select, Select,
Switch,
Text, Text,
useDisclosure, useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useState, useRef } from "react"; import React, { useContext, useEffect, useRef, useState } from "react";
import { Link, Link as RouterLink, useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { debounce } from "../../../Master/Sponser/AddSponser";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import DataTable from "../../../../Components/DataTable/NormalTable";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import Pagination from "../../../../Components/Pagination"; import DataTable from "../../../../Components/DataTable/NormalTable";
import ToastBox from "../../../../Components/ToastBox"; import ToastBox from "../../../../Components/ToastBox";
import ReasonBanModal from "./ReasonBanModal";
import {
useGetInvestorQuery,
useGetUnbanInvestorQuery,
} from "../../../../Services/ban.investor.service";
import { generateSerialNumber } from "../../../../Constants/Constants"; import { generateSerialNumber } from "../../../../Constants/Constants";
import { TABLE_PAGINATION } from "../../../../Constants/Paginations"; import { TABLE_PAGINATION } from "../../../../Constants/Paginations";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import { useGetUnbanInvestorQuery } from "../../../../Services/ban.investor.service";
import { debounce } from "../../../Master/Sponser/AddSponser";
import ReasonBanModal from "./ReasonBanModal";
import Pagination from "../../../../Components/Pagination";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
@@ -270,6 +265,14 @@ const UnbanInvestor = () => {
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
/> />
<HStack display={"flex"} alignItems={"center"}> <HStack display={"flex"} alignItems={"center"}>
<Pagination
isLoading={unbanLoading}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalItems={data?.data?.totalItems}
/>
{/* <Select {/* <Select
focusBorderColor="green.500" focusBorderColor="green.500"
size={"sm"} size={"sm"}

View File

@@ -16,14 +16,13 @@ import {
Stack, Stack,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import * as yup from "yup";
import React, { useState, useContext } from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import * as yup from "yup";
import CustomAlertDialog from "../Components/CustomAlertDialog"; import CustomAlertDialog from "../Components/CustomAlertDialog";
import ToastBox from "../Components/ToastBox"; import ToastBox from "../Components/ToastBox";
import { useUpdatePasswordMutation } from "../Services/change.password.service"; import { useUpdatePasswordMutation } from "../Services/change.password.service";
import { all } from "axios";
// Validation schema // Validation schema
const passwordSchema = yup.object().shape({ const passwordSchema = yup.object().shape({
@@ -42,8 +41,8 @@ const passwordSchema = yup.object().shape({
), ),
confirmNewPassword: yup confirmNewPassword: yup
.string() .string()
.required("Confirm Password is required") .required("Confirm New Password is required")
.oneOf([yup.ref("newPassword")], "Passwords must match"), .oneOf([yup.ref("newPassword")], "Password do not match"),
}); });
const ChangePassword = ({ const ChangePassword = ({
@@ -53,12 +52,18 @@ const ChangePassword = ({
actionId, actionId,
setActionId, setActionId,
}) => { }) => {
const initialValue = {
oldPassword: "",
newPassword: "",
confirmNewPassword: "",
};
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [alert, setAlert] = useState(false); const [alert, setAlert] = useState(false);
const [showCurrentPassword, setShowCurrentPassword] = useState(false); const [showCurrentPassword, setShowCurrentPassword] = useState(false);
const [showNewPassword, setShowNewPassword] = useState(false); const [showNewPassword, setShowNewPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const toast = useToast(); const toast = useToast();
const [input, setInput] = useState(initialValue);
const [updatePassword] = useUpdatePasswordMutation(); const [updatePassword] = useUpdatePasswordMutation();
@@ -74,10 +79,10 @@ const ChangePassword = ({
}); });
// Form submit handler // Form submit handler
const onSubmit = async (data) => { const onSubmit = async () => {
setIsLoading(true); setIsLoading(true);
try { try {
const res = await updatePassword(data); // Assuming API request works as expected const res = await updatePassword(input); // Assuming API request works as expected
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
toast({ toast({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
@@ -89,6 +94,7 @@ const ChangePassword = ({
<ToastBox message={res?.error?.data?.message} status={"error"} /> <ToastBox message={res?.error?.data?.message} status={"error"} />
), ),
}); });
setAlert(false);
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@@ -97,6 +103,11 @@ const ChangePassword = ({
} }
}; };
const handleSubmitFrom = (data) => {
setAlert(true);
setInput(data);
};
// Handle modal close // Handle modal close
const handleClose = () => { const handleClose = () => {
setAlert(false); setAlert(false);
@@ -106,7 +117,7 @@ const ChangePassword = ({
return ( return (
<> <>
<Modal isOpen={isOpen} onClose={onClose} initialFocusRef={firstField}> <Modal isOpen={isOpen} onClose={handleClose} initialFocusRef={firstField}>
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<ModalHeader fontSize="md">Change Password</ModalHeader> <ModalHeader fontSize="md">Change Password</ModalHeader>
@@ -114,7 +125,7 @@ const ChangePassword = ({
<ModalBody pb={6}> <ModalBody pb={6}>
<Stack spacing={4}> <Stack spacing={4}>
{/* Current Password */} {/* Current Password */}
<FormControl isInvalid={errors.oldPassword}> <FormControl isInvalid={errors.oldPassword} isRequired>
<FormLabel fontSize="sm" mb={1} fontWeight={500}> <FormLabel fontSize="sm" mb={1} fontWeight={500}>
Current Password Current Password
</FormLabel> </FormLabel>
@@ -141,7 +152,7 @@ const ChangePassword = ({
</FormControl> </FormControl>
{/* New Password */} {/* New Password */}
<FormControl isInvalid={errors.newPassword}> <FormControl isInvalid={errors.newPassword} isRequired>
<FormLabel fontSize="sm" mb={1}> <FormLabel fontSize="sm" mb={1}>
New Password New Password
</FormLabel> </FormLabel>
@@ -168,7 +179,7 @@ const ChangePassword = ({
</FormControl> </FormControl>
{/* Confirm Password */} {/* Confirm Password */}
<FormControl isInvalid={errors.confirmNewPassword}> <FormControl isInvalid={errors.confirmNewPassword} isRequired>
<FormLabel fontSize="sm" mb={1}> <FormLabel fontSize="sm" mb={1}>
Confirm New Password Confirm New Password
</FormLabel> </FormLabel>
@@ -210,7 +221,8 @@ const ChangePassword = ({
rounded={"sm"} rounded={"sm"}
colorScheme="forestGreen" colorScheme="forestGreen"
size="sm" size="sm"
onClick={() => setAlert(true)} // onClick={() => setAlert(true)}
onClick={handleSubmit(handleSubmitFrom)}
isLoading={isLoading} isLoading={isLoading}
> >
Save Save
@@ -222,7 +234,7 @@ const ChangePassword = ({
<CustomAlertDialog <CustomAlertDialog
isOpen={alert} isOpen={alert}
onClose={() => setAlert(false)} onClose={() => setAlert(false)}
alertHandler={handleSubmit(onSubmit)} alertHandler={onSubmit}
message={"Are you sure you want to change the password?"} message={"Are you sure you want to change the password?"}
isLoading={isLoading} isLoading={isLoading}
/> />

View File

@@ -15,7 +15,7 @@ import {
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import * as yup from "yup"; import * as yup from "yup";
import React, { useState} from "react"; import React, { useState } from "react";
import { useForm, Controller } from "react-hook-form"; import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import { useForgetPasswordMutation } from "../Services/forget.password.service"; import { useForgetPasswordMutation } from "../Services/forget.password.service";
@@ -25,7 +25,9 @@ const validationSchema = yup.object().shape({
emailAddress: yup emailAddress: yup
.string() .string()
.email("Invalid email format") .email("Invalid email format")
.required("Email, Phone, or Username is required"), .required("Email address is required")
.min(6, "Email address must be at least 6 characters long")
.max(255, "Email address can be at most 255 characters long"),
}); });
const ForgetPassword = ({ isOpen, onClose, firstField }) => { const ForgetPassword = ({ isOpen, onClose, firstField }) => {
@@ -38,12 +40,12 @@ const ForgetPassword = ({ isOpen, onClose, firstField }) => {
control, control,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
reset, // Add reset from useForm
} = useForm({ } = useForm({
resolver: yupResolver(validationSchema), resolver: yupResolver(validationSchema),
}); });
const onSubmit = async (formData) => { const onSubmit = async (formData) => {
setIsLoading(true); setIsLoading(true);
try { try {
const res = await forgetPassword(formData); const res = await forgetPassword(formData);
@@ -52,13 +54,14 @@ const ForgetPassword = ({ isOpen, onClose, firstField }) => {
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
handleClose(); handleClose();
} else if (res?.error?.status === 401) { } else if (res?.error?.status === 400) {
toast({ toast({
render: () => ( render: () => (
<ToastBox message={res?.error?.data?.message} status="error" /> <ToastBox message={res?.error?.data?.message} status="error" />
), ),
}); });
handleClose(); handleClose();
} }
} catch (error) { } catch (error) {
console.error(error); console.error(error);
@@ -70,6 +73,7 @@ const ForgetPassword = ({ isOpen, onClose, firstField }) => {
const handleClose = () => { const handleClose = () => {
setIsLoading(false); setIsLoading(false);
onClose(); onClose();
reset(); // Reset form state when modal closes
}; };
return ( return (
@@ -82,13 +86,13 @@ const ForgetPassword = ({ isOpen, onClose, firstField }) => {
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<ModalHeader fontSize="md">Forget Password</ModalHeader> <ModalHeader fontSize="md">Forgot Password</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody pb={4}> <ModalBody pb={4}>
<Stack spacing={4}> <Stack spacing={4}>
<FormControl isInvalid={errors.emailAddress}> <FormControl isInvalid={errors.emailAddress} isRequired>
<FormLabel fontSize="sm" mb={3} fontWeight={500}> <FormLabel fontSize="sm" mb={3} fontWeight={500}>
Email, Phone, or Username Please Enter Email Address
</FormLabel> </FormLabel>
<Controller <Controller
name="emailAddress" name="emailAddress"
@@ -98,7 +102,7 @@ const ForgetPassword = ({ isOpen, onClose, firstField }) => {
{...field} {...field}
size="md" size="md"
fontSize="sm" fontSize="sm"
focusBorderColor="forestGreen.300" focusBorderColor="forestGreen.300"
rounded={4} rounded={4}
type="text" type="text"
/> />
@@ -114,7 +118,7 @@ const ForgetPassword = ({ isOpen, onClose, firstField }) => {
<DrawerFooter mb={5}> <DrawerFooter mb={5}>
<Button <Button
w="100%" w="100%"
colorScheme="forestGreen" colorScheme="forestGreen"
rounded="md" rounded="md"
size="md" size="md"
type="submit" type="submit"
@@ -122,7 +126,7 @@ const ForgetPassword = ({ isOpen, onClose, firstField }) => {
fontWeight={400} fontWeight={400}
fontSize="sm" fontSize="sm"
> >
Send Login Link Reset Password
</Button> </Button>
</DrawerFooter> </DrawerFooter>
</form> </form>

View File

@@ -217,7 +217,7 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, da
isOpen={alert} isOpen={alert}
onClose={() => setAlert(false)} onClose={() => setAlert(false)}
alertHandler={handleSave} alertHandler={handleSave}
message={"Are you sure you want to update this artifact?"} message={"Are you sure you want to add this artifact?"}
isLoading={isLoading} isLoading={isLoading}
/> />
</> </>

View File

@@ -20,7 +20,7 @@ import AddCaseDetails from "./AddCaseDetails";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service"; import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox"; import ToastBox from "../../../../Components/ToastBox";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { encryptString } from "../../../../Constants/Constants"; import { encryptString, isMaker } from "../../../../Constants/Constants";
const IOCashDetails = () => { const IOCashDetails = () => {
const params = useParams(); const params = useParams();
@@ -88,7 +88,8 @@ const IOCashDetails = () => {
Pending Pending
{IODetails?.ioCashStatusHistory?.Pending.length > 0 && ( {IODetails?.ioCashStatusHistory?.Pending.length > 0 && (
<Badge rounded={"sm"} colorScheme="forestGreen" ms={2}> <Badge rounded={"sm"} colorScheme="forestGreen" ms={2}>
{IODetails?.ioCashStatusHistory?.Pending.length !== 0 && IODetails?.ioCashStatusHistory?.Pending.length} {IODetails?.ioCashStatusHistory?.Pending.length !== 0 &&
IODetails?.ioCashStatusHistory?.Pending.length}
</Badge> </Badge>
)} )}
{/* <Badge rounded={"sm"} colorScheme="forestGreen" ms={2}> {/* <Badge rounded={"sm"} colorScheme="forestGreen" ms={2}>
@@ -106,7 +107,8 @@ const IOCashDetails = () => {
</Tab> </Tab>
</TabList> </TabList>
{IODetails?.isInvestedAmount {IODetails?.isInvestedAmount
? localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) && ( ? isMaker() &&
IODetails?.ioSatatus !== "Exited" && (
<Button <Button
onClick={handleAdd} onClick={handleAdd}
leftIcon={<AddIcon />} leftIcon={<AddIcon />}

View File

@@ -38,7 +38,7 @@ import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import RequestApproveModal from "./RequestApproveModal"; import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal"; import RequestRejectModal from "./RequestRejectModal";
import AddCaseDetails from "./AddCaseDetails"; import AddCaseDetails from "./AddCaseDetails";
import { encryptString } from "../../../../Constants/Constants"; import { encryptString, isMaker } from "../../../../Constants/Constants";
const formatDate = (date) => new Date(date).toLocaleDateString(); const formatDate = (date) => new Date(date).toLocaleDateString();
@@ -105,8 +105,7 @@ const Pending = () => {
"Comments", "Comments",
"Update By", "Update By",
"Update On", "Update On",
...(localStorage?.getItem('role')!==encryptString(import.meta.env.VITE_VITE_MAKER) ? ["Actions"] : []), ...(!isMaker() ? ["Actions"] : []),
]; ];
const extractedArray = filteredData?.map((item, index) => ({ const extractedArray = filteredData?.map((item, index) => ({
@@ -132,9 +131,9 @@ const Pending = () => {
$ $
</Badge> </Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, { {parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})} })}
</Text> </Text>
), ),
Comments: ( Comments: (
@@ -167,64 +166,69 @@ const Pending = () => {
), ),
Actions: ( Actions: (
<Box display={"flex"} justifyContent={"center"}> <Box display={"flex"} justifyContent={"center"}>
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) ? <Box> {!isMaker() ? (
{index===0&&<Box display={"flex"} justifyContent={"center"} gap={2}> <Box>
<Tooltip {index === 0 && (
rounded={"sm"} <Box display={"flex"} justifyContent={"center"} gap={2}>
fontSize={"xs"} <Tooltip
label="Approve" rounded={"sm"}
bg="#fff" fontSize={"xs"}
color={"green.500"} label="Approve"
placement="left-start" bg="#fff"
> color={"green.500"}
placement="left-start"
>
<Button
// colorScheme="forestGreen"
// color="green.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
py={1}
onClick={() => {
setActionId(item.id);
onConfirmOpen();
}}
colorScheme="green"
variant={"solid"}
cursor={"pointer"}
>
<CheckIcon fontSize={"12px"} />
</Button>
</Tooltip>
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="Reject"
bg="#fff"
color={"red.500"}
placement="left-start"
>
<Button
colorScheme="red"
// color="red.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
onClick={() => {
setActionId(item.id);
onRejectOpen();
}}
py={1}
// variant={"solid"}
>
<CloseIcon fontSize={"10px"} />
</Button>
</Tooltip>
</Box>
)}
</Box>
) : (
<Button <Button
// colorScheme="forestGreen"
// color="green.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
py={1}
onClick={() => {
setActionId(item.id);
onConfirmOpen();
}}
colorScheme="green"
variant={"solid"}
cursor={"pointer"}
>
<CheckIcon fontSize={"12px"} />
</Button>
</Tooltip>
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="Reject"
bg="#fff"
color={"red.500"}
placement="left-start"
>
<Button
colorScheme="red"
// color="red.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
onClick={() => {
setActionId(item.id);
onRejectOpen();
}}
py={1}
// variant={"solid"}
>
<CloseIcon fontSize={"10px"} />
</Button>
</Tooltip></Box>}
</Box> : <Button
colorScheme="green" colorScheme="green"
rounded={"sm"} rounded={"sm"}
size={"xs"} size={"xs"}
@@ -236,7 +240,8 @@ const Pending = () => {
}} }}
> >
<ViewIcon me={"4px"} /> View <ViewIcon me={"4px"} /> View
</Button>} </Button>
)}
</Box> </Box>
), ),
})); }));
@@ -314,9 +319,9 @@ const Pending = () => {
$ $
</Badge> </Badge>
{parseFloat(IODetails?.ioCash || 0).toLocaleString(undefined, { {parseFloat(IODetails?.ioCash || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})} })}
</Th> </Th>
<Th <Th
textAlign={"center"} textAlign={"center"}

View File

@@ -12,11 +12,12 @@ import {
useUpdateIOMutation, useUpdateIOMutation,
} from "../../../Services/io.service"; } from "../../../Services/io.service";
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
import { import { useToast } from "@chakra-ui/react";
useToast,
} from "@chakra-ui/react";
import { formatDatee } from "../../../Components/FormField"; import { formatDatee } from "../../../Components/FormField";
import { formatDateToYYYYMMDD, removeTrailingZeros } from "../../../Constants/Constants"; import {
formatDateToYYYYMMDD,
removeTrailingZeros,
} from "../../../Constants/Constants";
const schema = yup.object().shape({ const schema = yup.object().shape({
investmentNameEnglish: yup investmentNameEnglish: yup
@@ -25,7 +26,7 @@ const schema = yup.object().shape({
.min(3, "IO name in English must be at least 3 characters long") .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"), .max(150, "IO name in English must be at most 150 characters long"),
investmentNameArabic: yup investmentNameArabic: yup
.string() .string()
.required("IO name in Arabic is required") .required("IO name in Arabic is required")
.min(3, "IO name in Arabic must be at least 3 characters long") .min(3, "IO name in Arabic must be at least 3 characters long")
@@ -42,15 +43,15 @@ const schema = yup.object().shape({
.required("Description in Arabic is required") .required("Description in Arabic is required")
.min(10, "Description in Arabic must be at least 10 characters long") .min(10, "Description in Arabic must be at least 10 characters long")
.max(2000, "Description in Arabic must be at most 500 characters long"), .max(2000, "Description in Arabic must be at most 500 characters long"),
expectedReturnArabic: yup expectedReturnArabic: yup
.string() .string()
.required("Expected return in Arabic is required"), .required("Expected return in Arabic is required"),
goalAmount: yup goalAmount: yup
.number() .number()
.typeError("Goal Amount is must be number") .typeError("Goal Amount is must be number")
.required('Goal amount is required') .required("Goal amount is required")
.positive('Goal amount must be a positive number'), .positive("Goal amount must be a positive number"),
closingDate: yup closingDate: yup
.date() .date()
.notRequired("Closing date is required") .notRequired("Closing date is required")
@@ -69,28 +70,25 @@ const schema = yup.object().shape({
InvestmentDetails: yup.string().notRequired(), InvestmentDetails: yup.string().notRequired(),
comment: yup.string().notRequired() comment: yup
// .min(10, "Comment must be at least 10 characters long")
.max(100, "Comment must be at most 100 characters long"),
expectedReturn: yup
.string() .string()
.required("Expected return is required"), .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 IODetails = ({ enableNextTab, index, data }) => { const IODetails = ({ enableNextTab, index, data }) => {
const params = useParams(); const params = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
const toast = useToast(); const toast = useToast();
const handleInputChangeCreate = (index, newValue) => { const handleInputChangeCreate = (index, newValue) => {
const updatedValues = [...values]; const updatedValues = [...values];
updatedValues[index].value = newValue; updatedValues[index].value = newValue;
setValues(updatedValues); setValues(updatedValues);
console.log(values); console.log(values);
}; };
const handleInputChangeEdit = (index, newValue) => { const handleInputChangeEdit = (index, newValue) => {
@@ -143,9 +141,12 @@ const IODetails = ({ enableNextTab, index, data }) => {
}); });
const miniValue = data?.country?.map( const miniValue = data?.country?.map(
({ countryName, flagIcon, minInvestmentAmt, countryCode, id, currency }, index) => { (
{ countryName, flagIcon, minInvestmentAmt, countryCode, id, currency },
index
) => {
return { return {
id:id, id: id,
country: countryName, country: countryName,
value: minInvestmentAmt, value: minInvestmentAmt,
logo: flagIcon, logo: flagIcon,
@@ -154,18 +155,19 @@ const IODetails = ({ enableNextTab, index, data }) => {
} }
); );
const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, currencyCode, country_xid,id })=>{ const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(
console.log(currencyCode); ({ minInvestmentAmt, country, currencyCode, country_xid, id }) => {
return{ console.log(currencyCode);
_id:id, return {
id:country_xid, _id: id,
country: country?.countryName, id: country_xid,
value: removeTrailingZeros(minInvestmentAmt), country: country?.countryName,
logo: country?.flagIcon, value: removeTrailingZeros(minInvestmentAmt),
curr: currencyCode, logo: country?.flagIcon,
curr: currencyCode,
};
} }
}) );
const schemaEdit = yup.object().shape({ const schemaEdit = yup.object().shape({
investmentNameEnglish: yup investmentNameEnglish: yup
@@ -173,74 +175,67 @@ const IODetails = ({ enableNextTab, index, data }) => {
.required("IO name in English is required") .required("IO name in English is required")
.min(3, "IO name in English must be at least 3 characters long") .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"), .max(150, "IO name in English must be at most 150 characters long"),
investmentNameArabic: yup investmentNameArabic: yup
.string() .string()
.required("IO name in Arabic is required") .required("IO name in Arabic is required")
.min(3, "IO name in Arabic must be at least 3 characters long") .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"), .max(50, "IO name in Arabic must be at most 50 characters long"),
descriptionEnglish: yup descriptionEnglish: yup
.string() .string()
.required("Description in English is required") .required("Description in English is required")
.min(10, "Description in English must be at least 10 characters long") .min(10, "Description in English must be at least 10 characters long")
.max(1000, "Description in English must be at most 1000 characters long"), .max(1000, "Description in English must be at most 1000 characters long"),
descriptionArabic: yup descriptionArabic: yup
.string() .string()
.required("Description in Arabic is required") .required("Description in Arabic is required")
.min(10, "Description in Arabic must be at least 10 characters long") .min(10, "Description in Arabic must be at least 10 characters long")
.max(2000, "Description in Arabic must be at most 500 characters long"), .max(2000, "Description in Arabic must be at most 500 characters long"),
expectedReturnArabic: yup expectedReturnArabic: yup
.string() .string()
.required("Expected return in Arabic is required"), .required("Expected return in Arabic is required"),
goalAmount: yup goalAmount: yup
.number() .number()
.typeError("Goal Amount is must be number") .typeError("Goal Amount is must be number")
.required('Goal amount is required') .required("Goal amount is required")
.positive('Goal amount must be a positive number') .positive("Goal amount must be a positive number")
.min(IObyID?.data?.totalAmtInvestmentInUSD, `Goal amount should not be lesser then amount raised ${IObyID?.data?.totalAmtInvestmentInUSD}`), .min(
closingDate: yup IObyID?.data?.totalAmtInvestmentInUSD,
.date() `Goal amount should not be lesser then amount raised ${IObyID?.data?.totalAmtInvestmentInUSD}`
.notRequired("Closing date is required") ),
.min(new Date(), "Closing date cannot be in the past"), closingDate: yup.date().notRequired("Closing date is required"),
holdingPeriod: yup.string().required("Holding period is required"), holdingPeriod: yup.string().required("Holding period is required"),
holdingPeriodArabic: yup.string().required("Holding period is required"), holdingPeriodArabic: yup.string().required("Holding period is required"),
isShariah: yup.string().required("CheckBox is required"), isShariah: yup.string().required("CheckBox is required"),
// minInvestmentAmount: yup // minInvestmentAmount: yup
// .number() // .number()
// .required("Minimum investment is required") // .required("Minimum investment is required")
// .positive("Minimum investment must be a positive number") // .positive("Minimum investment must be a positive number")
// .min(1, "Minimum investment must be at least 1"), // .min(1, "Minimum investment must be at least 1"),
ISIN: yup.string().notRequired(), ISIN: yup.string().notRequired(),
InvestmentDetails: yup.string().notRequired(), InvestmentDetails: yup.string().notRequired(),
comment: yup.string().notRequired() comment: yup
.min(10, "Comment must be at least 10 characters long")
.max(100, "Comment must be at most 100 characters long"),
expectedReturn: yup
.string() .string()
.required("Expected return is required"), .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);
const [values, setValues] = useState(id?minInvestmentById:miniValue);
console.log(values);
const formatNumber = (num) => { const formatNumber = (num) => {
// Remove non-numeric characters and format with commas // Remove non-numeric characters and format with commas
return num.replace(/\D/g, '') return num.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}; };
// console.log(values); // console.log(values);
@@ -254,10 +249,11 @@ const IODetails = ({ enableNextTab, index, data }) => {
formState: { errors }, formState: { errors },
} = useForm({ } = useForm({
resolver: yupResolver(id ? schemaEdit : schema), resolver: yupResolver(id ? schemaEdit : schema),
mode: "all",
}); });
useEffect(() => { useEffect(() => {
setIOloading(IObyIDisLoading) setIOloading(IObyIDisLoading);
setIODetails({ setIODetails({
...IObyID?.data, ...IObyID?.data,
}); });
@@ -278,10 +274,9 @@ const IODetails = ({ enableNextTab, index, data }) => {
minInvestmentAmount: IObyID?.data?.minInvestmentAmount, minInvestmentAmount: IObyID?.data?.minInvestmentAmount,
holdingPeriodArabic: IObyID?.data?.minInvestmentAmount, holdingPeriodArabic: IObyID?.data?.minInvestmentAmount,
expectedReturnArabic: IObyID?.data?.minInvestmentAmount, expectedReturnArabic: IObyID?.data?.minInvestmentAmount,
isShariah: IObyID?.data?.isShariah isShariah: IObyID?.data?.isShariah,
}); });
} }
}, [id, IObyID]); }, [id, IObyID]);
//=======================[ Creator ] //=======================[ Creator ]
@@ -294,8 +289,10 @@ const IODetails = ({ enableNextTab, index, data }) => {
isRequired: true, isRequired: true,
section: " ", section: " ",
width: "49%", width: "49%",
maxLength:150, maxLength: 150,
helperText:`Maximum length should be 150 characters. You have entered ${watch()?.investmentNameEnglish?.length || 0} characters.` helperText: `Maximum length should be 150 characters. You have entered ${
watch()?.investmentNameEnglish?.length || 0
} characters.`,
}, },
{ {
label: "IO Name (Arabic)", label: "IO Name (Arabic)",
@@ -306,8 +303,10 @@ const IODetails = ({ enableNextTab, index, data }) => {
arabic: true, arabic: true,
section: " ", section: " ",
width: "49%", width: "49%",
maxLength:150, maxLength: 150,
helperText:`Maximum length should be 150 characters. You have entered ${watch()?.investmentNameArabic?.length || 0} characters.` helperText: `Maximum length should be 150 characters. You have entered ${
watch()?.investmentNameArabic?.length || 0
} characters.`,
}, },
{ {
label: "Description", label: "Description",
@@ -317,8 +316,10 @@ const IODetails = ({ enableNextTab, index, data }) => {
isRequired: true, isRequired: true,
section: " ", section: " ",
width: "49%", width: "49%",
maxLength:1000, maxLength: 1000,
helperText:`Maximum length should be 1000 characters. You have entered ${watch()?.descriptionEnglish?.length || 0} characters.` helperText: `Maximum length should be 1000 characters. You have entered ${
watch()?.descriptionEnglish?.length || 0
} characters.`,
}, },
{ {
label: "Description (Arabic)", label: "Description (Arabic)",
@@ -329,9 +330,10 @@ const IODetails = ({ enableNextTab, index, data }) => {
arabic: true, arabic: true,
section: " ", section: " ",
width: "49%", width: "49%",
maxLength:1000, maxLength: 1000,
helperText:`Maximum length should be 1000 characters. You have entered ${watch()?.descriptionArabic?.length || 0} characters.` helperText: `Maximum length should be 1000 characters. You have entered ${
watch()?.descriptionArabic?.length || 0
} characters.`,
}, },
{ {
label: "Holding Period", label: "Holding Period",
@@ -342,8 +344,10 @@ const IODetails = ({ enableNextTab, index, data }) => {
section: " ", section: " ",
width: "49%", width: "49%",
value: IObyID?.data?.holdingPeriod, value: IObyID?.data?.holdingPeriod,
maxLength:20, maxLength: 20,
helperText:`Maximum length should be 20 characters. You have entered ${watch()?.holdingPeriod?.length || 0} characters.` helperText: `Maximum length should be 20 characters. You have entered ${
watch()?.holdingPeriod?.length || 0
} characters.`,
}, },
{ {
label: "Holding Period (Arabic)", label: "Holding Period (Arabic)",
@@ -355,11 +359,12 @@ const IODetails = ({ enableNextTab, index, data }) => {
section: " ", section: " ",
width: "49%", width: "49%",
value: IObyID?.data?.holdingPeriodArabic, value: IObyID?.data?.holdingPeriodArabic,
maxLength:20, maxLength: 20,
helperText:`Maximum length should be 20 characters. You have entered ${watch()?.holdingPeriodArabic?.length || 0} characters.` helperText: `Maximum length should be 20 characters. You have entered ${
watch()?.holdingPeriodArabic?.length || 0
} characters.`,
}, },
{ {
label: "Expected Return", label: "Expected Return",
name: "expectedReturn", name: "expectedReturn",
@@ -372,7 +377,7 @@ const IODetails = ({ enableNextTab, index, data }) => {
{ {
label: "Expected Return (Arabic)", label: "Expected Return (Arabic)",
name: "expectedReturnArabic", name: "expectedReturnArabic",
type: "text", type: "text",
isRequired: true, isRequired: true,
arabic: true, arabic: true,
@@ -382,16 +387,15 @@ const IODetails = ({ enableNextTab, index, data }) => {
}, },
{ {
label: "Shariah", label: "Shariah",
name: "isShariah", name: "isShariah",
type: "checkBox", type: "checkBox",
value:IObyID?.data?.isShariah, value: IObyID?.data?.isShariah,
// isRequired: true, // isRequired: true,
section: " ", section: " ",
width: "32.3%", width: "32.3%",
value: IObyID?.data?.isShariah, value: IObyID?.data?.isShariah,
}, },
{ {
label: "Investment Type", label: "Investment Type",
placeHolder: "Select option", placeHolder: "Select option",
@@ -429,19 +433,19 @@ const IODetails = ({ enableNextTab, index, data }) => {
name: "closingDate", name: "closingDate",
// value: "IObyID?.data?.closingDate", // value: "IObyID?.data?.closingDate",
type: "date", type: "date",
isRequired: true, // isRequired: true,
section: " ", section: " ",
width: "32.3%", width: "32.3%",
dateValue:formatDatee(IObyID?.data?.closingDate), dateValue: formatDatee(IObyID?.data?.closingDate),
// helperText: IObyID && `Current closing date is : ${formatDate(IObyID?.data?.closingDate)}` // helperText: IObyID && `Current closing date is : ${formatDate(IObyID?.data?.closingDate)}`
closingDate:true closingDate:id ? null : true
}, },
{ {
label: "ISIN", label: "ISIN",
placeHolder: "", placeHolder: "",
name: "ISIN", name: "ISIN",
type: "text", type: "text",
align:"right", align: "right",
section: " ", section: " ",
width: "32.3%", width: "32.3%",
}, },
@@ -453,8 +457,10 @@ const IODetails = ({ enableNextTab, index, data }) => {
section: " ", section: " ",
width: "32.3%", width: "32.3%",
value: IObyID?.data?.InvestmentDetails, value: IObyID?.data?.InvestmentDetails,
maxLength:20, maxLength: 20,
helperText:`Maximum length should be 20 characters. You have entered ${watch()?.InvestmentDetails?.length || 0} characters.` helperText: `Maximum length should be 20 characters. You have entered ${
watch()?.InvestmentDetails?.length || 0
} characters.`,
}, },
{ {
@@ -463,10 +469,10 @@ const IODetails = ({ enableNextTab, index, data }) => {
name: "table", name: "table",
type: "table", type: "table",
section: " ", section: " ",
width: "100%", width: "100%",
isRequired: true, isRequired: true,
options: investmentTypeOptions, options: investmentTypeOptions,
handleInputChange:id ? handleInputChangeEdit : handleInputChangeCreate, handleInputChange: id ? handleInputChangeEdit : handleInputChangeCreate,
value: values, value: values,
}, },
@@ -479,8 +485,10 @@ const IODetails = ({ enableNextTab, index, data }) => {
width: "100%", width: "100%",
options: investmentTypeOptions, options: investmentTypeOptions,
value: IObyID?.data?.comment, value: IObyID?.data?.comment,
maxLength:100, maxLength: 100,
helperText:`Maximum length should be 100 characters. You have entered ${watch()?.comment?.length || 0} characters.` helperText: `Maximum length should be 100 characters. You have entered ${
watch()?.comment?.length || 0
} characters.`,
}, },
]; ];
const groupedFields = formFields.reduce((groups, field) => { const groupedFields = formFields.reduce((groups, field) => {
@@ -493,30 +501,29 @@ const IODetails = ({ enableNextTab, index, data }) => {
}, {}); }, {});
const onSubmit = async (data) => { const onSubmit = async (data) => {
delete data.table; delete data.table;
setIsLoading(true); setIsLoading(true);
const updatedMinAmount = values?.map(({id, value, _id})=>{ const updatedMinAmount = values?.map(({ id, value, _id }) => {
return { return {
id:_id, id: _id,
country_xid:id, country_xid: id,
minInvestmentAmt: Number(value) minInvestmentAmt: Number(value),
} };
}) });
// console.log(formatDateToYYYYMMDD(data.closingDate)); // console.log(formatDateToYYYYMMDD(data.closingDate));
const formData = { const formData = {
...data, ...data,
investmentType_xid: Number(data.investmentType), investmentType_xid: Number(data.investmentType),
sponsor_xid: Number(data.sponserName), sponsor_xid: Number(data.sponserName),
minInvestmentAmt:updatedMinAmount, minInvestmentAmt: updatedMinAmount,
closingDate: formatDateToYYYYMMDD(data.closingDate) closingDate: formatDateToYYYYMMDD(data.closingDate),
}; };
// console.log(formData); // console.log(formData);
if (id) { if (id) {
console.log("========================",formData); console.log("========================", formData);
const res = await updateIO({ data: formData, id }); const res = await updateIO({ data: formData, id });
console.log(res); console.log(res);
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
@@ -526,20 +533,24 @@ const IODetails = ({ enableNextTab, index, data }) => {
}); });
navigate(`/view-io/${id}`); navigate(`/view-io/${id}`);
enableNextTab(index); enableNextTab(index);
} else if(res?.error?.status === 400){ } else if (res?.error?.status === 400) {
setIsLoading(false); setIsLoading(false);
toast({ toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />, render: () => (
}); <ToastBox message={res?.error?.data?.message} status={"error"} />
} else if(res?.error?.status === 500){ ),
});
} else if (res?.error?.status === 500) {
setIsLoading(false); setIsLoading(false);
toast({ toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />, render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
}); });
} }
} else { } else {
try { try {
console.log("========================",formData); console.log("========================", formData);
const res = await creatIO(formData); const res = await creatIO(formData);
console.log(res?.error?.status); console.log(res?.error?.status);
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
@@ -549,15 +560,19 @@ const IODetails = ({ enableNextTab, index, data }) => {
}); });
navigate(`/view-io/${res?.data?.data}`); navigate(`/view-io/${res?.data?.data}`);
enableNextTab(index); enableNextTab(index);
} else if(res?.error?.status === 400){ } else if (res?.error?.status === 400) {
setIsLoading(false); setIsLoading(false);
toast({ toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />, render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
}); });
}else if(res?.error?.status === 500){ } else if (res?.error?.status === 500) {
setIsLoading(false); setIsLoading(false);
toast({ toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />, render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
}); });
} }
} catch (error) { } catch (error) {
@@ -566,7 +581,6 @@ const IODetails = ({ enableNextTab, index, data }) => {
} }
} }
// ========================== // ==========================
// if (params?.id) { // if (params?.id) {
// return enableNextTab(index); // return enableNextTab(index);
@@ -584,9 +598,8 @@ const IODetails = ({ enableNextTab, index, data }) => {
}; };
return IObyIDisLoading ? ( return IObyIDisLoading ? (
<FullscreenLoaders height={'70vh'} /> <FullscreenLoaders height={"70vh"} />
) : ( ) : (
<FormInputMain <FormInputMain
p={0.1} p={0.1}
w={250} w={250}

View File

@@ -75,7 +75,7 @@ import ToastBox from "../../../../Components/ToastBox";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import AddNavDetails from "./AddNavDetails"; import AddNavDetails from "./AddNavDetails";
import { useUpdateIOCaseMutation } from "../../../../Services/io.service"; import { useUpdateIOCaseMutation } from "../../../../Services/io.service";
import { encryptString } from "../../../../Constants/Constants"; import { encryptString, isMaker } from "../../../../Constants/Constants";
const IONAVDetails = () => { const IONAVDetails = () => {
const params = useParams(); const params = useParams();
@@ -153,7 +153,8 @@ const IONAVDetails = () => {
</Tab> </Tab>
</TabList> </TabList>
{IODetails?.isInvestedAmount {IODetails?.isInvestedAmount
? localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) && ( ? isMaker() &&
IODetails?.ioSatatus !== "Exited" && (
<Button <Button
onClick={handleAdd} onClick={handleAdd}
leftIcon={<AddIcon />} leftIcon={<AddIcon />}

View File

@@ -22,7 +22,7 @@ import ToastBox from "../../../../Components/ToastBox";
import AddNavDetails from "./AddNavDetails"; import AddNavDetails from "./AddNavDetails";
import RequestApproveModal from "./RequestApproveModal"; import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal"; import RequestRejectModal from "./RequestRejectModal";
import { encryptString } from "../../../../Constants/Constants"; import { encryptString, isMaker } from "../../../../Constants/Constants";
const formatDate = (date) => new Date(date).toLocaleDateString(); const formatDate = (date) => new Date(date).toLocaleDateString();
@@ -91,7 +91,7 @@ const Pending = () => {
"Investment Closed", "Investment Closed",
"Comments", "Comments",
"Updated By", "Updated By",
...(localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) ? ["Status"] : []), ...(!isMaker() ? ["Status"] : []),
]; ];
const extractedArray = filteredData?.map((item, index) => ({ const extractedArray = filteredData?.map((item, index) => ({
@@ -112,9 +112,9 @@ const Pending = () => {
$ $
</Badge> </Badge>
{parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, { {parseFloat(item?.transactionAmount || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})} })}
</Text> </Text>
), ),
"Last Nav Update": ( "Last Nav Update": (
@@ -162,66 +162,80 @@ const Pending = () => {
{item?.modifier?.firstName} {item?.modifier?.firstName}
</Text> </Text>
), ),
Status: ( Status: isMaker() ? (
<Button
colorScheme="green"
rounded={"sm"}
size={"xs"}
px={2}
py={1}
fontWeight={500}
onClick={() => {
setActionId(item.id);
}}
>
<ViewIcon me={"4px"} /> View
</Button>
) : (
<Box display={"flex"} justifyContent={"center"}> <Box display={"flex"} justifyContent={"center"}>
<Box> <Box>
<Box display={"flex"} justifyContent={"center"} gap={2}> <Box display={"flex"} justifyContent={"center"} gap={2}>
<Tooltip <Tooltip
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} fontSize={"xs"}
label="Approve" label="Approve"
bg="#fff" bg="#fff"
color={"green.500"} color={"green.500"}
placement="left-start" placement="left-start"
> >
<Button <Button
// colorScheme="forestGreen" // colorScheme="forestGreen"
// color="green.500" // color="green.500"
rounded={"sm"} rounded={"sm"}
size={"xs"} size={"xs"}
textTransform={"inherit"} textTransform={"inherit"}
fontWeight={500} fontWeight={500}
px={2} px={2}
py={1} py={1}
onClick={() => { onClick={() => {
setActionId(item.id); setActionId(item.id);
onConfirmOpen(); onConfirmOpen();
}} }}
colorScheme="green" colorScheme="green"
variant={"solid"} variant={"solid"}
cursor={"pointer"} cursor={"pointer"}
> >
<CheckIcon fontSize={"12px"} /> <CheckIcon fontSize={"12px"} />
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip <Tooltip
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} fontSize={"xs"}
label="Reject" label="Reject"
bg="#fff" bg="#fff"
color={"red.500"} color={"red.500"}
placement="left-start" placement="left-start"
> >
<Button <Button
colorScheme="red" colorScheme="red"
// color="red.500" // color="red.500"
rounded={"sm"} rounded={"sm"}
size={"xs"} size={"xs"}
textTransform={"inherit"} textTransform={"inherit"}
fontWeight={500} fontWeight={500}
px={2} px={2}
onClick={() => { onClick={() => {
setActionId(item.id); setActionId(item.id);
onRejectOpen(); onRejectOpen();
}} }}
py={1} py={1}
// variant={"solid"} // variant={"solid"}
> >
<CloseIcon fontSize={"10px"} /> <CloseIcon fontSize={"10px"} />
</Button> </Button>
</Tooltip> </Tooltip>
</Box>
</Box> </Box>
</Box>
</Box> </Box>
), ),
})); }));

View File

@@ -1,33 +1,26 @@
import { ViewIcon } from "@chakra-ui/icons";
import { import {
Avatar,
Badge, Badge,
Box, Box,
Button, Button,
HStack, HStack,
Input, Input,
Table,
Tag,
Tbody,
Text, Text,
Th,
Tooltip,
Tr,
useDisclosure, useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useRef, useState } from "react"; import React, { useContext, useEffect, useRef, useState } from "react";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import NormalTable from "../../../../Components/DataTable/NormalTable";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../../../Components/CustomAlertDialog";
import { CheckIcon, CloseIcon, ViewIcon } from "@chakra-ui/icons"; import NormalTable from "../../../../Components/DataTable/NormalTable";
import { isMaker } from "../../../../Constants/Constants";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { OPACITY_ON_LOAD } from "../../../../Layout/animations";
import RequestApproveModal from "./RequestApproveModal"; import RequestApproveModal from "./RequestApproveModal";
import RequestRejectModal from "./RequestRejectModal"; import RequestRejectModal from "./RequestRejectModal";
import ViewAmountInvested from "./ViewAmountInvested"; import ViewAmountInvested from "./ViewAmountInvested";
import ViewCancel from "./ViewCancel";
import ViewDistributionInvestor from "./ViewDistributionInvestor"; import ViewDistributionInvestor from "./ViewDistributionInvestor";
import ViewExit from "./ViewExit"; import ViewExit from "./ViewExit";
import ViewCancel from "./ViewCancel";
import { encryptString } from "../../../../Constants/Constants";
const formatDate = (date) => new Date(date).toLocaleDateString(); const formatDate = (date) => new Date(date).toLocaleDateString();
@@ -43,6 +36,7 @@ const Pending = () => {
const [actionId, setActionId] = useState(false); const [actionId, setActionId] = useState(false);
const [mouseEntered, setMouseEntered] = useState(false); const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState(""); const [mouseEnteredId, setMouseEnteredId] = useState("");
const [distributedAmt, setDistributedAmt] = useState();
const { const {
isOpen: isConfirmOpen, isOpen: isConfirmOpen,
@@ -93,11 +87,6 @@ const Pending = () => {
}); });
}; };
console.log(
"==============panding",
IODetails?.ioTransactionRecords?.Pending
);
// Table filter // Table filter
// const filteredData = IODetails?.ioTransactionRecords?.Pending?.filter((item) => { // const filteredData = IODetails?.ioTransactionRecords?.Pending?.filter((item) => {
// // Filter by name (case insensitive) // // Filter by name (case insensitive)
@@ -128,11 +117,7 @@ const Pending = () => {
</Text> </Text>
), ),
"Transaction Date": ( "Transaction Date": (
<Text <Text as={"span"} color={"gray.600"} fontWeight={"500"}>
as={"span"}
color={"gray.600"}
fontWeight={"500"}
>
{formatDate(item?.transactionDate)} {formatDate(item?.transactionDate)}
</Text> </Text>
), ),
@@ -152,9 +137,19 @@ const Pending = () => {
})} })}
</Text> </Text>
), ),
// Amount:(
// <div>
// <ViewDistributionInvestor amount={item?.transactionAmount} />
// </div>
// ),
"Created By": ( "Created By": (
<Text <Text
textTransform={'capitalize'} w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}> textTransform={"capitalize"}
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{item?.creator?.firstName} {item?.creator?.firstName}
</Text> </Text>
), ),
@@ -164,8 +159,13 @@ const Pending = () => {
</Text> </Text>
), ),
"Approved By": ( "Approved By": (
<Text <Text
textTransform={'capitalize'} w={"100px"} as={"span"} color={"gray.800"} fontWeight={"500"}> textTransform={"capitalize"}
w={"100px"}
as={"span"}
color={"gray.800"}
fontWeight={"500"}
>
{item?.modifier?.firstName} {item?.modifier?.firstName}
</Text> </Text>
), ),
@@ -189,6 +189,7 @@ const Pending = () => {
onInvestmentOpen(); onInvestmentOpen();
} else if (item?.transactionType === "Distribution To Investor") { } else if (item?.transactionType === "Distribution To Investor") {
onDistInvestorOpen(); onDistInvestorOpen();
setDistributedAmt(item?.transactionAmount);
} else if (item?.transactionType === "Exit") { } else if (item?.transactionType === "Exit") {
onExitOpen(); onExitOpen();
} else if (item?.transactionType === "Cancel") { } else if (item?.transactionType === "Cancel") {
@@ -196,13 +197,16 @@ const Pending = () => {
} }
}} }}
> >
{localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) ? <ViewIcon me={"4px"} /> : null} {localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) ? "View" : "Approve / Reject"} {isMaker() ? <ViewIcon me={"4px"} /> : null}{" "}
{isMaker() ? "View" : "Approve / Reject"}
</Button> </Button>
</Box> </Box>
), ),
}) })
); );
const handleDelete = () => { const handleDelete = () => {
const updatedSponsors = sponser.filter( const updatedSponsors = sponser.filter(
(sponsor) => sponsor.id !== actionId (sponsor) => sponsor.id !== actionId
@@ -263,20 +267,13 @@ const Pending = () => {
id={actionId} id={actionId}
/> />
<ViewDistributionInvestor <ViewDistributionInvestor
isOpen={isDistInvestorOpen} isOpen={isDistInvestorOpen}
onClose={onDistInvestorClose} onClose={onDistInvestorClose}
id={actionId}
/>
<ViewExit
isOpen={isExitOpen}
onClose={onExitClose}
id={actionId} id={actionId}
amount={distributedAmt}
/> />
<ViewCancel <ViewExit isOpen={isExitOpen} onClose={onExitClose} id={actionId} />
isOpen={isCancelOpen} <ViewCancel isOpen={isCancelOpen} onClose={onCancelClose} id={actionId} />
onClose={onCancelClose}
id={actionId}
/>
<RequestApproveModal <RequestApproveModal
// data={data?.data?.rows} // data={data?.data?.rows}
isOpen={isConfirmOpen} isOpen={isConfirmOpen}

View File

@@ -27,7 +27,7 @@ import CurrencyInput from "../../../../Components/CurrencyInput";
import RequestRejectModal from "./RequestRejectModal"; import RequestRejectModal from "./RequestRejectModal";
import ApproveInvestedModal from "./ApproveInvestedModal"; import ApproveInvestedModal from "./ApproveInvestedModal";
import { formatDate } from "../../../Master/Sponser/Sponsers"; import { formatDate } from "../../../Master/Sponser/Sponsers";
import { encryptString } from "../../../../Constants/Constants"; import { encryptString, isMaker } from "../../../../Constants/Constants";
// Validation schema // Validation schema
const validationSchema = yup.object().shape({ const validationSchema = yup.object().shape({
@@ -117,7 +117,6 @@ const ViewAmountInvested = ({ isOpen, onClose, id: investorId }) => {
}; };
// const formatDate = (date) => new Date(date).toLocaleDateString(); // const formatDate = (date) => new Date(date).toLocaleDateString();
const handleAmountChange = (e) => { const handleAmountChange = (e) => {
// e might be an object or just a value, handle both cases // e might be an object or just a value, handle both cases
@@ -237,41 +236,43 @@ const ViewAmountInvested = ({ isOpen, onClose, id: investorId }) => {
/> />
</FormControl> </FormControl>
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) && <ModalFooter> {!isMaker() && (
<Box display={"flex"} justifyContent={"center"} gap={2}> <ModalFooter>
<Button <Box display={"flex"} justifyContent={"center"} gap={2}>
rounded={"sm"} <Button
size={"xs"} rounded={"sm"}
textTransform={"inherit"} size={"xs"}
fontWeight={500} textTransform={"inherit"}
px={3} fontWeight={500}
py={2} px={3}
onClick={() => { py={2}
setActionId(id); // Use the `id` variable from params onClick={() => {
onConfirmOpen(); setActionId(id); // Use the `id` variable from params
}} onConfirmOpen();
colorScheme="forestGreen" }}
variant={"solid"} colorScheme="forestGreen"
cursor={"pointer"} variant={"solid"}
> cursor={"pointer"}
Approve >
</Button> Approve
<Button </Button>
rounded={"sm"} <Button
size={"xs"} rounded={"sm"}
textTransform={"inherit"} size={"xs"}
fontWeight={500} textTransform={"inherit"}
px={3} fontWeight={500}
py={2} px={3}
onClick={() => { py={2}
setActionId(id); // Use the `id` variable from params onClick={() => {
onRejectOpen(); setActionId(id); // Use the `id` variable from params
}} onRejectOpen();
> }}
Reject >
</Button> Reject
</Box> </Button>
</ModalFooter>} </Box>
</ModalFooter>
)}
</form> </form>
</ModalBody> </ModalBody>
</ModalContent> </ModalContent>

View File

@@ -1,128 +1,128 @@
import { import {
Badge, Badge,
Box, Box,
Button, Button,
HStack, HStack,
Modal, Modal,
ModalBody, ModalBody,
ModalCloseButton, ModalCloseButton,
ModalContent, ModalContent,
ModalFooter, ModalFooter,
ModalHeader, ModalHeader,
ModalOverlay, ModalOverlay,
Table, Table,
Tbody, Tbody,
Text, Text,
Th, Th,
Tr, Tr,
useDisclosure, useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import NormalData from "../../../../Components/DataTable/NormalTable"; import NormalData from "../../../../Components/DataTable/NormalTable";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { import {
useExitIOTransactionMutation, useExitIOTransactionMutation,
useGetDistributedToInvestorMutation, useGetDistributedToInvestorMutation,
useGetDistributionInvestorMutation, useGetDistributionInvestorMutation,
useGetIOByIdQuery, useGetIOByIdQuery,
} from "../../../../Services/io.service"; } from "../../../../Services/io.service";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { useEffect } from "react"; import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import * as yup from "yup"; import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import ToastBox from "../../../../Components/ToastBox"; import ToastBox from "../../../../Components/ToastBox";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import ApprovedCancelTransaction from "./ApprovedCancelTransaction"; import ApprovedCancelTransaction from "./ApprovedCancelTransaction";
import RequestRejectModal from "./RequestRejectModal"; import RequestRejectModal from "./RequestRejectModal";
import { encryptString } from "../../../../Constants/Constants"; import { encryptString, isMaker } from "../../../../Constants/Constants";
const ViewCancel = ({ isOpen, onClose,id:cancleId }) => { const ViewCancel = ({ isOpen, onClose, id: cancleId }) => {
const params = useParams(); const params = useParams();
const toast = useToast(); const toast = useToast();
const id = params?.id; const id = params?.id;
const [isCalculateLoading, setIsCalculateLoading] = useState(false); const [isCalculateLoading, setIsCalculateLoading] = useState(false);
const [isFinalCalculateLoading, setIsFinalCalculateLoading] = useState(false); const [isFinalCalculateLoading, setIsFinalCalculateLoading] = useState(false);
const [calcualtedData, setCalculatedDate] = useState(null); const [calcualtedData, setCalculatedDate] = useState(null);
const [isCalcualtedData, setIsCalcualtedData] = useState(false); const [isCalcualtedData, setIsCalcualtedData] = useState(false);
const { investors, setInvestors, slideFromRight, IODetails } = const { investors, setInvestors, slideFromRight, IODetails } =
useContext(GlobalStateContext); useContext(GlobalStateContext);
const [actionId, setActionId] = useState(false); const [actionId, setActionId] = useState(false);
const { const {
isOpen: isConfirmOpen, isOpen: isConfirmOpen,
onOpen: onConfirmOpen, onOpen: onConfirmOpen,
onClose: onConfirmClose, onClose: onConfirmClose,
} = useDisclosure(); } = useDisclosure();
const { const {
isOpen: isRejectOpen, isOpen: isRejectOpen,
onOpen: onRejectOpen, onOpen: onRejectOpen,
onClose: onRejectClose, onClose: onRejectClose,
} = useDisclosure(); } = useDisclosure();
const investorExit = yup.object().shape({ const investorExit = yup.object().shape({
amount: yup amount: yup
.string() .string()
.required("Amount is required") .required("Amount is required")
.test( .test(
"max", "max",
`Distribution amount should not be greater than IO cash amount ${IODetails?.ioCash}`, `Distribution amount should not be greater than IO cash amount ${IODetails?.ioCash}`,
function (value) { function (value) {
const { ioCash } = IODetails || {}; // Safely get ioCash const { ioCash } = IODetails || {}; // Safely get ioCash
if (value && ioCash) { if (value && ioCash) {
return parseFloat(value) <= parseFloat(ioCash); // Ensure both are compared as numbers return parseFloat(value) <= parseFloat(ioCash); // Ensure both are compared as numbers
}
return true; // If ioCash is not available, skip validation
} }
), return true; // If ioCash is not available, skip validation
}); }
),
const { });
control,
handleSubmit, const {
formState: { errors }, control,
reset, handleSubmit,
} = useForm({ formState: { errors },
resolver: yupResolver(investorExit), reset,
}); } = useForm({
resolver: yupResolver(investorExit),
useEffect(() => { });
console.log("hiit useEffectc");
if (id && IODetails) { useEffect(() => {
handleCalculate(id, { console.log("hiit useEffectc");
amount: IODetails?.ioMVNAV, if (id && IODetails) {
}); handleCalculate(id, {
}
reset({
amount: IODetails?.ioMVNAV, amount: IODetails?.ioMVNAV,
}); });
}, [IODetails, id]); }
reset({
const handleCalculate = async (id, data) => { amount: IODetails?.ioMVNAV,
try {
const res = await getDistributionInvestment({ id, data });
console.log(res?.data?.data);
if (res?.error?.status === 401) {
setIsCalculateLoading(false);
setIsCalcualtedData(false);
} else if (res?.data?.statusCode === 200) {
setCalculatedDate(res?.data?.data);
setIsCalculateLoading(false);
setIsCalcualtedData(true);
}
} catch (error) {}
};
const [getDistributionInvestment] = useGetDistributionInvestorMutation();
const investor = yup.object().shape({
amount: yup.string().required("Amount is required"),
}); });
}, [IODetails, id]);
// ====================================================[Table Setup]================================================================
const tableHeadRow = [ const handleCalculate = async (id, data) => {
try {
const res = await getDistributionInvestment({ id, data });
console.log(res?.data?.data);
if (res?.error?.status === 401) {
setIsCalculateLoading(false);
setIsCalcualtedData(false);
} else if (res?.data?.statusCode === 200) {
setCalculatedDate(res?.data?.data);
setIsCalculateLoading(false);
setIsCalcualtedData(true);
}
} catch (error) {}
};
const [getDistributionInvestment] = useGetDistributionInvestorMutation();
const investor = yup.object().shape({
amount: yup.string().required("Amount is required"),
});
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
"Client ID", "Client ID",
"First name", "First name",
"Last name", "Last name",
@@ -134,221 +134,223 @@ import { encryptString } from "../../../../Constants/Constants";
"Distribution Percent", "Distribution Percent",
"Total Return", "Total Return",
"Total return on Investment", "Total return on Investment",
]; ];
const extractedArray = IODetails?.investors?.map((item, index) => ({ const extractedArray = IODetails?.investors?.map((item, index) => ({
id: item?.id, id: item?.id,
"Client ID": ( "Client ID": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={slideFromRight ? "right" : "center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item?.clientReference_id} {item?.clientReference_id}
</Text> </Text>
), ),
"First name": ( "First name": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={slideFromRight ? "right" : "center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.firstName} {item.firstName}
</Text> </Text>
), ),
"Last name": ( "Last name": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={slideFromRight ? "right" : "center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.lastName} {item.lastName}
</Text> </Text>
), ),
"Investment amount": ( "Investment amount": (
<Text <Text
justifyContent={slideFromRight ? "right" : "left"} justifyContent={slideFromRight ? "right" : "left"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
<Badge ms={1} colorScheme="green" me={1}> <Badge ms={1} colorScheme="green" me={1}>
$ $
</Badge> </Badge>
{/* {`$${formatCurrency(item.InvestedAmount_USD)}`} */} {/* {`$${formatCurrency(item.InvestedAmount_USD)}`} */}
{`${parseFloat(item.InvestedAmount_USD || 0).toLocaleString(undefined, { {`${parseFloat(item.InvestedAmount_USD || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})}`} })}`}
</Text> </Text>
), ),
Percentage: ( Percentage: (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={slideFromRight ? "right" : "center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.Investor_Holidings} % {item.Investor_Holidings} %
</Text> </Text>
), ),
"Market Value": ( "Market Value": (
<Text <Text
justifyContent={slideFromRight ? "right" : "left"} justifyContent={slideFromRight ? "right" : "left"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
<Badge ms={1} colorScheme="green" me={1}> <Badge ms={1} colorScheme="green" me={1}>
$ $
</Badge> </Badge>
{`${parseFloat(item.Market_Value || 0).toLocaleString(undefined, { {`${parseFloat(item.Market_Value || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})}`} })}`}
</Text> </Text>
), ),
"Return on Investment": ( "Return on Investment": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={slideFromRight ? "right" : "center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
h={6} h={6}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.Return_On_Investment || 0} % {item.Return_On_Investment || 0} %
</Text> </Text>
), ),
Distribution: ( Distribution: (
<Text <Text
justifyContent={slideFromRight ? "right" : "left"} justifyContent={slideFromRight ? "right" : "left"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
<Badge ms={1} colorScheme="green" me={1}> <Badge ms={1} colorScheme="green" me={1}>
$ $
</Badge> </Badge>
{/* {`$${item.Distribution_Amt}`} */} {/* {`$${item.Distribution_Amt}`} */}
{`${parseFloat(item.Distribution_Amt || 0).toLocaleString(undefined, { {`${parseFloat(item.Distribution_Amt || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})}`} })}`}
</Text> </Text>
), ),
"Distribution Percent": ( "Distribution Percent": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={slideFromRight ? "right" : "center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{/* {`$${item.Distribution_Amt}`} */} {/* {`$${item.Distribution_Amt}`} */}
{`${parseFloat(item.Distribution_Per || 0).toLocaleString(undefined, { {`${parseFloat(item.Distribution_Per || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})} %`} })} %`}
</Text> </Text>
), ),
"Total Return": ( "Total Return": (
<Text <Text
justifyContent={slideFromRight ? "right" : "left"} justifyContent={slideFromRight ? "right" : "left"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
<Badge ms={1} colorScheme="green" me={1}> <Badge ms={1} colorScheme="green" me={1}>
$ $
</Badge> </Badge>
{/* {`$${formatCurrency(item.Total_Return) || 0}`} */} {/* {`$${formatCurrency(item.Total_Return) || 0}`} */}
{`${parseFloat(item.Total_Return || 0).toLocaleString(undefined, { {`${parseFloat(item.Total_Return || 0).toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})}`} })}`}
</Text> </Text>
), ),
"Total return on Investment": ( "Total return on Investment": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={slideFromRight ? "right" : "center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.Total_Return_On_Investment || 0} % {item.Total_Return_On_Investment || 0} %
</Text> </Text>
), ),
})); }));
const handleClose = () => { const handleClose = () => {
onClose(); onClose();
setIsFinalCalculateLoading(false); setIsFinalCalculateLoading(false);
setIsCalcualtedData(false); setIsCalcualtedData(false);
}; };
return ( return (
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose} > <Modal size={"xl"} isOpen={isOpen} onClose={handleClose}>
<ModalOverlay /> <ModalOverlay />
<ModalContent maxW={1000}> <ModalContent maxW={1000}>
<ModalHeader fontSize={"md"}>Cancel Transaction</ModalHeader> <ModalHeader fontSize={"md"}>Cancel Transaction</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody> <ModalBody>
<NormalData <NormalData
emptyMessage={`We don't have any Sponers `} emptyMessage={`We don't have any Sponers `}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
data={extractedArray} data={extractedArray}
/> />
</ModalBody> </ModalBody>
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) && <ModalFooter pt={0}> {!isMaker() && (
<ModalFooter pt={0}>
<Box display={"flex"} justifyContent={"center"} gap={2}> <Box display={"flex"} justifyContent={"center"} gap={2}>
<Button <Button
rounded={"sm"} rounded={"sm"}
size={"xs"} size={"xs"}
textTransform={"inherit"} textTransform={"inherit"}
fontWeight={500} fontWeight={500}
px={3} px={3}
py={2} py={2}
onClick={() => { onClick={() => {
setActionId(id); // Use the `id` variable from params setActionId(id); // Use the `id` variable from params
onConfirmOpen(); onConfirmOpen();
}} }}
colorScheme="forestGreen" colorScheme="forestGreen"
variant={"solid"} variant={"solid"}
cursor={"pointer"} cursor={"pointer"}
> >
Approve Approve
</Button> </Button>
<Button <Button
rounded={"sm"} rounded={"sm"}
size={"xs"} size={"xs"}
textTransform={"inherit"} textTransform={"inherit"}
fontWeight={500} fontWeight={500}
px={3} px={3}
py={2} py={2}
onClick={() => { onClick={() => {
setActionId(id); // Use the `id` variable from params setActionId(id); // Use the `id` variable from params
onRejectOpen(); onRejectOpen();
}} }}
> >
Reject Reject
</Button> </Button>
</Box> </Box>
</ModalFooter>} </ModalFooter>
</ModalContent> )}
<ApprovedCancelTransaction </ModalContent>
<ApprovedCancelTransaction
isOpen={isConfirmOpen} isOpen={isConfirmOpen}
onClose={onConfirmClose} onClose={onConfirmClose}
onBigModalClose={onClose} onBigModalClose={onClose}
@@ -360,9 +362,8 @@ import { encryptString } from "../../../../Constants/Constants";
onBigModalClose={onClose} onBigModalClose={onClose}
id={cancleId} id={cancleId}
/> />
</Modal> </Modal>
); );
}; };
export default ViewCancel; export default ViewCancel;

View File

@@ -23,9 +23,9 @@ import { yupResolver } from "@hookform/resolvers/yup";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import ApproveDistrubationModal from "./ApproveDistrubationModal"; import ApproveDistrubationModal from "./ApproveDistrubationModal";
import RequestRejectModal from "./RequestRejectModal"; import RequestRejectModal from "./RequestRejectModal";
import { encryptString } from "../../../../Constants/Constants"; import { encryptString, isMaker } from "../../../../Constants/Constants";
const ViewDistributionInvestor = ({ isOpen, onClose,id:exitId }) => { const ViewDistributionInvestor = ({ isOpen, onClose, id: exitId, amount }) => {
const params = useParams(); const params = useParams();
const toast = useToast(); const toast = useToast();
const id = params?.id; const id = params?.id;
@@ -72,19 +72,15 @@ const ViewDistributionInvestor = ({ isOpen, onClose,id:exitId }) => {
}); });
useEffect(() => { useEffect(() => {
console.log("hiit useEffectc");
// handleCalculate(id, {
// amount: IODetails?.ioMVNAV,
// });
if (id && IODetails) { if (id && IODetails) {
handleCalculate(id, { handleCalculate(id, {
amount: IODetails?.ioMVNAV, amount: Math.abs(amount),
}); });
} }
reset({ reset({
amount: IODetails?.ioMVNAV, amount: amount,
}); });
}, [IODetails, id]); }, [IODetails, id, amount]);
const handleCalculate = async (id, data) => { const handleCalculate = async (id, data) => {
try { try {
@@ -176,7 +172,7 @@ const ViewDistributionInvestor = ({ isOpen, onClose,id:exitId }) => {
"Distriution Amt($)": ( "Distriution Amt($)": (
<Box minW={24} isTruncated={true}> <Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}> <Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.distribution_amt?.toLocaleString(undefined, { {IODetails?.ioTransactionRecords?.Pending[index]?.transactionAmount?.toLocaleString(undefined, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2, maximumFractionDigits: 2,
})} })}
@@ -201,7 +197,6 @@ const ViewDistributionInvestor = ({ isOpen, onClose,id:exitId }) => {
setIsFinalCalculateLoading(false); setIsFinalCalculateLoading(false);
setIsCalcualtedData(false); setIsCalcualtedData(false);
}; };
return ( return (
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose}> <Modal size={"xl"} isOpen={isOpen} onClose={handleClose}>
@@ -219,41 +214,43 @@ const ViewDistributionInvestor = ({ isOpen, onClose,id:exitId }) => {
/> />
</ModalBody> </ModalBody>
{/* ...(localStorage?.getItem("role") !== "Maker" ? ["Status"] : []), */} {/* ...(localStorage?.getItem("role") !== "Maker" ? ["Status"] : []), */}
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) &&<ModalFooter pt={0}> {!isMaker() && (
<Box display={"flex"} justifyContent={"center"} gap={2}> <ModalFooter pt={0}>
<Button <Box display={"flex"} justifyContent={"center"} gap={2}>
rounded={"sm"} <Button
size={"xs"} rounded={"sm"}
textTransform={"inherit"} size={"xs"}
fontWeight={500} textTransform={"inherit"}
px={3} fontWeight={500}
py={2} px={3}
onClick={() => { py={2}
setActionId(id); // Use the `id` variable from params onClick={() => {
onConfirmOpen(); setActionId(id); // Use the `id` variable from params
}} onConfirmOpen();
colorScheme="forestGreen" }}
variant={"solid"} colorScheme="forestGreen"
cursor={"pointer"} variant={"solid"}
> cursor={"pointer"}
Approve >
</Button> Approve
<Button </Button>
rounded={"sm"} <Button
size={"xs"} rounded={"sm"}
textTransform={"inherit"} size={"xs"}
fontWeight={500} textTransform={"inherit"}
px={3} fontWeight={500}
py={2} px={3}
onClick={() => { py={2}
setActionId(id); // Use the `id` variable from params onClick={() => {
onRejectOpen(); setActionId(id); // Use the `id` variable from params
}} onRejectOpen();
> }}
Reject >
</Button> Reject
</Box> </Button>
</ModalFooter>} </Box>
</ModalFooter>
)}
</ModalContent> </ModalContent>
<ApproveDistrubationModal <ApproveDistrubationModal
isOpen={isConfirmOpen} isOpen={isConfirmOpen}

View File

@@ -1,330 +1,332 @@
import { import {
Alert, Alert,
AlertIcon, AlertIcon,
Box, Box,
Button, Button,
FormControl, FormControl,
FormErrorMessage, FormErrorMessage,
FormLabel, FormLabel,
HStack, HStack,
Input, Input,
Modal, Modal,
ModalBody, ModalBody,
ModalCloseButton, ModalCloseButton,
ModalContent, ModalContent,
ModalFooter, ModalFooter,
ModalHeader, ModalHeader,
ModalOverlay, ModalOverlay,
Switch, Switch,
Table, Table,
Tbody, Tbody,
Text, Text,
Textarea, Textarea,
Th, Th,
Tr, Tr,
useDisclosure, useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import NormalData from "../../../../Components/DataTable/NormalTable"; import NormalData from "../../../../Components/DataTable/NormalTable";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { AddIcon } from "@chakra-ui/icons"; import { AddIcon } from "@chakra-ui/icons";
import { import {
useExitIOTransactionMutation, useExitIOTransactionMutation,
useGetDistributedToInvestorMutation, useGetDistributedToInvestorMutation,
useGetDistributionInvestorMutation, useGetDistributionInvestorMutation,
useUpdateExitToInvestorMutation, useUpdateExitToInvestorMutation,
} from "../../../../Services/io.service"; } from "../../../../Services/io.service";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { useEffect } from "react"; import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import * as yup from "yup"; import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import ToastBox from "../../../../Components/ToastBox"; import ToastBox from "../../../../Components/ToastBox";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import ApprovedExit from "./ApprovedExit"; import ApprovedExit from "./ApprovedExit";
import RequestRejectModal from "./RequestRejectModal"; import RequestRejectModal from "./RequestRejectModal";
import { encryptString } from "../../../../Constants/Constants"; import { encryptString, isMaker } from "../../../../Constants/Constants";
const ViewExit = ({ isOpen, onClose ,id:investerId}) => {
const params = useParams();
const toast = useToast();
const id = params?.id;
const [isCalculateLoading, setIsCalculateLoading] = useState(false);
const [isFinalCalculateLoading, setIsFinalCalculateLoading] = useState(false);
const [calcualtedData, setCalculatedDate] = useState(null);
const [isCalcualtedData, setIsCalcualtedData] = useState(false);
const { IODetails } = useContext(GlobalStateContext);
const [actionId, setActionId] = useState(false);
const { const ViewExit = ({ isOpen, onClose, id: investerId }) => {
isOpen: isConfirmOpen, const params = useParams();
onOpen: onConfirmOpen, const toast = useToast();
onClose: onConfirmClose, const id = params?.id;
} = useDisclosure(); const [isCalculateLoading, setIsCalculateLoading] = useState(false);
const { const [isFinalCalculateLoading, setIsFinalCalculateLoading] = useState(false);
isOpen: isRejectOpen, const [calcualtedData, setCalculatedDate] = useState(null);
onOpen: onRejectOpen, const [isCalcualtedData, setIsCalcualtedData] = useState(false);
onClose: onRejectClose, const { IODetails } = useContext(GlobalStateContext);
} = useDisclosure(); const [actionId, setActionId] = useState(false);
const {
const { isOpen: isConfirmOpen,
control, onOpen: onConfirmOpen,
handleSubmit, onClose: onConfirmClose,
formState: { errors }, } = useDisclosure();
reset, const {
} = useForm({ isOpen: isRejectOpen,
resolver: yupResolver(), onOpen: onRejectOpen,
}); onClose: onRejectClose,
} = useDisclosure();
useEffect(() => {
console.log("hiit useEffectc"); const {
if (id && IODetails) { control,
handleSubmit,
formState: { errors },
reset,
} = useForm({
resolver: yupResolver(),
});
useEffect(() => {
console.log("hiit useEffectc");
if (id && IODetails) {
handleCalculate(id, { handleCalculate(id, {
amount: IODetails?.ioMVNAV, amount: IODetails?.ioMVNAV,
}); });
} }
reset({ reset({
amount: IODetails?.ioMVNAV, amount: IODetails?.ioMVNAV,
});
}, [IODetails, id]);
const handleCalculate = async (id, data) => {
try {
const res = await getDistributionInvestment({ id, data });
console.log(res?.data?.data);
if (res?.error?.status === 401) {
setIsCalculateLoading(false);
setIsCalcualtedData(false);
} else if (res?.data?.statusCode === 200) {
setCalculatedDate(res?.data?.data);
setIsCalculateLoading(false);
setIsCalcualtedData(true);
}
} catch (error) {}
};
const [getDistributionInvestment] = useGetDistributionInvestorMutation();
const investor = yup.object().shape({
amount: yup.string().required("Amount is required"),
}); });
}, [IODetails, id]);
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
"Sr No.",
"Client Id",
"First name",
"Last Name",
"Amount",
"Holding (%)",
"Exit Amt($)",
];
const handleCalculate = async (id, data) => {
try {
const extractedArray = calcualtedData?.data?.map((item, index) => ({ const res = await getDistributionInvestment({ id, data });
id: item?.id, console.log(res?.data?.data);
"Sr No.": (
<Box
w={9}
display={"flex"}
alignItems={"center"}
isTruncated={true}
h={25}
>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{index + 1}
</Text>
</Box>
),
"Client Id": (
<Box w={100} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.clientId}
</Text>
</Box>
),
"First name": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.firstName}
</Text>
</Box>
),
"Last Name": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.lastName}
</Text>
</Box>
),
Amount: (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.amount?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</Box>
),
"Holding (%)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.investor_holidings?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}%
</Text>
</Box>
),
"Exit Amt($)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.distribution_amt?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</Box>
),
}));
const onSubmit = async (data) => {
setIsCalculateLoading(true);
try {
const res = await getDistributionInvestment({ id, data });
console.log(res?.data?.data);
if (res?.error?.status === 401) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
});
setIsCalculateLoading(false);
setIsCalcualtedData(false);
} else if (res?.data?.statusCode === 200) {
setCalculatedDate(res?.data?.data);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
setIsCalculateLoading(false);
setIsCalcualtedData(true);
}
} catch (error) {}
};
const handleClose = () => {
onClose();
setIsFinalCalculateLoading(false);
setIsCalcualtedData(false);
};
console.log(id);
return ( if (res?.error?.status === 401) {
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose} > setIsCalculateLoading(false);
<ModalOverlay /> setIsCalcualtedData(false);
<ModalContent maxW={1000}> } else if (res?.data?.statusCode === 200) {
<ModalHeader fontSize={"md"}>Exit Transaction</ModalHeader> setCalculatedDate(res?.data?.data);
<ModalCloseButton /> setIsCalculateLoading(false);
<ModalBody> setIsCalcualtedData(true);
{/* <Text as="label" mb="5px" fontSize="sm" fontWeight={500}> }
} catch (error) {}
};
const [getDistributionInvestment] = useGetDistributionInvestorMutation();
const investor = yup.object().shape({
amount: yup.string().required("Amount is required"),
});
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
"Sr No.",
"Client Id",
"First name",
"Last Name",
"Amount",
"Holding (%)",
"Exit Amt($)",
];
const extractedArray = calcualtedData?.data?.map((item, index) => ({
id: item?.id,
"Sr No.": (
<Box
w={9}
display={"flex"}
alignItems={"center"}
isTruncated={true}
h={25}
>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{index + 1}
</Text>
</Box>
),
"Client Id": (
<Box w={100} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.clientId}
</Text>
</Box>
),
"First name": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.firstName}
</Text>
</Box>
),
"Last Name": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.lastName}
</Text>
</Box>
),
Amount: (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.amount?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</Box>
),
"Holding (%)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.investor_holidings?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
%
</Text>
</Box>
),
"Exit Amt($)": (
<Box minW={24} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.distribution_amt?.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</Text>
</Box>
),
}));
const onSubmit = async (data) => {
setIsCalculateLoading(true);
try {
const res = await getDistributionInvestment({ id, data });
console.log(res?.data?.data);
if (res?.error?.status === 401) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
});
setIsCalculateLoading(false);
setIsCalcualtedData(false);
} else if (res?.data?.statusCode === 200) {
setCalculatedDate(res?.data?.data);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
setIsCalculateLoading(false);
setIsCalcualtedData(true);
}
} catch (error) {}
};
const handleClose = () => {
onClose();
setIsFinalCalculateLoading(false);
setIsCalcualtedData(false);
};
console.log(id);
return (
<Modal size={"xl"} isOpen={isOpen} onClose={handleClose}>
<ModalOverlay />
<ModalContent maxW={1000}>
<ModalHeader fontSize={"md"}>Exit Transaction</ModalHeader>
<ModalCloseButton />
<ModalBody>
{/* <Text as="label" mb="5px" fontSize="sm" fontWeight={500}>
Amount to Distribute Amount to Distribute
</Text> */} </Text> */}
<HStack onSubmit={handleSubmit(onSubmit)} as={"form"} mb={4} alignItems={'center'}> <HStack
{/* <Input placeholder="$00.00" size={"sm"} className="col" /> */} onSubmit={handleSubmit(onSubmit)}
{/* <FormControl isInvalid={errors.amount} isRequired>*/} as={"form"}
<Text textAlign={"right"} fontSize={"sm"}> mb={4}
Exit Amount : alignItems={"center"}
</Text> >
<Text {/* <Input placeholder="$00.00" size={"sm"} className="col" /> */}
textAlign={"start"} {/* <FormControl isInvalid={errors.amount} isRequired>*/}
bg={"green.100"} <Text textAlign={"right"} fontSize={"sm"}>
p={2} Exit Amount :
rounded={"md"} </Text>
fontSize={"sm"} <Text
pt={1} textAlign={"start"}
pb={1} bg={"green.100"}
fontWeight={600} p={2}
> rounded={"md"}
${" "} fontSize={"sm"}
{parseFloat(IODetails?.ioMVNAV || 0).toLocaleString(undefined, { pt={1}
minimumFractionDigits: 2, pb={1}
maximumFractionDigits: 2, fontWeight={600}
})} >
</Text> ${" "}
{parseFloat(IODetails?.ioMVNAV || 0).toLocaleString(undefined, {
{/* </FormControl> */} minimumFractionDigits: 2,
</HStack> maximumFractionDigits: 2,
})}
{/* {calcualtedData && ( */} </Text>
<NormalData
emptyMessage={`We don't have any Sponers `} {/* </FormControl> */}
tableHeadRow={tableHeadRow} </HStack>
data={extractedArray}
// total={<Total />} {/* {calcualtedData && ( */}
// isLoading={isLoading} <NormalData
/> emptyMessage={`We don't have any Sponers `}
{/* ) } */} tableHeadRow={tableHeadRow}
</ModalBody> data={extractedArray}
{localStorage?.getItem("role") !== encryptString(import.meta.env.VITE_VITE_MAKER) && <ModalFooter pt={0}> // total={<Total />}
// isLoading={isLoading}
/>
{/* ) } */}
</ModalBody>
{!isMaker() && (
<ModalFooter pt={0}>
<Box display={"flex"} justifyContent={"center"} gap={2}> <Box display={"flex"} justifyContent={"center"} gap={2}>
<Button <Button
rounded={"sm"} rounded={"sm"}
size={"xs"} size={"xs"}
textTransform={"inherit"} textTransform={"inherit"}
fontWeight={500} fontWeight={500}
px={3} px={3}
py={2} py={2}
onClick={() => { onClick={() => {
setActionId(id); // Use the `id` variable from params setActionId(id); // Use the `id` variable from params
onConfirmOpen(); onConfirmOpen();
}} }}
colorScheme="forestGreen" colorScheme="forestGreen"
variant={"solid"} variant={"solid"}
cursor={"pointer"} cursor={"pointer"}
> >
Approve Approve
</Button> </Button>
<Button <Button
rounded={"sm"} rounded={"sm"}
size={"xs"} size={"xs"}
textTransform={"inherit"} textTransform={"inherit"}
fontWeight={500} fontWeight={500}
px={3} px={3}
py={2} py={2}
onClick={() => { onClick={() => {
setActionId(id); // Use the `id` variable from params setActionId(id); // Use the `id` variable from params
onRejectOpen(); onRejectOpen();
}} }}
> >
Reject Reject
</Button> </Button>
</Box> </Box>
</ModalFooter>} </ModalFooter>
</ModalContent> )}
<ApprovedExit </ModalContent>
isOpen={isConfirmOpen} <ApprovedExit
onClose={onConfirmClose} isOpen={isConfirmOpen}
onBigModalClose={onClose} onClose={onConfirmClose}
id={investerId} onBigModalClose={onClose}
/> id={investerId}
<RequestRejectModal />
isOpen={isRejectOpen} <RequestRejectModal
onClose={onRejectClose} isOpen={isRejectOpen}
onBigModalClose={onClose} onClose={onRejectClose}
id={investerId} onBigModalClose={onClose}
/> id={investerId}
</Modal> />
); </Modal>
}; );
};
export default ViewExit;
export default ViewExit;

View File

@@ -1,57 +1,29 @@
import React, { useContext, useEffect, useState } from "react";
import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import { import {
Box, Box,
Divider,
FormControl,
FormLabel,
Heading,
Input,
Select,
Textarea,
Button,
Text,
Image,
Tabs,
TabList,
Tab, Tab,
TabList,
TabPanel, TabPanel,
TabPanels, TabPanels,
Tooltip, Tabs,
Switch,
useDisclosure, useDisclosure,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup"; import React, { useContext, useEffect, useState } from "react";
import { import { useForm } from "react-hook-form";
AddIcon,
CloseIcon,
DeleteIcon,
EditIcon,
ViewIcon,
WarningTwoIcon,
} from "@chakra-ui/icons";
import { TiWarning } from "react-icons/ti";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import FormField from "../../../Components/FormField"; import * as yup from "yup";
import { v4 as uuidv4 } from "uuid"; import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import AddIOCharges from "../AddIOCharges"; import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import FormInputMain from "../../../Components/FormInputMain";
import DataTable from "../../../Components/DataTable/DataTable";
import { debounce } from "../../Master/Sponser/AddSponser";
import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import { formatDate } from "../../../Components/Functions/UTCConvertor";
import IODetails from "./IODetails";
import KeyMerits from "./KeyMerits";
import IOArtifacts from "./IOArtifacts";
import Investors from "./Investors";
import IOCashDetails from "./IOCashDetails";
import IONAVDetails from "./IONAVDetails";
import Distribution from "./Destribution"; import Distribution from "./Destribution";
import InvestmentDocuments from "../InvestmentDocuments";
import InvestmentDocument from "./InvestmentDocument"; import InvestmentDocument from "./InvestmentDocument";
import Investors from "./Investors";
import IOArtifacts from "./IOArtifacts";
import IOCashDetails from "./IOCashDetails";
import IODetails from "./IODetails";
import IONAVDetails from "./IONAVDetails";
import KeyMerits from "./KeyMerits";
import { useAuthProfileQuery } from "../../Services/token.serivce";
import { encryptString } from "../../Constants/Constants";
const schema = yup.object().shape({ const schema = yup.object().shape({
ioName: yup.string().required("Arabic name is required"), ioName: yup.string().required("Arabic name is required"),
@@ -59,7 +31,9 @@ const schema = yup.object().shape({
discription: yup.string().required("Description is required"), discription: yup.string().required("Description is required"),
discriptionArabic: yup.string().required("Arabic Description is required"), discriptionArabic: yup.string().required("Arabic Description is required"),
typeName: yup.string().required("Investment type is required"), typeName: yup.string().required("Investment type is required"),
typeNameArabic: yup.string().required("Investment type arabic name is required"), typeNameArabic: yup
.string()
.required("Investment type arabic name is required"),
sponserName: yup.string().required("Sponsorer name is required"), sponserName: yup.string().required("Sponsorer name is required"),
sponserNameArabic: yup sponserNameArabic: yup
.string() .string()
@@ -293,7 +267,7 @@ const EditViewIO = () => {
isRequired: true, isRequired: true,
section: " ", section: " ",
width: "32.3%", width: "32.3%",
}, },
{ {
label: "Name (Arabic)", label: "Name (Arabic)",
placeHolder: " ", placeHolder: " ",

View File

@@ -360,7 +360,7 @@ const IOArtifactsAdd = ({
isOpen={alert} isOpen={alert}
onClose={handleAlertClose} onClose={handleAlertClose}
alertHandler={handleSave} alertHandler={handleSave}
message={"Are you sure you want to update this artifact?"} message={"Are you sure you want to add this artifact?"}
isLoading={loading} isLoading={loading}
/> />
</> </>

View File

@@ -112,8 +112,18 @@ const AmountInvested = ({ isOpen, onClose }) => {
}); });
}; };
const handleModalClose = () => {
reset({
transactionDate: "",
Total_Amount: IODetails?.totalAmtInvestmentInUSD || 0,
amountInvested: 0,
IoCash: IODetails?.totalAmtInvestmentInUSD || 0,
});
onClose();
};
return ( return (
<Modal isOpen={isOpen} onClose={onClose}> <Modal isOpen={isOpen} onClose={handleModalClose}>
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<ModalHeader fontSize={"md"}>Amount Invested</ModalHeader> <ModalHeader fontSize={"md"}>Amount Invested</ModalHeader>
@@ -246,7 +256,7 @@ const AmountInvested = ({ isOpen, onClose }) => {
> >
Save Save
</Button> </Button>
<Button size={"sm"} rounded={"sm"} mr={3} onClick={onClose}> <Button size={"sm"} rounded={"sm"} mr={3} onClick={handleModalClose}>
Close Close
</Button> </Button>
</ModalFooter> </ModalFooter>

View File

@@ -495,7 +495,7 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
> >
Save Save
</Button> </Button>
<Button size={"sm"} rounded={"sm"} mr={3} onClick={onClose}> <Button size={"sm"} rounded={"sm"} mr={3} onClick={handleClose}>
Close Close
</Button> </Button>
</> </>

View File

@@ -58,7 +58,7 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => {
let res; let res;
// If selectedItem is 'Cancelled', make the updateCancelStatus API call // If selectedItem is 'Cancelled', make the updateCancelStatus API call
if (selectedItem === "Cancelled") { if (selectedItem === import.meta.env.VITE_STATUS_CANCELLED) {
res = await updateCancleStatus({ res = await updateCancleStatus({
id id
}); });
@@ -119,17 +119,17 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => {
mb={1.5} mb={1.5}
textTransform={"none"} textTransform={"none"}
colorScheme={ colorScheme={
selectedItem === "Draft" selectedItem === import.meta.env.VITE_STATUS_DRAFT
? "gray" ? "gray"
: selectedItem === "Processing" : selectedItem === import.meta.env.VITE_STATUS_PROCESSING
? "yellow" ? "yellow"
: selectedItem === "Open" : selectedItem === import.meta.env.VITE_STATUS_OPEN
? "blue" ? "blue"
: selectedItem === "Closed" : selectedItem === import.meta.env.VITE_STATUS_CLOSED
? "green" ? "green"
: selectedItem === "Exited" : selectedItem === import.meta.env.VITE_STATUS_EXITED
? "red" ? "red"
: selectedItem === "Cancelled" : selectedItem === import.meta.env.VITE_STATUS_CANCELLED
? "orange" ? "orange"
: "purple" : "purple"
} }
@@ -154,24 +154,24 @@ const UpdateIOStatus = ({ isOpen, onClose, status }) => {
<Badge <Badge
rounded={"full"} rounded={"full"}
pt={1.5} pt={1.5}
pb={1.5} pb={1.5}
ps={4} ps={4}
pe={4} pe={4}
mt={1.5} mt={1.5}
mb={1.5} mb={1.5}
textTransform={"none"} textTransform={"none"}
colorScheme={ colorScheme={
statusAdmin === "Draft" statusAdmin === import.meta.env.VITE_STATUS_DRAFT
? "gray" ? "gray"
: statusAdmin === "Processing" : statusAdmin === import.meta.env.VITE_STATUS_PROCESSING
? "yellow" ? "yellow"
: statusAdmin === "Open" : statusAdmin === import.meta.env.VITE_STATUS_OPEN
? "blue" ? "blue"
: statusAdmin === "Closed" : statusAdmin === import.meta.env.VITE_STATUS_CLOSED
? "green" ? "green"
: statusAdmin === "Exited" : statusAdmin === import.meta.env.VITE_STATUS_EXITED
? "red" ? "red"
: statusAdmin === "Cancelled" : statusAdmin === import.meta.env.VITE_STATUS_CANCELLED
? "orange" ? "orange"
: "purple" : "purple"
} }

View File

@@ -97,7 +97,6 @@ const ViewIOTable = () => {
skip: debouncedSearchTerm === "" && searchTerm !== "", // Skip if search is empty and it's not the initial request skip: debouncedSearchTerm === "" && searchTerm !== "", // Skip if search is empty and it's not the initial request
}); });
console.log(data);
// ===============================[ Table Header ] // ===============================[ Table Header ]
const tableHeadRow = [ const tableHeadRow = [
@@ -242,17 +241,17 @@ const ViewIOTable = () => {
textTransform={"none"} textTransform={"none"}
// variant={"solid"} // variant={"solid"}
colorScheme={ colorScheme={
item?.ioStatus?.statusAdmin === "Draft" item?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_DRAFT
? "gray" ? "gray"
: item?.ioStatus?.statusAdmin === "Processing" : item?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_PROCESSING
? "yellow" ? "yellow"
: item?.ioStatus?.statusAdmin === "Open" : item?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_OPEN
? "blue" ? "blue"
: item?.ioStatus?.statusAdmin === "Closed" : item?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_CLOSED
? "green" ? "green"
: item?.ioStatus?.statusAdmin === "Exited" : item?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_EXITED
? "red" ? "red"
: item?.ioStatus?.statusAdmin === "Canclled" : item?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_CANCELLED
? "orange" ? "orange"
: "purple" : "purple"
} }

View File

@@ -1,8 +1,6 @@
import { import {
Box, Box,
Button, Button,
Icon,
Input,
keyframes, keyframes,
Stack, Stack,
Tab, Tab,
@@ -10,40 +8,29 @@ import {
TabPanel, TabPanel,
TabPanels, TabPanels,
Tabs, Tabs,
Text, useDisclosure
useDisclosure,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { useContext, useState } from "react";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import GlobalStateContext from "../../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import { useContext, useEffect, useState } from "react";
import FormInputView from "../../../Components/FormInputView";
import { useForm } from "react-hook-form"; // assuming react-hook-form is used
import { OPACITY_ON_LOAD } from "../../../Layout/animations"; import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import { ArrowBackIcon, RepeatIcon } from "@chakra-ui/icons"; import InvestmentDocument from "../CreateIO/InvestmentDocument";
import CustomAlertDialog from "../../../Components/CustomAlertDialog"; import Investors from "../CreateIO/Investors";
import IOArtifacts from "../CreateIO/IOArtifacts";
import KeyMerits from "../CreateIO/KeyMerits";
import ViewIOdataHeader from "./ViewIOdataHeader"; import ViewIOdataHeader from "./ViewIOdataHeader";
import ViewIOdetails from "./ViewIOdetails"; import ViewIOdetails from "./ViewIOdetails";
import ViewIOdocs from "./ViewIOdocs";
import ViewKeyMerits from "./ViewKeyMerits";
import ViewIOartifacts from "./ViewIOartifacts";
import ViewInvestors from "./ViewInvestors";
import ViewIOcash from "./ViewIOcash";
import ViewIOnav from "./ViewIOnav";
import ViewDistribution from "./ViewDistribution";
import InvestmentDocument from "../CreateIO/InvestmentDocument";
import KeyMerits from "../CreateIO/KeyMerits";
import Investors from "../CreateIO/Investors";
import EditIO from "../EditIO/EditIO";
import IOArtifacts from "../CreateIO/IOArtifacts";
// import IOCashDetails from "../CreateIO/IOCashDetailsold"; // import IOCashDetails from "../CreateIO/IOCashDetailsold";
// import IONAVDetails from "../CreateIO/IONAVDetailsOld"; // import IONAVDetails from "../CreateIO/IONAVDetailsOld";
import { useGetIOByIdQuery, useGetIOprepopulateDataQuery } from "../../../Services/io.service"; import { GoDotFill } from "react-icons/go";
import UnderConstruction from "../../UnderConstruction"; import {
useGetIOByIdQuery,
useGetIOprepopulateDataQuery,
} from "../../../Services/io.service";
import Destribution from "../CreateIO/Destribution"; import Destribution from "../CreateIO/Destribution";
import IOCashDetails from "../CreateIO/IOCashDetails/IOCashDetails"; import IOCashDetails from "../CreateIO/IOCashDetails/IOCashDetails";
import IONAVDetails from "../CreateIO/IONAVDetails/IONAVDetails"; import IONAVDetails from "../CreateIO/IONAVDetails/IONAVDetails";
import IOTransaction from "../CreateIO/IOTransaction/IOTransaction"; import IOTransaction from "../CreateIO/IOTransaction/IOTransaction";
import { GoDotFill } from "react-icons/go";
const rotate = keyframes` const rotate = keyframes`
from { from {
@@ -69,7 +56,6 @@ const ViewIOdata = () => {
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const [isRefetchLoading, setIsRefetchLoading] = useState(false); const [isRefetchLoading, setIsRefetchLoading] = useState(false);
const { IODetails, setIODetails } = useContext(GlobalStateContext); const { IODetails, setIODetails } = useContext(GlobalStateContext);
console.log(IODetails?.isInvestedAmount);
const tabs = [ const tabs = [
{ label: "IO Details", content: <ViewIOdetails data={data?.data} /> }, { label: "IO Details", content: <ViewIOdetails data={data?.data} /> },
@@ -193,13 +179,19 @@ const ViewIOdata = () => {
cursor={"pointer"} cursor={"pointer"}
/> />
</Box> */} </Box> */}
<Stack position={"absolute"} right={1} bottom={1} direction="row" spacing={4}> <Stack
position={"absolute"}
right={1}
bottom={1}
direction="row"
spacing={4}
>
<Button <Button
isLoading={isRefetchLoading} isLoading={isRefetchLoading}
loadingText="Refresh" loadingText="Refresh"
colorScheme="forestGreen" colorScheme="forestGreen"
variant="solid" variant="solid"
size={'xs'} size={"xs"}
onClick={handleRefresh} onClick={handleRefresh}
fontWeight={400} fontWeight={400}
> >

View File

@@ -1,61 +1,59 @@
import { import {
Button, Badge,
Divider, Box,
HStack,
Icon,
Image, Image,
Menu, Menu,
MenuButton, MenuButton,
MenuItem, MenuItem,
MenuList, MenuList,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Portal,
Text, Text,
useDisclosure, useDisclosure,
MenuItemOption,
MenuGroup,
MenuOptionGroup,
MenuDivider,
Badge,
Box,
Icon,
HStack,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import header from "../../../assets/IOheader.png"; import { useContext, useRef } from "react";
import { GrGallery } from "react-icons/gr";
import { HiDotsVertical } from "react-icons/hi"; import { HiDotsVertical } from "react-icons/hi";
import { Link, useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import Loader01 from "../../../Components/Loaders/Loader01";
import ToastBox from "../../../Components/ToastBox";
import {
decryptString,
encryptString,
isMaker,
} from "../../../Constants/Constants";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import { useUpdateTransactionMutation } from "../../../Services/io.service";
import AmountInvested from "./HeaderModal/AmountInvested"; import AmountInvested from "./HeaderModal/AmountInvested";
import FeesExpenses from "./HeaderModal/FeesExpenses"; import Cancle from "./HeaderModal/Cancle";
import DistributionSponsor from "./HeaderModal/DistributionSponsor";
import DistributionInvestor from "./HeaderModal/DistributionInvestor"; import DistributionInvestor from "./HeaderModal/DistributionInvestor";
import DistributionSponsor from "./HeaderModal/DistributionSponsor";
import Exit from "./HeaderModal/Exit";
import FeesExpenses from "./HeaderModal/FeesExpenses";
import UpdateIONav from "./HeaderModal/UpdateIONav"; import UpdateIONav from "./HeaderModal/UpdateIONav";
import UpdateIOStatus from "./HeaderModal/UpdateIOStatus"; import UpdateIOStatus from "./HeaderModal/UpdateIOStatus";
import { useContext, useRef } from "react"; import { useAuthProfileQuery } from "../../../Services/token.serivce";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import Exit from "./HeaderModal/Exit";
import Cancle from "./HeaderModal/Cancle";
import { AddIcon } from "@chakra-ui/icons";
import { GrGallery } from "react-icons/gr";
import Loader01 from "../../../Components/Loaders/Loader01";
import { useUpdateTransactionMutation } from "../../../Services/io.service";
import ToastBox from "../../../Components/ToastBox";
import { encryptString } from "../../../Constants/Constants";
// import { formatCurrency } from "../../../Components/CurrencyInput"; // import { formatCurrency } from "../../../Components/CurrencyInput";
// import { removeTrailingZeros } from "../../../Constants/Constants"; // import { removeTrailingZeros } from "../../../Constants/Constants";
const ViewIOdataHeader = ({ data, isLoading }) => { const ViewIOdataHeader = ({ data, isLoading }) => {
const params = useParams() const params = useParams();
const toast = useToast(); const toast = useToast();
const id = params?.id const id = params?.id;
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const btnRef = useRef(); const btnRef = useRef();
const { IODetails, isIOloading } = useContext(GlobalStateContext); const { IODetails, isIOloading } = useContext(GlobalStateContext);
const { data: authProfile } = useAuthProfileQuery();
if (authProfile?.data?.role) {
localStorage.setItem("role", encryptString(authProfile.data.role));
} else {
console.warn("Role is undefined or null. Skipping localStorage update.");
}
const { const {
isOpen: isInvestmentOpen, isOpen: isInvestmentOpen,
onOpen: onInvestmentOpen, onOpen: onInvestmentOpen,
@@ -107,95 +105,83 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
fontSize: "0.875rem", fontSize: "0.875rem",
fontWeight: "400", fontWeight: "400",
}; };
const [updateTransaction] = useUpdateTransactionMutation();
console.log( const handleDistributionInvestors = async () => {
import.meta.env.VITE_IMAGE_URL +
IODetails?.artifactsImage?.[0]?.artifactPathName
);
const [updateTransaction] = useUpdateTransactionMutation()
const handleDistributionInvestors = async () =>{
try { try {
const res = await updateTransaction(id) const res = await updateTransaction(id);
if (res?.data) { if (res?.data) {
// toast({ // toast({
// render: () => ( // render: () => (
// <ToastBox status={"success"} message={res?.data?.message} /> // <ToastBox status={"success"} message={res?.data?.message} />
// ), // ),
// }); // });
// setIsLoading(false); // setIsLoading(false);
onDistInvestorOpen() onDistInvestorOpen();
} else if (res?.error) {
} else if (res?.error) { toast({
toast({ render: () => (
render: () => ( <ToastBox status={"error"} message={res?.error?.data?.message} />
<ToastBox status={"error"} message={res?.error?.data?.message} /> ),
), });
});
// setIsLoading(false); // setIsLoading(false);
} }
} catch (error) { } catch (error) {
console.log(error);
} }
} };
const handleExit = async () =>{ const handleExit = async () => {
try { try {
const res = await updateTransaction(id) const res = await updateTransaction(id);
if (res?.data) { if (res?.data) {
// toast({ // toast({
// render: () => ( // render: () => (
// <ToastBox status={"success"} message={res?.data?.message} /> // <ToastBox status={"success"} message={res?.data?.message} />
// ), // ),
// }); // });
// setIsLoading(false); // setIsLoading(false);
onExitOpen() onExitOpen();
} else if (res?.error) {
} else if (res?.error) { toast({
toast({ render: () => (
render: () => ( <ToastBox status={"error"} message={res?.error?.data?.message} />
<ToastBox status={"error"} message={res?.error?.data?.message} /> ),
), });
});
// setIsLoading(false); // setIsLoading(false);
} }
} catch (error) { } catch (error) {
console.log(error);
} }
} };
const handleInvestment = async () =>{ const handleInvestment = async () => {
try { try {
const res = await updateTransaction(id) const res = await updateTransaction(id);
if (res?.data) { if (res?.data) {
// toast({ // toast({
// render: () => ( // render: () => (
// <ToastBox status={"success"} message={res?.data?.message} /> // <ToastBox status={"success"} message={res?.data?.message} />
// ), // ),
// }); // });
// setIsLoading(false); // setIsLoading(false);
onInvestmentOpen() onInvestmentOpen();
} else if (res?.error) {
} else if (res?.error) { toast({
toast({ render: () => (
render: () => ( <ToastBox status={"error"} message={res?.error?.data?.message} />
<ToastBox status={"error"} message={res?.error?.data?.message} /> ),
), });
});
// setIsLoading(false); // setIsLoading(false);
} }
} catch (error) { } catch (error) {
console.log(error);
} }
} };
const menu = [ const menu = [
{ {
@@ -217,7 +203,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
id: 6, id: 6,
title: "Distribution To Investors", title: "Distribution To Investors",
onClickFunction: handleDistributionInvestors, onClickFunction: handleDistributionInvestors,
}, },
{ {
id: 5, id: 5,
title: "Update IO NAV", title: "Update IO NAV",
@@ -251,8 +237,8 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
apiTransactionTitles?.includes(item.id) apiTransactionTitles?.includes(item.id)
); );
const balanceAmount =
const balanceAmount = IODetails?.goalAmount - IODetails?.totalAmtInvestmentInUSD IODetails?.goalAmount - IODetails?.totalAmtInvestmentInUSD;
return IODetails?.investmentNameEnglish ? ( return IODetails?.investmentNameEnglish ? (
<Box <Box
@@ -261,19 +247,19 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
justifyContent={"space-between"} justifyContent={"space-between"}
gap={8} gap={8}
bg={ bg={
IODetails?.ioStatus?.statusAdmin === "Draft" IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_DRAFT
? "#EDF2F7" ? "#EDF2F7"
: IODetails?.ioStatus?.statusAdmin === "Processing" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_PROCESSING
? "#FEFBBF" ? "#FEFBBF"
: IODetails?.ioStatus?.statusAdmin === "Open" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_OPEN
? "#BEE2F8" ? "#BEE2F8"
: IODetails?.ioStatus?.statusAdmin === "Closed" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_CLOSED
? "#C6F6D5" ? "#C6F6D5"
: IODetails?.ioStatus?.statusAdmin === "Exited" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_EXITED
? "#FED7D7" ? "#FED7D7"
: IODetails?.ioStatus?.statusAdmin === "Cancelled" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_CANCELLED
? "#E9D8FD" ? "#E9D8FD"
: IODetails?.ioStatus?.statusAdmin === "DeActivate" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_DEACTIVATE
? "#E9D8FD" ? "#E9D8FD"
: null : null
} }
@@ -318,7 +304,6 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
</Box> </Box>
<Box> <Box>
<Box display={"flex"} gap={2} pb={1}> <Box display={"flex"} gap={2} pb={1}>
<Text <Text
as={"span"} as={"span"}
@@ -336,7 +321,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
</Text> </Text>
</Box> </Box>
<Box display={"flex"} gap={2} pb={1}> <Box display={"flex"} gap={2} pb={1}>
<Text <Text
as={"span"} as={"span"}
fontSize={"xs"} fontSize={"xs"}
@@ -353,7 +338,7 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
</Text> </Text>
</Box> </Box>
<Box display={"flex"} gap={2} pb={1}> <Box display={"flex"} gap={2} pb={1}>
<Text <Text
as={"span"} as={"span"}
fontSize={"xs"} fontSize={"xs"}
@@ -364,18 +349,13 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
IO ID :- IO ID :-
</Text> </Text>
<Text as={"span"} fontSize={"xs"} fontWeight={"500"}> <Text as={"span"} fontSize={"xs"} fontWeight={"500"}>
{IODetails?.io_id {IODetails?.io_id ? IODetails?.io_id : "---"}
? IODetails?.io_id
: "---"}
</Text> </Text>
</Box> </Box>
</Box> </Box>
</HStack> </HStack>
<Box gap={8} me={12} w={"220px"}>
<Box gap={8} me={12} w={"220px"}>
<Box display={"flex"} justifyContent={"space-between"} gap={2} pb={1}> <Box display={"flex"} justifyContent={"space-between"} gap={2} pb={1}>
<Text <Text
as={"span"} as={"span"}
@@ -405,10 +385,13 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
</Text> </Text>
<Text as={"span"} fontSize={"xs"} fontWeight={"500"}> <Text as={"span"} fontSize={"xs"} fontWeight={"500"}>
{/* {IODetails?.ioCash ? formatCurrency(removeTrailingZeros(IODetails?.ioCash)) : "00.00"} */} {/* {IODetails?.ioCash ? formatCurrency(removeTrailingZeros(IODetails?.ioCash)) : "00.00"} */}
{parseFloat(IODetails?.totalAmtInvestmentInUSD || 0).toLocaleString(undefined, { {parseFloat(IODetails?.totalAmtInvestmentInUSD || 0).toLocaleString(
minimumFractionDigits: 2, undefined,
maximumFractionDigits: 2, {
})} minimumFractionDigits: 2,
maximumFractionDigits: 2,
}
)}
</Text> </Text>
</Box> </Box>
@@ -449,17 +432,17 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
textTransform={"none"} textTransform={"none"}
// variant={"solid"} // variant={"solid"}
colorScheme={ colorScheme={
IODetails?.ioStatus?.statusAdmin === "Draft" IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_DRAFT
? "gray" ? "gray"
: IODetails?.ioStatus?.statusAdmin === "Processing" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_PROCESSING
? "yellow" ? "yellow"
: IODetails?.ioStatus?.statusAdmin === "Open" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_OPEN
? "blue" ? "blue"
: IODetails?.ioStatus?.statusAdmin === "Closed" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_CLOSED
? "green" ? "green"
: IODetails?.ioStatus?.statusAdmin === "Exited" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_EXITED
? "red" ? "red"
: IODetails?.ioStatus?.statusAdmin === "Cancelled" : IODetails?.ioStatus?.statusAdmin === import.meta.env.VITE_STATUS_CANCELLED
? "purple" ? "purple"
: "purple" : "purple"
} }
@@ -533,39 +516,41 @@ const ViewIOdataHeader = ({ data, isLoading }) => {
alignItems={"start"} alignItems={"start"}
height={"95px"} height={"95px"}
> >
{localStorage?.getItem("role") === encryptString(import.meta.env.VITE_VITE_MAKER) && <Menu> {isMaker() && (
<MenuButton <Menu>
className="link p-1 rounded-1 " <MenuButton
bg={"#fff"} className="link p-1 rounded-1 "
_hover={{ backgroundColor: "#fff !important" }} bg={"#fff"}
onClick={onOpen} _hover={{ backgroundColor: "#fff !important" }}
ref={btnRef} onClick={onOpen}
> ref={btnRef}
<HiDotsVertical className="rubix-text-dark fs-6" />
</MenuButton>
<MenuList fontSize={"sm"}>
<MenuItem
_hover={{
bg: "#fff",
}}
as={"span"}
fontWeight={600}
className="border-bottom"
> >
Tansaction <HiDotsVertical className="rubix-text-dark fs-6" />
</MenuItem> </MenuButton>
<MenuList fontSize={"sm"}>
{filteredMenu?.map(({ id, title, onClickFunction }) => (
<MenuItem <MenuItem
key={id} _hover={{
onClick={onClickFunction} bg: "#fff",
}}
as={"span"}
fontWeight={600}
className="border-bottom" className="border-bottom"
> >
{title} Tansaction
</MenuItem> </MenuItem>
))}
</MenuList> {filteredMenu?.map(({ id, title, onClickFunction }) => (
</Menu>} <MenuItem
key={id}
onClick={onClickFunction}
className="border-bottom"
>
{title}
</MenuItem>
))}
</MenuList>
</Menu>
)}
{/* Modals */} {/* Modals */}
<AmountInvested isOpen={isInvestmentOpen} onClose={onInvestmentClose} /> <AmountInvested isOpen={isInvestmentOpen} onClose={onInvestmentClose} />

View File

@@ -1,5 +1,5 @@
import { ViewIcon } from "@chakra-ui/icons";
import { import {
Avatar,
Badge, Badge,
Box, Box,
Button, Button,
@@ -11,23 +11,21 @@ import {
useDisclosure, useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useState, useRef } from "react"; import React, { useContext, useEffect, useRef, useState } from "react";
import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import NormalTable from "../../../Components/DataTable/NormalTable";
import { Link, Link as RouterLink, useNavigate } from "react-router-dom";
import {
ViewIcon,
} from "@chakra-ui/icons";
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";
import InvestmentDetailsEdit from "./InvestmentDetailsEdit";
import { useGetInvestorsQuery } from "../../../Services/investor.details.service";
import { TABLE_PAGINATION } from "../../../Constants/Paginations";
import { exportToExcel, exportToExcelNew, generateSerialNumber } from "../../../Constants/Constants";
import { LuFileSpreadsheet } from "react-icons/lu"; import { LuFileSpreadsheet } from "react-icons/lu";
import { useNavigate } from "react-router-dom";
import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import NormalTable from "../../../Components/DataTable/NormalTable";
import Pagination from "../../../Components/Pagination";
import {
exportToExcelNew,
generateSerialNumber,
} from "../../../Constants/Constants";
import { INVESTOR_TABLE_PAGINATION } from "../../../Constants/Paginations";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import { useGetInvestorsQuery } from "../../../Services/investor.details.service";
import InvestmentDetailsEdit from "./InvestmentDetailsEdit";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
@@ -49,10 +47,11 @@ const InvestorDetails = () => {
} = useDisclosure(); } = useDisclosure();
const btnRef = React.useRef(); const btnRef = React.useRef();
// =========================== [Use State] =============================
// =========================== [Use State] ============================= const [pageSize, setPageSize] = useState(INVESTOR_TABLE_PAGINATION?.size);
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size); const [currentPage, setCurrentPage] = useState(
const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page); INVESTOR_TABLE_PAGINATION?.page
);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(""); const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
@@ -73,20 +72,19 @@ const InvestorDetails = () => {
data: investorDetails, data: investorDetails,
isLoading: investorDetailsLoading, isLoading: investorDetailsLoading,
error, error,
} = useGetInvestorsQuery({ } = useGetInvestorsQuery(
page: debouncedSearchTerm ? undefined : currentPage, // Omit pagination for search {
size: debouncedSearchTerm ? undefined : pageSize, // Omit pagination for search userStatus KYCStatus investorType_xid page: debouncedSearchTerm ? undefined : currentPage, // Omit pagination for search
search: debouncedSearchTerm, size: debouncedSearchTerm ? undefined : pageSize, // Omit pagination for search userStatus KYCStatus investorType_xid
userStatus: status, search: debouncedSearchTerm,
KYCStatus: kyc, userStatus: status,
country_xid: country KYCStatus: kyc,
country_xid: country,
}, },
{ {
skip: debouncedSearchTerm === "" && searchTerm !== "", // Skip if search is empty and it's not the initial request skip: debouncedSearchTerm === "" && searchTerm !== "", // Skip if search is empty and it's not the initial request
} }
); );
useEffect(() => { useEffect(() => {
// Simulate loading // Simulate loading
@@ -104,43 +102,41 @@ const InvestorDetails = () => {
"Client ID", "Client ID",
"First Name", "First Name",
"Last Name", "Last Name",
"Country", "Country",
"Phone Number", "Phone Number",
"E-mail ID", "E-mail ID",
"Type", "Type",
"KYC Status", "KYC Status",
"Status", "Status",
"Action", "Action",
]; ];
// ====================================================[Table Filter]================================================================ // ====================================================[Table Filter]================================================================
const exportInvestor = investorDetails?.data?.rows?.map((item, idx) => ({ const exportInvestor = investorDetails?.data?.rows?.map((item, idx) => ({
"Id": parseInt(item?.id, 10) || item?.id, // Convert to integer, fallback to string if conversion fails Id: parseInt(item?.id, 10) || item?.id, // Convert to integer, fallback to string if conversion fails
"Client ID": item?.clientReference_id, // This is likely a string "Client ID": item?.clientReference_id, // This is likely a string
"First Name": item?.principal?.firstName, "First Name": item?.principal?.firstName,
"Last Name": item?.principal?.lastName, "Last Name": item?.principal?.lastName,
"Country": item?.country?.countryName, Country: item?.country?.countryName,
"Phone Number": item?.principal?.mobileNumber, // Skipping integer conversion, as this is likely a string "Phone Number": item?.principal?.mobileNumber, // Skipping integer conversion, as this is likely a string
"E-mail ID": item?.principal?.emailAddress, "E-mail ID": item?.principal?.emailAddress,
"Type": item?.investor_type?.investorTypeName, Type: item?.investor_type?.investorTypeName,
"Status": item.ioStatus ? "Ban" : "Unban", Status: item.ioStatus ? "Ban" : "Unban",
"KYC Status": item.KYCStatus ? "Completed" : "Not complete" "KYC Status": item.KYCStatus ? "Completed" : "Not complete",
})); }));
const extractedArray = investorDetails?.data?.rows?.map((item, idx) => ({ const extractedArray = investorDetails?.data?.rows?.map((item, idx) => ({
id: item?.id, id: item?.id,
"Sr No": ( "Sr No": (
<Text <Text
w={'24px'} w={"24px"}
justifyContent={slideFromRight ? "right" : "left"} justifyContent={slideFromRight ? "right" : "left"}
as={"span"} as={"span"}
color={"gray.600"} color={"gray.600"}
className="d-flex align-items-center fw-bold web-text-small" className="d-flex align-items-center fw-bold web-text-small"
> >
{/* {item.id} */} {/* {item.id} */}
{generateSerialNumber(idx,currentPage, pageSize )} {generateSerialNumber(idx, currentPage, pageSize)}
</Text> </Text>
), ),
"Client ID": ( "Client ID": (
@@ -148,7 +144,7 @@ const InvestorDetails = () => {
<Text as={"span"} color={"teal.900"}> <Text as={"span"} color={"teal.900"}>
{item.clientReference_id} {item.clientReference_id}
</Text> </Text>
</Box> </Box>
), ),
"First Name": ( "First Name": (
<Box w={"auto"} isTruncated={true}> <Box w={"auto"} isTruncated={true}>
@@ -185,39 +181,44 @@ const InvestorDetails = () => {
</Text> </Text>
</Box> </Box>
), ),
"Type": ( Type: (
<Box w={"auto"} isTruncated={true}> <Box w={"auto"} isTruncated={true}>
<Text as={"span"} > <Text as={"span"}>
<Badge color={"forestGreen.500"} variant={'ghost'} fontWeight={"700"} px={2} py={0.5}> <Badge
color={"forestGreen.500"}
variant={"ghost"}
fontWeight={"700"}
px={2}
py={0.5}
>
{item?.investor_type?.investorTypeName} {item?.investor_type?.investorTypeName}
</Badge> </Badge>
</Text> </Text>
</Box> </Box>
), ),
Status: ( Status: (
<Box w={"auto"} isTruncated={true}> <Box w={"auto"} isTruncated={true}>
<Badge <Badge
fontWeight={"700"} fontWeight={"700"}
textTransform={"none"} textTransform={"none"}
colorScheme={item.ioStatus ? "red" : "green"} colorScheme={item.ioStatus ? "red" : "green"}
px={2} px={2}
py={0.5} py={0.5}
> >
{item.ioStatus ? "Ban" : "Unban"} {item.ioStatus ? "Ban" : "Unban"}
</Badge> </Badge>
</Box> </Box>
), ),
"KYC Status": ( "KYC Status": (
<Box w={"auto"} display={'flex'} alignItems={'center'} isTruncated={true}> <Box w={"auto"} display={"flex"} alignItems={"center"} isTruncated={true}>
<Text <Text
as={'span'} as={"span"}
fontWeight={"700"} fontWeight={"700"}
textTransform={"none"} textTransform={"none"}
color={item?.KYCStatus === true ? "green" : "yellow.500"} color={item?.KYCStatus === true ? "green" : "yellow.500"}
px={2} px={2}
py={0.5} py={0.5}
variant={'solid'} variant={"solid"}
> >
{/* {item.KYCStatus ? "Completed" : "Not complete"} */} {/* {item.KYCStatus ? "Completed" : "Not complete"} */}
{item?.KYCStatus === true ? "Completed" : "NotCompleted"} {item?.KYCStatus === true ? "Completed" : "NotCompleted"}
@@ -235,7 +236,7 @@ const InvestorDetails = () => {
placement="top" placement="top"
> >
<Button <Button
isDisabled={item.ioStatus} isDisabled={item.ioStatus}
onClick={() => { onClick={() => {
navigate(`/investor-details/profile-view/${item.id}`); navigate(`/investor-details/profile-view/${item.id}`);
}} }}
@@ -266,7 +267,6 @@ const InvestorDetails = () => {
setIsLoading(true); setIsLoading(true);
}; };
return ( return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}> <Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
<Box bg="white.500"> <Box bg="white.500">
@@ -346,35 +346,29 @@ const InvestorDetails = () => {
</Select> </Select>
<Pagination <Pagination
isLoading={investorDetailsLoading} isLoading={investorDetailsLoading}
pageSize={pageSize} pageSize={pageSize}
setPageSize={setPageSize} setPageSize={setPageSize}
currentPage={currentPage} currentPage={currentPage}
setCurrentPage={setCurrentPage} setCurrentPage={setCurrentPage}
totalItems={investorDetails?.data?.totalItems} totalItems={investorDetails?.data?.totalItems}
/> />
</HStack> </HStack>
<Button <Button
onClick={() => onClick={() => exportToExcelNew(exportInvestor, "Investor Details")}
exportToExcelNew(exportInvestor, "Investor Details") leftIcon={<LuFileSpreadsheet />}
} colorScheme="forestGreen"
leftIcon={<LuFileSpreadsheet />} size={"sm"}
colorScheme="forestGreen" variant={"outline"}
size={"sm"} rounded={"sm"}
variant={"outline"} fontSize={"xs"}
rounded={"sm"} w={100}
fontSize={"xs"} me={2}
w={100} isDisabled={exportInvestor?.length === 0}
me={2} >
Export xls
isDisabled={exportInvestor?.length === 0} </Button>
>
Export xls
</Button>
</HStack> </HStack>
<InvestmentDetailsEdit <InvestmentDetailsEdit
id={actionId} id={actionId}

View File

@@ -245,7 +245,7 @@ const Login = () => {
)} )}
</FormControl> </FormControl>
<Box fontSize={"sm"} display={"flex"} justifyContent={"end"} mt={0}> <Box fontSize={"sm"} display={"flex"} justifyContent={"end"} mt={0}>
<Text fontWeight={500} cursor={"pointer"} onClick={onOpen}>Forget Password?</Text> <Text fontWeight={500} cursor={"pointer"} onClick={onOpen}>Forgot Password?</Text>
</Box> </Box>
<Button <Button

View File

@@ -316,7 +316,7 @@ const AddInvestmentType = () => {
<Box display={"flex"} justifyContent={"space-between"} alignItems={"center"} mt={5} px={4} mb={5}> <Box display={"flex"} justifyContent={"space-between"} alignItems={"center"} mt={5} px={4} mb={5}>
<Text fontSize={"sm"} mb={0} onClick={() => navigate(-1)} cursor={"pointer"}> <Text fontSize={"sm"} mb={0} onClick={() => navigate(-1)} cursor={"pointer"}>
<ArrowBackIcon fontSize={"xl"} me={2} />Add Details <ArrowBackIcon fontSize={"xl"} me={2} />{params?.id ? "Edit Details" : "Add Details"}
</Text> </Text>
<SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} /> <SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} />
</Box> </Box>

View File

@@ -301,7 +301,7 @@ const AddSponser = () => {
{/* ===================== [Switch Button] ======================== */} {/* ===================== [Switch Button] ======================== */}
<Box display={"flex"} justifyContent={"space-between"} alignItems={"center"} mt={5} px={4}> <Box display={"flex"} justifyContent={"space-between"} alignItems={"center"} mt={5} px={4}>
<Text fontSize={"sm"} mb={0} onClick={() => navigate(-1)} cursor={"pointer"}> <Text fontSize={"sm"} mb={0} onClick={() => navigate(-1)} cursor={"pointer"}>
<ArrowBackIcon fontSize={"xl"} me={2} />Add Details <ArrowBackIcon fontSize={"xl"} me={2} />{params?.id ? "Edit Details" : "Add Details"}
</Text> </Text>
<SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} /> <SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} />
</Box> </Box>

View File

@@ -1,26 +1,21 @@
import { CheckIcon, CloseIcon, InfoIcon } from "@chakra-ui/icons";
import { import {
Avatar, Avatar,
Box, Box,
ButtonGroup, ButtonGroup,
Editable,
EditableInput,
EditablePreview,
EditableTextarea,
Flex,
HStack, HStack,
Heading, Heading,
Icon, Icon,
IconButton, IconButton,
Input,
Text, Text,
VStack, VStack,
useEditableControls, useEditableControls
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React from "react"; import React, { useEffect, useState } from "react";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import { CheckIcon, CloseIcon, EditIcon, InfoIcon } from "@chakra-ui/icons";
import { FaEarthAmericas } from "react-icons/fa6"; import { FaEarthAmericas } from "react-icons/fa6";
import logoMini from "../../assets/propic.png"; import logoMini from "../../assets/propic.png";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import { useAuthProfileQuery } from "../../Services/token.serivce";
const Profile = () => { const Profile = () => {
/* Here's a custom control */ /* Here's a custom control */
@@ -53,19 +48,56 @@ const Profile = () => {
) )
); );
} }
const { data } = useAuthProfileQuery();
const [fields, setFields] = useState([
// Array of fields to render {
const fields = [ name: "firstName",
{ name: "firstName", label: "First Name", defaultValue: "Faisal" }, label: "First Name",
{ name: "lastName", label: "Last Name", defaultValue: "Aljalahma" }, defaultValue: null,
{ name: "email", label: "Email Address", defaultValue: "f.aljalahma@tanamicapital.com" }, },
{ name: "mobile", label: "Mobile Number", defaultValue: "9898767876" }, {
{ name: "role", label: "Role", defaultValue: "Maker" }, name: "lastName",
]; label: "Last Name",
defaultValue: null,
},
{
name: "email",
label: "Email Address",
defaultValue: null,
},
{
name: "mobile",
label: "Mobile Number",
defaultValue: null,
},
{ name: "role", label: "Role", defaultValue: null },
]);
useEffect(() => {
setFields([
{
name: "firstName",
label: "First Name",
defaultValue: data?.data?.firstName || null,
},
{
name: "lastName",
label: "Last Name",
defaultValue: data?.data?.lastName || null,
},
{
name: "email",
label: "Email Address",
defaultValue: data?.data?.emailAddress || null,
},
{
name: "mobile",
label: "Mobile Number",
defaultValue: data?.data?.mobileNumber || null,
},
{ name: "role", label: "Role", defaultValue: data?.data?.role || null },
]);
}, [data]);
return ( return (
<VStack <VStack
@@ -114,7 +146,7 @@ const Profile = () => {
color={"gray.700"} color={"gray.700"}
fontWeight={500} fontWeight={500}
> >
Faisal Aljalahma {data?.data?.firstName + " " + data?.data?.lastName}
</Text> </Text>
<Text <Text
@@ -123,7 +155,7 @@ const Profile = () => {
color={"gray.500"} color={"gray.500"}
fontWeight={400} fontWeight={400}
> >
f.aljalahma@tanamicapital.com {data?.data?.emailAddress}
</Text> </Text>
</VStack> </VStack>
</HStack> </HStack>
@@ -150,16 +182,16 @@ const Profile = () => {
fontWeight={500} fontWeight={500}
> >
{" "} {" "}
<Icon as={FaEarthAmericas} /> Maker <Icon as={FaEarthAmericas} /> {data?.data?.role}
</Text> </Text>
</VStack> </VStack>
</HStack> </HStack>
</Box> </Box>
{/*
<Heading as="h3" size="sm"> <Heading as="h3" size="sm">
About you About you
</Heading> </Heading>
<Box <Box
rounded="md" rounded="md"
boxShadow="base" boxShadow="base"
@@ -170,55 +202,56 @@ const Profile = () => {
alignItems="flex-start" alignItems="flex-start"
p={6} p={6}
gap={0} gap={0}
pb={6} pb={6}
> >
{fields?.map((item) => (
{fields?.map((item) => ( <VStack
<VStack alignItems={"flex-start"} w={"100%"} gap={1.5} mb={6} key={item?.label}> alignItems={"flex-start"}
<Text w={"100%"}
as={"span"} gap={1.5}
fontSize="xs" mb={6}
fontWeight="semibold" key={item?.label}
color={"gray.500"} >
> <Text
{item?.label} as={"span"}
</Text> fontSize="xs"
<Editable fontWeight="semibold"
position={"relative"} color={"gray.500"}
gap={0} >
defaultValue={item?.defaultValue} {item?.label}
w="100%" </Text>
> <Editable
<EditablePreview position={"relative"}
cursor={'pointer'} gap={0}
p={2} defaultValue={item?.defaultValue}
rounded={"sm"} w="100%"
w={"100%"} >
_hover={{ <EditablePreview
bg: "gray.100", cursor={"pointer"}
}} p={2}
fontSize="sm" rounded={"sm"}
transition={"0.5s"} w={"100%"}
/> _hover={{
<Input bg: "gray.100",
as={EditableInput} }}
ps={2} fontSize="sm"
size={'sm'} transition={"0.5s"}
fontSize="sm" />
rounded={"sm"} <Input
_focus={{ as={EditableInput}
borderColor:"blue.500" ps={2}
}} size={"sm"}
/> fontSize="sm"
<EditableControls /> rounded={"sm"}
</Editable> _focus={{
</VStack> borderColor: "blue.500",
))} }}
/>
<EditableControls />
</Editable>
</Box> </VStack>
))}
</Box> */}
</VStack> </VStack>
</VStack> </VStack>
); );

View File

@@ -1,3 +1,4 @@
import { AddIcon, DeleteIcon, EditIcon } from "@chakra-ui/icons";
import { import {
Badge, Badge,
Box, Box,
@@ -9,24 +10,24 @@ import {
Tooltip, Tooltip,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useState } from "react";
import { Link, Link as RouterLink } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { AddIcon, DeleteIcon, EditIcon } from "@chakra-ui/icons";
import { useNavigate } from "react-router-dom";
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 CustomAlertDialog from "../../Components/CustomAlertDialog";
import NormalTable from "../../Components/DataTable/NormalTable";
import ToastBox from "../../Components/ToastBox"; import ToastBox from "../../Components/ToastBox";
import { TABLE_PAGINATION } from "../../Constants/Paginations";
import { generateSerialNumber } from "../../Constants/Constants";
import { useGetSponserMasterQuery } from "../../Services/io.service";
import { import {
CHECKER_ID,
generateSerialNumber,
MAKER_ID,
SUPER_ADMIN_ID,
} from "../../Constants/Constants";
import GlobalStateContext from "../../Contexts/GlobalStateContext";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import {
useDeleteUserMutation,
useGetSubAdminMasterQuery, useGetSubAdminMasterQuery,
useToggleStatusMutation, useToggleStatusMutation,
} from "../../Services/subadmin.service"; } from "../../Services/subadmin.service";
import RoleSwitchButton from "../../Components/RoleSwitchButton";
export const formatDate = (date) => { export const formatDate = (date) => {
const d = new Date(date); const d = new Date(date);
@@ -46,31 +47,28 @@ const SubAdmin = () => {
const [mouseEntered, setMouseEntered] = useState(false); const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState(""); const [mouseEnteredId, setMouseEnteredId] = useState("");
// const [deleteSponser] = useDeleteSponserMutation(); // const [deleteSponser] = useDeleteSponserMutation();
const { sponser, setSponser, slideFromRight } = const { slideFromRight } = useContext(GlobalStateContext);
useContext(GlobalStateContext);
// =========================== [Use State] ============================= // =========================== [Use State] =============================
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size); // const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page); // const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(""); // const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
const [isSwitchOn, setIsSwitchOn] = useState(true);
// Debounce the search term to avoid making a request on every keystroke // Debounce the search term to avoid making a request on every keystroke
useEffect(() => { // useEffect(() => {
const handler = setTimeout(() => { // const handler = setTimeout(() => {
setDebouncedSearchTerm(searchTerm); // setDebouncedSearchTerm(searchTerm);
}, 500); // Adjust delay as needed // }, 500); // Adjust delay as needed
return () => { // return () => {
clearTimeout(handler); // clearTimeout(handler);
}; // };
}, [searchTerm]); // }, [searchTerm]);
const { const { data: subAdmin, isLoading: isSponserLoading } =
data: subAdmin, useGetSubAdminMasterQuery();
error,
isLoading: isSponserLoading, const [deleteUser] = useDeleteUserMutation();
} = useGetSubAdminMasterQuery();
const [toggleStatus] = useToggleStatusMutation(); const [toggleStatus] = useToggleStatusMutation();
@@ -91,13 +89,13 @@ const SubAdmin = () => {
}); });
const handleToggleStatus = async (isMaker, id) => { const handleToggleStatus = async (isMaker, id) => {
console.log("hit"); // console.log("hit");
const data = { const data = {
role_xid: isMaker ? "2" : "1", role_xid: isMaker ? CHECKER_ID : MAKER_ID,
}; };
console.log("=======================",data) console.log("=======================", data);
try { try {
const res = await toggleStatus({id, data}); const res = await toggleStatus({ id, data });
if (res?.error) { if (res?.error) {
toast({ toast({
render: () => ( render: () => (
@@ -137,7 +135,7 @@ const SubAdmin = () => {
"Action", "Action",
]; ];
const extractedArray = subAdmin?.data?.map((item, index) => ({ const extractedArray = filteredData?.map((item, index) => ({
"Sr No": ( "Sr No": (
<Text <Text
w={"24px"} w={"24px"}
@@ -147,7 +145,7 @@ const SubAdmin = () => {
className="d-flex align-items-center fw-bold web-text-small" className="d-flex align-items-center fw-bold web-text-small"
> >
{/* {item.id} */} {/* {item.id} */}
{generateSerialNumber(index, currentPage, pageSize)} {generateSerialNumber(index)}
</Text> </Text>
), ),
"First Name": ( "First Name": (
@@ -180,17 +178,17 @@ const SubAdmin = () => {
</Box> </Box>
), ),
Role: ( Role: (
<Box isTruncated={true} > <Box isTruncated={true}>
<Badge <Badge
py={"2px"} py={"2px"}
me={2} me={2}
fontWeight={600} fontWeight={600}
bg={item?.role[0]?.role === "Maker" ? "#00ffcc" : "#b3ff99"} bg={item?.role[0]?.role === "Maker" ? "#00ffcc" : "#b3ff99"}
px={item?.role[0]?.role === "Maker" ? "12px" : "5px"} px={item?.role[0]?.role === "Maker" ? "12px" : "5px"}
> >
{item?.role[0]?.role} {item?.role[0]?.role}
</Badge> </Badge>
<Switch {/* <Switch
onChange={() => onChange={() =>
handleToggleStatus(item?.role[0]?.role === "Maker", item?.id) handleToggleStatus(item?.role[0]?.role === "Maker", item?.id)
} }
@@ -201,7 +199,7 @@ const SubAdmin = () => {
bg: item?.role[0]?.role === "Maker" ? "#00ffcc" : "#b3ff99", // "Off" state color bg: item?.role[0]?.role === "Maker" ? "#00ffcc" : "#b3ff99", // "Off" state color
}, },
}} }}
/> /> */}
{/* <RoleSwitchButton {/* <RoleSwitchButton
setIsSwitchOn={setIsSwitchOn} setIsSwitchOn={setIsSwitchOn}
isSwitchOn={item?.role[0]?.role === "Maker"} isSwitchOn={item?.role[0]?.role === "Maker"}
@@ -231,7 +229,7 @@ const SubAdmin = () => {
</Button> </Button>
</Tooltip> </Tooltip>
{/* <Tooltip <Tooltip
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} fontSize={"xs"}
label="Delete" label="Delete"
@@ -240,12 +238,14 @@ const SubAdmin = () => {
placement="top" placement="top"
> >
<Button <Button
isDisabled={item?.id === SUPER_ADMIN_ID}
onClick={() => { onClick={() => {
setActionId(item?.id); setActionId(item?.id);
setDeleteAlert(true); setDeleteAlert(true);
}} }}
// _hover={{ color: "red.500" }} // _hover={{ color: "red.500" }}
// color="red" // color="red"
// disabled={true}
rounded={"sm"} rounded={"sm"}
size={"xs"} size={"xs"}
colorScheme="red" colorScheme="red"
@@ -253,46 +253,42 @@ const SubAdmin = () => {
> >
<DeleteIcon /> <DeleteIcon />
</Button> </Button>
</Tooltip> */} </Tooltip>
</Box> </Box>
), ),
})); }));
// =========================== [ Delete Function ] ================================= // =========================== [ Delete Function ] =================================
// const handleDelete = async () => { const handleDelete = async () => {
// console.log(actionId); setIsLoading(true);
// setIsLoading(true); try {
// try { const response = await deleteUser(actionId);
// const response = await deleteSponser(actionId); if (response?.error?.data?.code === 400) {
// console.log(response?.data); toast({
// if (response?.error?.data?.code === 400) { render: () => (
// toast({ <ToastBox
// render: () => ( message={response?.error?.data?.message}
// <ToastBox status={"error"}
// message={response?.error?.data?.message} />
// status={"error"} ),
// /> });
// ), setIsLoading(false);
// }); setDeleteAlert(false);
// setIsLoading(false); } else if (
// setDeleteAlert(false); response?.data?.statusCode === 201 ||
// } else if ( response?.data?.statusCode === 200
// response?.data?.statusCode === 201 || ) {
// response?.data?.statusCode === 200 toast({
// ) { render: () => (
// toast({ <ToastBox message={response?.data?.message} status={"success"} />
// render: () => ( ),
// <ToastBox message={response?.data?.message} status={"success"} /> });
// ), setIsLoading(false);
// }); setDeleteAlert(false);
// setIsLoading(false); }
// setDeleteAlert(false); } catch (error) {}
// } };
// } catch (error) {}
// };
console.log(isSponserLoading);
return ( return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}> <Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
@@ -322,14 +318,14 @@ const SubAdmin = () => {
<HStack display={"flex"} alignItems={"center"}> <HStack display={"flex"} alignItems={"center"}>
{/* ====================[Pagination]===================== */} {/* ====================[Pagination]===================== */}
<Pagination {/* <Pagination
isLoading={isSponserLoading} isLoading={isSponserLoading}
pageSize={pageSize} pageSize={pageSize}
setPageSize={setPageSize} setPageSize={setPageSize}
currentPage={currentPage} currentPage={currentPage}
setCurrentPage={setCurrentPage} setCurrentPage={setCurrentPage}
totalItems={subAdmin?.data?.totalItems} totalItems={subAdmin?.data?.totalItems}
/> /> */}
{/* =====================[Add Button]===================== */} {/* =====================[Add Button]===================== */}
@@ -366,8 +362,8 @@ const SubAdmin = () => {
<CustomAlertDialog <CustomAlertDialog
onClose={() => setDeleteAlert(false)} onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert} isOpen={deleteAlert}
message={"Are you sure you want to delete sponers?"} message={"Are you sure you want to delete sub-admin?"}
// alertHandler={handleDelete} alertHandler={handleDelete}
isLoading={isLoading} isLoading={isLoading}
/> />
</Box> </Box>

View File

@@ -1,42 +1,42 @@
import React, { useContext, useEffect, useState } from "react";
import { Box, Button, Text, useToast } from "@chakra-ui/react";
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { useNavigate, useParams } from "react-router-dom";
import { v4 as uuidv4 } from "uuid";
import { ArrowBackIcon } from "@chakra-ui/icons"; import { ArrowBackIcon } from "@chakra-ui/icons";
import { OPACITY_ON_LOAD } from "../../Layout/animations"; import { Box, Text, useToast } from "@chakra-ui/react";
import FormInputMain from "../../Components/FormInputMain"; import { yupResolver } from "@hookform/resolvers/yup";
import ToastBox from "../../Components/ToastBox"; import React, { useEffect, useState } from "react";
import FullscreenLoaders from "../../Components/Loaders/FullscreenLoaders"; import { useForm } from "react-hook-form";
import { useNavigate, useParams } from "react-router-dom";
import * as yup from "yup";
import CustomAlertDialog from "../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../Components/CustomAlertDialog";
import FormInputMain from "../../Components/FormInputMain";
import FullscreenLoaders from "../../Components/Loaders/FullscreenLoaders";
import RoleSwitchButton from "../../Components/RoleSwitchButton"; import RoleSwitchButton from "../../Components/RoleSwitchButton";
import ToastBox from "../../Components/ToastBox";
import {
isMaker
} from "../../Constants/Constants";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import { import {
useCreateSubAdminMutation, useCreateSubAdminMutation,
useGetSubAdminByIdQuery, useGetSubAdminByIdQuery,
useUpdateSubAdminMutation, useUpdateSubAdminMutation,
} from "../../Services/subadmin.service"; } from "../../Services/subadmin.service";
import { useGetSponserByIdQuery } from "../../Services/io.service";
import { encryptString } from "../../Constants/Constants";
// ======================= [validation] ========================= // ======================= [validation] =========================
const addSubAdminSchema = yup.object().shape({
export const addSubAdmin = yup.object().shape({
firstName: yup firstName: yup
.string() .string()
.required("First Name is required") .required("First Name is required")
.min(3, "First Name must be at least 3 characters long") .min(3, "First Name must be at least 3 characters long")
.max(50, "First Name cannot exceed 50 characters") .max(35, "First Name cannot exceed 35 characters")
.matches(/^[^\d]+$/, "First Name cannot contain numbers"), .matches(/^[^\d]+$/, "First Name cannot contain numbers"),
lastName: yup.string().required("Last Name name in arabic is required"), lastName: yup.string().required("Last Name is required")
emailAddress: yup.string().email("Invalid email address").notRequired(), .min(3, "Last Name must be at least 3 characters long")
// .test("emailValidity", "Email address is invalid", async function (value) { .max(35, "Last Name cannot exceed 35 characters")
// if (!value) { .matches(/^[^\d]+$/, "Last Name cannot contain numbers"),
// return true; // Allow if the field is empty emailAddress:yup.
// } string()
// return await checkEmailValidity(value); .required("Email address is required")
// }), .min(6, "Email address must be at least 6 characters long")
.max(255, "Email address can be at most 255 characters long"),
}); });
// ==================== [debounce] ======================== // ==================== [debounce] ========================
@@ -60,17 +60,15 @@ const SubAdminUpdateCreate = () => {
const [isLoadingBtn, setIsLoadingBtn] = useState(false); const [isLoadingBtn, setIsLoadingBtn] = useState(false);
const [alert, setAlert] = useState(false); const [alert, setAlert] = useState(false);
const [form, setForm] = useState(); const [form, setForm] = useState();
const [isSwitchOn, setIsSwitchOn] = useState(true); const [isSwitchOn, setIsSwitchOn] = useState(false);
const [createSubAdmin] = useCreateSubAdminMutation(); const [createSubAdmin] = useCreateSubAdminMutation();
const [updateSubAdmin] = useUpdateSubAdminMutation(); const [updateSubAdmin] = useUpdateSubAdminMutation();
// Fetch sponsor data only if id exists // Fetch sponsor data only if id exists
const { const { data: subAdminByIdData, isLoading } = useGetSubAdminByIdQuery(id, {
data: subAdminByIdData, skip: !id,
error, });
isLoading,
} = useGetSubAdminByIdQuery(id, { skip: !id });
// ======================== [validators] =========================== // ======================== [validators] ===========================
@@ -81,7 +79,8 @@ const SubAdminUpdateCreate = () => {
formState: { errors }, formState: { errors },
reset, reset,
} = useForm({ } = useForm({
resolver: yupResolver(addSubAdmin), resolver: yupResolver(addSubAdminSchema),
mode: "all",
}); });
// ========================== [useEffect] ================================ // ========================== [useEffect] ================================
@@ -93,15 +92,11 @@ const SubAdminUpdateCreate = () => {
lastName: subAdminByIdData?.data?.lastName, lastName: subAdminByIdData?.data?.lastName,
emailAddress: subAdminByIdData?.data?.emailAddress, emailAddress: subAdminByIdData?.data?.emailAddress,
}); });
setIsSwitchOn( setIsSwitchOn(isMaker(subAdminByIdData?.data?.role[0]?.role));
subAdminByIdData?.data?.role[0]?.role ===
encryptString(import.meta.env.VITE_VITE_MAKER)
);
console.log(subAdminByIdData?.data?.role);
} }
}, [subAdminByIdData, reset]); }, [subAdminByIdData, reset]);
if (false) { if (isLoading) {
return <FullscreenLoaders />; return <FullscreenLoaders />;
} }
@@ -116,7 +111,7 @@ const SubAdminUpdateCreate = () => {
try { try {
const formData = { const formData = {
...form, ...form,
// role_xid: !isSwitchOn ? 1 : 2, role_xid: !isSwitchOn ? 2 : 1,
}; };
await updateSubAdmin({ data: formData, id }).then((response) => { await updateSubAdmin({ data: formData, id }).then((response) => {
if (response?.data?.statusCode) { if (response?.data?.statusCode) {
@@ -194,8 +189,8 @@ const SubAdminUpdateCreate = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "", section: "",
maxLength: 50, maxLength: 35,
helperText: `Maximum length should be 50 characters. You have entered ${ helperText: `Maximum length should be 35 characters. You have entered ${
watch()?.firstName?.length || 0 watch()?.firstName?.length || 0
} characters.`, } characters.`,
}, },
@@ -206,8 +201,8 @@ const SubAdminUpdateCreate = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "", section: "",
maxLength: 55, maxLength: 35,
helperText: `Maximum length should be 55 characters. You have entered ${ helperText: `Maximum length should be 35 characters. You have entered ${
watch()?.lastName?.length || 0 watch()?.lastName?.length || 0
} characters.`, } characters.`,
}, },
@@ -216,7 +211,7 @@ const SubAdminUpdateCreate = () => {
name: "emailAddress", name: "emailAddress",
placeHolder: " ", placeHolder: " ",
type: "email", type: "email",
// isRequired: true, isRequired: true,
section: "", section: "",
}, },
]; ];
@@ -231,8 +226,8 @@ const SubAdminUpdateCreate = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "", section: "",
maxLength: 55, maxLength: 35,
helperText: `Maximum length should be 55 characters. You have entered ${ helperText: `Maximum length should be 35 characters. You have entered ${
watch()?.firstName?.length || 0 watch()?.firstName?.length || 0
} characters.`, } characters.`,
}, },
@@ -243,8 +238,8 @@ const SubAdminUpdateCreate = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "", section: "",
maxLength: 55, maxLength: 35,
helperText: `Maximum length should be 55 characters. You have entered ${ helperText: `Maximum length should be 35 characters. You have entered ${
watch()?.lastName?.length || 0 watch()?.lastName?.length || 0
} characters.`, } characters.`,
}, },
@@ -253,7 +248,7 @@ const SubAdminUpdateCreate = () => {
name: "emailAddress", name: "emailAddress",
placeHolder: " ", placeHolder: " ",
type: "email", type: "email",
// isRequired: true, isRequired: true,
section: "", section: "",
}, },
]; ];
@@ -281,7 +276,7 @@ const SubAdminUpdateCreate = () => {
}, {}); }, {});
// ==================== [On Submit] ======================== // ==================== [On Submit] ========================
console.log(errors); // console.log(errors);
const onSubmit = async (data) => { const onSubmit = async (data) => {
console.log("Hit"); console.log("Hit");
@@ -311,16 +306,20 @@ const SubAdminUpdateCreate = () => {
cursor={"pointer"} cursor={"pointer"}
> >
<ArrowBackIcon fontSize={"xl"} me={2} /> <ArrowBackIcon fontSize={"xl"} me={2} />
Add Details {params?.id ? "Edit Details" : "Add Details"}
</Text> </Text>
{params?.id ? ( {/* {params?.id ? (
"" ""
) : ( ) : (
<RoleSwitchButton <RoleSwitchButton
isSwitchOn={isSwitchOn} isSwitchOn={isSwitchOn}
setIsSwitchOn={setIsSwitchOn} setIsSwitchOn={setIsSwitchOn}
/> />
)} )} */}
<RoleSwitchButton
isSwitchOn={isSwitchOn}
setIsSwitchOn={setIsSwitchOn}
/>
</Box> </Box>
{/* ====================== [Form Input] ====================== */} {/* ====================== [Form Input] ====================== */}

View File

@@ -421,7 +421,7 @@ export const ioService = createApi({
}), }),
profile: builder.query({ profile: builder.query({
query: (id) => `/auth/admin/profile`, query: () => `/auth/admin/profile`,
}), }),
// ========Add Io Details======== // ========Add Io Details========
@@ -435,7 +435,7 @@ export const ioService = createApi({
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
updateTransaction: builder.mutation({ updateTransaction: builder.mutation({
query: (id) => ({ query: (id) => ({
// url: `/io/admin/maker-transaction/${id}/verify-pending-transaction-for-cash-and-nav`, // url: `/io/admin/maker-transaction/${id}/verify-pending-transaction-for-cash-and-nav`,
@@ -448,45 +448,45 @@ export const ioService = createApi({
addNavDetails: builder.mutation({ addNavDetails: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/maker-transaction/${id}/io-nav`, url: `/io/admin/maker-transaction/${id}/io-nav`,
method: "POST", method: "POST",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
addIOTransaction: builder.mutation({ addIOTransaction: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/maker-transaction/${id}/io-nav`, url: `/io/admin/maker-transaction/${id}/io-nav`,
method: "POST", method: "POST",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
saveIOTransaction: builder.mutation({ saveIOTransaction: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/maker-transaction/${id}/io-yeild`, url: `/io/admin/maker-transaction/${id}/io-yeild`,
method: "POST", method: "POST",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
exitIOTransaction: builder.mutation({ exitIOTransaction: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/maker-transaction/${id}/io-exit`, url: `/io/admin/maker-transaction/${id}/io-exit`,
method: "POST", method: "POST",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
addIoCase: builder.mutation({ addIoCase: builder.mutation({
query: (id) => ({ query: (id) => ({
@@ -499,10 +499,10 @@ export const ioService = createApi({
approveIOCase: builder.mutation({ approveIOCase: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/approved/io-cash/${id}`, url: `/io/admin/checker-transaction/approved/io-cash/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
@@ -510,71 +510,71 @@ export const ioService = createApi({
approveIONav: builder.mutation({ approveIONav: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/approved/io-nav/${id}`, url: `/io/admin/checker-transaction/approved/io-nav/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
approveDistribution: builder.mutation({ approveDistribution: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/approved/distributed-to-investor/${id}`, url: `/io/admin/checker-transaction/approved/distributed-to-investor/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
approveExit: builder.mutation({ approveExit: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/approved/exit/${id}`, url: `/io/admin/checker-transaction/approved/exit/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
approveInvested: builder.mutation({ approveInvested: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/approved/amount-invested/${id}`, url: `/io/admin/checker-transaction/approved/amount-invested/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
approveDistributed: builder.mutation({ approveDistributed: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/approved/distributed-to-investor/${id}`, url: `/io/admin/checker-transaction/approved/distributed-to-investor/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
approveExitTransaction: builder.mutation({ approveExitTransaction: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/approved/exit/${id}`, url: `/io/admin/checker-transaction/approved/exit/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
approveCancleTransaction: builder.mutation({ approveCancleTransaction: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/approved/cancel/${id}`, url: `/io/admin/checker-transaction/approved/cancel/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
@@ -582,16 +582,16 @@ export const ioService = createApi({
rejectIOCase: builder.mutation({ rejectIOCase: builder.mutation({
query: ({id,data}) => ({ query: ({ id, data }) => ({
url: `/io/admin/checker-transaction/reject/${id}`, url: `/io/admin/checker-transaction/reject/${id}`,
method: "PATCH", method: "PATCH",
body:data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
}), }),
}); });

View File

@@ -9,7 +9,7 @@ import { baseQuery } from "./token.serivce";
export const sabAdminMaster = createApi({ export const sabAdminMaster = createApi({
reducerPath: "sabAdminMaster", reducerPath: "sabAdminMaster",
baseQuery: baseQuery, baseQuery: baseQuery,
tagTypes: ["getSubAdmin", "prePopulate"], tagTypes: ["getSubAdmin", "prePopulate","getSubAdminById"],
endpoints: (builder) => ({ endpoints: (builder) => ({
@@ -29,7 +29,7 @@ export const sabAdminMaster = createApi({
method: "POST", method: "POST",
body: data, body: data,
}), }),
invalidatesTags: ["getSubAdmin","prePopulate"], invalidatesTags: ["getSubAdmin", "prePopulate"],
}), }),
// // ========[Update Sponser]======== // // ========[Update Sponser]========
@@ -40,17 +40,18 @@ export const sabAdminMaster = createApi({
method: "PATCH", method: "PATCH",
body: data, body: data,
}), }),
invalidatesTags: ["getSubAdmin"], invalidatesTags: ["getSubAdmin","getSubAdminById"],
}), }),
getSubAdminById: builder.query({ getSubAdminById: builder.query({
query: (id) => `/subadmin/admin/${id}`, query: (id) => `/subadmin/admin/${id}`,
providesTags: ["getSubAdminById"],
}), }),
// // ========[Toggle Status]======== // // ========[Toggle Status]========
toggleStatus: builder.mutation({ toggleStatus: builder.mutation({
query: ({id, data}) => ({ query: ({ id, data }) => ({
url: `/subadmin/admin/toggle-role/${id}`, url: `/subadmin/admin/toggle-role/${id}`,
method: "PATCH", method: "PATCH",
body: data, body: data,
@@ -58,41 +59,26 @@ export const sabAdminMaster = createApi({
invalidatesTags: ["getSubAdmin"], invalidatesTags: ["getSubAdmin"],
}), }),
// // ========[Get Active]========
// getActiveSponserMaster: builder.query({ // ==========[Delete User] ==========
// query: () => `/sponsor/admin/active`, deleteUser: builder.mutation({
// }), query: (id) => ({
url: `/subadmin/admin/${id}`,
// getSponserMasterActive: builder.query({ method: "DELETE",
// query: () => "/sponsor/admin/active", }),
// }), invalidatesTags: ["getSubAdmin"],
}),
// // ======[Get ID]=====
// getSponserById: builder.query({
// query: (id) => `/sponsor/admin/${id}`,
// }),
// // ========[Update Sponser]========
// updateSponser: builder.mutation({
// query: ({ data, id }) => ({
// url: `/sponsor/admin/${id}`,
// method: "PATCH",
// body: data,
// }),
// invalidatesTags: ["getSponser"],
// }),
}), }),
}); });
// Export hooks for usage in functional components // Export hooks for usage in functional components
export const { export const {
useGetSubAdminMasterQuery, useGetSubAdminMasterQuery,
useCreateSubAdminMutation, useCreateSubAdminMutation,
useUpdateSubAdminMutation, useUpdateSubAdminMutation,
useGetSubAdminByIdQuery, useGetSubAdminByIdQuery,
useToggleStatusMutation useToggleStatusMutation,
useDeleteUserMutation,
} = sabAdminMaster; } = sabAdminMaster;

View File

@@ -1,132 +1,122 @@
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { encryptString } from '../Constants/Constants' import { encryptString } from '../Constants/Constants'
// Define a base query function with RTK Query // Define a base query function with token refresh logic, retry mechanism, and AbortController
// export const baseQuery = fetchBaseQuery({
// baseUrl: 'https://sprint4.tanami.betadelivery.com/api/v1',
// prepareHeaders: (headers) => {
// const token = localStorage.getItem('accessToken');
// if (token) {
// headers.set('x-auth-token', `${token}`);
// }
// return headers;
// },
// });
// Define a base query function with token refresh logic
export const baseQuery = async (args, api, extraOptions) => { export const baseQuery = async (args, api, extraOptions) => {
let result = await fetchBaseQuery({ const fetchBase = fetchBaseQuery({
baseUrl: import.meta.env.VITE_BAS_URL, baseUrl: import.meta.env.VITE_BAS_URL,
prepareHeaders: (headers) => { credentials: 'include',
const token = localStorage.getItem("accessToken"); prepareHeaders: (headers) => {
if (token) { // headers.set('Content-Type', 'application/json');
headers.set("x-auth-token", token); return headers;
} },
return headers; });
},
})(args, api, extraOptions);
if (result.error && result.error.status === 403) { const abortController = new AbortController();
// Handle token refresh extraOptions = {
const refreshToken = localStorage.getItem("refreshToken"); ...extraOptions,
console.log(refreshToken); signal: abortController.signal,
if (refreshToken) { };
try {
const refreshResult = await fetchBaseQuery({
baseUrl: import.meta.env.VITE_BAS_URL,
})(
{
url: "/auth/user/regenerate-token",
method: "POST",
body: { refreshToken },
},
api,
extraOptions
);
if (refreshResult.data) { let result = await fetchBase(args, api, extraOptions);
// Save new tokens
localStorage.setItem("accessToken", refreshResult?.data?.data?.access?.token);
// localStorage.setItem("role", refreshResult?.data?.data?.role);
// console.log(refreshResult?.data?.data?.role);
// Retry the original request with the new token if (result.error) {
result = await fetchBaseQuery({ if (result.error.status === 403) {
baseUrl: import.meta.env.VITE_BAS_URL, let retryCount = 0;
prepareHeaders: (headers) => { const maxRetries = import.meta.env.VITE_MAX_TRY_REGENRATE_TOKEN || 2;
const token = localStorage.getItem("accessToken");
if (token) {
headers.set("x-auth-token", token);
}
return headers;
},
})(args, api, extraOptions);
}else{
console.log('refresh failed'); while (retryCount < maxRetries) {
localStorage.clear(); try {
window.location.href = '/login'; // Redirect to login page const { data, error } = await fetchBase(
{
url: "/auth/user/regenerate-token",
method: "POST",
},
api,
{ ...extraOptions, signal: abortController.signal }
);
if (data) {
// Retry the original query after successful token regeneration
return await fetchBase(args, api, { ...extraOptions, signal: abortController.signal });
}
} throw error;
} catch (err) { } catch (err) {
console.error("Failed to refresh token:", err); retryCount++;
localStorage.clear(); if (retryCount >= maxRetries) {
window.location.href = '/login'; // Redirect to login page console.error("Failed to refresh token after retries:", err);
// Handle refresh failure (e.g., redirect to login) abortController.abort();
} localStorage.clear();
} window.location.href = '/login'; // Redirect to login page
} break;
}
}
}
} else if (result.error.status === 401) {
abortController.abort();
localStorage.clear();
window.location.href = '/login';
}
}
return result; return result;
}; };
// Create an RTK Query API slice // Create an RTK Query API slice
export const apiSlice = createApi({ export const apiSlice = createApi({
reducerPath: "api", reducerPath: "api",
baseQuery: baseQuery, baseQuery: baseQuery,
endpoints: (builder) => ({ tagTypes: ["authProfile"],
login: builder.mutation({ endpoints: (builder) => ({
query: (credentials) => ({
url: "/auth/admin", login: builder.mutation({
method: "POST", query: (credentials) => ({
body: credentials, url: "/auth/admin",
}), method: "POST",
async onQueryStarted(arg, { dispatch, queryFulfilled }) { body: credentials,
try { }),
const { data } = await queryFulfilled; async onQueryStarted(arg, { queryFulfilled }) {
// Store tokens in local storage try {
localStorage.setItem("accessToken", data?.data?.access?.token); const { data } = await queryFulfilled;
localStorage.setItem("role", encryptString(data?.data?.role));
localStorage.setItem("refreshToken", data?.data?.refresh?.token); } catch (error) {
// localStorage.setItem('refreshTokenExp', data?.data?.refresh?.expires); console.error("Login failed:", error);
localStorage.setItem("accessTokenExp", data?.data?.access?.expires); }
localStorage.setItem("role", encryptString(data?.data?.role)); },
} catch (error) { }),
console.error("Login failed:", error);
} refreshToken: builder.mutation({
}, query: (refreshToken) => ({
}), url: "/auth/user/regenerate-token",
refreshToken: builder.mutation({ method: "POST",
query: (refreshToken) => ({ body: { refreshToken },
url: "/auth/user/regenerate-token", }),
method: "POST", }),
body: { refreshToken },
}), logout: builder.mutation({
}), query: () => ({
url: "/auth/admin/logout",
method: "POST",
}),
}),
authProfile: builder.query({
query: () => `/auth/admin/profile`,
providesTags: (result) => result ? [{ type: 'Auth', id: 'profile' }] : [],
onQueryStarted: async (args, { queryFulfilled }) => {
try {
const { data } = await queryFulfilled; // Get the data from the query response
if (data?.role) {
localStorage.setItem('role', encryptString(data.role));
}
} catch (error) {
console.error('Error setting role in localStorage:', error);
}
},
}),
logout: builder.mutation({ }),
query: () => ({ });
url: "/auth/admin/logout",
method: "POST",
}),
}),
export const { useLoginMutation, useRefreshTokenMutation, useLogoutMutation, useAuthProfileQuery } = apiSlice;
}),
});
export const { useLoginMutation, useRefreshTokenMutation, useLogoutMutation } = apiSlice;