diff --git a/package-lock.json b/package-lock.json index 41168e3..1f7821c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "react-dom": "^18.2.0", "react-hook-form": "^7.51.3", "react-icons": "^5.1.0", - "react-quill": "^0.0.2", + "react-quill": "^2.0.0", "react-redux": "^9.1.1", "react-router-dom": "^6.22.3", "redux-persist": "^6.0.0", @@ -2757,6 +2757,15 @@ "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", "license": "MIT" }, + "node_modules/@types/quill": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz", + "integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==", + "license": "MIT", + "dependencies": { + "parchment": "^1.1.2" + } + }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", @@ -3182,7 +3191,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -3255,6 +3263,15 @@ "pnpm": ">=8" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/codepage": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", @@ -3460,6 +3477,26 @@ } } }, + "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==", + "license": "MIT", + "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", @@ -3471,7 +3508,6 @@ "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, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -3489,7 +3525,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -3617,7 +3652,6 @@ "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, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" @@ -3630,7 +3664,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4111,10 +4144,16 @@ "node": ">=0.10.0" } }, - "node_modules/eventemitter2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", + "node_modules/eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, "node_modules/fast-deep-equal": { @@ -4125,10 +4164,10 @@ "license": "MIT" }, "node_modules/fast-diff": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.0.1.tgz", - "integrity": "sha512-anEzYJ8VOA5iAMjDOVMTVMrUOXveDTMMk5x0E4p0nJ3VPoIOolF51AqYyE+UD0QIyggUwqppqH7XVA9lF3fdaQ==", - "license": "Apache 2.0" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", + "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==", + "license": "Apache-2.0" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", @@ -4371,7 +4410,6 @@ "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, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4381,7 +4419,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -4489,7 +4526,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" @@ -4528,7 +4564,6 @@ "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, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -4541,7 +4576,6 @@ "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, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4554,7 +4588,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4567,7 +4600,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -4689,6 +4721,22 @@ "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==", + "license": "MIT", + "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", @@ -4806,7 +4854,6 @@ "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, "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" @@ -4926,7 +4973,6 @@ "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, "license": "MIT", "dependencies": { "call-bind": "^1.0.2", @@ -5223,13 +5269,9 @@ } }, "node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", - "engines": [ - "node", - "rhino" - ], + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, "node_modules/lodash.merge": { @@ -5351,11 +5393,26 @@ "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==", + "license": "MIT", + "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, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5492,6 +5549,12 @@ "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==", + "license": "BSD-3-Clause" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5676,15 +5739,29 @@ ], "license": "MIT" }, - "node_modules/quilljs": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/quilljs/-/quilljs-0.18.1.tgz", - "integrity": "sha512-VKaO7GNehgnH4LlFPx5ZAl+KFDoRVtboY0I6UUbYXUsPHP8kR80Tg/CFEYqrqrpCOGQr4OQ5Tjm813gV1DUyQw==", + "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==", "license": "BSD-3-Clause", "dependencies": { - "eventemitter2": "~0.4.13", - "lodash": "~2.4.1", - "rich-text": "~1.0.2" + "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==", + "license": "MIT", + "dependencies": { + "deep-equal": "^1.0.1", + "extend": "^3.0.2", + "fast-diff": "1.1.2" }, "engines": { "node": ">=0.10" @@ -5876,18 +5953,18 @@ "license": "MIT" }, "node_modules/react-quill": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/react-quill/-/react-quill-0.0.2.tgz", - "integrity": "sha512-PeiHXZ63Sumh41OdovBQExXJH7B4UsJpyCW8CtRvXrNBa2RJXdciaJvTeb0x6pYQfqkoCYPT5EbUvEr0Z1tohg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz", + "integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==", "license": "MIT", "dependencies": { - "quilljs": "^0.18.1" - }, - "engines": { - "node": ">= 0.8.x" + "@types/quill": "^1.3.10", + "lodash": "^4.17.4", + "quill": "^1.3.7" }, "peerDependencies": { - "react": ">=0.11.0" + "react": "^16 || ^17 || ^18", + "react-dom": "^16 || ^17 || ^18" } }, "node_modules/react-redux": { @@ -6085,7 +6162,6 @@ "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, "license": "MIT", "dependencies": { "call-bind": "^1.0.6", @@ -6143,18 +6219,6 @@ "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==", - "license": "MIT", - "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", @@ -6292,7 +6356,6 @@ "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, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -6310,7 +6373,6 @@ "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, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", diff --git a/package.json b/package.json index 1cab514..4a00935 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "react-dom": "^18.2.0", "react-hook-form": "^7.51.3", "react-icons": "^5.1.0", - "react-quill": "^0.0.2", + "react-quill": "^2.0.0", "react-redux": "^9.1.1", "react-router-dom": "^6.22.3", "redux-persist": "^6.0.0", diff --git a/src/Components/CurrencyInput.jsx b/src/Components/CurrencyInput.jsx index c972aee..573c341 100644 --- a/src/Components/CurrencyInput.jsx +++ b/src/Components/CurrencyInput.jsx @@ -1,36 +1,32 @@ import React, { forwardRef } from 'react'; import { Input } from "@chakra-ui/react"; -// export const formatCurrency = (value) => { -// if (!value) return ''; -// const [integer, decimal] = value.split('.'); -// const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ','); -// return decimal ? `${formattedInteger}.${decimal}` : formattedInteger; -// }; - export const formatCurrency = (value) => { - if (value === undefined || value === null) return ''; // Handle undefined or null values - const [integer, decimal] = String(value).split('.'); // Convert value to string before splitting + if (value === undefined || value === null) return ''; + const [integer, decimal] = String(value).split('.'); const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ','); - return decimal ? `${formattedInteger}.${decimal}` : formattedInteger; + return decimal !== undefined ? `${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, ''); + value = value.replace(/[^0-9.]/g, ''); // Ensure only one decimal point - const parts = value?.split('.'); + const parts = value.split('.'); if (parts.length > 2) { - value = parts[0] + '.' + parts?.slice(1)?.join(''); + value = parts[0] + '.' + parts.slice(1).join(''); } - onChange(value); // Pass the raw value to parent or use it directly + // Restrict to two decimal places + if (parts[1]?.length > 2) { + value = parts[0] + '.' + parts[1].slice(0, 2); + } + + onChange(value); // Pass the raw value to parent }; return ( @@ -45,3 +41,50 @@ const CurrencyInput = forwardRef(({ value, onChange, ...props }, ref) => { }); export default CurrencyInput; + + + + +// import React, { forwardRef } from 'react'; +// import { Input } from "@chakra-ui/react"; + +// export const formatCurrency = (value) => { +// if (value === undefined || value === null) return ''; // Handle undefined or null values +// const [integer, decimal] = String(value).split('.'); // Convert value to string before splitting +// const formattedInteger = integer.replace(/\B(?=(\d{3})+(?!\d))/g, ','); +// return decimal ? `${formattedInteger}.${decimal}` : formattedInteger; +// }; + +// const CurrencyInput = forwardRef(({ value, onChange, ...props }, ref) => { + +// const handleChange = (event) => { +// let { value } = event?.target; + +// // Remove non-numeric characters except decimal point +// value = value?.replace(/[^0-9.]/g, ''); + +// // Ensure only one decimal point and restrict to two decimal places +// const parts = value?.split('.'); +// if (parts.length > 2) { +// value = parts[0] + '.' + parts?.slice(1)?.join(''); +// } + +// if (parts[1]?.length > 2) { +// value = parts[0] + '.' + parts[1]?.slice(0, 2); +// } + +// onChange(value); // Pass the raw value to parent or use it directly +// }; + +// return ( +// +// ); +// }); + +// export default CurrencyInput; diff --git a/src/Components/FormField.jsx b/src/Components/FormField.jsx index abf6817..c18c14f 100644 --- a/src/Components/FormField.jsx +++ b/src/Components/FormField.jsx @@ -477,8 +477,8 @@ const FormField = ({ placeholder={placeHolder ? placeHolder : label} textAlign={arabic ? "right" : align ? align : "left"} _placeholder={{ fontSize: "sm" }} - min={type === "date" ? today : undefined} - maxLength={maxLength} + // min={type === "date" ? today : undefined} + // maxLength={maxLength} // defaultValue={type === "date" && "2023-07-26" : undefined} // defaultValue={value} // value={dateValue} diff --git a/src/Constants/Constants.js b/src/Constants/Constants.js index 510695e..9654fc9 100644 --- a/src/Constants/Constants.js +++ b/src/Constants/Constants.js @@ -1,5 +1,6 @@ import dns from "node:dns" +import * as XLSX from 'xlsx'; export const generateSerialNumber = (index, currentPage, pageSize) => { @@ -138,4 +139,54 @@ export function formatDate(dateString) { const options = { year: 'numeric', month: 'short', day: 'numeric' }; const date = new Date(dateString); return date.toLocaleDateString('en-US', options); -} \ No newline at end of file +} + + +export const exportToExcel = (data, customHeaders, fileName = 'exported-data.xlsx') => { + // Map your data to include only the fields that match your custom headers + const mappedData = data.map(item => + customHeaders.map(header => item[header.key] || '') + ); + + // Prepend the headers row + const sheetData = [customHeaders.map(header => header.label), ...mappedData]; + + // Create a worksheet from the data array + const worksheet = XLSX.utils.aoa_to_sheet(sheetData); + + // Apply styles to header cells + customHeaders.forEach((header, index) => { + const cellAddress = XLSX.utils.encode_cell({ r: 0, c: index }); // r: row, c: column + if (!worksheet[cellAddress]) return; // Skip if cell doesn't exist + + worksheet[cellAddress].s = { + fill: { + fgColor: { rgb: "FFFF00" } // Set header background color (Yellow in this case) + }, + font: { + bold: true, // Make header text bold + color: { rgb: "000000" } // Set header text color (Black in this case) + } + }; + }); + + // Create a new workbook and append the worksheet + const workbook = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1'); + + // Generate a buffer from the workbook + const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' }); + + // Create a Blob object from the buffer + const dataBlob = new Blob([excelBuffer], { type: 'application/octet-stream' }); + + // Create a link element to trigger the download + const link = document.createElement('a'); + link.href = URL.createObjectURL(dataBlob); + link.download = fileName; + + // Append the link to the document body, trigger the download, and remove the link + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); +}; \ No newline at end of file diff --git a/src/Pages/Deposit/DepositRequest/DepositRequest.jsx b/src/Pages/Deposit/DepositRequest/DepositRequest.jsx index 032fd56..27c416d 100644 --- a/src/Pages/Deposit/DepositRequest/DepositRequest.jsx +++ b/src/Pages/Deposit/DepositRequest/DepositRequest.jsx @@ -161,7 +161,7 @@ const DepositRequest = () => { ), "First Name": ( - + {item?.firstName} diff --git a/src/Pages/IO_Management/CreateIO/AddIONav.jsx b/src/Pages/IO_Management/CreateIO/AddIONav.jsx index 98acdf5..84d91c0 100644 --- a/src/Pages/IO_Management/CreateIO/AddIONav.jsx +++ b/src/Pages/IO_Management/CreateIO/AddIONav.jsx @@ -11,10 +11,13 @@ import { FormControl, FormErrorMessage, FormLabel, + HStack, Input, Select, Stack, + Text, Textarea, + VStack, useToast, } from "@chakra-ui/react"; import * as yup from "yup"; @@ -123,7 +126,15 @@ import { formatDatee } from "../../../Components/FormField"; -const today = formatDatee(new Date(), 'yyyy-MM-dd'); +const today = formatDatee(new Date(), 'yyyy-MM-dd'); + +function calculatePercentage(newNav, currNav) { + const per = (newNav - currNav) / currNav * 100 + return per.toFixed(2) +} + + +console.log(calculatePercentage(1092500, 976070)); @@ -162,7 +173,7 @@ const today = formatDatee(new Date(), 'yyyy-MM-dd'); - Transaction Amount + New NAV - + + + + + Current nav + {parseFloat(IODetails?.ioNAV || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} + + + + + Live return % + {calculatePercentage(watch()?.transactionAmount||IODetails?.ioNAV,IODetails?.ioNAV)} + + + diff --git a/src/Pages/IO_Management/CreateIO/IODetails.jsx b/src/Pages/IO_Management/CreateIO/IODetails.jsx index 2983b65..ed02983 100644 --- a/src/Pages/IO_Management/CreateIO/IODetails.jsx +++ b/src/Pages/IO_Management/CreateIO/IODetails.jsx @@ -69,7 +69,6 @@ const schema = yup.object().shape({ .typeError("Goal Amount is must be number") .required('Goal amount is required') .positive('Goal amount must be a positive number'), - closingDate: yup .date() .notRequired("Closing date is required") @@ -98,6 +97,9 @@ const schema = yup.object().shape({ }); + + + const IODetails = ({ enableNextTab, index, data }) => { @@ -166,21 +168,90 @@ const IODetails = ({ enableNextTab, index, data }) => { } ); + console.log(IObyID?.data?.minInvestmentAmt); - const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, country_xid,id })=>{ + + const minInvestmentById = IObyID?.data?.minInvestmentAmt?.map(({minInvestmentAmt, country, currencyCode, country_xid,id })=>{ + console.log(currencyCode); return{ _id:id, id:country_xid, country: country?.countryName, value: removeTrailingZeros(minInvestmentAmt), logo: country?.flagIcon, - curr: country?.countryCode, + curr: currencyCode, } }) + + const schemaEdit = 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(150, "IO name in English must be at most 150 characters long"), + + investmentNameArabic: yup + .string() + .required("IO name in Arabic is required") + .min(3, "IO name in Arabic must be at least 3 characters long") + .max(50, "IO name in Arabic must be at most 50 characters long"), + + descriptionEnglish: yup + .string() + .required("Description in English is required") + .min(10, "Description in English must be at least 10 characters long") + .max(1000, "Description in English must be at most 1000 characters long"), + + descriptionArabic: yup + .string() + .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() + .typeError("Goal Amount is must be number") + .required('Goal amount is required') + .positive('Goal amount must be a positive number') + .min(IObyID?.data?.totalAmtInvestmentInUSD, `Goal amount should not be lesser then amount raised ${IObyID?.data?.totalAmtInvestmentInUSD}`), + closingDate: yup + .date() + .notRequired("Closing date is required") + .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() + // .required("Minimum investment is required") + // .positive("Minimum investment must be a positive number") + // .min(1, "Minimum investment must be at least 1"), + + ISIN: yup.string().notRequired(), + + InvestmentDetails: yup.string().notRequired(), + + comment: yup.string().notRequired() + .min(10, "Comment must be at least 10 characters long") + .max(100, "Comment must be at most 100 characters long"), + + expectedReturn: yup + .string() + .required("Expected return is required"), + }); + + + const [values, setValues] = useState(id?minInvestmentById:miniValue); + + console.log(values); const formatNumber = (num) => { // Remove non-numeric characters and format with commas @@ -198,7 +269,7 @@ const IODetails = ({ enableNextTab, index, data }) => { handleSubmit, formState: { errors }, } = useForm({ - resolver: yupResolver(schema), + resolver: yupResolver(id ? schemaEdit : schema), }); useEffect(() => { diff --git a/src/Pages/IO_Management/CreateIO/IONAVDetails.jsx b/src/Pages/IO_Management/CreateIO/IONAVDetails.jsx index 3a002f0..faa8f7a 100644 --- a/src/Pages/IO_Management/CreateIO/IONAVDetails.jsx +++ b/src/Pages/IO_Management/CreateIO/IONAVDetails.jsx @@ -9,6 +9,8 @@ import { formatDatee } from '../../../Components/FormField'; import { AddIcon } from '@chakra-ui/icons'; import AddIONav from './AddIONav'; import { formatDate } from '../../Master/Sponser/Sponsers'; +import { LuFileSpreadsheet } from "react-icons/lu"; +import { exportToExcel } from '../../../Constants/Constants'; const IONAVDetails = () => { const { navDetails, setNavDetails, IODetails } = @@ -144,6 +146,27 @@ const IONAVDetails = () => { ), })); + const customHeaders = [ + { label: 'ID', key: 'id' }, + { label: 'Valuation Date', key: 'transactionDate' }, + { label: 'NAV', key: 'transactionAmount' }, + { label: 'Last NAV update', key: 'previousNAVvalue' }, + + + + { label: 'Investment Closed', key: 'initialNAVvalue' }, + { label: 'Comments', key: 'comments' }, + + + { label: 'Update by', key: 'creator' }, + { label: 'Transaction Type', key: 'transactionType' }, + { label: 'Comments', key: 'comments' }, + // Add more headers as needed + ]; + + + console.log(IODetails?.ioNAVHistory); + const handleDelete = () => { @@ -159,6 +182,9 @@ const IONAVDetails = () => { setIsLoading(true); }; + const handleExport = () =>{ + + } @@ -186,9 +212,10 @@ const IONAVDetails = () => { */} {/* {IODetails?.isInvestedAmount ? :null} */} + + - -{IODetails?.isInvestedAmount ? :null} +{IODetails?.isInvestedAmount ? :null} diff --git a/src/Pages/IO_Management/ViewIO/HeaderModal/DistributionInvestor.jsx b/src/Pages/IO_Management/ViewIO/HeaderModal/DistributionInvestor.jsx index 83f26d8..8cc5158 100644 --- a/src/Pages/IO_Management/ViewIO/HeaderModal/DistributionInvestor.jsx +++ b/src/Pages/IO_Management/ViewIO/HeaderModal/DistributionInvestor.jsx @@ -25,7 +25,7 @@ import { useToast, } from "@chakra-ui/react"; import NormalData from "../../../../Components/DataTable/NormalTable"; -import { useState } from "react"; +import { useContext, useState } from "react"; import { AddIcon } from "@chakra-ui/icons"; import { useGetDistributedToInvestorMutation, useGetDistributionInvestorMutation, useUpdateExitToInvestorMutation } from "../../../../Services/io.service"; import { useParams } from "react-router-dom"; @@ -37,10 +37,9 @@ import ToastBox from "../../../../Components/ToastBox"; import CurrencyInput from "../../../../Components/CurrencyInput"; import { IoCalculator } from "react-icons/io5"; import { debounce } from "../../../Master/Sponser/AddSponser"; +import GlobalStateContext from "../../../../Contexts/GlobalStateContext"; + -export const investor = yup.object().shape({ - amount: yup.string().required("Amount is required"), -}); const DistributionInvestor = ({ isOpen, onClose, exit }) => { const params = useParams(); @@ -50,6 +49,7 @@ const DistributionInvestor = ({ isOpen, onClose, exit }) => { const [ isFinalCalculateLoading, setIsFinalCalculateLoading ] = useState(false) const [ calcualtedData, setCalculatedDate ] = useState(null) const [ isCalcualtedData, setIsCalcualtedData ] = useState(false) + const { IODetails } = useContext(GlobalStateContext); // const { // data:IObyID, @@ -61,13 +61,35 @@ const DistributionInvestor = ({ isOpen, onClose, exit }) => { const [getFinalDistributionInvestment] = useGetDistributedToInvestorMutation(); const [ updateExitToInvestor ] = useUpdateExitToInvestorMutation() + const investorExit = yup.object().shape({ + amount: yup + .string() + .required("Amount is required") + .test( + "max", + `Distribution amount should not be greater than IO cash amount ${IODetails?.ioCash}`, + function(value) { + const { ioCash } = IODetails || {}; // Safely get ioCash + if (value && ioCash) { + return parseFloat(value) <= parseFloat(ioCash); // Ensure both are compared as numbers + } + return true; // If ioCash is not available, skip validation + } + ), + }); + + const investor = yup.object().shape({ + amount: yup.string().required("Amount is required"), + }); + + const { control, handleSubmit, formState: { errors }, reset, } = useForm({ - resolver: yupResolver(investor), + resolver: yupResolver(!exit? investorExit: investor), }); @@ -374,7 +396,7 @@ const DistributionInvestor = ({ isOpen, onClose, exit }) => { Calculate - + {errors.amount?.message} diff --git a/src/Pages/IO_Management/ViewIO/ViewIOTable.jsx b/src/Pages/IO_Management/ViewIO/ViewIOTable.jsx index 4f7a8d4..28d76ce 100644 --- a/src/Pages/IO_Management/ViewIO/ViewIOTable.jsx +++ b/src/Pages/IO_Management/ViewIO/ViewIOTable.jsx @@ -91,7 +91,7 @@ const ViewIOTable = () => { "Goal Amount", "Closing Date", "IO Status", - "Preview", + // "Preview", "Action", ]; diff --git a/src/Pages/IO_Management/ViewIO/ViewIOdetails.jsx b/src/Pages/IO_Management/ViewIO/ViewIOdetails.jsx index 4262bfe..750ddc1 100644 --- a/src/Pages/IO_Management/ViewIO/ViewIOdetails.jsx +++ b/src/Pages/IO_Management/ViewIO/ViewIOdetails.jsx @@ -125,7 +125,7 @@ const ViewIOdetails = () => { country: country?.countryName, value: removeTrailingZeros(minInvestmentAmt), logo: country?.flagIcon, - curr: country?.countryCode, + curr: currencyCode, } }) diff --git a/src/Pages/Investor_Management/InvestorDetails/Transaction.jsx b/src/Pages/Investor_Management/InvestorDetails/Transaction.jsx index ac127ed..a6c0c83 100644 --- a/src/Pages/Investor_Management/InvestorDetails/Transaction.jsx +++ b/src/Pages/Investor_Management/InvestorDetails/Transaction.jsx @@ -23,7 +23,7 @@ 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 Pagination from "../../../Components/Pagination"; import GlobalStateContext from "../../../Contexts/GlobalStateContext"; import CustomAlertDialog from "../../../Components/CustomAlertDialog"; @@ -60,20 +60,7 @@ import { year: 'numeric', }); }; - - // ====================================================[Table Setup]================================================================ - const tableHeadRow = [ - // "Sr N/O", - "Date", - "Transaction", - "Amount in investors currency", - // "Currency", - "TO USD", - "From USD", - "USD amount", - "IO Name", - "Payment Method", - ]; + console.log(transaction); @@ -100,7 +87,20 @@ console.log(transaction); console.log(filteredData); - + + // ====================================================[Table Setup]================================================================ + const tableHeadRow = [ + // "Sr N/O", + "Date", + "Transaction", + "Amount in investors currency", + // "Currency", + "TO USD", + "From USD", + "USD amount", + "IO Name", + "Payment Method", + ]; const extractedArray = filteredData?.map((item) => ({ id: item?.id, "Sr N/O": ( @@ -135,8 +135,8 @@ console.log(transaction); ), "Amount in investors currency": ( - - + + {/* {item.investorAmount} */} {parseFloat(item?.investorAmount || 0).toLocaleString(undefined, { minimumFractionDigits: 2, @@ -144,25 +144,21 @@ console.log(transaction); })} {item?.investorCurrency} - + ), "From USD": ( - {item.USDToInvCur_Rate} - ), "TO USD": ( - {item.invCurToUSD_Rate} - ), "USD amount": ( - - + + {/* {item.USDAmount} */} {parseFloat(item?.USDAmount || 0).toLocaleString(undefined, { minimumFractionDigits: 2, @@ -187,6 +183,43 @@ console.log(transaction); ), })); + + + + const totalRow = { + // id: "total", // or any unique ID + // "Sr N/O": ( + // Total + // ), + "Date": + Total + , + "Transaction": null, + // "Currency": null, + "Amount in investors currency": ( + + + {parseFloat(InvestorWallet?.WalletBalance_InInvCur).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} + {InvestorWallet?.currencyCode_InCur} + + + ), + "TO USD": null, + "From USD": null, + "USD amount": ( + + + + {parseFloat(InvestorWallet?.WalletBalance_InUSD).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} + $ + + + ), + "IO Name": null, + "Payment Method": null, + }; + + extractedArray?.push(totalRow) const handleDelete = () => { const updatedInvestorDetails = InvestorDetails.filter( @@ -201,111 +234,7 @@ console.log(transaction); setIsLoading(true); }; - const Total = () => { - return ( - - - - - - - - - - - - - -
- Balance: - - {" "} - - - {parseFloat(InvestorWallet?.WalletBalance_InInvCur).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} - {InvestorWallet?.currencyCode_InCur} - - - {" "} - - {" "} - - - {parseFloat(InvestorWallet?.WalletBalance_InUSD).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })} - {InvestorWallet?.currencyCode_InCur} - - - {" "} - - {" "} -
- ); - }; + return ( @@ -336,7 +265,7 @@ console.log(transaction); - } setMouseEntered={setMouseEntered} /> diff --git a/src/Pages/Investor_Management/InvestorDetails/ViewInvestorDetails.jsx b/src/Pages/Investor_Management/InvestorDetails/ViewInvestorDetails.jsx index f871af0..52861a5 100644 --- a/src/Pages/Investor_Management/InvestorDetails/ViewInvestorDetails.jsx +++ b/src/Pages/Investor_Management/InvestorDetails/ViewInvestorDetails.jsx @@ -19,7 +19,7 @@ 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, Navigate, Link as RouterLink } from "react-router-dom"; import { @@ -47,7 +47,7 @@ const ViewInvestorDetails = () => { const [actionId, setActionId] = useState(false); const [mouseEntered, setMouseEntered] = useState(false); const [mouseEnteredId, setMouseEnteredId] = useState(""); - + useEffect(() => { // Simulate loading const timer = setTimeout(() => { @@ -75,8 +75,7 @@ const ViewInvestorDetails = () => { // "Action", ]; -console.log(viewInvestor); - + console.log(viewInvestor); // ====================================================[Table Filter]================================================================ const filteredData = viewInvestor?.filter((item) => { @@ -99,10 +98,11 @@ console.log(viewInvestor); console.log(filteredData); - const extractedArray = filteredData?.map((item,index) => ({ + const extractedArray = filteredData?.map((item, index) => ({ id: item?.id, "Sr N/O": ( - ), "Sponsor Name": ( - + {item.sponsorName} @@ -128,15 +128,15 @@ console.log(viewInvestor); "Investment Amount": ( - {/* {item.investedAmount} */} - $ {parseFloat(item?.investedAmount || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} + {/* {item.investedAmount} */}${" "} + {parseFloat(item?.investedAmount || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} ), - "Percentage": ( + Percentage: ( {item?.Investor_Holidings} % @@ -146,10 +146,11 @@ console.log(viewInvestor); "Market Value": ( - $ {parseFloat(item?.MarketValue || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} + ${" "} + {parseFloat(item?.MarketValue || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} ), @@ -160,13 +161,17 @@ console.log(viewInvestor); ), - "Distribution": ( + Distribution: ( - $ {parseFloat(item?.DistributionAmountReceived || 0).toLocaleString(undefined, { + ${" "} + {parseFloat(item?.DistributionAmountReceived || 0).toLocaleString( + undefined, + { minimumFractionDigits: 2, maximumFractionDigits: 2, - })} + } + )} ), @@ -180,10 +185,11 @@ console.log(viewInvestor); "Total return": ( - $ {parseFloat(item?.TotalReturn || 0).toLocaleString(undefined, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })} + ${" "} + {parseFloat(item?.TotalReturn || 0).toLocaleString(undefined, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + })} ), @@ -195,23 +201,35 @@ console.log(viewInvestor); ), Status: ( - - - {item.statusAdmin} - - + + {item?.statusAdmin} + ), Action: ( @@ -279,7 +297,7 @@ console.log(viewInvestor); - - ); }; diff --git a/src/Services/api.service.js b/src/Services/api.service.js index 0cbd46d..e69de29 100644 --- a/src/Services/api.service.js +++ b/src/Services/api.service.js @@ -1,66 +0,0 @@ -import axios from "axios"; - -// Create an Axios instance for API calls -export const api = axios.create({ - // baseURL: `https://tanami.betadelivery.com/api/v1`, - baseURL: import.meta.env.VITE_BAS_URL, // Replace with your API base URL - timeout: 10000, // Adjust timeout as needed - headers: { - "Content-Type": "application/json", - }, -}); - -// Add Axios request interceptor to refresh token if expired -api.interceptors.request.use( - (config) => { - console.log(config); - // Modify headers or add tokens as needed - // const token = localStorage.getItem("accessToken"); - // if (token) { - // config.headers.Authorization = `Bearer ${token}`; - // } - return config; - }, - (error) => { - return Promise.reject(error); - } -); - -// // Add Axios response interceptor to handle token refreshing -api.interceptors.response.use( - (response) => { - return response; - }, - async (error) => { - const originalRequest = error.config; - - // Example logic for handling token expiration and refreshing - if ( - error.response.status === 401 && - !originalRequest._retry && - localStorage.getItem("refreshToken") - ) { - originalRequest._retry = true; - - try { - const response = await api.post("/refresh_token", { - refreshToken: localStorage.getItem("refreshToken"), - }); - - if (response.status === 200) { - // Update tokens in local storage - localStorage.setItem("accessTokenn", response.data.accessToken); - localStorage.setItem("refreshTokenn", response.data.refreshToken); - - // Retry the original request with the new tokens - return api(originalRequest); - } - } catch (error) { - console.error("Failed to refresh token:", error); - // Handle token refresh failure (e.g., redirect to login) - } - } - - return Promise.reject(error); - } -);