Compare commits

..

79 Commits

Author SHA1 Message Date
YasinShaikh123
d7012f2692 selected css 2024-08-20 19:10:58 +05:30
YasinShaikh123
e07a92ba03 mobile downloader 2024-08-20 15:55:06 +05:30
YasinShaikh123
adb4bd5d27 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into feature-dev 2024-08-20 14:53:05 +05:30
cfda3264fc [.env update] 2024-08-20 14:52:13 +05:30
YasinShaikh123
1569afe4f0 mobile height 2024-08-20 13:47:46 +05:30
YasinShaikh123
4a3072b4d3 io mobile 2024-08-20 13:00:22 +05:30
4516c70406 Merge branch 'main' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel 2024-08-20 12:19:06 +05:30
50f87869be Edit update 2024-08-20 12:19:02 +05:30
d69e4a203f Merge branch 'main' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel 2024-08-20 11:26:40 +05:30
6e4c794d2b update 2024-08-17 20:38:06 +05:30
dfbc1ad338 finalUp 2024-08-16 20:44:13 +05:30
aa1c0c994a updted 2024-08-16 20:30:42 +05:30
cecd8dd5e0 final Commit 2024-08-16 20:24:25 +05:30
620b365437 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-16 20:03:54 +05:30
2e5ecb967f update 2024-08-16 20:03:50 +05:30
3df4ed8df3 [Updated]=Final 2024-08-16 19:50:51 +05:30
6f514fe121 Merge branch 'feature-dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel 2024-08-16 19:44:55 +05:30
125d6e6ae3 [Update]=final 2024-08-16 19:44:29 +05:30
YasinShaikh123
68d6bd7c9e io header 2024-08-16 19:26:02 +05:30
e7aef39fa7 rixky update 2024-08-16 18:42:34 +05:30
71f8c8a98d update final 2024-08-16 18:31:04 +05:30
08559eb833 Merge branch 'feature-dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel 2024-08-16 18:30:43 +05:30
fc7d8ac0e9 updated final 2024-08-16 18:29:33 +05:30
YasinShaikh123
692e08abd6 investor view 2024-08-16 18:26:25 +05:30
a0b722bd12 final update 2024-08-16 18:23:55 +05:30
YasinShaikh123
34c51c4c4c Merge branch 'feature-dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into feature-dev 2024-08-16 17:59:44 +05:30
YasinShaikh123
b5a960f7df investor details 2024-08-16 17:59:39 +05:30
1f97c841f7 updated investor in IO 2024-08-16 16:33:20 +05:30
ba9efdd48b update sorting 2024-08-16 15:44:30 +05:30
YasinShaikh123
e103258995 tabs padding 2024-08-16 15:24:18 +05:30
YasinShaikh123
9d404a58f2 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into feature-dev 2024-08-16 15:23:51 +05:30
YasinShaikh123
24d4926f75 Merge branch 'main' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into feature-dev 2024-08-16 15:12:42 +05:30
YasinShaikh123
ee8f905d3a mobile view 2024-08-16 15:12:37 +05:30
568b2f716a finalUpdate Fri 16 Aug 2024-08-16 15:02:02 +05:30
27a975fe8a Merge branch 'feature-dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-14 20:48:27 +05:30
YasinShaikh123
395d60fd2f mobile modal 2024-08-14 20:48:12 +05:30
78c7f55673 Merge branch 'feature-dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-14 20:33:06 +05:30
YasinShaikh123
b308e22b6d updated 2024-08-14 20:31:04 +05:30
c9ad4a4377 update 2024-08-14 18:48:25 +05:30
2d641a9748 updated 2024-08-14 12:19:27 +05:30
83aa170c60 updated 2024-08-13 19:58:31 +05:30
YasinShaikh123
54e37a3703 mobile banner 2024-08-13 19:58:16 +05:30
8dae36daaf updated 13-Aug 2024-08-13 19:02:47 +05:30
84fb0d77cf Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-13 16:56:29 +05:30
94d3e25cce updated 2024-08-13 16:56:17 +05:30
YasinShaikh123
f17f77d409 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-13 13:47:52 +05:30
YasinShaikh123
51a4bc7917 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-13 13:47:29 +05:30
YasinShaikh123
78d573037d dashboard graph 2024-08-13 13:47:25 +05:30
5b1f89efc9 updateed 2024-08-13 13:46:41 +05:30
YasinShaikh123
7de0a679e0 dashboard charts 2024-08-12 17:23:56 +05:30
8cc16ddc8a updated 2024-08-12 17:22:04 +05:30
60b0263133 update 2024-08-12 16:19:47 +05:30
fd45d6aeef update nav 2024-08-12 15:48:55 +05:30
f7a8da789c update 2024-08-12 15:35:39 +05:30
YasinShaikh123
e0765514f5 deposite api changes 2024-08-12 12:34:56 +05:30
0393a18762 ionav updated 2024-08-12 12:22:01 +05:30
e8b9a4af40 update friday 2024-08-09 19:22:18 +05:30
dce1a09f98 dashboard update 2024-08-09 15:37:52 +05:30
1de2710cd1 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-09 12:24:48 +05:30
YasinShaikh123
66afc30a14 add switch btn 2024-08-09 12:24:29 +05:30
e657409edb update dashboard 2024-08-09 12:24:18 +05:30
9f6136935d Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-08 19:39:39 +05:30
26363e2b0c updatw 2024-08-08 19:38:17 +05:30
YasinShaikh123
0e7f954d20 sponser button 2024-08-08 19:37:14 +05:30
9da83b8297 token condition update 2024-08-07 20:27:34 +05:30
591e0c92a0 token update 2024-08-07 20:24:38 +05:30
YasinShaikh123
e234ce3181 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-07 20:19:18 +05:30
YasinShaikh123
4c6df2cc2f deposite reject 2024-08-07 20:19:15 +05:30
2a11fed4f0 UPDATED 070824 2024-08-07 20:18:36 +05:30
2b4896fa9b update 2024-08-06 13:10:24 +05:30
YasinShaikh123
2202305d28 deposit table 2024-08-05 20:11:13 +05:30
059275b310 contact updted 2024-08-05 20:10:07 +05:30
YasinShaikh123
d42cdf0a50 deposite table api 2024-08-05 17:58:01 +05:30
YasinShaikh123
5ca4dad151 Merge branch 'main' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-05 17:57:43 +05:30
eaf6394a4f update main 2024-08-05 17:56:07 +05:30
6b9dc86a5e Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-02 20:20:07 +05:30
60a6a053b3 updated 2024-08-02 20:19:41 +05:30
YasinShaikh123
8d5788ce02 Merge branch 'dev' of http://git.wdipl.com/Siddhesh.More/tanami-admin-panel into dev 2024-08-02 20:19:19 +05:30
YasinShaikh123
3e3c47149a Deposit Table 2024-08-02 20:19:17 +05:30
101 changed files with 6579 additions and 2399 deletions

View File

@@ -22,7 +22,7 @@ const craftedMsg = "Crafted with ❤️ by WDI Team for a better web.";
</script> </script>
<script type="text/javascript"> <!-- <script type="text/javascript">
function googleTranslateElementInit() { function googleTranslateElementInit() {
new google.translate.TranslateElement({ new google.translate.TranslateElement({
pageLanguage: 'en', pageLanguage: 'en',
@@ -30,7 +30,10 @@ const craftedMsg = "Crafted with ❤️ by WDI Team for a better web.";
layout: google.translate.TranslateElement.InlineLayout.SIMPLE layout: google.translate.TranslateElement.InlineLayout.SIMPLE
}, 'google_translate_element'); }, 'google_translate_element');
} }
</script> </script> -->
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script> <!-- <script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script> -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
</body> </body>
</html> </html>

2363
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -16,17 +16,21 @@
"@emotion/styled": "^11.11.5", "@emotion/styled": "^11.11.5",
"@hookform/resolvers": "^3.3.4", "@hookform/resolvers": "^3.3.4",
"@reduxjs/toolkit": "^2.2.3", "@reduxjs/toolkit": "^2.2.3",
"apexcharts": "^3.52.0",
"axios": "^1.7.2", "axios": "^1.7.2",
"bootstrap": "5.3.3", "bootstrap": "5.3.3",
"chart.js": "^4.4.3",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"framer-motion": "^11.1.5", "framer-motion": "^11.1.5",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"react": "^18.2.0", "react": "^18.2.0",
"react-apexcharts": "^1.4.1",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hook-form": "^7.51.3", "react-hook-form": "^7.51.3",
"react-icons": "^5.1.0", "react-icons": "^5.1.0",
"react-quill": "^2.0.0", "react-quill": "^0.0.2",
"react-redux": "^9.1.1", "react-redux": "^9.1.1",
"react-router-dom": "^6.22.3", "react-router-dom": "^6.22.3",
"redux-persist": "^6.0.0", "redux-persist": "^6.0.0",

View File

@@ -14,6 +14,11 @@
/* font-family: "Lato", sans-serif !important; */ /* font-family: "Lato", sans-serif !important; */
} }
::selection {
background-color: #004717; /* Change this to your desired color */
color: white; /* Optional: Change the text color */
}
.pointer { .pointer {
cursor: pointer !important; cursor: pointer !important;
} }
@@ -336,3 +341,151 @@
font-size: 22px !important; font-size: 22px !important;
} }
} }
/* ========= [ switch BTN ============ */
/* From Uiverse.io by Nawsome */
.switch {
display: block;
background-color: black;
width: 85px;
height: 115px;
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0 1px 2px black, inset 0 2px 2px -2px white, inset 0 0 2px 15px #47434c, inset 0 0 2px 22px black;
border-radius: 5px;
padding: 20px;
perspective: 700px;
}
.switch input {
display: none;
}
.switch input:checked + .button {
transform: translateZ(20px) rotateX(25deg);
box-shadow: 0 -10px 20px #ff1818;
}
.switch input:checked + .button .light {
animation: flicker 0.2s infinite 0.3s;
}
.switch input:checked + .button .shine {
opacity: 1;
}
.switch input:checked + .button .shadow {
opacity: 0;
}
.switch .button {
display: block;
transition: all 0.3s cubic-bezier(1, 0, 1, 1);
transform-origin: center center -20px;
transform: translateZ(20px) rotateX(-25deg);
transform-style: preserve-3d;
background-color: #9b0621;
height: 100%;
position: relative;
cursor: pointer;
background: linear-gradient(#980000 0%, #6f0000 30%, #6f0000 70%, #980000 100%);
background-repeat: no-repeat;
}
.switch .button::before {
content: "";
background: linear-gradient(rgba(255, 255, 255, 0.8) 10%, rgba(255, 255, 255, 0.3) 30%, #650000 75%, #320000) 50% 50%/97% 97%, #b10000;
background-repeat: no-repeat;
width: 100%;
height: 50px;
transform-origin: top;
transform: rotateX(-90deg);
position: absolute;
top: 0;
}
.switch .button::after {
content: "";
background-image: linear-gradient(#650000, #320000);
width: 100%;
height: 58px;
transform-origin: top;
transform: translateY(50px) rotateX(-90deg);
position: absolute;
bottom: 0;
box-shadow: 0 50px 8px 0px black, 0 80px 20px 0px rgba(0, 0, 0, 0.5);
}
.switch .light {
opacity: 0;
animation: light-off 1s;
position: absolute;
width: 100%;
height: 100%;
background-image: radial-gradient(#ffc97e, #ff1818 40%, transparent 70%);
}
.switch .dots {
position: absolute;
width: 100%;
height: 100%;
background-image: radial-gradient(transparent 30%, rgba(101, 0, 0, 0.7) 70%);
background-size: 10px 10px;
}
.switch .characters {
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(white, white) 50% 20%/5% 20%, radial-gradient(circle, transparent 50%, white 52%, white 70%, transparent 72%) 50% 80%/33% 25%;
background-repeat: no-repeat;
}
.switch .shine {
transition: all 0.3s cubic-bezier(1, 0, 1, 1);
opacity: 0.3;
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(white, transparent 3%) 50% 50%/97% 97%, linear-gradient(rgba(255, 255, 255, 0.5), transparent 50%, transparent 80%, rgba(255, 255, 255, 0.5)) 50% 50%/97% 97%;
background-repeat: no-repeat;
}
.switch .shadow {
transition: all 0.3s cubic-bezier(1, 0, 1, 1);
opacity: 1;
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(transparent 70%, rgba(0, 0, 0, 0.8));
background-repeat: no-repeat;
}
@keyframes flicker {
0% {
opacity: 1;
}
80% {
opacity: 0.8;
}
100% {
opacity: 1;
}
}
@keyframes light-off {
0% {
opacity: 1;
}
80% {
opacity: 0;
}
}

View File

@@ -37,12 +37,16 @@ const App = () => {
}; };
}, []); }, []);
const PrivateRoute = ({ children }) => { // const token = localStorage.getItem('accessToken')
if (!isAuthenticate && isAuthenticatedInCookie !== "true") { // console.log(token);
return <Navigate to="/login" replace />;
}
return children; // const PrivateRoute = ({ children }) => {
}; // if (!isAuthenticate && isAuthenticatedInCookie !== "true") {
// return <Navigate to="/login" replace />;
// }
// return children;
// };
return ( return (
<Router> <Router>
@@ -52,7 +56,8 @@ const App = () => {
path="/*" path="/*"
element={ element={
// isOnline ? ( // isOnline ? (
isAuthenticate || isAuthenticatedInCookie === "true" ? ( // isAuthenticate || isAuthenticatedInCookie === "true" ? (
localStorage.getItem('accessToken') && localStorage.getItem('refreshToken') ? (
<DefaultLayout isOnline={isOnline} /> <DefaultLayout isOnline={isOnline} />
) : ( ) : (
<Login /> <Login />

View File

@@ -151,7 +151,7 @@ const CreateIO = () => {
}, []); }, []);
const tableHeadRow = [ const tableHeadRow = [
"Sponsorer name", "Sponsor name",
"Address", "Address",
"Mobile no", "Mobile no",
"Created At", "Created At",
@@ -191,7 +191,7 @@ const CreateIO = () => {
const extractedArray = filteredData?.map((item) => ({ const extractedArray = filteredData?.map((item) => ({
id: item?.id, id: item?.id,
"Sponsorer name": ( "Sponsor name": (
<Text <Text
justifyContent={"left"} justifyContent={"left"}
as={"span"} as={"span"}
@@ -413,7 +413,7 @@ const CreateIO = () => {
], ],
}, },
{ {
label: "Sponsorer Name (English)", label: "Sponsor Name (English)",
placeHolder: " ", placeHolder: " ",
name: "sponserName", name: "sponserName",
type: "text", type: "text",

View File

@@ -0,0 +1,47 @@
import React, { forwardRef } from 'react';
import { Input } from "@chakra-ui/react";
// export const formatCurrency = (value) => {
// if (!value) return '';
// const [integer, decimal] = value.split('.');
// const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
// return decimal ? `${formattedInteger}.${decimal}` : formattedInteger;
// };
export const formatCurrency = (value) => {
if (value === undefined || value === null) return ''; // Handle undefined or null values
const [integer, decimal] = String(value).split('.'); // Convert value to string before splitting
const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return decimal ? `${formattedInteger}.${decimal}` : formattedInteger;
};
const CurrencyInput = forwardRef(({ value, onChange, ...props }, ref) => {
const handleChange = (event) => {
let { value } = event?.target;
// Remove non-numeric characters except decimal point
value = value?.replace(/[^0-9.]/g, '');
// Ensure only one decimal point
const parts = value?.split('.');
if (parts.length > 2) {
value = parts[0] + '.' + parts?.slice(1)?.join('');
}
onChange(value); // Pass the raw value to parent or use it directly
};
return (
<Input
{...props}
ref={ref} // Forward ref here
type="text"
value={formatCurrency(value)}
onChange={handleChange}
/>
);
});
export default CurrencyInput;

View File

@@ -50,7 +50,7 @@ const DataTable = ({
const [removed] = reorderedItems.splice(result.source.index, 1); const [removed] = reorderedItems.splice(result.source.index, 1);
reorderedItems.splice(result.destination.index, 0, removed); reorderedItems.splice(result.destination.index, 0, removed);
setData(reorderedItems) setData(reorderedItems)
console.log("New Order:", reorderedItems.map((item, index) => ({ index, item }))); // console.log("New Order:", reorderedItems.map((item, index) => ({ index, item })));
}; };
return ( return (

View File

@@ -12,6 +12,7 @@ import {
Tfoot, Tfoot,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import EmptySearchList from "../EmptySearchList"; import EmptySearchList from "../EmptySearchList";
import { TABLE_PAGINATION } from "../../Constants/Paginations";
const DataTable = ({ const DataTable = ({
data, data,
@@ -20,6 +21,9 @@ const DataTable = ({
emptyMessage, emptyMessage,
centered, centered,
}) => { }) => {
console.log(data);
const columnWidth = const columnWidth =
data && data[0] data && data[0]
? `${(100 / Object.keys(data[0]).length).toFixed(2)}%` ? `${(100 / Object.keys(data[0]).length).toFixed(2)}%`
@@ -35,7 +39,6 @@ const DataTable = ({
<Tr> <Tr>
{tableHeadRow.map((heading, index) => ( {tableHeadRow.map((heading, index) => (
<Th <Th
width={'fit-content'}
textAlign={ textAlign={
tableHeadRow.length - 1 === index || centered tableHeadRow.length - 1 === index || centered
? "center" ? "center"
@@ -43,7 +46,13 @@ const DataTable = ({
} }
key={index} key={index}
p={3} p={3}
w={columnWidth} width="20px" // Adjust width as needed
color={"#004118"}
whiteSpace="normal" // Allow text to wrap
wordBreak="normal" // Ensure long words break properly
overflowWrap="normal" // Break long words if necessary
textTransform={'none'}
> >
{isLoading ? <Skeleton height="20px" /> : heading} {isLoading ? <Skeleton height="20px" /> : heading}
{/* {heading} */} {/* {heading} */}
@@ -53,7 +62,7 @@ const DataTable = ({
</Thead> </Thead>
<Tbody className="web-text-small"> <Tbody className="web-text-small">
{isLoading {isLoading
? Array.from({ length: 12 }).map((_, index) => ( ? Array.from({ length: TABLE_PAGINATION?.size }).map((_, index) => (
<Tr key={index}> <Tr key={index}>
{tableHeadRow.map((_, i) => ( {tableHeadRow.map((_, i) => (
<Td <Td

View File

@@ -0,0 +1,55 @@
import React, { useState } from 'react';
import ApexCharts from 'react-apexcharts';
const ApexChart = ({ data }) => {
// Customize colors and series titles here
const [options] = useState({
chart: {
width: 600,
type: 'donut',
},
plotOptions: {
pie: {
startAngle: -90,
endAngle: 270,
donut: {
size: '45%' // Adjust the donut size here (percentage of chart size)
}
}
},
labels:data?.labels,
dataLabels: {
enabled: false
},
fill: {
type: 'gradient',
},
colors: data?.backgroundColor,
legend: {
show: false,
position: 'right',
labels: {
colors: ['#000'], // Customize the color of the legend labels
useSeriesColors: true
}
},
responsive: [{
breakpoint: 480,
options: {
chart: {
width: 500
},
legend: {
position: 'center'
}
}
}]
});
return (
<ApexCharts options={options} series={data?.values} type="donut" width={300} />
);
};
export default ApexChart;

View File

@@ -0,0 +1,66 @@
import React, { useState } from 'react';
import ReactApexChart from 'react-apexcharts';
function ApexLine() {
const [chartOptions, setChartOptions] = useState({
series: [{
name: 'Rate',
data: [45, 23, 70, 65, 5, 34, 32],
gradientToColors: ['#004017'],
}],
options: {
chart: {
height: 350,
type: 'line',
toolbar: {
show: false // Hide the action icons
}
},
stroke: {
width: 5,
curve: 'smooth',
colors: ['#598369'], // Customize the line color here
},
markers: {
size: 6, // Size of markers
colors: ['#004118'], // Marker (dot) color
strokeColor: '#fff', // Stroke color of the marker
strokeWidth: 2
},
xaxis: {
type: 'category', // Change from 'datetime' to 'category'
categories: ['BH', 'KW', 'OM', 'QA', 'SA', 'UAE', 'IND'],
tickAmount: 7
},
title: {
text: 'Exchange Rate Currency', // Adjust the title if needed
align: 'left',
style: {
fontSize: '15px',
color: '#000',
fontWeight: 400
}
},
fill: {
type: 'gradient',
gradient: {
shade: 'dark',
gradientToColors: ['#004017'],
shadeIntensity: 4,
type: 'horizontal',
opacityFrom: 1,
opacityTo: 1,
stops: [0, 100] // Gradient stops
},
}
}
});
return (
<div>
<ReactApexChart options={chartOptions.options} series={chartOptions.series} type="line" height={"100%"} width={"600"} />
</div>
);
}
export default ApexLine;

View File

@@ -0,0 +1,39 @@
// DonutChart.jsx
import React from 'react';
import { Doughnut } from 'react-chartjs-2';
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement } from 'chart.js';
ChartJS.register(Title, Tooltip, Legend, ArcElement);
const DonutChart = ({ data, width = 300, height = 250 }) => {
const chartData = {
labels: data.labels,
datasets: [
{
label: 'My Dataset',
data: data.values,
backgroundColor: [ '#3182ce', '#004118', '#D69E2E', '#E53E3E' ],
borderColor: ['#FFF'],
borderWidth: 2,
},
],
};
const options = {
responsive: true,
plugins: {
legend: {
display: false, // Hide the legend
},
tooltip: {
callbacks: {
label: (tooltipItem) => `${tooltipItem.label}: ${tooltipItem.raw}`,
},
},
},
};
return <Doughnut data={chartData} options={options} width={'100%'} />;
};
export default DonutChart;

View File

@@ -0,0 +1,80 @@
// LineChart.jsx
import React from 'react';
import { Line } from 'react-chartjs-2';
import { Chart as ChartJS, Title, Tooltip, Legend, LineElement, PointElement, LinearScale, CategoryScale } from 'chart.js';
// Register the necessary components
ChartJS.register( Title, Tooltip, Legend, LineElement, PointElement, LinearScale, CategoryScale );
// Sample options for the chart
// Sample options for the chart
const options = {
responsive: true,
plugins: {
legend: {
position: 'top',
},
tooltip: {
callbacks: {
label: function (context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += `${context.parsed.y}`;
}
return label;
}
}
}
},
animation: {
tension: {
duration: 2000,
easing: 'linear',
from: 1,
to: 0,
loop: true
}
}
};
const Utils = {
numbers: ({ count, min, max }) => Array.from({ length: count }, () => Math.floor(Math.random() * (max - min + 1)) + min),
CHART_COLORS: {
red: 'rgba(255, 99, 132, 1)',
darkGreen: 'rgba(0, 65, 24, 1)' // Added color related to #004118
},
transparentize: (color, opacity) => {
// Use regex to replace the alpha value
return color.replace(/(rgba\(\d+, \d+, \d+, )\d+(\))/, `$1${opacity}$2`);
}
};
const LineChart = ({ width = 300, height = 250 }) => {
const data = {
labels: ['Bahrain', 'Kuwait', 'Oman', 'Qatar', 'Saudi Arabia', 'UAE', 'India'],
datasets: [
{
label: 'Exchange rate',
data: [45.9087, 23.8798, 99.9809, 65.8987, 65.8987, 34.9898, 32.8987],
borderColor: Utils.CHART_COLORS.darkGreen,
backgroundColor: Utils.transparentize(Utils.CHART_COLORS.darkGreen, 0.5),
pointStyle: 'rectRounded',
pointRadius: 10,
pointHoverRadius: 15
}
]
};
return (
<Line data={data} options={options} />
);
};
export default LineChart;

View File

@@ -0,0 +1,41 @@
import { Box, Input } from "@chakra-ui/react";
import React, { useRef, useState } from "react";
import audioClick from "../assets/click-151673.mp3";
const DummyComponent = () => {
// Define the state for the checkbox
const [isSwitchOn, setIsSwitchOn] = useState(false);
const audio = useRef();
// Function to toggle the switch
const handleToggle = () => {
setIsSwitchOn(!isSwitchOn);
if(audio.current){
audio.current.play();
}
};
return (
<Box display={"flex"} justifyContent={"right"} p={"2rem"}>
<label className="switch">
<Input
type="checkbox"
checked={isSwitchOn}
onChange={handleToggle} // Toggle the switch on change
/>
<Box className="button">
<div className="light"></div>
<div className="dots"></div>
<div className="characters"></div>
<div className="shine"></div>
<div className="shadow"></div>
</Box>
</label>
<audio ref={audio} src={audioClick} />
</Box>
);
};
export default DummyComponent;

View File

@@ -27,10 +27,11 @@ import { Controller } from "react-hook-form";
import { TiWarning } from "react-icons/ti"; import { TiWarning } from "react-icons/ti";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { AddIcon, CloseIcon } from "@chakra-ui/icons"; import { AddIcon, CloseIcon } from "@chakra-ui/icons";
import CurrencyInput from "./CurrencyInput";
const today = new Date().toISOString().split("T")[0]; const today = new Date().toISOString().split("T")[0];
const formatDate = (dateString) => { export const formatDatee = (dateString) => {
const date = new Date(dateString); const date = new Date(dateString);
const year = date.getFullYear(); const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0"); // Months are zero-based const month = String(date.getMonth() + 1).padStart(2, "0"); // Months are zero-based
@@ -41,7 +42,7 @@ const formatDate = (dateString) => {
const defaultDate = "8/2/2024"; const defaultDate = "8/2/2024";
// Format the default date as YYYY-MM-DD // Format the default date as YYYY-MM-DD
const formattedDate = formatDate(defaultDate); const formattedDate = formatDatee(defaultDate);
const FormField = ({ const FormField = ({
label, label,
@@ -67,12 +68,13 @@ const FormField = ({
handleInputChange, handleInputChange,
align, align,
maxLength, maxLength,
dateValue,
...props ...props
}) => ( }) => (
<FormControl <FormControl
w={width ? width : "49%"} w={width ? width : "49%"}
isInvalid={errors[name]} isInvalid={errors[name]}
isRequired={isRequired} isRequired={type === "date" ? false: isRequired}
mb={2} mb={2}
> >
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}> <FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
@@ -402,7 +404,7 @@ const FormField = ({
w={6} w={6}
h={6} h={6}
src={ src={
" https://tanami.betadelivery.com/" + import.meta.env.VITE_IMAGE_URL +
item?.logo item?.logo
} }
/> />
@@ -460,7 +462,51 @@ const FormField = ({
</Tbody> </Tbody>
</Table> </Table>
); );
} else { } else if(type === 'date'){
return (
<Input
position={'relative'}
bg={"#F5F8F6"}
focusBorderColor="forestGreen.300"
size={"sm"}
fontSize={"sm"}
rounded={"sm"}
type={"date"}
{...field}
{...props}
placeholder={placeHolder ? placeHolder : label}
textAlign={arabic ? "right" : align ? align : "left"}
_placeholder={{ fontSize: "sm" }}
min={type === "date" ? today : undefined}
maxLength={maxLength}
// defaultValue={type === "date" && "2023-07-26" : undefined}
// defaultValue={value}
// value={dateValue}
/>
);
}else if(type === 'number'){
return (
<CurrencyInput
position={'relative'}
bg={"#F5F8F6"}
focusBorderColor="forestGreen.300"
size={"sm"}
fontSize={"sm"}
rounded={"sm"}
{...field}
{...props}
placeholder={placeHolder ? placeHolder : label}
textAlign={"right"}
_placeholder={{ fontSize: "sm" }}
maxLength={maxLength}
// defaultValue={type === "date" && "2023-07-26" : undefined}
// defaultValue={value}
// value={dateValue}
/>
);} else{
return ( return (
<Input <Input
bg={"#F5F8F6"} bg={"#F5F8F6"}
@@ -474,7 +520,7 @@ const FormField = ({
placeholder={placeHolder ? placeHolder : label} placeholder={placeHolder ? placeHolder : label}
textAlign={arabic || type === "number" ? "right" : align ? align : "left"} textAlign={arabic || type === "number" ? "right" : align ? align : "left"}
_placeholder={{ fontSize: "sm" }} _placeholder={{ fontSize: "sm" }}
min={type === "date" ? today : undefined} // min={type === "date" ? today : undefined}
maxLength={maxLength} maxLength={maxLength}
// defaultValue={type === "date" && "2023-07-26" : undefined} // defaultValue={type === "date" && "2023-07-26" : undefined}
// value={"2023-07-26"} // value={"2023-07-26"}
@@ -490,7 +536,7 @@ const FormField = ({
</span> </span>
)} )}
{helperText && ( {helperText && (
<FormHelperText className="web-text-small">{helperText}</FormHelperText> <FormHelperText color={'gray.500'} className="web-text-small">{helperText}</FormHelperText>
)} )}
{type === "file" && ( {type === "file" && (
<FormHelperText className="web-text-small"> <FormHelperText className="web-text-small">

View File

@@ -59,7 +59,8 @@ const FormInputMain = ({
value, value,
handleInputChange, handleInputChange,
align, align,
maxLength maxLength,
dateValue
}, },
key key
) => ( ) => (
@@ -83,10 +84,11 @@ const FormInputMain = ({
handleImageChange={handleImageChange} handleImageChange={handleImageChange}
removeImage={removeImage} removeImage={removeImage}
width={width} width={width}
value={type === "date" ? null :value} value={value}
handleInputChange={handleInputChange} handleInputChange={handleInputChange}
align={align} align={align}
maxLength={maxLength} maxLength={maxLength}
dateValue={dateValue}
/> />
) )
)} )}

View File

@@ -30,16 +30,16 @@ const FormInputView = ({
<form> <form>
{Object?.entries(groupedFields, groupedFieldsTwo).map( {Object?.entries(groupedFields, groupedFieldsTwo).map(
([section, fields], index) => ( ([section, fields], index) => (
<Box key={section}> <Box key={index}>
<Heading as="h6" size="xs" mt={index === 0 ? 3 : 4}> <Heading as="h6" size="xs" mt={index === 0 ? 3 : 4}>
{section} {section}
</Heading> </Heading>
{/* <Box display={"flex"} gap={0}> */} {/* <Box display={"flex"} gap={0}> */}
<Box width={"100%"} display={"flex"} flexWrap={"wrap"} gap={4}> <Box key={index} width={"100%"} display={"flex"} flexWrap={"wrap"} gap={4}>
{fields.map( {fields.map(
({ value, label, id, width, btn, arabic, type, align }, key) => ({ value, label, id, width, btn, arabic, type, align }, key) =>
type === "table" ? ( type === "table" ? (
<Table w={"100%"} variant="simple"> <Table key={id} w={"100%"} variant="simple">
<Thead> <Thead>
<Tr> <Tr>
{value?.map((item, index) => ( {value?.map((item, index) => (
@@ -121,7 +121,7 @@ const FormInputView = ({
</Tbody> </Tbody>
</Table> </Table>
) : ( ) : (
<Box w={!width ? "49%" : width}> <Box key={id} w={!width ? "49%" : width}>
<FormLabel key={id} color={"gray.500"} fontSize={"xs"}> <FormLabel key={id} color={"gray.500"} fontSize={"xs"}>
{label} {label}
</FormLabel> </FormLabel>

View File

@@ -1,8 +1,9 @@
import { AddIcon } from "@chakra-ui/icons"; import { AddIcon, ArrowBackIcon } from "@chakra-ui/icons";
import { import {
Avatar, Avatar,
Box, Box,
Button, Button,
HStack,
Popover, Popover,
PopoverArrow, PopoverArrow,
PopoverBody, PopoverBody,
@@ -14,13 +15,14 @@ import {
useColorMode, useColorMode,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext } from "react"; import React, { useContext } from "react";
import { Link } from "react-router-dom"; import { Link, useNavigate } from "react-router-dom";
import { IoMdDownload } from "react-icons/io"; import { IoMdDownload } from "react-icons/io";
import * as XLSX from "xlsx"; import * as XLSX from "xlsx";
import profile from "../assets/proavatar.webp"; import profile from "../assets/proavatar.webp";
import GlobalStateContext from "../Contexts/GlobalStateContext"; import GlobalStateContext from "../Contexts/GlobalStateContext";
import { MdOutlineDarkMode, MdOutlineLightMode } from "react-icons/md"; import { MdOutlineDarkMode, MdOutlineLightMode } from "react-icons/md";
import logoMini from "../assets/propic.png" import logoMini from "../assets/propic.png"
import { BsBack } from "react-icons/bs";
const HeaderMain = ({ const HeaderMain = ({
link, link,
@@ -30,6 +32,7 @@ const HeaderMain = ({
logOutHandler, logOutHandler,
slideDirecttion, slideDirecttion,
}) => { }) => {
const navigate = useNavigate()
const { colorMode, toggleColorMode } = useContext(GlobalStateContext); const { colorMode, toggleColorMode } = useContext(GlobalStateContext);
@@ -38,7 +41,12 @@ const HeaderMain = ({
className={` pt-2 pb-2 fw-400 border-bottom d-flex ${ className={` pt-2 pb-2 fw-400 border-bottom d-flex ${
slideDirecttion ? "flex-row-reverse ps-2" : "" slideDirecttion ? "flex-row-reverse ps-2" : ""
} justify-content-between align-items-center`} } justify-content-between align-items-center`}
// boxShadow={"0 0px 8px rgba(0, 0, 0, 0.2)"}
zIndex={999}
> >
<HStack>
{/* <ArrowBackIcon onClick={()=>navigate(-1)} /> */}
<Text <Text
as={"span"} as={"span"}
fontWeight={"500"} fontWeight={"500"}
@@ -48,6 +56,7 @@ const HeaderMain = ({
{/* <icon /> */} {/* <icon /> */}
{title} {title}
</Text> </Text>
</HStack>
<Box me={4} gap={2} className="d-flex justify-content-center "> <Box me={4} gap={2} className="d-flex justify-content-center ">

View File

@@ -26,7 +26,7 @@ const ImageViewer = ({ src, isOpen, onClose }) => {
rounded={6} rounded={6}
w={"100%"} w={"100%"}
h={"100%"} h={"100%"}
src={"https://tanami.betadelivery.com/" + src} src={import.meta.env.VITE_IMAGE_URL + src}
/> />
</ModalBody> </ModalBody>
</ModalContent> </ModalContent>

View File

@@ -0,0 +1,105 @@
/* From Uiverse.io by abrahamcalsin */
.dot-spinner {
--uib-size: 2.8rem;
--uib-speed: .9s;
--uib-color: #004717;
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
height: var(--uib-size);
width: var(--uib-size);
}
.dot-spinner__dot {
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: flex-start;
height: 100%;
width: 100%;
}
.dot-spinner__dot::before {
content: '';
height: 20%;
width: 20%;
border-radius: 50%;
background-color: var(--uib-color);
transform: scale(0);
opacity: 0.5;
animation: pulse0112 calc(var(--uib-speed) * 1.111) ease-in-out infinite;
box-shadow: 0 0 20px rgba(18, 31, 53, 0.3);
}
.dot-spinner__dot:nth-child(2) {
transform: rotate(45deg);
}
.dot-spinner__dot:nth-child(2)::before {
animation-delay: calc(var(--uib-speed) * -0.875);
}
.dot-spinner__dot:nth-child(3) {
transform: rotate(90deg);
}
.dot-spinner__dot:nth-child(3)::before {
animation-delay: calc(var(--uib-speed) * -0.75);
}
.dot-spinner__dot:nth-child(4) {
transform: rotate(135deg);
}
.dot-spinner__dot:nth-child(4)::before {
animation-delay: calc(var(--uib-speed) * -0.625);
}
.dot-spinner__dot:nth-child(5) {
transform: rotate(180deg);
}
.dot-spinner__dot:nth-child(5)::before {
animation-delay: calc(var(--uib-speed) * -0.5);
}
.dot-spinner__dot:nth-child(6) {
transform: rotate(225deg);
}
.dot-spinner__dot:nth-child(6)::before {
animation-delay: calc(var(--uib-speed) * -0.375);
}
.dot-spinner__dot:nth-child(7) {
transform: rotate(270deg);
}
.dot-spinner__dot:nth-child(7)::before {
animation-delay: calc(var(--uib-speed) * -0.25);
}
.dot-spinner__dot:nth-child(8) {
transform: rotate(315deg);
}
.dot-spinner__dot:nth-child(8)::before {
animation-delay: calc(var(--uib-speed) * -0.125);
}
@keyframes pulse0112 {
0%,
100% {
transform: scale(0);
opacity: 0.5;
}
50% {
transform: scale(1);
opacity: 1;
}
}

View File

@@ -1,7 +1,8 @@
import { Box, Spinner, Text } from "@chakra-ui/react"; import { Box, Spinner, Text } from "@chakra-ui/react";
import React from "react"; import React from "react";
import './FullscreenLoaders.css'
const FullscreenLoaders = () => { const FullscreenLoaders = ({height}) => {
return ( return (
<Box <Box
display={"flex"} display={"flex"}
@@ -9,16 +10,19 @@ const FullscreenLoaders = () => {
flexDirection={'column'} flexDirection={'column'}
alignItems={"center"} alignItems={"center"}
w={"100%"} w={"100%"}
h={"100vh"} h={height ? height: "100vh"}
gap={4} gap={4}
><Spinner ><div className="dot-spinner">
thickness='3px' <div className="dot-spinner__dot"></div>
speed='0.65s' <div className="dot-spinner__dot"></div>
emptyColor='green.100' <div className="dot-spinner__dot"></div>
color='#004717' <div className="dot-spinner__dot"></div>
size='lg' <div className="dot-spinner__dot"></div>
/> <div className="dot-spinner__dot"></div>
<Text color='#004717' fontSize={'md'} fontWeight={500}>Loading...</Text> <div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
</div>
{/* <Text color='#004717' fontSize={'md'} fontWeight={500}>Loading...</Text> */}
</Box> </Box>
); );
}; };

View File

@@ -1,12 +1,18 @@
import React from "react"; import React from "react";
import './FullscreenLoaders.css'
const Loader01 = () => { const Loader01 = () => {
return ( return (
<div className="lds-ellipsis ">
<div></div> <div className="dot-spinner">
<div></div> <div className="dot-spinner__dot"></div>
<div></div> <div className="dot-spinner__dot"></div>
<div></div> <div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
</div> </div>
); );
}; };

View File

@@ -0,0 +1,460 @@
import {
Box,
Button,
Heading,
HStack,
Image,
Modal,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Progress,
Spinner,
Stack,
Text,
} from "@chakra-ui/react";
import React, { useEffect, useState } from "react";
import Mobile from "../assets/mobileWing.png";
import mobileBanner from "../assets/welcome.avif";
import { GrDownload } from "react-icons/gr";
import { LuClock } from "react-icons/lu";
import { GiNetworkBars } from "react-icons/gi";
import { GrLinkedinOption } from "react-icons/gr";
import { FiInstagram } from "react-icons/fi";
import { IoBatteryHalf } from "react-icons/io5";
import { BiWifi } from "react-icons/bi";
import { useGetIOByIdQuery } from "../Services/io.service";
import { useNavigate, useParams } from "react-router-dom";
import FullscreenLoaders from "./Loaders/FullscreenLoaders";
import { formatDate } from "../Constants/Constants";
import { BsFileText } from "react-icons/bs";
const MobileView = ({ isOpen, onClose, finalRef, actionId }) => {
const [time, setTime] = useState(new Date());
const navigate = useNavigate();
const params = useParams();
const id = actionId;
const {
data: IObyID,
isLoading: IObyIDisLoading,
error: IObyIDerror,
} = useGetIOByIdQuery(id, { skip: !id });
console.log(IObyID);
const keyMerits = IObyID?.data?.keyMerits || [];
const artifactsImage = IObyID?.data?.artifactsImage || [];
useEffect(() => {
const timer = setInterval(() => {
setTime(new Date());
}, 1000);
return () => clearInterval(timer);
}, []);
const formatTime = (date) => {
return date.toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
hour12: true,
});
};
return (
<Modal
display={"flex"}
size={"xl"}
justifyContent={"center"}
isCentered
finalFocusRef={finalRef}
isOpen={isOpen}
onClose={onClose}
>
<ModalOverlay
backdropFilter="blur(5px)" // Add this line for backdrop blur
bg="rgba(0, 0, 0, 0.4)" // Optional: Adjust the overlay color and opacity
/>
<ModalContent backgroundColor={"transparent"} shadow={"none"}>
<HStack w={"100"} display={"flex"} justify={"center"}>
<Box
as="span"
boxShadow={"none"}
position={"relative"}
display={"flex"}
justifyContent={"center"}
h={"600px"}
w={"320px"}
sx={{
"@media (max-width: 2024px)": {
height:"695px",
width:"360px",
},
"@media (max-width: 1440px)": {
height:"600px",
width:"320px",
},
}}
>
<Image
h={"100%"}
w={"100%"}
src={Mobile}
position={"absolute"}
top={"0"}
left={"0"}
/>
<Box
backgroundColor={"#fff"}
h={"98%"}
w={"96%"}
// m={2}
borderRadius={"47px"}
pt={"36px"}
px={"15px"}
>
{IObyIDisLoading ? (
<Box
display={"flex"}
justifyContent={"center"}
alignItems={"center"}
h={"100%"}
>
<Spinner
thickness='3px'
color='purple.900'
size='lg'
/>
</Box>
) : (
<>
<Box>
<Box
display={"flex"}
alignItems={"center"}
position={"absolute"}
left={"30px"}
top={"18px"}
>
<Text ml={1} mb={0}>
<GiNetworkBars fontSize={"10px"} />
</Text>
<Text ml={1} mb={0} fontSize={"10px"}>
{formatTime(time)}
</Text>
<Text ml={"5px"} mb={0}>
<GrLinkedinOption fontSize={"10px"} />
</Text>
{/* <Text ml={1} mb={0}><FiInstagram fontSize={"10px"} /></Text> */}
</Box>
<Box
display={"flex"}
alignItems={"center"}
position={"absolute"}
right={"36px"}
top={"17px"}
>
<Text mb={0}>
<BiWifi fontSize={"14px"} />
</Text>
<Text ml={1} mb={0}>
<IoBatteryHalf fontSize={"15px"} />
</Text>
</Box>
</Box>
<Box
p={"10px"}
overflowY={"scroll"}
h={"483px"}
zIndex={"99"}
position={"relative"}
borderBottomLeftRadius={"23px"}
borderBottomRightRadius={"23px"}
sx={{
"@media (max-width: 2024px)": {
height:"575px",
},
"@media (max-width: 1440px)": {
height:"483px",
},
}}
>
<Box
mb={4}
bg={"#f5f8f6"}
borderRadius={"20px"}
boxShadow={"rgba(0, 0, 0, 0.15) 0px 2px 8px"}
>
<Box position={"relative"}>
<Text
position={"absolute"}
top={"12px"}
left={"10px"}
backgroundColor={"#e4f6ea"}
fontSize={"10px"}
fontWeight={500}
color="green"
p={"7px 12px"}
borderRadius={"20px"}
>
Stock
</Text>
<Text
position={"absolute"}
top={"12px"}
right={"10px"}
fontSize={"10px"}
display={"flex"}
alignItems={"center"}
fontWeight={500}
backgroundColor={"#fff"}
p={"7px 12px"}
borderRadius={"20px"}
>
<LuClock color="#d8804e" />{" "}
<Text mb={0} ml={1}>
Closing Date {formatDate(IObyID?.data?.closingDate)}
</Text>
</Text>
{artifactsImage?.[0]?.artifactPathName && (
<Image
borderTopLeftRadius={"20px"}
borderTopRightRadius={"20px"}
h={"130px"}
w={"100%"}
src={
"https://tanami.betadelivery.com/" +
artifactsImage[0]?.artifactPathName
}
/>
)}
</Box>
<Stack mt="3" bg={"#fff"} py={4} px={4}>
<Text
fontSize={"sm"}
fontWeight={"500"}
color={"#000"}
mb={0}
>
{IObyID?.data?.investmentType?.investmentTypeName}
</Text>
<Heading fontSize="16px" color={"#004717"}>
BHD {IObyID?.data?.goalAmount}
</Heading>
<Progress
colorScheme="green"
size="sm"
value={20}
borderRadius={"3px"}
/>
<Text
color={"#4e4e4e"}
fontSize={"xs"}
fontWeight={600}
mb={0}
>
0.0% funded
</Text>
<Text
fontSize={"xs"}
fontWeight={500}
mb={0}
color={"#9d9d9d"}
>
{IObyID?.data?.descriptionEnglish}
</Text>
</Stack>
<Box py={4} px={4}>
<Box display={"flex"} justifyContent={"space-between"}>
<Text
fontSize={"xs"}
mb={1}
fontWeight={500}
color={"#616161"}
>
Sponsor name:
</Text>
<Text fontSize={"xs"} mb={1} fontWeight={500}>
{IObyID?.data?.sponsor?.sponsorName}
</Text>
</Box>
<Box display={"flex"} justifyContent={"space-between"}>
<Text
fontSize={"xs"}
mb={1}
fontWeight={500}
color={"#616161"}
>
Estimated return:
</Text>
<Text fontSize={"xs"} mb={1} fontWeight={500}>
{IObyID?.data?.expectedReturn}
</Text>
</Box>
<Box display={"flex"} justifyContent={"space-between"}>
<Text
fontSize={"xs"}
mb={1}
fontWeight={500}
color={"#616161"}
>
Hoiding period:
</Text>
<Text fontSize={"xs"} mb={1} fontWeight={500}>
{IObyID?.data?.holdingPeriod}
</Text>
</Box>
<Box display={"flex"} justifyContent={"space-between"}>
<Text
fontSize={"xs"}
mb={1}
fontWeight={500}
color={"#616161"}
>
Minimum investment:
</Text>
<Text fontSize={"xs"} mb={1} fontWeight={500}>
{
IObyID?.data?.minInvestmentAmt?.[0]?.country
?.minInvestmentAmt
}
</Text>
</Box>
</Box>
</Box>
<Box
mb={4}
p={5}
bg={"#f5f8f6"}
borderRadius={"20px"}
boxShadow={"rgba(0, 0, 0, 0.15) 0px 2px 8px"}
>
<Heading fontSize="14px" fontWeight={600}>
Key Merits
</Heading>
<Box display={"flex"} alignItems={"center"}>
{keyMerits?.[0]?.icon?.iconFilePath && (
<Image
rounded={"md"}
display={"flex"}
p={1}
justifyContent={"center"}
alignItems={"center"}
src={
"https://tanami.betadelivery.com/" +
keyMerits[0].icon.iconFilePath
}
w={8}
h={8}
/>
)}
<Text fontSize={"xs"} mb={0}>
{IObyID?.data?.keyMerits[0]?.meritsDescription}
</Text>
</Box>
</Box>
<Box
mb={4}
p={5}
borderRadius={"20px"}
boxShadow={"rgba(0, 0, 0, 0.15) 0px 2px 8px"}
>
<Heading fontSize="14px" fontWeight={600}>
Investment Documents
</Heading>
<Box
bg={"#f5f8f6"}
w={"150px"}
p={3}
borderRadius={"10px"}
>
<Box display={"flex"} alignItems={"center"} mb={2}>
{/* <Image
me={1}
src="https://tanami.betadelivery.com/public/icons/icon8.svg"
/> */}
<BsFileText color="forestGreen" fontSize="18px" />
<Text fontSize={"xs"} mb={0} ml={2}>
{IObyID?.data?.documents?.[0]?.documentName}
</Text>
</Box>
<Box
display={"flex"}
alignItems={"center"}
justifyContent={"space-between"}
>
<Text mb={0} fontSize={"sm"}>
{IObyID?.data?.documents?.[0]?.documentSize}
</Text>
<GrDownload fontSize={"15px"} />
</Box>
</Box>
</Box>
<Box
mb={4}
p={4}
borderRadius={"20px"}
boxShadow={"rgba(0, 0, 0, 0.15) 0px 2px 8px"}
>
<Heading fontSize="14px" fontWeight={600}>
Videos
</Heading>
<video
autoPlay
loop
controls
style={{
borderRadius: "18px",
width: "100%",
height: "auto",
}}
>
<source
src={
IObyID?.data?.artifactsVideo?.[0]
?.artifactStreamingURL
}
type="video/mp4"
style={{ height: "200px" }}
/>
Your browser does not support the video tag.
</video>
</Box>
</Box>
<Box
position={"relative"}
p={4}
background={"#fff"}
padding={"24px"}
paddingBottom={"3px"}
borderBottomLeftRadius={"30px"}
borderBottomRightRadius="30px"
>
<Button
margin={"auto"}
width={"85%"}
bottom="10px"
left="0"
colorScheme="forestGreen"
mr={3}
w={"100%"}
fontWeight={500}
borderRadius={"20px"}
>
Invest
</Button>
</Box>
</>
)}
</Box>
</Box>
</HStack>
</ModalContent>
</Modal>
);
};
export default MobileView;

View File

@@ -1,9 +1,18 @@
import { Box, Text } from '@chakra-ui/react'; import { Box, Text } from "@chakra-ui/react";
import React from 'react'; import React, { useRef } from "react";
import audioClick from "../assets/click-151673.mp3";
const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => { const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {
// const [isSwitchOn, setIsSwitchOn] = useState(false);
const audio = useRef();
const switch_onChange_handle = () => { const switch_onChange_handle = () => {
setIsSwitchOn(!isSwitchOn); setIsSwitchOn(!isSwitchOn);
if (audio.current) {
audio.current.play();
}
}; };
return ( return (
@@ -15,7 +24,7 @@ const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {
alignItems="center" alignItems="center"
// justifyContent={isSwitchOn ? "flex-end" : "flex-start"} // justifyContent={isSwitchOn ? "flex-end" : "flex-start"}
width="90px" width="90px"
height="24px" height="25px"
borderRadius="20px" borderRadius="20px"
backgroundColor={isSwitchOn ? "#004118" : "#ef0000"} backgroundColor={isSwitchOn ? "#004118" : "#ef0000"}
onClick={switch_onChange_handle} onClick={switch_onChange_handle}
@@ -24,16 +33,28 @@ const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {
fontWeight="100" fontWeight="100"
transition="background-color 0.2s" transition="background-color 0.2s"
_before={{ _before={{
// content: '""',
// position: "absolute",
// width: "20px",
// height: "20px",
// borderRadius: "50%",
// backgroundColor: "#FFF",
// boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
// transform: isSwitchOn ? "translateX(65px)" : "translateX(0)",
// transition: "transform 0.2s",
// left:'2px'
content: '""', content: '""',
position: "absolute", position: "absolute",
width: "20px", height: "25px",
height: "20px", width: "25px",
left: "0px",
background:
"conic-gradient(rgb(104, 104, 104), white, rgb(104, 104, 104), white, rgb(104, 104, 104))",
borderRadius: "50%", borderRadius: "50%",
backgroundColor: "#FFF", transitionDuration: ".3s",
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)", boxShadow: " 5px 2px 7px rgba(8, 8, 8, 0.308)",
transform: isSwitchOn ? "translateX(65px)" : "translateX(0)", transform: isSwitchOn ? "translateX(65px)" : "translateX(0)",
transition: "transform 0.2s",
left:'2px'
}} }}
> >
<Text <Text
@@ -46,9 +67,10 @@ const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {
left={isSwitchOn ? "10px" : "auto"} left={isSwitchOn ? "10px" : "auto"}
right={isSwitchOn ? "auto" : "10px"} right={isSwitchOn ? "auto" : "10px"}
> >
{isSwitchOn ? 'Active' : 'InActive'} {isSwitchOn ? "Active" : "InActive"}
</Text> </Text>
</Box> </Box>
<audio ref={audio} src={audioClick} />
</Box> </Box>
); );
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -1,6 +1,77 @@
import dns from "node:dns" import dns from "node:dns"
export function getTomorrowDate() {
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
// Format the date as YYYY-MM-DD (ISO 8601)
return tomorrow.toISOString().split('T')[0];
}
export function removeTrailingZeros(value) {
// Convert the value to a number and then to a string
let number = parseFloat(value);
let result = number.toString();
// Check if the result contains a decimal point
if (result.includes('.')) {
// Remove trailing zeros if the decimal part is 0 or 00
result = result.replace(/(\.\d*?)0+$/, '$1'); // Remove trailing zeros
result = result.replace(/\.$/, ''); // Remove the decimal point if it's the last character
}
return result;
}
export function getCountdownTimer(utcDateString) {
// Parse the UTC datetime string into a Date object
const targetDate = new Date(utcDateString);
const now = new Date();
// Calculate the difference in milliseconds
const difference = targetDate - now;
if (difference <= 0) {
return 'The time has passed or is now!';
}
// Convert the difference from milliseconds to a more readable format
const seconds = Math.floor(difference / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const remainingDays = days;
const remainingHours = hours % 24;
const remainingMinutes = minutes % 60;
const remainingSeconds = seconds % 60;
return `${remainingDays === 0 ? "": remainingDays+"d"} ${remainingHours === 0 ? "": remainingHours+"h"} ${remainingMinutes}m `;
}
export function startCountdown(utcDateString) {
// Function to update the countdown
const updateCountdown = () => {
const countdown = getCountdownTimer(utcDateString);
console.log(countdown);
};
// Update countdown immediately
updateCountdown();
// Set up interval to update countdown every minute (60000 milliseconds)
setInterval(updateCountdown, 60000);
}
export const getFileNameFromPath = (filePath) => { export const getFileNameFromPath = (filePath) => {
const parts = filePath?.split("/"); const parts = filePath?.split("/");
return parts?.[parts?.length - 1]; return parts?.[parts?.length - 1];
@@ -42,3 +113,27 @@ export async function checkEmailValidity(email) {
return false; // Error occurred return false; // Error occurred
} }
} }
// Function to convert timestamp to readable date format in Gulf timezone
export function formatTimestampInGulfTimezone(timestamp) {
const date = new Date(timestamp);
const options = {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
timeZone: 'Asia/Dubai', // Gulf Standard Time (GST) timezone
timeZoneName: 'short'
};
return date.toLocaleDateString('en-GB', options);
}
export function formatDate(dateString) {
const options = { year: 'numeric', month: 'short', day: 'numeric' };
const date = new Date(dateString);
return date.toLocaleDateString('en-US', options);
}

View File

@@ -46,7 +46,6 @@ const GlobalStateProvider = ({ children }) => {
const [slideFromRight, setSlideFormRight] = useState(false); const [slideFromRight, setSlideFormRight] = useState(false);
const { colorMode, toggleColorMode } = useColorMode(); const { colorMode, toggleColorMode } = useColorMode();
const [sponser, setSponser] = useState([]); const [sponser, setSponser] = useState([]);
const [ioStatus, setIoStatus] = useState([]);
const [investors, setInvestors] = useState([ const [investors, setInvestors] = useState([
{ {
@@ -1450,7 +1449,6 @@ const GlobalStateProvider = ({ children }) => {
}, },
]); ]);
const [IODetails, setIODetails] = useState({});
const [depositRequest, setDepositRequest] = useState([ const [depositRequest, setDepositRequest] = useState([
{ {
@@ -1724,6 +1722,17 @@ const GlobalStateProvider = ({ children }) => {
}, },
]); ]);
// ==============[ prod state ]===============================
const [IODetails, setIODetails] = useState(null);
const [ isIOloading, setIOloading ] = useState(false)
return ( return (
<GlobalStateContext.Provider <GlobalStateContext.Provider
value={{ value={{
@@ -1795,8 +1804,10 @@ const GlobalStateProvider = ({ children }) => {
setAcademicDocuments, setAcademicDocuments,
iOArtifactsTwo, iOArtifactsTwo,
setIOArtifactsTwo, setIOArtifactsTwo,
ioStatus,
setIoStatus,
isIOloading,
setIOloading
}} }}
> >
{children} {children}

View File

@@ -72,6 +72,7 @@ import shield from "../assets/shield.png";
import SplashScreen from "../Pages/SplashScreen"; import SplashScreen from "../Pages/SplashScreen";
import CutomBreadcrumb from "../Components/CutomBreadcrumb"; import CutomBreadcrumb from "../Components/CutomBreadcrumb";
import CustomBreadcrumb from "../Components/CutomBreadcrumb"; import CustomBreadcrumb from "../Components/CutomBreadcrumb";
import { getCountdownTimer } from "../Constants/Constants";
const DashboardLayout = ({ isOnline }) => { const DashboardLayout = ({ isOnline }) => {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -107,7 +108,7 @@ const DashboardLayout = ({ isOnline }) => {
// Set a timer to hide the splash screen after 3 seconds // Set a timer to hide the splash screen after 3 seconds
const timer = setTimeout(() => { const timer = setTimeout(() => {
setSplashVisible(false); setSplashVisible(false);
},300); // 3000ms = 3 seconds },1000); // 3000ms = 3 seconds
// Cleanup the timer // Cleanup the timer
return () => clearTimeout(timer); return () => clearTimeout(timer);
@@ -121,6 +122,9 @@ const DashboardLayout = ({ isOnline }) => {
// dispach(loginUser(false)); // dispach(loginUser(false));
setIsAuthenticate(false); setIsAuthenticate(false);
Cookies.remove("isAuthenticated"); Cookies.remove("isAuthenticated");
localStorage.removeItem('refreshToken')
localStorage.removeItem('accessToken')
localStorage.removeItem('refreshTokenExp')
navigate("/login"); navigate("/login");
}; };
@@ -132,7 +136,7 @@ const DashboardLayout = ({ isOnline }) => {
case path.startsWith("/sponser"): case path.startsWith("/sponser"):
return ( return (
<span className="d-flex align-items-end gap-2"> <span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0" /> Sponsorer <RiMoneyDollarBoxLine className="h4 m-0" /> Sponsor
</span> </span>
); );
case path.startsWith("/investment-type"): case path.startsWith("/investment-type"):
@@ -184,6 +188,30 @@ const DashboardLayout = ({ isOnline }) => {
Investor Transactions Investor Transactions
</span> </span>
); );
case path.startsWith("/deposit-request"):
return (
<span className="d-flex align-items-end gap-2">
<RiMoneyDollarBoxLine className="h4 m-0 fw-normal" />
Deposite pending request
</span>
);
case path.startsWith("/deposit-history"):
return (
<span className="d-flex align-items-end gap-2">
<RiExchangeBoxLine className="h4 m-0 fw-normal" />
Deposite withdrawal request
</span>
);
case path.startsWith("/withdraw-request"): case path.startsWith("/withdraw-request"):
return ( return (
<span className="d-flex align-items-end gap-2"> <span className="d-flex align-items-end gap-2">
@@ -387,7 +415,7 @@ const DashboardLayout = ({ isOnline }) => {
// onMouseOver={() => setIsDrawerOpen(true)} // onMouseOver={() => setIsDrawerOpen(true)}
// onMouseLeave={() => setIsDrawerOpen(false)} // onMouseLeave={() => setIsDrawerOpen(false)}
style={{ style={{
width: isDrawerOpen || openDrawerClick ? 232 : 74, width: isDrawerOpen || openDrawerClick ? 230 : 74,
transition: "width 0.3s ease-in-out", // Smooth transition for width change transition: "width 0.3s ease-in-out", // Smooth transition for width change
// overflow: "hidden", // overflow: "hidden",
backgroundColor: "#0041180A", backgroundColor: "#0041180A",
@@ -400,16 +428,18 @@ const DashboardLayout = ({ isOnline }) => {
isDrawerOpen || openDrawerClick isDrawerOpen || openDrawerClick
? "justify-content-start" ? "justify-content-start"
: "justify-content-center" : "justify-content-center"
} p-3 pt-3 pb-4 position-relative `} } p-3 pt-3 pb-3 position-relative `}
height={"10%"} height={"10%"}
> >
{isDrawerOpen || openDrawerClick ? ( {isDrawerOpen || openDrawerClick ? (
<Image <Image
style={{ style={{
width: 120, width: 110,
}} }}
src={colorMode === "light" ? logo : logoDark} src={colorMode === "light" ? logo : logoDark}
alt="Logo" alt="Logo"
onClick={()=> navigate('/')}
cursor={"pointer"}
/> />
) : ( ) : (
<Image <Image
@@ -418,12 +448,14 @@ const DashboardLayout = ({ isOnline }) => {
}} }}
src={colorMode === "light" ? logoMini : logoMiniDark} src={colorMode === "light" ? logoMini : logoMiniDark}
alt="Logo" alt="Logo"
onClick={()=> navigate('/')}
cursor={"pointer"}
/> />
)} )}
</div> </div>
<Box <Box
className="ps-2 scroll-bar pe-1" className="ps-2 scroll-bar pe-1 pt-3"
style={{ style={{
height: "90%", height: "90%",
overflowY: "scroll", overflowY: "scroll",
@@ -594,7 +626,7 @@ const DashboardLayout = ({ isOnline }) => {
</Accordion> </Accordion>
</Box> </Box>
<Button {/* <Button
colorScheme={"forestGreen"} colorScheme={"forestGreen"}
rounded={"lg"} rounded={"lg"}
// onMouseOver={() => setIsDrawerOpen(true)} // onMouseOver={() => setIsDrawerOpen(true)}
@@ -614,20 +646,16 @@ const DashboardLayout = ({ isOnline }) => {
) : ( ) : (
<ArrowRightIcon className="web-text-small " /> <ArrowRightIcon className="web-text-small " />
)} )}
</Button> </Button> */}
<Text textAlign={'center'} fontWeight={500} fontSize={'xs'} color={"gray.600"}>{getCountdownTimer(localStorage.getItem('accessTokenExp'))}</Text>
<Box
id="google_translate_element"
display="block"
className="bg-danger"
/>
</aside> </aside>
)} )}
<main <main
className={`h-100 ${slideFromRight ? "pe-3" : "ps-3"} d-flex flex-column gap-0`} className={`h-100 ${slideFromRight ? "pe-3" : "ps-3"} d-flex flex-column gap-0`}
style={{ style={{
width: `calc(100% - ${isDrawerOpen || openDrawerClick ? 232 : 74}px)`, width: `calc(100% - ${isDrawerOpen || openDrawerClick ? 230 : 74}px)`,
transition: "width 0.3s ease-in-out", transition: "width 0.3s ease-in-out",
}} }}

View File

@@ -64,7 +64,6 @@ const BankDetails = () => {
error, error,
} = useGetBankQuery({ page: 1, size: 10 }); } = useGetBankQuery({ page: 1, size: 10 });
console.log(bankDetails?.data);
useEffect(() => { useEffect(() => {
// Simulate loading // Simulate loading
@@ -115,8 +114,7 @@ const BankDetails = () => {
return nameMatches; return nameMatches;
}); });
console.log(bankDetails);
const extractedArray = filteredData?.map((item) => ({ const extractedArray = filteredData?.map((item) => ({
id: item?.id, id: item?.id,

View File

@@ -10,6 +10,7 @@ import {
Textarea, Textarea,
Button, Button,
Text, Text,
useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/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";
@@ -19,8 +20,9 @@ import { v4 as uuidv4 } from "uuid";
import GlobalStateContext from "../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../Contexts/GlobalStateContext";
import { OPACITY_ON_LOAD } from "../../Layout/animations"; import { OPACITY_ON_LOAD } from "../../Layout/animations";
import FormInputMain from "../../Components/FormInputMain"; import FormInputMain from "../../Components/FormInputMain";
import { useGetContactQuery } from "../../Services/contact.service"; import { useGetContactQuery, useUpdateContactMutation } from "../../Services/contact.service";
import FullscreenLoaders from "../../Components/Loaders/FullscreenLoaders"; import FullscreenLoaders from "../../Components/Loaders/FullscreenLoaders";
import ToastBox from "../../Components/ToastBox";
export const addSponser = yup.object().shape({ export const addSponser = yup.object().shape({
phoneNumber: yup.string().required("Phone Number is required"), phoneNumber: yup.string().required("Phone Number is required"),
@@ -37,8 +39,10 @@ export function debounce(func, delay) {
} }
const Contact = () => { const Contact = () => {
const toast = useToast()
const navigate = useNavigate(); const navigate = useNavigate();
const [form, setForm] = useState({}); const [form, setForm] = useState({});
const [ isLoading, setIsLoading ] = useState(false)
// const { sponser, setSponser } = useContext(GlobalStateContext); // const { sponser, setSponser } = useContext(GlobalStateContext);
const { const {
@@ -50,22 +54,21 @@ const Contact = () => {
resolver: yupResolver(addSponser), resolver: yupResolver(addSponser),
}); });
console.log(errors);
const { const {
data: contact, data: contact,
isLoading: contactLoading, isLoading: contactLoading,
error, error,
} = useGetContactQuery({ page: 1, size: 10 }); } = useGetContactQuery();
const [ updateContact ] = useUpdateContactMutation()
console.log(contact?.data);
useEffect(() => { useEffect(() => {
if (contact) { if (contact) {
reset({ reset({
phoneNumber: contact.phoneNumber, phoneNumber: contact?.data[0]?.phoneNumber,
emailAddress: contact.emailAddress, emailAddress: contact?.data[0]?.emailAddress,
websiteUrl: contact.websiteUrl, websiteUrl: contact?.data[0]?.websiteUrl,
}); });
} }
}, [contact, reset]); }, [contact, reset]);
@@ -82,7 +85,7 @@ const Contact = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "Add Details",
defaultValue: contact?.phoneNumber || "", // value: contact?.phoneNumber || "",
}, },
{ {
label: "E-mail ID", label: "E-mail ID",
@@ -91,7 +94,7 @@ const Contact = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "Add Details",
defaultValue: contact?.emailAddress || "", // value: contact?.emailAddress || "",
}, },
{ {
label: "Website URL", label: "Website URL",
@@ -100,7 +103,7 @@ const Contact = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "Add Details",
defaultValue: contact?.websiteUrl || "", // value: contact?.websiteUrl || "",
}, },
]; ];
@@ -113,11 +116,25 @@ const Contact = () => {
return groups; return groups;
}, {}); }, {});
const onSubmit = (data) => { const onSubmit = async (data) => {
if (!Object.keys(errors).length) { setIsLoading(true)
setForm(data); try {
setAlert(true); const res = await updateContact(data)
if (res?.data?.statusCode === 200) {
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
setIsLoading(false)
}
} catch (error) {
console.log(error);
setIsLoading(false)
} }
}; };
return ( return (
@@ -127,6 +144,7 @@ const Contact = () => {
control={control} control={control}
errors={errors} errors={errors}
onSubmit={handleSubmit(onSubmit)} onSubmit={handleSubmit(onSubmit)}
btnLoading={isLoading}
/> />
</Box> </Box>
); );

162
src/Pages/Dashbaord.jsx Normal file
View File

@@ -0,0 +1,162 @@
import { Box, HStack, Icon, position, Text, VStack } from '@chakra-ui/react'
import React from 'react'
import { HiOutlineChartSquareBar } from 'react-icons/hi'
import { RiMoneyDollarBoxLine } from 'react-icons/ri'
import { TbTransactionDollar } from 'react-icons/tb'
import { VscSymbolClass } from 'react-icons/vsc'
import { TABLE_PAGINATION } from '../Constants/Paginations'
import FullscreenLoaders from '../Components/Loaders/FullscreenLoaders'
import { useGetIOprepopulateDataQuery, useGetIOsQuery } from '../Services/io.service'
import { useGetInvestorsQuery } from '../Services/investor.details.service'
import DonutChart from '../Components/Doughnut/DonutChart'
import { GoDotFill } from "react-icons/go";
import { useNavigate } from 'react-router-dom'
import LineChart from '../Components/Doughnut/LineChart'
import { PiChartLineUpDuotone } from 'react-icons/pi'
import ApexChart from '../Components/Doughnut/ApexDonut'
import ApexLine from '../Components/Doughnut/ApexLine'
import ReactApexChart from 'react-apexcharts'
import { BsGraphUpArrow } from "react-icons/bs";
const Dashbaord = () => {
const navigate = useNavigate()
const { data, isLoading: isIoPreLoading } = useGetIOprepopulateDataQuery();
const { data: IO, isLoading: isIoLoading } = useGetIOsQuery({ page: TABLE_PAGINATION?.page, size: TABLE_PAGINATION?.size });
const { data: investorDetails, isInvestorLoading } = useGetInvestorsQuery({ page: TABLE_PAGINATION?.page, size: TABLE_PAGINATION?.size });
const sortArrayByStatus = () => {
const sortedArrays = {
open: [],
closed: [],
processing: [],
draft: []
};
IO?.data?.rows.forEach(item => {
const status = item.ioStatus?.statusAdmin;
if (status === 'Open') {
sortedArrays.open.push(item);
} else if (status === 'Closed') {
sortedArrays.closed.push(item);
} else if (status === 'Processing') {
sortedArrays.processing.push(item);
} else if (status === 'Draft') {
sortedArrays.draft.push(item);
}
});
return sortedArrays;
};
const statusData = sortArrayByStatus()
const chartData = {
labels: ['Draft', 'Open', 'Processing', 'Closed',],
backgroundColor: ['#3182ce', '#004118', '#D69E2E', '#E53E3E'],
values: [statusData?.draft?.length, statusData?.open?.length, statusData?.processing?.length, statusData?.closed?.length]
};
const series1= [{
data: [25, 66, 41, 89, 63, 25, 44, 12, 36, 9, 54]
}]
const options1= {
chart: {
type: 'line',
position:"absolute",
right:0,
width: 100,
height: 35,
sparkline: {
enabled: true
}
},
tooltip: {
fixed: {
enabled: false
},
x: {
show: false
},
y: {
title: {
formatter: function (seriesName) {
return ''
}
}
},
marker: {
show: false
}
}
}
return (
isIoPreLoading || isIoLoading || isInvestorLoading ? <FullscreenLoaders /> :
<Box height={'100vh'} bg={'#fff'} roundedTop={0} pt={5} overflowX={"hidden"}>
<Box display={'flex'} gap={6} w={'100%'} pt={3} pb={3} p={3} >
<Box position={'relative'} cursor={'pointer'} onClick={() => navigate("/investor-details")} boxShadow={'lg'} color={"#004118"} p={4} rounded={'xl'} w={'25%'} display={'flex'} bg={'#f5f8f6'} flexDirection={'column'} alignItems={'start'} >
<Icon left={"10px"} bg={'#004118'} rounded={9} p={2} color={"#fff"} as={TbTransactionDollar} mb={6} boxSize={12} />
<Text as={'span'} fontSize={'xs'} fontWeight={500}>Total Investors</Text>
<Text as={'span'} fontSize={'32px'} fontWeight={600}>{investorDetails?.data?.totalItems}</Text>
<Icon position={'absolute'} right={6} bottom={6} boxSize={8} as={BsGraphUpArrow} />
{/* <ReactApexChart position={'absolute'} right={6} bottom={6} options={options1} series={series1} type="line" height={35} width={100} /> */}
</Box>
<Box position={'relative'} cursor={'pointer'} onClick={() => navigate("/view-io")} boxShadow={'lg'} bg={'#f5f8f6'} color={"#004118"} p={3} rounded={'xl'} w={'25%'} display={'flex'} flexDirection={'column'} alignItems={'start'} >
<Icon bg={'#004118'} rounded={9} p={2} color={"#fff"} as={HiOutlineChartSquareBar} mb={6} boxSize={12} />
<Text as={'span'} fontSize={'xs'} fontWeight={500}>Total IO</Text>
<Text as={'span'} fontSize={'32px'} fontWeight={600}>{IO?.data?.totalItems}</Text>
<Icon position={'absolute'} right={6} bottom={6} boxSize={8} as={BsGraphUpArrow} />
</Box>
<Box position={'relative'} cursor={'pointer'} onClick={() => navigate("/sponser")} boxShadow={'lg'} bg={'#f5f8f6'} color={"#004118"} p={3} rounded={'xl'} w={'25%'} display={'flex'} flexDirection={'column'} alignItems={'start'} >
<Icon bg={'#004118'} rounded={9} p={2} color={"#fff"} as={RiMoneyDollarBoxLine} mb={6} boxSize={12} />
<Text as={'span'} fontSize={'xs'} fontWeight={500}>Total sponors</Text>
<Text as={'span'} fontSize={'32px'} fontWeight={600}>{data?.data?.sponsor?.length}</Text>
<Icon position={'absolute'} right={6} bottom={6} boxSize={8} as={BsGraphUpArrow} />
</Box>
<Box position={'relative'} cursor={'pointer'} onClick={() => navigate("/investment-type")} boxShadow={'lg'} bg={'#f5f8f6'} color={"#004118"} p={3} rounded={'xl'} w={'25%'} display={'flex'} flexDirection={'column'} alignItems={'start'} >
<Icon bg={'#004118'} rounded={9} p={2} color={"#fff"} as={VscSymbolClass} mb={6} boxSize={12} />
<Text as={'span'} fontSize={'xs'} fontWeight={500}>Total Investment Type</Text>
<Text as={'span'} fontSize={'32px'} fontWeight={600}>{data?.data?.investmentType?.length}</Text>
<Icon position={'absolute'} right={6} bottom={6} boxSize={8} as={BsGraphUpArrow} />
</Box>
</Box>
<Box h={'70%'} w={"100%"} display={'flex'} pe={4} mt={2}>
<Box w={'60%'} h={'100%'} p={4} pe={6} pt={1} >
<Box position={'relative'} h={'100%'} boxShadow={'lg'} display={'flex'} justifyContent={'center'} rounded={'xl'} p={5} ps={0} pe={0}>
{/* <Text position={'absolute'} top={0} left={6} as={'span'} fontSize={'sm'}>Exchange rate currency</Text> */}
{/* <LineChart /> */}
<ApexLine/>
</Box>
</Box>
<Box boxShadow={'lg'} position={"relative"} bg={'#fff'} rounded={'xl'} w={'40%'} display={'flex'} justifyContent={'space-between'} flexDirection={'column'} h={"95%"} mt={1} p={4}>
<Text as={'span'} fontSize={'sm'}>IO Status</Text>
<Box display={'flex'} w={'100%'} h={'100%'} alignItems={'center'} justifyContent={'space-around'} >
{/* <Box display={'flex'} w={'70%'} alignItems={'center'} h={325} p={6}> */}
{/* <DonutChart data={chartData} /> */}
<ApexChart data={chartData} />
{/* </Box> */}
<VStack alignItems={'start'} justifyContent={'center'} flexWrap={'wrap'}>
{chartData?.labels?.map((item, index) => <Text key={index} as={'span'} display={'flex'} gap={0.5} alignItems={'center'} fontSize={'sm'} fontWeight={600}><GoDotFill color={chartData?.backgroundColor[index]} fontSize={30} />{item}</Text>)}
</VStack>
</Box>
</Box>
</Box>
</Box>
)
}
export default Dashbaord

View File

@@ -31,6 +31,11 @@ import ToastBox from "../../../Components/ToastBox";
import DataTable from "../../../Components/DataTable/DataTable"; import DataTable from "../../../Components/DataTable/DataTable";
import DepositRequestApprove from "./DepositRequestApprove"; import DepositRequestApprove from "./DepositRequestApprove";
import DepositRequestReject from "./DepositRequestReject"; import DepositRequestReject from "./DepositRequestReject";
import NormalTable from "../../../Components/DataTable/NormalTable";
import { useGetDepositRequestQuery } from "../../../Services/deposit.request.service";
import { current } from "@reduxjs/toolkit";
import { TABLE_PAGINATION } from "../../../Constants/Paginations";
import { removeTrailingZeros } from "../../../Constants/Constants";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
@@ -42,7 +47,7 @@ const DepositRequest = () => {
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [deleteAlert, setDeleteAlert] = useState(false); const [deleteAlert, setDeleteAlert] = useState(false);
const [actionId, setActionId] = useState(false); const [actionId, setActionId] = useState("");
const [mouseEntered, setMouseEntered] = useState(false); const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState(""); const [mouseEnteredId, setMouseEnteredId] = useState("");
const { const {
@@ -56,30 +61,27 @@ const DepositRequest = () => {
onClose: onRejectClose, onClose: onRejectClose,
} = useDisclosure(); } = useDisclosure();
useEffect(() => { const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
// Simulate loading const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page);
const timer = setTimeout(() => {
setIsLoading(false); const {
}, 1500); data,
isLoading: depositRequestLoading,
error,
} = useGetDepositRequestQuery({ page: currentPage, size: pageSize });
// Cleanup the timer on component unmount
return () => clearTimeout(timer);
}, []);
// ====================================================[Table Setup]================================================================ // ====================================================[Table Setup]================================================================
const tableHeadRow = [ const tableHeadRow = [
"Sr.no", // "Sr.no",
"Date",
"Client ID", "Client ID",
"First Name", "First Name",
"Last Name", "Last Name",
"Country", "Country",
"Phone Number", "Phone Number",
"Currency",
"Deposit Amount",
"Fees",
"Total Amount",
"Amount in Investor currency", "Amount in Investor currency",
"Deposit Date",
"Action", "Action",
]; ];
@@ -96,14 +98,14 @@ const DepositRequest = () => {
}); });
}, 300); }, 300);
// ====================================================[Table Filter]================================================================ const filteredData = data?.data?.rows
const filteredData = depositRequest.filter((item) => { .filter((item) => {
// Filter by name (case insensitive) // Filter by name (case insensitive)
const name = item.clientId; const name = [item.firstName, item.lastName, item.countryName].filter(Boolean).join(' ');
const searchLower = searchTerm.toLowerCase(); const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower); const nameMatches = name.toLowerCase().includes(searchLower);
// Filter by status // Filter by status (Uncomment and use if needed)
// const status = item.status; // const status = item.status;
// const statusLower = status ? "active" : "inactive"; // const statusLower = status ? "active" : "inactive";
@@ -113,162 +115,146 @@ const DepositRequest = () => {
// (statusFilter === "inactive" && status === false); // (statusFilter === "inactive" && status === false);
return nameMatches; return nameMatches;
}); })
.sort((b, a) => new Date(a.createdAt) - new Date(b.createdAt));
const [extractedArray, setExtractedArray] = useState( console.log(data?.data?.rows);
filteredData?.map((item, index) => ({
// id: item?.id,
"Sr.no": ( const extractedArray = filteredData?.map((item, index) => ({
<Text // id: item?.id,
w={"30px"} "Sr.no": (
justifyContent={slideFromRight ? "right" : "left"} <Text
as={"span"} w={"30px"}
color={"teal.900"} justifyContent={slideFromRight ? "right" : "left"}
fontWeight={"500"} as={"span"}
className="d-flex align-items-center web-text-small" color={"teal.900"}
> fontWeight={"500"}
{index + 1} className="d-flex align-items-center web-text-small"
>
{index + 1}
</Text>
),
"Client ID": (
<Text
w={"60px"}
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item?.clientReference_id}
</Text>
),
"First Name": (
<Box isTruncated={true} w={"70px"}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.firstName}
</Text> </Text>
), </Box>
Date: ( ),
<Text "Last Name": (
w={"60px"} <Box w={"70px"} isTruncated={true}>
justifyContent={slideFromRight ? "right" : "left"} <Text as={"span"} color={"teal.900"}>
as={"span"} {item?.lastName}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.date}
</Text> </Text>
), </Box>
"Client ID": ( ),
<Text Country: (
w={"60px"} <Box w={"100px"} isTruncated={true}>
justifyContent={slideFromRight ? "right" : "left"} <Text as={"span"} color={"teal.900"}>
as={"span"} {item?.countryName}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.clientId}
</Text> </Text>
), </Box>
"First Name": ( ),
<Box isTruncated={true} w={"50px"}> "Phone Number": (
<Text as={"span"} color={"teal.900"} fontWeight={"500"}> <Box w={"80px"} isTruncated={true}>
{item.firstName} <Text as={"span"} color={"teal.900"}>
</Text> {item?.mobileNumber}
</Box> </Text>
), </Box>
"Last Name": ( ),
<Box w={"50px"} isTruncated={true}> "Amount in Investor currency": (
<Text as={"span"} color={"teal.900"}> <Box display={'flex'} justifyContent={'end'} w={"100px"} isTruncated={true}>
{item.lastName} <Text as={"span"} color={"teal.900"}>
</Text> {/* {formatCurrency(removeTrailingZeros(item?.investorAmount))} */}
</Box> {parseFloat(item?.investorAmount||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
), <Badge ms={1} colorScheme="green">{item?.currencyCode}</Badge>
Country: ( </Text>
<Box w={"70px"} isTruncated={true}> </Box>
<Text as={"span"} color={"teal.900"}> ),
{item.country} "Deposit Date": (
</Text> <Text
</Box> w={"60px"}
), justifyContent={slideFromRight ? "right" : "left"}
"Phone Number": ( as={"span"}
<Box w={"70px"} isTruncated={true}> color={"teal.900"}
<Text as={"span"} color={"teal.900"}> fontWeight={"500"}
{item.phoneNumber} className="d-flex align-items-center web-text-small"
</Text> >
</Box> {formatDate(item?.createdAt)}
), </Text>
Currency: ( ),
<Box w={"50px"} isTruncated={true}> Action: (
<Text as={"span"} color={"teal.900"}> <Box display={"flex"} justifyContent={"center"} gap={2}>
<Badge px={2} py={1}> <Tooltip
{item.currency} rounded={"sm"}
</Badge> fontSize={"xs"}
</Text> label="Approve"
</Box> bg="#fff"
), color={"green.500"}
"Deposit Amount": ( placement="left-start"
<Box w={"50px"} isTruncated={true}> >
<Text as={"span"} color={"teal.900"}> <Button
{item.depositAmount} // colorScheme="forestGreen"
</Text> // color="green.500"
</Box>
),
Fees: (
<Box w={"auto"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.fees}
</Text>
</Box>
),
"Total Amount": (
<Box w={"auto"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.totalAmount}
</Text>
</Box>
),
"Amount in Investor currency": (
<Box w={"70px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.amountcurrency}
</Text>
</Box>
),
Action: (
<Box display={"flex"} justifyContent={"space-around"} gap={2}>
<Tooltip
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} size={"xs"}
label="Approve" textTransform={"inherit"}
bg="#fff" fontWeight={500}
color={"green.500"} px={2}
placement="left-start" py={1}
onClick={() => {
setActionId(item.id);
onConfirmOpen();
}}
colorScheme="green"
variant={"solid"}
cursor={"pointer"}
> >
<Badge <CheckIcon fontSize={"12px"} />
colorScheme="forestGreen" </Button>
color="green.500" </Tooltip>
rounded={"sm"} <Tooltip
size={"xs"} rounded={"sm"}
textTransform={"inherit"} fontSize={"xs"}
fontWeight={500} label="Reject"
px={2} bg="#fff"
py={1} color={"red.500"}
onClick={onConfirmOpen} placement="left-start"
> >
<CheckIcon fontSize={"12px"} /> <Button
</Badge> colorScheme="red"
</Tooltip> // color="red.500"
<Tooltip
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} size={"xs"}
label="Reject" textTransform={"inherit"}
bg="#fff" fontWeight={500}
color={"red.500"} px={2}
placement="left-start" onClick={() => {
setActionId(item.id);
onRejectOpen();
}}
py={1}
// variant={"solid"}
> >
<Badge <CloseIcon fontSize={"10px"} />
colorScheme="red" </Button>
color="red.500" </Tooltip>
rounded={"sm"} </Box>
size={"xs"} ),
textTransform={"inherit"} }));
fontWeight={500}
px={2}
onClick={onRejectOpen}
py={1}
>
<CloseIcon fontSize={"10px"} />
</Badge>
</Tooltip>
</Box>
),
}))
);
const handleDelete = () => { const handleDelete = () => {
const IOtype = investmentType.filter( const IOtype = investmentType.filter(
@@ -307,17 +293,23 @@ const DepositRequest = () => {
/> />
<HStack display={"flex"} alignItems={"center"}> <HStack display={"flex"} alignItems={"center"}>
<Pagination totalItems={10} /> <Pagination
isLoading={depositRequestLoading}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalItems={data?.data?.totalItems}
/>
</HStack> </HStack>
</HStack> </HStack>
</Box> </Box>
<DataTable <NormalTable
emptyMessage={`We don't have any Investment type `} emptyMessage={`We don't have any Investment type `}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
setData={setExtractedArray}
data={extractedArray} data={extractedArray}
isLoading={isLoading} isLoading={depositRequestLoading}
viewActionId={actionId} viewActionId={actionId}
setViewActionId={setActionId} setViewActionId={setActionId}
// totalPages={10} // totalPages={10}
@@ -334,11 +326,17 @@ const DepositRequest = () => {
isLoading={isLoading} isLoading={isLoading}
/> />
<DepositRequestApprove <DepositRequestApprove
data={data?.data?.rows}
isOpen={isConfirmOpen} isOpen={isConfirmOpen}
onClose={onConfirmClose} onClose={onConfirmClose}
// firstField={firstField} id={actionId}
// firstField={firstField}
/>
<DepositRequestReject
isOpen={isRejectOpen}
onClose={onRejectClose}
id={actionId}
/> />
<DepositRequestReject isOpen={isRejectOpen} onClose={onRejectClose} />
</Box> </Box>
); );
}; };

View File

@@ -1,128 +1,226 @@
import { import {
Box, Badge,
Button, Box,
FormControl, Button,
FormLabel, FormControl,
Input, FormLabel,
Modal, Input,
ModalBody, Modal,
ModalCloseButton, ModalBody,
ModalContent, ModalCloseButton,
ModalFooter, ModalContent,
ModalHeader, ModalFooter,
ModalOverlay, ModalHeader,
Text, ModalOverlay,
useDisclosure, Text,
} from "@chakra-ui/react"; Textarea,
import React from "react"; useDisclosure,
import * as yup from "yup"; useToast,
import { yupResolver } from "@hookform/resolvers/yup"; } from "@chakra-ui/react";
import { useForm } from "react-hook-form"; import React, { useEffect, useState } from "react";
import * as yup from "yup";
export const conformModalSchema = yup.object().shape({ import { yupResolver } from "@hookform/resolvers/yup";
fees: yup.string().required("File name is required"), import { useForm } from "react-hook-form";
totalAmount: yup.string().required("File name is required"), import { useGetDepositRequestByIdQuery, useUpdateDepositRequestMutation } from "../../../Services/deposit.request.service";
import FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders";
import ToastBox from "../../../Components/ToastBox";
const FILE_TYPES = ["image/jpeg", "image/png", "image/gif"];
export const conformModalSchema = yup.object().shape({
investorAmount: yup.string().required("Investor amount is required"),
comment: yup.string().notRequired(),
supporting_FileName: yup.mixed().required("File is required"),
// .test("fileType", "Unsupported File Format", (value) => {
// return value && FILE_TYPES.includes(value.type);
// }),
});
const DepositRequestApprove = ({ isOpen, onClose, firstField, id, data:requestData }) => {
const toast = useToast()
const [file, setFile] = useState();
const [isBtnLoading , setIsBtnLoading] = useState(false)
const fileredData = requestData?.find((item)=> item?.id === id)
console.log(fileredData);
const [ updateDepositRequest ] = useUpdateDepositRequestMutation()
const {
register,
reset,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
}); });
useEffect(() => {
reset({
investorAmount:fileredData?.investorAmount
})
const DepositRequestApprove = ({ isOpen, onClose, firstField }) => {
const { }, [requestData, id])
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const onSubmit = (data) => { const onSubmit = async(data) => {
setFile(data.document[0]); setIsBtnLoading(true)
const formData = new FormData();
const newDocument = {
...data, formData.append("investorAmount", data.investorAmount);
document: data.document[0].name, // Store the document name formData.append("comment", data.comment);
status: true, const file = data.supporting_FileName["0"];
id: uuidv4(), formData.append("supporting_FileName", file);
createdAt: new Date().toISOString(),
Type: getFileIcon(file.type),
}; try {
const res = await updateDepositRequest({ id ,data: formData})
setCreate((prevCreate) => [...prevCreate, newDocument]);
onClose();
}; if (res?.error) {
toast({
const handleFileChange = (event) => { render: () => (
const selectedFile = event.target.files[0]; <ToastBox message={res?.error?.data?.message} status={"error"} />
setFile(selectedFile); ),
}; });
setIsBtnLoading(false)
return ( }else if(res?.data?.statusCode === 200) {
<Modal isOpen={isOpen} onClose={onClose} initialFocusRef={firstField}> toast({
<ModalOverlay /> render: () => (
<ModalContent pb={4}> <ToastBox message={res?.data?.message} />
<ModalHeader fontSize={"md"}>Confirm</ModalHeader> ),
<ModalCloseButton /> });
setIsBtnLoading(false)
}
} catch (error) {
}
heandleOnClose();
};
const handleFileChange = (event) => {
const selectedFile = event.target.files[0];
setFile(selectedFile);
};
const { data, isLoading } =
(id, {
skip: !id,
});
useEffect(() => {
if (data) {
reset({
investorAmount: data?.data?.investorAmount,
});
}
}, [data, reset]);
const heandleOnClose = () =>{
reset()
onClose()
}
return (
<Modal isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Confirm</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}> <Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody> <ModalBody>
<FormControl mb={4}> <FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Deposit Amount</FormLabel> <FormLabel fontSize="sm">Deposit Amount <Badge colorScheme="green">{fileredData?.currencyCode}</Badge></FormLabel>
<Input <Input
focusBorderColor='green.400' focusBorderColor="green.400"
name="fileName" name="investorAmount"
{...register("fileName")} {...register("investorAmount")}
fontSize="sm" fontSize="sm"
type="text" type="number"
size="sm" size="sm"
placeholder={"$100,000"} placeholder={"100,000"}
readOnly textAlign={"right"}
// readOnly
/> />
</FormControl> {errors.investorAmount && (
<FormControl mb={4}>
<FormLabel fontSize="sm">Fees</FormLabel>
<Input
focusBorderColor='green.400'
name="fileName"
{...register("fileName")}
fontSize="sm"
type="text"
size="sm"
placeholder={"$100,000"}
/>
{errors.fees && (
<Text fontSize="xs" color="red"> <Text fontSize="xs" color="red">
{errors.fees.message} {errors.investorAmount.message}
</Text>
)}
</FormControl>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Upload Supporting</FormLabel>
<Input
focusBorderColor="green.400"
name="supporting_FileName"
{...register("supporting_FileName")}
fontSize="sm"
type="file"
size="sm"
placeholder={"$100,000"}
className="form-control"
accept="image/*"
/>
{errors.supporting_FileName && (
<Text fontSize="xs" color="red">
{errors.supporting_FileName.message}
</Text> </Text>
)} )}
</FormControl> </FormControl>
<FormControl mb={4}> <FormControl mb={4}>
<FormLabel fontSize="sm">Total Amount</FormLabel> <FormLabel fontSize="sm">Comments</FormLabel>
<Input <Textarea
focusBorderColor='green.400' rows={5}
name="fileName" focusBorderColor="green.400"
{...register("fileName")} name="comment"
{...register("comment")}
fontSize="sm" fontSize="sm"
type="text" type="textarea"
size="sm" size="sm"
placeholder={"$100,000"} placeholder={"Enter your comments...."}
resize={"none"}
/> />
{errors.totalAmount && ( {errors.comment && (
<Text fontSize="xs" color="red"> <Text fontSize="xs" color="red">
{errors.totalAmount.message} {errors.comment.message}
</Text> </Text>
)} )}
</FormControl> </FormControl>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button colorScheme="gray" mr={3} onClick={onClose} size={'sm'} rounded={'sm'}> <Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel Cancel
</Button> </Button>
<Button colorScheme="forestGreen" variant="solid" size={'sm'} rounded={'sm'}> <Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Confirm Confirm
</Button> </Button>
</ModalFooter> </ModalFooter>
</Box> </Box>
</ModalContent> )}
</Modal> </ModalContent>
); </Modal>
}; );
};
export default DepositRequestApprove;
export default DepositRequestApprove;

View File

@@ -1,99 +1,163 @@
import { import {
Box, Box,
Button, Button,
FormControl, FormControl,
FormLabel, FormLabel,
Input, Input,
Modal, Modal,
ModalBody, ModalBody,
ModalCloseButton, ModalCloseButton,
ModalContent, ModalContent,
ModalFooter, ModalFooter,
ModalHeader, ModalHeader,
ModalOverlay, ModalOverlay,
Text, Text,
Textarea, Textarea,
useDisclosure, useDisclosure,
} from "@chakra-ui/react"; useToast,
import React from "react"; } from "@chakra-ui/react";
import * as yup from "yup"; import React, { useEffect, useState } from "react";
import { yupResolver } from "@hookform/resolvers/yup"; import * as yup from "yup";
import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
export const conformModalSchema = yup.object().shape({ import { useDepositRejectMutation } from "../../../Services/deposit.request.service";
comment: yup.string().required("Comment is required"), import ToastBox from "../../../Components/ToastBox";
export const conformModalSchema = yup.object().shape({
comments: yup.string().required("Comment is required"),
});
const DepositRequestReject = ({ isOpen, onClose, firstField ,id}) => {
const [isBtnLoading , setIsBtnLoading] = useState(false)
const toast = useToast()
const {
register,
reset,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
}); });
const [ depositReject ] = useDepositRejectMutation()
const DepositRequestReject = ({ isOpen, onClose, firstField }) => {
const { const onSubmit = async(data) => {
register, setIsBtnLoading(true)
handleSubmit, try {
formState: { errors }, const res = await depositReject({ id ,data})
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const onSubmit = (data) => { if (res?.error) {
setFile(data.document[0]); toast({
render: () => (
const newDocument = { <ToastBox message={res?.error?.data?.message} status={"error"} />
...data, ),
document: data.document[0].name, // Store the document name });
comment: true, setIsBtnLoading(false)
id: uuidv4(), onClose();
Type: getFileIcon(file.type),
}; }else if(res?.data?.statusCode === 200) {
toast({
setCreate((prevCreate) => [...prevCreate, newDocument]); render: () => (
onClose(); <ToastBox message={res?.data?.message} />
}; ),
});
const handleFileChange = (event) => { setIsBtnLoading(false)
const selectedFile = event.target.files[0]; onClose();
setFile(selectedFile);
}; }
return ( } catch (error) {
<Modal isOpen={isOpen} onClose={onClose} initialFocusRef={firstField}> console.log(error);
<ModalOverlay />
<ModalContent pb={4}> }
<ModalHeader fontSize={"md"}>Reject</ModalHeader>
<ModalCloseButton />
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4}>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea rows={6}
focusBorderColor='green.400'
name="fileName"
{...register("fileName")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"$100,000"}
rounded={'md'}
resize={'none'}
/>
{errors.comment && (
<Text fontSize="xs" color="red">
{errors.comment.message}
</Text>
)}
</FormControl>
</ModalBody>
<ModalFooter>
<Button colorScheme="gray" mr={3} onClick={onClose} size={'sm'} rounded={'sm'}>
Cancel
</Button>
<Button colorScheme="forestGreen" variant="solid" size={'sm'} rounded={'sm'}>
Send
</Button>
</ModalFooter>
</Box>
</ModalContent>
</Modal>
);
}; };
export default DepositRequestReject; const handleFileChange = (event) => {
const selectedFile = event.target.files[0];
setFile(selectedFile);
};
const { data, isLoading } =
(id, {
skip: !id,
});
useEffect(() => {
if (data) {
reset({
investorAmount: data?.data?.investorAmount,
});
}
}, [data, reset]);
const heandleOnClose = () =>{
reset()
onClose()
}
return (
<Modal isOpen={isOpen} onClose={heandleOnClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Reject</ModalHeader>
<ModalCloseButton />
{isLoading ? (
<FullscreenLoaders height={"50vh"} />
) : (
<Box as="form" onSubmit={handleSubmit(onSubmit)}>
<ModalBody>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Comment</FormLabel>
<Textarea
rows={6}
focusBorderColor="green.400"
name="comments"
{...register("comments")}
fontSize="sm"
type="textarea"
size="md"
placeholder={"Enter your comments...."}
rounded={"md"}
resize={"none"}
/>
{errors.comments && (
<Text fontSize="xs" color="red">
{errors.comments.message}
</Text>
)}
</FormControl>
</ModalBody>
<ModalFooter>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel
</Button>
<Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Send
</Button>
</ModalFooter>
</Box>
)}
</ModalContent>
</Modal>
);
};
export default DepositRequestReject;

View File

@@ -8,20 +8,27 @@ import {
Text, Text,
Tooltip, Tooltip,
useToast, useToast,
useDisclosure useDisclosure,
Link,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from "react";
import { HiDotsVertical } from "react-icons/hi"; import { HiDotsVertical } from "react-icons/hi";
import { Link, Link as RouterLink, useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { debounce } from "../../Master/Sponser/AddSponser"; import { debounce } from "../../Master/Sponser/AddSponser";
import { OPACITY_ON_LOAD } from "../../../Layout/animations"; import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import Pagination from "../../../Components/Pagination"; import Pagination from "../../../Components/Pagination";
import GlobalStateContext from "../../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
import DataTable from "../../../Components/DataTable/DataTable"; import NormalTable from "../../../Components/DataTable/NormalTable";
import ConfirmModal from "./ConfirmModal"; import ConfirmModal from "./ConfirmModal";
import RejectModal from "./RejectModal"; import RejectModal from "./RejectModal";
import {
useDepositRejectMutation,
useGetDepositHistoryQuery,
} from "../../../Services/deposit.request.service";
import { ExternalLinkIcon } from "@chakra-ui/icons";
import { TABLE_PAGINATION } from "../../../Constants/Paginations";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
@@ -36,42 +43,40 @@ const DepositHistory = () => {
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 { // 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 [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page);
const {
data,
error,
isLoading: depositHistoryLoading,
} = useGetDepositHistoryQuery({ page: currentPage, size: pageSize });
useEffect(() => {
// Simulate loading
const timer = setTimeout(() => {
setIsLoading(false);
}, 1500);
// Cleanup the timer on component unmount
return () => clearTimeout(timer);
}, []);
// ====================================================[Table Setup]================================================================ // ====================================================[Table Setup]================================================================
const tableHeadRow = [ const tableHeadRow = [
"Sr.no", // "Sr.no",
"Date",
"Client ID", "Client ID",
"First Name", "First Name",
"Last Name", "Last Name",
"Country", "Country",
"Phone Number", "Phone Number",
"Currency",
"Deposit Amount",
"Fees",
"Total Amount",
"Amount in Investor currency", "Amount in Investor currency",
"Deposit Date",
"Status", "Status",
"Supporting's",
]; ];
const handleUpdateStatus = debounce((id) => { const handleUpdateStatus = debounce((id) => {
@@ -87,22 +92,37 @@ const DepositHistory = () => {
}); });
}, 300); }, 300);
// ====================================================[Table Filter]================================================================
const filteredData = depositHistory.filter((item) => {
// Filter by name (case insensitive)
const name = item.clientId;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches;
});
const filteredData = data?.data?.rows
.filter((item) => {
// Filter by name (case insensitive)
const name = [item.firstName, item.lastName, item.countryName].filter(Boolean).join(' ');
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
// Filter by status (Uncomment and use if needed)
// const status = item.status;
// const statusLower = status ? "active" : "inactive";
// const statusMatches =
// statusFilter === "all" ||
// (statusFilter === "active" && status === true) ||
// (statusFilter === "inactive" && status === false);
return nameMatches;
})
.sort((b, a) => new Date(a.createdAt) - new Date(b.createdAt));
// const handleView = (id) => { // const handleView = (id) => {
// setActionId(id); // setActionId(id);
// onViewOpen(); // onViewOpen();
// }; // };
const [extractedArray, setExtractedArray] = useState( const extractedArray =
filteredData?.map((item, index) => ({ filteredData?.map((item, index) => ({
"Sr.no": ( "Sr.no": (
<Text <Text
@@ -116,18 +136,6 @@ const DepositHistory = () => {
{index + 1} {index + 1}
</Text> </Text>
), ),
"Date": (
<Text
w={"60px"}
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.date}
</Text>
),
"Client ID": ( "Client ID": (
<Text <Text
w={"60px"} w={"60px"}
@@ -137,98 +145,108 @@ const DepositHistory = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.clientId} {item?.clientReference_id}
</Text> </Text>
), ),
"First Name": ( "First Name": (
<Box isTruncated={true} w={"50px"}> <Box isTruncated={true} w={"60px"}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}> <Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item.firstName} {item?.firstName}
</Text> </Text>
</Box> </Box>
), ),
"Last Name": ( "Last Name": (
<Box w={"50px"} isTruncated={true}> <Box w={"70px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}> <Text as={"span"} color={"teal.900"}>
{item.lastName} {item?.lastName}
</Text> </Text>
</Box> </Box>
), ),
Country: ( Country: (
<Box w={"70px"} isTruncated={true}> <Box w={"80px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}> <Text as={"span"} color={"teal.900"}>
{item.country} {item?.countryName}
</Text> </Text>
</Box> </Box>
), ),
"Phone Number": ( "Phone Number": (
<Box w={"70px"} isTruncated={true}> <Box w={"80px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}> <Text as={"span"} color={"teal.900"}>
{item.phoneNumber} {item?.mobileNumber}
</Text>
</Box>
),
Currency: (
<Box w={"50px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
<Badge px={2} py={1}>
{item.currency}
</Badge>
</Text>
</Box>
),
"Deposit Amount": (
<Box w={"50px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.depositAmount}
</Text>
</Box>
),
Fees: (
<Box w={"auto"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.fees}
</Text>
</Box>
),
"Total Amount": (
<Box w={"auto"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.totalAmount}
</Text> </Text>
</Box> </Box>
), ),
"Amount in Investor currency": ( "Amount in Investor currency": (
<Box w={"70px"} isTruncated={true}> <Box w={"100px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}> <Text as={"span"} color={"teal.900"}>
{item.amountcurrency} {/* <Badge px={2} py={1}> */}
{item?.investorAmount} <Badge ms={1} colorScheme="green">{item?.currencyCode}</Badge>
{/* </Badge> */}
</Text> </Text>
</Box> </Box>
), ),
"Deposit Date": (
<Text
w={"60px"}
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{formatDate(item?.createdAt)}
</Text>
),
Status: ( Status: (
<Box w={"70px"} isTruncated={true} cursor={'pointer'}> <Box w={"70px"} isTruncated={true} cursor={"pointer"}>
<Text <Text
// onClick={() => {
// setActionId(item.id);
// onConfirmOpen();
// }}
onClick={() => {
setActionId(item.id);
if (item.status === "Approved") {
onConfirmOpen();
} else {
onRejectOpen();
}
}}
as={"span"} as={"span"}
color={item.status === "Approved" ? "green" : "red"} color={item.transactionStatus === "Approved" ? "green.500" : "red.500"}
fontWeight={700}
> >
{item.status} {item.transactionStatus}
</Text> </Text>
</Box> </Box>
), ),
"Supporting's": (
<Text
w={"60px"}
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{/* {item?.supporting_FileName} */}
<Badge
px={2}
py={0.5}
display={"flex"}
alignItems={"center"}
textTransform={"inherit"}
fontWeight={500}
colorScheme={"forestGreen"}
>
<Link
href={import.meta.env.VITE_IMAGE_URL + item?.supporting_FileName}
isExternal
>
<Box
as="span"
cursor={"pointer"}
>
View
</Box>
<ExternalLinkIcon />
</Link>
{/* <Link to="www.google.com" isExternal>
<Box as="span">View</Box> <ExternalLinkIcon />
</Link> */}
</Badge>
</Text>
),
})) }))
);
const handleDelete = () => { const handleDelete = () => {
const IOtype = investmentType.filter( const IOtype = investmentType.filter(
@@ -245,15 +263,14 @@ const DepositHistory = () => {
return ( return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}> <Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
<ConfirmModal {/* <ConfirmModal
isOpen={isConfirmOpen} isOpen={isConfirmOpen}
onClose={onConfirmClose} onClose={onConfirmClose}
// firstField={firstField}
/> />
<RejectModal <RejectModal
isOpen={isRejectOpen} isOpen={isRejectOpen}
onClose={onRejectClose} onClose={onRejectClose}
/> /> */}
<Box bg="white.500"> <Box bg="white.500">
<HStack <HStack
display={"flex"} display={"flex"}
@@ -276,17 +293,24 @@ const DepositHistory = () => {
/> />
<HStack display={"flex"} alignItems={"center"}> <HStack display={"flex"} alignItems={"center"}>
<Pagination totalItems={10} /> <Pagination
isLoading={depositHistoryLoading}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalItems={data?.data?.totalItems}
/>
</HStack> </HStack>
</HStack> </HStack>
</Box> </Box>
<DataTable <NormalTable
emptyMessage={`We don't have any Investment type `} emptyMessage={`We don't have any Investment type `}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
setData={setExtractedArray} // setData={setExtractedArray}
data={extractedArray} data={extractedArray}
isLoading={isLoading} isLoading={depositHistoryLoading}
viewActionId={actionId} viewActionId={actionId}
setViewActionId={setActionId} setViewActionId={setActionId}
setMouseEnteredId={setMouseEnteredId} setMouseEnteredId={setMouseEnteredId}

View File

@@ -46,7 +46,7 @@ const RejectModal = ({ isOpen, onClose, firstField }) => {
setCreate((prevCreate) => [...prevCreate, newDocument]); setCreate((prevCreate) => [...prevCreate, newDocument]);
onClose(); onClose();
}; };
const handleFileChange = (event) => { const handleFileChange = (event) => {
const selectedFile = event.target.files[0]; const selectedFile = event.target.files[0];

View File

@@ -0,0 +1,250 @@
import {
Box,
Button,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
FormControl,
FormErrorMessage,
FormLabel,
Input,
Select,
Stack,
Textarea,
useToast,
} from "@chakra-ui/react";
import * as yup from "yup";
import React, { useState, useEffect, useContext } from "react";
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import { v4 as uuidv4 } from "uuid";
import { useCreateIoCashMutation, useCreateVideoArtifactsMutation, useUpdateVideoArtifactsMutation } from "../../../Services/io.service";
import { useParams } from "react-router-dom";
import ToastBox from "../../../Components/ToastBox";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import CurrencyInput from "../../../Components/CurrencyInput";
const cashDetails = yup.object().shape({
transactionDate: yup.string().required("Artifact name is required"),
ioTransType_xid: yup.number().required("Artifact name is required"),
transactionAmount: yup.number().required("Artifact name is required"),
comments: yup.string().notRequired(),
});
const AddCashDetails = ({ isOpen, onClose, firstField, actionId, setActionId, data }) => {
const params = useParams()
const id = params?.id
const [file, setFile] = useState("");
const [fileName, setFileName] = useState("");
const [isLoading, setIsLoading] = useState(false)
const [alert, setAlert] = useState(false);
const toast = useToast();
// ======================[ Cotext Api ]
const { IODetails } = useContext(GlobalStateContext);
const found = data?.find((item) => item?.id === actionId);
const [createArtifactsVideo] = useCreateVideoArtifactsMutation()
const [updateVideoArtifacts] = useUpdateVideoArtifactsMutation()
// const {
// data
// } = useGetArtifactsQuery(id)
const {
control,
handleSubmit,
watch,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(cashDetails),
});
const [createIoCash] = useCreateIoCashMutation()
const onSubmit = async (data) => {
setIsLoading(true)
try {
const res = await createIoCash({ data, id })
if (res?.data?.statusCode === 200) {
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
handleClose()
}else if(res?.error?.status === 400){
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />,
});
}
} catch (error) {
console.log(error);
}
};
const handleConfirm = () => {
handleSubmit(onSubmit)();
};
const handleSave = () => {
handleSubmit(onSubmit)();
};
const handleClose = () => {
setAlert(false)
onClose()
reset({
transactionAmount:""
})
}
return (
<>
<Drawer
size={"md"}
isOpen={isOpen}
placement="right"
initialFocusRef={firstField}
onClose={handleClose}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader fontSize={"sm"}>IO Cash Details</DrawerHeader>
<DrawerBody>
<Stack spacing={4}>
<FormControl isInvalid={errors.transactionDate} isRequired>
<FormLabel fontSize={"sm"}>Date Selection</FormLabel>
<Controller
name="transactionDate"
control={control}
render={({ field }) => (
<Input {...field} fontSize={"sm"} type="date" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionDate?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.ioTransType_xid} isRequired>
<FormLabel fontSize={"sm"}>Cash transaction</FormLabel>
<Controller
name="ioTransType_xid"
control={control}
render={({ field }) => (
<Select
{...field}
placeholder="Select an option"
fontSize={"sm"}
size={"sm"}
>
{IODetails?.ioCashTransaction?.map(({ id, transactionName }) => (
<option key={id} value={id}>
{transactionName}
</option>
))}
</Select>
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.ioTransType_xid?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.transactionAmount} isRequired>
<FormLabel fontSize={"sm"}>Transaction Amount</FormLabel>
<Controller
name="transactionAmount"
control={control}
render={({ field }) => (
<CurrencyInput {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionAmount?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.comments}>
<FormLabel fontSize={"sm"}>Comments</FormLabel>
<Controller
name="comments"
control={control}
render={({ field }) => (
<Textarea {...field} textAlign={'right'} fontSize={"sm"} type="text" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.comments?.message}
</FormErrorMessage>
</FormControl>
</Stack>
</DrawerBody>
<DrawerFooter>
<Button
variant="outline"
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
mr={3}
onClick={handleClose}
>
Cancel
</Button>
<Button
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
onClick={() => setAlert(true)}
>
Save
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
<CustomAlertDialog
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleSave}
message={"Are you sure you want to add cash details?"}
isLoading={isLoading}
/>
</>
);
};
export default AddCashDetails;

View File

@@ -0,0 +1,234 @@
import {
Box,
Button,
Drawer,
DrawerBody,
DrawerCloseButton,
DrawerContent,
DrawerFooter,
DrawerHeader,
DrawerOverlay,
FormControl,
FormErrorMessage,
FormLabel,
Input,
Select,
Stack,
Textarea,
useToast,
} from "@chakra-ui/react";
import * as yup from "yup";
import React, { useState, useEffect, useContext } from "react";
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import { v4 as uuidv4 } from "uuid";
import { useCreateIoCashMutation, useCreateIoNavMutation, useCreateVideoArtifactsMutation, useUpdateVideoArtifactsMutation } from "../../../Services/io.service";
import { useParams } from "react-router-dom";
import ToastBox from "../../../Components/ToastBox";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import CurrencyInput from "../../../Components/CurrencyInput";
import { formatDatee } from "../../../Components/FormField";
const ioNav = yup.object().shape({
transactionDate: yup.string().required("Artifact name is required"),
transactionAmount: yup.number().required("Artifact name is required"),
comments: yup.string().notRequired(),
});
const AddIONav = ({ isOpen, onClose, firstField, actionId, setActionId, data }) => {
const params = useParams()
const id = params?.id
const [file, setFile] = useState("");
const [fileName, setFileName] = useState("");
const [isLoading, setIsLoading] = useState(false)
const [alert, setAlert] = useState(false);
const toast = useToast();
// ======================[ Cotext Api ]
const { IODetails } = useContext(GlobalStateContext);
const found = data?.find((item) => item?.id === actionId);
const [createIoNav] = useCreateIoNavMutation()
// const {
// data
// } = useGetArtifactsQuery(id)
const {
control,
handleSubmit,
watch,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(ioNav),
});
const [createIoCash] = useCreateIoCashMutation()
const onSubmit = async (data) => {
setIsLoading(true)
try {
const res = await createIoNav({ data, id })
if (res?.data?.statusCode === 201) {
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
handleClose()
}else if(res?.error?.status === 400){
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />,
});
}
} catch (error) {
console.log(error);
}
};
const handleConfirm = () => {
handleSubmit(onSubmit)();
};
const handleSave = () => {
handleSubmit(onSubmit)();
};
const handleClose = () => {
setAlert(false)
onClose()
reset({
transactionDate:"",
transactionAmount:"",
comments:""
})
}
const today = formatDatee(new Date(), 'yyyy-MM-dd');
return (
<>
<Drawer
size={"md"}
isOpen={isOpen}
placement="right"
initialFocusRef={firstField}
onClose={handleClose}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader fontSize={"sm"}>IO Nav Details</DrawerHeader>
<DrawerBody>
<Stack spacing={4}>
<FormControl isInvalid={errors.transactionDate} isRequired>
<FormLabel fontSize={"sm"}>Date Selection</FormLabel>
<Controller
name="transactionDate"
control={control}
render={({ field }) => (
<Input {...field}
max={today} // Set max attribute to todays date
fontSize={"sm"} type="date" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionDate?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.transactionAmount} isRequired>
<FormLabel fontSize={"sm"}>Transaction Amount</FormLabel>
<Controller
name="transactionAmount"
control={control}
render={({ field }) => (
<CurrencyInput {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionAmount?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.comments}>
<FormLabel fontSize={"sm"}>Comments</FormLabel>
<Controller
name="comments"
control={control}
render={({ field }) => (
<Textarea {...field} fontSize={"sm"} type="text" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.comments?.message}
</FormErrorMessage>
</FormControl>
</Stack>
</DrawerBody>
<DrawerFooter>
<Button
variant="outline"
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
mr={3}
onClick={handleClose}
>
Cancel
</Button>
<Button
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
onClick={() => setAlert(true)}
>
Save
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer>
<CustomAlertDialog
isOpen={alert}
onClose={() => setAlert(false)}
alertHandler={handleSave}
message={"Are you sure you want to add NAV details?"}
isLoading={isLoading}
/>
</>
);
};
export default AddIONav;

View File

@@ -15,6 +15,7 @@ import ViewIOdataHeader from "../ViewIO/ViewIOdataHeader";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders"; import FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders";
import { useGetIOprepopulateDataQuery } from "../../../Services/io.service"; import { useGetIOprepopulateDataQuery } from "../../../Services/io.service";
import UnderConstruction from "../../UnderConstruction";
const CreateIO = () => { const CreateIO = () => {
const id = useParams()?.id; const id = useParams()?.id;
@@ -57,18 +58,24 @@ const CreateIO = () => {
}, },
{ {
label: "Investors", label: "Investors",
Content: Investors, // Content: Investors,
isDisabled: id ? false : false, Content: UnderConstruction,
isDisabled: id ? false : true,
}, },
{ {
label: "IO Cash Details", label: "IO Cash Detail",
Content: IOCashDetails, Content: IOCashDetails,
isDisabled: id ? false : false, isDisabled: id ? false : true,
}, },
{ {
label: "IO NAV Details", label: "IO NAV Details",
Content: IONAVDetails, Content: IONAVDetails,
isDisabled: id ? false : false, isDisabled: id ? false : true,
},
{
label: "Distribution to Investors",
Content: IONAVDetails,
isDisabled: id ? false : true,
}, },
]; ];
@@ -86,19 +93,23 @@ const CreateIO = () => {
height={"100vh"} height={"100vh"}
pb={10} pb={10}
> >
<Box paddingInline={"12px"} mt={2}> {id && <Box
ps={1}
pe={2} mt={2}>
{/* <span {/* <span
onClick={() => navigate(-1)} onClick={() => navigate(-1)}
style={{ fontSize: "15px", cursor: "pointer" }} style={{ fontSize: "15px", cursor: "pointer" }}
> >
<ArrowBackIcon cursor={"pointer"} /> Back <ArrowBackIcon cursor={"pointer"} /> Back
</span> */} </span> */}
<ViewIOdataHeader /> <ViewIOdataHeader isLoading={isLoading} data={data?.data} />
</Box> </Box>}
<Tabs <Tabs
index={activeIndex} index={activeIndex}
onChange={(index) => setActiveIndex(index)} onChange={(index) => setActiveIndex(index)}
mt={2} mt={2}
ps={1}
pe={2}
> >
<TabList> <TabList>
{tabs?.map(({ label, isDisabled }, index) => ( {tabs?.map(({ label, isDisabled }, index) => (

View File

@@ -7,6 +7,7 @@ import {
Text, Text,
Tooltip, Tooltip,
useDisclosure, useDisclosure,
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 DataTable from "../../../Components/DataTable/DataTable"; import DataTable from "../../../Components/DataTable/DataTable";
@@ -30,8 +31,10 @@ import {
} from "../../../Services/io.service"; } from "../../../Services/io.service";
import { getFileNameFromPath } from "../../../Constants/Constants"; import { getFileNameFromPath } from "../../../Constants/Constants";
import ImageViewer from "../../../Components/ImageViewer"; import ImageViewer from "../../../Components/ImageViewer";
import ToastBox from "../../../Components/ToastBox";
const IOArtifacts = ({ enableNextTab, index, data }) => { const IOArtifacts = ({ enableNextTab, index, data }) => {
const toast = useToast()
const params = useParams(); const params = useParams();
const id = params?.id; const id = params?.id;
@@ -107,10 +110,12 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
setIsLoadingBtn(true); setIsLoadingBtn(true);
try { try {
const res = await deleteVideoArtifacts(id); const res = await deleteVideoArtifacts(id);
console.log(res?.data?.statusCode);
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
setDeleteAlertVideo(false); setDeleteAlertVideo(false);
setIsLoadingBtn(false); setIsLoadingBtn(false);
toast({
render: () => <ToastBox message={res?.data?.message} status="error" />,
});
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@@ -121,10 +126,15 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
setIsLoadingBtn(true); setIsLoadingBtn(true);
try { try {
const res = await deleteImageArtifacts(id); const res = await deleteImageArtifacts(id);
console.log(res?.data?.statusCode); console.log(res);
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
setDeleteAlertImage(false); setDeleteAlertImage(false);
setIsLoadingBtn(false); setIsLoadingBtn(false);
toast({
render: () => <ToastBox message={res?.data?.message} status="error" />,
});
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
@@ -170,7 +180,7 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
colorScheme={"forestGreen"} colorScheme={"forestGreen"}
> >
<Link <Link
href={"https://tanami.betadelivery.com/" + item?.artifactPathName} href={import.meta.env.VITE_IMAGE_URL + item?.artifactPathName}
isExternal isExternal
> >
<Box <Box
@@ -342,7 +352,9 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
Manage IO Images Manage IO Images
</Box> </Box>
<HStack> <HStack>
<SetDisplayOrder data={IObyID?.data?.artifactsImage} />
{IObyID?.data?.artifactsImage?.length !== 0 &&<SetDisplayOrder data={IObyID?.data?.artifactsImage} />}
<Button <Button
leftIcon={<AddIcon />} leftIcon={<AddIcon />}
onClick={onOpen} onClick={onOpen}
@@ -378,7 +390,7 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
Manage IO videos Manage IO videos
</Box> </Box>
<HStack> <HStack>
<SetDisplayOrder data={IObyID?.data?.artifactsImage} /> {IObyID?.data?.artifactsVideo?.length !== 0 &&<SetDisplayOrder data={IObyID?.data?.artifactsVideo} />}
<Button <Button
leftIcon={<AddIcon />} leftIcon={<AddIcon />}
onClick={onOpenVideo} onClick={onOpenVideo}

View File

@@ -27,24 +27,28 @@ import ToastBox from "../../../Components/ToastBox";
const investmentVideoSchema = yup.object().shape({ const investmentVideoSchema = yup.object().shape({
artifactName: yup.string().required("Artifact name is required"), artifactName: yup.string().required("Artifact name is required"),
artifactStreamingURL: yup.string().required("Artifact streaming URL is required").url("Invalid URL format"), artifactStreamingURL: yup.string()
.required("Artifact streaming URL is required")
.url("Invalid URL format")
.matches(/\.mp4$/, "URL must end with .mp4"),
}); });
const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, data}) => { const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, data }) => {
const params = useParams() const params = useParams()
const id = params?.id const id = params?.id
const [file, setFile] = useState(""); const [file, setFile] = useState("");
const [fileName, setFileName] = useState(""); const [fileName, setFileName] = useState("");
const [ isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [alert, setAlert] = useState(false); const [alert, setAlert] = useState(false);
const toast = useToast(); const toast = useToast();
const found = data?.find((item) => item?.id === actionId); const found = data?.find((item) => item?.id === actionId);
console.log(found); console.log(actionId);
const [ createArtifactsVideo ] = useCreateVideoArtifactsMutation()
const [ updateVideoArtifacts ] = useUpdateVideoArtifactsMutation() const [createArtifactsVideo] = useCreateVideoArtifactsMutation()
const [updateVideoArtifacts] = useUpdateVideoArtifactsMutation()
// const { // const {
// data // data
// } = useGetArtifactsQuery(id) // } = useGetArtifactsQuery(id)
@@ -63,7 +67,7 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, d
// useEffect to reset the form when `found` changes // useEffect to reset the form when `found` changes
useEffect(() => { useEffect(() => {
if (found) { if (found && actionId) {
reset({ reset({
artifactName: found?.artifactName, artifactName: found?.artifactName,
artifactStreamingURL: found?.artifactStreamingURL, artifactStreamingURL: found?.artifactStreamingURL,
@@ -71,8 +75,6 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, d
} }
}, [found, reset]); }, [found, reset]);
console.log(watch());
const onSubmit = async (data) => { const onSubmit = async (data) => {
setIsLoading(true) setIsLoading(true)
@@ -80,38 +82,39 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, d
try { try {
if (found) { if (found) {
const res = await updateVideoArtifacts({data, id: found?.id}) const res = await updateVideoArtifacts({ data, id: found?.id })
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
toast({ toast({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
setAlert(false); setAlert(false);
setIsLoading(false) setIsLoading(false)
handleClose(); handleClose();
} }
} else { } else {
const res = await createArtifactsVideo({data, id}) const res = await createArtifactsVideo({ data, id })
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
toast({ toast({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
setAlert(false); setAlert(false);
setIsLoading(false) setIsLoading(false)
handleClose(); setActionId(false);
handleClose();
} }
} }
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
}; };
@@ -128,12 +131,16 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, d
onClose() onClose()
reset() reset()
setActionId(false); setActionId(false);
reset({
artifactName: "",
artifactStreamingURL: "",
});
} }
return ( return (
<> <>
<Drawer <Drawer
size={"md"} size={"md"}
isOpen={isOpen} isOpen={isOpen}
placement="right" placement="right"
initialFocusRef={firstField} initialFocusRef={firstField}
@@ -200,7 +207,7 @@ const IOArtifactsAdd = ({ isOpen, onClose, firstField, actionId, setActionId, d
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
<CustomAlertDialog <CustomAlertDialog
isOpen={alert} isOpen={alert}
onClose={() => setAlert(false)} onClose={() => setAlert(false)}

View File

@@ -1,4 +1,5 @@
import { import {
Avatar,
Box, Box,
Button, Button,
HStack, HStack,
@@ -9,23 +10,27 @@ import {
Text, Text,
Th, Th,
Tr, Tr,
useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useRef, useState } from "react";
import { OPACITY_ON_LOAD } from "../../../Layout/animations"; import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import DataTable from "../../../Components/DataTable/DataTable"; import NormalTable from "../../../Components/DataTable/NormalTable";
import Pagination from "../../../Components/Pagination"; import Pagination from "../../../Components/Pagination";
import GlobalStateContext from "../../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
import { debounce } from "../../Master/Sponser/AddSponser"; import { debounce } from "../../Master/Sponser/AddSponser";
import { AddIcon } from "@chakra-ui/icons";
import AddCashDetails from "./AddCashDetails";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
const IOCashDetails = () => { const IOCashDetails = () => {
const toast = useToast(); const toast = useToast();
const { caseDetails, setCaseDetails, slideFromRight } = const firstField = useRef();
useContext(GlobalStateContext); const { isOpen, onOpen, onClose } = useDisclosure();
const { caseDetails, setCaseDetails, IODetails } = useContext(GlobalStateContext);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [deleteAlert, setDeleteAlert] = useState(false); const [deleteAlert, setDeleteAlert] = useState(false);
@@ -52,7 +57,7 @@ const IOCashDetails = () => {
// Table setup // Table setup
const tableHeadRow = [ const tableHeadRow = [
"Date", "Date",
"Particulars", "Transaction type",
"Amount", "Amount",
"Comments", "Comments",
"Update by ", "Update by ",
@@ -71,52 +76,52 @@ const IOCashDetails = () => {
}, 300); }, 300);
// Table filter // Table filter
const filteredData = caseDetails.filter((item) => { const filteredData = IODetails?.ioCashHistory?.filter((item) => {
const name = item.date; const name = item.transactionType;
const searchLower = searchTerm.toLowerCase(); const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower); const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches; return nameMatches;
}); }).sort((b, a) => new Date(a.createdAt) - new Date(b.createdAt));
const [ extractedArray, setExtractedArray ] = useState(filteredData?.map((item, index) => ({ const extractedArray = filteredData?.map((item, index) => ({
id: item?.id, id: item?.id,
"Date": ( "Date": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={"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.date} {item?.transactionDate}
</Text> </Text>
), ),
"Particulars": ( "Transaction type": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent ={"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.particulars} {item?.transactionType}
</Text> </Text>
), ),
"Amount": ( "Amount": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent ={"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.amount} {`$${parseFloat(item.transactionAmount||0).toLocaleString()}`}
</Text> </Text>
), ),
"Comments": ( "Comments": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent ={"center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
@@ -127,18 +132,20 @@ const IOCashDetails = () => {
), ),
"Update by ": ( "Update by ": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent ={"center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
gap={2}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.updateBy}
<Avatar size='sm' name={item.creator?.firstName} src={item.creator?.profilePhoto} />{item.creator?.firstName}
</Text> </Text>
), ),
"Update On": ( "Update On": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent ={"center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
@@ -147,7 +154,7 @@ const IOCashDetails = () => {
{item.updateOn} {item.updateOn}
</Text> </Text>
), ),
}))); }));
const handleDelete = () => { const handleDelete = () => {
const updatedSponsors = sponser.filter( const updatedSponsors = sponser.filter(
@@ -260,18 +267,17 @@ const IOCashDetails = () => {
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
/> />
<HStack display={"flex"} alignItems={"center"}>
<Pagination totalItems={10} /> {IODetails?.isInvestedAmount ? <Button onClick={onOpen} leftIcon={<AddIcon/>} colorScheme="forestGreen" size={'sm'} rounded={'sm'} fontSize={'xs'} >Add IO Cash</Button>:null}
</HStack>
</HStack> </HStack>
</Box> </Box>
<DataTable <NormalTable
centered={true} centered={true}
emptyMessage={`We don't have any Sponers`} emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
data={extractedArray} data={extractedArray}
setData={setExtractedArray}
isLoading={isLoading} isLoading={isLoading}
viewActionId={actionId} viewActionId={actionId}
setViewActionId={setActionId} setViewActionId={setActionId}
@@ -287,6 +293,24 @@ const IOCashDetails = () => {
alertHandler={handleDelete} alertHandler={handleDelete}
isLoading={isLoading} isLoading={isLoading}
/> />
<AddCashDetails
isOpen={isOpen}
onClose={onClose}
firstField={firstField} />
</Box> </Box>
); );
}; };

View File

@@ -33,13 +33,15 @@ import oman from "../../../assets/oman_flag.png";
import qatar from "../../../assets/qatar_flag.png"; import qatar from "../../../assets/qatar_flag.png";
import uae from "../../../assets/uae_flag.png"; import uae from "../../../assets/uae_flag.png";
import saudi from "../../../assets/saudi_arabia_flag.png"; import saudi from "../../../assets/saudi_arabia_flag.png";
import { formatDatee } from "../../../Components/FormField";
import { removeTrailingZeros } from "../../../Constants/Constants";
const schema = yup.object().shape({ const schema = yup.object().shape({
investmentNameEnglish: yup investmentNameEnglish: yup
.string() .string()
.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(50, "IO name in English must be at most 50 characters long"), .max(150, "IO name in English must be at most 150 characters long"),
investmentNameArabic: yup investmentNameArabic: yup
.string() .string()
@@ -58,12 +60,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
.string()
.required("Expected return in Arabic is required"),
goalAmount: yup goalAmount: yup
.number() .number()
.required("Goal amount is required") .typeError("Goal Amount is must be number")
.positive("Goal amount must be a positive number") .required('Goal amount is required')
.min(1, "Goal amount must be at least 1"), .positive('Goal amount must be a positive number'),
closingDate: yup closingDate: yup
.date() .date()
@@ -71,6 +76,7 @@ const schema = yup.object().shape({
.min(new Date(), "Closing date cannot be in the past"), .min(new Date(), "Closing date cannot be in the past"),
holdingPeriod: yup.string().required("Holding period is required"), holdingPeriod: yup.string().required("Holding period is required"),
holdingPeriodArabic: yup.string().required("Holding period is required"),
// minInvestmentAmount: yup // minInvestmentAmount: yup
// .number() // .number()
@@ -93,6 +99,9 @@ const schema = yup.object().shape({
const IODetails = ({ enableNextTab, index, data }) => { const IODetails = ({ enableNextTab, index, data }) => {
const params = useParams(); const params = useParams();
@@ -113,7 +122,7 @@ const IODetails = ({ enableNextTab, index, data }) => {
const id = params?.id; const id = params?.id;
// ======================[ Cotext Api ] // ======================[ Cotext Api ]
const { investmentType, sponser, IODetails, setIODetails } = const { investmentType, sponser, setIOStatus, setIODetails, setIOloading } =
useContext(GlobalStateContext); useContext(GlobalStateContext);
// ======================[ RTK Querry Api ] // ======================[ RTK Querry Api ]
@@ -124,8 +133,6 @@ const IODetails = ({ enableNextTab, index, data }) => {
error: IObyIDerror, error: IObyIDerror,
} = useGetIOByIdQuery(id, { skip: !id }); } = useGetIOByIdQuery(id, { skip: !id });
const [creatIO] = useCreateIOMutation(); const [creatIO] = useCreateIOMutation();
const [updateIO] = useUpdateIOMutation(); const [updateIO] = useUpdateIOMutation();
@@ -147,22 +154,24 @@ const IODetails = ({ enableNextTab, index, data }) => {
}); });
const miniValue = data?.country?.map( const miniValue = data?.country?.map(
({ countryName, flagIcon, minInvestmentAmt, countryCode, id }, 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,
curr: countryCode, curr: currency?.currencyCode,
}; };
} }
); );
const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, country_xid})=>{
const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, country_xid, })=>{
return{ return{
id:country_xid, id:country_xid,
country: country?.countryName, country: country?.countryName,
value: minInvestmentAmt, value: removeTrailingZeros(minInvestmentAmt),
logo: country?.flagIcon, logo: country?.flagIcon,
curr: country?.countryCode, curr: country?.countryCode,
} }
@@ -170,12 +179,18 @@ const IODetails = ({ enableNextTab, index, data }) => {
const [values, setValues] = useState(id?minInvestmentById:miniValue); const [values, setValues] = useState(id?minInvestmentById:miniValue);
const formatNumber = (num) => {
// Remove non-numeric characters and format with commas
return num.replace(/\D/g, '')
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};
// console.log(values); // console.log(values);
// ======================[ Validator filter ] // ======================[ Validator filter ]
const { const {
control, control,
reset, reset,
watch,
setValue, setValue,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
@@ -184,6 +199,7 @@ const IODetails = ({ enableNextTab, index, data }) => {
}); });
useEffect(() => { useEffect(() => {
setIOloading(IObyIDisLoading)
setIODetails({ setIODetails({
...IObyID?.data, ...IObyID?.data,
}); });
@@ -194,19 +210,23 @@ const IODetails = ({ enableNextTab, index, data }) => {
descriptionEnglish: IObyID?.data?.descriptionEnglish, descriptionEnglish: IObyID?.data?.descriptionEnglish,
descriptionArabic: IObyID?.data?.descriptionArabic, descriptionArabic: IObyID?.data?.descriptionArabic,
goalAmount: IObyID?.data?.goalAmount, goalAmount: IObyID?.data?.goalAmount,
closingDate: IObyID?.data?.closingDate, closingDate: formatDatee(IObyID?.data?.closingDate),
holdingPeriod: IObyID?.data?.holdingPeriod, holdingPeriod: IObyID?.data?.holdingPeriod,
ISIN: IObyID?.data?.ISIN, ISIN: IObyID?.data?.ISIN,
comment: IObyID?.data?.comment, comment: IObyID?.data?.comment,
expectedReturn: IObyID?.data?.expectedReturn, expectedReturn: IObyID?.data?.expectedReturn,
investmentType_xid: IObyID?.data?.investmentType_xid, investmentType_xid: IObyID?.data?.investmentType_xid,
investmentType_xid: IObyID?.data?.investmentType_xid,
InvestmentDetails: IObyID?.data?.InvestmentDetails, InvestmentDetails: IObyID?.data?.InvestmentDetails,
minInvestmentAmount: IObyID?.data?.minInvestmentAmount, minInvestmentAmount: IObyID?.data?.minInvestmentAmount,
holdingPeriodArabic: IObyID?.data?.minInvestmentAmount,
expectedReturnArabic: IObyID?.data?.minInvestmentAmount,
}); });
} }
}, [id, IObyID]); }, [id, IObyID]);
// const minInvestmentById = // const minInvestmentById =
@@ -221,6 +241,8 @@ const IODetails = ({ enableNextTab, index, data }) => {
isRequired: true, isRequired: true,
section: " ", section: " ",
width: "49%", width: "49%",
maxLength:150,
helperText:`Maximum length should be 150 characters. You have entered ${watch()?.investmentNameEnglish?.length || 0} characters.`
}, },
{ {
label: "IO Name (Arabic)", label: "IO Name (Arabic)",
@@ -231,6 +253,8 @@ const IODetails = ({ enableNextTab, index, data }) => {
arabic: true, arabic: true,
section: " ", section: " ",
width: "49%", width: "49%",
maxLength:150,
helperText:`Maximum length should be 150 characters. You have entered ${watch()?.investmentNameArabic?.length || 0} characters.`
}, },
{ {
label: "Description", label: "Description",
@@ -240,7 +264,8 @@ 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.`
}, },
{ {
label: "Description (Arabic)", label: "Description (Arabic)",
@@ -251,8 +276,59 @@ const IODetails = ({ enableNextTab, index, data }) => {
arabic: true, arabic: true,
section: " ", section: " ",
width: "49%", width: "49%",
maxLength:1000,
helperText:`Maximum length should be 1000 characters. You have entered ${watch()?.descriptionArabic?.length || 0} characters.`
}, },
{
label: "Holding Period",
name: "holdingPeriod",
type: "text",
placeHolder: "1Y",
isRequired: true,
section: " ",
width: "49%",
value: IObyID?.data?.holdingPeriod,
maxLength:20,
helperText:`Maximum length should be 20 characters. You have entered ${watch()?.holdingPeriod?.length || 0} characters.`
},
{
label: "Holding Period (Arabic)",
name: "holdingPeriodArabic",
type: "text",
placeHolder: "1Y",
isRequired: true,
arabic: true,
section: " ",
width: "49%",
value: IObyID?.data?.holdingPeriodArabic,
maxLength:20,
helperText:`Maximum length should be 20 characters. You have entered ${watch()?.holdingPeriodArabic?.length || 0} characters.`
},
{
label: "Expected Return",
name: "expectedReturn",
type: "text",
isRequired: true,
section: " ",
width: "49%",
value: IObyID?.data?.expectedReturn,
},
{
label: "Expected Return (Arabic)",
name: "expectedReturnArabic",
type: "text",
isRequired: true,
arabic: true,
section: " ",
width: "49%",
value: IObyID?.data?.expectedReturnArabic,
},
{ {
label: "Investment Type", label: "Investment Type",
placeHolder: "Select option", placeHolder: "Select option",
@@ -265,7 +341,7 @@ const IODetails = ({ enableNextTab, index, data }) => {
value: IObyID?.data?.investmentType_xid, value: IObyID?.data?.investmentType_xid,
}, },
{ {
label: "Sponsorer Name", label: "Sponsor Name",
placeHolder: "Select option", placeHolder: "Select option",
name: "sponserName", name: "sponserName",
type: "select", type: "select",
@@ -288,32 +364,13 @@ const IODetails = ({ enableNextTab, index, data }) => {
{ {
label: "Closing Date", label: "Closing Date",
name: "closingDate", name: "closingDate",
value: formatDate(IObyID?.data?.closingDate), // value: "IObyID?.data?.closingDate",
type: "date", type: "date",
isRequired: true, isRequired: true,
section: " ", section: " ",
width: "32.3%", width: "32.3%",
helperText: IObyID && `Current closing date is : ${formatDate(IObyID?.data?.closingDate)}` dateValue:formatDatee(IObyID?.data?.closingDate),
}, // helperText: IObyID && `Current closing date is : ${formatDate(IObyID?.data?.closingDate)}`
{
label: "Holding Period",
name: "holdingPeriod",
type: "text",
placeHolder: "1Y",
isRequired: true,
section: " ",
width: "32.3%",
value: IObyID?.data?.holdingPeriod,
},
{
label: "Expected Return",
placeHolder: "$00.00",
name: "expectedReturn",
type: "text",
isRequired: true,
section: " ",
width: "32.3%",
value: IObyID?.data?.expectedReturn,
}, },
{ {
label: "ISIN", label: "ISIN",
@@ -343,7 +400,6 @@ const IODetails = ({ enableNextTab, index, data }) => {
width: "100%", width: "100%",
isRequired: true, isRequired: true,
options: investmentTypeOptions, options: investmentTypeOptions,
type: "table",
handleInputChange: handleInputChange, handleInputChange: handleInputChange,
value: values, value: values,
}, },
@@ -357,7 +413,8 @@ 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.`
}, },
]; ];
//=======================[ Editor ] //=======================[ Editor ]
@@ -567,6 +624,11 @@ const IODetails = ({ enableNextTab, index, data }) => {
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){
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.error?.data?.message } status={"error"} />,
});
} }
} catch (error) { } catch (error) {
setIsLoading(false); setIsLoading(false);
@@ -592,8 +654,9 @@ const IODetails = ({ enableNextTab, index, data }) => {
}; };
return IObyIDisLoading ? ( return IObyIDisLoading ? (
<FullscreenLoaders /> <FullscreenLoaders height={'70vh'} />
) : ( ) : (
<FormInputMain <FormInputMain
p={0.1} p={0.1}
w={250} w={250}

View File

@@ -1,14 +1,19 @@
import React, { useContext, useEffect, useState } from 'react' import React, { useContext, useEffect, useRef, useState } from 'react'
import GlobalStateContext from '../../../Contexts/GlobalStateContext'; import GlobalStateContext from '../../../Contexts/GlobalStateContext';
import { Box, HStack, Input,Text, Table, Tbody, Th, Tr } from '@chakra-ui/react'; import { Box, HStack, Input,Text, Table, Tbody, Th, Tr, Avatar, useDisclosure,Button } from '@chakra-ui/react';
import { OPACITY_ON_LOAD } from '../../../Layout/animations'; import { OPACITY_ON_LOAD } from '../../../Layout/animations';
import Pagination from '../../../Components/Pagination'; import Pagination from '../../../Components/Pagination';
import DataTable from '../../../Components/DataTable/DataTable'; import NormalTable from '../../../Components/DataTable/NormalTable';
import CustomAlertDialog from '../../../Components/CustomAlertDialog'; import CustomAlertDialog from '../../../Components/CustomAlertDialog';
import { formatDatee } from '../../../Components/FormField';
import { AddIcon } from '@chakra-ui/icons';
import AddIONav from './AddIONav';
const IONAVDetails = () => { const IONAVDetails = () => {
const { navDetails, setNavDetails, slideFromRight } = const { navDetails, setNavDetails, IODetails } =
useContext(GlobalStateContext); useContext(GlobalStateContext);
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [deleteAlert, setDeleteAlert] = useState(false); const [deleteAlert, setDeleteAlert] = useState(false);
@@ -16,6 +21,10 @@ const IONAVDetails = () => {
const [mouseEntered, setMouseEntered] = useState(false); const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState(""); const [mouseEnteredId, setMouseEnteredId] = useState("");
console.log(IODetails?.ioNAVHistory);
useEffect(() => { useEffect(() => {
// Simulate loading // Simulate loading
@@ -29,50 +38,76 @@ const IONAVDetails = () => {
// Table setup // Table setup
const tableHeadRow = [ const tableHeadRow = [
"Sr.No", // "Sr.No",
"As On Date", "Valuation Date",
"IO NAV Value", "NAV",
"Last NAV update",
"Investment Closed",
"Comments", "Comments",
"Update by ", "Update by ",
"Update On", // "Update On",
]; ];
// Table filter // Table filter
const filteredData = navDetails?.filter((item) => { const filteredData = IODetails?.ioNAVHistory?.filter((item) => {
const name = item.updateBy; const name = item.transactionType;
const searchLower = searchTerm.toLowerCase(); const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower); const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches; return nameMatches;
}); }).sort((b, a) => new Date(a.transactionDate) - new Date(b.transactionDate));
const [ extractedArray, setExtractedArray ] = useState(filteredData?.map((item, index) => ({ const extractedArray=filteredData?.map((item, index) => ({
id: item?.id, id: item?.id,
"Sr.No": index +1, "Sr.No": index +1,
"As On Date": ( "Valuation Date": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={"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.date} {formatDatee(item.transactionDate)}
</Text> </Text>
), ),
"IO NAV Value": ( "NAV": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={"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.IONavValue}`} {/* {`${item.transactionAmount}`} */}
{`$${parseFloat(item.transactionAmount||0).toLocaleString()}`}
</Text>
),
"Last NAV update": (
<Text
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.previousNAVvalue && `${item.previousNAVvalue}`}
</Text>
),
"Investment Closed": (
<Text
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.initialNAVvalue&& `${item.initialNAVvalue}`}
</Text> </Text>
), ),
"Comments": ( "Comments": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={"center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
@@ -83,18 +118,20 @@ const IONAVDetails = () => {
), ),
"Update by ": ( "Update by ": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent ={"center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
gap={2}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.updateBy}
<Avatar size='sm' name={"faisal"} src={null} />Faisal
</Text> </Text>
), ),
"Update On": ( "Update On": (
<Text <Text
justifyContent={slideFromRight ? "right" : "center"} justifyContent={"center"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
@@ -103,7 +140,7 @@ const IONAVDetails = () => {
{item.updateOn} {item.updateOn}
</Text> </Text>
), ),
}))); }));
@@ -142,18 +179,21 @@ const IONAVDetails = () => {
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
/> />
<HStack display={"flex"} alignItems={"center"}> {/* <HStack display={"flex"} alignItems={"center"}>
<Pagination totalItems={10} /> <Pagination totalItems={10} />
</HStack> </HStack> */}
{IODetails?.isInvestedAmount ? <Button onClick={onOpen} leftIcon={<AddIcon/>} colorScheme="forestGreen" size={'sm'} rounded={'sm'} fontSize={'xs'} >Add IO NAV</Button>:null}
</HStack> </HStack>
</Box> </Box>
<DataTable <NormalTable
centered={true} centered={true}
emptyMessage={`We don't have any Sponers`} emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
data={extractedArray} data={extractedArray}
setData={setExtractedArray}
isLoading={isLoading} isLoading={isLoading}
viewActionId={actionId} viewActionId={actionId}
setViewActionId={setActionId} setViewActionId={setActionId}
@@ -169,6 +209,15 @@ const IONAVDetails = () => {
alertHandler={handleDelete} alertHandler={handleDelete}
isLoading={isLoading} isLoading={isLoading}
/> />
<AddIONav
isOpen={isOpen}
onClose={onClose}
firstField={firstField} />
</Box> </Box>
) )
} }

View File

@@ -36,9 +36,8 @@ import { TbFileTypeDocx } from "react-icons/tb";
import SetDisplayOrder from "./SetDisplayOrder"; import SetDisplayOrder from "./SetDisplayOrder";
const downloadFile = (filePath, fileName) => { const downloadFile = (filePath, fileName) => {
console.log("https://tanami.betadelivery.com/" + filePath);
fetch("https://tanami.betadelivery.com/" + filePath) fetch(import.meta.env.VITE_IMAGE_URL+filePath)
.then((response) => { .then((response) => {
if (!response.ok) { if (!response.ok) {
throw new Error("Network response was not ok"); throw new Error("Network response was not ok");
@@ -72,10 +71,10 @@ const downloadFile = (filePath, fileName) => {
}); });
}; };
const InvestmentDocument = ({ control, errors, enableNextTab, index }) => { const InvestmentDocument = ({ control, errors, enableNextTab, index, }) => {
const params = useParams(); const params = useParams();
const id = params?.id; const id = params?.id;
const { slideFromRight, create, setCreate } = useContext(GlobalStateContext); const { slideFromRight, create, setCreate, IODetails } = useContext(GlobalStateContext);
const firstField = useRef(); const firstField = useRef();
const secondField = useRef(); const secondField = useRef();
const thirdField = useRef(); const thirdField = useRef();
@@ -101,13 +100,18 @@ const InvestmentDocument = ({ control, errors, enableNextTab, index }) => {
const [deleteIODocs] = useDeleteIODocsMutation(); const [deleteIODocs] = useDeleteIODocsMutation();
const { // const {
data, // data,
error, // error,
isLoading: isIODocLoading, // isLoading: isIODocLoading,
} = useGetInvestmentDocumentsQuery(id, { // } = useGetInvestmentDocumentsQuery(id, {
skip: !id, // skip: !id,
}); // });
const tableHeadRow = ["Sr.no", "Type", "File Name", "Document", "Action"]; const tableHeadRow = ["Sr.no", "Type", "File Name", "Document", "Action"];
@@ -126,7 +130,7 @@ const InvestmentDocument = ({ control, errors, enableNextTab, index }) => {
}); });
}, 300); }, 300);
const filteredData = data?.data?.filter((item) => const filteredData = IODetails?.documents?.filter((item) =>
item?.documentName?.toLowerCase().includes(searchTerm.toLowerCase()) item?.documentName?.toLowerCase().includes(searchTerm.toLowerCase())
); );
@@ -294,7 +298,9 @@ const InvestmentDocument = ({ control, errors, enableNextTab, index }) => {
return ( return (
<Box> <Box>
<Box display="flex" justifyContent="end" mb={4} gap={2}> <Box display="flex" justifyContent="end" mb={4} gap={2}>
<SetDisplayOrder data={filteredData} />
{filteredData?.length !== 0 &&<SetDisplayOrder data={filteredData} />}
<Button <Button
leftIcon={<AddIcon />} leftIcon={<AddIcon />}
onClick={onOpen} onClick={onOpen}
@@ -319,7 +325,7 @@ const InvestmentDocument = ({ control, errors, enableNextTab, index }) => {
secondField={secondField} secondField={secondField}
/> />
<InvestmentEdit <InvestmentEdit
data={data?.data} data={IODetails?.documents}
id={actionId} id={actionId}
isOpen={isEditOpen} isOpen={isEditOpen}
onClose={onEditClose} onClose={onEditClose}

View File

@@ -4,6 +4,7 @@ import {
Box, Box,
Button, Button,
HStack, HStack,
Icon,
Input, Input,
Menu, Menu,
MenuButton, MenuButton,
@@ -24,21 +25,40 @@ import {
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from "react";
import { OPACITY_ON_LOAD } from "../../../Layout/animations"; import { OPACITY_ON_LOAD } from "../../../Layout/animations";
import DataTable from "../../../Components/DataTable/DataTable"; import NormalTable from "../../../Components/DataTable/NormalTable";
import { HiDotsVertical } from "react-icons/hi"; import { HiDotsVertical } from "react-icons/hi";
import { Link, Link as RouterLink } from "react-router-dom"; import { Link, Link as RouterLink, useParams } from "react-router-dom";
import Pagination from "../../../Components/Pagination"; import Pagination from "../../../Components/Pagination";
import GlobalStateContext from "../../../Contexts/GlobalStateContext"; import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
import { debounce } from "../../Master/Sponser/AddSponser"; import { debounce } from "../../Master/Sponser/AddSponser";
import { formatCurrency } from "../../../Components/CurrencyInput";
import { FiRefreshCw } from "react-icons/fi";
import { useGetIOByIdQuery } from "../../../Services/io.service";
import { RepeatIcon } from "@chakra-ui/icons";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
const Investors = () => { const Investors = ({data}) => {
const params = useParams()
const id = params?.id
const toast = useToast(); const toast = useToast();
const { investors, setInvestors, slideFromRight } = const { investors, setInvestors, slideFromRight, IODetails } =
useContext(GlobalStateContext); useContext(GlobalStateContext);
console.log(params?.id);
const {
data: IObyID,
isLoading: IObyIDisLoading,
error: IObyIDerror,
refetch
} = useGetIOByIdQuery(id, { skip: !id });
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [deleteAlert, setDeleteAlert] = useState(false); const [deleteAlert, setDeleteAlert] = useState(false);
@@ -84,6 +104,7 @@ const Investors = () => {
"Market Value", "Market Value",
"Return on Investment", "Return on Investment",
"Distribution", "Distribution",
"Distribution Percent",
"Total Return", "Total Return",
"Total return on Investment", "Total return on Investment",
]; ];
@@ -100,15 +121,17 @@ const Investors = () => {
}, 300); }, 300);
// Table filter // Table filter
const filteredData = investors.filter((item) => { const filteredData = IODetails?.investors?.filter((item) => {
const name = item.firstName; const name = item.firstName;
const searchLower = searchTerm.toLowerCase(); const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower); const nameMatches = name.toLowerCase().includes(searchLower);
return nameMatches; return nameMatches;
}); });
const [ extractedArray, setExtractedArray ] = useState(filteredData?.map((item, index) => ({
const extractedArray = filteredData?.map((item, index) => ({
id: item?.id, id: item?.id,
"Client ID": ( "Client ID": (
<Text <Text
@@ -118,7 +141,7 @@ const Investors = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.clientId} {item?.clientReference_id}
</Text> </Text>
), ),
"First name": ( "First name": (
@@ -151,7 +174,8 @@ const Investors = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{`$${item.investedAmount}`} {/* {`$${formatCurrency(item.InvestedAmount_USD)}`} */}
{`$${parseFloat(item.InvestedAmount_USD||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`}
</Text> </Text>
), ),
"Percentage": ( "Percentage": (
@@ -162,7 +186,7 @@ const Investors = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.percentage} {item.Investor_Holidings} %
</Text> </Text>
), ),
"Market Value": ( "Market Value": (
@@ -173,7 +197,7 @@ const Investors = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{`$${item.marketValue}`} {`$${parseFloat(item.Market_Value ||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`}
</Text> </Text>
), ),
"Return on Investment": ( "Return on Investment": (
@@ -185,7 +209,7 @@ const Investors = () => {
h={6} h={6}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.returnOnInvestment} {item.Return_On_Investment || 0} %
</Text> </Text>
), ),
"Distribution": ( "Distribution": (
@@ -196,7 +220,20 @@ const Investors = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{`$${item.distribution}`} {/* {`$${item.Distribution_Amt}`} */}
{`$${parseFloat(item.Distribution_Amt||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`}
</Text>
),
"Distribution Percent": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{/* {`$${item.Distribution_Amt}`} */}
{`${parseFloat(item.Distribution_Per||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} %`}
</Text> </Text>
), ),
"Total Return": ( "Total Return": (
@@ -207,7 +244,8 @@ const Investors = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{`$${item.totalReturn}`} {/* {`$${formatCurrency(item.Total_Return) || 0}`} */}
{`$${parseFloat(item.Total_Return||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`}
</Text> </Text>
), ),
"Total return on Investment": ( "Total return on Investment": (
@@ -218,10 +256,10 @@ const Investors = () => {
fontWeight={"500"} fontWeight={"500"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.totalReturnOnInvestment} {item.Total_Return_On_Investment||0} %
</Text> </Text>
), ),
}))); }));
const handleDelete = () => { const handleDelete = () => {
const updatedSponsors = sponser.filter( const updatedSponsors = sponser.filter(
@@ -357,6 +395,11 @@ const Investors = () => {
); );
}; };
const handleRefresh = () =>{
refetch()
}
return ( return (
<Box {...OPACITY_ON_LOAD} pb={0}> <Box {...OPACITY_ON_LOAD} pb={0}>
<Box bg="white.500"> <Box bg="white.500">
@@ -365,7 +408,9 @@ const Investors = () => {
justifyContent={"space-between"} justifyContent={"space-between"}
pb={3} pb={3}
spacing="24px" spacing="24px"
> >
<span>
<Input <Input
type="search" type="search"
width={300} width={300}
@@ -376,19 +421,22 @@ const Investors = () => {
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
/> />
<Icon ms={3} bg={"gray.100"} onClick={handleRefresh} fontWeight={600} as={RepeatIcon} boxSize={8} p={2} rounded={'md'} _hover={{bg:'gray.100'}} cursor={'pointer'} />
</span>
<HStack display={"flex"} alignItems={"center"}> <HStack bg={'#C6F6D5'} ps={4} pe={4} pt={1.5} pb={1.5} rounded={'md'} boxShadow={'sm'} display={"flex"} alignItems={"end"} flexDirection={'column'} >
<Pagination totalItems={10} /> <Text fontWeight={600} fontSize={'sm'} as={'span'}>$ {parseFloat(IODetails?.totalAmtInvestmentInUSD).toLocaleString()}</Text>
<Text fontWeight={600} color={'gray.500'} fontSize={'xs'} as={'span'}>Total Investment Amount ( USD )</Text>
</HStack> </HStack>
</HStack> </HStack>
</Box> </Box>
<DataTable <NormalTable
centered={true} centered={true}
emptyMessage={`We don't have any Sponers `} emptyMessage={`We don't have any Sponers `}
tableHeadRow={tableHeadRow} tableHeadRow={tableHeadRow}
data={extractedArray} data={extractedArray}
setData={setExtractedArray}
isLoading={isLoading} isLoading={isLoading}
viewActionId={actionId} viewActionId={actionId}
setViewActionId={setActionId} setViewActionId={setActionId}

View File

@@ -38,16 +38,16 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
const toast = useToast(); const toast = useToast();
const params = useParams(); const params = useParams();
// =====================[ variables ] // =====================[ variables ]
const id = params?.id; const id = params?.id;
const { data, isLoading, error } = useGetKeyMeritsQuery(id, { // const { data, isLoading, error } = useGetKeyMeritsQuery(id, {
skip: !id, // skip: !id,
}); // });
console.log(data?.data); const { IODetails} = useContext(GlobalStateContext);
const { keyMerits, setKeyMerits, slideFromRight } =
useContext(GlobalStateContext);
const firstField = useRef(); const firstField = useRef();
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
@@ -57,6 +57,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
const [isBtnLoading, setIsBtnLoading] = useState(false); const [isBtnLoading, setIsBtnLoading] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState(""); const [mouseEnteredId, setMouseEnteredId] = useState("");
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const { const {
isOpen: isEditOpen, isOpen: isEditOpen,
onOpen: onEditOpen, onOpen: onEditOpen,
@@ -66,20 +67,9 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
const tableHeadRow = ["Sr.no", "Title", "Sub title", "Icon", "Action"]; const tableHeadRow = ["Sr.no", "Title", "Sub title", "Icon", "Action"];
const handleUpdateStatus = debounce((id) => {
setKeyMerits((prevKeyMerits) =>
prevKeyMerits.map((keyMerits) =>
keyMerits.id === id
? { ...keyMerits, status: !keyMerits.status }
: keyMerits
)
);
toast({
render: () => <ToastBox message={"Status changed succesfully.!"} />,
});
}, 300);
const filteredData = data?.data?.filter((item) => {
const filteredData = IODetails?.keyMerits?.filter((item) => {
// Filter by name (case insensitive) // Filter by name (case insensitive)
const name = item.meritsHeader; const name = item.meritsHeader;
const searchLower = searchTerm.toLowerCase(); const searchLower = searchTerm.toLowerCase();
@@ -111,7 +101,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
id: item.id, id: item.id,
"Sr.no": ( "Sr.no": (
<Text <Text
justifyContent={slideFromRight ? "right" : "left"} justifyContent={"left"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
@@ -122,7 +112,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
), ),
Title: ( Title: (
<Text <Text
justifyContent={slideFromRight ? "right" : "left"} justifyContent={"left"}
as={"span"} as={"span"}
color={"teal.900"} color={"teal.900"}
fontWeight={"500"} fontWeight={"500"}
@@ -139,14 +129,14 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
</Box> </Box>
), ),
Icon: item?.icon?.iconFilePath && ( Icon: item?.icon?.iconFilePath && (
<Image <Image
rounded={"md"} rounded={"md"}
// bg={"#003B14"} // bg={"#003B14"}
display={"flex"} display={"flex"}
p={1} p={1}
justifyContent={"center"} justifyContent={"center"}
alignItems={"center"} alignItems={"center"}
src={" https://tanami.betadelivery.com/" + item?.icon?.iconFilePath} src={import.meta.env.VITE_IMAGE_URL+ item?.icon?.iconFilePath}
w={8} w={8}
h={8} h={8}
/> />
@@ -224,7 +214,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
), ),
})); }));
return isLoading ? ( return false ? (
<FullscreenLoaders /> <FullscreenLoaders />
) : ( ) : (
<Box> <Box>
@@ -241,7 +231,9 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
/> */} /> */}
<Box display={"flex"} gap={2} as="span"> <Box display={"flex"} gap={2} as="span">
<SetDisplayOrder data={filteredData} />
{filteredData?.length !== 0 &&<SetDisplayOrder data={filteredData} />}
<Button <Button
leftIcon={<AddIcon />} leftIcon={<AddIcon />}
onClick={onOpen} onClick={onOpen}
@@ -269,7 +261,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
isOpen={isEditOpen} isOpen={isEditOpen}
onClose={onEditCloseOpen} onClose={onEditCloseOpen}
firstField={firstField} firstField={firstField}
data={data?.data} data={IODetails?.keyMerits}
/> />
</Box> </Box>
<DataTable <DataTable

View File

@@ -63,7 +63,7 @@ const SetDisplayOrder = ({ data }) => {
p={1} p={1}
justifyContent={"center"} justifyContent={"center"}
alignItems={"center"} alignItems={"center"}
src={"https://tanami.betadelivery.com/" + item?.icon?.iconFilePath} src={import.meta.env.VITE_IMAGE_URL + item?.icon?.iconFilePath}
w={8} w={8}
h={8} h={8}
/> />

View File

@@ -39,13 +39,8 @@ const InvestmentEdit = ({ isOpen, onClose, thirdField, id, data }) => {
const [updateInvestmentDocuments] = useUpdateInvestmentDocumentsMutation(); const [updateInvestmentDocuments] = useUpdateInvestmentDocumentsMutation();
// =====================[ variables ] // =====================[ variables ]
// const id = params?.id;
console.log(id);
console.log(data);
const filterObject = data?.find((item) => item?.id === id); const filterObject = data?.find((item) => item?.id === id);
console.log(filterObject);
const getFileTitle = (type) => { const getFileTitle = (type) => {
switch (type) { switch (type) {
case "application/pdf": case "application/pdf":
@@ -74,12 +69,16 @@ const InvestmentEdit = ({ isOpen, onClose, thirdField, id, data }) => {
resolver: yupResolver(investmentDocSchema), resolver: yupResolver(investmentDocSchema),
}); });
console.log(errors);
// useEffect to reset the form when `found` changes // useEffect to reset the form when `found` changes
useEffect(() => { useEffect(() => {
if (filterObject) { if (filterObject) {
reset({ reset({
document: filterObject?.documentPath, document: filterObject?.documentPath,
fileName: filterObject?.documentName, fileName: filterObject?.documentName,
documentNameArabic: filterObject?.documentNameArabic,
}); });
} }
}, [filterObject, reset]); }, [filterObject, reset]);
@@ -89,6 +88,7 @@ const InvestmentEdit = ({ isOpen, onClose, thirdField, id, data }) => {
reset({ reset({
fileName: filteredObject?.fileName, fileName: filteredObject?.fileName,
document: filteredObject?.document, document: filteredObject?.document,
documentNameArabic: filterObject?.documentNameArabic,
Type: filteredObject?.Type, Type: filteredObject?.Type,
}); });
} }
@@ -158,6 +158,7 @@ const InvestmentEdit = ({ isOpen, onClose, thirdField, id, data }) => {
if (Object.keys(errors).length === 0) { if (Object.keys(errors).length === 0) {
const formData = new FormData(); const formData = new FormData();
formData.append("documentName", data.fileName); formData.append("documentName", data.fileName);
formData.append("documentNameArabic", data.documentNameArabic);
typeof data?.document !== "string" typeof data?.document !== "string"
? formData.append("document", data?.document[0]) ? formData.append("document", data?.document[0])
: null; : null;
@@ -171,7 +172,6 @@ const InvestmentEdit = ({ isOpen, onClose, thirdField, id, data }) => {
setFile(selectedFile); setFile(selectedFile);
}; };
console.log(filteredObject);
return ( return (
<Drawer <Drawer
@@ -200,6 +200,27 @@ const InvestmentEdit = ({ isOpen, onClose, thirdField, id, data }) => {
</Text> </Text>
)} )}
</FormControl> </FormControl>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">File Name ( Arabic )</FormLabel>
<Input
name="documentNameArabic"
{...register("documentNameArabic")}
fontSize="sm"
type="text"
size="sm"
textAlign={'right'}
/>
{errors.documentNameArabic && (
<Text mt={1} fontSize="xs" fontWeight={500} color="red">
{errors.documentNameArabic.message}
</Text>
)}
</FormControl>
<FormControl mb={4} isInvalid={errors.Type}> <FormControl mb={4} isInvalid={errors.Type}>
<FormLabel fontSize="sm">Document</FormLabel> <FormLabel fontSize="sm">Document</FormLabel>
<Input <Input
@@ -209,6 +230,7 @@ const InvestmentEdit = ({ isOpen, onClose, thirdField, id, data }) => {
className="form-control" className="form-control"
type="file" type="file"
size="sm" size="sm"
accept=".pdf, .doc, .docx"
onChange={handleFileChange} onChange={handleFileChange}
/> />
{errors.document && ( {errors.document && (

View File

@@ -11,13 +11,15 @@ import {
FormControl, FormControl,
FormErrorMessage, FormErrorMessage,
FormLabel, FormLabel,
Icon,
Image, Image,
Input, Input,
Stack, Stack,
Text,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import * as yup from "yup"; import * as yup from "yup";
import React, { useEffect, useState } from "react"; import React, { useEffect, useRef, 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 CustomAlertDialog from "../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../Components/CustomAlertDialog";
@@ -27,6 +29,9 @@ import {
} from "../../Services/io.service"; } from "../../Services/io.service";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import ToastBox from "../../Components/ToastBox"; import ToastBox from "../../Components/ToastBox";
import { bytesToMB } from "./InvestmentDocuments";
import { formatTimestampInGulfTimezone } from "../../Constants/Constants";
import { IoMdRemoveCircleOutline } from "react-icons/io";
const investmentImageSchema = yup.object().shape({ const investmentImageSchema = yup.object().shape({
artifactName: yup.string().required("Artifact image name is required"), artifactName: yup.string().required("Artifact image name is required"),
@@ -41,8 +46,6 @@ const IOArtifactsAdd = ({
setActionId, setActionId,
data, data,
}) => { }) => {
console.log(actionId);
console.log(data);
const params = useParams(); const params = useParams();
const id = params?.id; const id = params?.id;
const [file, setFile] = useState(null); const [file, setFile] = useState(null);
@@ -55,7 +58,8 @@ const IOArtifactsAdd = ({
const [updateImageArtifacts] = useUpdateImageArtifactsMutation(); const [updateImageArtifacts] = useUpdateImageArtifactsMutation();
const found = data?.find((item) => item?.id === actionId); const found = data?.find((item) => item?.id === actionId);
console.log(found); const fileInputRef = useRef(null);
const { const {
control, control,
@@ -78,7 +82,6 @@ const IOArtifactsAdd = ({
} }
}, [found, reset]); }, [found, reset]);
console.log(watch());
const onSubmit = async (data) => { const onSubmit = async (data) => {
setIsLoading(true); setIsLoading(true);
@@ -86,29 +89,25 @@ const IOArtifactsAdd = ({
formData.append("artifactName", data.artifactName); formData.append("artifactName", data.artifactName);
file && formData.append("artifactPathName", file); // Assuming artifactPathName is an array of files file && formData.append("artifactPathName", file); // Assuming artifactPathName is an array of files
console.log("FormData:", formData);
for (let [key, value] of formData.entries()) {
console.log(`${key}:`, value);
}
try { try {
if (found) { if (found) {
const res = await updateImageArtifacts({ const res = await updateImageArtifacts({
data: formData, data: formData,
id: found?.id, id: found?.id,
}); });
console.log(res?.error);
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
toast({ toast({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
reset();
setFile(null); setFile(null);
setIsLoading(false); setIsLoading(false);
setAlert(false); setAlert(false);
setPreview(null); setPreview(null);
onClose(); onClose();
reset({
artifactName: "",
artifactPathName: "",
});
} }
if (res?.error) { if (res?.error) {
@@ -126,7 +125,10 @@ const IOArtifactsAdd = ({
toast({ toast({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
reset(); reset({
artifactName: "",
artifactPathName: "",
});
setFile(null); setFile(null);
setIsLoading(false); setIsLoading(false);
setAlert(false); setAlert(false);
@@ -153,6 +155,8 @@ const IOArtifactsAdd = ({
reader.readAsDataURL(file); reader.readAsDataURL(file);
}; };
const handleSave = () => { const handleSave = () => {
handleSubmit(onSubmit)(); handleSubmit(onSubmit)();
}; };
@@ -169,6 +173,18 @@ const IOArtifactsAdd = ({
setActionId(false); setActionId(false);
}; };
const handleRemove = () => {
setFile(null)
setPreview(null)
// Reset the file input value
if (fileInputRef.current) {
fileInputRef.current.value = "";
}
}
return ( return (
<> <>
<Drawer <Drawer
@@ -214,6 +230,7 @@ const IOArtifactsAdd = ({
fontSize={"sm"} fontSize={"sm"}
size={"sm"} size={"sm"}
className="form-control" className="form-control"
ref={fileInputRef} // Set the ref here
/> />
<FormErrorMessage fontSize={"xs"} fontWeight={500}> <FormErrorMessage fontSize={"xs"} fontWeight={500}>
{!preview && {!preview &&
@@ -221,18 +238,29 @@ const IOArtifactsAdd = ({
errors.artifactPathName?.message} errors.artifactPathName?.message}
</FormErrorMessage> </FormErrorMessage>
{preview && ( {preview && (
<Image <>
rounded={"md"} <Image
src={preview} rounded={"md"}
alt="Image Preview" src={preview}
mt={2} alt="Image Preview"
/> mt={3}
width={'100%'}
height={300}
objectFit={'cover'}
/>
<Box w={'100%'} position={'relative'} mt={2} fontSize={'xs'} display={'flex'} flexDirection={'column'} as="span">
<Text as={'span'}>Name: {file?.name}</Text>
<Text as={'span'} fontSize={'xs'}>File size: {bytesToMB(file?.size)}</Text>
<Text as={'span'} fontSize={'xs'}>Last update: {formatTimestampInGulfTimezone(file?.lastModified)}</Text>
<Icon onClick={() => handleRemove()} _hover={{ bg: "gray.100" }} transition={'all 0-5s'} cursor={'pointer'} position={'absolute'} right={0} p={1} bottom={0} rounded={'lg'} boxSize={7} as={IoMdRemoveCircleOutline} />
</Box>
</>
)} )}
{found && !preview && ( {found && !preview && (
<Image <Image
rounded={"md"} rounded={"md"}
src={ src={
"https://tanami.betadelivery.com/" + import.meta.env.VITE_IMAGE_URL +
watch()?.artifactPathName watch()?.artifactPathName
} }
alt="Image Preview" alt="Image Preview"

View File

@@ -9,6 +9,7 @@ import {
DrawerHeader, DrawerHeader,
DrawerOverlay, DrawerOverlay,
FormControl, FormControl,
FormHelperText,
FormLabel, FormLabel,
Input, Input,
Text, Text,
@@ -59,6 +60,7 @@ export const investmentDocSchema = yup.object().shape({
// return value && value.size <= 2 * 1024 * 1024; // 2MB in bytes // return value && value.size <= 2 * 1024 * 1024; // 2MB in bytes
// }) // })
fileName: yup.string().required("File name is required"), fileName: yup.string().required("File name is required"),
documentNameArabic: yup.string().required("File name Arabic is required")
}); });
const InvestmentDocuments = ({ const InvestmentDocuments = ({
@@ -94,11 +96,10 @@ const InvestmentDocuments = ({
}); });
const onSubmit = async (data) => { const onSubmit = async (data) => {
console.log("sibmited");
console.log(errors);
if (Object.keys(errors).length === 0) { if (Object.keys(errors).length === 0) {
const formData = new FormData(); const formData = new FormData();
formData.append("documentName", data.fileName); formData.append("documentName", data.fileName);
formData.append("documentNameArabic", data.documentNameArabic);
formData.append("document", data?.document[0]); formData.append("document", data?.document[0]);
setFormData(formData); setFormData(formData);
setAlert(true); setAlert(true);
@@ -109,7 +110,7 @@ const InvestmentDocuments = ({
setIsLoading(true); setIsLoading(true);
try { try {
const res = await createInvestmentDocument({ data: formData, id }); const res = await createInvestmentDocument({ data: formData, id });
console.log(res);
if (res?.error) { if (res?.error) {
toast({ toast({
render: () => ( render: () => (
@@ -214,6 +215,27 @@ const InvestmentDocuments = ({
</Text> </Text>
)} )}
</FormControl> </FormControl>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">File Name ( Arabic )</FormLabel>
<Input
name="documentNameArabic"
{...register("documentNameArabic")}
fontSize="sm"
type="text"
size="sm"
textAlign={'right'}
/>
{errors.documentNameArabic && (
<Text mt={1} fontSize="xs" fontWeight={500} color="red">
{errors.documentNameArabic.message}
</Text>
)}
</FormControl>
<FormControl mb={4} isRequired> <FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Document</FormLabel> <FormLabel fontSize="sm">Document</FormLabel>
<Input <Input
@@ -231,6 +253,8 @@ const InvestmentDocuments = ({
{errors.document.message} {errors.document.message}
</Text> </Text>
)} )}
<FormHelperText mt={1} fontSize="xs" fontWeight={500} color="gray.500">File size should be max 2mb</FormHelperText>
</FormControl> </FormControl>
{file && ( {file && (
<Box mt={4}> <Box mt={4}>

View File

@@ -71,7 +71,6 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
const onSubmit = (data) => { const onSubmit = (data) => {
if (Object.keys(errors).length === 0) { if (Object.keys(errors).length === 0) {
console.log("hit");
setFormData(data); setFormData(data);
setAlert(true); setAlert(true);
} }
@@ -81,32 +80,26 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
setIsLoading(true); setIsLoading(true);
try { try {
const res = await createKeyMerits({ data: formData, id }); const res = await createKeyMerits({ data: formData, id });
console.log(res?.error?.status);
if (res?.data?.statusCode === 201) { if (res?.data?.statusCode === 201) {
toast({ toast({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
setAlert(false); handleClose()
onClose();
setIsLoading(false);
reset();
return; return;
} }
if (res?.error?.data?.code === 400) { if (res?.error?.status === 400 || res?.error?.status === 500 ) {
toast({ toast({
render: () => ( render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} /> <ToastBox message={res?.error?.data?.message} status={"error"} />
), ),
}); });
setIsLoading(false); setIsLoading(false);
onClose();
setAlert(false); setAlert(false);
reset();
setFile(null);
setSelectedImageIcon(null);
setSelectedIcon("Select Icon");
return; return;
} }
} catch (error) { } catch (error) {
if (error) { if (error) {
toast({ toast({
@@ -119,12 +112,7 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
}); });
} }
setIsLoading(false); setIsLoading(false);
onClose(); handleClose()
setAlert(false);
reset();
setFile(null);
setSelectedImageIcon(null);
setSelectedIcon("Select Icon");
} }
reset(); reset();
}; };
@@ -135,7 +123,6 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
const handleFileChange = (e) => { const handleFileChange = (e) => {
const file = e.target.files[0]; const file = e.target.files[0];
console.log(file);
if (file) { if (file) {
setFile(URL.createObjectURL(file)); setFile(URL.createObjectURL(file));
} }
@@ -149,6 +136,7 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
const handleClose = () => { const handleClose = () => {
onClose(); onClose();
setIsLoading(false);
setAlert(false); setAlert(false);
reset(); reset();
setFile(null); setFile(null);
@@ -296,18 +284,18 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
} }
> >
<Box display="flex" alignItems="center"> <Box display="flex" alignItems="center">
<Image {selectedImageIcon && <Image
src={`https://tanami.betadelivery.com/${selectedImageIcon}`} src={`${import.meta.env.VITE_IMAGE_URL}${selectedImageIcon}`}
alt={selectedImageIcon} alt={selectedImageIcon}
boxSize="1rem" boxSize="1rem"
mr="12px" mr="12px"
/>{" "} />}{" "}
<Text as={"span"} fontSize={"sm"} fontWeight={500}> <Text as={"span"} fontSize={"sm"} fontWeight={500}>
{selectedIcon} {selectedIcon}
</Text> </Text>
</Box> </Box>
</MenuButton> </MenuButton>
<MenuList minW="415px" size={"sm"} fontWeight={500}> <MenuList overflow={'scroll'} minW="415px" size={"sm"} fontWeight={500}>
{icons?.map(({ iconName, id, iconFilePath }) => ( {icons?.map(({ iconName, id, iconFilePath }) => (
<MenuItem <MenuItem
key={id} key={id}
@@ -317,7 +305,7 @@ const KeyMeritsAdd = ({ isOpen, onClose, firstField, id, icons }) => {
> >
<Box display="flex" alignItems="center"> <Box display="flex" alignItems="center">
<Image <Image
src={`https://tanami.betadelivery.com/${iconFilePath}`} src={`${import.meta.env.VITE_IMAGE_URL}${iconFilePath}`}
alt={iconName} alt={iconName}
boxSize="1rem" boxSize="1rem"
mr="12px" mr="12px"

View File

@@ -59,6 +59,8 @@ const KeyMeritsEdit = ({
const [selectedImageIcon, setSelectedImageIcon] = useState(null); const [selectedImageIcon, setSelectedImageIcon] = useState(null);
const found = data?.find((item) => item?.id === actionId); const found = data?.find((item) => item?.id === actionId);
console.log(found);
const { const {
control, control,
@@ -71,6 +73,9 @@ const KeyMeritsEdit = ({
}); });
// useEffect to reset the form when `found` changes // useEffect to reset the form when `found` changes
useEffect(() => { useEffect(() => {
setValue("icon_xid", found?.icon?.id);
setSelectedIcon(found?.icon?.iconName); // Update selected icon name
setSelectedImageIcon(found?.icon?.iconFilePath);
if (found) { if (found) {
reset({ reset({
meritsHeader: found?.meritsHeader, meritsHeader: found?.meritsHeader,
@@ -91,10 +96,7 @@ const KeyMeritsEdit = ({
toast({ toast({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
setAlert(false); handleClose()
onClose();
setIsLoading(false);
reset();
return; return;
} }
if (res?.error?.data?.code === 400) { if (res?.error?.data?.code === 400) {
@@ -103,10 +105,7 @@ const KeyMeritsEdit = ({
<ToastBox message={res?.error?.data?.message} status={"error"} /> <ToastBox message={res?.error?.data?.message} status={"error"} />
), ),
}); });
setAlert(false); handleClose()
onClose();
setIsLoading(false);
reset();
return; return;
} }
} catch (error) { } catch (error) {
@@ -121,10 +120,7 @@ const KeyMeritsEdit = ({
), ),
}); });
} }
setIsLoading(false); handleClose()
setAlert(false);
onClose();
reset();
} }
reset(); reset();
}; };
@@ -133,7 +129,6 @@ const KeyMeritsEdit = ({
handleSubmit(onSubmit)(); handleSubmit(onSubmit)();
}; };
console.log(errors);
const handleIconSelect = (id, iconName, iconFilePath) => { const handleIconSelect = (id, iconName, iconFilePath) => {
setValue("icon_xid", id); setValue("icon_xid", id);
@@ -141,6 +136,14 @@ const KeyMeritsEdit = ({
setSelectedImageIcon(iconFilePath); setSelectedImageIcon(iconFilePath);
}; };
const handleClose = () => {
setIsLoading(false);
setAlert(false);
onClose();
reset();
}
return ( return (
<> <>
<Drawer <Drawer
@@ -280,12 +283,12 @@ const KeyMeritsEdit = ({
} }
> >
<Box display="flex" alignItems="center"> <Box display="flex" alignItems="center">
<Image {selectedImageIcon&&<Image
src={`https://tanami.betadelivery.com/${selectedImageIcon}`} src={`${import.meta.env.VITE_IMAGE_URL}${selectedImageIcon}`}
alt={selectedImageIcon} alt={selectedImageIcon}
boxSize="1rem" boxSize="1rem"
mr="12px" mr="12px"
/>{" "} />}{" "}
<Text as={"span"} fontSize={"sm"} fontWeight={500}> <Text as={"span"} fontSize={"sm"} fontWeight={500}>
{selectedIcon} {selectedIcon}
</Text> </Text>
@@ -301,7 +304,7 @@ const KeyMeritsEdit = ({
> >
<Box display="flex" alignItems="center"> <Box display="flex" alignItems="center">
<Image <Image
src={`https://tanami.betadelivery.com/${iconFilePath}`} src={`${import.meta.env.VITE_IMAGE_URL}${iconFilePath}`}
alt={iconName} alt={iconName}
boxSize="1rem" boxSize="1rem"
mr="12px" mr="12px"

View File

@@ -1,3 +1,4 @@
import React, { useContext, useEffect, useState } from 'react';
import { import {
Box, Box,
Button, Button,
@@ -12,10 +13,93 @@ import {
ModalHeader, ModalHeader,
ModalOverlay, ModalOverlay,
Text, Text,
Textarea, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { useForm } from 'react-hook-form';
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import GlobalStateContext from '../../../../Contexts/GlobalStateContext';
import { useParams } from 'react-router-dom';
import { useAmountIvestmentMutation } from '../../../../Services/io.service';
import ToastBox from '../../../../Components/ToastBox';
// Validation schema
const validationSchema = yup.object().shape({
transactionDate: yup.date().required('Date is required'),
Total_Amount: yup.number().required('Amount is required'),
amountInvested: yup.number().required('Amount to invest is required'),
IoCash: yup.number().positive('IO Cash must be positive').required('IO Cash is required'),
});
// Function to format currency
const formatCurrency = (value) => {
if (isNaN(value)) return '';
const formatted = parseFloat(value).toFixed(2).toString();
const [integer, decimal] = formatted.split('.');
const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return decimal ? `${formattedInteger}.${decimal}` : formattedInteger;
};
const AmountInvested = ({ isOpen, onClose }) => { const AmountInvested = ({ isOpen, onClose }) => {
const params = useParams();
const toast = useToast();
const id = params?.id;
const { control, register, handleSubmit, reset, watch, formState: { errors } } = useForm({
resolver: yupResolver(validationSchema),
});
const [isLoading, setIsLoading] = useState(false);
const { IODetails } = useContext(GlobalStateContext);
const [amountInvested] = useAmountIvestmentMutation();
useEffect(() => {
if (IODetails?.totalAmtInvestmentInUSD) {
const totalAmount = parseFloat(IODetails.totalAmtInvestmentInUSD);
const ioCashUpdate = parseFloat(IODetails.totalAmtInvestmentInUSD)
reset({
Total_Amount: totalAmount,
IoCash: ioCashUpdate,
});
}
}, [IODetails, reset]);
const onSubmit = async (data) => {
console.log(data);
setIsLoading(true);
try {
const res = await amountInvested({ data, id });
console.log(res);
if (res?.data?.statusCode === 200) {
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
setIsLoading(false);
onClose();
} else if (res?.error?.status === 400) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
});
setIsLoading(false);
}
} catch (error) {
setIsLoading(false);
}
};
const handleAmountChange = (e) => {
const amount = parseFloat(e.target.value) || 0;
const totalAmount = parseFloat(IODetails?.totalAmtInvestmentInUSD) || 0;
const ioCash = (totalAmount - amount).toFixed(2);
reset({
amountInvested: parseFloat(amount),
IoCash: parseFloat(ioCash),
Total_Amount: IODetails?.totalAmtInvestmentInUSD
});
};
return ( return (
<Modal isOpen={isOpen} onClose={onClose}> <Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay /> <ModalOverlay />
@@ -23,73 +107,92 @@ const AmountInvested = ({ isOpen, onClose }) => {
<ModalHeader fontSize={'md'}>Amount Invested</ModalHeader> <ModalHeader fontSize={'md'}>Amount Invested</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody> <ModalBody>
<FormControl mb={"15px"}> <form onSubmit={handleSubmit(onSubmit)}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}> <FormControl mb={"15px"} isInvalid={!!errors.transactionDate} isRequired>
Date <FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
</FormLabel> Date
<Input </FormLabel>
placeholder="Select Date" <Input
size="sm" type="date"
rounded={'sm'} {...register('transactionDate')}
fontSize={"sm"} size="sm"
focusBorderColor="forestGreen.300" rounded={'sm'}
type="date" fontSize={"sm"}
/> focusBorderColor="forestGreen.300"
</FormControl> />
{errors.transactionDate && <Text color="red.500">{errors.transactionDate.message}</Text>}
</FormControl>
<FormControl mb={"15px"} > <FormControl mb={"15px"} isInvalid={!!errors.Total_Amount} isReadOnly>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount</FormLabel> <FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount</FormLabel>
<Input <Input
size="sm" type="text"
rounded={'sm'} value={formatCurrency(watch('Total_Amount'))}
textAlign={'end'} size="sm"
readOnly rounded={'sm'}
value={"$ 100000"} textAlign={'end'}
focusBorderColor="forestGreen.300" focusBorderColor="forestGreen.300"
fontSize={"sm"} placeholder="$00.00" /> fontSize={"sm"}
</FormControl> readOnly
/>
{errors.Total_Amount && <Text color="red.500">{errors.Total_Amount.message}</Text>}
</FormControl>
<FormControl mb={"15px"} > <FormControl mb={"15px"} isInvalid={!!errors.amountInvested} isRequired>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount to invest</FormLabel> <FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount to invest</FormLabel>
<Input <Input
size="sm" type="number"
rounded={'sm'} {...register('amountInvested')}
textAlign={'end'} size="sm"
focusBorderColor="forestGreen.300" rounded={'sm'}
fontSize={"sm"} placeholder="$00.00" /> textAlign={'end'}
</FormControl> focusBorderColor="forestGreen.300"
fontSize={"sm"}
onChange={handleAmountChange}
/>
{errors.amountInvested && <Text color="red.500">{errors.amountInvested.message}</Text>}
</FormControl>
<FormControl mb={"15px"}> <FormControl mb={"15px"} isInvalid={!!errors.IoCash}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}> <FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
IO Cash IO Cash
</FormLabel> </FormLabel>
<Input <Input
size="sm" type="text"
rounded={'sm'} value={formatCurrency(watch('IoCash'))}
placeholder="$00.00" size="sm"
focusBorderColor="forestGreen.300" rounded={'sm'}
fontSize={"sm"} /> focusBorderColor="forestGreen.300"
</FormControl> fontSize={"sm"}
textAlign={'right'}
readOnly
/>
{errors.IoCash && <Text color="red.500">{errors.IoCash.message}</Text>}
</FormControl>
<ModalFooter>
<Button
type="submit"
bg={"hsla(139, 100%, 14%, 1)"}
mr={3}
color={"#fff"}
_hover={{
bg: "hsl(139deg 98.99% 26.59%)",
}}
size={'sm'}
rounded={"sm"}
isLoading={isLoading}
>
Save
</Button>
<Button
size={'sm'}
rounded={"sm"} mr={3} onClick={onClose}>
Close
</Button>
</ModalFooter>
</form>
</ModalBody> </ModalBody>
<ModalFooter>
<Button
bg={"hsla(139, 100%, 14%, 1)"}
mr={3}
color={"#fff"}
_hover={{
bg: "hsl(139deg 98.99% 26.59%)",
}}
size={'sm'}
rounded={"sm"}
>
Save
</Button>
<Button
size={'sm'}
rounded={"sm"} mr={3} onClick={onClose}>
Close
</Button>
</ModalFooter>
</ModalContent> </ModalContent>
</Modal> </Modal>
); );

View File

@@ -2,6 +2,7 @@ import {
Box, Box,
Button, Button,
FormControl, FormControl,
FormErrorMessage,
FormLabel, FormLabel,
HStack, HStack,
Input, Input,
@@ -23,8 +24,61 @@ import {
import DataTable from "../../../../Components/DataTable/DataTable"; import DataTable from "../../../../Components/DataTable/DataTable";
import { useState } from "react"; import { useState } from "react";
import { AddIcon } from "@chakra-ui/icons"; import { AddIcon } from "@chakra-ui/icons";
import { useGetDistributionInvestorMutation } from "../../../../Services/io.service";
import { useParams } from "react-router-dom";
import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
export const investor = yup.object().shape({
amount: yup.string().required("Amount is required"),
});
const DistributionInvestor = ({ isOpen, onClose, }) => {
const params = useParams()
const id = params?.id
// const {
// data:IObyID,
// error,
// isLoading,
// } = useGetDistributionInvestorMutation(id);
const [ getDistributionInvestment ] = useGetDistributionInvestorMutation()
const {
control,
handleSubmit,
formState: { errors },
reset,
} = useForm({
resolver: yupResolver(investor),
});
// useEffect(()=>{
// try {
// const res = getDistributionInvestment({id,data})
// console.log(res);
// } catch (error) {
// }
// },[])
// console.log(IObyID);
const DistributionInvestor = ({ isOpen, onClose }) => {
// ====================================================[Table Setup]================================================================ // ====================================================[Table Setup]================================================================
const tableHeadRow = [ const tableHeadRow = [
"Sr No.", "Sr No.",
@@ -205,22 +259,48 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
); );
}; };
const onSubmit = (data) =>{
console.log( data );
}
return ( return (
<Modal size={"xl"} isOpen={isOpen} onClose={onClose}> <Modal size={"xl"} isOpen={isOpen} onClose={onClose}>
<ModalOverlay /> <ModalOverlay />
<ModalContent maxW={1000}> <ModalContent maxW={1000}>
<ModalHeader fontSize={"md"}>Distribution To Investor Transaction</ModalHeader> <ModalHeader fontSize={"md"}>
Distribution To Investor Transaction
</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody> <ModalBody>
<Text as="label" mb='5px' fontSize='sm' fontWeight={500}>Amount to Distribute</Text> {/* <Text as="label" mb="5px" fontSize="sm" fontWeight={500}>
<HStack mb={4}> Amount to Distribute
<Input placeholder="$00.00" size={"sm"} className="col" /> </Text> */}
<HStack onSubmit={handleSubmit(onSubmit)} as={"form"} mb={4}>
{/* <Input placeholder="$00.00" size={"sm"} className="col" /> */} {/* <Input placeholder="$00.00" size={"sm"} className="col" /> */}
<FormControl isInvalid={errors.amount}>
<FormLabel fontSize={"sm"}> Amount to Distribute</FormLabel>
<Controller
name="amount"
control={control}
render={({ field }) => (
<Input {...field} fontSize={"sm"} type="number" size={"sm"} textAlign={"right"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.amount?.message}
</FormErrorMessage>
</FormControl>
<Button <Button
// leftIcon={<AddIcon />} // leftIcon={<AddIcon />}
size={"sm"} size={"sm"}
rounded={"sm"} rounded={"sm"}
colorScheme="forestGreen" colorScheme="forestGreen"
type="submit"
> >
Calculate Calculate
</Button> </Button>
@@ -243,14 +323,12 @@ const DistributionInvestor = ({ isOpen, onClose }) => {
_hover={{ _hover={{
bg: "hsl(139deg 98.99% 26.59%)", bg: "hsl(139deg 98.99% 26.59%)",
}} }}
size={'sm'} size={"sm"}
rounded={"sm"} rounded={"sm"}
> >
Save Save
</Button> </Button>
<Button <Button size={"sm"} rounded={"sm"} mr={3} onClick={onClose}>
size={'sm'}
rounded={"sm"} mr={3} onClick={onClose}>
Close Close
</Button> </Button>
</ModalFooter> </ModalFooter>

View File

@@ -2,6 +2,7 @@ import {
Box, Box,
Button, Button,
FormControl, FormControl,
FormErrorMessage,
FormLabel, FormLabel,
Input, Input,
Modal, Modal,
@@ -11,52 +12,168 @@ import {
ModalFooter, ModalFooter,
ModalHeader, ModalHeader,
ModalOverlay, ModalOverlay,
Select,
Stack,
Text, Text,
Textarea, Textarea,
useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { useContext, useState } from "react";
import * as yup from "yup";
import GlobalStateContext from "../../../../Contexts/GlobalStateContext";
import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import CurrencyInput from "../../../../Components/CurrencyInput";
import { useCreateIoNavMutation } from "../../../../Services/io.service";
import ToastBox from "../../../../Components/ToastBox";
import { useParams } from "react-router-dom";
import { formatDatee } from "../../../../Components/FormField";
const ioNav = yup.object().shape({
transactionDate: yup.string().required("Artifact name is required"),
// ioTransType_xid: yup.number().required("Artifact name is required"),
transactionAmount: yup.number().required("Artifact name is required"),
comments: yup.string().notRequired(),
});
const UpdateIONav = ({ isOpen, onClose }) => { const UpdateIONav = ({ isOpen, onClose }) => {
const params = useParams()
const toast = useToast();
const id = params?.id
const { IODetails } = useContext(GlobalStateContext);
const [isLoading, setIsLoading] = useState(false)
const {
control,
handleSubmit,
watch,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(ioNav),
});
const [createIoNav] = useCreateIoNavMutation()
const onSubmit = async (data) => {
setIsLoading(true);
try {
const res = await createIoNav({ data, id })
if (res?.data?.statusCode === 201) {
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
handleClose()
} else if (res?.error?.status === 400) {
setIsLoading(false);
toast({
render: () => <ToastBox message={res?.error?.data?.message} status={"error"} />,
});
}
} catch (error) {
console.log(error);
}
}
const handleClose = () => {
onClose()
reset()
}
const today = formatDatee(new Date(), 'yyyy-MM-dd');
return ( return (
<Modal isOpen={isOpen} onClose={onClose}> <Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent as={'form'} onSubmit={handleSubmit(onSubmit)} >
<ModalHeader fontSize={'md'}>Update iO NAV Transaction</ModalHeader> <ModalHeader fontSize={'md'}>Update iO NAV Transaction</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody> <ModalBody>
<FormControl mb={"15px"}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
Date
</FormLabel>
<Input
placeholder="Select Date"
size="sm"
rounded={'sm'}
fontSize={"sm"}
focusBorderColor="forestGreen.300"
type="date"
/>
</FormControl>
<FormControl mb={"15px"} > <Stack spacing={4}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount</FormLabel> <FormControl isInvalid={errors.transactionDate} isRequired>
<Input <FormLabel fontSize={"sm"}>Date Selection</FormLabel>
size="sm" <Controller
rounded={'sm'} name="transactionDate"
textAlign={'end'} control={control}
focusBorderColor="forestGreen.300" render={({ field }) => (
fontSize={"sm"} placeholder="$00.00" /> <Input {...field}
</FormControl> max={today} // Set max attribute to todays date
fontSize={"sm"} type="date" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionDate?.message}
</FormErrorMessage>
</FormControl>
<FormControl mb={"15px"}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}> {/* <FormControl isInvalid={errors.ioTransType_xid} isRequired>
Comments <FormLabel fontSize={"sm"}>Cash transaction</FormLabel>
</FormLabel> <Controller
<Textarea name="ioTransType_xid"
size="sm" control={control}
rounded={'sm'} render={({ field }) => (
focusBorderColor="forestGreen.300" <Select
fontSize={"sm"} placeholder="Write Comments" /> {...field}
</FormControl> placeholder="Select an option"
fontSize={"sm"}
size={"sm"}
>
{IODetails?.ioCashTransaction?.map(({ id, transactionName }) => (
<option key={id} value={id}>
{transactionName}
</option>
))}
</Select>
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.ioTransType_xid?.message}
</FormErrorMessage>
</FormControl> */}
<FormControl isInvalid={errors.transactionAmount} isRequired>
<FormLabel fontSize={"sm"}>Transaction Amount</FormLabel>
<Controller
name="transactionAmount"
control={control}
render={({ field }) => (
<CurrencyInput {...field} textAlign={'right'} fontSize={"sm"} type="number" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.transactionAmount?.message}
</FormErrorMessage>
</FormControl>
<FormControl isInvalid={errors.comments}>
<FormLabel fontSize={"sm"}>Comments</FormLabel>
<Controller
name="comments"
control={control}
render={({ field }) => (
<Textarea {...field} textAlign={'right'} fontSize={"sm"} type="text" size={"sm"} />
)}
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{errors.comments?.message}
</FormErrorMessage>
</FormControl>
</Stack>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button
@@ -68,10 +185,12 @@ const UpdateIONav = ({ isOpen, onClose }) => {
}} }}
size={'sm'} size={'sm'}
rounded={"sm"} rounded={"sm"}
type="submit"
isLoading={isLoading}
> >
Save Save
</Button> </Button>
<Button <Button
size={'sm'} size={'sm'}
rounded={"sm"} mr={3} onClick={onClose}> rounded={"sm"} mr={3} onClick={onClose}>
Close Close

View File

@@ -1,8 +1,9 @@
import { ChevronDownIcon } from "@chakra-ui/icons"; import { ChevronDownIcon } from "@chakra-ui/icons";
import React, { useState } from "react"; import React, { useEffect, useState } from "react";
import { import {
Badge, Badge,
Button, Button,
FormControl,
FormLabel, FormLabel,
Menu, Menu,
MenuButton, MenuButton,
@@ -15,6 +16,7 @@ import {
ModalFooter, ModalFooter,
ModalHeader, ModalHeader,
ModalOverlay, ModalOverlay,
FormErrorMessage
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { import {
useGetIOprepopulateDataQuery, useGetIOprepopulateDataQuery,
@@ -22,18 +24,20 @@ import {
} from "../../../../Services/io.service"; } from "../../../../Services/io.service";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
const UpdateIOStatus = ({ isOpen, onClose }) => { const UpdateIOStatus = ({ isOpen, onClose, status }) => {
const params = useParams(); const params = useParams();
const id = params?.id; const id = params?.id;
const [selectedItem, setSelectedItem] = useState("Open"); const [selectedItem, setSelectedItem] = useState();
const [isLoadingg, setIsLoading] = useState(false); const [isLoadingg, setIsLoading] = useState(false);
const { data, error, isLoading } = useGetIOprepopulateDataQuery(); const [error, setError] = useState("");
const [selectedStatusId, setSelectedStatusId] = useState(data?.data?.ioStatus[0]?.id); const [selectedStatusId, setSelectedStatusId] = useState('');
const { data } = useGetIOprepopulateDataQuery();
const [updateStatusIo] = useUpdateStatusIoMutation(); const [updateStatusIo] = useUpdateStatusIoMutation();
console.log(data?.data?.ioStatus);
console.log(data?.data?.ioStatus); // useEffect(() => {
// setSelectedStatusId(status?.[0]?.id);
// }, [status]);
const handleMenuItemClick = (item, id) => { const handleMenuItemClick = (item, id) => {
setSelectedItem(item); setSelectedItem(item);
@@ -41,7 +45,12 @@ const UpdateIOStatus = ({ isOpen, onClose }) => {
}; };
const handleSubmit = async () => { const handleSubmit = async () => {
setIsLoading(true) if (!selectedStatusId) {
setError("Please select status");
return;
}
setError("");
setIsLoading(true);
try { try {
const res = await updateStatusIo({ const res = await updateStatusIo({
data: { data: {
@@ -50,55 +59,119 @@ const UpdateIOStatus = ({ isOpen, onClose }) => {
id, id,
}); });
console.log(res); console.log(res);
setIsLoading(false) setIsLoading(false);
onClose() handleClose();
} catch (error) {} } catch (error) {
setIsLoading(false);
}
}; };
const handleClose = () => {
setSelectedItem(null)
setSelectedStatusId(null)
onClose()
setError("")
}
return ( return (
<Modal isOpen={isOpen} onClose={onClose}> <Modal isOpen={isOpen} onClose={handleClose}>
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<ModalHeader fontSize={"md"}>Update IO Status Transaction</ModalHeader> <ModalHeader fontSize={"md"}>Update IO Status Transaction</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody> <ModalBody>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}> <FormControl isInvalid={!!error}>
Status <FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
</FormLabel> Status
<Menu> </FormLabel>
<MenuButton <Menu>
as={Button} <MenuButton
rightIcon={<ChevronDownIcon />} as={Button}
fontSize={"sm"} rightIcon={<ChevronDownIcon />}
fontWeight={500} fontSize={"sm"}
w={"100%"} fontWeight={500}
textAlign={"left"} w={"100%"}
> textAlign={"left"}
{selectedItem} >
</MenuButton> {selectedItem ? (
<MenuList w={"400px"}> <Badge
{data?.data?.ioStatus?.map(({ id, statusAdmin }) => ( rounded={"full"}
<MenuItem pt={1.5}
key={id} pb={1.5}
fontSize={"sm"} ps={4}
onClick={() => handleMenuItemClick(statusAdmin, id)} pe={4}
> mt={1.5}
<Badge py={"1px"} px={"8px"}> mb={1.5}
{statusAdmin} textTransform={"none"}
colorScheme={
selectedItem === "Draft"
? "gray"
: selectedItem === "Processing"
? "yellow"
: selectedItem === "Open"
? "blue"
: selectedItem === "Closed"
? "green"
: selectedItem === "Exited"
? "red"
: selectedItem === "Canclled"
? "orange"
: "purple"
}
py={"3px"} px={"8px"}
>
{selectedItem}
</Badge> </Badge>
</MenuItem> ) : "Select Item"}
))} </MenuButton>
</MenuList>
</Menu> {status?.length > 0 ?<MenuList w={"400px"}>
{status?.map(({ id, statusAdmin }) => (
<MenuItem
key={id}
fontSize={"sm"}
onClick={() => handleMenuItemClick(statusAdmin, id)}
>
<Badge
rounded={"full"}
pt={1.5}
pb={1.5}
ps={4}
pe={4}
mt={1.5}
mb={1.5}
textTransform={"none"}
colorScheme={
statusAdmin === "Draft"
? "gray"
: statusAdmin === "Processing"
? "yellow"
: statusAdmin === "Open"
? "blue"
: statusAdmin === "Closed"
? "green"
: statusAdmin === "Exited"
? "red"
: statusAdmin === "Canclled"
? "orange"
: "purple"
}
py={"1px"} px={"8px"}
>
{statusAdmin}
</Badge>
</MenuItem>
))}
</MenuList>:""}
</Menu>
<FormErrorMessage fontSize={'xs'} fontWeight={600} >{error}</FormErrorMessage>
</FormControl>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<Button <Button
bg={"hsla(139, 100%, 14%, 1)"} colorScheme="forestGreen"
mr={3} mr={3}
color={"#fff"} color={"#fff"}
_hover={{
bg: "hsl(139deg 98.99% 26.59%)",
}}
size={"sm"} size={"sm"}
rounded={"sm"} rounded={"sm"}
onClick={handleSubmit} onClick={handleSubmit}
@@ -106,7 +179,7 @@ const UpdateIOStatus = ({ 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>
</ModalFooter> </ModalFooter>

View File

@@ -15,6 +15,7 @@ import {
Tag, Tag,
Text, Text,
Tooltip, Tooltip,
useDisclosure,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import React, { useContext, useEffect, useState } from "react"; import React, { useContext, useEffect, useState } from "react";
@@ -37,6 +38,11 @@ import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
import { useGetIOsQuery } from "../../../Services/io.service"; import { useGetIOsQuery } from "../../../Services/io.service";
import { TABLE_PAGINATION } from "../../../Constants/Paginations"; import { TABLE_PAGINATION } from "../../../Constants/Paginations";
import { formatCurrency } from "../../../Components/CurrencyInput";
import { IoIosPhonePortrait } from "react-icons/io";
import MobileView from "../../../Components/MobileView";
import { ImMobile } from "react-icons/im";
import { removeTrailingZeros } from "../../../Constants/Constants";
// import { debounce } from "./AddIOCharges"; // import { debounce } from "./AddIOCharges";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
@@ -54,27 +60,28 @@ const ViewIOTable = () => {
const [mouseEntered, setMouseEntered] = useState(false); const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState(""); const [mouseEnteredId, setMouseEnteredId] = useState("");
// ===============================[ Paginations ] const { isOpen: isOpen, onOpen: onOpen, onClose: onClose } = useDisclosure();
// ===============================[ Paginations ]
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);
// ===============================[ RTK Api calls ] // ===============================[ RTK Api calls ]
const { const { data, isLoading, error } = useGetIOsQuery({
data, page: currentPage,
isLoading, size: pageSize,
error, });
} = useGetIOsQuery({ page: currentPage, size: pageSize });
console.log(data);
// ===============================[ Table Header ] // ===============================[ Table Header ]
const tableHeadRow = [ const tableHeadRow = [
"IO ID", "IO ID",
"IO Name", "IO Name",
"Sponsorer", "Sponsor",
"Investment Type", "Investment Type",
"Goal Amount", "Goal Amount",
"Holding Period", "Holding Period",
"IO Status", "IO Status",
"Preview",
"Action", "Action",
]; ];
@@ -94,8 +101,6 @@ const ViewIOTable = () => {
return nameMatches && statusMatches; return nameMatches && statusMatches;
}); });
console.log(filteredData);
const extractedArray = filteredData?.map((item, index) => ({ const extractedArray = filteredData?.map((item, index) => ({
"IO ID": ( "IO ID": (
<Box w={"auto"} isTruncated={true}> <Box w={"auto"} isTruncated={true}>
@@ -121,14 +126,24 @@ const ViewIOTable = () => {
"Investment Type": ( "Investment Type": (
<Box w={"auto"} isTruncated={true}> <Box w={"auto"} isTruncated={true}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}> <Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item?.investmentType?.investmentTypeName ? item.investmentType?.investmentTypeName : "---"} {item?.investmentType?.investmentTypeName
? item.investmentType?.investmentTypeName
: "---"}
</Text> </Text>
</Box> </Box>
), ),
"Goal Amount": ( "Goal Amount": (
<Box w={"auto"} isTruncated={true}> <Box w={"100%"} display={"flex"} alignItems={"center"}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}> <Text
{item.goalAmount ? item.goalAmount : "---"} w={"100%"}
textAlign={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
>
{item.goalAmount
? formatCurrency(removeTrailingZeros(item.goalAmount))
: "---"}
</Text> </Text>
</Box> </Box>
), ),
@@ -142,63 +157,87 @@ const ViewIOTable = () => {
"IO Status": ( "IO Status": (
<Box w={"auto"} isTruncated={true}> <Box w={"auto"} isTruncated={true}>
<Badge <Badge
rounded={"sm"} rounded={"full"}
pt={0.5} pt={1}
pb={0.5} pb={1}
ps={4} ps={4}
pe={4} pe={4}
mt={1.5}
mb={1.5}
textTransform={"none"} textTransform={"none"}
color={ // variant={"solid"}
item?.ioStatus?.statusAdmin === "Draft"
? "yellow.500"
: item.ioStatus === "Pending"
? "#6226EF"
: "#EF3826"
}
colorScheme={ colorScheme={
item?.ioStatus?.statusAdmin === "Draft" item?.ioStatus?.statusAdmin === "Draft"
? "gray"
: item?.ioStatus?.statusAdmin === "Processing"
? "yellow" ? "yellow"
: item.ioStatus?.statusAdmin === "Pending" : item?.ioStatus?.statusAdmin === "Open"
? "purple" ? "blue"
: "red" : item?.ioStatus?.statusAdmin === "Closed"
? "green"
: item?.ioStatus?.statusAdmin === "Exited"
? "red"
: item?.ioStatus?.statusAdmin === "Canclled"
? "orange"
: "purple"
} }
boxShadow={"0 4px 6px rgba(0, 0, 0, 0.1)"} // Adjusted shadow
> >
{item.ioStatus?.statusAdmin} {item.ioStatus?.statusAdmin}
</Badge> </Badge>
</Box> </Box>
), ),
Preview: (
<Box display={"flex"} justifyContent={"start"}>
<Badge
display={"flex"} px={2} py={1} alignItems={"center"}
color={"#000"}
fontWeight={500}
bg="purple.200"
onClick={() =>{
setActionId(item.id)
onOpen();
}}
rounded={"sm"}
size={"xs"}
variant={"ghost"}
cursor={"pointer"}
>
<ImMobile className="me-1" /> View
</Badge>
</Box>
),
Action: ( Action: (
<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="View" label="View"
bg="#fff" bg="#fff"
color={"green.500"} color={"green.500"}
placement="top" placement="top"
> */}
<Button
// _hover={{ color: "green.500" }}
colorScheme="green"
// transition={"0.5s all"}
onClick={() => {
navigate(`/view-io/${item.id}`);
}}
// color="green.300"
rounded={"sm"}
size={"xs"}
> >
<Button <ViewIcon me={2} /> View
// _hover={{ color: "green.500" }} </Button>
colorScheme="green" {/* </Tooltip> */}
// transition={"0.5s all"}
onClick={() => {
navigate(`/view-io/${item.id}`);
}}
// color="green.300"
rounded={"sm"}
size={"xs"}
>
<ViewIcon />
</Button>
</Tooltip>
<Tooltip {/* <Tooltip
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} fontSize={"xs"}
label="View" label="Edit"
bg="#fff" bg="#fff"
color={"green.500"} color={"blue.500"}
placement="top" placement="top"
> >
<Button <Button
@@ -214,7 +253,7 @@ const ViewIOTable = () => {
> >
<EditIcon /> <EditIcon />
</Button> </Button>
</Tooltip> </Tooltip> */}
{/* <Tooltip {/* <Tooltip
rounded={"sm"} rounded={"sm"}
@@ -244,8 +283,6 @@ const ViewIOTable = () => {
const handleDelete = () => {}; const handleDelete = () => {};
console.log(extractedArray);
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">
@@ -290,10 +327,15 @@ const ViewIOTable = () => {
<option value="Exited">Exited</option> <option value="Exited">Exited</option>
<option value="Closed">Closed</option> <option value="Closed">Closed</option>
</Select> </Select>
<Pagination isLoading={isLoading} pageSize={pageSize} setPageSize={setPageSize} currentPage={currentPage} setCurrentPage={setCurrentPage} totalItems={data?.data?.totalItems} />
<Pagination
isLoading={isLoading}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalItems={data?.data?.totalItems}
/>
{/* <Link to={"/create-io"}> {/* <Link to={"/create-io"}>
<Button <Button
@@ -325,6 +367,8 @@ const ViewIOTable = () => {
setMouseEntered={setMouseEntered} setMouseEntered={setMouseEntered}
/> />
<MobileView isOpen={isOpen} onClose={onClose} actionId={actionId} />
<CustomAlertDialog <CustomAlertDialog
onClose={() => setDeleteAlert(false)} onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert} isOpen={deleteAlert}

View File

@@ -35,26 +35,32 @@ import IOArtifacts from "../CreateIO/IOArtifacts";
import IOCashDetails from "../CreateIO/IOCashDetails"; import IOCashDetails from "../CreateIO/IOCashDetails";
import IONAVDetails from "../CreateIO/IONAVDetails"; import IONAVDetails from "../CreateIO/IONAVDetails";
import { useGetIOprepopulateDataQuery } from "../../../Services/io.service"; import { useGetIOprepopulateDataQuery } from "../../../Services/io.service";
import UnderConstruction from "../../UnderConstruction";
const ViewIOdata = () => { const ViewIOdata = () => {
const params = useParams() const params = useParams()
const id = params?.id const id = params?.id
const { data, error, isLoading } = useGetIOprepopulateDataQuery(); const { data, error, isLoading } = useGetIOprepopulateDataQuery();
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const navigate = useNavigate(); const navigate = useNavigate();
const [isEditing, setIsEditing] = useState(false); const [isEditing, setIsEditing] = useState(false);
const { 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} /> },
{ label: "Investment documents", content: <InvestmentDocument data={data?.data} /> }, { label: "Investment documents", content: <InvestmentDocument data={data?.data} /> },
{ label: "Key merits", content: <KeyMerits data={data?.data} /> }, { label: "Key merits", content: <KeyMerits data={data?.data} /> },
{ label: "IO artifacts", content: <IOArtifacts data={data?.data} /> }, { label: "IO artifacts", content: <IOArtifacts data={data?.data} /> },
{ label: "Investors", content: <Investors data={data?.data} /> }, { label: "Investors", content: <Investors data={data?.data} /> },
// { label: "Investors", content: <UnderConstruction h={'75vh'} /> },
{ label: "IO Cash Details", content: <IOCashDetails data={data?.data} /> }, { label: "IO Cash Details", content: <IOCashDetails data={data?.data} /> },
{ label: "IO NAV Details", content: <IONAVDetails data={data?.data} /> }, { label: "IO NAV Details", content: <IONAVDetails data={data?.data} /> },
// { label: "Distribution", content: <ViewDistribution /> }, // { label: "Distribution to Investors", content: <IONAVDetails data={data?.data} /> },
{ label: "Distribution to Investors", content: <UnderConstruction h={'75vh'} /> },
]; ];
return ( return (
@@ -74,7 +80,15 @@ const ViewIOdata = () => {
<Box display={'flex'} > <Box display={'flex'} >
{tabs.map(({ label }, index) => ( {tabs.map(({ label }, index) => (
<Tab <Tab
disabled={true} px={3}
isDisabled={
index === 0 ||
index === 1 ||
index === 2 ||
index === 3 ||
index === 4 ?
false :
!IODetails?.isInvestedAmount}
key={index} key={index}
fontSize={"sm"} fontSize={"sm"}
_selected={{ _selected={{
@@ -89,7 +103,7 @@ const ViewIOdata = () => {
</TabList> </TabList>
<TabPanels> <TabPanels>
{tabs.map(({ content }, index) => ( {tabs.map(({ content }, index) => (
<TabPanel key={index}>{content}</TabPanel> <TabPanel key={index}>{content}</TabPanel>
))} ))}
</TabPanels> </TabPanels>
</Tabs> </Tabs>

View File

@@ -23,6 +23,7 @@ import {
Badge, Badge,
Box, Box,
Icon, Icon,
HStack,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import header from "../../../assets/IOheader.png"; import header from "../../../assets/IOheader.png";
import { HiDotsVertical } from "react-icons/hi"; import { HiDotsVertical } from "react-icons/hi";
@@ -39,18 +40,18 @@ import Exit from "./HeaderModal/Exit";
import Cancle from "./HeaderModal/Cancle"; import Cancle from "./HeaderModal/Cancle";
import { AddIcon } from "@chakra-ui/icons"; import { AddIcon } from "@chakra-ui/icons";
import { GrGallery } from "react-icons/gr"; import { GrGallery } from "react-icons/gr";
import Loader01 from "../../../Components/Loaders/Loader01";
// import { formatCurrency } from "../../../Components/CurrencyInput";
// import { removeTrailingZeros } from "../../../Constants/Constants";
const ViewIOdataHeader = () => { const ViewIOdataHeader = ({data, isLoading}) => {
const params = useParams(); const params = useParams();
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 } = useContext(GlobalStateContext); const { IODetails, isIOloading } = useContext(GlobalStateContext);
console.log(
"=================>>>>>",
IODetails?.artifactsImage?.[0]?.artifactPathName
);
const { const {
isOpen: isInvestmentOpen, isOpen: isInvestmentOpen,
onOpen: onInvestmentOpen, onOpen: onInvestmentOpen,
@@ -91,27 +92,104 @@ const ViewIOdataHeader = () => {
onOpen: onCancleOpen, onOpen: onCancleOpen,
onClose: onCancleClose, onClose: onCancleClose,
} = useDisclosure(); } = useDisclosure();
const bg = { const bg = {
bg: "#fff", bg: "#fff",
}; };
const hover = { const hover = {
textDecoration: "underline", textDecoration: "underline",
background: "#fff", background: "#fff",
}; };
const style = { const style = {
fontSize: "0.875rem", fontSize: "0.875rem",
fontWeight: "400", fontWeight: "400",
}; };
console.log(import.meta.env.VITE_IMAGE_URL +
IODetails?.artifactsImage?.[0]?.artifactPathName);
const menu = [
{
id:1,
title:"Amount Invested",
onClickFunction: onInvestmentOpen
},
// {
// id:2,
// title:"Fees & Expenses",
// onClickFunction:onFeesOpen
// },
// {
// id:3,
// title:"Distribution From Sponsors",
// onClickFunction:onDistSponsorOpen
// },
{
id:6,
title:"Distribution To Investors",
onClickFunction:onDistInvestorOpen
},
{
id:5,
title:"Update IO NAV",
onClickFunction:onUpdateNavOpen
},
{
id:8,
title:"Exit",
onClickFunction:onExitOpen
},
{
id:9,
title:"Cancel",
onClickFunction:onCancleOpen
},
{
id:10,
title:"Update IO Status",
onClickFunction:onUpdateStatusOpen
},
]
// console.log(IODetails?.mainTranscation);
// Extract titles from apiTransaction
const apiTransactionTitles = IODetails?.mainTranscation?.map(transaction => transaction.id);
// Filter menu items
const filteredMenu = menu?.filter(item => apiTransactionTitles?.includes(item.id));
return ( return (
IODetails?.investmentNameEnglish ?
<Box <Box
display={"flex"} display={"flex"}
alignItems={"center"} alignItems={"center"}
justifyContent={"start"} justifyContent={"space-between"}
gap={8} gap={8}
bg={"#caf5d8"} bg={
IODetails?.ioStatus?.statusAdmin === "Draft"
? "#EDF2F7"
: IODetails?.ioStatus?.statusAdmin === "Processing"
? "#FEFBBF"
: IODetails?.ioStatus?.statusAdmin === "Open"
? "#BEE2F8"
: IODetails?.ioStatus?.statusAdmin === "Closed"
? "#C6F6D5"
: IODetails?.ioStatus?.statusAdmin === "Exited"
? "red.500"
: IODetails?.ioStatus?.statusAdmin === "Canclled"
? "orange.500"
: IODetails?.ioStatus?.statusAdmin === "DeActivate"
? "#E9D8FD"
: null
}
rounded={"md"} rounded={"md"}
// bgGradient='linear(to-r, #caf5d8, #f5e8ca)' // bgGradient='linear(to-r, #caf5d8, #f5e8ca)'
// bgGradient='linear(to-r, #caf5d8, #d4a5a5)' // bgGradient='linear(to-r, #caf5d8, #d4a5a5)'
@@ -120,10 +198,12 @@ const ViewIOdataHeader = () => {
// bgGradient='linear(to-r, #ffd54f, #caf5d8)' // bgGradient='linear(to-r, #ffd54f, #caf5d8)'
// bgGradient='linear(to-r, #caf5d8, #a8e6cf)' // bgGradient='linear(to-r, #caf5d8, #a8e6cf)'
boxShadow={"md"} boxShadow={"md"}
paddingRight={"10px"}
borderRadius={"10px"}
position={"relative"} position={"relative"}
> >
<HStack gap={8}>
<Box h={100} w={200} p={1.5}> <Box h={100} w={200} p={1.5}>
{/* <Image rounded={'md'} h={"100%"} src={ " https://tanami.betadelivery.com/" + IODetails?.ioName} alt={IODetails?.ioName}/> */} {/* <Image rounded={'md'} h={"100%"} src={ " https://tanami.betadelivery.com/" + IODetails?.ioName} alt={IODetails?.ioName}/> */}
{IODetails?.artifactsImage?.[0]?.artifactPathName ? ( {IODetails?.artifactsImage?.[0]?.artifactPathName ? (
@@ -133,7 +213,7 @@ const ViewIOdataHeader = () => {
w={"100%"} w={"100%"}
objectFit={"cover"} objectFit={"cover"}
src={ src={
" https://tanami.betadelivery.com/" + import.meta.env.VITE_IMAGE_URL +
IODetails?.artifactsImage?.[0]?.artifactPathName IODetails?.artifactsImage?.[0]?.artifactPathName
} }
alt={IODetails?.ioName} alt={IODetails?.ioName}
@@ -152,24 +232,7 @@ const ViewIOdataHeader = () => {
</Box> </Box>
)} )}
</Box> </Box>
{/* <Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
IO name: <Text as={'span'} ms={2}>{foundObject?.ioName}</Text>
</Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
Sponsor name: <Text as={'span'} ms={2}>{foundObject?.sponserName}</Text>
</Text>
</Box> */}
{/* <Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO ID
</Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{IODetails?.io_id ? IODetails?.io_id : "---"}
</Text>
</Box> */}
<Box display={"flex"} w={"auto"} flexDirection={"column"} gap={2}> <Box display={"flex"} w={"auto"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}> <Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO Name IO Name
@@ -183,7 +246,7 @@ const ViewIOdataHeader = () => {
<Box display={"flex"} flexDirection={"column"} gap={2}> <Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}> <Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
Sponsorer Name Sponsor Name
</Text> </Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}> <Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{IODetails?.sponsor?.sponsorName {IODetails?.sponsor?.sponsorName
@@ -191,26 +254,38 @@ const ViewIOdataHeader = () => {
: "---"} : "---"}
</Text> </Text>
</Box> </Box>
</HStack>
<HStack gap={8} me={20}>
<Box display={"flex"} flexDirection={"column"} gap={2}> <Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}> <Text as={"span"} textAlign={'center'} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO Status IO Status
</Text> </Text>
<Badge <Badge
rounded={"sm"} rounded={"full"}
pt={0.5} pt={0}
pb={0.5} pb={0.5}
ps={4} ps={4}
pe={4} pe={4}
textTransform={"none"} textTransform={"none"}
variant={"solid"}
color={"#fff"} // variant={"solid"}
colorScheme={ colorScheme={
IODetails?.ioStatus?.statusAdmin === "Draft" IODetails?.ioStatus?.statusAdmin === "Draft"
? "gray"
: IODetails?.ioStatus?.statusAdmin === "Processing"
? "yellow"
: IODetails?.ioStatus?.statusAdmin === "Open"
? "blue" ? "blue"
: IODetails?.ioStatus?.statusAdmin === "Pending" : IODetails?.ioStatus?.statusAdmin === "Closed"
? "purple" ? "green"
: "forestGreen" : IODetails?.ioStatus?.statusAdmin === "Exited"
? "red"
: IODetails?.ioStatus?.statusAdmin === "Canclled"
? "orange"
: "purple"
} }
> >
{IODetails?.ioStatus?.statusAdmin {IODetails?.ioStatus?.statusAdmin
@@ -218,31 +293,39 @@ const ViewIOdataHeader = () => {
: "---"} : "---"}
</Badge> </Badge>
</Box> </Box>
<Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO MV
</Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{/* {IODetails?.ioNAV ? formatCurrency(removeTrailingZeros(IODetails?.ioNAV)) : "00.00"} */}
{parseFloat(IODetails?.ioNAV||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</Text>
</Box>
<Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO cash
</Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{/* {IODetails?.ioCash ? formatCurrency(removeTrailingZeros(IODetails?.ioCash)) : "00.00"} */}
{parseFloat(IODetails?.ioCash||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</Text>
</Box>
<Box display={"flex"} flexDirection={"column"} gap={2}> <Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}> <Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO NAV IO NAV
</Text> </Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}> <Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{IODetails?.currentValuation ? IODetails?.currentValuation : "00.00"} {/* {IODetails?.ioMVNAV ? formatCurrency(removeTrailingZeros(IODetails?.ioMVNAV)) : "00.00"} */}
</Text> {parseFloat(IODetails?.ioMVNAV||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
</Box>
<Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO cash
</Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{IODetails?.ioCash ? IODetails?.ioCash : "00.00"}
</Text>
</Box>
<Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO MV NAV
</Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{IODetails?.marketValue ? IODetails?.marketValue : "00.00"}
</Text> </Text>
</Box> </Box>
</HStack>
<Box <Box
position={"absolute"} position={"absolute"}
right={3} right={3}
@@ -272,113 +355,16 @@ const ViewIOdataHeader = () => {
> >
Tansaction Tansaction
</MenuItem> </MenuItem>
<MenuItem onClick={onInvestmentOpen} className="border-bottom">
Amount Invested {filteredMenu?.map(({id, title, onClickFunction})=><MenuItem key={id} onClick={onClickFunction} className="border-bottom">
</MenuItem> {title}
<MenuItem onClick={onFeesOpen} className="border-bottom"> </MenuItem>)}
Fees & Expenses
</MenuItem>
<MenuItem onClick={onDistSponsorOpen} className="border-bottom">
Distribution from Sponsors
</MenuItem>
<MenuItem onClick={onDistInvestorOpen} className="border-bottom">
Distribution To investors
</MenuItem>
<MenuItem onClick={onUpdateNavOpen} className="border-bottom">
Update iO NAV
</MenuItem>
<MenuItem onClick={onExitOpen} className="border-bottom">
Exit
</MenuItem>
<MenuItem onClick={onCancleOpen} className="border-bottom">
Cancel
</MenuItem>
<MenuItem onClick={onUpdateStatusOpen}>Update iO status</MenuItem>
</MenuList> </MenuList>
</Menu> </Menu>
{/* Drawer */}
{/* <Drawer
isOpen={isOpen}
placement="right"
onClose={onClose}
finalFocusRef={btnRef}
>
<DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader>Transaction</DrawerHeader>
<DrawerBody>
<Box
display={"grid"}
alignContent={"left"}
justifyItems={"start"}
>
<Button
onClick={onInvestmentOpen}
bg={bg}
_hover={hover}
paddingInline={"0px"}
>
Amount Invested
</Button>
<Divider />
<Button
onClick={onFeesOpen}
bg={bg}
_hover={hover}
paddingInline={"0px"}
>
Fees & Expenses
</Button>
<Divider />
<Button
onClick={onDistSponsorOpen}
bg={bg}
_hover={hover}
paddingInline={"0px"}
>
Distribution from Sponsors
</Button>
<Divider />
<Button
onClick={onDistInvestorOpen}
bg={bg}
_hover={hover}
paddingInline={"0px"}
>
Distribution To Investors
</Button>
<Divider />
<Button
onClick={onUpdateNavOpen}
bg={bg}
_hover={hover}
paddingInline={"0px"}
>
Update IO NAV
</Button>
<Divider />
<Button
onClick={onUpdateStatusOpen}
bg={bg}
_hover={hover}
paddingInline={"0px"}
>
Update IO Status
</Button>
<Divider />
</Box>
</DrawerBody>
<DrawerFooter>
<Button variant="outline" mr={3} onClick={onClose}>
Cancel
</Button>
</DrawerFooter>
</DrawerContent>
</Drawer> */}
{/* Modals */} {/* Modals */}
<AmountInvested isOpen={isInvestmentOpen} onClose={onInvestmentClose} /> <AmountInvested isOpen={isInvestmentOpen} onClose={onInvestmentClose} />
@@ -395,11 +381,29 @@ const ViewIOdataHeader = () => {
/> />
<UpdateIONav isOpen={isUpdateNavOpen} onClose={onUpdateNavClose} /> <UpdateIONav isOpen={isUpdateNavOpen} onClose={onUpdateNavClose} />
<UpdateIOStatus <UpdateIOStatus
status={IODetails?.nextStatus}
isOpen={isUpdateStatusOpen} isOpen={isUpdateStatusOpen}
onClose={onUpdateStatusClose} onClose={onUpdateStatusClose}
/> />
</Box> </Box>
</Box>
</Box>:
<Box
display={"flex"}
alignItems={"center"}
justifyContent={"center"}
rounded={"md"}
height={100}
bg={"#fff"}
// bgGradient='linear(to-r, #caf5d8, #f5e8ca)'
// bgGradient='linear(to-r, #caf5d8, #d4a5a5)'
// bgGradient='linear(to-r, #caf5d8, #d4a5a5)'
// bgGradient='linear(to-r, #caf5d8, #b3e5fc)'
// bgGradient='linear(to-r, #ffd54f, #caf5d8)'
// bgGradient='linear(to-r, #caf5d8, #a8e6cf)'
boxShadow={"md"}
> <Loader01 /></Box>
); );
}; };

View File

@@ -11,6 +11,8 @@ import { useGetIOByIdQuery } from "../../../Services/io.service";
import * as yup from "yup"; import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import { formatDate } from "../../Master/Sponser/Sponsers"; import { formatDate } from "../../Master/Sponser/Sponsers";
import { formatCurrency } from "../../../Components/CurrencyInput";
import { removeTrailingZeros } from "../../../Constants/Constants";
const schema = yup.object().shape({ const schema = yup.object().shape({
investmentNameEnglish: yup investmentNameEnglish: yup
@@ -71,7 +73,7 @@ const schema = yup.object().shape({
.positive("Expected return must be a positive number") .positive("Expected return must be a positive number")
.min(0.01, "Expected return must be at least 0.01"), .min(0.01, "Expected return must be at least 0.01"),
}); });
const ViewIOdetails = () => { const ViewIOdetails = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const params = useParams(); const params = useParams();
@@ -104,31 +106,33 @@ const ViewIOdetails = () => {
investmentNameArabic: IObyID?.data?.investmentNameArabic, investmentNameArabic: IObyID?.data?.investmentNameArabic,
descriptionEnglish: IObyID?.data?.descriptionEnglish, descriptionEnglish: IObyID?.data?.descriptionEnglish,
descriptionArabic: IObyID?.data?.descriptionArabic, descriptionArabic: IObyID?.data?.descriptionArabic,
goalAmount: IObyID?.data?.goalAmount, goalAmount: removeTrailingZeros(IObyID?.data?.goalAmount),
closingDate: IObyID?.data?.closingDate, closingDate: IObyID?.data?.closingDate,
holdingPeriod: IObyID?.data?.holdingPeriod, holdingPeriod: IObyID?.data?.holdingPeriod,
ISIN: IObyID?.data?.ISIN, ISIN: IObyID?.data?.ISIN,
comment: IObyID?.data?.comment, comment: IObyID?.data?.comment,
expectedReturn: IObyID?.data?.expectedReturn, expectedReturn: IObyID?.data?.expectedReturn,
investmentType_xid: IObyID?.data?.investmentType_xid, investmentType_xid: IObyID?.data?.investmentType_xid,
investmentType_xid: IObyID?.data?.investmentType_xid,
InvestmentDetails: IObyID?.data?.InvestmentDetails, InvestmentDetails: IObyID?.data?.InvestmentDetails,
minInvestmentAmount: IObyID?.data?.minInvestmentAmount, minInvestmentAmount: IObyID?.data?.minInvestmentAmount,
}); });
} }
}, [id, IObyID]); }, [id, IObyID]);
console.log(IObyID);
const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, id})=>{ const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, currencyCode, id})=>{
return{ return{
id:id, id:id,
country: country?.countryName, country: country?.countryName,
value: minInvestmentAmt, value: removeTrailingZeros(minInvestmentAmt),
logo: country?.flagIcon, logo: country?.flagIcon,
curr: country?.countryCode, curr: currencyCode,
} }
}) })
console.log();
//=======================[ Editor ] //=======================[ Editor ]
const formFields = [ const formFields = [
{ {
@@ -177,6 +181,61 @@ const ViewIOdetails = () => {
section: " ", section: " ",
width: "49%", width: "49%",
}, },
{
label: "Holding Period",
name: "holdingPeriod",
value: IObyID?.data?.holdingPeriod ? IObyID?.data?.holdingPeriod : "---",
type: "text",
isRequired: true,
placeHolder: "1Y",
section: " ",
width: "49%",
},
{
label: "Holding Period (Arabic)",
name: "holdingPeriodArabic",
value: IObyID?.data?.holdingPeriodArabic ? IObyID?.data?.holdingPeriodArabic : "---",
type: "text",
isRequired: true,
arabic: true,
placeHolder: "1Y",
section: " ",
width: "49%",
},
{
label: "Expected Return",
placeHolder: "$00.00",
name: "expectedReturn",
type: "number",
isRequired: true,
value: IObyID?.data?.expectedReturn
? IObyID?.data?.expectedReturn
: "---",
section: " ",
width: "49%",
},
{
label: "Expected Return (Arabic)",
name: "expectedReturnArabic",
placeHolder: "$00.00",
type: "number",
isRequired: true,
arabic: true,
value: IObyID?.data?.expectedReturnArabic
? IObyID?.data?.expectedReturnArabic
: "---",
section: " ",
width: "49%",
},
{ {
label: "Investment Type", label: "Investment Type",
placeHolder: "Select option", placeHolder: "Select option",
@@ -190,7 +249,7 @@ const ViewIOdetails = () => {
width: "32.3%", width: "32.3%",
}, },
{ {
label: "Sponsorer Name", label: "Sponsor Name",
placeHolder: "Select option", placeHolder: "Select option",
name: "sponsor_xid", name: "sponsor_xid",
type: "select", type: "select",
@@ -204,10 +263,12 @@ const ViewIOdetails = () => {
{ {
label: "Goal Amount", label: "Goal Amount",
placeHolder: "$00.00", placeHolder: "$00.00",
value: IObyID?.data?.goalAmount ? IObyID?.data?.goalAmount : "---", value: IObyID?.data?.goalAmount?parseFloat(IObyID?.data?.goalAmount||0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : "---",
name: "goalAmount", name: "goalAmount",
type: "number", type: "number",
isRequired: true, isRequired: true,
arabic:true,
section: " ", section: " ",
width: "32.3%", width: "32.3%",
}, },
@@ -222,28 +283,6 @@ const ViewIOdetails = () => {
section: " ", section: " ",
width: "32.3%", width: "32.3%",
}, },
{
label: "Holding Period",
name: "holdingPeriod",
value: IObyID?.data?.holdingPeriod ? IObyID?.data?.holdingPeriod : "---",
type: "text",
isRequired: true,
placeHolder: "1Y",
section: " ",
width: "32.3%",
},
{
label: "Expected Return",
placeHolder: "$00.00",
name: "expectedReturn",
type: "number",
isRequired: true,
value: IObyID?.data?.expectedReturn
? IObyID?.data?.expectedReturn
: "---",
section: " ",
width: "32.3%",
},
{ {
label: "ISIN", label: "ISIN",
placeHolder: "$00.00", placeHolder: "$00.00",
@@ -274,7 +313,6 @@ const ViewIOdetails = () => {
section: " ", section: " ",
width: "100%", width: "100%",
isRequired: true, isRequired: true,
type: "table",
value: minInvestmentById, value: minInvestmentById,
}, },
@@ -299,7 +337,7 @@ const ViewIOdetails = () => {
}, {}); }, {});
if (!IObyID?.data) { if (!IObyID?.data) {
return <FullscreenLoaders />; return <FullscreenLoaders height={'70vh'} />;
} }
return ( return (

View File

@@ -68,7 +68,6 @@ const InvestorDetails = () => {
error, error,
} = useGetInvestorsQuery({ page: currentPage, size: pageSize }); } = useGetInvestorsQuery({ page: currentPage, size: pageSize });
console.log(investorDetails);
useEffect(() => { useEffect(() => {
// Simulate loading // Simulate loading
@@ -82,7 +81,7 @@ const InvestorDetails = () => {
// ====================================================[Table Setup]================================================================ // ====================================================[Table Setup]================================================================
const tableHeadRow = [ const tableHeadRow = [
"Sr N/O", // "Sr N/O",
"Client ID", "Client ID",
"First Name", "First Name",
"Last Name", "Last Name",
@@ -109,7 +108,7 @@ const InvestorDetails = () => {
// ====================================================[Table Filter]================================================================ // ====================================================[Table Filter]================================================================
const filteredData = investorDetails?.data?.rows?.filter((item) => { const filteredData = investorDetails?.data?.rows?.filter((item) => {
// Filter by name (case insensitive) // Filter by name (case insensitive)
const name = item.clientReference_id; const name = [item?.principal?.firstName, item?.principal?.lastName, item?.country?.countryName, item?.principal?.mobileNumber, item?.principal?.emailAddress].filter(Boolean).join(' ');
const searchLower = searchTerm.toLowerCase(); const searchLower = searchTerm.toLowerCase();
const nameMatches = name?.toLowerCase().includes(searchLower); const nameMatches = name?.toLowerCase().includes(searchLower);
@@ -125,7 +124,6 @@ const InvestorDetails = () => {
return nameMatches; return nameMatches;
}); });
console.log(investorDetails);
const extractedArray = filteredData?.map((item) => ({ const extractedArray = filteredData?.map((item) => ({
id: item?.id, id: item?.id,
@@ -264,6 +262,9 @@ const InvestorDetails = () => {
onEditOpen(); onEditOpen();
}; };
console.log(investorDetails?.data?.totalItems);
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">
@@ -365,12 +366,13 @@ 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>
</HStack> </HStack>

View File

@@ -34,7 +34,6 @@ const ProfileView = () => {
skip: !id, skip: !id,
}); });
console.log(data?.data);
const foundObject = data?.data; const foundObject = data?.data;
@@ -175,7 +174,7 @@ const ProfileView = () => {
as="span" as="span"
boxShadow={"lg"} boxShadow={"lg"}
rounded={"md"} rounded={"md"}
bg={"#EAF2EC"} bg={"#EAF2EC"}
> >
<Icon color={"#004717"} boxSize={8} as={LuWallet} /> <Icon color={"#004717"} boxSize={8} as={LuWallet} />
@@ -238,6 +237,7 @@ const ProfileView = () => {
View Details View Details
</Tab> </Tab>
<Tab <Tab
isDisabled={true}
fontSize={"sm"} fontSize={"sm"}
_selected={{ _selected={{
color: "#004118", color: "#004118",
@@ -247,6 +247,7 @@ const ProfileView = () => {
Portfolio Portfolio
</Tab> </Tab>
<Tab <Tab
isDisabled={true}
fontSize={"sm"} fontSize={"sm"}
_selected={{ _selected={{
color: "#004118", color: "#004118",
@@ -256,6 +257,7 @@ const ProfileView = () => {
Transaction Transaction
</Tab> </Tab>
<Tab <Tab
isDisabled={true}
fontSize={"sm"} fontSize={"sm"}
_selected={{ _selected={{
color: "#004118", color: "#004118",

View File

@@ -22,8 +22,21 @@ import {
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import GlobalStateContext from "../Contexts/GlobalStateContext"; import GlobalStateContext from "../Contexts/GlobalStateContext";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { validationSchema } from "../Validations/Validations";
import ToastBox from "../Components/ToastBox"; import ToastBox from "../Components/ToastBox";
import { useLoginMutation } from "../Services/token.serivce";
// import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";
const validationSchema = Yup.object().shape({
emailAddress: Yup.string()
.email("Invalid email address")
.required("Email address is required"),
password_hash: Yup.string().required("Password is required"),
});
const Login = () => { const Login = () => {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
@@ -36,43 +49,77 @@ const Login = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
const [login] = useLoginMutation()
useEffect(() => { useEffect(() => {
if (isAuthenticate) { if (isAuthenticate) {
navigate("/"); navigate("/sponser");
} }
}, [navigate, isAuthenticate]); }, [navigate, isAuthenticate]);
const onSubmit = (value) => { const onSubmit = async (value) => {
setIsLoading(true); setIsLoading(true);
if (value.name === "admin@tanami.com" && value.password === "Admin@123") { try {
return setTimeout(() => { const res = await login(value).unwrap();
// dispatch(loginUser(true));
if (res?.statusCode === 200) {
toast({
render: () => (
<ToastBox status={"success"} message={res?.message} />
),
})
setIsLoading(false);
setIsAuthenticate(true); setIsAuthenticate(true);
setIsLoading(false);
toast({
render: () => (
<ToastBox status={"success"} message={"Login Successfully"} />
),
});
Cookies.set("isAuthenticated", true, { expires: 7 }); Cookies.set("isAuthenticated", true, { expires: 7 });
navigate("/"); navigate("/sponser");
}, 2000); // 3-second delay reset();
} else { }
return setTimeout(() => {
// dispatch(loginUser(true));
setIsAuthenticate(false);
setIsLoading(false);
} catch (err) {
if (err) {
toast({ toast({
render: () => ( render: () => (
<ToastBox status={"error"} message={"Invalid credentials"} /> <ToastBox status={"error"} message={err?.data?.message} />
), ),
}); });
reset(); setIsLoading(false);
navigate("/login"); }
}, 2000);
} }
// if (value.emailAddress === "admin@tanami.com" && value.password_hash === "Admin@123") {
// return setTimeout(() => {
// // dispatch(loginUser(true));
// setIsAuthenticate(true);
// setIsLoading(false);
// toast({
// render: () => (
// <ToastBox status={"success"} message={"Login Successfully"} />
// ),
// });
// Cookies.set("isAuthenticated", true, { expires: 7 });
// navigate("/");
// }, 2000); // 3-second delay
// } else {
// return setTimeout(() => {
// // dispatch(loginUser(true));
// setIsAuthenticate(false);
// setIsLoading(false);
// toast({
// render: () => (
// <ToastBox status={"error"} message={"Invalid credentials"} />
// ),
// });
// reset();
// navigate("/login");
// }, 2000);
// }
}; };
const { const {
@@ -84,6 +131,9 @@ const Login = () => {
resolver: yupResolver(validationSchema), resolver: yupResolver(validationSchema),
}); });
console.log(errors);
return ( return (
<div <div
style={{ style={{
@@ -138,18 +188,18 @@ const Login = () => {
</FormLabel> </FormLabel>
<Input <Input
{...register("name")} {...register("emailAddress")}
focusBorderColor="green.500" focusBorderColor="green.500"
type="text" type="text"
name="name" name="emailAddress"
variant="filled" variant="filled"
placeholder="Email" placeholder="Email"
size="lg" size="lg"
className="web-text-medium" className="web-text-medium"
/> />
{errors.name && ( {errors.emailAddress && (
<span className="text-danger web-text-small fw-bold ps-2 d-flex align-items-center gap-1 mt-1"> <span className="text-danger web-text-small fw-bold ps-2 d-flex align-items-center gap-1 mt-1">
<TiWarning className="fw-bold fs-5 " /> {errors.name.message} <TiWarning className="fw-bold fs-5 " /> {errors.emailAddress.message}
</span> </span>
)} )}
</FormControl> </FormControl>
@@ -161,7 +211,7 @@ const Login = () => {
<InputGroup size="lg"> <InputGroup size="lg">
<Input <Input
{...register("password")} {...register("password_hash")}
className="web-text-medium" className="web-text-medium"
focusBorderColor="green.500" focusBorderColor="green.500"
variant="filled" variant="filled"
@@ -181,9 +231,9 @@ const Login = () => {
</Button> </Button>
</InputRightElement> </InputRightElement>
</InputGroup> </InputGroup>
{errors.password && ( {errors.password_hash && (
<span className="text-danger web-text-small fw-bold ps-2 d-flex align-items-center gap-1 mt-1"> <span className="text-danger web-text-small fw-bold ps-2 d-flex align-items-center gap-1 mt-1">
<TiWarning className="fw-bold fs-5 " /> {errors.password.message} <TiWarning className="fw-bold fs-5 " /> {errors.password_hash.message}
</span> </span>
)} )}
</FormControl> </FormControl>

View File

@@ -29,6 +29,9 @@ import {
useUpdateExchangeRateMutation, useUpdateExchangeRateMutation,
} from "../../../Services/exchange.rate.service"; } from "../../../Services/exchange.rate.service";
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
import { getTomorrowDate } from "../../../Constants/Constants";
// Convert date to YYYY-MM-DD format // Convert date to YYYY-MM-DD format
const formatDateValue = (date) => { const formatDateValue = (date) => {
@@ -44,7 +47,7 @@ const formatDateValue = (date) => {
return [year, month, day].join("-"); return [year, month, day].join("-");
}; };
const EditExchangeRate = ({ id, setIsLoading, updateHistory }) => { const EditExchangeRate = ({ id, setIsLoading }) => {
const btnRef = useRef(); const btnRef = useRef();
const toast = useToast(); const toast = useToast();
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
@@ -73,9 +76,7 @@ const EditExchangeRate = ({ id, setIsLoading, updateHistory }) => {
rate: rate, rate: rate,
}; };
const res = await updateExchange({ data, id }); const res = await updateExchange({ data, id });
console.log(res?.data?.statusCode);
if (res?.data?.statusCode === 200) { if (res?.data?.statusCode === 200) {
console.log("hit");
toast({ toast({
render: () => <ToastBox message={res?.data?.message} />, render: () => <ToastBox message={res?.data?.message} />,
}); });
@@ -88,7 +89,6 @@ const EditExchangeRate = ({ id, setIsLoading, updateHistory }) => {
return ( return (
<> <>
{" "}
<Tooltip <Tooltip
rounded={"sm"} rounded={"sm"}
fontSize={"xs"} fontSize={"xs"}
@@ -115,79 +115,97 @@ const EditExchangeRate = ({ id, setIsLoading, updateHistory }) => {
</Button> </Button>
</Tooltip> </Tooltip>
<Drawer <Drawer
size={"md"} // size={"md"}
isOpen={isOpen} isOpen={isOpen}
placement="right" placement="right"
onClose={onClose} onClose={onClose}
finalFocusRef={btnRef} finalFocusRef={btnRef}
> >
<form onSubmit={(e) =>{ <form
e.preventDefault() onSubmit={(e) => {
setAlert(true)}}> e.preventDefault();
<DrawerOverlay /> setAlert(true);
<DrawerContent> }}
<DrawerCloseButton /> >
<DrawerHeader fontSize={"md"}>Edit rate</DrawerHeader> <DrawerOverlay />
<DrawerContent>
<DrawerCloseButton />
<DrawerHeader fontSize={"md"}>Edit rate</DrawerHeader>
<DrawerBody> <DrawerBody>
<Box display={"flex"} mb={5}>
<Box display={"flex"} mb={5}> <Box
<Box w={"50%"} display={"flex"} flexDirection={"column"} gap={1}> w={"50%"}
<FormLabel fontSize={"sm"}>From</FormLabel> display={"flex"}
<Text as={"span"} fontSize={"sm"} fontWeight={"bold"}> flexDirection={"column"}
{foundObject?.fromCurrency?.currencyCode} gap={1}
</Text> >
<FormLabel fontSize={"sm"}>From</FormLabel>
<Text as={"span"} fontSize={"sm"} fontWeight={"bold"}>
{foundObject?.fromCurrency?.currencyCode}
</Text>
</Box>
<Box
w={"50%"}
display={"flex"}
flexDirection={"column"}
gap={1}
>
<FormLabel fontSize={"sm"}>To</FormLabel>
<Text as={"span"} fontSize={"sm"} fontWeight={"bold"}>
{foundObject?.toCurrency?.currencyCode}
</Text>
</Box>
</Box> </Box>
<Box w={"50%"} display={"flex"} flexDirection={"column"} gap={1}>
<FormLabel fontSize={"sm"}>To</FormLabel> <FormControl mb={4}>
<Text as={"span"} fontSize={"sm"} fontWeight={"bold"}> <FormLabel fontSize={"sm"}>Last effective date</FormLabel>
{foundObject?.toCurrency?.currencyCode} <Text color={'gray.500'} fontSize={"sm"}>
{formatDate(foundObject?.effectiveFrom)}
</Text> </Text>
</Box> </FormControl>
</Box> <FormControl mb={4}>
<FormLabel fontSize={"sm"}>Effective from</FormLabel>
<Text fontSize={"sm"}>
{formatDate(getTomorrowDate())}
</Text>
</FormControl>
<FormControl mb={4}> <FormControl mb={4} isRequired>
<FormLabel fontSize={"sm"}>Effective from</FormLabel> <FormLabel fontSize={"sm"}>Rate</FormLabel>
<Text fontSize={"sm"}> <Input
{formatDate(foundObject?.effectiveFrom)} required
</Text> type="number"
</FormControl> placeholder="Type rate here..."
size={"sm"}
value={rate}
onChange={(e) => setRate(e.target.value)}
/>
</FormControl>
</DrawerBody>
<FormControl mb={4} isRequired> <DrawerFooter>
<FormLabel fontSize={"sm"}>Rate</FormLabel> <Button
<Input variant="outline"
required colorScheme={"forestGreen"}
type="number" rounded={"sm"}
placeholder="Type rate here..."
size={"sm"} size={"sm"}
value={rate} mr={3}
onChange={(e) => setRate(e.target.value)} onClick={onClose}
/> >
</FormControl> Cancel
</DrawerBody> </Button>
<DrawerFooter> <Button
<Button colorScheme={"forestGreen"}
variant="outline" rounded={"sm"}
colorScheme={"forestGreen"} size={"sm"}
rounded={"sm"} type="submit"
size={"sm"} >
mr={3} Save
onClick={onClose} </Button>
> </DrawerFooter>
Cancel </DrawerContent>
</Button>
<Button
colorScheme={"forestGreen"}
rounded={"sm"}
size={"sm"}
type="submit"
>
Save
</Button>
</DrawerFooter>
</DrawerContent>
</form> </form>
</Drawer> </Drawer>
<CustomAlertDialog <CustomAlertDialog

View File

@@ -34,10 +34,11 @@ import { useGetAllExchangeRatesQuery } from "../../../Services/exchange.rate.ser
import { TABLE_PAGINATION } from "../../../Constants/Paginations"; import { TABLE_PAGINATION } from "../../../Constants/Paginations";
import NormalTable from "../../../Components/DataTable/NormalTable"; import NormalTable from "../../../Components/DataTable/NormalTable";
import { MdHistory } from "react-icons/md"; import { MdHistory } from "react-icons/md";
import { formatCurrency } from "../../../Components/CurrencyInput";
const ExchangeRate = () => { const ExchangeRate = () => {
const toast = useToast(); const toast = useToast();
const navigate = useNavigate() const navigate = useNavigate();
const { slideFromRight, rateExchange, setRateExchange } = const { slideFromRight, rateExchange, setRateExchange } =
useContext(GlobalStateContext); useContext(GlobalStateContext);
const [searchTerm, setSearchTerm] = useState(""); const [searchTerm, setSearchTerm] = useState("");
@@ -46,47 +47,18 @@ const ExchangeRate = () => {
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 [history, setHistory] = useState([]);
// ===============================[ Paginations ] // ===============================[ Paginations ]
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size); const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { const {
data, data,
isLoading: isExchangeRateLoading, isLoading: isExchangeRateLoading,
errors, errors,
} = useGetAllExchangeRatesQuery({ page: currentPage, size: pageSize }) } = useGetAllExchangeRatesQuery({ page: currentPage, size: pageSize });
console.log(data?.data); console.log(data?.data);
const updateHistory = (id, previousRate, newRate, effectFrom) => {
setHistory((prevHistory) => [
...prevHistory,
{ id, effectFrom, previousRate, newRate },
]);
};
// ====================================================[Table Filter]================================================================
const filteredData = rateExchange.filter((item) => {
// Filter by name (case insensitive)
const name = item.fromCurr;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
// Filter by status
// const status = item.status;
// const statusLower = status ? "active" : "inactive";
// const statusMatches =
// statusFilter === "all" ||
// (statusFilter === "active" && status === true) ||
// (statusFilter === "inactive" && status === false);
return nameMatches;
});
// ====================================================[Table Setup]================================================================ // ====================================================[Table Setup]================================================================
const tableHeadRow = [ const tableHeadRow = [
@@ -129,7 +101,7 @@ const ExchangeRate = () => {
fontWeight={"600"} fontWeight={"600"}
className="d-flex align-items-center fw- web-text-small" className="d-flex align-items-center fw- web-text-small"
> >
{item?.toCurrency?.currencyCode} {item?.toCurrency?.currencyCode}
</Text> </Text>
), ),
"Effective from": ( "Effective from": (
@@ -145,13 +117,13 @@ const ExchangeRate = () => {
), ),
Rate: ( Rate: (
<Text <Text
justifyContent={slideFromRight ? "right" : "left"} justifyContent={"left"}
as={"span"} as={"span"}
color={"gray.600"} color={"gray.600"}
fontWeight={"600"} fontWeight={"600"}
className="d-flex align-items-center web-text-small" className="d-flex align-items-center web-text-small"
> >
{item.rate} {formatCurrency(item.rate)}
</Text> </Text>
), ),
@@ -163,34 +135,32 @@ const ExchangeRate = () => {
<EditExchangeRate <EditExchangeRate
setIsLoading={setIsLoading} setIsLoading={setIsLoading}
id={item.id} id={item.id}
updateHistory={updateHistory} // updateHistory={updateHistory}
/> />
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="History"
bg="#fff"
color={"purple.500"}
placement="top"
>
<Button
// _hover={{ color: "purple.500" }}
// transition={"0.5s all"}
// color="purple.400"
colorScheme="purple"
rounded={"sm"}
size={{base:'xs', lg:'xs'}}
onClick={() => navigate(`currency-history/${item?.id}`)}
display={'flex'} <Tooltip
alignItems={'center'} rounded={"sm"}
gap={1} fontSize={"xs"}
label="History"
> bg="#fff"
<MdHistory /> color={"purple.500"}
</Button> placement="top"
</Tooltip> >
<Button
// _hover={{ color: "purple.500" }}
// transition={"0.5s all"}
// color="purple.400"
colorScheme="purple"
rounded={"sm"}
size={{ base: "xs", lg: "xs" }}
onClick={() => navigate(`currency-history/${item?.id}`)}
display={"flex"}
alignItems={"center"}
gap={1}
>
<MdHistory />
</Button>
</Tooltip>
</Box> </Box>
), ),
})); }));
@@ -214,7 +184,7 @@ const ExchangeRate = () => {
<HStack <HStack
display={"flex"} display={"flex"}
justifyContent={"space-between"} justifyContent={"space-between"}
ps={1} ps={1}
pe={1} pe={1}
pb={4} pb={4}
pt={4} pt={4}
@@ -230,8 +200,6 @@ const ExchangeRate = () => {
value={searchTerm} value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
/> />
</HStack> </HStack>
</Box> </Box>

View File

@@ -7,21 +7,25 @@ import * as yup from "yup";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import FormInputMain from "../../../Components/FormInputMain"; import FormInputMain from "../../../Components/FormInputMain";
import SwitchButton from "../../../Components/SwitchButton"; import SwitchButton from "../../../Components/SwitchButton";
import {useCreateInvestmentTypeMutation, import {
useCreateInvestmentTypeMutation,
useGetInvestmentTypeByIdQuery, useGetInvestmentTypeByIdQuery,
useUpdateInvestmentTypeMutation, useUpdateInvestmentTypeMutation,
} from "../../../Services/investment.type.service"; } from "../../../Services/investment.type.service";
import ToastBox from "../../../Components/ToastBox"; import ToastBox from "../../../Components/ToastBox";
import CustomAlertDialog from "../../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders";
// ======================= [validation] ========================= // ======================= [validation] =========================
export const addInvestmentType = yup.object().shape({ export const addInvestmentType = yup.object().shape({
investmentTypeName: yup.string() investmentTypeName: yup.string()
.required('Investment type is required') .required('Investment type is required')
.max(50, 'Investment name cannot be more than 50 characters'), .max(50, 'Investment name cannot be more than 50 characters'),
note: yup.string().notRequired(), note: yup.string()
investmentTypeNameArabic: yup.string().required(), .optional()
.max(255, 'Note cannot exceed 255 characters'),
investmentTypeNameArabic: yup.string().required("Investment type in arabic required"),
noteArabic: yup.string().notRequired(), noteArabic: yup.string().notRequired(),
}); });
@@ -36,7 +40,7 @@ export function debounce(func, delay) {
} }
const AddInvestmentType = () => { const AddInvestmentType = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const toast = useToast(); const toast = useToast();
const params = useParams(); const params = useParams();
@@ -60,13 +64,14 @@ const AddInvestmentType = () => {
const { const {
control, control,
handleSubmit, handleSubmit,
watch,
formState: { errors }, formState: { errors },
reset, reset,
} = useForm({ } = useForm({
resolver: yupResolver(addInvestmentType), resolver: yupResolver(addInvestmentType),
}); });
const {data: investmentTypeByIdData,error,isLoading,} = useGetInvestmentTypeByIdQuery(id, { skip: !id }); const { data: investmentTypeByIdData, error, isLoading, } = useGetInvestmentTypeByIdQuery(id, { skip: !id });
@@ -81,6 +86,7 @@ const AddInvestmentType = () => {
note: investmentTypeByIdData?.data?.note, note: investmentTypeByIdData?.data?.note,
noteArabic: investmentTypeByIdData?.data?.noteArabic, noteArabic: investmentTypeByIdData?.data?.noteArabic,
}); });
setIsSwitchOn(investmentTypeByIdData?.data?.isActive)
} }
}, [investmentTypeByIdData, reset]); }, [investmentTypeByIdData, reset]);
@@ -88,7 +94,7 @@ const AddInvestmentType = () => {
return <FullscreenLoaders />; return <FullscreenLoaders />;
} }
// ============================ [API]=============================== // ============================ [API]===============================
const handleConfirm = async () => { const handleConfirm = async () => {
setIsLoadingBtn(true); setIsLoadingBtn(true);
@@ -169,7 +175,8 @@ const AddInvestmentType = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "Add Details",
maxLength:50 maxLength: 50,
helperText:`Maximum length should be 50 characters. You have entered ${watch()?.investmentTypeName?.length || 0} characters.`
}, },
{ {
label: "Investment Type (Arabic) ", label: "Investment Type (Arabic) ",
@@ -179,7 +186,8 @@ const AddInvestmentType = () => {
isRequired: true, isRequired: true,
section: "Add Details", section: "Add Details",
arabic: true, arabic: true,
maxLength:255 maxLength: 255,
helperText:`Maximum length should be 255 characters. You have entered ${watch()?.investmentTypeNameArabic?.length || 0} characters.`
}, },
{ {
label: "Description (English)", label: "Description (English)",
@@ -188,7 +196,8 @@ const AddInvestmentType = () => {
type: "textarea", type: "textarea",
// isRequired: true, // isRequired: true,
section: "Add Details", section: "Add Details",
maxLength:255 maxLength: 255,
helperText:`Maximum length should be 255 characters. You have entered ${watch()?.note?.length || 0} characters.`
}, },
{ {
label: "Description (Arabic)", label: "Description (Arabic)",
@@ -198,7 +207,8 @@ const AddInvestmentType = () => {
// isRequired: true, // isRequired: true,
arabic: true, arabic: true,
section: "Add Details", section: "Add Details",
maxLength:255 maxLength: 255,
helperText:`Maximum length should be 255 characters. You have entered ${watch()?.noteArabic?.length || 0} characters.`
}, },
]; ];
@@ -212,6 +222,8 @@ const AddInvestmentType = () => {
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "Add Details",
maxLength: 50,
helperText:`Maximum length should be 50 characters. You have entered ${watch()?.investmentTypeName?.length || 0} characters.`
}, },
{ {
label: "Investment Type (Arabic)", label: "Investment Type (Arabic)",
@@ -221,6 +233,8 @@ const AddInvestmentType = () => {
isRequired: true, isRequired: true,
section: "Add Details", section: "Add Details",
arabic: true, arabic: true,
maxLength: 255,
helperText:`Maximum length should be 255 characters. You have entered ${watch()?.investmentTypeNameArabic?.length || 0} characters.`
}, },
{ {
label: "Description (English)", label: "Description (English)",
@@ -229,6 +243,8 @@ const AddInvestmentType = () => {
type: "textarea", type: "textarea",
// isRequired: true, // isRequired: true,
section: "Add Details", section: "Add Details",
maxLength: 255,
helperText:`Maximum length should be 255 characters. You have entered ${watch()?.note?.length || 0} characters.`
}, },
{ {
label: "Description (Arabic)", label: "Description (Arabic)",
@@ -238,6 +254,8 @@ const AddInvestmentType = () => {
// isRequired: true, // isRequired: true,
arabic: true, arabic: true,
section: "Add Details", section: "Add Details",
maxLength: 255,
helperText:`Maximum length should be 255 characters. You have entered ${watch()?.noteArabic?.length || 0} characters.`
}, },
]; ];
@@ -263,7 +281,7 @@ const AddInvestmentType = () => {
return groups; return groups;
}, {}); }, {});
// ==================== [On Submit] ======================== // ==================== [On Submit] ========================
const onSubmit = async (data) => { const onSubmit = async (data) => {
@@ -275,37 +293,38 @@ const AddInvestmentType = () => {
}; };
return ( return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={14}> isLoading ? <FullscreenLoaders /> :
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={14}>
{/* ===================== [Switch Button] ======================== */} {/* ===================== [Switch Button] ======================== */}
<Box mt={5} display={"flex"} justifyContent={"right"} mr={5}> <Box mt={5} display={"flex"} justifyContent={"right"} mr={5}>
<SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} /> <SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} />
</Box> </Box>
{/* ====================== [Form Input] ====================== */} {/* ====================== [Form Input] ====================== */}
<FormInputMain <FormInputMain
groupedFields={params?.id ? groupedEditFields : groupedFields} groupedFields={params?.id ? groupedEditFields : groupedFields}
control={control} control={control}
errors={errors} errors={errors}
onSubmit={handleSubmit(onSubmit)} onSubmit={handleSubmit(onSubmit)}
submitTitle={params?.id ? "Update" : "Submit"} submitTitle={params?.id ? "Update" : "Submit"}
// btnLoading={isLoadingBtn} // btnLoading={isLoadingBtn}
> >
</FormInputMain> </FormInputMain>
{/* ======================= [Modal] =========================== */} {/* ======================= [Modal] =========================== */}
<CustomAlertDialog <CustomAlertDialog
isOpen={alert} isOpen={alert}
onClose={() => setAlert(false)} onClose={() => setAlert(false)}
alertHandler={handleConfirm} alertHandler={handleConfirm}
message={"Are you sure you want to add this?"} message={"Are you sure you want to add this?"}
isLoading={isLoadingBtn} isLoading={isLoadingBtn}
/> />
</Box> </Box>
); );
}; };

View File

@@ -12,13 +12,18 @@ import ToastBox from "../../../Components/ToastBox";
import FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders"; import FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders";
import CustomAlertDialog from "../../../Components/CustomAlertDialog"; import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import SwitchButton from "../../../Components/SwitchButton"; import SwitchButton from "../../../Components/SwitchButton";
import DummyComponent from "../../../Components/DummyComponent";
// ======================= [validation] ========================= // ======================= [validation] =========================
export const addSponser = yup.object().shape({ export const addSponser = yup.object().shape({
sponsorName: yup.string().required("Sponser name is required"), sponsorName: yup.
sponsorNameArabic: yup.string().required("Sponser name is required"), string()
email: yup.string().email("Must be a valid email").notRequired(), .required('Sponsor Name is required')
.min(3, 'Sponsor Name must be at least 3 characters long')
.max(50, 'Investment Type Name cannot exceed 50 characters'),
sponsorNameArabic: yup.string().required("Sponser name in arabic is required"),
email: yup.string().email("Invalid email address").notRequired(),
// .test("emailValidity", "Email address is invalid", async function (value) { // .test("emailValidity", "Email address is invalid", async function (value) {
// if (!value) { // if (!value) {
// return true; // Allow if the field is empty // return true; // Allow if the field is empty
@@ -61,6 +66,7 @@ const AddSponser = () => {
const { const {
control, control,
watch,
handleSubmit, handleSubmit,
formState: { errors }, formState: { errors },
reset, reset,
@@ -78,9 +84,15 @@ const AddSponser = () => {
sponsorNameArabic: sponserByIdData?.data?.sponsorNameArabic, sponsorNameArabic: sponserByIdData?.data?.sponsorNameArabic,
email: sponserByIdData?.data?.email, email: sponserByIdData?.data?.email,
}); });
setIsSwitchOn(sponserByIdData?.data?.isActive)
console.log(sponserByIdData?.data?.isActive);
} }
}, [sponserByIdData, reset]); }, [sponserByIdData, reset]);
// console.log(isSwitchOn);
if (false) { if (false) {
return <FullscreenLoaders />; return <FullscreenLoaders />;
} }
@@ -109,15 +121,15 @@ const AddSponser = () => {
setIsLoadingBtn(false); setIsLoadingBtn(false);
setAlert(false); setAlert(false);
navigate("/sponser"); navigate("/sponser");
} else { } else if(response?.error?.status === 400) {
toast({ toast({
render: () => ( render: () => (
<ToastBox message={"Something Went Wrong"} status={"error"} /> <ToastBox message={response?.error?.data?.message} status={"error"} />
), ),
}); });
setIsLoadingBtn(false); setIsLoadingBtn(false);
navigate("/sponser"); setAlert(false)
} }
}); });
} catch (error) { } catch (error) {
@@ -148,7 +160,7 @@ const AddSponser = () => {
}); });
setIsLoadingBtn(false); setIsLoadingBtn(false);
navigate("/sponser"); setAlert(false)
} }
}); });
} catch (error) { } catch (error) {
@@ -164,24 +176,26 @@ const AddSponser = () => {
const formFields = [ const formFields = [
{ {
label: "Sponser name (English)", label: "Sponsor name (English)",
placeHolder: " ", placeHolder: " ",
name: "sponsorName", name: "sponsorName",
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "",
maxLength:50 maxLength:50,
helperText:`Maximum length should be 50 characters. You have entered ${watch()?.sponsorName?.length || 0} characters.`
}, },
{ {
label: "Sponser name (Arabic)", label: "Sponsor name (Arabic)",
name: "sponsorNameArabic", name: "sponsorNameArabic",
placeHolder: " ", placeHolder: " ",
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "",
arabic: true, arabic: true,
right: true, right: true,
maxLength:255 maxLength:55,
helperText:`Maximum length should be 55 characters. You have entered ${watch()?.sponsorNameArabic?.length || 0} characters.`
}, },
{ {
label: "Email address", label: "Email address",
@@ -189,7 +203,7 @@ const AddSponser = () => {
placeHolder: " ", placeHolder: " ",
type: "email", type: "email",
// isRequired: true, // isRequired: true,
section: "Add Details", section: "",
}, },
]; ];
@@ -197,23 +211,25 @@ const AddSponser = () => {
const formEditFields = [ const formEditFields = [
{ {
label: "Sponser name", label: "Sponsor name",
placeHolder: " ", placeHolder: " ",
name: "sponsorName", name: "sponsorName",
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "",
maxLength:50 maxLength:55,
helperText:`Maximum length should be 55 characters. You have entered ${watch()?.sponsorName?.length || 0} characters.`
}, },
{ {
label: "Sponser name (Arabic)", label: "Sponsor name (Arabic)",
name: "sponsorNameArabic", name: "sponsorNameArabic",
placeHolder: " ", placeHolder: " ",
type: "text", type: "text",
isRequired: true, isRequired: true,
section: "Add Details", section: "",
arabic: true, arabic: true,
maxLength:255 maxLength:55,
helperText:`Maximum length should be 55 characters. You have entered ${watch()?.sponsorNameArabic?.length || 0} characters.`
}, },
{ {
label: "Email adress", label: "Email adress",
@@ -221,7 +237,7 @@ const AddSponser = () => {
placeHolder: " ", placeHolder: " ",
type: "email", type: "email",
// isRequired: true, // isRequired: true,
section: "Add Details", section: "",
}, },
]; ];
@@ -257,14 +273,16 @@ const AddSponser = () => {
}; };
return ( return (
isLoading?<FullscreenLoaders/>:
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={14}> <Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={14}>
{/* ===================== [Switch Button] ======================== */} {/* ===================== [Switch Button] ======================== */}
<Box mt={5} display={"flex"} justifyContent={"right"} mr={5}> <Box mt={5} display={"flex"} justifyContent={"right"} mr={5}>
<SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} /> <SwitchButton isSwitchOn={isSwitchOn} setIsSwitchOn={setIsSwitchOn} />
</Box> </Box>
{/* ====================== [Form Input] ====================== */} {/* ====================== [Form Input] ====================== */}
<FormInputMain <FormInputMain
@@ -284,6 +302,8 @@ const AddSponser = () => {
message={"Are you sure you want to add this?"} message={"Are you sure you want to add this?"}
isLoading={isLoadingBtn} isLoading={isLoadingBtn}
/> />
{/* <DummyComponent /> */}
</Box> </Box>
); );
}; };

View File

@@ -19,7 +19,7 @@ export const formatDate = (date) => {
const month = String(d.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed const month = String(d.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
const day = String(d.getDate()).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0');
return `${day}-${month}-${year}`; return `${day}/${month}/${year}`;
}; };
const Sponser = () => { const Sponser = () => {
@@ -158,14 +158,28 @@ const Sponser = () => {
setIsLoading(true); setIsLoading(true);
try { try {
const response = await deleteSponser(actionId); const response = await deleteSponser(actionId);
console.log(response); console.log(response?.data);
setIsLoading(false); if(response?.error?.data?.code === 400){
setDeleteAlert(false); toast({
render: () => <ToastBox message={response?.error?.data?.message} status={'error'} />,
});
setIsLoading(false);
setDeleteAlert(false);
} else if(response?.data?.statusCode === 201 || response?.data?.statusCode === 200){
toast({
render: () => <ToastBox message={response?.data?.message} status={'error'} />,
});
setIsLoading(false);
setDeleteAlert(false);
}
} catch (error) {} } catch (error) {}
}; };
console.log(isSponserLoading); 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}>
<Box bg="white.500"> <Box bg="white.500">

View File

@@ -13,7 +13,17 @@ const SplashScreen = () => {
gap={10} gap={10}
> >
<Image src={logo} /> <Image src={logo} />
<Spinner color='green.900' size='md' /> {/* <Spinner color='green.900' size='md' /> */}
<div className="dot-spinner">
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
<div className="dot-spinner__dot"></div>
</div>
</Box> </Box>
) )
} }

View File

@@ -3,18 +3,18 @@ import React from 'react'
// import noInternet from "../assets/Error.svg" // import noInternet from "../assets/Error.svg"
import robot from "../assets/robot.png" import robot from "../assets/robot.png"
const UnderConstruction = ({title}) => { const UnderConstruction = ({title, h}) => {
return ( return (
<Box <Box
h={'100vh'} h={h?h:'100vh'}
display={'flex'} display={'flex'}
justifyContent={'center'} justifyContent={'center'}
alignItems={'center'} alignItems={'center'}
flexDirection={'column'} flexDirection={'column'}
gap={8} gap={8}
> >
<Image src={robot} w={"171px"} /> <Image src={robot} w={200} />
{/* <Text color={'green.800'} as={'span'} fontSize={'small'}>The requested URL was not found on this server.</Text> */} <Text color={'green.800'} as={'span'} mt={4} fontSize={'small'}>🚧 Building Something Amazing Just for You! 🚧</Text>
</Box> </Box>
) )
} }

63
src/Pages/Welcome.jsx Normal file
View File

@@ -0,0 +1,63 @@
import React from 'react';
import welcome from '../assets/welcome.avif';
import welcome2 from '../assets/welcome2.avif';
import welcome3 from '../assets/welcome3.avif';
import welcome4 from '../assets/welcome4.avif';
import { Box, Button, Image } from '@chakra-ui/react';
import logo from "../../src/assets/logo.png"
const Welcome = () => {
return (
<Box position="relative" h="100vh">
<div id="carouselExampleSlidesOnly" className="carousel slide" data-bs-ride="carousel">
<div className="carousel-inner">
<div className="carousel-item active" data-bs-interval="3000">
<img src={welcome4} className="d-block w-100" alt="Welcome 2" />
</div>
<div className="carousel-item" data-bs-interval="3000">
<img src={welcome3} className="d-block w-100" alt="Welcome 3" />
</div>
<div className="carousel-item" data-bs-interval="3000">
<img src={welcome2} className="d-block w-100" alt="Welcome 4" />
</div>
</div>
{/* <a className="carousel-control-prev" href="#carouselExampleSlidesOnly" role="button" data-bs-slide="prev">
<span className="carousel-control-prev-icon" aria-hidden="true"></span>
<span className="visually-hidden">Previous</span>
</a>
<a className="carousel-control-next" href="#carouselExampleSlidesOnly" role="button" data-bs-slide="next">
<span className="carousel-control-next-icon" aria-hidden="true"></span>
<span className="visually-hidden">Next</span>
</a> */}
</div>
<Box
opacity={1}
bgGradient="linear(to-b, rgba(0, 0, 0, 0.5), #0047178e 100%)"
zIndex={999}
position="absolute"
top={0}
left={0}
w="100%"
h="100%"
display={'flex'}
justifyContent={'center'}
alignItems={'center'}
>
<Image src={logo} />
{/* <Box
position="absolute"
bottom={12}
right={0}
p={4} // Adjust padding as needed
>
<Button color={'#004717'} size={'lg'} bg="white" variant="solid">
Let's get started
</Button>
</Box> */}
</Box>
</Box>
);
}
export default Welcome;

View File

@@ -1,5 +1,5 @@
import { HiOutlineNewspaper } from "react-icons/hi"; import { HiOutlineNewspaper } from "react-icons/hi";
import { TbBrandMedium, TbChartHistogram, TbReportMoney } from "react-icons/tb"; import { TbBrandMedium, TbChartHistogram, TbLayoutDashboard, TbReportMoney } from "react-icons/tb";
import { import {
RiBankLine, RiBankLine,
RiFileUserLine, RiFileUserLine,
@@ -26,6 +26,12 @@ import { LiaCrownSolid } from "react-icons/lia";
import { PiCrownDuotone } from "react-icons/pi"; import { PiCrownDuotone } from "react-icons/pi";
export const nav = [ export const nav = [
// {
// title: "Dashboard",
// type: "single",
// path: "/",
// Icon: TbLayoutDashboard,
// },
{ {
title: "MASTER MENU", title: "MASTER MENU",
type: "title", type: "title",

View File

@@ -31,6 +31,9 @@ import InvestmentType from "../Pages/Master/InvestmentType/InvestmentType";
import DepositRequest from "../Pages/Deposit/DepositRequest/DepositRequest"; import DepositRequest from "../Pages/Deposit/DepositRequest/DepositRequest";
import EditBankDetails from "../Pages/Admin/BankDetails/EditBankDetails"; import EditBankDetails from "../Pages/Admin/BankDetails/EditBankDetails";
import ExchangeHistory from "../Pages/Master/ExchangeRate/ExchangeHistroy"; import ExchangeHistory from "../Pages/Master/ExchangeRate/ExchangeHistroy";
import Welcome from "../Pages/Welcome";
import Dashbaord from "../Pages/Dashbaord";
import UnderConstruction from "../Pages/UnderConstruction";
export const RouteLink = [ export const RouteLink = [
// =============[ Tanami ]================ // =============[ Tanami ]================
@@ -46,10 +49,6 @@ export const RouteLink = [
{ path: "/exchange-rate", Component: ExchangeRate }, { path: "/exchange-rate", Component: ExchangeRate },
{ path: "/exchange-rate/currency-history/:id", Component: ExchangeHistory }, { path: "/exchange-rate/currency-history/:id", Component: ExchangeHistory },
{ path: "/investment-type", Component: InvestmentType }, { path: "/investment-type", Component: InvestmentType },
{ path: "/investment-type/add-investment/:id", Component: AddInvestmentType }, { path: "/investment-type/add-investment/:id", Component: AddInvestmentType },
{ path: "/investment-type/add-investment", Component: AddInvestmentType }, { path: "/investment-type/add-investment", Component: AddInvestmentType },
@@ -66,30 +65,43 @@ export const RouteLink = [
{ path: "/investor-details", Component: InvestorDetails }, { path: "/investor-details", Component: InvestorDetails },
{ path: "/investor-details/profile-view/:id", Component: ProfileView }, { path: "/investor-details/profile-view/:id", Component: ProfileView },
{ path: "/investor-details/view-investor-details", Component: ViewInvestorDetails }, { path: "/investor-details/view-investor-details", Component: ViewInvestorDetails },
{ path: "/investor-transactions", Component: InvestorTransactions }, // { path: "/investor-transactions", Component: InvestorTransactions },
{ path: "/investor-transactions", Component: UnderConstruction },
// ===============[ Deposit ]=============== // ===============[ Deposit ]===============
{ path: "/deposit-request", Component: DepositRequest }, { path: "/deposit-request", Component: DepositRequest },
{ path: "/deposit-history", Component: DepositHistory }, { path: "/deposit-history", Component: DepositHistory },
// ===============[ Withdrawal]=============== // ===============[ Withdrawal]===============
{ path: "/withdraw-request", Component: PendingRequest }, // { path: "/withdraw-request", Component: PendingRequest },
{ path: "/withdraw-history", Component: ViewHistory }, { path: "/withdraw-request", Component: UnderConstruction },
// { path: "/withdraw-history", Component: ViewHistory },
{ path: "/withdraw-history", Component: UnderConstruction },
// ===============[ Withdrawal]=============== // ===============[ Withdrawal]===============
{ path: "/investor-history", Component: UpgradeHistory }, // { path: "/investor-history", Component: UpgradeHistory },
{ path: "/investor-request", Component: InvestorPendingRequest }, { path: "/investor-history", Component: UnderConstruction },
// { path: "/investor-request", Component: InvestorPendingRequest },
{ path: "/investor-request", Component: UnderConstruction },
// ===============[ Deletion]=============== // ===============[ Deletion]===============
{ path: "/deletion-request", Component: DeletionRequest }, // { path: "/deletion-request", Component: DeletionRequest },
{ path: "/deletion-history", Component: DeletionHistory }, { path: "/deletion-request", Component: UnderConstruction },
// { path: "/deletion-history", Component: DeletionHistory },
{ path: "/deletion-history", Component: UnderConstruction },
// ===============[ Admin]=============== // ===============[ Admin]===============
{ path: "/bank-investor", Component: BankInvestor }, // { path: "/bank-investor", Component: BankInvestor },
{ path: "/academy", Component: Academy }, { path: "/bank-investor", Component: UnderConstruction },
{ path: "/notification", Component: Notification }, // { path: "/academy", Component: Academy },
{ path: "/contact", Component: Contact }, { path: "/academy", Component: UnderConstruction },
{ path: "/users", Component: Users }, // { path: "/notification", Component: Notification },
{ path: "/bank-details", Component: BankDetails }, { path: "/notification", Component: UnderConstruction },
// { path: "/contact", Component: Contact },
{ path: "/contact", Component: UnderConstruction },
// { path: "/users", Component: Users },
{ path: "/users", Component: UnderConstruction },
// { path: "/bank-details", Component: BankDetails },
{ path: "/bank-details", Component: UnderConstruction },
{ path: "/bank-details/edit-bank-details/:id", Component: EditBankDetails }, { path: "/bank-details/edit-bank-details/:id", Component: EditBankDetails },
]; ];

View File

@@ -1,12 +1,13 @@
// io.service.js // io.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
const baseUrl = api?.defaults.baseURL; // const baseUrl = api?.defaults.baseURL;
export const keyMerits = createApi({ export const keyMerits = createApi({
reducerPath: "ioService", reducerPath: "ioService",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: ["getKeyMerits"], tagTypes: ["getKeyMerits"],
endpoints: (builder) => ({ endpoints: (builder) => ({
// =====[get] // =====[get]

View File

@@ -3,7 +3,7 @@ import axios from "axios";
// Create an Axios instance for API calls // Create an Axios instance for API calls
export const api = axios.create({ export const api = axios.create({
// baseURL: `https://tanami.betadelivery.com/api/v1`, // baseURL: `https://tanami.betadelivery.com/api/v1`,
baseURL: `https://tanami.betadelivery.com/api/v1`, // Replace with your API base URL baseURL: import.meta.env.VITE_BAS_URL, // Replace with your API base URL
timeout: 10000, // Adjust timeout as needed timeout: 10000, // Adjust timeout as needed
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@@ -49,8 +49,8 @@ api.interceptors.response.use(
if (response.status === 200) { if (response.status === 200) {
// Update tokens in local storage // Update tokens in local storage
localStorage.setItem("accessToken", response.data.accessToken); localStorage.setItem("accessTokenn", response.data.accessToken);
localStorage.setItem("refreshToken", response.data.refreshToken); localStorage.setItem("refreshTokenn", response.data.refreshToken);
// Retry the original request with the new tokens // Retry the original request with the new tokens
return api(originalRequest); return api(originalRequest);

View File

@@ -1,14 +1,16 @@
// investorDetails.service.js // investorDetails.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
const baseUrl = api?.defaults.baseURL; // const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints // Define a service using a base URL and expected endpoints
export const bankDetails = createApi({ export const bankDetails = createApi({
reducerPath: "bankDetails", reducerPath: "bankDetails",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: [], tagTypes: ["getBank"],
endpoints: (builder) => ({ endpoints: (builder) => ({
getBank: builder.query({ getBank: builder.query({
@@ -25,7 +27,7 @@ export const bankDetails = createApi({
method: "PATCH", method: "PATCH",
body: data, body: data,
}), }),
invalidatesTags: ["getBankDetails"], invalidatesTags: ["getBank"],
}), }),
}), }),

View File

@@ -1,24 +1,37 @@
// investorDetails.service.js // investorDetails.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
const baseUrl = api?.defaults.baseURL; // const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints // Define a service using a base URL and expected endpoints
export const contact = createApi({ export const contact = createApi({
reducerPath: "contact", reducerPath: "contact",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: [], tagTypes: ["getContact"],
endpoints: (builder) => ({ endpoints: (builder) => ({
getContact: builder.query({ getContact: builder.query({
query: ({ page, size }) => query: () =>
`/contactDetails/admin/?page=${page}&size=${size}`, `/contactDetails/admin`,
providesTags: ["getContact"], providesTags: ["getContact"],
}), }),
// ========[Update Investment]=======
updateContact: builder.mutation({
query: (data) => ({
url: `/contactDetails/admin/`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getContact"],
}),
}), }),
}); });
// Export hooks for usage in functional components // Export hooks for usage in functional components
export const { useGetContactQuery } = contact; export const { useGetContactQuery, useUpdateContactMutation } = contact;

View File

@@ -0,0 +1,55 @@
// investorDetails.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
// const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints
export const depositRequest = createApi({
reducerPath: "depositRequest",
baseQuery: baseQuery,
tagTypes: ["getDepositRequest", "getDepositHistory"],
endpoints: (builder) => ({
getDepositRequest: builder.query({
query: () => `/deposit/admin/pending-requests`,
providesTags: ["getDepositRequest"],
}),
getDepositRequestById: builder.query({
query: (id) => `/deposit/admin/getById/${id}`,
}),
updateDepositRequest: builder.mutation({
query: ({ id, data }) => ({
url: `/deposit/admin/approved/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getDepositRequest", "getDepositHistory"],
}),
depositReject: builder.mutation({
query: ({ id, data }) => ({
url: `/deposit/admin/rejected/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getDepositRequest", "getDepositHistory"],
}),
getDepositHistory: builder.query({
query: () => `/deposit/admin/history`,
providesTags: ["getDepositHistory"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetDepositRequestQuery,
useGetDepositRequestByIdQuery,
useUpdateDepositRequestMutation,
useDepositRejectMutation,
useGetDepositHistoryQuery,
} = depositRequest;

View File

@@ -0,0 +1,101 @@
//sponser.service
// Need to use the React-specific entry point to import createApi
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service";
const baseUrl = api?.defaults.baseURL;
// const baseUrl = `${import.meta.env.VITE_API_BASE_URL}/${import.meta.env.VITE_API_VERSION}`
// Define a service using a base URL and expected endpoints
export const deposite = createApi({
reducerPath: "deposite",
baseQuery: fetchBaseQuery({ baseUrl: baseUrl }),
tagTypes: ["gtDeposite"],
endpoints: (builder) => ({
// ======[Get All]=====
getSponserMaster: builder.query({
query: ({ page, size }) => `/sponsor/admin?page=${page}&size=${size}`,
providesTags: ["getSponser"],
}),
// ========[Get Active]========
getActiveSponserMaster: builder.query({
query: () => `/sponsor/admin/active`,
providesTags: ["getSponser"],
}),
getSponserMasterActive: builder.query({
query: () => "/sponsor/admin/active",
}),
// ======[Get ID]=====
getSponserById: builder.query({
query: (id) => `/sponsor/admin/${id}`,
providesTags: ["getSponser"],
}),
// ========[Toggle Status]========
toggleStatus: builder.mutation({
query: ({ id }) => ({
url: `/sponsor/admin/toggle-status/${id}`,
method: "PATCH",
}),
invalidatesTags: ["getSponser"],
}),
// ========[Create Sponser]========
createSponser: builder.mutation({
query: (data) => ({
url: `/sponsor/admin`,
method: "POST",
body: data,
}),
invalidatesTags: ["getSponser"],
}),
// ========[Update Sponser]========
updateSponser: builder.mutation({
query: ({ data, id }) => ({
url: `/sponsor/admin/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getSponser"],
}),
// ========[Delete Sponser]========
deleteSponser: builder.mutation({
query: (id) => ({
url: `/sponsor/admin/delete/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getSponser"],
}),
}),
});
// Export hooks for usage in functional components
export const {
useGetSponserMasterQuery,
useGetSponserMasterActiveQuery,
useToggleStatusMutation,
useCreateSponserMutation,
useUpdateSponserMutation,
useGetSponserByIdQuery,
useDeleteSponserMutation,
useGetActiveSponserMasterQuery
} = sponserMaster;

View File

@@ -1,13 +1,14 @@
// exchangeRate.service.js // exchangeRate.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
const baseUrl = api?.defaults.baseURL; // const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints // Define a service using a base URL and expected endpoints
export const exchangeRate = createApi({ export const exchangeRate = createApi({
reducerPath: "exchangeRate", reducerPath: "exchangeRate",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: ["getAllExchangeRate", "getExchangeById"], tagTypes: ["getAllExchangeRate", "getExchangeById"],
endpoints: (builder) => ({ endpoints: (builder) => ({
@@ -21,7 +22,7 @@ export const exchangeRate = createApi({
query: (id) => `/currencyExchange/admin/${id}`, query: (id) => `/currencyExchange/admin/${id}`,
providesTags: ["getAllExchangeRate"], providesTags: ["getAllExchangeRate"],
}), }),
updateExchangeRate: builder.mutation({ updateExchangeRate: builder.mutation({
query: ({ data, id }) => ({ query: ({ data, id }) => ({
url: `/currencyExchange/admin/${id}`, url: `/currencyExchange/admin/${id}`,

View File

@@ -1,12 +1,13 @@
// io.service.js // io.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
const baseUrl = api?.defaults.baseURL; // const baseUrl = api?.defaults.baseURL;
export const ioService = createApi({ export const ioService = createApi({
reducerPath: "ioService", reducerPath: "ioService",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: ["getInvestmentDocuments"], tagTypes: ["getInvestmentDocuments"],
@@ -23,7 +24,7 @@ export const ioService = createApi({
// =====[create] // =====[create]
createInvestmentDocuments: builder.mutation({ createInvestmentDocuments: builder.mutation({
query: ({data, id}) => ({ query: ({data, id}) => ({
url: `/io/admin/document/${id}`, url: `/io/admin/document/${id}`,

View File

@@ -1,13 +1,14 @@
// investmentType.service.js // investmentType.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
const baseUrl = api?.defaults.baseURL; // const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints // Define a service using a base URL and expected endpoints
export const investmentType = createApi({ export const investmentType = createApi({
reducerPath: "investmentType", reducerPath: "investmentType",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: ["getInvestmentType", "getInvestmentTypeID"], tagTypes: ["getInvestmentType", "getInvestmentTypeID"],
endpoints: (builder) => ({ endpoints: (builder) => ({

View File

@@ -1,13 +1,14 @@
// investorDetails.service.js // investorDetails.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
const baseUrl = api?.defaults.baseURL; // const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints // Define a service using a base URL and expected endpoints
export const investorDetails = createApi({ export const investorDetails = createApi({
reducerPath: "investorDetails", reducerPath: "investorDetails",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: [], tagTypes: [],
endpoints: (builder) => ({ endpoints: (builder) => ({

View File

@@ -1,12 +1,13 @@
// investorTransaction.service.js // investorTransaction.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./token.serivce";
const baseUrl = import.meta.env.VITE_API_BASE_URL + "/api"; // const baseUrl = import.meta.env.VITE_API_BASE_URL + "/api";
// Define a service using a base URL and expected endpoints // Define a service using a base URL and expected endpoints
export const investorTransaction = createApi({ export const investorTransaction = createApi({
reducerPath: "investorTransaction", reducerPath: "investorTransaction",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: [], tagTypes: [],
endpoints: (builder) => ({ endpoints: (builder) => ({
getTransactions: builder.query({ getTransactions: builder.query({

View File

@@ -1,12 +1,13 @@
// io.service.js // io.service.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
const baseUrl = api?.defaults.baseURL; // const baseUrl = api?.defaults.baseURL;
// Define a service using a base URL and expected endpoints // Define a service using a base URL and expected endpoints
export const ioService = createApi({ export const ioService = createApi({
reducerPath: "ioService", reducerPath: "ioService",
baseQuery: fetchBaseQuery({ baseUrl }), baseQuery: baseQuery,
tagTypes: [ tagTypes: [
"prePopulate", "prePopulate",
"getIO", "getIO",
@@ -49,7 +50,7 @@ export const ioService = createApi({
method: "PATCH", method: "PATCH",
body: data, body: data,
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById", "getIO","prePopulate"],
}), }),
// =====[Key Merits] // =====[Key Merits]
@@ -57,6 +58,7 @@ export const ioService = createApi({
query: (id) => `/io/admin/key-merits/${id}`, query: (id) => `/io/admin/key-merits/${id}`,
providesTags: ["getKeyMerits"], providesTags: ["getKeyMerits"],
}), }),
createKeyMerits: builder.mutation({ createKeyMerits: builder.mutation({
query: ({ data, id }) => ({ query: ({ data, id }) => ({
url: `/io/admin/key-merits/${id}`, url: `/io/admin/key-merits/${id}`,
@@ -64,7 +66,7 @@ export const ioService = createApi({
body: data, body: data,
// No need to manually set 'Content-Type' // No need to manually set 'Content-Type'
}), }),
invalidatesTags: ["getKeyMerits"], invalidatesTags: ["getIOById"],
}), }),
deleteKeyMerits: builder.mutation({ deleteKeyMerits: builder.mutation({
@@ -72,15 +74,16 @@ export const ioService = createApi({
url: `/io/admin/key-merits/hard-delete/${id}`, url: `/io/admin/key-merits/hard-delete/${id}`,
method: "DELETE", method: "DELETE",
}), }),
invalidatesTags: ["getKeyMerits"], invalidatesTags: ["getIOById"],
}), }),
updateKeyMerits: builder.mutation({ updateKeyMerits: builder.mutation({
query: ({ data, id }) => ({ query: ({ data, id }) => ({
url: `/io/admin/key-merits/byId/${id}`, url: `/io/admin/key-merits/byId/${id}`,
method: "PATCH", method: "PATCH",
body: data, body: data,
}), }),
invalidatesTags: ["getKeyMerits"], invalidatesTags: ["getIOById"],
}), }),
// =====[getIODocument] // =====[getIODocument]
@@ -91,7 +94,7 @@ export const ioService = createApi({
body: data, body: data,
}), }),
invalidatesTags: ["getInvestmentDocuments"], invalidatesTags: ["getIOById"],
}), }),
updateInvestmentDocuments: builder.mutation({ updateInvestmentDocuments: builder.mutation({
@@ -100,7 +103,7 @@ export const ioService = createApi({
method: "PATCH", method: "PATCH",
body: data, body: data,
}), }),
invalidatesTags: ["getInvestmentDocuments"], invalidatesTags: ["getIOById"],
}), }),
getInvestmentDocuments: builder.query({ getInvestmentDocuments: builder.query({
@@ -113,7 +116,7 @@ export const ioService = createApi({
url: `/io/admin/document/hard-delete/${id}`, url: `/io/admin/document/hard-delete/${id}`,
method: "DELETE", method: "DELETE",
}), }),
invalidatesTags: ["getInvestmentDocuments"], invalidatesTags: ["getIOById"],
}), }),
// =====[Artifacts] // =====[Artifacts]
@@ -125,36 +128,36 @@ export const ioService = createApi({
// =====[createImageArtifacts] // =====[createImageArtifacts]
createImageArtifacts: builder.mutation({ createImageArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/artifact/artifactImage/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
updateImageArtifacts: builder.mutation({
query: ({ data, id }) => ({ query: ({ data, id }) => ({
url: `/io/artifact/image/${id}`, url: `/io/admin/artifact/image/${id}`,
method: "PATCH", method: "POST",
body: data, body: data,
}), }),
invalidatesTags: ["getIOById"],
}), invalidatesTags: ["getIOById"],
}),
// =====[createVideoArtifacts]
createVideoArtifacts: builder.mutation({ updateImageArtifacts: builder.mutation({
query: ({ data, id }) => ({ query: ({ data, id }) => ({
url: `/io/artifact/artifactVideo/${id}`, url: `/io/admin/artifact/image/byId/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
// =====[createVideoArtifacts]
createVideoArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/artifact/video/${id}`,
method: "POST", method: "POST",
body: data, body: data,
}), }),
@@ -162,10 +165,9 @@ export const ioService = createApi({
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
deleteVideoArtifacts: builder.mutation({ deleteVideoArtifacts: builder.mutation({
query: (id) => ({ query: (id) => ({
url: `/io/artifact/video/${id}`, url: `/io/admin/artifact/video/byId/${id}`,
method: "DELETE", method: "DELETE",
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
@@ -173,17 +175,15 @@ export const ioService = createApi({
deleteImageArtifacts: builder.mutation({ deleteImageArtifacts: builder.mutation({
query: (id) => ({ query: (id) => ({
url: `/io/artifact/image/${id}`, url: `/io/admin/artifact/image/byId/${id}`,
method: "DELETE", method: "DELETE",
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
updateVideoArtifacts: builder.mutation({ updateVideoArtifacts: builder.mutation({
query: ({ data, id }) => ({ query: ({ data, id }) => ({
url: `/io/artifact/video/${id}`, url: `/io/admin/artifact/video/byId/${id}`,
method: "PATCH", method: "PATCH",
body: data, body: data,
}), }),
@@ -198,7 +198,7 @@ export const ioService = createApi({
}), }),
invalidatesTags: ["getIOById"], invalidatesTags: ["getIOById"],
}), }),
updateStatusIo: builder.mutation({ updateStatusIo: builder.mutation({
query: ({ data, id }) => ({ query: ({ data, id }) => ({
url: `/io/admin/update-status/${id}`, url: `/io/admin/update-status/${id}`,
@@ -208,7 +208,53 @@ export const ioService = createApi({
invalidatesTags: ["getIOById", 'getIO'], invalidatesTags: ["getIOById", 'getIO'],
}), }),
createIoCash: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/io-cash/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
createIoNav: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/io-nav/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
// =====[ Amount Investment ] ======
amountIvestment : builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/amount-invested/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
// ======== [ Distribution Transaction ] ========
getDistributionInvestor : builder.mutation({
query: ({id,data}) => ({
url: `/io/admin/io-distribution/pre-populate/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
@@ -250,6 +296,16 @@ export const {
useSetDisplayOrderMutation, useSetDisplayOrderMutation,
useCreateIoCashMutation,
useCreateIoNavMutation,
useUpdateStatusIoMutation
useUpdateStatusIoMutation,
useAmountIvestmentMutation,
useGetDistributionInvestorMutation,
} = ioService; } = ioService;

View File

@@ -1,17 +1,23 @@
//sponser.service //sponser.service
// Need to use the React-specific entry point to import createApi // Need to use the React-specific entry point to import createApi
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { api } from "./api.service"; // import { api } from "./api.service";
import { baseQuery } from "./token.serivce";
import { ioService } from "./io.service";
// const baseUrl = api?.defaults.baseURL;
const baseUrl = api?.defaults.baseURL;
// const baseUrl = `${import.meta.env.VITE_API_BASE_URL}/${import.meta.env.VITE_API_VERSION}` // const baseUrl = `${import.meta.env.VITE_API_BASE_URL}/${import.meta.env.VITE_API_VERSION}`
// Define a service using a base URL and expected endpoints // Define a service using a base URL and expected endpoints
export const sponserMaster = createApi({ export const sponserMaster = createApi({
reducerPath: "sponserMaster", reducerPath: "sponserMaster",
baseQuery: fetchBaseQuery({ baseUrl: baseUrl }), baseQuery: baseQuery,
tagTypes: ["getSponser"], tagTypes: ["getSponser", "prePopulate"],
endpoints: (builder) => ({ endpoints: (builder) => ({
@@ -28,7 +34,6 @@ export const sponserMaster = createApi({
getActiveSponserMaster: builder.query({ getActiveSponserMaster: builder.query({
query: () => `/sponsor/admin/active`, query: () => `/sponsor/admin/active`,
providesTags: ["getSponser"],
}), }),
getSponserMasterActive: builder.query({ getSponserMasterActive: builder.query({
@@ -40,7 +45,6 @@ export const sponserMaster = createApi({
getSponserById: builder.query({ getSponserById: builder.query({
query: (id) => `/sponsor/admin/${id}`, query: (id) => `/sponsor/admin/${id}`,
providesTags: ["getSponser"],
}), }),
// ========[Toggle Status]======== // ========[Toggle Status]========
@@ -61,7 +65,7 @@ export const sponserMaster = createApi({
method: "POST", method: "POST",
body: data, body: data,
}), }),
invalidatesTags: ["getSponser"], invalidatesTags: ["getSponser","prePopulate"],
}), }),
// ========[Update Sponser]======== // ========[Update Sponser]========

View File

@@ -0,0 +1,113 @@
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// Define a base query function with RTK Query
// 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) => {
let result = await fetchBaseQuery({
baseUrl: import.meta.env.VITE_BAS_URL,
prepareHeaders: (headers) => {
const token = localStorage.getItem("accessToken");
if (token) {
headers.set("x-auth-token", token);
}
return headers;
},
})(args, api, extraOptions);
if (result.error && result.error.status === 401) {
// Handle token refresh
const refreshToken = localStorage.getItem("refreshToken");
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) {
// Save new tokens
localStorage.setItem("accessToken", refreshResult.data.access.token);
localStorage.setItem(
"refreshToken",
refreshResult.data.refresh.token
);
localStorage.setItem(
"refreshTokenExp",
refreshResult.data.refresh.expires
);
// Retry the original request with the new token
result = await fetchBaseQuery({
baseUrl: import.meta.env.VITE_BAS_URL,
prepareHeaders: (headers) => {
const token = localStorage.getItem("accessToken");
if (token) {
headers.set("x-auth-token", token);
}
return headers;
},
})(args, api, extraOptions);
}
} catch (err) {
console.error("Failed to refresh token:", err);
// Handle refresh failure (e.g., redirect to login)
}
}
}
return result;
};
// Create an RTK Query API slice
export const apiSlice = createApi({
reducerPath: "api",
baseQuery: baseQuery,
endpoints: (builder) => ({
login: builder.mutation({
query: (credentials) => ({
url: "/auth/admin",
method: "POST",
body: credentials,
}),
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled;
// Store tokens in local storage
localStorage.setItem("accessToken", data?.data?.access?.token);
localStorage.setItem("refreshToken", data?.data?.refresh?.token);
// localStorage.setItem('refreshTokenExp', data?.data?.refresh?.expires);
localStorage.setItem("accessTokenExp", data?.data?.access?.expires);
} catch (error) {
console.error("Login failed:", error);
}
},
}),
refreshToken: builder.mutation({
query: (refreshToken) => ({
url: "/auth/user/regenerate-token",
method: "POST",
body: { refreshToken },
}),
}),
}),
});
export const { useLoginMutation, useRefreshTokenMutation } = apiSlice;

View File

@@ -6,13 +6,16 @@ import { exchangeRate } from "../Services/exchange.rate.service";
import { ioService } from "../Services/io.service"; import { ioService } from "../Services/io.service";
import { investorDetails } from "../Services/investor.details.service"; import { investorDetails } from "../Services/investor.details.service";
import { investorTransaction } from "../Services/investor.transaction.service"; import { investorTransaction } from "../Services/investor.transaction.service";
import { api } from "../Services/api.service"; // import { api } from "../Services/api.service";
import { keyMerits } from "../Services/Key.merits.service"; // import { keyMerits } from "../Services/Key.merits.service";
import { bankDetails } from "../Services/bank.details.service"; import { bankDetails } from "../Services/bank.details.service";
import { contact } from "../Services/contact.service"; import { contact } from "../Services/contact.service";
import { depositRequest } from "../Services/deposit.request.service";
import { apiSlice, baseQuery } from "../Services/token.serivce";
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
[apiSlice.reducerPath]: apiSlice.reducer,
[sponserMaster.reducerPath]: sponserMaster.reducer, [sponserMaster.reducerPath]: sponserMaster.reducer,
[investmentType.reducerPath]: investmentType.reducer, [investmentType.reducerPath]: investmentType.reducer,
[exchangeRate.reducerPath]: exchangeRate.reducer, [exchangeRate.reducerPath]: exchangeRate.reducer,
@@ -21,14 +24,16 @@ export const store = configureStore({
[investorTransaction.reducerPath]: investorTransaction.reducer, [investorTransaction.reducerPath]: investorTransaction.reducer,
[bankDetails.reducerPath]: bankDetails.reducer, [bankDetails.reducerPath]: bankDetails.reducer,
[contact.reducerPath]: contact.reducer, [contact.reducerPath]: contact.reducer,
[depositRequest.reducerPath]: depositRequest.reducer,
// Add other reducers as needed // Add other reducers as needed
}, },
middleware: (getDefaultMiddleware) => middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ getDefaultMiddleware({
thunk: { thunk: {
extraArgument: api, // Pass Axios instance as extra argument extraArgument: baseQuery, // Pass Axios instance as extra argument
}, },
}).concat( }).concat(
apiSlice.middleware,
sponserMaster.middleware, sponserMaster.middleware,
investmentType.middleware, investmentType.middleware,
exchangeRate.middleware, exchangeRate.middleware,
@@ -37,6 +42,7 @@ export const store = configureStore({
investorTransaction.middleware, investorTransaction.middleware,
bankDetails.middleware, bankDetails.middleware,
contact.middleware, contact.middleware,
depositRequest.middleware,
), ),
}); });

View File

@@ -1,7 +1,7 @@
import * as Yup from "yup"; import * as Yup from "yup";
export const validationSchema = Yup.object().shape({ export const validationSchema = Yup.object().shape({
name: Yup.string().required("Owner name is required"), name: Yup.string().required("Email name is required"),
password: Yup.string().required("Password is required"), password: Yup.string().required("Password is required"),
}); });

BIN
src/assets/click-151673.mp3 Normal file

Binary file not shown.

BIN
src/assets/commingsoon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
src/assets/mobileImg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/assets/mobileWing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 KiB

BIN
src/assets/welcome.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
src/assets/welcome2.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 KiB

BIN
src/assets/welcome3.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 KiB

BIN
src/assets/welcome4.avif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Some files were not shown because too many files have changed in this diff Show More