Compare commits

...

67 Commits

Author SHA1 Message Date
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
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
97 changed files with 4894 additions and 1678 deletions

View File

@@ -22,7 +22,7 @@ const craftedMsg = "Crafted with ❤️ by WDI Team for a better web.";
</script>
<script type="text/javascript">
<!-- <script type="text/javascript">
function googleTranslateElementInit() {
new google.translate.TranslateElement({
pageLanguage: 'en',
@@ -30,7 +30,10 @@ const craftedMsg = "Crafted with ❤️ by WDI Team for a better web.";
layout: google.translate.TranslateElement.InlineLayout.SIMPLE
}, 'google_translate_element');
}
</script>
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
</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>
</html>

310
package-lock.json generated
View File

@@ -14,17 +14,21 @@
"@emotion/styled": "^11.11.5",
"@hookform/resolvers": "^3.3.4",
"@reduxjs/toolkit": "^2.2.3",
"apexcharts": "^3.52.0",
"axios": "^1.7.2",
"bootstrap": "5.3.3",
"chart.js": "^4.4.3",
"dotenv": "^16.4.5",
"framer-motion": "^11.1.5",
"js-cookie": "^3.0.5",
"react": "^18.2.0",
"react-apexcharts": "^1.4.1",
"react-beautiful-dnd": "^13.1.1",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.51.3",
"react-icons": "^5.1.0",
"react-quill": "^2.0.0",
"react-quill": "^0.0.2",
"react-redux": "^9.1.1",
"react-router-dom": "^6.22.3",
"redux-persist": "^6.0.0",
@@ -1964,6 +1968,11 @@
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"dev": true
},
"node_modules/@kurkle/color": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -2498,14 +2507,6 @@
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
},
"node_modules/@types/quill": {
"version": "1.3.10",
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
"dependencies": {
"parchment": "^1.1.2"
}
},
"node_modules/@types/react": {
"version": "18.2.79",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz",
@@ -2566,6 +2567,11 @@
"vite": "^4 || ^5"
}
},
"node_modules/@yr/monotone-cubic-spline": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz",
"integrity": "sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA=="
},
"node_modules/@zag-js/dom-query": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-0.16.0.tgz",
@@ -2653,6 +2659,20 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/apexcharts": {
"version": "3.52.0",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.52.0.tgz",
"integrity": "sha512-7dg0ADKs8AA89iYMZMe2sFDG0XK5PfqllKV9N+i3hKHm3vEtdhwz8AlXGm+/b0nJ6jKiaXsqci5LfVxNhtB+dA==",
"dependencies": {
"@yr/monotone-cubic-spline": "^1.0.3",
"svg.draggable.js": "^2.2.2",
"svg.easing.js": "^2.0.0",
"svg.filter.js": "^2.0.2",
"svg.pathmorphing.js": "^0.1.3",
"svg.resize.js": "^1.4.3",
"svg.select.js": "^3.0.1"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -2891,6 +2911,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
"dev": true,
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
@@ -2941,12 +2962,15 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
"node_modules/chart.js": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.3.tgz",
"integrity": "sha512-qK1gkGSRYcJzqrrzdR6a+I0vQ4/R+SoODXyAjscQ/4mzuNzySaMCd+hyVxitSY1+L2fjPD1Gbn+ibNqRmwQeLw==",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
"engines": {
"node": ">=0.8"
"pnpm": ">=8"
}
},
"node_modules/codepage": {
@@ -3141,25 +3165,6 @@
}
}
},
"node_modules/deep-equal": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
"integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
"dependencies": {
"is-arguments": "^1.1.1",
"is-date-object": "^1.0.5",
"is-regex": "^1.1.4",
"object-is": "^1.1.5",
"object-keys": "^1.1.1",
"regexp.prototype.flags": "^1.5.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -3170,6 +3175,7 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
"dev": true,
"dependencies": {
"es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
@@ -3186,6 +3192,7 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
"dev": true,
"dependencies": {
"define-data-property": "^1.0.1",
"has-property-descriptors": "^1.0.0",
@@ -3306,6 +3313,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"dev": true,
"dependencies": {
"get-intrinsic": "^1.2.4"
},
@@ -3317,6 +3325,7 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
@@ -3671,15 +3680,10 @@
"node": ">=0.10.0"
}
},
"node_modules/eventemitter3": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg=="
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
"node_modules/eventemitter2": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
"integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ=="
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
@@ -3688,9 +3692,9 @@
"dev": true
},
"node_modules/fast-diff": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.0.1.tgz",
"integrity": "sha512-anEzYJ8VOA5iAMjDOVMTVMrUOXveDTMMk5x0E4p0nJ3VPoIOolF51AqYyE+UD0QIyggUwqppqH7XVA9lF3fdaQ=="
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
@@ -3913,6 +3917,7 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -3921,6 +3926,7 @@
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"dev": true,
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2",
@@ -4026,6 +4032,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
"dev": true,
"dependencies": {
"get-intrinsic": "^1.1.3"
},
@@ -4061,6 +4068,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
"dev": true,
"dependencies": {
"es-define-property": "^1.0.0"
},
@@ -4072,6 +4080,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
@@ -4083,6 +4092,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
@@ -4094,6 +4104,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"dev": true,
"dependencies": {
"has-symbols": "^1.0.3"
},
@@ -4204,21 +4215,6 @@
"loose-envify": "^1.0.0"
}
},
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-array-buffer": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
@@ -4325,6 +4321,7 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
"dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
@@ -4435,6 +4432,7 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -4694,9 +4692,13 @@
}
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
"integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==",
"engines": [
"node",
"rhino"
]
},
"node_modules/lodash.merge": {
"version": "4.6.2",
@@ -4803,25 +4805,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-is": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
"dev": true,
"engines": {
"node": ">= 0.4"
}
@@ -4966,11 +4954,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/parchment": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg=="
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -5139,27 +5122,14 @@
}
]
},
"node_modules/quill": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
"node_modules/quilljs": {
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/quilljs/-/quilljs-0.18.1.tgz",
"integrity": "sha512-VKaO7GNehgnH4LlFPx5ZAl+KFDoRVtboY0I6UUbYXUsPHP8kR80Tg/CFEYqrqrpCOGQr4OQ5Tjm813gV1DUyQw==",
"dependencies": {
"clone": "^2.1.1",
"deep-equal": "^1.0.1",
"eventemitter3": "^2.0.3",
"extend": "^3.0.2",
"parchment": "^1.1.4",
"quill-delta": "^3.6.2"
}
},
"node_modules/quill-delta": {
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
"dependencies": {
"deep-equal": "^1.0.1",
"extend": "^3.0.2",
"fast-diff": "1.1.2"
"eventemitter2": "~0.4.13",
"lodash": "~2.4.1",
"rich-text": "~1.0.2"
},
"engines": {
"node": ">=0.10"
@@ -5181,6 +5151,18 @@
"node": ">=0.10.0"
}
},
"node_modules/react-apexcharts": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/react-apexcharts/-/react-apexcharts-1.4.1.tgz",
"integrity": "sha512-G14nVaD64Bnbgy8tYxkjuXEUp/7h30Q0U33xc3AwtGFijJB9nHqOt1a6eG0WBn055RgRg+NwqbKGtqPxy15d0Q==",
"dependencies": {
"prop-types": "^15.8.1"
},
"peerDependencies": {
"apexcharts": "^3.41.0",
"react": ">=0.13"
}
},
"node_modules/react-beautiful-dnd": {
"version": "13.1.1",
"resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz",
@@ -5236,6 +5218,15 @@
"@babel/runtime": "^7.9.2"
}
},
"node_modules/react-chartjs-2": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz",
"integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==",
"peerDependencies": {
"chart.js": "^4.1.1",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-clientside-effect": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.6.tgz",
@@ -5315,17 +5306,17 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-quill": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
"integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-0.0.2.tgz",
"integrity": "sha512-PeiHXZ63Sumh41OdovBQExXJH7B4UsJpyCW8CtRvXrNBa2RJXdciaJvTeb0x6pYQfqkoCYPT5EbUvEr0Z1tohg==",
"dependencies": {
"@types/quill": "^1.3.10",
"lodash": "^4.17.4",
"quill": "^1.3.7"
"quilljs": "^0.18.1"
},
"engines": {
"node": ">= 0.8.x"
},
"peerDependencies": {
"react": "^16 || ^17 || ^18",
"react-dom": "^16 || ^17 || ^18"
"react": ">=0.11.0"
}
},
"node_modules/react-redux": {
@@ -5515,6 +5506,7 @@
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
"integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
"dev": true,
"dependencies": {
"call-bind": "^1.0.6",
"define-properties": "^1.2.1",
@@ -5567,6 +5559,17 @@
"node": ">=0.10.0"
}
},
"node_modules/rich-text": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/rich-text/-/rich-text-1.0.3.tgz",
"integrity": "sha512-L+Mi0fBH4/TBGH68XZqUXdUr5Ze+ViYkrKuwEvCpeyB1Blbp4CLO4LyYleutTNybujCMQfcmivaNrE3YLrEUgg==",
"dependencies": {
"fast-diff": "~1.0.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -5696,6 +5699,7 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dev": true,
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
@@ -5712,6 +5716,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
"dev": true,
"dependencies": {
"define-data-property": "^1.1.4",
"es-errors": "^1.3.0",
@@ -5916,6 +5921,89 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svg.draggable.js": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
"dependencies": {
"svg.js": "^2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.easing.js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
"integrity": "sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==",
"dependencies": {
"svg.js": ">=2.3.x"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.filter.js": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
"integrity": "sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==",
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
},
"node_modules/svg.pathmorphing.js": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
"dependencies": {
"svg.js": "^2.4.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
"dependencies": {
"svg.js": "^2.6.5",
"svg.select.js": "^2.1.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.resize.js/node_modules/svg.select.js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
"dependencies": {
"svg.js": "^2.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/svg.select.js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
"dependencies": {
"svg.js": "^2.6.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,48 @@
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) return '';
const [integer, decimal] = value?.split('.');
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);
reorderedItems.splice(result.destination.index, 0, removed);
setData(reorderedItems)
console.log("New Order:", reorderedItems.map((item, index) => ({ index, item })));
// console.log("New Order:", reorderedItems.map((item, index) => ({ index, item })));
};
return (

View File

@@ -12,6 +12,7 @@ import {
Tfoot,
} from "@chakra-ui/react";
import EmptySearchList from "../EmptySearchList";
import { TABLE_PAGINATION } from "../../Constants/Paginations";
const DataTable = ({
data,
@@ -20,6 +21,9 @@ const DataTable = ({
emptyMessage,
centered,
}) => {
console.log(data);
const columnWidth =
data && data[0]
? `${(100 / Object.keys(data[0]).length).toFixed(2)}%`
@@ -35,7 +39,6 @@ const DataTable = ({
<Tr>
{tableHeadRow.map((heading, index) => (
<Th
width={'fit-content'}
textAlign={
tableHeadRow.length - 1 === index || centered
? "center"
@@ -43,7 +46,13 @@ const DataTable = ({
}
key={index}
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}
{/* {heading} */}
@@ -53,7 +62,7 @@ const DataTable = ({
</Thead>
<Tbody className="web-text-small">
{isLoading
? Array.from({ length: 12 }).map((_, index) => (
? Array.from({ length: TABLE_PAGINATION?.size }).map((_, index) => (
<Tr key={index}>
{tableHeadRow.map((_, i) => (
<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 { motion } from "framer-motion";
import { AddIcon, CloseIcon } from "@chakra-ui/icons";
import CurrencyInput from "./CurrencyInput";
const today = new Date().toISOString().split("T")[0];
const formatDate = (dateString) => {
export const formatDatee = (dateString) => {
const date = new Date(dateString);
const year = date.getFullYear();
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";
// Format the default date as YYYY-MM-DD
const formattedDate = formatDate(defaultDate);
const formattedDate = formatDatee(defaultDate);
const FormField = ({
label,
@@ -67,12 +68,13 @@ const FormField = ({
handleInputChange,
align,
maxLength,
dateValue,
...props
}) => (
<FormControl
w={width ? width : "49%"}
isInvalid={errors[name]}
isRequired={isRequired}
isRequired={type === "date" ? false: isRequired}
mb={2}
>
<FormLabel textAlign={"left"} fontSize={"xs"} color={"gray.600"}>
@@ -460,7 +462,51 @@ const FormField = ({
</Tbody>
</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 (
<Input
bg={"#F5F8F6"}
@@ -474,7 +520,7 @@ const FormField = ({
placeholder={placeHolder ? placeHolder : label}
textAlign={arabic || type === "number" ? "right" : align ? align : "left"}
_placeholder={{ fontSize: "sm" }}
min={type === "date" ? today : undefined}
// min={type === "date" ? today : undefined}
maxLength={maxLength}
// defaultValue={type === "date" && "2023-07-26" : undefined}
// value={"2023-07-26"}
@@ -490,7 +536,7 @@ const FormField = ({
</span>
)}
{helperText && (
<FormHelperText className="web-text-small">{helperText}</FormHelperText>
<FormHelperText color={'gray.500'} className="web-text-small">{helperText}</FormHelperText>
)}
{type === "file" && (
<FormHelperText className="web-text-small">

View File

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

View File

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

View File

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

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

View File

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

View File

@@ -0,0 +1,381 @@
import {
Box,
Button,
Heading,
HStack,
Image,
Modal,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Progress,
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";
const MobileView = ({ isOpen, onClose, finalRef }) => {
const [time, setTime] = useState(new Date());
const navigate = useNavigate();
const params = useParams();
const id = params?.id;
const {
data,
isLoading: IObyIDisLoading,
error: IObyIDerror,
} = useGetIOByIdQuery(id, { skip: !id });
console.log(data);
useEffect(() => {
const timer = setInterval(() => {
setTime(new Date());
}, 1000);
return () => clearInterval(timer);
}, []);
const formatTime = (date) => {
return date.toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
hour12: false,
});
};
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={"330px"}
>
<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"}
>
<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"}
>
<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 Aug 23 2024
</Text>
</Text>
<Image
borderTopLeftRadius={"20px"}
borderTopRightRadius={"20px"}
h={"130px"}
w={"100%"}
src={mobileBanner}
/>
</Box>
<Stack mt="3" bg={"#fff"} py={4} px={4}>
<Text
fontSize={"sm"}
fontWeight={"500"}
color={"#000"}
mb={0}
>
Guinevere Gates
</Text>
<Heading fontSize="16px" color={"#004717"}>
BHD 46,258
</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"}
>
fugit eligendi dolore dolore et
</Text>
</Stack>
<Box py={4} px={4}>
<Box display={"flex"} justifyContent={"space-between"}>
<Text
fontSize={"10px"}
mb={1}
fontWeight={600}
color={"#616161"}
>
Sponsor name:
</Text>
<Text fontSize={"10px"} mb={1} fontWeight={600}>
Scott Simon
</Text>
</Box>
<Box display={"flex"} justifyContent={"space-between"}>
<Text
fontSize={"10px"}
mb={1}
fontWeight={600}
color={"#616161"}
>
Estimated return:
</Text>
<Text fontSize={"10px"} mb={1} fontWeight={600}>
A provident veniam
</Text>
</Box>
<Box display={"flex"} justifyContent={"space-between"}>
<Text
fontSize={"10px"}
mb={1}
fontWeight={600}
color={"#616161"}
>
Hoiding period:
</Text>
<Text fontSize={"10px"} mb={1} fontWeight={600}>
Eius eiusmod exericit
</Text>
</Box>
<Box display={"flex"} justifyContent={"space-between"}>
<Text
fontSize={"10px"}
mb={1}
fontWeight={600}
color={"#616161"}
>
Minimum investment:
</Text>
<Text fontSize={"10px"} mb={1} fontWeight={600}>
BHD 1
</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"}>
<Image
width={"30px"}
me={2}
src="https://tanami.betadelivery.com/public/icons/icon3.svg"
/>
<Text fontSize={"xs"} mb={0}>
Sit sunt consequunt Dolores minim suscip
</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"
/>
<Text fontSize={"xs"} mb={0}>
Merrill Rocha
</Text>
</Box>
<Box
display={"flex"}
alignItems={"center"}
justifyContent={"space-between"}
>
<Text mb={0} fontSize={"sm"}>
0.03 mb
</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 style={{ borderRadius: "18px" }}>
<source
src="https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4"
type="video/mp4"
style={{ height: "200px" }}
/>
</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 React from 'react';
import { Box, Text } from "@chakra-ui/react";
import React, { useRef } from "react";
import audioClick from "../assets/click-151673.mp3";
const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {
// const [isSwitchOn, setIsSwitchOn] = useState(false);
const audio = useRef();
const switch_onChange_handle = () => {
setIsSwitchOn(!isSwitchOn);
if (audio.current) {
audio.current.play();
}
};
return (
@@ -15,7 +24,7 @@ const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {
alignItems="center"
// justifyContent={isSwitchOn ? "flex-end" : "flex-start"}
width="90px"
height="24px"
height="25px"
borderRadius="20px"
backgroundColor={isSwitchOn ? "#004118" : "#ef0000"}
onClick={switch_onChange_handle}
@@ -24,16 +33,28 @@ const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {
fontWeight="100"
transition="background-color 0.2s"
_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: '""',
position: "absolute",
width: "20px",
height: "20px",
height: "25px",
width: "25px",
left: "0px",
background:
"conic-gradient(rgb(104, 104, 104), white, rgb(104, 104, 104), white, rgb(104, 104, 104))",
borderRadius: "50%",
backgroundColor: "#FFF",
boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)",
transitionDuration: ".3s",
boxShadow: " 5px 2px 7px rgba(8, 8, 8, 0.308)",
transform: isSwitchOn ? "translateX(65px)" : "translateX(0)",
transition: "transform 0.2s",
left:'2px'
}}
>
<Text
@@ -46,9 +67,10 @@ const SwitchButton = ({ isSwitchOn, setIsSwitchOn }) => {
left={isSwitchOn ? "10px" : "auto"}
right={isSwitchOn ? "auto" : "10px"}
>
{isSwitchOn ? 'Active' : 'InActive'}
{isSwitchOn ? "Active" : "InActive"}
</Text>
</Box>
<audio ref={audio} src={audioClick} />
</Box>
);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -1,6 +1,77 @@
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) => {
const parts = filePath?.split("/");
return parts?.[parts?.length - 1];
@@ -42,3 +113,20 @@ export async function checkEmailValidity(email) {
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);
}

View File

@@ -46,7 +46,6 @@ const GlobalStateProvider = ({ children }) => {
const [slideFromRight, setSlideFormRight] = useState(false);
const { colorMode, toggleColorMode } = useColorMode();
const [sponser, setSponser] = useState([]);
const [ioStatus, setIoStatus] = useState([]);
const [investors, setInvestors] = useState([
{
@@ -1450,7 +1449,6 @@ const GlobalStateProvider = ({ children }) => {
},
]);
const [IODetails, setIODetails] = 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 (
<GlobalStateContext.Provider
value={{
@@ -1795,8 +1804,10 @@ const GlobalStateProvider = ({ children }) => {
setAcademicDocuments,
iOArtifactsTwo,
setIOArtifactsTwo,
ioStatus,
setIoStatus,
isIOloading,
setIOloading
}}
>
{children}

View File

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

View File

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

View File

@@ -10,6 +10,7 @@ import {
Textarea,
Button,
Text,
useToast,
} from "@chakra-ui/react";
import { useForm, Controller } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
@@ -19,8 +20,9 @@ import { v4 as uuidv4 } from "uuid";
import GlobalStateContext from "../../Contexts/GlobalStateContext";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
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 ToastBox from "../../Components/ToastBox";
export const addSponser = yup.object().shape({
phoneNumber: yup.string().required("Phone Number is required"),
@@ -37,8 +39,10 @@ export function debounce(func, delay) {
}
const Contact = () => {
const toast = useToast()
const navigate = useNavigate();
const [form, setForm] = useState({});
const [ isLoading, setIsLoading ] = useState(false)
// const { sponser, setSponser } = useContext(GlobalStateContext);
const {
@@ -50,22 +54,21 @@ const Contact = () => {
resolver: yupResolver(addSponser),
});
console.log(errors);
const {
data: contact,
isLoading: contactLoading,
error,
} = useGetContactQuery({ page: 1, size: 10 });
} = useGetContactQuery();
const [ updateContact ] = useUpdateContactMutation()
console.log(contact?.data);
useEffect(() => {
if (contact) {
reset({
phoneNumber: contact.phoneNumber,
emailAddress: contact.emailAddress,
websiteUrl: contact.websiteUrl,
phoneNumber: contact?.data[0]?.phoneNumber,
emailAddress: contact?.data[0]?.emailAddress,
websiteUrl: contact?.data[0]?.websiteUrl,
});
}
}, [contact, reset]);
@@ -82,7 +85,7 @@ const Contact = () => {
type: "text",
isRequired: true,
section: "Add Details",
defaultValue: contact?.phoneNumber || "",
// value: contact?.phoneNumber || "",
},
{
label: "E-mail ID",
@@ -91,7 +94,7 @@ const Contact = () => {
type: "text",
isRequired: true,
section: "Add Details",
defaultValue: contact?.emailAddress || "",
// value: contact?.emailAddress || "",
},
{
label: "Website URL",
@@ -100,7 +103,7 @@ const Contact = () => {
type: "text",
isRequired: true,
section: "Add Details",
defaultValue: contact?.websiteUrl || "",
// value: contact?.websiteUrl || "",
},
];
@@ -113,11 +116,25 @@ const Contact = () => {
return groups;
}, {});
const onSubmit = (data) => {
if (!Object.keys(errors).length) {
setForm(data);
setAlert(true);
const onSubmit = async (data) => {
setIsLoading(true)
try {
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 (
@@ -127,6 +144,7 @@ const Contact = () => {
control={control}
errors={errors}
onSubmit={handleSubmit(onSubmit)}
btnLoading={isLoading}
/>
</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,12 @@ import ToastBox from "../../../Components/ToastBox";
import DataTable from "../../../Components/DataTable/DataTable";
import DepositRequestApprove from "./DepositRequestApprove";
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";
import { formatCurrency } from "../../../Components/CurrencyInput";
const formatDate = (date) => new Date(date).toLocaleDateString(); // Simple date formatter
@@ -42,7 +48,7 @@ const DepositRequest = () => {
const [searchTerm, setSearchTerm] = useState("");
const [isLoading, setIsLoading] = useState(true);
const [deleteAlert, setDeleteAlert] = useState(false);
const [actionId, setActionId] = useState(false);
const [actionId, setActionId] = useState("");
const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState("");
const {
@@ -56,30 +62,27 @@ const DepositRequest = () => {
onClose: onRejectClose,
} = useDisclosure();
useEffect(() => {
// Simulate loading
const timer = setTimeout(() => {
setIsLoading(false);
}, 1500);
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page);
const {
data,
isLoading: depositRequestLoading,
error,
} = useGetDepositRequestQuery({ page: currentPage, size: pageSize });
// Cleanup the timer on component unmount
return () => clearTimeout(timer);
}, []);
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
"Sr.no",
"Date",
// "Sr.no",
"Client ID",
"First Name",
"Last Name",
"Country",
"Phone Number",
"Currency",
"Deposit Amount",
"Fees",
"Total Amount",
"Amount in Investor currency",
"Deposit Date",
"Action",
];
@@ -96,14 +99,14 @@ const DepositRequest = () => {
});
}, 300);
// ====================================================[Table Filter]================================================================
const filteredData = depositRequest.filter((item) => {
const filteredData = data?.data?.rows
.filter((item) => {
// 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 nameMatches = name.toLowerCase().includes(searchLower);
// Filter by status
// Filter by status (Uncomment and use if needed)
// const status = item.status;
// const statusLower = status ? "active" : "inactive";
@@ -113,162 +116,144 @@ const DepositRequest = () => {
// (statusFilter === "inactive" && status === false);
return nameMatches;
});
})
.sort((b, a) => new Date(a.createdAt) - new Date(b.createdAt));
const [extractedArray, setExtractedArray] = useState(
filteredData?.map((item, index) => ({
// id: item?.id,
"Sr.no": (
<Text
w={"30px"}
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{index + 1}
console.log(data?.data?.rows);
const extractedArray = filteredData?.map((item, index) => ({
// id: item?.id,
"Sr.no": (
<Text
w={"30px"}
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
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>
),
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}
</Box>
),
"Last Name": (
<Box w={"70px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item?.lastName}
</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.clientId}
</Box>
),
Country: (
<Box w={"100px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item?.countryName}
</Text>
),
"First Name": (
<Box isTruncated={true} w={"50px"}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item.firstName}
</Text>
</Box>
),
"Last Name": (
<Box w={"50px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.lastName}
</Text>
</Box>
),
Country: (
<Box w={"70px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.country}
</Text>
</Box>
),
"Phone Number": (
<Box w={"70px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.phoneNumber}
</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>
</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
</Box>
),
"Phone Number": (
<Box w={"80px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item?.mobileNumber}
</Text>
</Box>
),
"Amount in Investor currency": (
<Box display={'flex'} justifyContent={'end'} w={"100px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{formatCurrency(removeTrailingZeros(item?.investorAmount))} <Badge ms={1} colorScheme="green">{item?.currencyCode}</Badge>
</Text>
</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>
),
Action: (
<Box display={"flex"} justifyContent={"center"} gap={2}>
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="Approve"
bg="#fff"
color={"green.500"}
placement="left-start"
>
<Button
// colorScheme="forestGreen"
// color="green.500"
rounded={"sm"}
fontSize={"xs"}
label="Approve"
bg="#fff"
color={"green.500"}
placement="left-start"
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
py={1}
onClick={() => {
setActionId(item.id);
onConfirmOpen();
}}
colorScheme="green"
variant={"solid"}
cursor={"pointer"}
>
<Badge
colorScheme="forestGreen"
color="green.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
py={1}
onClick={onConfirmOpen}
>
<CheckIcon fontSize={"12px"} />
</Badge>
</Tooltip>
<Tooltip
<CheckIcon fontSize={"12px"} />
</Button>
</Tooltip>
<Tooltip
rounded={"sm"}
fontSize={"xs"}
label="Reject"
bg="#fff"
color={"red.500"}
placement="left-start"
>
<Button
colorScheme="red"
// color="red.500"
rounded={"sm"}
fontSize={"xs"}
label="Reject"
bg="#fff"
color={"red.500"}
placement="left-start"
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
onClick={() => {
setActionId(item.id);
onRejectOpen();
}}
py={1}
// variant={"solid"}
>
<Badge
colorScheme="red"
color="red.500"
rounded={"sm"}
size={"xs"}
textTransform={"inherit"}
fontWeight={500}
px={2}
onClick={onRejectOpen}
py={1}
>
<CloseIcon fontSize={"10px"} />
</Badge>
</Tooltip>
</Box>
),
}))
);
<CloseIcon fontSize={"10px"} />
</Button>
</Tooltip>
</Box>
),
}));
const handleDelete = () => {
const IOtype = investmentType.filter(
@@ -307,17 +292,23 @@ const DepositRequest = () => {
/>
<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>
</Box>
<DataTable
<NormalTable
emptyMessage={`We don't have any Investment type `}
tableHeadRow={tableHeadRow}
setData={setExtractedArray}
data={extractedArray}
isLoading={isLoading}
isLoading={depositRequestLoading}
viewActionId={actionId}
setViewActionId={setActionId}
// totalPages={10}
@@ -334,11 +325,17 @@ const DepositRequest = () => {
isLoading={isLoading}
/>
<DepositRequestApprove
data={data?.data?.rows}
isOpen={isConfirmOpen}
onClose={onConfirmClose}
// firstField={firstField}
id={actionId}
// firstField={firstField}
/>
<DepositRequestReject
isOpen={isRejectOpen}
onClose={onRejectClose}
id={actionId}
/>
<DepositRequestReject isOpen={isRejectOpen} onClose={onRejectClose} />
</Box>
);
};

View File

@@ -1,128 +1,225 @@
import {
Box,
Button,
FormControl,
FormLabel,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
useDisclosure,
} from "@chakra-ui/react";
import React from "react";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
export const conformModalSchema = yup.object().shape({
fees: yup.string().required("File name is required"),
totalAmount: yup.string().required("File name is required"),
Box,
Button,
FormControl,
FormLabel,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
Textarea,
useDisclosure,
useToast,
} from "@chakra-ui/react";
import React, { useEffect, useState } from "react";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
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 {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
}, [requestData, id])
const onSubmit = (data) => {
setFile(data.document[0]);
const newDocument = {
...data,
document: data.document[0].name, // Store the document name
status: true,
id: uuidv4(),
createdAt: new Date().toISOString(),
Type: getFileIcon(file.type),
};
setCreate((prevCreate) => [...prevCreate, newDocument]);
onClose();
};
const handleFileChange = (event) => {
const selectedFile = event.target.files[0];
setFile(selectedFile);
};
return (
<Modal isOpen={isOpen} onClose={onClose} initialFocusRef={firstField}>
<ModalOverlay />
<ModalContent pb={4}>
<ModalHeader fontSize={"md"}>Confirm</ModalHeader>
<ModalCloseButton />
const onSubmit = async(data) => {
setIsBtnLoading(true)
const formData = new FormData();
formData.append("investorAmount", data.investorAmount);
formData.append("comment", data.comment);
const file = data.supporting_FileName["0"];
formData.append("supporting_FileName", file);
try {
const res = await updateDepositRequest({ id ,data: formData})
if (res?.error) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
});
setIsBtnLoading(false)
}else if(res?.data?.statusCode === 200) {
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
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)}>
<ModalBody>
<FormControl mb={4}>
<FormLabel fontSize="sm">Deposit Amount</FormLabel>
<FormControl mb={4} isRequired>
<FormLabel fontSize="sm">Deposit Amount (SAR)</FormLabel>
<Input
focusBorderColor='green.400'
name="fileName"
{...register("fileName")}
focusBorderColor="green.400"
name="investorAmount"
{...register("investorAmount")}
fontSize="sm"
type="text"
type="number"
size="sm"
placeholder={"$100,000"}
readOnly
placeholder={"100,000"}
textAlign={"right"}
// readOnly
/>
</FormControl>
<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 && (
{errors.investorAmount && (
<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>
)}
</FormControl>
<FormControl mb={4}>
<FormLabel fontSize="sm">Total Amount</FormLabel>
<Input
focusBorderColor='green.400'
name="fileName"
{...register("fileName")}
<FormLabel fontSize="sm">Comments</FormLabel>
<Textarea
rows={5}
focusBorderColor="green.400"
name="comment"
{...register("comment")}
fontSize="sm"
type="text"
type="textarea"
size="sm"
placeholder={"$100,000"}
placeholder={"Enter your comments...."}
resize={"none"}
/>
{errors.totalAmount && (
{errors.comment && (
<Text fontSize="xs" color="red">
{errors.totalAmount.message}
{errors.comment.message}
</Text>
)}
</FormControl>
</ModalBody>
<ModalFooter>
<Button colorScheme="gray" mr={3} onClick={onClose} size={'sm'} rounded={'sm'}>
<Button
colorScheme="gray"
mr={3}
onClick={onClose}
size={"sm"}
rounded={"sm"}
>
Cancel
</Button>
<Button colorScheme="forestGreen" variant="solid" size={'sm'} rounded={'sm'}>
<Button
colorScheme="forestGreen"
variant="solid"
size={"sm"}
rounded={"sm"}
isLoading={isBtnLoading}
type="submit"
>
Confirm
</Button>
</ModalFooter>
</Box>
</ModalContent>
</Modal>
);
};
export default DepositRequestApprove;
)}
</ModalContent>
</Modal>
);
};
export default DepositRequestApprove;

View File

@@ -1,99 +1,163 @@
import {
Box,
Button,
FormControl,
FormLabel,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
Textarea,
useDisclosure,
} from "@chakra-ui/react";
import React from "react";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
export const conformModalSchema = yup.object().shape({
comment: yup.string().required("Comment is required"),
Box,
Button,
FormControl,
FormLabel,
Input,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
Text,
Textarea,
useDisclosure,
useToast,
} from "@chakra-ui/react";
import React, { useEffect, useState } from "react";
import * as yup from "yup";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
import { useDepositRejectMutation } from "../../../Services/deposit.request.service";
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 {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(conformModalSchema),
});
const onSubmit = async(data) => {
setIsBtnLoading(true)
try {
const res = await depositReject({ id ,data})
const onSubmit = (data) => {
setFile(data.document[0]);
const newDocument = {
...data,
document: data.document[0].name, // Store the document name
comment: true,
id: uuidv4(),
Type: getFileIcon(file.type),
};
setCreate((prevCreate) => [...prevCreate, newDocument]);
onClose();
};
const handleFileChange = (event) => {
const selectedFile = event.target.files[0];
setFile(selectedFile);
};
return (
<Modal isOpen={isOpen} onClose={onClose} initialFocusRef={firstField}>
<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>
);
if (res?.error) {
toast({
render: () => (
<ToastBox message={res?.error?.data?.message} status={"error"} />
),
});
setIsBtnLoading(false)
onClose();
}else if(res?.data?.statusCode === 200) {
toast({
render: () => (
<ToastBox message={res?.data?.message} />
),
});
setIsBtnLoading(false)
onClose();
}
} catch (error) {
console.log(error);
}
};
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,
Tooltip,
useToast,
useDisclosure
useDisclosure,
Link,
} from "@chakra-ui/react";
import React, { useContext, useEffect, useState } from "react";
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 { OPACITY_ON_LOAD } from "../../../Layout/animations";
import Pagination from "../../../Components/Pagination";
import GlobalStateContext from "../../../Contexts/GlobalStateContext";
import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import ToastBox from "../../../Components/ToastBox";
import DataTable from "../../../Components/DataTable/DataTable";
import NormalTable from "../../../Components/DataTable/NormalTable";
import ConfirmModal from "./ConfirmModal";
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
@@ -36,42 +43,40 @@ const DepositHistory = () => {
const [actionId, setActionId] = useState(false);
const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState("");
const {
isOpen: isConfirmOpen,
onOpen: onConfirmOpen,
onClose: onConfirmClose,
} = useDisclosure();
const {
isOpen: isRejectOpen,
onOpen: onRejectOpen,
onClose: onRejectClose,
} = useDisclosure();
// const {
// isOpen: isConfirmOpen,
// onOpen: onConfirmOpen,
// onClose: onConfirmClose,
// } = useDisclosure();
// const {
// isOpen: isRejectOpen,
// onOpen: onRejectOpen,
// onClose: onRejectClose,
// } = 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]================================================================
const tableHeadRow = [
"Sr.no",
"Date",
// "Sr.no",
"Client ID",
"First Name",
"Last Name",
"Country",
"Phone Number",
"Currency",
"Deposit Amount",
"Fees",
"Total Amount",
"Amount in Investor currency",
"Deposit Date",
"Status",
"Supporting's",
];
const handleUpdateStatus = debounce((id) => {
@@ -87,22 +92,37 @@ const DepositHistory = () => {
});
}, 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) => {
// setActionId(id);
// onViewOpen();
// };
const [extractedArray, setExtractedArray] = useState(
const extractedArray =
filteredData?.map((item, index) => ({
"Sr.no": (
<Text
@@ -116,18 +136,6 @@ const DepositHistory = () => {
{index + 1}
</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": (
<Text
w={"60px"}
@@ -137,98 +145,108 @@ const DepositHistory = () => {
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.clientId}
{item?.clientReference_id}
</Text>
),
"First Name": (
<Box isTruncated={true} w={"50px"}>
<Box isTruncated={true} w={"60px"}>
<Text as={"span"} color={"teal.900"} fontWeight={"500"}>
{item.firstName}
{item?.firstName}
</Text>
</Box>
),
"Last Name": (
<Box w={"50px"} isTruncated={true}>
<Box w={"70px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.lastName}
{item?.lastName}
</Text>
</Box>
),
Country: (
<Box w={"70px"} isTruncated={true}>
<Box w={"80px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.country}
{item?.countryName}
</Text>
</Box>
),
"Phone Number": (
<Box w={"70px"} isTruncated={true}>
<Box w={"80px"} isTruncated={true}>
<Text as={"span"} color={"teal.900"}>
{item.phoneNumber}
</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}
{item?.mobileNumber}
</Text>
</Box>
),
"Amount in Investor currency": (
<Box w={"70px"} isTruncated={true}>
<Box w={"100px"} isTruncated={true}>
<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>
</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: (
<Box w={"70px"} isTruncated={true} cursor={'pointer'}>
<Box w={"70px"} isTruncated={true} cursor={"pointer"}>
<Text
// onClick={() => {
// setActionId(item.id);
// onConfirmOpen();
// }}
onClick={() => {
setActionId(item.id);
if (item.status === "Approved") {
onConfirmOpen();
} else {
onRejectOpen();
}
}}
as={"span"}
color={item.status === "Approved" ? "green" : "red"}
color={item.transactionStatus === "Approved" ? "green.500" : "red.500"}
fontWeight={700}
>
{item.status}
{item.transactionStatus}
</Text>
</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={"https://tanami.betadelivery.com/" + 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 IOtype = investmentType.filter(
@@ -245,15 +263,14 @@ const DepositHistory = () => {
return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
<ConfirmModal
{/* <ConfirmModal
isOpen={isConfirmOpen}
onClose={onConfirmClose}
// firstField={firstField}
/>
<RejectModal
isOpen={isRejectOpen}
onClose={onRejectClose}
/>
/> */}
<Box bg="white.500">
<HStack
display={"flex"}
@@ -276,17 +293,24 @@ const DepositHistory = () => {
/>
<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>
</Box>
<DataTable
<NormalTable
emptyMessage={`We don't have any Investment type `}
tableHeadRow={tableHeadRow}
setData={setExtractedArray}
// setData={setExtractedArray}
data={extractedArray}
isLoading={isLoading}
isLoading={depositHistoryLoading}
viewActionId={actionId}
setViewActionId={setActionId}
setMouseEnteredId={setMouseEnteredId}

View File

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

View File

@@ -0,0 +1,248 @@
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()
}
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 FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders";
import { useGetIOprepopulateDataQuery } from "../../../Services/io.service";
import UnderConstruction from "../../UnderConstruction";
const CreateIO = () => {
const id = useParams()?.id;
@@ -57,18 +58,24 @@ const CreateIO = () => {
},
{
label: "Investors",
Content: Investors,
isDisabled: id ? false : false,
// Content: Investors,
Content: UnderConstruction,
isDisabled: id ? false : true,
},
{
label: "IO Cash Details",
label: "IO Cash Detail",
Content: IOCashDetails,
isDisabled: id ? false : false,
isDisabled: id ? false : true,
},
{
label: "IO NAV Details",
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"}
pb={10}
>
<Box paddingInline={"12px"} mt={2}>
{id && <Box
ps={1}
pe={2} mt={2}>
{/* <span
onClick={() => navigate(-1)}
style={{ fontSize: "15px", cursor: "pointer" }}
>
<ArrowBackIcon cursor={"pointer"} /> Back
</span> */}
<ViewIOdataHeader />
</Box>
<ViewIOdataHeader isLoading={isLoading} data={data?.data} />
</Box>}
<Tabs
index={activeIndex}
onChange={(index) => setActiveIndex(index)}
mt={2}
ps={1}
pe={2}
>
<TabList>
{tabs?.map(({ label, isDisabled }, index) => (

View File

@@ -7,6 +7,7 @@ import {
Text,
Tooltip,
useDisclosure,
useToast,
} from "@chakra-ui/react";
import React, { useContext, useEffect, useRef, useState } from "react";
import DataTable from "../../../Components/DataTable/DataTable";
@@ -30,8 +31,10 @@ import {
} from "../../../Services/io.service";
import { getFileNameFromPath } from "../../../Constants/Constants";
import ImageViewer from "../../../Components/ImageViewer";
import ToastBox from "../../../Components/ToastBox";
const IOArtifacts = ({ enableNextTab, index, data }) => {
const toast = useToast()
const params = useParams();
const id = params?.id;
@@ -107,10 +110,12 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
setIsLoadingBtn(true);
try {
const res = await deleteVideoArtifacts(id);
console.log(res?.data?.statusCode);
if (res?.data?.statusCode === 200) {
setDeleteAlertVideo(false);
setIsLoadingBtn(false);
toast({
render: () => <ToastBox message={res?.data?.message} status="error" />,
});
}
} catch (error) {
console.log(error);
@@ -121,10 +126,15 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
setIsLoadingBtn(true);
try {
const res = await deleteImageArtifacts(id);
console.log(res?.data?.statusCode);
console.log(res);
if (res?.data?.statusCode === 200) {
setDeleteAlertImage(false);
setIsLoadingBtn(false);
toast({
render: () => <ToastBox message={res?.data?.message} status="error" />,
});
}
} catch (error) {
console.log(error);
@@ -342,7 +352,9 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
Manage IO Images
</Box>
<HStack>
<SetDisplayOrder data={IObyID?.data?.artifactsImage} />
{IObyID?.data?.artifactsImage?.length !== 0 &&<SetDisplayOrder data={IObyID?.data?.artifactsImage} />}
<Button
leftIcon={<AddIcon />}
onClick={onOpen}
@@ -378,7 +390,7 @@ const IOArtifacts = ({ enableNextTab, index, data }) => {
Manage IO videos
</Box>
<HStack>
<SetDisplayOrder data={IObyID?.data?.artifactsImage} />
{IObyID?.data?.artifactsVideo?.length !== 0 &&<SetDisplayOrder data={IObyID?.data?.artifactsVideo} />}
<Button
leftIcon={<AddIcon />}
onClick={onOpenVideo}

View File

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

View File

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

View File

@@ -33,13 +33,15 @@ import oman from "../../../assets/oman_flag.png";
import qatar from "../../../assets/qatar_flag.png";
import uae from "../../../assets/uae_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({
investmentNameEnglish: yup
.string()
.required("IO name in English is required")
.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
.string()
@@ -58,12 +60,15 @@ const schema = yup.object().shape({
.required("Description in Arabic is required")
.min(10, "Description in Arabic must be at least 10 characters long")
.max(2000, "Description in Arabic must be at most 500 characters long"),
expectedReturnArabic: yup
.string()
.required("Expected return in Arabic is required"),
goalAmount: yup
.number()
.required("Goal amount is required")
.positive("Goal amount must be a positive number")
.min(1, "Goal amount must be at least 1"),
goalAmount: yup
.number()
.typeError("Goal Amount is must be number")
.required('Goal amount is required')
.positive('Goal amount must be a positive number'),
closingDate: yup
.date()
@@ -71,6 +76,7 @@ const schema = yup.object().shape({
.min(new Date(), "Closing date cannot be in the past"),
holdingPeriod: yup.string().required("Holding period is required"),
holdingPeriodArabic: yup.string().required("Holding period is required"),
// minInvestmentAmount: yup
// .number()
@@ -93,6 +99,9 @@ const schema = yup.object().shape({
const IODetails = ({ enableNextTab, index, data }) => {
const params = useParams();
@@ -113,7 +122,7 @@ const IODetails = ({ enableNextTab, index, data }) => {
const id = params?.id;
// ======================[ Cotext Api ]
const { investmentType, sponser, IODetails, setIODetails } =
const { investmentType, sponser, setIOStatus, setIODetails, setIOloading } =
useContext(GlobalStateContext);
// ======================[ RTK Querry Api ]
@@ -124,8 +133,6 @@ const IODetails = ({ enableNextTab, index, data }) => {
error: IObyIDerror,
} = useGetIOByIdQuery(id, { skip: !id });
const [creatIO] = useCreateIOMutation();
const [updateIO] = useUpdateIOMutation();
@@ -147,22 +154,24 @@ const IODetails = ({ enableNextTab, index, data }) => {
});
const miniValue = data?.country?.map(
({ countryName, flagIcon, minInvestmentAmt, countryCode, id }, index) => {
({ countryName, flagIcon, minInvestmentAmt, countryCode, id, currency }, index) => {
return {
id:id,
country: countryName,
value: minInvestmentAmt,
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{
id:country_xid,
country: country?.countryName,
value: minInvestmentAmt,
value: removeTrailingZeros(minInvestmentAmt),
logo: country?.flagIcon,
curr: country?.countryCode,
}
@@ -170,12 +179,18 @@ const IODetails = ({ enableNextTab, index, data }) => {
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);
// ======================[ Validator filter ]
const {
control,
reset,
watch,
setValue,
handleSubmit,
formState: { errors },
@@ -184,6 +199,7 @@ const IODetails = ({ enableNextTab, index, data }) => {
});
useEffect(() => {
setIOloading(IObyIDisLoading)
setIODetails({
...IObyID?.data,
});
@@ -194,19 +210,23 @@ const IODetails = ({ enableNextTab, index, data }) => {
descriptionEnglish: IObyID?.data?.descriptionEnglish,
descriptionArabic: IObyID?.data?.descriptionArabic,
goalAmount: IObyID?.data?.goalAmount,
closingDate: IObyID?.data?.closingDate,
closingDate: formatDatee(IObyID?.data?.closingDate),
holdingPeriod: IObyID?.data?.holdingPeriod,
ISIN: IObyID?.data?.ISIN,
comment: IObyID?.data?.comment,
expectedReturn: IObyID?.data?.expectedReturn,
investmentType_xid: IObyID?.data?.investmentType_xid,
investmentType_xid: IObyID?.data?.investmentType_xid,
InvestmentDetails: IObyID?.data?.InvestmentDetails,
minInvestmentAmount: IObyID?.data?.minInvestmentAmount,
holdingPeriodArabic: IObyID?.data?.minInvestmentAmount,
expectedReturnArabic: IObyID?.data?.minInvestmentAmount,
});
}
}, [id, IObyID]);
// const minInvestmentById =
@@ -221,6 +241,8 @@ const IODetails = ({ enableNextTab, index, data }) => {
isRequired: true,
section: " ",
width: "49%",
maxLength:150,
helperText:`Maximum length should be 150 characters. You have entered ${watch()?.investmentNameEnglish?.length || 0} characters.`
},
{
label: "IO Name (Arabic)",
@@ -231,6 +253,8 @@ const IODetails = ({ enableNextTab, index, data }) => {
arabic: true,
section: " ",
width: "49%",
maxLength:150,
helperText:`Maximum length should be 150 characters. You have entered ${watch()?.investmentNameArabic?.length || 0} characters.`
},
{
label: "Description",
@@ -240,7 +264,8 @@ const IODetails = ({ enableNextTab, index, data }) => {
isRequired: true,
section: " ",
width: "49%",
maxLength:1000
maxLength:1000,
helperText:`Maximum length should be 1000 characters. You have entered ${watch()?.descriptionEnglish?.length || 0} characters.`
},
{
label: "Description (Arabic)",
@@ -251,8 +276,59 @@ const IODetails = ({ enableNextTab, index, data }) => {
arabic: true,
section: " ",
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",
placeHolder: "Select option",
@@ -265,7 +341,7 @@ const IODetails = ({ enableNextTab, index, data }) => {
value: IObyID?.data?.investmentType_xid,
},
{
label: "Sponsorer Name",
label: "Sponsor Name",
placeHolder: "Select option",
name: "sponserName",
type: "select",
@@ -288,32 +364,13 @@ const IODetails = ({ enableNextTab, index, data }) => {
{
label: "Closing Date",
name: "closingDate",
value: formatDate(IObyID?.data?.closingDate),
// value: "IObyID?.data?.closingDate",
type: "date",
isRequired: true,
section: " ",
width: "32.3%",
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,
dateValue:formatDatee(IObyID?.data?.closingDate),
// helperText: IObyID && `Current closing date is : ${formatDate(IObyID?.data?.closingDate)}`
},
{
label: "ISIN",
@@ -343,7 +400,6 @@ const IODetails = ({ enableNextTab, index, data }) => {
width: "100%",
isRequired: true,
options: investmentTypeOptions,
type: "table",
handleInputChange: handleInputChange,
value: values,
},
@@ -357,7 +413,8 @@ const IODetails = ({ enableNextTab, index, data }) => {
width: "100%",
options: investmentTypeOptions,
value: IObyID?.data?.comment,
maxLength:100
maxLength:100,
helperText:`Maximum length should be 100 characters. You have entered ${watch()?.comment?.length || 0} characters.`
},
];
//=======================[ Editor ]
@@ -567,6 +624,11 @@ const IODetails = ({ enableNextTab, index, data }) => {
toast({
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) {
setIsLoading(false);
@@ -592,8 +654,9 @@ const IODetails = ({ enableNextTab, index, data }) => {
};
return IObyIDisLoading ? (
<FullscreenLoaders />
<FullscreenLoaders height={'70vh'} />
) : (
<FormInputMain
p={0.1}
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 { 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 Pagination from '../../../Components/Pagination';
import DataTable from '../../../Components/DataTable/DataTable';
import NormalTable from '../../../Components/DataTable/NormalTable';
import CustomAlertDialog from '../../../Components/CustomAlertDialog';
import { formatDatee } from '../../../Components/FormField';
import { AddIcon } from '@chakra-ui/icons';
import AddIONav from './AddIONav';
const IONAVDetails = () => {
const { navDetails, setNavDetails, slideFromRight } =
const { navDetails, setNavDetails, IODetails } =
useContext(GlobalStateContext);
const firstField = useRef();
const { isOpen, onOpen, onClose } = useDisclosure();
const [searchTerm, setSearchTerm] = useState("");
const [isLoading, setIsLoading] = useState(true);
const [deleteAlert, setDeleteAlert] = useState(false);
@@ -16,6 +21,10 @@ const IONAVDetails = () => {
const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState("");
console.log(IODetails?.ioNAVHistory);
useEffect(() => {
// Simulate loading
@@ -29,50 +38,76 @@ const IONAVDetails = () => {
// Table setup
const tableHeadRow = [
"Sr.No",
"As On Date",
"IO NAV Value",
// "Sr.No",
"Valuation Date",
"NAV",
"Last NAV update",
"Investment Closed",
"Comments",
"Update by ",
"Update On",
// "Update On",
];
// Table filter
const filteredData = navDetails?.filter((item) => {
const name = item.updateBy;
const filteredData = IODetails?.ioNAVHistory?.filter((item) => {
const name = item.transactionType;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
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,
"Sr.No": index +1,
"As On Date": (
"Valuation Date": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
className="d-flex align-items-center web-text-small"
>
{item.date}
{formatDatee(item.transactionDate)}
</Text>
),
"IO NAV Value": (
"NAV": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
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>
),
"Comments": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
@@ -83,18 +118,20 @@ const IONAVDetails = () => {
),
"Update by ": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
justifyContent ={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
gap={2}
className="d-flex align-items-center web-text-small"
>
{item.updateBy}
<Avatar size='sm' name={"faisal"} src={null} />Faisal
</Text>
),
"Update On": (
<Text
justifyContent={slideFromRight ? "right" : "center"}
justifyContent={"center"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
@@ -103,7 +140,7 @@ const IONAVDetails = () => {
{item.updateOn}
</Text>
),
})));
}));
@@ -142,18 +179,21 @@ const IONAVDetails = () => {
onChange={(e) => setSearchTerm(e.target.value)}
/>
<HStack display={"flex"} alignItems={"center"}>
{/* <HStack display={"flex"} alignItems={"center"}>
<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>
</Box>
<DataTable
<NormalTable
centered={true}
emptyMessage={`We don't have any Sponers`}
tableHeadRow={tableHeadRow}
data={extractedArray}
setData={setExtractedArray}
isLoading={isLoading}
viewActionId={actionId}
setViewActionId={setActionId}
@@ -169,6 +209,15 @@ const IONAVDetails = () => {
alertHandler={handleDelete}
isLoading={isLoading}
/>
<AddIONav
isOpen={isOpen}
onClose={onClose}
firstField={firstField} />
</Box>
)
}

View File

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

View File

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

View File

@@ -38,16 +38,16 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
const toast = useToast();
const params = useParams();
// =====================[ variables ]
// =====================[ variables ]
const id = params?.id;
const { data, isLoading, error } = useGetKeyMeritsQuery(id, {
skip: !id,
});
// const { data, isLoading, error } = useGetKeyMeritsQuery(id, {
// skip: !id,
// });
console.log(data?.data);
const { IODetails} = useContext(GlobalStateContext);
const { keyMerits, setKeyMerits, slideFromRight } =
useContext(GlobalStateContext);
const firstField = useRef();
const [searchTerm, setSearchTerm] = useState("");
@@ -66,20 +66,9 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
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)
const name = item.meritsHeader;
const searchLower = searchTerm.toLowerCase();
@@ -111,7 +100,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
id: item.id,
"Sr.no": (
<Text
justifyContent={slideFromRight ? "right" : "left"}
justifyContent={"left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
@@ -122,7 +111,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
),
Title: (
<Text
justifyContent={slideFromRight ? "right" : "left"}
justifyContent={"left"}
as={"span"}
color={"teal.900"}
fontWeight={"500"}
@@ -224,7 +213,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
),
}));
return isLoading ? (
return false ? (
<FullscreenLoaders />
) : (
<Box>
@@ -241,7 +230,9 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
/> */}
<Box display={"flex"} gap={2} as="span">
<SetDisplayOrder data={filteredData} />
{filteredData?.length !== 0 &&<SetDisplayOrder data={filteredData} />}
<Button
leftIcon={<AddIcon />}
onClick={onOpen}
@@ -269,7 +260,7 @@ const KeyMerits = ({ enableNextTab, index, data: prepopData }) => {
isOpen={isEditOpen}
onClose={onEditCloseOpen}
firstField={firstField}
data={data?.data}
data={IODetails?.keyMerits}
/>
</Box>
<DataTable

View File

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

View File

@@ -11,13 +11,15 @@ import {
FormControl,
FormErrorMessage,
FormLabel,
Icon,
Image,
Input,
Stack,
Text,
useToast,
} from "@chakra-ui/react";
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 { yupResolver } from "@hookform/resolvers/yup";
import CustomAlertDialog from "../../Components/CustomAlertDialog";
@@ -27,6 +29,9 @@ import {
} from "../../Services/io.service";
import { useParams } from "react-router-dom";
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({
artifactName: yup.string().required("Artifact image name is required"),
@@ -41,8 +46,6 @@ const IOArtifactsAdd = ({
setActionId,
data,
}) => {
console.log(actionId);
console.log(data);
const params = useParams();
const id = params?.id;
const [file, setFile] = useState(null);
@@ -55,7 +58,8 @@ const IOArtifactsAdd = ({
const [updateImageArtifacts] = useUpdateImageArtifactsMutation();
const found = data?.find((item) => item?.id === actionId);
console.log(found);
const fileInputRef = useRef(null);
const {
control,
@@ -78,7 +82,6 @@ const IOArtifactsAdd = ({
}
}, [found, reset]);
console.log(watch());
const onSubmit = async (data) => {
setIsLoading(true);
@@ -86,29 +89,25 @@ const IOArtifactsAdd = ({
formData.append("artifactName", data.artifactName);
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 {
if (found) {
const res = await updateImageArtifacts({
data: formData,
id: found?.id,
});
console.log(res?.error);
if (res?.data?.statusCode === 200) {
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
reset();
setFile(null);
setIsLoading(false);
setAlert(false);
setPreview(null);
onClose();
reset({
artifactName: "",
artifactPathName: "",
});
}
if (res?.error) {
@@ -126,7 +125,10 @@ const IOArtifactsAdd = ({
toast({
render: () => <ToastBox message={res?.data?.message} />,
});
reset();
reset({
artifactName: "",
artifactPathName: "",
});
setFile(null);
setIsLoading(false);
setAlert(false);
@@ -153,6 +155,8 @@ const IOArtifactsAdd = ({
reader.readAsDataURL(file);
};
const handleSave = () => {
handleSubmit(onSubmit)();
};
@@ -169,6 +173,18 @@ const IOArtifactsAdd = ({
setActionId(false);
};
const handleRemove = () => {
setFile(null)
setPreview(null)
// Reset the file input value
if (fileInputRef.current) {
fileInputRef.current.value = "";
}
}
return (
<>
<Drawer
@@ -214,6 +230,7 @@ const IOArtifactsAdd = ({
fontSize={"sm"}
size={"sm"}
className="form-control"
ref={fileInputRef} // Set the ref here
/>
<FormErrorMessage fontSize={"xs"} fontWeight={500}>
{!preview &&
@@ -221,12 +238,23 @@ const IOArtifactsAdd = ({
errors.artifactPathName?.message}
</FormErrorMessage>
{preview && (
<Image
rounded={"md"}
src={preview}
alt="Image Preview"
mt={2}
/>
<>
<Image
rounded={"md"}
src={preview}
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 && (
<Image

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
import React, { useContext, useEffect, useState } from 'react';
import {
Box,
Button,
@@ -12,10 +13,93 @@ import {
ModalHeader,
ModalOverlay,
Text,
Textarea,
useToast,
} 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 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 (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
@@ -23,73 +107,92 @@ const AmountInvested = ({ isOpen, onClose }) => {
<ModalHeader fontSize={'md'}>Amount Invested</ModalHeader>
<ModalCloseButton />
<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>
<form onSubmit={handleSubmit(onSubmit)}>
<FormControl mb={"15px"} isInvalid={!!errors.transactionDate} isRequired>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
Date
</FormLabel>
<Input
type="date"
{...register('transactionDate')}
size="sm"
rounded={'sm'}
fontSize={"sm"}
focusBorderColor="forestGreen.300"
/>
{errors.transactionDate && <Text color="red.500">{errors.transactionDate.message}</Text>}
</FormControl>
<FormControl mb={"15px"} >
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount</FormLabel>
<Input
size="sm"
rounded={'sm'}
textAlign={'end'}
readOnly
value={"$ 100000"}
focusBorderColor="forestGreen.300"
fontSize={"sm"} placeholder="$00.00" />
</FormControl>
<FormControl mb={"15px"} isInvalid={!!errors.Total_Amount} isReadOnly>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount</FormLabel>
<Input
type="text"
value={formatCurrency(watch('Total_Amount'))}
size="sm"
rounded={'sm'}
textAlign={'end'}
focusBorderColor="forestGreen.300"
fontSize={"sm"}
readOnly
/>
{errors.Total_Amount && <Text color="red.500">{errors.Total_Amount.message}</Text>}
</FormControl>
<FormControl mb={"15px"} >
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount to invest</FormLabel>
<Input
size="sm"
rounded={'sm'}
textAlign={'end'}
focusBorderColor="forestGreen.300"
fontSize={"sm"} placeholder="$00.00" />
</FormControl>
<FormControl mb={"15px"} isInvalid={!!errors.amountInvested} isRequired>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount to invest</FormLabel>
<Input
type="number"
{...register('amountInvested')}
size="sm"
rounded={'sm'}
textAlign={'end'}
focusBorderColor="forestGreen.300"
fontSize={"sm"}
onChange={handleAmountChange}
/>
{errors.amountInvested && <Text color="red.500">{errors.amountInvested.message}</Text>}
</FormControl>
<FormControl mb={"15px"}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
IO Cash
</FormLabel>
<Input
size="sm"
rounded={'sm'}
placeholder="$00.00"
focusBorderColor="forestGreen.300"
fontSize={"sm"} />
</FormControl>
<FormControl mb={"15px"} isInvalid={!!errors.IoCash}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
IO Cash
</FormLabel>
<Input
type="text"
value={formatCurrency(watch('IoCash'))}
size="sm"
rounded={'sm'}
focusBorderColor="forestGreen.300"
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>
<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>
</Modal>
);

View File

@@ -2,6 +2,7 @@ import {
Box,
Button,
FormControl,
FormErrorMessage,
FormLabel,
Input,
Modal,
@@ -11,52 +12,168 @@ import {
ModalFooter,
ModalHeader,
ModalOverlay,
Select,
Stack,
Text,
Textarea,
useToast,
} 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 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 (
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalContent as={'form'} onSubmit={handleSubmit(onSubmit)} >
<ModalHeader fontSize={'md'}>Update iO NAV Transaction</ModalHeader>
<ModalCloseButton />
<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"} >
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>Amount</FormLabel>
<Input
size="sm"
rounded={'sm'}
textAlign={'end'}
focusBorderColor="forestGreen.300"
fontSize={"sm"} placeholder="$00.00" />
</FormControl>
<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 mb={"15px"}>
<FormLabel as={"label"} fontSize={"sm"} fontWeight={500}>
Comments
</FormLabel>
<Textarea
size="sm"
rounded={'sm'}
focusBorderColor="forestGreen.300"
fontSize={"sm"} placeholder="Write Comments" />
</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>
</ModalBody>
<ModalFooter>
<Button
@@ -68,10 +185,12 @@ const UpdateIONav = ({ isOpen, onClose }) => {
}}
size={'sm'}
rounded={"sm"}
type="submit"
isLoading={isLoading}
>
Save
</Button>
<Button
<Button
size={'sm'}
rounded={"sm"} mr={3} onClick={onClose}>
Close

View File

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

View File

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

View File

@@ -35,6 +35,7 @@ import IOArtifacts from "../CreateIO/IOArtifacts";
import IOCashDetails from "../CreateIO/IOCashDetails";
import IONAVDetails from "../CreateIO/IONAVDetails";
import { useGetIOprepopulateDataQuery } from "../../../Services/io.service";
import UnderConstruction from "../../UnderConstruction";
const ViewIOdata = () => {
@@ -44,17 +45,22 @@ const ViewIOdata = () => {
const { isOpen, onOpen, onClose } = useDisclosure();
const navigate = useNavigate();
const [isEditing, setIsEditing] = useState(false);
const { IODetails, setIODetails } = useContext(GlobalStateContext);
console.log(IODetails?.isInvestedAmount);
const tabs = [
{ label: "IO Details", content: <ViewIOdetails data={data?.data} /> },
{ label: "Investment documents", content: <InvestmentDocument data={data?.data} /> },
{ label: "Key merits", content: <KeyMerits data={data?.data} /> },
{ label: "IO artifacts", content: <IOArtifacts 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 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 (
@@ -74,7 +80,15 @@ const ViewIOdata = () => {
<Box display={'flex'} >
{tabs.map(({ label }, index) => (
<Tab
disabled={true}
px={3}
isDisabled={
index === 0 ||
index === 1 ||
index === 2 ||
index === 3 ||
index === 4 ?
false :
!IODetails?.isInvestedAmount}
key={index}
fontSize={"sm"}
_selected={{
@@ -89,7 +103,7 @@ const ViewIOdata = () => {
</TabList>
<TabPanels>
{tabs.map(({ content }, index) => (
<TabPanel key={index}>{content}</TabPanel>
<TabPanel key={index}>{content}</TabPanel>
))}
</TabPanels>
</Tabs>

View File

@@ -23,6 +23,7 @@ import {
Badge,
Box,
Icon,
HStack,
} from "@chakra-ui/react";
import header from "../../../assets/IOheader.png";
import { HiDotsVertical } from "react-icons/hi";
@@ -39,18 +40,17 @@ import Exit from "./HeaderModal/Exit";
import Cancle from "./HeaderModal/Cancle";
import { AddIcon } from "@chakra-ui/icons";
import { GrGallery } from "react-icons/gr";
import Loader01 from "../../../Components/Loaders/Loader01";
import { formatCurrency } from "../../../Components/CurrencyInput";
import { removeTrailingZeros } from "../../../Constants/Constants";
const ViewIOdataHeader = () => {
const ViewIOdataHeader = ({data, isLoading}) => {
const params = useParams();
const id = params?.id;
const { isOpen, onOpen, onClose } = useDisclosure();
const btnRef = useRef();
const { IODetails } = useContext(GlobalStateContext);
console.log(
"=================>>>>>",
IODetails?.artifactsImage?.[0]?.artifactPathName
);
const { IODetails, isIOloading } = useContext(GlobalStateContext);
const {
isOpen: isInvestmentOpen,
onOpen: onInvestmentOpen,
@@ -91,27 +91,100 @@ const ViewIOdataHeader = () => {
onOpen: onCancleOpen,
onClose: onCancleClose,
} = useDisclosure();
const bg = {
bg: "#fff",
};
const hover = {
textDecoration: "underline",
background: "#fff",
};
const style = {
fontSize: "0.875rem",
fontWeight: "400",
};
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 (
IODetails?.investmentNameEnglish ?
<Box
display={"flex"}
alignItems={"center"}
justifyContent={"start"}
justifyContent={"space-between"}
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"}
// bgGradient='linear(to-r, #caf5d8, #f5e8ca)'
// bgGradient='linear(to-r, #caf5d8, #d4a5a5)'
@@ -120,10 +193,12 @@ const ViewIOdataHeader = () => {
// bgGradient='linear(to-r, #ffd54f, #caf5d8)'
// bgGradient='linear(to-r, #caf5d8, #a8e6cf)'
boxShadow={"md"}
paddingRight={"10px"}
borderRadius={"10px"}
position={"relative"}
>
<HStack gap={8}>
<Box h={100} w={200} p={1.5}>
{/* <Image rounded={'md'} h={"100%"} src={ " https://tanami.betadelivery.com/" + IODetails?.ioName} alt={IODetails?.ioName}/> */}
{IODetails?.artifactsImage?.[0]?.artifactPathName ? (
@@ -152,24 +227,7 @@ const ViewIOdataHeader = () => {
</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}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO Name
@@ -183,7 +241,7 @@ const ViewIOdataHeader = () => {
<Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
Sponsorer Name
Sponsor Name
</Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{IODetails?.sponsor?.sponsorName
@@ -191,26 +249,38 @@ const ViewIOdataHeader = () => {
: "---"}
</Text>
</Box>
</HStack>
<HStack gap={8} me={20}>
<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
</Text>
<Badge
rounded={"sm"}
pt={0.5}
rounded={"full"}
pt={0}
pb={0.5}
ps={4}
pe={4}
textTransform={"none"}
variant={"solid"}
color={"#fff"}
// variant={"solid"}
colorScheme={
IODetails?.ioStatus?.statusAdmin === "Draft"
? "gray"
: IODetails?.ioStatus?.statusAdmin === "Processing"
? "yellow"
: IODetails?.ioStatus?.statusAdmin === "Open"
? "blue"
: IODetails?.ioStatus?.statusAdmin === "Pending"
? "purple"
: "forestGreen"
: IODetails?.ioStatus?.statusAdmin === "Closed"
? "green"
: IODetails?.ioStatus?.statusAdmin === "Exited"
? "red"
: IODetails?.ioStatus?.statusAdmin === "Canclled"
? "orange"
: "purple"
}
>
{IODetails?.ioStatus?.statusAdmin
@@ -218,31 +288,36 @@ const ViewIOdataHeader = () => {
: "---"}
</Badge>
</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"}
</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"}
</Text>
</Box>
<Box display={"flex"} flexDirection={"column"} gap={2}>
<Text as={"span"} fontSize={"xs"} color={"gray.500"} fontWeight={"500"}>
IO NAV
</Text>
<Text as={"span"} fontSize={"sm"} fontWeight={"500"}>
{IODetails?.currentValuation ? IODetails?.currentValuation : "00.00"}
</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 ? 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"}
{IODetails?.ioMVNAV ? formatCurrency(removeTrailingZeros(IODetails?.ioMVNAV)) : "00.00"}
</Text>
</Box>
</HStack>
<Box
position={"absolute"}
right={3}
@@ -272,113 +347,16 @@ const ViewIOdataHeader = () => {
>
Tansaction
</MenuItem>
<MenuItem onClick={onInvestmentOpen} className="border-bottom">
Amount Invested
</MenuItem>
<MenuItem onClick={onFeesOpen} className="border-bottom">
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>
{filteredMenu?.map(({id, title, onClickFunction})=><MenuItem key={id} onClick={onClickFunction} className="border-bottom">
{title}
</MenuItem>)}
</MenuList>
</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 */}
<AmountInvested isOpen={isInvestmentOpen} onClose={onInvestmentClose} />
@@ -395,11 +373,29 @@ const ViewIOdataHeader = () => {
/>
<UpdateIONav isOpen={isUpdateNavOpen} onClose={onUpdateNavClose} />
<UpdateIOStatus
status={IODetails?.nextStatus}
isOpen={isUpdateStatusOpen}
onClose={onUpdateStatusClose}
/>
</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 { yupResolver } from "@hookform/resolvers/yup";
import { formatDate } from "../../Master/Sponser/Sponsers";
import { formatCurrency } from "../../../Components/CurrencyInput";
import { removeTrailingZeros } from "../../../Constants/Constants";
const schema = yup.object().shape({
investmentNameEnglish: yup
@@ -71,7 +73,7 @@ const schema = yup.object().shape({
.positive("Expected return must be a positive number")
.min(0.01, "Expected return must be at least 0.01"),
});
const ViewIOdetails = () => {
const navigate = useNavigate();
const params = useParams();
@@ -104,31 +106,33 @@ const ViewIOdetails = () => {
investmentNameArabic: IObyID?.data?.investmentNameArabic,
descriptionEnglish: IObyID?.data?.descriptionEnglish,
descriptionArabic: IObyID?.data?.descriptionArabic,
goalAmount: IObyID?.data?.goalAmount,
goalAmount: removeTrailingZeros(IObyID?.data?.goalAmount),
closingDate: IObyID?.data?.closingDate,
holdingPeriod: IObyID?.data?.holdingPeriod,
ISIN: IObyID?.data?.ISIN,
comment: IObyID?.data?.comment,
expectedReturn: IObyID?.data?.expectedReturn,
investmentType_xid: IObyID?.data?.investmentType_xid,
investmentType_xid: IObyID?.data?.investmentType_xid,
InvestmentDetails: IObyID?.data?.InvestmentDetails,
minInvestmentAmount: IObyID?.data?.minInvestmentAmount,
});
}
}, [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{
id:id,
country: country?.countryName,
value: minInvestmentAmt,
value: removeTrailingZeros(minInvestmentAmt),
logo: country?.flagIcon,
curr: country?.countryCode,
curr: currencyCode,
}
})
console.log();
//=======================[ Editor ]
const formFields = [
{
@@ -177,6 +181,61 @@ const ViewIOdetails = () => {
section: " ",
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",
placeHolder: "Select option",
@@ -190,7 +249,7 @@ const ViewIOdetails = () => {
width: "32.3%",
},
{
label: "Sponsorer Name",
label: "Sponsor Name",
placeHolder: "Select option",
name: "sponsor_xid",
type: "select",
@@ -204,10 +263,11 @@ const ViewIOdetails = () => {
{
label: "Goal Amount",
placeHolder: "$00.00",
value: IObyID?.data?.goalAmount ? IObyID?.data?.goalAmount : "---",
value: IObyID?.data?.goalAmount ? formatCurrency(removeTrailingZeros(IObyID?.data?.goalAmount)) : "---",
name: "goalAmount",
type: "number",
isRequired: true,
arabic:true,
section: " ",
width: "32.3%",
},
@@ -222,28 +282,6 @@ const ViewIOdetails = () => {
section: " ",
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",
placeHolder: "$00.00",
@@ -274,7 +312,6 @@ const ViewIOdetails = () => {
section: " ",
width: "100%",
isRequired: true,
type: "table",
value: minInvestmentById,
},
@@ -299,7 +336,7 @@ const ViewIOdetails = () => {
}, {});
if (!IObyID?.data) {
return <FullscreenLoaders />;
return <FullscreenLoaders height={'70vh'} />;
}
return (

View File

@@ -68,7 +68,6 @@ const InvestorDetails = () => {
error,
} = useGetInvestorsQuery({ page: currentPage, size: pageSize });
console.log(investorDetails);
useEffect(() => {
// Simulate loading
@@ -82,7 +81,7 @@ const InvestorDetails = () => {
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
"Sr N/O",
// "Sr N/O",
"Client ID",
"First Name",
"Last Name",
@@ -109,7 +108,7 @@ const InvestorDetails = () => {
// ====================================================[Table Filter]================================================================
const filteredData = investorDetails?.data?.rows?.filter((item) => {
// 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 nameMatches = name?.toLowerCase().includes(searchLower);
@@ -125,7 +124,6 @@ const InvestorDetails = () => {
return nameMatches;
});
console.log(investorDetails);
const extractedArray = filteredData?.map((item) => ({
id: item?.id,
@@ -264,6 +262,9 @@ const InvestorDetails = () => {
onEditOpen();
};
console.log(investorDetails?.data?.totalItems);
return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
<Box bg="white.500">
@@ -365,12 +366,13 @@ const InvestorDetails = () => {
</Select>
<Pagination
isLoading={investorDetailsLoading}
isLoading={investorDetailsLoading}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalItems={investorDetails?.data?.totalItems}
/>
</HStack>
</HStack>

View File

@@ -34,7 +34,6 @@ const ProfileView = () => {
skip: !id,
});
console.log(data?.data);
const foundObject = data?.data;
@@ -238,6 +237,7 @@ const ProfileView = () => {
View Details
</Tab>
<Tab
isDisabled={true}
fontSize={"sm"}
_selected={{
color: "#004118",
@@ -247,6 +247,7 @@ const ProfileView = () => {
Portfolio
</Tab>
<Tab
isDisabled={true}
fontSize={"sm"}
_selected={{
color: "#004118",
@@ -256,6 +257,7 @@ const ProfileView = () => {
Transaction
</Tab>
<Tab
isDisabled={true}
fontSize={"sm"}
_selected={{
color: "#004118",

View File

@@ -22,8 +22,21 @@ import {
} from "@chakra-ui/react";
import GlobalStateContext from "../Contexts/GlobalStateContext";
import Cookies from "js-cookie";
import { validationSchema } from "../Validations/Validations";
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 [show, setShow] = useState(false);
@@ -36,43 +49,77 @@ const Login = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const [login] = useLoginMutation()
useEffect(() => {
if (isAuthenticate) {
navigate("/");
navigate("/sponser");
}
}, [navigate, isAuthenticate]);
const onSubmit = (value) => {
const onSubmit = async (value) => {
setIsLoading(true);
if (value.name === "admin@tanami.com" && value.password === "Admin@123") {
return setTimeout(() => {
// dispatch(loginUser(true));
try {
const res = await login(value).unwrap();
if (res?.statusCode === 200) {
toast({
render: () => (
<ToastBox status={"success"} message={res?.message} />
),
})
setIsLoading(false);
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);
navigate("/sponser");
reset();
}
} catch (err) {
if (err) {
toast({
render: () => (
<ToastBox status={"error"} message={"Invalid credentials"} />
<ToastBox status={"error"} message={err?.data?.message} />
),
});
reset();
navigate("/login");
}, 2000);
setIsLoading(false);
}
}
// 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 {
@@ -84,6 +131,9 @@ const Login = () => {
resolver: yupResolver(validationSchema),
});
console.log(errors);
return (
<div
style={{
@@ -138,18 +188,18 @@ const Login = () => {
</FormLabel>
<Input
{...register("name")}
{...register("emailAddress")}
focusBorderColor="green.500"
type="text"
name="name"
name="emailAddress"
variant="filled"
placeholder="Email"
size="lg"
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">
<TiWarning className="fw-bold fs-5 " /> {errors.name.message}
<TiWarning className="fw-bold fs-5 " /> {errors.emailAddress.message}
</span>
)}
</FormControl>
@@ -161,7 +211,7 @@ const Login = () => {
<InputGroup size="lg">
<Input
{...register("password")}
{...register("password_hash")}
className="web-text-medium"
focusBorderColor="green.500"
variant="filled"
@@ -181,9 +231,9 @@ const Login = () => {
</Button>
</InputRightElement>
</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">
<TiWarning className="fw-bold fs-5 " /> {errors.password.message}
<TiWarning className="fw-bold fs-5 " /> {errors.password_hash.message}
</span>
)}
</FormControl>

View File

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

View File

@@ -34,10 +34,11 @@ import { useGetAllExchangeRatesQuery } from "../../../Services/exchange.rate.ser
import { TABLE_PAGINATION } from "../../../Constants/Paginations";
import NormalTable from "../../../Components/DataTable/NormalTable";
import { MdHistory } from "react-icons/md";
import { formatCurrency } from "../../../Components/CurrencyInput";
const ExchangeRate = () => {
const toast = useToast();
const navigate = useNavigate()
const navigate = useNavigate();
const { slideFromRight, rateExchange, setRateExchange } =
useContext(GlobalStateContext);
const [searchTerm, setSearchTerm] = useState("");
@@ -46,47 +47,18 @@ const ExchangeRate = () => {
const [actionId, setActionId] = useState(false);
const [mouseEntered, setMouseEntered] = useState(false);
const [mouseEnteredId, setMouseEnteredId] = useState("");
const [history, setHistory] = useState([]);
// ===============================[ Paginations ]
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(1);
const {
data,
isLoading: isExchangeRateLoading,
errors,
} = useGetAllExchangeRatesQuery({ page: currentPage, size: pageSize })
const {
data,
isLoading: isExchangeRateLoading,
errors,
} = useGetAllExchangeRatesQuery({ page: currentPage, size: pageSize });
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;
});
console.log(data?.data);
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
@@ -129,7 +101,7 @@ const ExchangeRate = () => {
fontWeight={"600"}
className="d-flex align-items-center fw- web-text-small"
>
{item?.toCurrency?.currencyCode}
{item?.toCurrency?.currencyCode}
</Text>
),
"Effective from": (
@@ -145,13 +117,13 @@ const ExchangeRate = () => {
),
Rate: (
<Text
justifyContent={slideFromRight ? "right" : "left"}
as={"span"}
justifyContent={"left"}
as={"span"}
color={"gray.600"}
fontWeight={"600"}
className="d-flex align-items-center web-text-small"
>
{item.rate}
{formatCurrency(item.rate)}
</Text>
),
@@ -163,34 +135,32 @@ const ExchangeRate = () => {
<EditExchangeRate
setIsLoading={setIsLoading}
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'}
alignItems={'center'}
gap={1}
>
<MdHistory />
</Button>
</Tooltip>
<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"}
alignItems={"center"}
gap={1}
>
<MdHistory />
</Button>
</Tooltip>
</Box>
),
}));
@@ -214,7 +184,7 @@ const ExchangeRate = () => {
<HStack
display={"flex"}
justifyContent={"space-between"}
ps={1}
ps={1}
pe={1}
pb={4}
pt={4}
@@ -230,8 +200,6 @@ const ExchangeRate = () => {
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</HStack>
</Box>

View File

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

View File

@@ -12,13 +12,18 @@ import ToastBox from "../../../Components/ToastBox";
import FullscreenLoaders from "../../../Components/Loaders/FullscreenLoaders";
import CustomAlertDialog from "../../../Components/CustomAlertDialog";
import SwitchButton from "../../../Components/SwitchButton";
import DummyComponent from "../../../Components/DummyComponent";
// ======================= [validation] =========================
export const addSponser = yup.object().shape({
sponsorName: yup.string().required("Sponser name is required"),
sponsorNameArabic: yup.string().required("Sponser name is required"),
email: yup.string().email("Must be a valid email").notRequired(),
sponsorName: yup.
string()
.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) {
// if (!value) {
// return true; // Allow if the field is empty
@@ -61,6 +66,7 @@ const AddSponser = () => {
const {
control,
watch,
handleSubmit,
formState: { errors },
reset,
@@ -78,9 +84,15 @@ const AddSponser = () => {
sponsorNameArabic: sponserByIdData?.data?.sponsorNameArabic,
email: sponserByIdData?.data?.email,
});
setIsSwitchOn(sponserByIdData?.data?.isActive)
console.log(sponserByIdData?.data?.isActive);
}
}, [sponserByIdData, reset]);
// console.log(isSwitchOn);
if (false) {
return <FullscreenLoaders />;
}
@@ -109,15 +121,15 @@ const AddSponser = () => {
setIsLoadingBtn(false);
setAlert(false);
navigate("/sponser");
} else {
} else if(response?.error?.status === 400) {
toast({
render: () => (
<ToastBox message={"Something Went Wrong"} status={"error"} />
<ToastBox message={response?.error?.data?.message} status={"error"} />
),
});
setIsLoadingBtn(false);
navigate("/sponser");
setAlert(false)
}
});
} catch (error) {
@@ -148,7 +160,7 @@ const AddSponser = () => {
});
setIsLoadingBtn(false);
navigate("/sponser");
setAlert(false)
}
});
} catch (error) {
@@ -164,24 +176,26 @@ const AddSponser = () => {
const formFields = [
{
label: "Sponser name (English)",
label: "Sponsor name (English)",
placeHolder: " ",
name: "sponsorName",
type: "text",
isRequired: true,
section: "Add Details",
maxLength:50
section: "",
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",
placeHolder: " ",
type: "text",
isRequired: true,
section: "Add Details",
section: "",
arabic: 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",
@@ -189,7 +203,7 @@ const AddSponser = () => {
placeHolder: " ",
type: "email",
// isRequired: true,
section: "Add Details",
section: "",
},
];
@@ -197,23 +211,25 @@ const AddSponser = () => {
const formEditFields = [
{
label: "Sponser name",
label: "Sponsor name",
placeHolder: " ",
name: "sponsorName",
type: "text",
isRequired: true,
section: "Add Details",
maxLength:50
section: "",
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",
placeHolder: " ",
type: "text",
isRequired: true,
section: "Add Details",
section: "",
arabic: true,
maxLength:255
maxLength:55,
helperText:`Maximum length should be 55 characters. You have entered ${watch()?.sponsorNameArabic?.length || 0} characters.`
},
{
label: "Email adress",
@@ -221,7 +237,7 @@ const AddSponser = () => {
placeHolder: " ",
type: "email",
// isRequired: true,
section: "Add Details",
section: "",
},
];
@@ -257,14 +273,16 @@ const AddSponser = () => {
};
return (
isLoading?<FullscreenLoaders/>:
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={14}>
{/* ===================== [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} />
</Box>
{/* ====================== [Form Input] ====================== */}
<FormInputMain
@@ -284,6 +302,8 @@ const AddSponser = () => {
message={"Are you sure you want to add this?"}
isLoading={isLoadingBtn}
/>
{/* <DummyComponent /> */}
</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 day = String(d.getDate()).padStart(2, '0');
return `${day}-${month}-${year}`;
return `${day}/${month}/${year}`;
};
const Sponser = () => {
@@ -158,14 +158,28 @@ const Sponser = () => {
setIsLoading(true);
try {
const response = await deleteSponser(actionId);
console.log(response);
setIsLoading(false);
setDeleteAlert(false);
console.log(response?.data);
if(response?.error?.data?.code === 400){
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) {}
};
console.log(isSponserLoading);
return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"} pb={38}>
<Box bg="white.500">

View File

@@ -13,7 +13,17 @@ const SplashScreen = () => {
gap={10}
>
<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>
)
}

View File

@@ -3,18 +3,18 @@ import React from 'react'
// import noInternet from "../assets/Error.svg"
import robot from "../assets/robot.png"
const UnderConstruction = ({title}) => {
const UnderConstruction = ({title, h}) => {
return (
<Box
h={'100vh'}
h={h?h:'100vh'}
display={'flex'}
justifyContent={'center'}
alignItems={'center'}
flexDirection={'column'}
gap={8}
>
<Image src={robot} w={"171px"} />
{/* <Text color={'green.800'} as={'span'} fontSize={'small'}>The requested URL was not found on this server.</Text> */}
<Image src={robot} w={200} />
<Text color={'green.800'} as={'span'} mt={4} fontSize={'small'}>🚧 Building Something Amazing Just for You! 🚧</Text>
</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 { TbBrandMedium, TbChartHistogram, TbReportMoney } from "react-icons/tb";
import { TbBrandMedium, TbChartHistogram, TbLayoutDashboard, TbReportMoney } from "react-icons/tb";
import {
RiBankLine,
RiFileUserLine,
@@ -26,6 +26,12 @@ import { LiaCrownSolid } from "react-icons/lia";
import { PiCrownDuotone } from "react-icons/pi";
export const nav = [
// {
// title: "Dashboard",
// type: "single",
// path: "/",
// Icon: TbLayoutDashboard,
// },
{
title: "MASTER MENU",
type: "title",

View File

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

View File

@@ -1,12 +1,13 @@
// io.service.js
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({
reducerPath: "ioService",
baseQuery: fetchBaseQuery({ baseUrl }),
baseQuery: baseQuery,
tagTypes: ["getKeyMerits"],
endpoints: (builder) => ({
// =====[get]

View File

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

View File

@@ -1,14 +1,16 @@
// investorDetails.service.js
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
export const bankDetails = createApi({
reducerPath: "bankDetails",
baseQuery: fetchBaseQuery({ baseUrl }),
tagTypes: [],
baseQuery: baseQuery,
tagTypes: ["getBank"],
endpoints: (builder) => ({
getBank: builder.query({
@@ -25,7 +27,7 @@ export const bankDetails = createApi({
method: "PATCH",
body: data,
}),
invalidatesTags: ["getBankDetails"],
invalidatesTags: ["getBank"],
}),
}),

View File

@@ -1,24 +1,37 @@
// investorDetails.service.js
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
export const contact = createApi({
reducerPath: "contact",
baseQuery: fetchBaseQuery({ baseUrl }),
tagTypes: [],
baseQuery: baseQuery,
tagTypes: ["getContact"],
endpoints: (builder) => ({
getContact: builder.query({
query: ({ page, size }) =>
`/contactDetails/admin/?page=${page}&size=${size}`,
query: () =>
`/contactDetails/admin`,
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 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

@@ -1,13 +1,14 @@
// exchangeRate.service.js
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
export const exchangeRate = createApi({
reducerPath: "exchangeRate",
baseQuery: fetchBaseQuery({ baseUrl }),
baseQuery: baseQuery,
tagTypes: ["getAllExchangeRate", "getExchangeById"],
endpoints: (builder) => ({

View File

@@ -1,12 +1,13 @@
// io.service.js
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({
reducerPath: "ioService",
baseQuery: fetchBaseQuery({ baseUrl }),
baseQuery: baseQuery,
tagTypes: ["getInvestmentDocuments"],

View File

@@ -1,13 +1,14 @@
// investmentType.service.js
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
export const investmentType = createApi({
reducerPath: "investmentType",
baseQuery: fetchBaseQuery({ baseUrl }),
baseQuery: baseQuery,
tagTypes: ["getInvestmentType", "getInvestmentTypeID"],
endpoints: (builder) => ({

View File

@@ -1,13 +1,14 @@
// investorDetails.service.js
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
export const investorDetails = createApi({
reducerPath: "investorDetails",
baseQuery: fetchBaseQuery({ baseUrl }),
baseQuery: baseQuery,
tagTypes: [],
endpoints: (builder) => ({

View File

@@ -1,12 +1,13 @@
// investorTransaction.service.js
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
export const investorTransaction = createApi({
reducerPath: "investorTransaction",
baseQuery: fetchBaseQuery({ baseUrl }),
baseQuery: baseQuery,
tagTypes: [],
endpoints: (builder) => ({
getTransactions: builder.query({

View File

@@ -1,12 +1,13 @@
// io.service.js
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
export const ioService = createApi({
reducerPath: "ioService",
baseQuery: fetchBaseQuery({ baseUrl }),
baseQuery: baseQuery,
tagTypes: [
"prePopulate",
"getIO",
@@ -49,7 +50,7 @@ export const ioService = createApi({
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById"],
invalidatesTags: ["getIOById", "getIO","prePopulate"],
}),
// =====[Key Merits]
@@ -57,6 +58,7 @@ export const ioService = createApi({
query: (id) => `/io/admin/key-merits/${id}`,
providesTags: ["getKeyMerits"],
}),
createKeyMerits: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/key-merits/${id}`,
@@ -64,7 +66,7 @@ export const ioService = createApi({
body: data,
// No need to manually set 'Content-Type'
}),
invalidatesTags: ["getKeyMerits"],
invalidatesTags: ["getIOById"],
}),
deleteKeyMerits: builder.mutation({
@@ -72,15 +74,16 @@ export const ioService = createApi({
url: `/io/admin/key-merits/hard-delete/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getKeyMerits"],
invalidatesTags: ["getIOById"],
}),
updateKeyMerits: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/key-merits/byId/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getKeyMerits"],
invalidatesTags: ["getIOById"],
}),
// =====[getIODocument]
@@ -91,7 +94,7 @@ export const ioService = createApi({
body: data,
}),
invalidatesTags: ["getInvestmentDocuments"],
invalidatesTags: ["getIOById"],
}),
updateInvestmentDocuments: builder.mutation({
@@ -100,7 +103,7 @@ export const ioService = createApi({
method: "PATCH",
body: data,
}),
invalidatesTags: ["getInvestmentDocuments"],
invalidatesTags: ["getIOById"],
}),
getInvestmentDocuments: builder.query({
@@ -113,7 +116,7 @@ export const ioService = createApi({
url: `/io/admin/document/hard-delete/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getInvestmentDocuments"],
invalidatesTags: ["getIOById"],
}),
// =====[Artifacts]
@@ -125,36 +128,36 @@ export const ioService = createApi({
// =====[createImageArtifacts]
createImageArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/artifact/artifactImage/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
updateImageArtifacts: builder.mutation({
// =====[createImageArtifacts]
createImageArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/artifact/image/${id}`,
method: "PATCH",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
// =====[createVideoArtifacts]
createVideoArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/artifact/artifactVideo/${id}`,
url: `/io/admin/artifact/image/${id}`,
method: "POST",
body: data,
}),
invalidatesTags: ["getIOById"],
}),
updateImageArtifacts: builder.mutation({
query: ({ data, 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",
body: data,
}),
@@ -162,10 +165,9 @@ export const ioService = createApi({
invalidatesTags: ["getIOById"],
}),
deleteVideoArtifacts: builder.mutation({
query: (id) => ({
url: `/io/artifact/video/${id}`,
url: `/io/admin/artifact/video/byId/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getIOById"],
@@ -173,17 +175,15 @@ export const ioService = createApi({
deleteImageArtifacts: builder.mutation({
query: (id) => ({
url: `/io/artifact/image/${id}`,
url: `/io/admin/artifact/image/byId/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getIOById"],
}),
updateVideoArtifacts: builder.mutation({
query: ({ data, id }) => ({
url: `/io/artifact/video/${id}`,
url: `/io/admin/artifact/video/byId/${id}`,
method: "PATCH",
body: data,
}),
@@ -198,7 +198,7 @@ export const ioService = createApi({
}),
invalidatesTags: ["getIOById"],
}),
updateStatusIo: builder.mutation({
query: ({ data, id }) => ({
url: `/io/admin/update-status/${id}`,
@@ -208,6 +208,44 @@ export const ioService = createApi({
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"],
}),
@@ -250,6 +288,16 @@ export const {
useSetDisplayOrderMutation,
useCreateIoCashMutation,
useCreateIoNavMutation,
useUpdateStatusIoMutation
useUpdateStatusIoMutation,
useAmountIvestmentMutation,
} = ioService;

View File

@@ -1,17 +1,23 @@
//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";
// 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}`
// Define a service using a base URL and expected endpoints
export const sponserMaster = createApi({
reducerPath: "sponserMaster",
baseQuery: fetchBaseQuery({ baseUrl: baseUrl }),
tagTypes: ["getSponser"],
baseQuery: baseQuery,
tagTypes: ["getSponser", "prePopulate"],
endpoints: (builder) => ({
@@ -28,7 +34,6 @@ export const sponserMaster = createApi({
getActiveSponserMaster: builder.query({
query: () => `/sponsor/admin/active`,
providesTags: ["getSponser"],
}),
getSponserMasterActive: builder.query({
@@ -40,7 +45,6 @@ export const sponserMaster = createApi({
getSponserById: builder.query({
query: (id) => `/sponsor/admin/${id}`,
providesTags: ["getSponser"],
}),
// ========[Toggle Status]========
@@ -61,7 +65,7 @@ export const sponserMaster = createApi({
method: "POST",
body: data,
}),
invalidatesTags: ["getSponser"],
invalidatesTags: ["getSponser","prePopulate"],
}),
// ========[Update Sponser]========

View File

@@ -0,0 +1,107 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
// Define a base query function with RTK Query
// export const baseQuery = fetchBaseQuery({
// baseUrl: 'https://admin.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: 'https://admin.tanami.betadelivery.com/api/v1',
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: 'https://admin.tanami.betadelivery.com/api/v1',
})({
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: 'https://admin.tanami.betadelivery.com/api/v1',
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 { investorDetails } from "../Services/investor.details.service";
import { investorTransaction } from "../Services/investor.transaction.service";
import { api } from "../Services/api.service";
import { keyMerits } from "../Services/Key.merits.service";
// import { api } from "../Services/api.service";
// import { keyMerits } from "../Services/Key.merits.service";
import { bankDetails } from "../Services/bank.details.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({
reducer: {
[apiSlice.reducerPath]: apiSlice.reducer,
[sponserMaster.reducerPath]: sponserMaster.reducer,
[investmentType.reducerPath]: investmentType.reducer,
[exchangeRate.reducerPath]: exchangeRate.reducer,
@@ -21,14 +24,16 @@ export const store = configureStore({
[investorTransaction.reducerPath]: investorTransaction.reducer,
[bankDetails.reducerPath]: bankDetails.reducer,
[contact.reducerPath]: contact.reducer,
[depositRequest.reducerPath]: depositRequest.reducer,
// Add other reducers as needed
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: {
extraArgument: api, // Pass Axios instance as extra argument
extraArgument: baseQuery, // Pass Axios instance as extra argument
},
}).concat(
apiSlice.middleware,
sponserMaster.middleware,
investmentType.middleware,
exchangeRate.middleware,
@@ -37,6 +42,7 @@ export const store = configureStore({
investorTransaction.middleware,
bankDetails.middleware,
contact.middleware,
depositRequest.middleware,
),
});

View File

@@ -1,7 +1,7 @@
import * as Yup from "yup";
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"),
});

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

View File

@@ -1,6 +1,9 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.bundle.min';
// import { persistor, store } from "./Redux/Store.js";
import { Provider } from "react-redux";