diff --git a/package-lock.json b/package-lock.json index 19f9a9db..2d72a7c1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,11 +20,14 @@ "aos": "^2.3.4", "axios": "^1.7.2", "cors": "^2.8.5", + "docx": "^8.5.0", "dotenv": "^16.4.5", "emoji-picker-react": "^4.11.1", + "file-saver": "^2.0.5", "formik": "^2.4.6", "html-webpack-plugin": "^5.6.0", - "js-cookie": "^3.0.5", + "jspdf": "^2.5.1", + "jspdf-autotable": "^3.8.2", "jwt-decode": "^4.0.0", "mini-css-extract-plugin": "^2.9.0", "papaparse": "^5.4.1", @@ -8131,6 +8134,13 @@ "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/range-parser": { "version": "1.2.7", "dev": true, @@ -9446,6 +9456,18 @@ "version": "0.4.0", "license": "MIT" }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "dev": true, @@ -9755,6 +9777,16 @@ "devOptional": true, "license": "MIT" }, + "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", + "optional": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "dev": true, @@ -10627,6 +10659,18 @@ "node-int64": "^0.4.0" } }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/buffer": { "version": "5.7.1", "dev": true, @@ -10837,6 +10881,33 @@ "node": ">=6" } }, + "node_modules/canvg": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", + "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", + "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/canvg/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT", + "optional": true + }, "node_modules/case-sensitive-paths-webpack-plugin": { "version": "2.4.0", "dev": true, @@ -11508,6 +11579,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/core-js": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz", + "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-js-compat": { "version": "3.37.1", "dev": true, @@ -11522,7 +11605,6 @@ }, "node_modules/core-util-is": { "version": "1.0.3", - "dev": true, "license": "MIT" }, "node_modules/cors": { @@ -11747,6 +11829,16 @@ "node": ">=4" } }, + "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", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/css-loader": { "version": "7.1.2", "dev": true, @@ -12804,6 +12896,40 @@ "node": ">=6.0.0" } }, + "node_modules/docx": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/docx/-/docx-8.5.0.tgz", + "integrity": "sha512-4SbcbedPXTciySXiSnNNLuJXpvxFe5nqivbiEHXyL8P/w0wx2uW7YXNjnYgjW0e2e6vy+L/tMISU/oAiXCl57Q==", + "license": "MIT", + "dependencies": { + "@types/node": "^20.3.1", + "jszip": "^3.10.1", + "nanoid": "^5.0.4", + "xml": "^1.0.1", + "xml-js": "^1.6.8" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/docx/node_modules/nanoid": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.7.tgz", + "integrity": "sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/dom-accessibility-api": { "version": "0.5.16", "dev": true, @@ -12870,6 +12996,13 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz", + "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optional": true + }, "node_modules/domutils": { "version": "2.8.0", "license": "BSD-2-Clause", @@ -15051,6 +15184,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==", + "license": "MIT" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "dev": true, @@ -15101,6 +15240,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==", + "license": "MIT" + }, "node_modules/file-system-cache": { "version": "2.3.0", "dev": true, @@ -16449,6 +16594,20 @@ } } }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "optional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/htmlparser2": { "version": "6.1.0", "funding": [ @@ -17025,6 +17184,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/immer": { "version": "10.1.1", "license": "MIT", @@ -17165,7 +17330,6 @@ }, "node_modules/inherits": { "version": "2.0.4", - "devOptional": true, "license": "ISC" }, "node_modules/ini": { @@ -17883,7 +18047,6 @@ }, "node_modules/isarray": { "version": "1.0.0", - "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -19982,14 +20145,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", - "engines": { - "node": ">=14" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "license": "MIT" @@ -20277,6 +20432,33 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jspdf": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", + "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.14.0", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "fflate": "^0.4.8" + }, + "optionalDependencies": { + "canvg": "^3.0.6", + "core-js": "^3.6.0", + "dompurify": "^2.2.0", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jspdf-autotable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.8.2.tgz", + "integrity": "sha512-zW1ix99/mtR4MbIni7IqvrpfHmuTaICl6iv6wqjRN86Nxtwaw/QtOeDbpXqYSzHIJK9JvgtLM283sc5x+ipkJg==", + "license": "MIT", + "peerDependencies": { + "jspdf": "^2.5.1" + } + }, "node_modules/jsprim": { "version": "1.4.2", "dev": true, @@ -20305,6 +20487,54 @@ "node": ">=4.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/junk": { "version": "3.1.0", "dev": true, @@ -20412,6 +20642,15 @@ "node": ">= 0.8.0" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "license": "MIT" @@ -22116,7 +22355,7 @@ }, "node_modules/performance-now": { "version": "2.1.0", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/picocolors": { @@ -22541,7 +22780,6 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", - "dev": true, "license": "MIT" }, "node_modules/prompts": { @@ -22789,6 +23027,16 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==" }, + "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/ramda": { "version": "0.29.0", "dev": true, @@ -24400,6 +24648,16 @@ "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": { "version": "2.7.1", "dev": true, @@ -24598,6 +24856,12 @@ "node_modules/save-dev": { "version": "0.0.1-security" }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, "node_modules/saxes": { "version": "6.0.0", "dev": true, @@ -24909,6 +25173,12 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", "dev": true, @@ -25271,6 +25541,16 @@ "node": ">=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/statuses": { "version": "2.0.1", "dev": true, @@ -25688,6 +25968,16 @@ "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/svgo": { "version": "2.8.0", "dev": true, @@ -26011,6 +26301,16 @@ "node": "*" } }, + "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", + "optional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -27011,7 +27311,6 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "devOptional": true, "license": "MIT" }, "node_modules/utila": { @@ -27026,6 +27325,16 @@ "node": ">= 0.4.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", + "optional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "8.3.2", "dev": true, @@ -28010,6 +28319,24 @@ "node": ">=0.8" } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "license": "MIT" + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/xml-name-validator": { "version": "4.0.0", "dev": true, diff --git a/package.json b/package.json index 193a45f6..27b8842c 100644 --- a/package.json +++ b/package.json @@ -22,11 +22,14 @@ "aos": "^2.3.4", "axios": "^1.7.2", "cors": "^2.8.5", + "docx": "^8.5.0", "dotenv": "^16.4.5", "emoji-picker-react": "^4.11.1", + "file-saver": "^2.0.5", "formik": "^2.4.6", "html-webpack-plugin": "^5.6.0", - "js-cookie": "^3.0.5", + "jspdf": "^2.5.1", + "jspdf-autotable": "^3.8.2", "jwt-decode": "^4.0.0", "mini-css-extract-plugin": "^2.9.0", "papaparse": "^5.4.1", diff --git a/src/assets/styles/SellerLayout.scss b/src/assets/styles/SellerLayout.scss index 7074f724..b9a9c9fe 100644 --- a/src/assets/styles/SellerLayout.scss +++ b/src/assets/styles/SellerLayout.scss @@ -73,20 +73,20 @@ gap: 3rem; .text_content { - color: $text-color; - font-size: 1.8rem; - text-decoration: none; - padding: 1rem; - border-radius: .5rem; - transition: background-color 0.3s, color 0.3s; - display: block; - - - &:hover { - background-color: $menu-hover; - color: $white !important; - width: 15rem !important ; - } + color: $text-color; + font-size: 1.8rem; + text-decoration: none; + padding: 1rem; + border-radius: .5rem; + transition: background-color 0.3s, color 0.3s; + display: block; + + + &:hover { + background-color: $menu-hover; + color: $white !important; + width: 15rem !important; + } } } @@ -96,20 +96,20 @@ margin-bottom: 3rem; .text_content { - color: $text-color; - font-size: 1.9rem; - text-decoration: none; - padding: 1rem; - border-radius: .5rem; - transition: background-color 0.3s, color 0.3s; - display: block; - - &:hover { - background-color: $menu-hover; - color: $white !important; - width: 15rem; - } + color: $text-color; + font-size: 1.9rem; + text-decoration: none; + padding: 1rem; + border-radius: .5rem; + transition: background-color 0.3s, color 0.3s; + display: block; + + &:hover { + background-color: $menu-hover; + color: $white !important; + width: 15rem; } + } } } @@ -125,151 +125,161 @@ } .main__seller__content__dashboard { - display: flex; - flex-direction: column; - flex: 1; - max-height: 100vh; + display: flex; + flex-direction: column; + flex: 1; + max-height: 100vh; } .main__seller__dashboard { + display: flex; + flex: 1; + width: 100%; + min-height: calc(100vh - 120px); + max-height: calc(100vh - 120px); + background-color: $container-color; + padding: 20px; + + .outlet { + background-color: white; + flex: 0 0 60%; + border-radius: 20px; + min-height: 95%; + max-height: 95%; + min-width: 70%; + max-width: 70%; + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); + padding: 2rem; + overflow-y: scroll; + scroll-behavior: smooth; + + &::-webkit-scrollbar { + display: none; + } + } + + .right__side { + flex: 0 0 20%; + min-width: 20%; + max-width: 20%; + min-height: 100%; + max-height: 100%; display: flex; - flex: 1; - width: 100%; - min-height: calc(100vh - 120px); - max-height: calc(100vh - 120px); - background-color: $container-color; - padding: 20px; + flex-direction: column; + gap: 25px; + padding: 0 20px; - .outlet { - background-color: white; - flex: 0 0 60%; - border-radius: 20px; - min-height: 95%; - max-height: 95%; - min-width: 70%; - max-width: 70%; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); - padding: 2rem; - overflow-y: scroll; - scroll-behavior: smooth; - - &::-webkit-scrollbar { - display: none; + .right-profile { + background-color: $white-color; + height: 40%; + border-radius: 20px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); + padding: 2rem; + + .profile-image { + border-radius: 50%; + height: 6rem; + border: 0.2rem solid #FF6D18; + width: 6rem; + object-fit: cover; + margin-bottom: 1rem; + } + + .profile-name { + font-size: 1.8rem; + font-weight: 600; + color: $text-color; + margin: 0; + } + + .profile-edit { + font-size: 1.4rem; + color: $text-color; + background-color: #ffede2; + margin: 0; + cursor: pointer; + border: none; + color: $primary-color; + border-radius: 2rem; + padding: 0.5rem 1.8rem; + margin-top: 1rem; + font-size: 1.4rem; + + .icon-edit { + color: $primary-color; + margin-left: 1rem; + } + } + + .progress-bar-container { + display: flex; + align-items: center; + font-size: 1.4rem; + margin-top: 1rem; + color: $text-color; + + .order-progress { + color: $primary-color; + margin-left: 0.5rem; + margin-right: 0.5rem; } + } + + .progress-bar { + width: 3rem; + height: 1rem; + background-color: #e0e0e0; + border-radius: 0.5rem; + overflow: hidden; + } + + .progress-bar-fill { + height: 100%; + transition: width 0.3s ease; + } } - .right__side { - flex: 0 0 20%; - min-width: 20%; - max-width: 20%; - min-height: 100%; - max-height: 100%; + .right-products { + .loader { display: flex; - flex-direction: column; - gap: 25px; - padding: 0 20px; + justify-content: center; + align-items: center; + height: 50vh; + } - .right-profile { - background-color: $white-color; - height: 40%; - border-radius: 20px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); - padding: 2rem; - .profile-image { - border-radius: 50%; - height: 6rem; - border: 0.2rem solid #FF6D18; - width: 6rem; - object-fit: cover; - margin-bottom: 1rem; - } - .profile-name { - font-size: 1.8rem; - font-weight: 600; - color: $text-color; - margin: 0; - } - .profile-edit { - font-size: 1.4rem; - color: $text-color; - background-color: #ffede2; - margin: 0; - cursor: pointer; - border: none; - color: $primary-color; - border-radius: 2rem; - padding: 0.5rem 1.8rem; - margin-top: 1rem; - font-size: 1.4rem; - .icon-edit { - color: $primary-color; - margin-left: 1rem; - } - } - .progress-bar-container { - display: flex; - align-items: center; - font-size: 1.4rem; - margin-top: 1rem; - color: $text-color; - .order-progress { - color: $primary-color; - margin-left: 0.5rem; - margin-right: 0.5rem; - } - } - - .progress-bar { - width: 3rem; - height: 1rem; - background-color: #e0e0e0; - border-radius: 0.5rem; - overflow: hidden; - } - - .progress-bar-fill { - height: 100%; - transition: width 0.3s ease; - } - } + background-color: $white-color; + height: 60%; + overflow-y: scroll; + scroll-behavior: smooth; + border-radius: 20px; + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); + padding: 1rem; - .right-products { - .loader { - display: flex; - justify-content: center; - align-items: center; - height: 50vh; - } - background-color: $white-color; - height: 60%; - overflow-y: scroll; - scroll-behavior: smooth; - border-radius: 20px; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1); - padding: 1rem; - &::-webkit-scrollbar { - display: none; - } - .right-header { - font-size: 1.4rem; - color: #000; - } - .product-header{ - display: flex; - justify-content: space-between; - align-items: center; - padding: 0.3rem 0.9rem; - border-radius: 2rem; - margin-top: 1rem; - background-color: #d9d9d9; - color: #FF6D18; - } - } + &::-webkit-scrollbar { + display: none; + } + + .right-header { + font-size: 1.4rem; + color: #000; + } + + .product-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.3rem 0.9rem; + border-radius: 2rem; + margin-top: 1rem; + background-color: #d9d9d9; + color: #FF6D18; + } } + } } } @@ -282,128 +292,192 @@ width: 100%; gap: 30px; - .statisticCards { + .statisticCards { + display: flex; + justify-content: center; + align-items: center; + flex-wrap: wrap; + + .card { + transition: margin-top 0.3s ease; + } + + .card:hover { + margin-top: -20px; + } + } + + .chart-container { + width: 95%; + height: auto; + border-radius: 30px; + background-color: #fff; + overflow: hidden; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); + + + .chart-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 20px; + background-color: #fff; + border-bottom: 1px solid #e0e0e0; + + .sub-header { display: flex; - justify-content: center; - align-items: center; - flex-wrap: wrap; + flex-direction: column; + gap: 10px; - .card { - transition: margin-top 0.3s ease; + h1 { + margin-left: 2%; } - .card:hover { - margin-top: -20px; + .legend { + display: flex; + align-items: center; + flex-direction: row; + gap: 20px; + + .dot { + height: 10px; + width: 10px; + border-radius: 50%; + + &.completed { + background-color: #ff7300; + } + + &.cancelled { + background-color: #bfbfbf; + } + } } } - .chart-container { - width: 95%; - height: auto; - border-radius: 30px; - background-color: #fff; - overflow: hidden; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3); - .chart-header { + .export-section { display: flex; - justify-content: space-between; - align-items: center; - padding: 10px 20px; - background-color: #fff; - border-bottom: 1px solid #e0e0e0; - .sub-header { - display: flex; - flex-direction: column; - gap: 10px; - h1 { - margin-left: 2%; + gap: 10px; + + .monthDropDown { + .dropdown-button { + background-color: #ff7300; + color: #fff; + border: none; + padding: 5px 10px; + border-radius: 5px; + cursor: pointer; + font-size: 14px; + + .arrow-down { + margin-left: 5px; + } } - .legend { - display: flex; - align-items: center; - flex-direction: row; - gap: 20px; + } - .dot { - height: 10px; - width: 10px; - border-radius: 50%; + .export-dropdown { + position: relative; - &.completed { - background-color: #ff7300; - } + .export-btn { + background-color: #0f8615; + color: #fff; + border: none; + padding: 5px 10px; + border-radius: 5px; + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + gap: 4px; - &.cancelled { - background-color: #bfbfbf; - } + .arrow-down { + margin-left: 5px; } } - } - .export-section{ - display: flex; - gap: 10px; - .monthDropDown { - .dropdown-button { - background-color: #ff7300; - color: #fff; - border: none; - padding: 5px 10px; - border-radius: 5px; + .export-menu { + position: absolute; + top: 100%; + right: 0; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 5px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + list-style-type: none; + padding: 0; + margin: 5px 0 0; + z-index: 1000; + + li { + padding: 8px 15px; cursor: pointer; + display: flex; + align-items: center; + gap: 8px; font-size: 14px; - - .arrow-down { - margin-left: 5px; + color: #333; + + &:hover { + background-color: #f5f5f5; + } + + svg { + font-size: 16px; + } + + &:nth-child(1) svg { + color: #217346; // Excel green + } + + &:nth-child(2) svg { + color: #888888; // CSV gray + } + + &:nth-child(3) svg { + color: #F40F02; // PDF red + } + + &:nth-child(4) svg { + color: #2B579A; // Word blue } } } - .export-btn{ - background-color: #0f8615; - color: #fff; - border: none; - padding: 5px 10px; - border-radius: 5px; - cursor: pointer; - font-size: 14px; - display: flex; - gap: 4px; - } } - } + } + } } @media (max-width: 1024px) { .seller__wrapper { - .left__side { - width: 6.5rem; + .left__side { + width: 6.5rem; - .dashboard__items { - display: none; - } + .dashboard__items { + display: none; } + } - .main__seller__content__dashboard { - flex: 1; - padding: auto; - padding-left: 0px; - } + .main__seller__content__dashboard { + flex: 1; + padding: auto; + padding-left: 0px; + } - .main__seller__dashboard { - padding: 12px; + .main__seller__dashboard { + padding: 12px; - .outlet { - max-width: calc(100vw - 3.5rem); - overflow-y: scroll; - } + .outlet { + max-width: calc(100vw - 3.5rem); + overflow-y: scroll; + } - .right__side { - display: none; - } + .right__side { + display: none; } + } } } diff --git a/src/assets/styles/SellerRegistration.scss b/src/assets/styles/SellerRegistration.scss index 38d5206d..65ddb076 100644 --- a/src/assets/styles/SellerRegistration.scss +++ b/src/assets/styles/SellerRegistration.scss @@ -142,6 +142,8 @@ .check-group{ display: flex; flex-direction: row; + gap: 1rem; + align-items: center; input[type="checkbox"] { appearance: none; @@ -173,8 +175,13 @@ } } label { - margin-left: .2rem; + margin: 0; font-size: 1.5rem; + .btn-link{ + color: $primary-color; + cursor: pointer; + + } } } .form-control { diff --git a/src/assets/styles/Settings.scss b/src/assets/styles/Settings.scss index c205f121..28932fe5 100644 --- a/src/assets/styles/Settings.scss +++ b/src/assets/styles/Settings.scss @@ -214,56 +214,6 @@ .viewer{ display: flex; } - - .view__pdf{ - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.453); - z-index: 10000; - - .close__icon{ - position: absolute; - top: 2rem; - right: 2rem; - font-size: 3rem; - cursor: pointer; - color: $white-color; - &:hover{ - color: $red-color; - transform: scale(1.1); - transition: all 0.5s ease-in-out; - } - } - } - - .pageNumber{ - display: flex; - justify-content: center; - align-items: center; - - button{ - background-color: transparent; - width: 6rem; - height: 6rem; - .pageNumber__icon{ - font-size: 6rem; - cursor: pointer; - &:hover{ - transform: scale(1.1); - transition: all 0.5s ease-in-out; - } - } - &:first-child{ - margin-right: 1rem; - } - &:last-child{ - margin-left: 1rem; - } - } - } } } diff --git a/src/assets/styles/UserDetails.scss b/src/assets/styles/UserDetails.scss index 735e9ed9..514738a2 100644 --- a/src/assets/styles/UserDetails.scss +++ b/src/assets/styles/UserDetails.scss @@ -165,30 +165,49 @@ height: 8rem; } } - .view__pdf{ - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.453); - z-index: 1000; - - .close__icon{ - position: absolute; - top: 2rem; - right: 2rem; - font-size: 3rem; - cursor: pointer; - color: $white-color; - &:hover{ - color: $red-color; - transform: scale(1.1); - transition: all 0.5s ease-in-out; - } - } + + } + .view__pdf { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.75); + z-index: 10000; + overflow: auto; + display: flex; + justify-content: center; + align-items: center; + pointer-events: all; + } + + .pdf__container { + width: 80%; + height: 90%; + background-color: #fff; + overflow: auto; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); + border-radius: 8px; + pointer-events: all; + } + + .close__icon { + position: absolute; + top: 1rem; + right: 1rem; + font-size: 2.5rem; + cursor: pointer; + color: $white-color; + pointer-events: all; + + &:hover { + color: $red-color; + transform: scale(1.1); + transition: all 0.5s ease-in-out; } } + .pageNumber{ display: flex; justify-content: center; diff --git a/src/assets/styles/adminDashboard.scss b/src/assets/styles/adminDashboard.scss index e240b457..68b3f5dc 100644 --- a/src/assets/styles/adminDashboard.scss +++ b/src/assets/styles/adminDashboard.scss @@ -156,21 +156,112 @@ } } - .monthDropDown { - .dropdown-button { - background-color: #ff7300; - color: #fff; - border: none; - padding: 5px 10px; - border-radius: 5px; - cursor: pointer; - font-size: 14px; - - .arrow-down { - margin-left: 5px; + // .monthDropDown { + // .dropdown-button { + // background-color: #ff7300; + // color: #fff; + // border: none; + // padding: 5px 10px; + // border-radius: 5px; + // cursor: pointer; + // font-size: 14px; + + // .arrow-down { + // margin-left: 5px; + // } + // } + // } + + .export-section { + display: flex; + gap: 10px; + + .monthDropDown { + .dropdown-button { + background-color: #ff7300; + color: #fff; + border: none; + padding: 5px 10px; + border-radius: 5px; + cursor: pointer; + font-size: 14px; + + .arrow-down { + margin-left: 5px; + } + } + } + + .export-dropdown { + position: relative; + + .export-btn { + background-color: #0f8615; + color: #fff; + border: none; + padding: 5px 10px; + border-radius: 5px; + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + gap: 4px; + + .arrow-down { + margin-left: 5px; + } + } + + .export-menu { + position: absolute; + top: 100%; + right: 0; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 5px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); + list-style-type: none; + padding: 0; + margin: 5px 0 0; + z-index: 1000; + + li { + padding: 8px 15px; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + font-size: 14px; + color: #333; + + &:hover { + background-color: #f5f5f5; + } + + svg { + font-size: 16px; + } + + &:nth-child(1) svg { + color: #217346; // Excel green + } + + &:nth-child(2) svg { + color: #888888; // CSV gray + } + + &:nth-child(3) svg { + color: #F40F02; // PDF red + } + + &:nth-child(4) svg { + color: #2B579A; // Word blue + } + } } } } + } } } diff --git a/src/assets/styles/verticalStepper.scss b/src/assets/styles/verticalStepper.scss index 10108cda..14af9026 100644 --- a/src/assets/styles/verticalStepper.scss +++ b/src/assets/styles/verticalStepper.scss @@ -102,53 +102,3 @@ } } - -.view__pdf{ - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.453); - z-index: 10000; - - .close__icon{ - position: absolute; - top: 2rem; - right: 2rem; - font-size: 3rem; - cursor: pointer; - color: $white-color; - &:hover{ - color: $red-color; - transform: scale(1.1); - transition: all 0.5s ease-in-out; - } - } - } - - .pageNumber{ - display: flex; - justify-content: center; - align-items: center; - - button{ - background-color: transparent; - width: 6rem; - height: 6rem; - .pageNumber__icon{ - font-size: 6rem; - cursor: pointer; - &:hover{ - transform: scale(1.1); - transition: all 0.5s ease-in-out; - } - } - &:first-child{ - margin-right: 1rem; - } - &:last-child{ - margin-left: 1rem; - } - } - } \ No newline at end of file diff --git a/src/components/FullScreenPdfView/FullScreenPdfView.tsx b/src/components/FullScreenPdfView/FullScreenPdfView.tsx index 75241a23..54a764cb 100644 --- a/src/components/FullScreenPdfView/FullScreenPdfView.tsx +++ b/src/components/FullScreenPdfView/FullScreenPdfView.tsx @@ -1,20 +1,28 @@ /* eslint-disable */ -import React, { useRef, useState } from "react"; +import React, { useRef, useState, useEffect } from "react"; import { Document, Page, pdfjs } from "react-pdf"; import { IoIosArrowBack, IoIosArrowForward } from "react-icons/io"; import 'react-pdf/dist/Page/TextLayer.css'; import 'react-pdf/dist/Page/AnnotationLayer.css'; +import { IoCloseCircleOutline } from "react-icons/io5"; +import { Button } from "@mui/material"; pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`; -export const FullScreenPdfView = ({ pdfUrl }) => { +export const FullScreenPdfView = ({ pdfUrl, open, onClose }) => { const pdfContainerRef = useRef(null); const [numPages, setNumPages] = useState(0); const [pageNumber, setPageNumber] = useState(1); const [scale, setScale] = useState(1); + useEffect(() => { + if (open) { + setPageNumber(1); // Reset to the first page when opening + } + }, [open]); + function onDocumentLoadSuccess({ numPages }: { numPages: number }): void { setNumPages(numPages); // adjustScale(); @@ -35,19 +43,27 @@ export const FullScreenPdfView = ({ pdfUrl }) => { setPageNumber((prevPage) => Math.min(prevPage + 1, numPages)); }; + if (!open) return null; + return ( -
-
- - - - - +
+
+
+ + + + + +
+
); }; diff --git a/src/components/TermsAndCondition/EditTerms.tsx b/src/components/TermsAndCondition/EditTerms.tsx index a5af99dc..265edeb6 100644 --- a/src/components/TermsAndCondition/EditTerms.tsx +++ b/src/components/TermsAndCondition/EditTerms.tsx @@ -44,7 +44,6 @@ export const EditTerms = ({ id }) => { await dispatch(updateTerm({formData, id})); } else if (localState.content) { const content = localState.content; - console.log(content) await dispatch(updateTerm({id,content})); } diff --git a/src/components/TermsAndCondition/TermsAndCondition.tsx b/src/components/TermsAndCondition/TermsAndCondition.tsx index 4e12dd55..39a5152f 100644 --- a/src/components/TermsAndCondition/TermsAndCondition.tsx +++ b/src/components/TermsAndCondition/TermsAndCondition.tsx @@ -114,7 +114,7 @@ const TermsAndConditionsForm: React.FC = ({ onNext }) => { {fileUrl && open && (
- +
)} diff --git a/src/components/UserDetails.tsx b/src/components/UserDetails.tsx index cfd1c168..f916eb22 100644 --- a/src/components/UserDetails.tsx +++ b/src/components/UserDetails.tsx @@ -68,7 +68,7 @@ const UserDetails: React.FC = ({ Request }) => { { open && (
- +
) diff --git a/src/components/seller/BusinessDetails.tsx b/src/components/seller/BusinessDetails.tsx index 8c0fcbed..38d44c49 100644 --- a/src/components/seller/BusinessDetails.tsx +++ b/src/components/seller/BusinessDetails.tsx @@ -9,9 +9,11 @@ import { DialogTitle, Box, Typography, + Checkbox, } from "@mui/material"; import { useAppDispatch, useAppSelector } from "../../store/store"; import { getAllTerms } from "../../store/features/admin/adminSlice"; +import { FullScreenPdfView } from "../FullScreenPdfView/FullScreenPdfView"; interface Props { nextStep: () => void; @@ -28,8 +30,24 @@ export const BusinessDetails: React.FC = ({ const [open, setOpen] = useState(false); const { terms } = useAppSelector((state) => state.admin); const [term, setTerm] = useState(); + const [fileUrl, setFileUrl] = useState(null); + const [content, setContent] = useState(null); const dispatch = useAppDispatch(); + useEffect(() => { + dispatch(getAllTerms()); + }, [dispatch]); + + useEffect(() => { + if (terms) { + const userTerms = terms.find((term) => term.type === "seller"); + if (userTerms) { + setFileUrl(userTerms.pdfUrl || null); + setContent(userTerms.content || null); + } + } + }, [terms]); + const handleChange = ( e: React.ChangeEvent ) => { @@ -52,19 +70,6 @@ export const BusinessDetails: React.FC = ({ nextStep(); }; - useEffect(() => { - dispatch(getAllTerms()); - }, [dispatch]); - - useEffect(() => { - if (terms) { - const userTerms = terms.find((term) => term.type === "seller"); - if (userTerms) { - setTerm(userTerms); - } - } - }, [terms]); - return (
@@ -112,94 +117,62 @@ export const BusinessDetails: React.FC = ({
-
- {term ? (
- - -
) : (
+
+
- -
)} - + I agree to the{" "} + + + +
- setOpen(false)} - aria-labelledby="terms-and-conditions-title" - aria-describedby="terms-and-conditions-description" - > - - Terms and Conditions - - - {term ? ( + {fileUrl && open && ( + setOpen(false)}/> + )} + {content && open && ( + setOpen(false)} + aria-labelledby="terms-and-conditions-title" + aria-describedby="terms-and-conditions-description" + > + + Terms and Conditions + + - {/* Display the term content */} - {term.content} +
- ) : ( - - No terms available for your role. - - )} - - - - -
+
+ + + +
+ )}
diff --git a/src/components/settings/GeneralSettings.tsx b/src/components/settings/GeneralSettings.tsx index 329844b0..e59e4891 100644 --- a/src/components/settings/GeneralSettings.tsx +++ b/src/components/settings/GeneralSettings.tsx @@ -133,7 +133,6 @@ export const GeneralSettings = () => { setEditorContent(""); setPdfFile(null); } catch (error) { - console.error("Error saving terms:", error); toast.error("An error occurred while saving terms. Please try again."); } finally { setIsDisabled(true); @@ -223,7 +222,7 @@ export const GeneralSettings = () => { { pdfOpen && (
- +
) diff --git a/src/pages/SignUp.tsx b/src/pages/SignUp.tsx index c59dcdc6..b08ed579 100644 --- a/src/pages/SignUp.tsx +++ b/src/pages/SignUp.tsx @@ -24,7 +24,7 @@ const SignUpSchema = Yup.object().shape({ export const SignUp = () => { const dispatch = useAppDispatch(); const navigate = useNavigate(); - const { user, isError, isSuccess, isLoading, message } = useAppSelector( + const { user, isError, isRegister, isLoading, message } = useAppSelector( (state) => state?.auth ); @@ -52,12 +52,12 @@ export const SignUp = () => { const [showError, setShowError] = useState(isError); useEffect(() => { - if (isSuccess) { + if (isRegister) { toast.success(message); navigate("/verify-email"); formik.resetForm(); } - }, [user, isError, isSuccess, isLoading, message, navigate]); + }, [user, isError, isRegister, isLoading, message, navigate]); useEffect(() => { setShowError(isError); @@ -79,9 +79,7 @@ export const SignUp = () => { setIsFocused(true); }; - useEffect(() => { - dispatch(resetAuth()); - }, [dispatch]); + return ( <> diff --git a/src/pages/UserViewCart.tsx b/src/pages/UserViewCart.tsx index a5d362a4..869f4cc1 100644 --- a/src/pages/UserViewCart.tsx +++ b/src/pages/UserViewCart.tsx @@ -147,7 +147,6 @@ const UserViewCart: React.FC = () => { unit_amount: unit_amount, }) ); - console.log(stripeProduct); localStorage.setItem( 'stripePrice', stripeProduct.payload.data.product.default_price @@ -192,9 +191,6 @@ const UserViewCart: React.FC = () => { const cartId = localStorage.getItem('cartToPay'); const products = localStorage.getItem('productsToSave'); const shopId = localStorage.getItem('shopIdToSave'); - console.log("Caert id", cartId); - console.log("Product ", products) - console.log("Shop id ", shopId) if (!cartId || !products || !shopId) { navigate('/shopping-cart'); toast.error('Unknown error occurred saving order'); diff --git a/src/pages/UserViewOrders.tsx b/src/pages/UserViewOrders.tsx index 365c0ef2..48389dfa 100644 --- a/src/pages/UserViewOrders.tsx +++ b/src/pages/UserViewOrders.tsx @@ -91,9 +91,7 @@ const UserVIewOrders: React.FC = () => { if (response.payload === 'orders not found') { setIsError(true); } - console.log('Response', response); setOrderResponseData(response.payload.data.orders); - console.log('Response', response.payload.data); } catch (error: any) { if (error === 'Not authorized') { setIsLoggedOut(true); diff --git a/src/pages/admin/OverView.tsx b/src/pages/admin/OverView.tsx index 8c653236..0a46fd6e 100644 --- a/src/pages/admin/OverView.tsx +++ b/src/pages/admin/OverView.tsx @@ -18,6 +18,12 @@ import { } from "../../store/features/admin/adminSlice"; import { useAppDispatch, useAppSelector } from "../../store/store"; import { useNavigate } from 'react-router-dom'; +import { FaFileExcel, FaFileCsv, FaFilePdf, FaFileWord } from "react-icons/fa"; +import exportToExcel from "../../utils/export/exportToExcel"; +import exportToCSV from "../../utils/export/exportToCSV"; +import exportToPDF from "../../utils/export/exportToPDF"; +import exportToWord from "../../utils/export/exportToWord"; + export const OverViewDashboard = () => { const getMonthName = (dateString) => { const date = new Date(dateString); @@ -44,6 +50,7 @@ export const OverViewDashboard = () => { const [numberOfSellers, setNumberOfSellers] = useState(null); const [numberOfShops, setNumberOfShops] = useState(null); const [selectedMonth, setSelectedMonth] = useState("All"); + const [orderHistory, setOrderHistory] = useState({ order: [] }) const dispatch = useAppDispatch(); const navigate = useNavigate(); @@ -78,6 +85,7 @@ export const OverViewDashboard = () => { const fetchData = async () => { try { const response = await dispatch(getOrderHistory()).unwrap(); + setOrderHistory({ order: response.data.OrderHistory }) const aggregatedData = response.data.OrderHistory.reduce( (acc, order) => { const monthName = getMonthName(order.orderDate); @@ -101,6 +109,34 @@ export const OverViewDashboard = () => { fetchData(); }, [dispatch]); + const [isExportOpen, setIsExportOpen] = useState(false); + + const toggleExportDropdown = () => { + setIsExportOpen(!isExportOpen); + }; + + const handleExport = (exportType) => { + console.dir(orderHistory) + switch (exportType) { + case 'excel': + exportToExcel(orderHistory, "admin_orders_report"); + break; + case 'csv': + exportToCSV(orderHistory, "admin_orders_report"); + break; + case 'pdf': + exportToPDF(orderHistory, "admin_orders_report"); + break; + case 'word': + exportToWord(orderHistory, "admin_orders_report"); + break; + default: + console.error('Invalid export type'); + } + setIsExportOpen(false); + }; + + const MonthDropDown = () => { const [isOpen, setIsOpen] = useState(false); const months = [ @@ -154,8 +190,8 @@ export const OverViewDashboard = () => { selectedMonth === "All" ? orderStats : orderStats.filter( - (stat) => stat.name === selectedMonth.substring(0, 3) - ); + (stat) => stat.name === selectedMonth.substring(0, 3) + ); return ( <> @@ -201,7 +237,22 @@ export const OverViewDashboard = () => {
- +
+ +
+ + {isExportOpen && ( +
    +
  • handleExport('excel')}> Excel
  • +
  • handleExport('csv')}> CSV
  • +
  • handleExport('pdf')}> PDF
  • +
  • handleExport('word')}> Word
  • +
+ )} +
+
diff --git a/src/pages/seller/SellerDashboard.tsx b/src/pages/seller/SellerDashboard.tsx index 2854d26e..030c53c9 100644 --- a/src/pages/seller/SellerDashboard.tsx +++ b/src/pages/seller/SellerDashboard.tsx @@ -17,10 +17,11 @@ import { sellerGetOrderHistory, } from "../../store/features/product/sellerCollectionProductsSlice"; import { useNavigate } from "react-router-dom"; -import productSlice from "../../store/features/product/productSlice"; -import { FaFileExcel } from "react-icons/fa"; -import exportToCSV from "../../utils/excel/exportToCSV"; -import exportToExcel from "../../utils/excel/exportToExcel"; +import { FaFileExcel, FaFileCsv, FaFilePdf, FaFileWord } from "react-icons/fa"; +import exportToExcel from "../../utils/export/exportToExcel"; +import exportToCSV from "../../utils/export/exportToCSV"; +import exportToPDF from "../../utils/export/exportToPDF"; +import exportToWord from "../../utils/export/exportToWord"; const SellerDashboard = () => { const { OrderHistory, message, data, isError } = useAppSelector( @@ -60,11 +61,11 @@ const SellerDashboard = () => { useEffect(() => { dispatch(sellerGetOrderHistory()); dispatch(fetchSellerCollectionProduct()); + dispatch(sellerGetAllProducts()); }, [dispatch]); useEffect(() => { try { const countData = async () => { - console.log(OrderHistory); if (OrderHistory) { const orderNumber = OrderHistory.order.length; setNumberOfOrders(orderNumber); @@ -108,6 +109,32 @@ const SellerDashboard = () => { } }, [OrderHistory, isError, message]); + const [isExportOpen, setIsExportOpen] = useState(false); + + const toggleExportDropdown = () => { + setIsExportOpen(!isExportOpen); + }; + + const handleExport = (exportType) => { + switch (exportType) { + case 'excel': + exportToExcel(OrderHistory); + break; + case 'csv': + exportToCSV(OrderHistory); + break; + case 'pdf': + exportToPDF(OrderHistory); + break; + case 'word': + exportToWord(OrderHistory); + break; + default: + console.error('Invalid export type'); + } + setIsExportOpen(false); + }; + const MonthDropDown = () => { const [isOpen, setIsOpen] = useState(false); const months = [ @@ -164,10 +191,6 @@ const SellerDashboard = () => { (stat) => stat.name === selectedMonth.substring(0, 3) ); - const exportStats = () => { - exportToExcel(OrderHistory) - } - return ( <>
@@ -203,7 +226,19 @@ const SellerDashboard = () => {
- +
+ + {isExportOpen && ( +
    +
  • handleExport('excel')}> Excel
  • +
  • handleExport('csv')}> CSV
  • +
  • handleExport('pdf')}> PDF
  • +
  • handleExport('word')}> Word
  • +
+ )} +
diff --git a/src/router.tsx b/src/router.tsx index 0bc89453..194c1f18 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -11,7 +11,7 @@ import { ResendEmail } from "./components/ResendEmail"; import GoogleCallback from "./components/GoogleCallback"; import SendResetPasswordLink from "./pages/SendResetPasswordLink"; import ResetPassword from "./pages/ResetPassword"; -import { ProtectedRoute } from "./utils/protectRoute/ProtectedRoute"; +import { GuestRoute, ProtectedRoute } from "./utils/protectRoute/ProtectedRoute"; import ViewProduct from "./pages/ViewProduct"; import Login from "./pages/Login"; import UserViewCart from "./pages/UserViewCart"; @@ -44,17 +44,17 @@ const AppRouter: React.FC = () => { + - + } /> + - + } /> { - } /> - } /> } /> @@ -183,4 +179,4 @@ const AppRouter: React.FC = () => { ); }; -export default AppRouter; +export default AppRouter; \ No newline at end of file diff --git a/src/store/features/admin/adminSlice.tsx b/src/store/features/admin/adminSlice.tsx index 17653c70..5bcf6d82 100644 --- a/src/store/features/admin/adminSlice.tsx +++ b/src/store/features/admin/adminSlice.tsx @@ -473,7 +473,6 @@ const adminSlice = createSlice({ state.request = action.payload.data.sellerRequest; state.message = action.payload.message; toast.success(state.message); - console.log(state.request); } ) .addCase( diff --git a/src/store/features/auth/authSlice.tsx b/src/store/features/auth/authSlice.tsx index 16418ab7..f7d0d656 100644 --- a/src/store/features/auth/authSlice.tsx +++ b/src/store/features/auth/authSlice.tsx @@ -23,6 +23,7 @@ const initialState: AuthService = { isOtpSuccess:false, isEmailResend:false, isNotVerified:false, + isRegister: false, }; type IUserEmailAndPassword = Pick; @@ -204,6 +205,7 @@ const userSlice = createSlice({ state.isOtpSuccess = false; state.isEmailResend = false state.isNotVerified = false; + state.isRegister = false; }, changingProfile: (state, action: any)=>{ (state.user as any).profilePicture = action.payload @@ -219,6 +221,7 @@ const userSlice = createSlice({ .addCase(registerUser.fulfilled, (state, action: PayloadAction) => { state.isLoading = false; state.isSuccess = true; + state.isRegister = true; state.message = action.payload.message; }) .addCase(registerUser.rejected, (state, action: PayloadAction) => { @@ -417,7 +420,6 @@ const userSlice = createSlice({ state.isOtpSuccess = true; state.message = action.payload.message; state.token = action.payload.data.token; - console.log(action.payload) }) .addCase(verifyOTP.rejected, (state, action: PayloadAction) => { state.isOtpFail = true; diff --git a/src/store/features/carts/cartService.tsx b/src/store/features/carts/cartService.tsx index 6b5ba73d..ff90f141 100644 --- a/src/store/features/carts/cartService.tsx +++ b/src/store/features/carts/cartService.tsx @@ -52,7 +52,6 @@ const clearCartProduct = async (cartId: string, productId: string) => { const clearCarts = async () => { try { const response = await axiosInstance.delete('/api/cart/buyer-clear-carts'); - console.log('MRR', response); return response; } catch (error) { console.error('Error clear carts', error); diff --git a/src/store/features/carts/cartSlice.tsx b/src/store/features/carts/cartSlice.tsx index dc85dcf8..e9334c40 100644 --- a/src/store/features/carts/cartSlice.tsx +++ b/src/store/features/carts/cartSlice.tsx @@ -243,7 +243,6 @@ const cartSlice = createSlice({ state.isError = false; state.isSuccess = true; state.carts = action.payload.data.carts; - console.log(state.carts); let cartProductsTotal = 0; let cartTotalAmount = 0; let cartsProductsList = []; diff --git a/src/store/features/chat/chatSlice.tsx b/src/store/features/chat/chatSlice.tsx index 7d6a4843..e94c50ed 100644 --- a/src/store/features/chat/chatSlice.tsx +++ b/src/store/features/chat/chatSlice.tsx @@ -5,7 +5,6 @@ import axios from 'axios'; export const uploadImage = createAsyncThunk( 'chat/uploadImage', async (file:File, thunkAPI) => { - console.log(file) const formData = new FormData(); formData.append("file",file); formData.append("upload_preset", "pbyvho95"); diff --git a/src/utils/axios/axiosInstance.ts b/src/utils/axios/axiosInstance.ts index 322b4095..78d76040 100644 --- a/src/utils/axios/axiosInstance.ts +++ b/src/utils/axios/axiosInstance.ts @@ -1,8 +1,8 @@ /* eslint-disable */ import axios from "axios"; import { getToken } from "../protectRoute/ProtectedRoute"; -export const URL = "https://e-commerce-ninjas-platform-backend.onrender.com"; -// export const URL = "http://localhost:5001"; +// export const URL = "https://e-commerce-ninjas-platform-backend.onrender.com"; +export const URL = "http://localhost:5001"; const axiosInstance = axios.create({ baseURL: `${URL}`, headers: { diff --git a/src/utils/excel/exportToCSV.ts b/src/utils/excel/exportToCSV.ts deleted file mode 100644 index bfdca6d1..00000000 --- a/src/utils/excel/exportToCSV.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* eslint-disable */ -import Papa from 'papaparse' - -const exportToCSV = (orderHistory) => { - const orders = orderHistory.order; - const rows = []; - rows.push([ - 'Order ID', - 'Order Date', - 'Expected Delivery Date', - 'Order Status', - 'Payment Method', - 'Products', - 'Total Order Revenue (RWF)', - 'Shipping Status' - ]); - orders.forEach(order => { - const products = JSON.parse(order.products); - const productSummary = products.map(p => `${p.name} (${p.quantity})`).join(', '); - const totalRevenue = products.reduce((sum, p) => sum + parseFloat(p.totalPrice), 0).toFixed(2); - - rows.push([ - order.id, - new Date(order.orderDate).toLocaleString(), - new Date(order.expectedDeliveryDate).toLocaleString(), - order.status, - order.paymentMethodId, - productSummary, - totalRevenue, - order.shippingProcess - ]); - }); - - const csv = Papa.unparse(rows); - const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); - const link = document.createElement('a'); - if (link.download !== undefined) { - const url = URL.createObjectURL(blob); - link.setAttribute('href', url); - link.setAttribute('download', 'seller_orders.csv'); - link.style.visibility = 'hidden'; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - - } -}; - -export default exportToCSV; \ No newline at end of file diff --git a/src/utils/export/exportToCSV.ts b/src/utils/export/exportToCSV.ts new file mode 100644 index 00000000..c0d0143f --- /dev/null +++ b/src/utils/export/exportToCSV.ts @@ -0,0 +1,56 @@ +/* eslint-disable */ +/* eslint-disable */ +import Papa from 'papaparse'; + +const exportToCSV = (orderHistory, docName = 'seller_orders') => { + const orders = orderHistory.order; + const rows = [ + [ + 'Order ID', + 'Order Date', + 'Expected Delivery Date', + 'Order Status', + 'Payment Method', + 'Products', + 'Shipping Status' + ] + ]; + + orders.forEach(order => { + let productsInfo = ''; + + if (Array.isArray(order.products)) { + productsInfo = order.products.map(p => `${p.productId}(${p.status})`).join(', '); + } + + rows.push([ + order.id, + new Date(order.orderDate).toLocaleString(), + new Date(order.expectedDeliveryDate).toLocaleString(), + order.status, + order.paymentMethodId, + productsInfo, + order.shippingProcess + ]); + }); + + // Convert the data to CSV + const csv = Papa.unparse(rows); + + // Create a Blob with the CSV data + const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); + + // Create a download link and trigger the download + const link = document.createElement('a'); + if (link.download !== undefined) { + const url = URL.createObjectURL(blob); + link.setAttribute('href', url); + link.setAttribute('download', `${docName}.csv`); + link.style.visibility = 'hidden'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } +}; + +export default exportToCSV; \ No newline at end of file diff --git a/src/utils/excel/exportToExcel.ts b/src/utils/export/exportToExcel.ts similarity index 90% rename from src/utils/excel/exportToExcel.ts rename to src/utils/export/exportToExcel.ts index 4d6f267f..ec4b5928 100644 --- a/src/utils/excel/exportToExcel.ts +++ b/src/utils/export/exportToExcel.ts @@ -1,7 +1,7 @@ /* eslint-disable */ import * as XLSX from 'xlsx'; -const exportToExcel = (orderHistory) => { +const exportToExcel = (orderHistory, docName = 'seller_orders') => { const orders = orderHistory.order; const rows = [ [ @@ -41,7 +41,7 @@ const exportToExcel = (orderHistory) => { XLSX.utils.book_append_sheet(workbook, worksheet, 'OrderHistory'); // Export the workbook to an Excel file - XLSX.writeFile(workbook, 'seller_orders.xlsx'); + XLSX.writeFile(workbook, `${docName}.xlsx`); }; export default exportToExcel; \ No newline at end of file diff --git a/src/utils/export/exportToPDF.ts b/src/utils/export/exportToPDF.ts new file mode 100644 index 00000000..82dc869e --- /dev/null +++ b/src/utils/export/exportToPDF.ts @@ -0,0 +1,52 @@ +/* eslint-disable */ +import jsPDF from 'jspdf'; +import 'jspdf-autotable'; + +const exportToPDF = (orderHistory, docName = 'seller_orders') => { + const doc = new jsPDF(); + const orders = orderHistory.order; + + // Add title + doc.text('Order History', 14, 15); + + // Prepare data for the table + const tableRows = orders.map(order => [ + order.id, + new Date(order.orderDate).toLocaleString(), + new Date(order.expectedDeliveryDate).toLocaleString(), + order.status, + order.paymentMethodId, + Array.isArray(order.products) ? order.products.map(p => `${p.productId}(${p.status})`).join(', ') : '', + order.shippingProcess + ]); + + const columnCount = 7; // Number of columns + const pageWidth = doc.internal.pageSize.width; + const tableWidth = pageWidth - 20; // 10mm margin on each side + const columnWidth = tableWidth / columnCount; + + // Add table to the PDF + // @ts-ignore + doc.autoTable({ + head: [['Order ID', 'Order Date', 'Expected Delivery Date', 'Order Status', 'Payment Method', 'Products', 'Shipping Status']], + body: tableRows, + startY: 20, + margin: { left: 10, right: 10 }, + columnStyles: { + 0: { cellWidth: columnWidth }, + 1: { cellWidth: columnWidth }, + 2: { cellWidth: columnWidth }, + 3: { cellWidth: columnWidth }, + 4: { cellWidth: columnWidth }, + 5: { cellWidth: columnWidth }, + 6: { cellWidth: columnWidth }, + }, + styles: { overflow: 'linebreak', cellPadding: 2 }, + headStyles: { fillColor: [41, 128, 185], textColor: 255 }, + }); + + // Save the PDF + doc.save(`${docName}.pdf`); +}; + +export default exportToPDF; \ No newline at end of file diff --git a/src/utils/export/exportToWord.ts b/src/utils/export/exportToWord.ts new file mode 100644 index 00000000..679af0b7 --- /dev/null +++ b/src/utils/export/exportToWord.ts @@ -0,0 +1,58 @@ +/* eslint-disable */ +import { Document, Packer, Paragraph, Table, TableRow, TableCell, WidthType } from 'docx'; +import { saveAs } from 'file-saver'; + +const exportToWord = (orderHistory, docName = 'seller_orders') => { + const orders = orderHistory.order; + + // Define equal width for each column + const columnWidth = 100 / 7; // 7 columns, so each gets 1/7 of the total width + + // Create table rows + const rows = orders.map(order => + new TableRow({ + children: [ + new TableCell({ children: [new Paragraph(order.id)], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph(new Date(order.orderDate).toLocaleString())], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph(new Date(order.expectedDeliveryDate).toLocaleString())], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph(order.status)], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph(order.paymentMethodId)], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph(Array.isArray(order.products) ? order.products.map(p => `${p.productId}(${p.status})`).join(', ') : '')], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph(order.shippingProcess)], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + ], + }) + ); + + // Create the document + const doc = new Document({ + sections: [{ + children: [ + new Paragraph("Order History"), + new Table({ + rows: [ + new TableRow({ + children: [ + new TableCell({ children: [new Paragraph("Order ID")], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph("Order Date")], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph("Expected Delivery Date")], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph("Order Status")], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph("Payment Method")], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph("Products")], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + new TableCell({ children: [new Paragraph("Shipping Status")], width: { size: columnWidth, type: WidthType.PERCENTAGE } }), + ], + }), + ...rows, + ], + width: { size: 100, type: WidthType.PERCENTAGE }, + }), + ], + }], + }); + + // Generate and save the document + Packer.toBlob(doc).then(blob => { + saveAs(blob, `${docName}.docx`); + }); +}; + +export default exportToWord; \ No newline at end of file diff --git a/src/utils/protectRoute/ProtectedRoute.tsx b/src/utils/protectRoute/ProtectedRoute.tsx index 1225d865..fbc8649c 100644 --- a/src/utils/protectRoute/ProtectedRoute.tsx +++ b/src/utils/protectRoute/ProtectedRoute.tsx @@ -1,45 +1,42 @@ /* eslint-disable */ import React, { useEffect, useState } from 'react'; -import { Navigate, Outlet, useLocation } from 'react-router-dom'; -import { toast } from 'react-toastify'; +import { Navigate, Outlet, useNavigate } from 'react-router-dom'; import Backdrop from '@mui/material/Backdrop'; import CircularProgress from '@mui/material/CircularProgress'; import Typography from '@mui/material/Typography'; import Box from '@mui/material/Box'; import { useAppDispatch, useAppSelector } from '../../store/store'; +import { toast } from 'react-toastify'; import { getUserDetails, logout } from '../../store/features/auth/authSlice'; -const ProtectedRoute = ({ redirectPath = '/', allowedRoles = [], children }) => { - const [loading, setLoading] = useState(true); - const [isAuthenticated, setIsAuthenticated] = useState(false); +const ProtectedRoute = ({ redirectPath = '/',allowedRoles = [] ,children }) => { const [userRole, setUserRole] = useState(null); - const location = useLocation(); const dispatch = useAppDispatch(); - const {user} = useAppSelector((state)=>state.auth) + const [loading, setLoading] = useState(true); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const { message, isError } = useAppSelector((state) => state.admin); useEffect(() => { - const authenticateUser = async () => { + setTimeout(() => { + const checkToken = async () => { const token = getToken(); - if (token) { - try { - const res = await dispatch(getUserDetails(token)); + if(token) { + const res = await dispatch(getUserDetails(token)); if (res) { setUserRole(res.payload.data.user.role); - setIsAuthenticated(true); - } else { + setIsAuthenticated(!!token); + setLoading(false); + }else { setIsAuthenticated(false); } - } catch (error) { - console.error("Failed to decode token:", error); + }else { setIsAuthenticated(false); + setLoading(false); } - } else { - setIsAuthenticated(false); - } - setLoading(false); - }; + }; + checkToken(); + }, 1000); - authenticateUser(); - }, [dispatch]); + }, []); if (loading) { return ( @@ -65,23 +62,14 @@ const ProtectedRoute = ({ redirectPath = '/', allowedRoles = [], children }) => ); } - // Allow guests to access home, login, and signup pages - if (isAuthenticated === false) { - if (location.pathname === '/' || location.pathname === '/login' || location.pathname === '/signup') { - return children ? children : ; - } else { - toast.info('Please log in to access this page.'); - return ; - } + if (!isAuthenticated) { + toast.info('Please log in to access this page.'); + return ; } - - // Prevent authenticated users from accessing login and signup pages - if (isAuthenticated && (location.pathname === '/login' || location.pathname === '/signup')) { - toast.info('You are already logged in.'); - return ; + if (isError && message === 'Not authorized') { + toast.info('You are not authorized to access this page'); + return ; } - - // Check if the authenticated user has the allowed role if (allowedRoles.length && !allowedRoles.includes(userRole)) { if (isAuthenticated && (userRole === 'admin' || userRole === 'seller')) { dispatch(logout()); @@ -92,10 +80,55 @@ const ProtectedRoute = ({ redirectPath = '/', allowedRoles = [], children }) => return ; } } - return children ? children : ; }; +const GuestRoute = () => { + const navigate = useNavigate(); + const [userRole, setUserRole] = useState(null); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const dispatch = useAppDispatch(); + + useEffect(() =>{ + const checkToken = async () => { + const token = getToken(); + if (token) { + try { + const resultAction = await dispatch(getUserDetails(token)); + + if (getUserDetails.fulfilled.match(resultAction)) { + const userRole = resultAction.payload.user.role; + setUserRole(userRole); + setIsAuthenticated(true); + } else { + navigate('/login'); + } + } catch (error) { + navigate('/login'); + } + } else { + navigate('/login'); + } + }; + + checkToken(); + },[dispatch,navigate]) + + useEffect(() => { + if (isAuthenticated && userRole) { + if (userRole === 'admin') { + navigate('/admin'); + } else if (userRole === 'seller') { + navigate('/seller'); + } else { + navigate('/'); + } + } + }, [isAuthenticated, userRole, navigate]); + + return ; +}; + const storeTokenWithExpiration = (token) => { const expirationTimeInMs = 28 * 60 * 60 * 1000; // 28 hours const expirationTime = Date.now() + expirationTimeInMs; @@ -122,4 +155,4 @@ const getToken = () => { return null; }; -export { ProtectedRoute, storeTokenWithExpiration, getToken }; +export { ProtectedRoute, storeTokenWithExpiration, getToken,GuestRoute }; diff --git a/src/utils/socket/socket.ts b/src/utils/socket/socket.ts index 571ef449..448f9f73 100644 --- a/src/utils/socket/socket.ts +++ b/src/utils/socket/socket.ts @@ -6,7 +6,6 @@ const socket = io('https://e-commerce-ninjas-platform-backend.onrender.com'); export const joinRoom = () => { const token = getToken(); - console.log(token) if (token) { socket.emit('join', token); } else { diff --git a/src/utils/types/store.d.ts b/src/utils/types/store.d.ts index e15d90b1..8020bffb 100644 --- a/src/utils/types/store.d.ts +++ b/src/utils/types/store.d.ts @@ -105,7 +105,8 @@ export interface AuthService { isOtpFail:boolean; isOtpSuccess:boolean; isEmailResend:boolean; - isNotVerified:boolean + isNotVerified:boolean; + isRegister:boolean; } export interface IEmail {