added self tenant
This commit is contained in:
parent
b28946333e
commit
67830372fb
@ -105,6 +105,8 @@
|
|||||||
<!-- <script src="./public/js/timppick.js"></script> -->
|
<!-- <script src="./public/js/timppick.js"></script> -->
|
||||||
|
|
||||||
<script src="/assets/vendor/libs/sweetalert2/sweetalert2.js"></script>
|
<script src="/assets/vendor/libs/sweetalert2/sweetalert2.js"></script>
|
||||||
|
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js"></script>
|
<!-- <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script> -->
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script> -->
|
||||||
|
|||||||
224
package-lock.json
generated
224
package-lock.json
generated
@ -22,6 +22,8 @@
|
|||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"dotenv-webpack": "^8.1.0",
|
"dotenv-webpack": "^8.1.0",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
|
"jspdf": "^3.0.3",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"match-sorter": "^6.3.1",
|
"match-sorter": "^6.3.1",
|
||||||
@ -259,12 +261,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.26.0",
|
"version": "7.28.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
|
||||||
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
|
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
|
||||||
"dependencies": {
|
"license": "MIT",
|
||||||
"regenerator-runtime": "^0.14.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@ -1561,6 +1561,12 @@
|
|||||||
"undici-types": "~7.12.0"
|
"undici-types": "~7.12.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/pako": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/prop-types": {
|
"node_modules/@types/prop-types": {
|
||||||
"version": "15.7.14",
|
"version": "15.7.14",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
|
||||||
@ -1576,6 +1582,13 @@
|
|||||||
"parchment": "^1.1.2"
|
"parchment": "^1.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/raf": {
|
||||||
|
"version": "3.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
|
||||||
|
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "18.3.16",
|
"version": "18.3.16",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.16.tgz",
|
||||||
@ -1595,6 +1608,13 @@
|
|||||||
"@types/react": "^18.0.0"
|
"@types/react": "^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/trusted-types": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/@types/use-sync-external-store": {
|
"node_modules/@types/use-sync-external-store": {
|
||||||
"version": "0.0.6",
|
"version": "0.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
||||||
@ -2156,6 +2176,15 @@
|
|||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/base64-arraybuffer": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
@ -2276,6 +2305,26 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/canvg": {
|
||||||
|
"version": "3.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz",
|
||||||
|
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.12.5",
|
||||||
|
"@types/raf": "^3.4.0",
|
||||||
|
"core-js": "^3.8.3",
|
||||||
|
"raf": "^3.4.1",
|
||||||
|
"regenerator-runtime": "^0.13.7",
|
||||||
|
"rgbcolor": "^1.0.1",
|
||||||
|
"stackblur-canvas": "^2.0.0",
|
||||||
|
"svg-pathdata": "^6.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cfb": {
|
"node_modules/cfb": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
|
||||||
@ -2388,6 +2437,18 @@
|
|||||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
|
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/core-js": {
|
||||||
|
"version": "3.46.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz",
|
||||||
|
"integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/core-js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/crc-32": {
|
"node_modules/crc-32": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
|
||||||
@ -2414,6 +2475,15 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-line-break": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"utrie": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/csstype": {
|
"node_modules/csstype": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
@ -2575,6 +2645,16 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dompurify": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==",
|
||||||
|
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||||
|
"optional": true,
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@types/trusted-types": "^2.0.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "16.4.7",
|
"version": "16.4.7",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
|
||||||
@ -3151,6 +3231,23 @@
|
|||||||
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-png": {
|
||||||
|
"version": "6.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz",
|
||||||
|
"integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/pako": "^2.0.3",
|
||||||
|
"iobuffer": "^5.3.2",
|
||||||
|
"pako": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fast-png/node_modules/pako": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
||||||
|
"license": "(MIT AND Zlib)"
|
||||||
|
},
|
||||||
"node_modules/fast-uri": {
|
"node_modules/fast-uri": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||||
@ -3187,6 +3284,12 @@
|
|||||||
"tough-cookie": "^4.0.0"
|
"tough-cookie": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fflate": {
|
||||||
|
"version": "0.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
|
||||||
|
"integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||||
@ -3558,6 +3661,19 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/html2canvas": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"css-line-break": "^2.1.0",
|
||||||
|
"text-segmentation": "^1.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ignore": {
|
"node_modules/ignore": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
|
||||||
@ -3637,6 +3753,12 @@
|
|||||||
"node": ">= 0.4"
|
"node": ">= 0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/iobuffer": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/is-arguments": {
|
"node_modules/is-arguments": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz",
|
||||||
@ -4131,6 +4253,23 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jspdf": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.26.9",
|
||||||
|
"fast-png": "^6.2.0",
|
||||||
|
"fflate": "^0.8.1"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"canvg": "^3.0.11",
|
||||||
|
"core-js": "^3.6.0",
|
||||||
|
"dompurify": "^3.2.4",
|
||||||
|
"html2canvas": "^1.0.0-rc.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsx-ast-utils": {
|
"node_modules/jsx-ast-utils": {
|
||||||
"version": "3.3.5",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
||||||
@ -4612,6 +4751,13 @@
|
|||||||
"resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.6.tgz",
|
||||||
"integrity": "sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw=="
|
"integrity": "sha512-rixgxw3SxyJbCaSpo1n35A/fwI1r2rdwMKOTCg/AcG+xOEyZcE8UHVjpZMFCVImzsFoCZeJTT+M/rdEIQYO2nw=="
|
||||||
},
|
},
|
||||||
|
"node_modules/performance-now": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
@ -4757,6 +4903,16 @@
|
|||||||
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==",
|
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/raf": {
|
||||||
|
"version": "3.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||||
|
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"performance-now": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/randombytes": {
|
"node_modules/randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
@ -4947,9 +5103,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.14.1",
|
"version": "0.13.11",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/regexp.prototype.flags": {
|
"node_modules/regexp.prototype.flags": {
|
||||||
"version": "1.5.3",
|
"version": "1.5.3",
|
||||||
@ -5030,6 +5188,16 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rgbcolor": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
|
||||||
|
"license": "MIT OR SEE LICENSE IN FEEL-FREE.md",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.15"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rimraf": {
|
"node_modules/rimraf": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
@ -5429,6 +5597,16 @@
|
|||||||
"node": ">=0.8"
|
"node": ">=0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stackblur-canvas": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.1.14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string.prototype.matchall": {
|
"node_modules/string.prototype.matchall": {
|
||||||
"version": "4.0.11",
|
"version": "4.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
|
||||||
@ -5562,6 +5740,16 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svg-pathdata": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/swiper": {
|
"node_modules/swiper": {
|
||||||
"version": "11.2.10",
|
"version": "11.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz",
|
||||||
@ -5648,6 +5836,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/text-segmentation": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"utrie": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/text-table": {
|
"node_modules/text-table": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
@ -5866,6 +6063,15 @@
|
|||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/utrie": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"base64-arraybuffer": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.4.11",
|
"version": "5.4.11",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
|
||||||
|
|||||||
@ -25,6 +25,8 @@
|
|||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"dotenv-webpack": "^8.1.0",
|
"dotenv-webpack": "^8.1.0",
|
||||||
"eventemitter3": "^5.0.1",
|
"eventemitter3": "^5.0.1",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
|
"jspdf": "^3.0.3",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"match-sorter": "^6.3.1",
|
"match-sorter": "^6.3.1",
|
||||||
|
|||||||
@ -67,34 +67,75 @@
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ✅ Success */
|
||||||
.timeline-point.completed {
|
.timeline-point.completed {
|
||||||
background-color: var(--bs-success);
|
background-color: var(--bs-success);
|
||||||
color: white;
|
color: #fff;
|
||||||
|
box-shadow: 0 0 5px rgba(25, 135, 84, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ❌ Failed */
|
||||||
|
.timeline-point.failed {
|
||||||
|
background-color: var(--bs-danger);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 0 5px rgba(220, 53, 69, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ⏳ Pending (Active) */
|
||||||
.timeline-point.active {
|
.timeline-point.active {
|
||||||
background-color: var(--bs-info);
|
background-color: var(--bs-info);
|
||||||
color: white;
|
color: #fff;
|
||||||
transform: scale(1.1);
|
transform: scale(1.15);
|
||||||
padding: 4px;
|
box-shadow: 0 0 6px rgba(13, 202, 240, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Connecting line */
|
||||||
.timeline-line-horizontal {
|
.timeline-line-horizontal {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
width:100% ;
|
width: 100%;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
background-color: #dee2e6;
|
background-color: #dee2e6;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make line green for completed sections */
|
||||||
.timeline-item.completed ~ .timeline-line-horizontal {
|
.timeline-item.completed ~ .timeline-line-horizontal {
|
||||||
background-color: #28a745;
|
background-color: var(--bs-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optional: subtle pulse for active step */
|
||||||
|
.timeline-point.active::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid var(--bs-info);
|
||||||
|
animation: pulse 1.5s infinite;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
transform: scale(1.5);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -175,3 +216,38 @@
|
|||||||
.h-screen{ height: 100vh; }
|
.h-screen{ height: 100vh; }
|
||||||
.h-min { height: min-content; }
|
.h-min { height: min-content; }
|
||||||
.h-max { height: max-content; }
|
.h-max { height: max-content; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------Text------------------------- */
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
.fs-sm-1 { font-size: calc(1.3rem + 1.6vw) !important; }
|
||||||
|
.fs-sm-2 { font-size: calc(1.2rem + 1.2vw) !important; }
|
||||||
|
.fs-sm-3 { font-size: calc(1.1rem + 0.8vw) !important; }
|
||||||
|
.fs-sm-4 { font-size: calc(1rem + 0.5vw) !important; }
|
||||||
|
.fs-sm-5 { font-size: 1.05rem !important; }
|
||||||
|
.fs-sm-6 { font-size: 0.9rem !important; }
|
||||||
|
|
||||||
|
.fs-sm-tiny { font-size: 72% !important; }
|
||||||
|
.fs-sm-big { font-size: 115% !important; }
|
||||||
|
.fs-sm-large { font-size: 155% !important; }
|
||||||
|
.fs-sm-xlarge { font-size: 175% !important; }
|
||||||
|
.fs-sm-xxlarge { font-size: calc(1.6rem + 3.5vw) !important; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 💻 Medium devices (≥768px) */
|
||||||
|
@media (min-width: 768px) {
|
||||||
|
.fs-md-1 { font-size: calc(1.4125rem + 1.95vw) !important; }
|
||||||
|
.fs-md-2 { font-size: calc(1.3625rem + 1.35vw) !important; }
|
||||||
|
.fs-md-3 { font-size: calc(1.3rem + 0.6vw) !important; }
|
||||||
|
.fs-md-4 { font-size: calc(1.275rem + 0.3vw) !important; }
|
||||||
|
.fs-md-5 { font-size: 1.125rem !important; }
|
||||||
|
.fs-md-6 { font-size: 0.9375rem !important; }
|
||||||
|
|
||||||
|
.fs-md-tiny { font-size: 70% !important; }
|
||||||
|
.fs-md-big { font-size: 112% !important; }
|
||||||
|
.fs-md-large { font-size: 150% !important; }
|
||||||
|
.fs-md-xlarge { font-size: 170% !important; }
|
||||||
|
.fs-md-xxlarge { font-size: calc(1.725rem + 5.7vw) !important; }
|
||||||
|
}
|
||||||
@ -105,8 +105,8 @@ const SubScription = ({ onSubmitSubScription, onNext }) => {
|
|||||||
return (
|
return (
|
||||||
<div key={plan.id} className="col-md-4">
|
<div key={plan.id} className="col-md-4">
|
||||||
<div
|
<div
|
||||||
className={`card h-100 shadow-none border-1 cursor-pointer ${
|
className={`card h-100 shadow-none cursor-pointer ${
|
||||||
isSelected ? "border-primary border-1 shadow-md" : ""
|
isSelected ? "border-primary shadow-md" : ""
|
||||||
}`}
|
}`}
|
||||||
onClick={() => handlePlanSelection(plan)}
|
onClick={() => handlePlanSelection(plan)}
|
||||||
>
|
>
|
||||||
|
|||||||
306
src/components/UserSubscription/Invoice.jsx
Normal file
306
src/components/UserSubscription/Invoice.jsx
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
import React, { useRef, useState } from "react";
|
||||||
|
import html2canvas from "html2canvas";
|
||||||
|
import jsPDF from "jspdf";
|
||||||
|
import { formatFigure } from "../../utils/appUtils";
|
||||||
|
|
||||||
|
const Invoice = ({ invoiceData, currencySymbol }) => {
|
||||||
|
const [isGenerating, setIsGenerating] = useState(false);
|
||||||
|
const invoiceRef = useRef(null);
|
||||||
|
|
||||||
|
const data = invoiceData || {
|
||||||
|
razorpayPaymentDetails: {
|
||||||
|
amount: 19999,
|
||||||
|
bankDetails: null,
|
||||||
|
captured: true,
|
||||||
|
cardDetails: {
|
||||||
|
cardId: null,
|
||||||
|
cardType: null,
|
||||||
|
emi: false,
|
||||||
|
international: false,
|
||||||
|
issuer: null,
|
||||||
|
last4Digits: null,
|
||||||
|
network: null,
|
||||||
|
subType: null,
|
||||||
|
},
|
||||||
|
contact: "+919145445127",
|
||||||
|
createdAt: "2025-10-25T06:46:30",
|
||||||
|
currency: "INR",
|
||||||
|
description: "",
|
||||||
|
email: "avn18042001@gmail.com",
|
||||||
|
errorCode: "",
|
||||||
|
errorDescription: "",
|
||||||
|
fee: 707.97,
|
||||||
|
internationalPayment: true,
|
||||||
|
method: "card",
|
||||||
|
orderId: "order_RXbzfh8d1X1SSg",
|
||||||
|
paymentId: "pay_RXc08bJHVpjytP",
|
||||||
|
status: "captured",
|
||||||
|
tax: 108,
|
||||||
|
upiDetails: null,
|
||||||
|
walletDetails: null,
|
||||||
|
},
|
||||||
|
razorpayOrderDetails: {
|
||||||
|
amount: 19999,
|
||||||
|
amountDue: 0,
|
||||||
|
amountPaid: 19999,
|
||||||
|
attempts: 1,
|
||||||
|
createdAt: "2025-10-25T06:46:02",
|
||||||
|
currency: "INR",
|
||||||
|
orderId: "order_RXbzfh8d1X1SSg",
|
||||||
|
receipt: "rec_aae16ec3-9571-4c96-bd77-59950fdce236",
|
||||||
|
status: "paid",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatAmount = (amount) => {
|
||||||
|
return currencySymbol + amount.toFixed(2);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleDateString("en-IN", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadPDF = async () => {
|
||||||
|
setIsGenerating(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const invoice = invoiceRef.current;
|
||||||
|
const canvas = await html2canvas(invoice, {
|
||||||
|
scale: 2,
|
||||||
|
useCORS: true,
|
||||||
|
logging: false,
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
});
|
||||||
|
|
||||||
|
const imgData = canvas.toDataURL("image/png");
|
||||||
|
const pdf = new jsPDF({
|
||||||
|
orientation: "portrait",
|
||||||
|
unit: "mm",
|
||||||
|
format: "a4",
|
||||||
|
});
|
||||||
|
|
||||||
|
const imgWidth = 210;
|
||||||
|
const pageHeight = 297;
|
||||||
|
const imgHeight = (canvas.height * imgWidth) / canvas.width;
|
||||||
|
|
||||||
|
pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
|
||||||
|
|
||||||
|
const paymentId = data.razorpayPaymentDetails.paymentId;
|
||||||
|
pdf.save(`Invoice_${paymentId}.pdf`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error generating PDF:", error);
|
||||||
|
alert("Failed to generate PDF. Please try again.");
|
||||||
|
} finally {
|
||||||
|
setIsGenerating(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const payment = data.razorpayPaymentDetails;
|
||||||
|
const order = data.razorpayOrderDetails;
|
||||||
|
const subtotal = payment.amount - payment.fee - payment.tax;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container-md text-start p-0">
|
||||||
|
<i className="bx bx-download cursor-pointer" onClick={downloadPDF}
|
||||||
|
disabled={isGenerating}></i>
|
||||||
|
|
||||||
|
<div className="invoice-preview p-2" ref={invoiceRef}>
|
||||||
|
<div className="invoice-content">
|
||||||
|
{/* Header */}
|
||||||
|
<div className="row align-items-start mb-4">
|
||||||
|
<div className="col-md-6 d-block text-start align-items-start">
|
||||||
|
<p className="fw-semibold fs-5 m-0 mb-0 text-primary">INVOICE</p>
|
||||||
|
<small className="text-muted">Payment Receipt</small>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-6 text-end">
|
||||||
|
<h6 className="fw-semibold mb-2">
|
||||||
|
INV-{payment.paymentId.slice(-8).toUpperCase()}
|
||||||
|
</h6>
|
||||||
|
<div className="small">
|
||||||
|
<div>
|
||||||
|
<strong>Date:</strong> {formatDate(payment.createdAt)}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Payment ID:</strong> {payment.paymentId}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className={`badge bg-${
|
||||||
|
order.status === "paid" ? "success" : "secondary"
|
||||||
|
} mt-2`}
|
||||||
|
>
|
||||||
|
{order.status.toUpperCase()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
{/* Billing Details */}
|
||||||
|
<div className="row mb-4">
|
||||||
|
<div className="col-md-6">
|
||||||
|
<h5 className="fw-semibold border-bottom pb-1 mb-3">Bill To</h5>
|
||||||
|
<p className="mb-1 fw-medium">{payment.customerName || "N/A"}</p>
|
||||||
|
<p className="mb-1">{payment.email || "N/A"}</p>
|
||||||
|
<p className="mb-1">{payment.contact || "N/A"}</p>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-6">
|
||||||
|
<h5 className="fw-semibold border-bottom pb-1 mb-3">
|
||||||
|
Payment Information
|
||||||
|
</h5>
|
||||||
|
<p className="mb-1">
|
||||||
|
<strong>Order ID:</strong> {order.orderId}
|
||||||
|
</p>
|
||||||
|
<p className="mb-1">
|
||||||
|
<strong>Receipt:</strong> {order.receipt}
|
||||||
|
</p>
|
||||||
|
<p className="mb-1">
|
||||||
|
<strong>Method:</strong>{" "}
|
||||||
|
{payment.method.charAt(0).toUpperCase() +
|
||||||
|
payment.method.slice(1)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
{/* Transaction Details */}
|
||||||
|
<div className="mb-4">
|
||||||
|
<h5 className="fw-semibold border-bottom pb-1 mb-3">
|
||||||
|
Transaction Details
|
||||||
|
</h5>
|
||||||
|
<div className="row g-3">
|
||||||
|
<div className="col-md-4 col-6">
|
||||||
|
<div className="border rounded p-2 bg-light">
|
||||||
|
<small className="text-muted d-block">Payment Status</small>
|
||||||
|
<span className="fw-semibold">
|
||||||
|
{payment.status.charAt(0).toUpperCase() +
|
||||||
|
payment.status.slice(1)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4 col-6">
|
||||||
|
<div className="border rounded p-2 bg-light">
|
||||||
|
<small className="text-muted d-block">Currency</small>
|
||||||
|
<span className="fw-semibold">{payment.currency}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4 col-6">
|
||||||
|
<div className="border rounded p-2 bg-light">
|
||||||
|
<small className="text-muted d-block">Card Type</small>
|
||||||
|
<span className="fw-semibold">
|
||||||
|
{payment.cardDetails?.cardType ||
|
||||||
|
payment.method.toUpperCase()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4 col-6">
|
||||||
|
<div className="border rounded p-2 bg-light">
|
||||||
|
<small className="text-muted d-block">Last 4 Digits</small>
|
||||||
|
<span className="fw-semibold">
|
||||||
|
{payment.cardDetails?.last4Digits || "N/A"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4 col-6">
|
||||||
|
<div className="border rounded p-2 bg-light">
|
||||||
|
<small className="text-muted d-block">International</small>
|
||||||
|
<span className="fw-semibold">
|
||||||
|
{payment.internationalPayment ? "Yes" : "No"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-md-4 col-6">
|
||||||
|
<div className="border rounded p-2 bg-light">
|
||||||
|
<small className="text-muted d-block">Captured</small>
|
||||||
|
<span className="fw-semibold">
|
||||||
|
{payment.captured ? "Yes" : "No"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
{/* Amount Breakdown */}
|
||||||
|
<div className="mt-3">
|
||||||
|
<h5 className="fw-semibold border-bottom pb-1 mb-3">
|
||||||
|
Payment Summary
|
||||||
|
</h5>
|
||||||
|
<div className="row justify-content-end">
|
||||||
|
<div className="col-md-6">
|
||||||
|
<table className="table table-sm mb-0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td className="fw-medium">Subtotal</td>
|
||||||
|
<td className="text-end">{formatFigure(subtotal.toFixed(2),{
|
||||||
|
type: "currency",
|
||||||
|
currency: payment.currency,
|
||||||
|
})}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td className="fw-medium">Processing Fee</td>
|
||||||
|
<td className="text-end">{formatFigure(payment.fee.toFixed(2),{
|
||||||
|
type: "currency",
|
||||||
|
currency: payment.currency,
|
||||||
|
})}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td className="fw-medium">Tax</td>
|
||||||
|
<td className="text-end">{formatFigure(payment.tax.toFixed(2),{
|
||||||
|
type: "currency",
|
||||||
|
currency: payment.currency,
|
||||||
|
})}</td>
|
||||||
|
</tr>
|
||||||
|
<tr className="bg-light-secondary fw-semibold">
|
||||||
|
<td>Total Paid</td>
|
||||||
|
<td className="text-end fw-bold">
|
||||||
|
{formatFigure(payment.amount, {
|
||||||
|
type: "currency",
|
||||||
|
currency: payment.currency,
|
||||||
|
})}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<div className="text-center mt-4">
|
||||||
|
<p className="mb-1 fw-medium ">
|
||||||
|
Thank you for your payment!
|
||||||
|
</p>
|
||||||
|
<small className="text-muted d-block">
|
||||||
|
This is a computer-generated invoice and does not require a
|
||||||
|
signature.
|
||||||
|
</small>
|
||||||
|
<small className="text-muted d-block mt-2">
|
||||||
|
Generated on:{" "}
|
||||||
|
{new Date().toLocaleDateString("en-IN", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "long",
|
||||||
|
day: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
})}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Invoice;
|
||||||
@ -1,12 +1,24 @@
|
|||||||
import React, { useState, useMemo } from "react";
|
import React, { useState, useMemo, useEffect } from "react";
|
||||||
import { useSubscription } from "../../hooks/useAuth";
|
import { useSubscription } from "../../hooks/useAuth";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { useCreateTenant, useIndustries } from "../../hooks/useTenant";
|
import { useCreateTenant, useIndustries } from "../../hooks/useTenant";
|
||||||
import { frequencyLabel } from "../../utils/appUtils";
|
import {
|
||||||
|
formatCurrency,
|
||||||
|
formatFigure,
|
||||||
|
frequencyLabel,
|
||||||
|
} from "../../utils/appUtils";
|
||||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||||
const ProcessedPayment = () => {
|
import { PaymentRepository } from "../../repositories/PaymentRepository";
|
||||||
|
import { useMakePayment } from "../../hooks/usePayment";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { setSelfTenant } from "../../slices/localVariablesSlice";
|
||||||
|
|
||||||
|
const ProcessedPayment = ({ onNext, resetPaymentStep }) => {
|
||||||
const { frequency, planName } = useParams();
|
const { frequency, planName } = useParams();
|
||||||
|
const dispatch = useDispatch();
|
||||||
const [selectedPlan, setSelectedPlan] = useState(planName);
|
const [selectedPlan, setSelectedPlan] = useState(planName);
|
||||||
|
const [currentPlan, setCurrentPlan] = useState(null);
|
||||||
|
const [failPayment, setFailPayment] = useState(null);
|
||||||
const {
|
const {
|
||||||
data: plans,
|
data: plans,
|
||||||
isError: isPlanError,
|
isError: isPlanError,
|
||||||
@ -21,13 +33,51 @@ const ProcessedPayment = () => {
|
|||||||
const planOrder = ["basic", "pro", "super"];
|
const planOrder = ["basic", "pro", "super"];
|
||||||
const currentIndex = planOrder.indexOf(planName?.toLowerCase());
|
const currentIndex = planOrder.indexOf(planName?.toLowerCase());
|
||||||
|
|
||||||
if (currentIndex === -1) return plans; // fallback: show all
|
if (currentIndex === -1) return plans;
|
||||||
const visibleNames = planOrder.slice(currentIndex);
|
const visibleNames = planOrder.slice(currentIndex);
|
||||||
|
const selected = plans?.find((p) => p.planName === selectedPlan);
|
||||||
|
debugger;
|
||||||
|
dispatch(
|
||||||
|
setSelfTenant({
|
||||||
|
planId: selected?.id,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
setCurrentPlan(selected);
|
||||||
|
|
||||||
return plans.filter((p) =>
|
return plans.filter((p) =>
|
||||||
visibleNames.includes(p.planName?.toLowerCase())
|
visibleNames.includes(p.planName?.toLowerCase())
|
||||||
);
|
);
|
||||||
}, [plans, selectedPlan]);
|
}, [plans, selectedPlan]);
|
||||||
|
|
||||||
|
const loadScript = (src) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = src;
|
||||||
|
script.onload = () => resolve(true);
|
||||||
|
script.onerror = () => resolve(false);
|
||||||
|
document.body.appendChild(script);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const { mutate: MakePayment, isPending } = useMakePayment(
|
||||||
|
(response) => {
|
||||||
|
onNext(response);
|
||||||
|
},
|
||||||
|
(fail) => {
|
||||||
|
setFailPayment(fail);
|
||||||
|
onNext(fail);
|
||||||
|
},
|
||||||
|
currentPlan
|
||||||
|
);
|
||||||
|
const ProcessToPayment = async (payload) => {
|
||||||
|
const res = await loadScript(
|
||||||
|
"https://checkout.razorpay.com/v1/checkout.js"
|
||||||
|
);
|
||||||
|
|
||||||
|
MakePayment({ amount: 1 });
|
||||||
|
};
|
||||||
|
|
||||||
const clients = [
|
const clients = [
|
||||||
{
|
{
|
||||||
firstName: "Alice",
|
firstName: "Alice",
|
||||||
@ -43,13 +93,65 @@ const ProcessedPayment = () => {
|
|||||||
reference: "d2e3f4a5-6789-0123-4567-89abcdef0123",
|
reference: "d2e3f4a5-6789-0123-4567-89abcdef0123",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleRetry = () => {
|
||||||
|
setFailPayment(null);
|
||||||
|
resetPaymentStep();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (failPayment) {
|
||||||
|
return (
|
||||||
|
<div className="container-md mt-5 text-center">
|
||||||
|
<div className="d-flex flex-column align-items-center justify-content-center">
|
||||||
|
<div
|
||||||
|
className="bg-danger p-3 rounded-circle mb-3 d-flex align-items-center justify-content-center"
|
||||||
|
style={{ width: "70px", height: "70px" }}
|
||||||
|
>
|
||||||
|
<i className="bx bx-x fs-1 text-white fw-bold"></i>
|
||||||
|
</div>
|
||||||
|
<h4 className="text-danger mb-2">Payment Failed!</h4>
|
||||||
|
<p className="text-muted">
|
||||||
|
Unfortunately, your payment could not be completed. Please try again
|
||||||
|
or use a different payment method.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="mt-4 d-flex gap-3 flex-column flex-md-row justify-content-center">
|
||||||
|
<button
|
||||||
|
className="btn btn-primary px-4 py-2 fw-semibold"
|
||||||
|
onClick={handleRetry}
|
||||||
|
>
|
||||||
|
Retry Payment
|
||||||
|
</button>
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
className="btn btn-outline-secondary px-4 py-2 fw-semibold"
|
||||||
|
>
|
||||||
|
Go Back to Dashboard
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{failPayment?.error && (
|
||||||
|
<div className="alert alert-light-danger mt-4 w-75 mx-auto text-start">
|
||||||
|
<strong>Error Details:</strong>
|
||||||
|
<pre className="small mb-0 mt-2 text-wrap">
|
||||||
|
{JSON.stringify(failPayment.error, null, 2)}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="container-md">
|
<div className="container-md text-start">
|
||||||
<div className="row">
|
<h6 className="fs-4 fw-bold">
|
||||||
<div className="col-12 col-md-6">
|
Make sure your selected details, and process to payment
|
||||||
|
</h6>
|
||||||
|
<div className="row gx-1 gy-3 justify-content-between">
|
||||||
|
<div className="col-12 col-md-6">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 mb-3 text-start">
|
<div className="col-12 mb-3 text-start">
|
||||||
<h4 className="fw-bold ">
|
<h4 className=" ">
|
||||||
Choose the Perfect Plan for Your Organization
|
Choose the Perfect Plan for Your Organization
|
||||||
</h4>
|
</h4>
|
||||||
<p className="text-muted small mb-3">
|
<p className="text-muted small mb-3">
|
||||||
@ -58,7 +160,7 @@ const ProcessedPayment = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{visiblePlans?.map((plan) => {
|
{visiblePlans?.map((plan) => {
|
||||||
let colSize = "8"; // default 1 card full width
|
let colSize = "8";
|
||||||
|
|
||||||
if (visiblePlans.length === 2) colSize = "6";
|
if (visiblePlans.length === 2) colSize = "6";
|
||||||
else if (visiblePlans.length === 3) colSize = "4";
|
else if (visiblePlans.length === 3) colSize = "4";
|
||||||
@ -106,12 +208,13 @@ const ProcessedPayment = () => {
|
|||||||
})}
|
})}
|
||||||
{selectedPlan && (
|
{selectedPlan && (
|
||||||
<div className="col-12 text-start">
|
<div className="col-12 text-start">
|
||||||
<div className="border-warning p-3 mt-3">
|
<div className="border-warning mt-3">
|
||||||
{(() => {
|
{(() => {
|
||||||
const selected = plans?.find(
|
const selected = plans?.find(
|
||||||
(p) => p.planName === selectedPlan
|
(p) => p.planName === selectedPlan
|
||||||
);
|
);
|
||||||
if (!selected) return null;
|
if (!selected) return null;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
planName,
|
planName,
|
||||||
description,
|
description,
|
||||||
@ -123,7 +226,6 @@ const ProcessedPayment = () => {
|
|||||||
currency,
|
currency,
|
||||||
features,
|
features,
|
||||||
} = selected;
|
} = selected;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="row g-2 mb-3">
|
<div className="row g-2 mb-3">
|
||||||
@ -150,42 +252,25 @@ const ProcessedPayment = () => {
|
|||||||
<h6 className="fw-bold text-secondary mb-2">
|
<h6 className="fw-bold text-secondary mb-2">
|
||||||
Included Features
|
Included Features
|
||||||
</h6>
|
</h6>
|
||||||
<div className="row">
|
<div className="row ">
|
||||||
{Object.entries(features?.modules || {}).map(
|
{features &&
|
||||||
([key, mod]) => (
|
Object.entries(features?.modules || {})
|
||||||
<div key={mod.id} className="col-md-6 mb-2">
|
.filter(([key]) => key !== "id")
|
||||||
|
.map(([key, mod]) => (
|
||||||
<div
|
<div
|
||||||
className={`border rounded-3 p-2 ${
|
key={key}
|
||||||
mod.enabled
|
className="col-4 mb-2 d-flex align-items-center mb-2"
|
||||||
? "border-success bg-light-success"
|
|
||||||
: "border-light"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div className="d-flex align-items-center justify-content-between">
|
<i
|
||||||
<span>
|
className={`fa-regular ${
|
||||||
<i
|
mod.enabled
|
||||||
className={`bx bx-check-circle me-2 ${
|
? "fa-circle-check text-success"
|
||||||
mod.enabled
|
: "fa-circle-xmark text-danger"
|
||||||
? "text-success"
|
}`}
|
||||||
: "text-muted"
|
></i>
|
||||||
}`}
|
<small className="ms-1">{mod.name}</small>
|
||||||
></i>
|
|
||||||
{mod.name}
|
|
||||||
</span>
|
|
||||||
<small
|
|
||||||
className={`badge ${
|
|
||||||
mod.enabled
|
|
||||||
? "bg-success-subtle text-success"
|
|
||||||
: "bg-secondary-subtle text-muted"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{mod.enabled ? "Enabled" : "Disabled"}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
))}
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h6 className="fw-bold text-secondary mt-3 mb-2">
|
<h6 className="fw-bold text-secondary mt-3 mb-2">
|
||||||
@ -211,6 +296,26 @@ const ProcessedPayment = () => {
|
|||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<hr className="divider border-2" />
|
||||||
|
<div className="d-flex flex-column co-12">
|
||||||
|
<div className="d-flex justify-content-between">
|
||||||
|
<h6 className="fs-6 m-0">Duration</h6>
|
||||||
|
<h5 className="fs-6 m-0">
|
||||||
|
{frequencyLabel(frequency, true)}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="d-flex justify-content-between ">
|
||||||
|
<h6 className="fs-4">Total Price</h6>
|
||||||
|
<h5 className="fs-3">
|
||||||
|
{formatFigure(price, {
|
||||||
|
type: "currency",
|
||||||
|
currency: currency.currencyCode,
|
||||||
|
})}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
@ -219,8 +324,7 @@ const ProcessedPayment = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 col-md-6 hv-100 ">
|
<div className="col-12 col-md-4 mt-12 ">
|
||||||
<h6>Client Info</h6>
|
|
||||||
{clients.map((client, idx) => (
|
{clients.map((client, idx) => (
|
||||||
<div key={idx} className="text-start">
|
<div key={idx} className="text-start">
|
||||||
<div className="row g-2">
|
<div className="row g-2">
|
||||||
@ -284,8 +388,9 @@ const ProcessedPayment = () => {
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="btn btn-label-primary d-flex align-items-center me-2"
|
className="btn btn-label-primary d-flex align-items-center me-2"
|
||||||
|
onClick={() => ProcessToPayment(currentPlan?.price)}
|
||||||
>
|
>
|
||||||
Processed To Payment
|
{isPending ? "Please Wait..." : "Processed To Payment"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,19 +9,12 @@ import Label from "../common/Label";
|
|||||||
import { orgSize, reference } from "../../utils/constants";
|
import { orgSize, reference } from "../../utils/constants";
|
||||||
import DatePicker from "../common/DatePicker";
|
import DatePicker from "../common/DatePicker";
|
||||||
import { useCreateTenant, useIndustries } from "../../hooks/useTenant";
|
import { useCreateTenant, useIndustries } from "../../hooks/useTenant";
|
||||||
|
import { useCreateSelfTenant } from "../../hooks/useAuth";
|
||||||
|
|
||||||
|
const SubscriptionForm = ({currentStep,
|
||||||
|
setCurrentStep,
|
||||||
const SubscriptionForm = ({onNext}) => {
|
setStepStatus }) => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const { data, isError, isLoading: industryLoading } = useIndustries();
|
const { data, isError, isLoading: industryLoading } = useIndustries();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -33,17 +26,22 @@ const SubscriptionForm = ({onNext}) => {
|
|||||||
defaultValues: OrganizationDefaultValue,
|
defaultValues: OrganizationDefaultValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { mutate: CreateTenant, isPending } = useCreateTenant(() => {
|
const { mutate: CreateTenant, isPending } = useCreateSelfTenant(
|
||||||
// nextstep
|
(resp) => {
|
||||||
if (onNext) onNext();
|
setStepStatus((prev) => ({ ...prev, [currentStep]: "success" }));
|
||||||
});
|
setCurrentStep((prev) => prev + 1);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
setStepStatus((prev) => ({ ...prev, [currentStep]: "failed" }));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const onSubmit = (data) => {
|
const onSubmit = (data) => {
|
||||||
CreateTenant(data)
|
CreateTenant(data);
|
||||||
// reset();
|
// reset();
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="container-md">
|
<div className="container-md vh-100">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12 col-md-6">
|
<div className="col-12 col-md-6">
|
||||||
<div className="row px-4">
|
<div className="row px-4">
|
||||||
@ -157,24 +155,6 @@ const SubscriptionForm = ({onNext}) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Onboarding Date */}
|
|
||||||
<div className="col-sm-6 mb-3">
|
|
||||||
<Label htmlFor="onBoardingDate" required>
|
|
||||||
Onboarding Date
|
|
||||||
</Label>
|
|
||||||
<DatePicker
|
|
||||||
name="onBoardingDate"
|
|
||||||
control={control}
|
|
||||||
placeholder="DD-MM-YYYY"
|
|
||||||
maxDate={new Date()}
|
|
||||||
/>
|
|
||||||
{errors.onBoardingDate && (
|
|
||||||
<div className="invalid-feedback">
|
|
||||||
{errors.onBoardingDate.message}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Organization Size */}
|
{/* Organization Size */}
|
||||||
<div className="col-sm-6 mb-3">
|
<div className="col-sm-6 mb-3">
|
||||||
<Label htmlFor="organizationSize" required>
|
<Label htmlFor="organizationSize" required>
|
||||||
|
|||||||
@ -1,53 +1,67 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
const SubscriptionLayout = ({ configStep = [], currentStep ,setCurrentStep }) => {
|
const SubscriptionLayout = ({
|
||||||
|
configStep = [],
|
||||||
|
currentStep,
|
||||||
|
setCurrentStep,
|
||||||
|
stepStatus = {},
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="stepper-container my-4 ">
|
<div className="stepper-container my-4">
|
||||||
<ul className="timeline-horizontal list-unstyled d-flex justify-content-between align-items-center position-relative w-100">
|
<ul className="timeline-horizontal list-unstyled d-flex justify-content-between align-items-center position-relative w-100">
|
||||||
{configStep.map((step, index) => (
|
{configStep.map((step, index) => {
|
||||||
<li
|
const stepNumber = index + 1;
|
||||||
key={step.name}
|
const status = stepStatus[stepNumber] || "pending";
|
||||||
className="timeline-item text-center flex-fill position-relative"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className={`timeline-point mx-auto mb-2 ${
|
|
||||||
index + 1 < currentStep
|
|
||||||
? "completed"
|
|
||||||
: index + 1 === currentStep
|
|
||||||
? "active"
|
|
||||||
: ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{index + 1 < currentStep ? <i className='bx bx-check'></i>: index + 1 }
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h6
|
return (
|
||||||
className={`fw-semibold mb-0 ${
|
<li
|
||||||
index + 1 < currentStep
|
key={step.name}
|
||||||
? "text-success"
|
className="timeline-item text-center flex-fill position-relative"
|
||||||
: index + 1 === currentStep
|
|
||||||
? "text-primary"
|
|
||||||
: "text-muted"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{step.name}
|
<div
|
||||||
</h6>
|
className={`timeline-point mx-auto mb-2
|
||||||
|
${status === "success" ? "completed" : ""}
|
||||||
|
${status === "failed" ? "failed" : ""}
|
||||||
|
${stepNumber === currentStep && status !== "failed" ? "active" : ""}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{status === "failed" ? (
|
||||||
|
<i className="bx bx-x text-white"></i>
|
||||||
|
) : status === "success" ? (
|
||||||
|
<i className="bx bx-check text-white"></i>
|
||||||
|
) : (
|
||||||
|
stepNumber
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
{index !== configStep.length - 1 && (
|
<h6
|
||||||
<div className={`timeline-line-horizontal `}></div>
|
className={`fw-semibold mb-0 ${
|
||||||
)}
|
status === "success"
|
||||||
</li>
|
? "text-success"
|
||||||
))}
|
: status === "failed"
|
||||||
|
? "text-danger"
|
||||||
|
: stepNumber === currentStep
|
||||||
|
? "text-primary"
|
||||||
|
: "text-muted"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{step.name}
|
||||||
|
</h6>
|
||||||
|
|
||||||
|
{index !== configStep.length - 1 && (
|
||||||
|
<div className={`timeline-line-horizontal`}></div>
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div className="step-content mt-4">
|
<div className="step-content mt-4">
|
||||||
{configStep[currentStep - 1]?.component()}
|
{configStep[currentStep - 1]?.component()}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default SubscriptionLayout;
|
export default SubscriptionLayout;
|
||||||
|
|||||||
100
src/components/UserSubscription/VerifiedPayment.jsx
Normal file
100
src/components/UserSubscription/VerifiedPayment.jsx
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import GlobalModel from "../common/GlobalModel";
|
||||||
|
import Invoice from "./Invoice";
|
||||||
|
|
||||||
|
const VerifiedPayment = ({ onNext, responsePayment }) => {
|
||||||
|
const [isGenerateInvoice, setIsGenerateInvoice] = useState(false);
|
||||||
|
|
||||||
|
if (!responsePayment) {
|
||||||
|
return (
|
||||||
|
<div className="container-md mt-5 text-center">
|
||||||
|
<div className="d-flex flex-column align-items-center justify-content-center">
|
||||||
|
<div
|
||||||
|
className="spinner-border text-primary mb-3 p-1"
|
||||||
|
role="status"
|
||||||
|
></div>
|
||||||
|
<h4 className="text-primary mb-2">Verifying payment...</h4>
|
||||||
|
<p className="text-muted">
|
||||||
|
Please wait while we verify your transaction. Do not refresh or
|
||||||
|
close this page.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responsePayment?.success) {
|
||||||
|
onNext();
|
||||||
|
return (
|
||||||
|
<div className="container-md mt-3 text-center">
|
||||||
|
{isGenerateInvoice && (
|
||||||
|
<GlobalModel
|
||||||
|
isOpen={isGenerateInvoice}
|
||||||
|
closeModal={() => setIsGenerateInvoice(false)}
|
||||||
|
>
|
||||||
|
<Invoice invoiceData={responsePayment?.data} />
|
||||||
|
</GlobalModel>
|
||||||
|
)}
|
||||||
|
<div className="d-flex align-items-center justify-content-center">
|
||||||
|
<span className="bg-success p-2 p-md-3 rounded-circle">
|
||||||
|
<i className="bx bx-check fs-2 fw-bold text-white"></i>
|
||||||
|
</span>
|
||||||
|
<span className="fs-3 fs-md-2 ms-3 text-success">
|
||||||
|
Payment Successful!
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-muted mb-4 fs-6 fs-md-5 text-center mt-3">
|
||||||
|
Thank you for your payment. Your <strong>subscription</strong> has
|
||||||
|
been successfully activated.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* <div className="row justify-content-center">
|
||||||
|
<div className="col-12 col-sm-10 col-md-8 bg-white rounded-4 p-3 p-md-4 text-start mb-4 shadow-sm">
|
||||||
|
<h5 className="fw-bold mb-3 text-secondary">
|
||||||
|
Subscription Details
|
||||||
|
</h5>
|
||||||
|
<ul className="list-unstyled mb-0">
|
||||||
|
<li className="mb-2 d-flex justify-content-between">
|
||||||
|
<span>Plan Name:</span>
|
||||||
|
<strong>Premium Plan</strong>
|
||||||
|
</li>
|
||||||
|
<li className="mb-2 d-flex justify-content-between">
|
||||||
|
<span>Amount Paid:</span>
|
||||||
|
<strong>₹999.00</strong>
|
||||||
|
</li>
|
||||||
|
<li className="mb-2 d-flex justify-content-between">
|
||||||
|
<span>Payment ID:</span>
|
||||||
|
<strong>{responsePayment?.paymentId}</strong>
|
||||||
|
</li>
|
||||||
|
<li className="mb-2 d-flex justify-content-between">
|
||||||
|
<span>Activation Date:</span>
|
||||||
|
<strong>{new Date().toLocaleDateString()}</strong>
|
||||||
|
</li>
|
||||||
|
<li className="d-flex justify-content-between">
|
||||||
|
<span>Expiry Date:</span>
|
||||||
|
<strong>27 Nov 2025</strong>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
<div className="d-flex flex-column flex-md-row justify-content-center gap-3">
|
||||||
|
<a href="/" className="btn btn-info px-4 py-2 fw-semibold">
|
||||||
|
Go to Dashboard
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
|
className="btn btn-outline-primary px-4 py-2 fw-semibold"
|
||||||
|
onClick={() => setIsGenerateInvoice(true)}
|
||||||
|
>
|
||||||
|
Generate Invoice
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VerifiedPayment;
|
||||||
@ -11,8 +11,10 @@ import { useDispatch, useSelector } from "react-redux";
|
|||||||
import {
|
import {
|
||||||
closeAuthModal,
|
closeAuthModal,
|
||||||
openAuthModal,
|
openAuthModal,
|
||||||
|
setSelfTenant,
|
||||||
} from "../slices/localVariablesSlice.jsx";
|
} from "../slices/localVariablesSlice.jsx";
|
||||||
import { removeSession } from "../utils/authUtils.js";
|
import { removeSession } from "../utils/authUtils.js";
|
||||||
|
import showToast from "../services/toastService.tsx";
|
||||||
|
|
||||||
// ----------------------------Modal--------------------------
|
// ----------------------------Modal--------------------------
|
||||||
|
|
||||||
@ -76,6 +78,30 @@ export const useSelectTenant = (onSuccessCallBack) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useCreateSelfTenant = (onSuccessCallBack, onFailureCallBack) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async (payload) => {
|
||||||
|
const resp = await AuthRepository.createSuscription(payload);
|
||||||
|
return resp.data;
|
||||||
|
},
|
||||||
|
onSuccess: (response, variables) => {
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
setSelfTenant({
|
||||||
|
tenantEnquireId: response?.tenantEnquireId,
|
||||||
|
planId: null,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (onSuccessCallBack) onSuccessCallBack(response);
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
showToast("Somthing worng went happend", "error");
|
||||||
|
if (onFailureCallBack) onFailureCallBack();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const useAuthModal = () => {
|
export const useAuthModal = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { isOpen } = useSelector((state) => state.localVariables.AuthModal);
|
const { isOpen } = useSelector((state) => state.localVariables.AuthModal);
|
||||||
|
|||||||
@ -1,36 +1,188 @@
|
|||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
import { PaymentRepository } from "../repositories/PaymentRepository";
|
import { PaymentRepository } from "../repositories/PaymentRepository";
|
||||||
|
import showToast from "../services/toastService";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
export const useMakePayment = (onSuccessCallBack) => {
|
export function removeRazorpayArtifacts() {
|
||||||
const client = useQueryClient();
|
try {
|
||||||
return useMutation({
|
document
|
||||||
mutationFn: (payload) => PaymentRepository.makePayment(payload),
|
.querySelectorAll("iframe[src*='razorpay'], iframe[name^='__PRIVATE']")
|
||||||
onSuccess: (_, varibales) => {
|
.forEach((iframe) => iframe.remove());
|
||||||
if (onSuccessCallBack) onSuccessCallBack();
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
showToast(
|
|
||||||
error.message ||
|
|
||||||
error.response.message ||
|
|
||||||
"Something went wrong.Please try again later.",
|
|
||||||
"error"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useVerifyPayment = () => {
|
document
|
||||||
|
.querySelectorAll(
|
||||||
|
"div.razorpay-container, div[class*='razorpay-backdrop'], div[style*='z-index: 1040'], div[style*='z-index: 9999']"
|
||||||
|
)
|
||||||
|
.forEach((el) => el.remove());
|
||||||
|
Array.from(document.querySelectorAll("body > div")).forEach((div) => {
|
||||||
|
const html = div.outerHTML || "";
|
||||||
|
if (
|
||||||
|
html.includes("razorpay-container") ||
|
||||||
|
html.includes("Test Mode") ||
|
||||||
|
html.includes("razorpay-backdrop")
|
||||||
|
) {
|
||||||
|
div.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.removeAttribute("style");
|
||||||
|
document.body.style.overflow = "";
|
||||||
|
document.body.style.position = "";
|
||||||
|
document.body.style.height = "";
|
||||||
|
document.body.style.pointerEvents = "auto";
|
||||||
|
|
||||||
|
document.documentElement.style.overflow = "";
|
||||||
|
document.documentElement.style.removeProperty("overflow");
|
||||||
|
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(" Error while cleaning Razorpay artifacts:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeRazorpayPopup() {
|
||||||
|
try {
|
||||||
|
if (window.Razorpay && typeof window.Razorpay.close === "function") {
|
||||||
|
window.Razorpay.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(removeRazorpayArtifacts, 600);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(" Error closing Razorpay popup:", err);
|
||||||
|
removeRazorpayArtifacts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useVerifyPayment = (onSuccessCallBack, onFailureCallBack) => {
|
||||||
const client = useQueryClient();
|
const client = useQueryClient();
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: (payload) => PaymentRepository.verifyPayment(payload),
|
mutationFn: (payload) => PaymentRepository.verifyPayment(payload),
|
||||||
onSuccess: (_, varibales) => {
|
|
||||||
if (onSuccessCallBack) onSuccessCallBack();
|
onSuccess: (data) => {
|
||||||
|
if (onSuccessCallBack) onSuccessCallBack(data);
|
||||||
},
|
},
|
||||||
|
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
|
if (onFailureCallBack) onFailureCallBack(error);
|
||||||
showToast(
|
showToast(
|
||||||
error.message ||
|
error?.message ||
|
||||||
error.response.message ||
|
error?.response?.message ||
|
||||||
"Something went wrong.Please try again later.",
|
"Something went wrong. Please try again later.",
|
||||||
|
"error"
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useMakePayment = (
|
||||||
|
onSuccessCallBack,
|
||||||
|
onFailureCallBack,
|
||||||
|
currentPlan
|
||||||
|
) => {
|
||||||
|
const client = useQueryClient();
|
||||||
|
const { tenantEnquireId, planId } = useSelector(
|
||||||
|
(store) => store.localVariables.selfTenant
|
||||||
|
);
|
||||||
|
const { mutate: verifyPayment } = useVerifyPayment(
|
||||||
|
(response) => {
|
||||||
|
if (onSuccessCallBack) onSuccessCallBack(response);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
if (onFailureCallBack) onFailureCallBack(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (payload) => PaymentRepository.makePayment(payload),
|
||||||
|
|
||||||
|
onSuccess: (data) => {
|
||||||
|
const orderId = data?.data?.orderId;
|
||||||
|
const key = data?.data?.key;
|
||||||
|
|
||||||
|
if (!orderId || !key) {
|
||||||
|
showToast("Invalid Razorpay order details.", "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
key,
|
||||||
|
amount: (currentPlan?.amount ?? 1) * 100,
|
||||||
|
currency: currentPlan?.currency?.currencyCode || "INR",
|
||||||
|
name: "MarcoAIOT Subscription",
|
||||||
|
order_id: orderId,
|
||||||
|
|
||||||
|
handler: async (response) => {
|
||||||
|
try {
|
||||||
|
const payload = {
|
||||||
|
tenantEnquireId: tenantEnquireId,
|
||||||
|
planId: planId,
|
||||||
|
orderId: response.razorpay_order_id,
|
||||||
|
paymentId: response.razorpay_payment_id,
|
||||||
|
signature: response.razorpay_signature,
|
||||||
|
};
|
||||||
|
verifyPayment(payload);
|
||||||
|
} finally {
|
||||||
|
closeRazorpayPopup();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
prefill: {
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
contact: "",
|
||||||
|
},
|
||||||
|
|
||||||
|
theme: { color: "#ea3b0fff" },
|
||||||
|
|
||||||
|
modal: {
|
||||||
|
ondismiss: () => {
|
||||||
|
if (onFailureCallBack) {
|
||||||
|
onFailureCallBack({
|
||||||
|
status: "failed",
|
||||||
|
message: "Payment was cancelled before completion.",
|
||||||
|
reason: "popup_closed",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
closeRazorpayPopup();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
setTimeout(() => {
|
||||||
|
const razorpay = new window.Razorpay(options);
|
||||||
|
|
||||||
|
razorpay.on("payment.failed", (response) => {
|
||||||
|
if (onFailureCallBack) {
|
||||||
|
onFailureCallBack({
|
||||||
|
status: "failed",
|
||||||
|
message: response.error?.description || "Payment failed.",
|
||||||
|
error: response.error,
|
||||||
|
reason: "transaction_failed",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
closeRazorpayPopup();
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
razorpay.open();
|
||||||
|
} catch (err) {
|
||||||
|
alert("This browser is not supported. Please try another browser.");
|
||||||
|
closeRazorpayPopup();
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
} catch (err) {
|
||||||
|
alert("This browser is not supported. Please try another browser.");
|
||||||
|
closeRazorpayPopup();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onError: (error) => {
|
||||||
|
showToast(
|
||||||
|
error?.message ||
|
||||||
|
error?.response?.message ||
|
||||||
|
"Something went wrong. Please try again later.",
|
||||||
"error"
|
"error"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -13,9 +13,9 @@ export const OrganizationSchema = z.object({
|
|||||||
/^[+]?[(]?[0-9]{1,4}[)]?[-\s./0-9]*$/,
|
/^[+]?[(]?[0-9]{1,4}[)]?[-\s./0-9]*$/,
|
||||||
"Invalid phone number format"
|
"Invalid phone number format"
|
||||||
),
|
),
|
||||||
onBoardingDate: z.coerce
|
// onBoardingDate: z.coerce
|
||||||
.date()
|
// .date()
|
||||||
.refine((d) => !Number.isNaN(d.getTime()), { message: "Invalid date" }),
|
// .refine((d) => !Number.isNaN(d.getTime()), { message: "Invalid date" }),
|
||||||
organizationSize: z.string().min(1, "Organization Size is required"),
|
organizationSize: z.string().min(1, "Organization Size is required"),
|
||||||
industryId: z.string().uuid("Industry is required"),
|
industryId: z.string().uuid("Industry is required"),
|
||||||
reference: z.string().min(1,{message:"Reference is required"}),
|
reference: z.string().min(1,{message:"Reference is required"}),
|
||||||
|
|||||||
@ -3,29 +3,70 @@ import React, { useState, useMemo } from "react";
|
|||||||
import SubscriptionLayout from "../../components/UserSubscription/SubscriptionLayout";
|
import SubscriptionLayout from "../../components/UserSubscription/SubscriptionLayout";
|
||||||
import SubscriptionForm from "../../components/UserSubscription/SubscriptionForm";
|
import SubscriptionForm from "../../components/UserSubscription/SubscriptionForm";
|
||||||
import ProcessedPayment from "../../components/UserSubscription/ProcessedPayment";
|
import ProcessedPayment from "../../components/UserSubscription/ProcessedPayment";
|
||||||
|
import VerifiedPayment from "../../components/UserSubscription/VerifiedPayment";
|
||||||
|
|
||||||
const MakeSubscription = () => {
|
const MakeSubscription = () => {
|
||||||
const [currentStep, setCurrentStep] = useState(2);
|
const [currentStep, setCurrentStep] = useState(1);
|
||||||
|
const [responsePayment, setResponsePayment] = useState(null);
|
||||||
|
|
||||||
|
const [stepStatus, setStepStatus] = useState({
|
||||||
|
1: "success",
|
||||||
|
2: "pending",
|
||||||
|
3: "pending",
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleVerification = (resp) => {
|
||||||
|
setResponsePayment(resp);
|
||||||
|
if (resp?.success) {
|
||||||
|
setStepStatus((prev) => ({ ...prev, 2: "success", 3: "success" }));
|
||||||
|
setCurrentStep(3);
|
||||||
|
} else {
|
||||||
|
setStepStatus((prev) => ({ ...prev, 2: "failed" }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const checkOut_Steps = [
|
const checkOut_Steps = [
|
||||||
{
|
{
|
||||||
name: "Client Info",
|
name: "Client Info",
|
||||||
component: () => <SubscriptionForm onNext={() => setCurrentStep(prev => prev + 1)}/>,
|
component: () => (
|
||||||
|
<SubscriptionForm
|
||||||
|
currentStep={currentStep}
|
||||||
|
setCurrentStep={setCurrentStep}
|
||||||
|
setStepStatus={setStepStatus}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Payment",
|
name: "Payment",
|
||||||
component: () =><ProcessedPayment onNext={() => setCurrentStep(prev => prev + 1)}/>,
|
component: () => (
|
||||||
|
<ProcessedPayment
|
||||||
|
onNext={(resp) => handleVerification(resp)}
|
||||||
|
onFail={() => setStepStatus((prev) => ({ ...prev, 2: "failed" }))}
|
||||||
|
resetPaymentStep={() =>
|
||||||
|
setStepStatus((prev) => ({ ...prev, 2: "pending" }))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Verified",
|
name: "Verified",
|
||||||
component: () => <div>Verified</div>,
|
component: () => (
|
||||||
|
<VerifiedPayment
|
||||||
|
onNext={(prev) => ({ ...prev, 4: "success" })}
|
||||||
|
responsePayment={responsePayment}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container-fluid bg-light-secondary min-vh-100 p-2">
|
<div className="container-fluid bg-light-secondary min-vh-100 p-2">
|
||||||
<SubscriptionLayout configStep={checkOut_Steps}
|
<SubscriptionLayout
|
||||||
|
configStep={checkOut_Steps}
|
||||||
currentStep={currentStep}
|
currentStep={currentStep}
|
||||||
setCurrentStep={setCurrentStep}/>
|
setCurrentStep={setCurrentStep}
|
||||||
|
stepStatus={stepStatus}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,6 +12,7 @@ const AuthRepository = {
|
|||||||
sendMail: (data) => api.postPublic("/api/auth/sendmail", data),
|
sendMail: (data) => api.postPublic("/api/auth/sendmail", data),
|
||||||
getSubscription: (frequency) =>
|
getSubscription: (frequency) =>
|
||||||
api.getPublic(`/api/market/list/subscription-plan?frequency=${frequency}`),
|
api.getPublic(`/api/market/list/subscription-plan?frequency=${frequency}`),
|
||||||
|
createSuscription:(data)=>api.post(`/api/Tenant/self/create`,data),
|
||||||
|
|
||||||
// Protected routes (require auth token)
|
// Protected routes (require auth token)
|
||||||
logout: (data) => api.post("/api/auth/logout", data),
|
logout: (data) => api.post("/api/auth/logout", data),
|
||||||
|
|||||||
@ -2,6 +2,6 @@ import { api } from "../utils/axiosClient";
|
|||||||
|
|
||||||
|
|
||||||
export const PaymentRepository = {
|
export const PaymentRepository = {
|
||||||
makePayment: () => api.post(`/api/Payment/create-order`),
|
makePayment: (payload) => api.post(`/api/Payment/create-order`,payload),
|
||||||
verifyPayment: () => api.post(`/api/Payment/verify-payment`),
|
verifyPayment: (payload) => api.post(`/api/Payment/verify-payment`,payload),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -31,6 +31,11 @@ const localVariablesSlice = createSlice({
|
|||||||
AuthModal: {
|
AuthModal: {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
selfTenant: {
|
||||||
|
tenantEnquireId: null,
|
||||||
|
planId: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
reducers: {
|
reducers: {
|
||||||
changeMaster: (state, action) => {
|
changeMaster: (state, action) => {
|
||||||
@ -96,6 +101,12 @@ const localVariablesSlice = createSlice({
|
|||||||
const { modalType } = action.payload;
|
const { modalType } = action.payload;
|
||||||
state.modals[modalType].isOpen = !state.modals[modalType].isOpen;
|
state.modals[modalType].isOpen = !state.modals[modalType].isOpen;
|
||||||
},
|
},
|
||||||
|
setSelfTenant: (state, action) => {
|
||||||
|
state.selfTenant.tenantEnquireId =
|
||||||
|
action.payload.tenantEnquireId ?? state.selfTenant.tenantEnquireId;
|
||||||
|
state.selfTenant.planId =
|
||||||
|
action.payload.planId ?? state.selfTenant.planId;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,6 +121,10 @@ export const {
|
|||||||
toggleOrgModal,
|
toggleOrgModal,
|
||||||
openAuthModal,
|
openAuthModal,
|
||||||
closeAuthModal,
|
closeAuthModal,
|
||||||
setOrganization,openModal, closeModal, toggleModal
|
setOrganization,
|
||||||
|
openModal,
|
||||||
|
closeModal,
|
||||||
|
toggleModal,
|
||||||
|
setSelfTenant,
|
||||||
} = localVariablesSlice.actions;
|
} = localVariablesSlice.actions;
|
||||||
export default localVariablesSlice.reducer;
|
export default localVariablesSlice.reducer;
|
||||||
|
|||||||
@ -136,16 +136,16 @@ export const formatFigure = (
|
|||||||
return new Intl.NumberFormat(locale, formatterOptions).format(amount);
|
return new Intl.NumberFormat(locale, formatterOptions).format(amount);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const frequencyLabel = (freq) => {
|
export const frequencyLabel = (freq,isLong=false) => {
|
||||||
switch (freq) {
|
switch (freq) {
|
||||||
case 0:
|
case 0:
|
||||||
return "1 mo";
|
return isLong ? "1 Month" : "1 mo";
|
||||||
case 1:
|
case 1:
|
||||||
return "3 mo";
|
return isLong ? "3 Months" : "3 mo";
|
||||||
case 2:
|
case 2:
|
||||||
return "6 mo";
|
return isLong ? "6 Months" : "6 mo";
|
||||||
case 3:
|
case 3:
|
||||||
return "1 yr";
|
return isLong ? "1 Year" : "1 yr";
|
||||||
default:
|
default:
|
||||||
return "mo";
|
return "mo";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user