diff --git a/.firebase/hosting.YnVpbGQ.cache b/.firebase/hosting.YnVpbGQ.cache index 5dd5fbb..74ca627 100644 --- a/.firebase/hosting.YnVpbGQ.cache +++ b/.firebase/hosting.YnVpbGQ.cache @@ -3,40 +3,40 @@ brand-dark.png,1694254597736,702452b4806f73230e4931aa592272e2b575041e860562fa40f favicon.png,1691226006659,98a04f7e56d94a7501464028a58de35b8c75edd22190662dd1c9a7d4506f9011 manifest.json,1694287199372,c83ecda918bbbda0c2ddf51f5dc7a3a681e7ce84438985e201e7a843e8f47ec9 robots.txt,1691226006661,b2090cf9761ef60aa06e4fab97679bd43dfa5e5df073701ead5879d7c68f1ec5 -asset-manifest.json,1696704887805,0d13e7a32d08d695f4b747318eb053620d05d83576e75808a6878fc13f912960 -index.html,1696704887742,525ad697503150d7f3c27ebd21123bde910e4236c9cf7e8e62d5d89f84753170 -static/css/main.21be9e29.css,1696704887747,055e9e85a0610e176e38ad174690ec4ff6808dd57ce88dbc54175c0171a16476 -static/css/main.21be9e29.css.map,1696704887805,386851af591d5f1544327c513e505eaf17e86e607bf4af9d607488d2db10b9c6 -static/js/703.68ff776a.chunk.js,1696704887805,e83256c6d19bf02880f9ae9f36584c69b9e491beecec0ceb1c5ac14b85c882e3 -static/js/703.68ff776a.chunk.js.LICENSE.txt,1696704887745,3d8cec7287cdb0530baa88a78b7810defffd2f56cc2cccf447bc5889a622b212 -static/js/main.9796e417.js.LICENSE.txt,1696704887745,20488bf5da16a483592651d1696300dd006944aa4bba15bece1383c3119057f9 -static/media/icon-blacklist.00461066f8dc77314608696b24ffca29.svg,1696704887727,23ec3e3fe5106041541173ea5bd667cebac2d62471759db00f4a4f9a99b65a8e -static/media/icon-facebook.7e5a10f05d754f6e65372e20a5452d60.svg,1696704887729,e886d6d8420e8ea3f5d92b3e4411d690cbf59db4b1c32c6baaf7fe0faebc1847 -static/media/icon-instagram.6916c290ec7f973be569508e95332846.svg,1696704887730,63d77fac1a784b57ac66383f2265c103bcdc61bb484ff50b344b970473ea452a -static/media/icon-preview.9d260cdcabe46fdc423492bfe2e317cf.svg,1696704887729,2e1fc9d039149ef375d54d7276089c55ff21f2504139c79859349613a6b31619 -static/media/icon-text.72e88c25f84b1cf1d3f69a697f689f64.svg,1696704887727,8c54c677a8fc3e9d0b054ebf7a46ae3573df7219603b04d736099fba7ea51efc -static/media/icon-twitter.09334153919ab7925dce3b54b4b9a815.svg,1696704887731,76bca9231586ca4c6fd04e7a2740cf1b0bdf8699094689df819e0eb50d57a3b2 -static/media/bruce-mars.8a606c4a6dab54c9ceff.jpg,1696704887731,b9d6660122b20a8a6fb1b6e7ea4d9b575b2ed1e9d86fe66e9ef7bbbc4804b964 -static/media/house.ce4190cf14822c2257b0.png,1696704887742,71651ecfee60076c2d84abd0128f2716b944250d4f529224f2724db4ebfcdb29 -static/media/logowithbrand.1e0479210ed4f2cd2af0.png,1696704887745,f1be59932f15bcc82152ef5f33a69abebcdb1ef28d5b929805acaf810ba17758 -static/js/703.68ff776a.chunk.js.map,1696704887806,5a0ff7437240593cc20bb51e55130a6d746b07e30495804530095587227ce082 -static/media/land.a180af0f55ec7508e106.png,1696704887742,ea3f98c35afa9311618ee456466cbc0e1927b4488fa6d7026c902146e597868c -static/media/marriage.7b26dbac84b6fb70b91e.png,1696704887742,eefda79f94949d6e5dfdfbeba1c84cbb8101058ff92e3131e7da6b562711f2e5 -static/media/mastercard.27fca3e7637a9458fb64.png,1696704887732,2015bca51ddb5859ebb94d73d1802bf322d2f7e544c0a2fbc3500fd992af8500 -static/media/visa.71c0d5e9e2aaee42e4c3.png,1696704887732,5675d0bb0a46ef1c343090c0b9ba4d2b398c937b72909a7fcd1c959e36dc784f -static/js/513.c3183f67.chunk.js,1696704887806,3ffbee61e1e12b2ac876d96a8aa82288d705827c4bd232805d09e4d26b19f184 -static/media/image-devices.7a9f93355333984b7941.png,1696704887744,db97ae84ccd9a09052017c203e159e7f57d14b473ce5d6095f4b2ff31a047ef8 -static/media/bg-header-desktop.3d39ff8e4eec581d1f91.png,1696704887730,6a8849446474587badf86ebf0d58bcf72aef1a680157d90c7cf5b471647da918 -static/media/image-computer.65db67db202be4e74616.png,1696704887744,a221118a6e05fc3c24fd4b56839206ab412de9339a853610d20ad142fac73e53 -static/js/513.c3183f67.chunk.js.map,1696704887807,0d4d4ba2f497ad3d0cb01e42846812c45900da1978e557b7a5301f8159fb8f5b -static/media/bg-profile.af1219a742e09fc7b612.jpeg,1696704887731,c0224651329e6f23cbe3bd9bfb37986a67de3566a837197af7ba31eb5bf2a928 -static/media/house (1).1c4662866d6ca3755cf4.jpg,1696704887731,8610be21401a79ecd5b0448b81190772e7b6e2504a455c9eaf6eb5d2982bb044 -static/media/wedding.72b9ec574465c95d19b9.jpg,1696704887744,c45f2c6592cab0cd42dd8d03cab88adaf91ce7aa2ecbf707fa93ca6fa84cfe1f -static/media/newspaper2.d4dec8c732058acfeec1.jpg,1696704887743,3a7a10c19aa48d4ad2c2678da165da3a0d59dd6ef638b2e71cb3af37928b83fa -static/media/background3.3ce0efefbd5f55c07b58.png,1696704887745,4b0f57791be4038375c5d4c7039357793e0c19837615de31b2b8ee60a3aedfc9 -static/media/land.545d66910852fb567f29.jpg,1696704887734,b76f1b1f28de91e7e91995c23f05d6dc5d77035402e3f1034be96384f6ec1004 -static/js/main.9796e417.js,1696704887807,6a93e135bacf08539a817d5b74177e66d6c95936338bf7941548aa52055bad70 -static/media/pattern-tree.431da656681abcdffac51bee04d7f581.svg,1696704887743,077b4cad6cd72eaf768124ce97b66451dabf05a04e422c8cb4452f887b8b8ebb -static/media/background.b28e08e8c97c1c73b13f.jpg,1696704887731,364ba257eb402e2e6a69bfd7544679734f3c62a719f015fa6c499238f87e9b1a -static/media/newspaper1.d9cb92762b7f143bf29b.jpg,1696704887746,dbd7a8fdf1f7f03040c6e6c8dc5d13e3726fc1b243ebeea59e9ceb35e7936e42 -static/js/main.9796e417.js.map,1696704887813,16f3e75cd0dcb91e6baf33f7b79310c5a29103b5c624c77a2aa56f4f50fe0992 +asset-manifest.json,1696732173023,23407ac00406df72732414da475e93139a9b2962c54ec9199451e48c7f893d4f +index.html,1696732171508,d6294f31c38bc467079eee92494e8d1ee34cfafd52f142717d3c5c0178576dc3 +static/css/main.21be9e29.css,1696732172843,055e9e85a0610e176e38ad174690ec4ff6808dd57ce88dbc54175c0171a16476 +static/js/703.68ff776a.chunk.js.LICENSE.txt,1696732171524,3d8cec7287cdb0530baa88a78b7810defffd2f56cc2cccf447bc5889a622b212 +static/js/703.68ff776a.chunk.js,1696732172843,e83256c6d19bf02880f9ae9f36584c69b9e491beecec0ceb1c5ac14b85c882e3 +static/css/main.21be9e29.css.map,1696732173022,386851af591d5f1544327c513e505eaf17e86e607bf4af9d607488d2db10b9c6 +static/js/main.3a0a9926.js.LICENSE.txt,1696732172706,20488bf5da16a483592651d1696300dd006944aa4bba15bece1383c3119057f9 +static/media/icon-facebook.7e5a10f05d754f6e65372e20a5452d60.svg,1696732171468,e886d6d8420e8ea3f5d92b3e4411d690cbf59db4b1c32c6baaf7fe0faebc1847 +static/media/icon-instagram.6916c290ec7f973be569508e95332846.svg,1696732171474,63d77fac1a784b57ac66383f2265c103bcdc61bb484ff50b344b970473ea452a +static/media/icon-blacklist.00461066f8dc77314608696b24ffca29.svg,1696732171474,23ec3e3fe5106041541173ea5bd667cebac2d62471759db00f4a4f9a99b65a8e +static/media/icon-preview.9d260cdcabe46fdc423492bfe2e317cf.svg,1696732171467,2e1fc9d039149ef375d54d7276089c55ff21f2504139c79859349613a6b31619 +static/media/icon-text.72e88c25f84b1cf1d3f69a697f689f64.svg,1696732171495,8c54c677a8fc3e9d0b054ebf7a46ae3573df7219603b04d736099fba7ea51efc +static/media/icon-twitter.09334153919ab7925dce3b54b4b9a815.svg,1696732171468,76bca9231586ca4c6fd04e7a2740cf1b0bdf8699094689df819e0eb50d57a3b2 +static/media/house.ce4190cf14822c2257b0.png,1696732171474,71651ecfee60076c2d84abd0128f2716b944250d4f529224f2724db4ebfcdb29 +static/media/logowithbrand.1e0479210ed4f2cd2af0.png,1696732172706,f1be59932f15bcc82152ef5f33a69abebcdb1ef28d5b929805acaf810ba17758 +static/js/703.68ff776a.chunk.js.map,1696732173225,5a0ff7437240593cc20bb51e55130a6d746b07e30495804530095587227ce082 +static/media/land.a180af0f55ec7508e106.png,1696732171507,ea3f98c35afa9311618ee456466cbc0e1927b4488fa6d7026c902146e597868c +static/media/mastercard.27fca3e7637a9458fb64.png,1696732171469,2015bca51ddb5859ebb94d73d1802bf322d2f7e544c0a2fbc3500fd992af8500 +static/media/marriage.7b26dbac84b6fb70b91e.png,1696732171507,eefda79f94949d6e5dfdfbeba1c84cbb8101058ff92e3131e7da6b562711f2e5 +static/media/visa.71c0d5e9e2aaee42e4c3.png,1696732171471,5675d0bb0a46ef1c343090c0b9ba4d2b398c937b72909a7fcd1c959e36dc784f +static/js/513.c3183f67.chunk.js,1696732173022,3ffbee61e1e12b2ac876d96a8aa82288d705827c4bd232805d09e4d26b19f184 +static/media/image-devices.7a9f93355333984b7941.png,1696732172843,db97ae84ccd9a09052017c203e159e7f57d14b473ce5d6095f4b2ff31a047ef8 +static/media/bg-header-desktop.3d39ff8e4eec581d1f91.png,1696732171468,6a8849446474587badf86ebf0d58bcf72aef1a680157d90c7cf5b471647da918 +static/media/image-computer.65db67db202be4e74616.png,1696732171597,a221118a6e05fc3c24fd4b56839206ab412de9339a853610d20ad142fac73e53 +static/media/socrates.8e85b668f6e9feea1255.jpeg,1696732171509,49aebb9fb695625ea2937ec9693a0afa883eacefd02d712d69bc0d5ab7b3cc67 +static/js/513.c3183f67.chunk.js.map,1696732173225,0d4d4ba2f497ad3d0cb01e42846812c45900da1978e557b7a5301f8159fb8f5b +static/media/bg-profile.af1219a742e09fc7b612.jpeg,1696732171469,c0224651329e6f23cbe3bd9bfb37986a67de3566a837197af7ba31eb5bf2a928 +static/media/house (1).1c4662866d6ca3755cf4.jpg,1696732171474,8610be21401a79ecd5b0448b81190772e7b6e2504a455c9eaf6eb5d2982bb044 +static/media/wedding.72b9ec574465c95d19b9.jpg,1696732171512,c45f2c6592cab0cd42dd8d03cab88adaf91ce7aa2ecbf707fa93ca6fa84cfe1f +static/media/newspaper2.d4dec8c732058acfeec1.jpg,1696732171523,3a7a10c19aa48d4ad2c2678da165da3a0d59dd6ef638b2e71cb3af37928b83fa +static/media/background3.3ce0efefbd5f55c07b58.png,1696732171523,4b0f57791be4038375c5d4c7039357793e0c19837615de31b2b8ee60a3aedfc9 +static/media/land.545d66910852fb567f29.jpg,1696732171471,b76f1b1f28de91e7e91995c23f05d6dc5d77035402e3f1034be96384f6ec1004 +static/js/main.3a0a9926.js,1696732173023,3ff2b97fad930d8d77cdf81ceceed8082ad1643cf3c73c5cf28044603b11ef58 +static/media/pattern-tree.431da656681abcdffac51bee04d7f581.svg,1696732171495,077b4cad6cd72eaf768124ce97b66451dabf05a04e422c8cb4452f887b8b8ebb +static/media/background.b28e08e8c97c1c73b13f.jpg,1696732171472,364ba257eb402e2e6a69bfd7544679734f3c62a719f015fa6c499238f87e9b1a +static/media/newspaper1.d9cb92762b7f143bf29b.jpg,1696732171512,dbd7a8fdf1f7f03040c6e6c8dc5d13e3726fc1b243ebeea59e9ceb35e7936e42 +static/js/main.3a0a9926.js.map,1696732174557,eb471357af0683df418a5be12130ab6da81e0b659fd311016c1c762542f27bdb diff --git a/package-lock.json b/package-lock.json index 8cb15f0..6783a1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "react-router-dom": "6.11.0", "react-scripts": "5.0.1", "react-table": "7.8.0", + "selenium-webdriver": "^4.14.0", "stylis": "4.1.4", "stylis-plugin-rtl": "2.1.1", "uuid": "^9.0.0", @@ -10458,6 +10459,11 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/immer": { "version": "9.0.21", "license": "MIT", @@ -14232,6 +14238,49 @@ "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==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "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==", + "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==" + }, + "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==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/kind-of": { "version": "6.0.3", "license": "MIT", @@ -14295,6 +14344,14 @@ "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==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "license": "MIT", @@ -15009,6 +15066,11 @@ "node": ">=6" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "node_modules/param-case": { "version": "3.0.4", "license": "MIT", @@ -18185,6 +18247,19 @@ "version": "2.0.0", "license": "MIT" }, + "node_modules/selenium-webdriver": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.14.0.tgz", + "integrity": "sha512-637rs8anqMKHbWxcBZpyG3Gcs+rBUtAUiqk0O/knUqH4Paj3MFUZrz88/pVGOLNryEVy2z92fZomT8p1ENl1gA==", + "dependencies": { + "jszip": "^3.10.1", + "tmp": "^0.2.1", + "ws": ">=8.14.2" + }, + "engines": { + "node": ">= 14.20.0" + } + }, "node_modules/selfsigned": { "version": "2.1.1", "license": "MIT", @@ -18321,6 +18396,11 @@ "node": ">= 0.8.0" } }, + "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==" + }, "node_modules/setprototypeof": { "version": "1.2.0", "license": "ISC" @@ -19122,6 +19202,17 @@ "version": "1.0.3", "license": "MIT" }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "license": "BSD-3-Clause" @@ -20268,9 +20359,9 @@ } }, "node_modules/ws": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.1.tgz", - "integrity": "sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index ac102a3..0ec064e 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "react-router-dom": "6.11.0", "react-scripts": "5.0.1", "react-table": "7.8.0", + "selenium-webdriver": "^4.14.0", "stylis": "4.1.4", "stylis-plugin-rtl": "2.1.1", "uuid": "^9.0.0", @@ -52,7 +53,7 @@ "scripts": { "start": "react-scripts start", "build": "react-scripts build", - "test": "react-scripts test --transformIgnorePatterns \"node_modules/(?!axios)/\"", + "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { diff --git a/src/App.js b/src/App.js index 493f572..14d32d4 100644 --- a/src/App.js +++ b/src/App.js @@ -47,7 +47,7 @@ import { useMaterialUIController, setMiniSidenav, setOpenConfigurator } from "co import brandWhite from "assets/images/brand-dark.png"; import brandDark from "assets/images/brand-light.png"; import Background from "examples/LayoutContainers/background"; -import bgImage from "layouts/landing/Assets/images/background3.png"; +// import bgImage from "layouts/landing/Assets/images/background3.png"; import { useUser } from "utils/userContext"; export default function App() { @@ -136,7 +136,7 @@ export default function App() { return ( - + {layout === "dashboard" && ( <> diff --git a/src/__test__/Login.test.js b/src/__test__/Login.test.js index c7f613f..ce1a780 100644 --- a/src/__test__/Login.test.js +++ b/src/__test__/Login.test.js @@ -87,7 +87,7 @@ jest.mock("react-router-dom", () => ({ describe("Sign In Page", () => { it("handles login correctly", () => { render( - + @@ -95,7 +95,7 @@ describe("Sign In Page", () => { - + ); // Mock the fetch function to handle the login request diff --git a/src/__test__/adCard.test.js b/src/__test__/adCard.test.js new file mode 100644 index 0000000..8d41a4d --- /dev/null +++ b/src/__test__/adCard.test.js @@ -0,0 +1,82 @@ +import React from "react"; +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { AdCard } from "layouts/dashboard/components/adCard"; // adjust the import path accordingly +import { BrowserRouter } from "react-router-dom"; +import { MaterialUIControllerProvider } from "context"; +import UserProvider from "utils/userContext"; +import { ThemeProvider } from "@mui/material"; +import theme from "assets/theme"; + +// Mock the data you expect to receive from the backend +const mockBackendData = [ + { + Advertisement_ID: 1, + category: "Land Sale", + Title: "Sample Land Ad", + Description: "This is a land ad description", + }, + { + Advertisement_ID: 2, + category: "House Sale", + Title: "Sample House Ad", + Description: "This is a house ad description", + }, + { + Advertisement_ID: 3, + category: "Marriage Proposal", + Title: "Sample Marriage Ad", + Description: "This is a marriage ad description", + }, +]; + +// Mock the getPopularAd function +jest.mock("api/advertisemntCards/advertisementCard", () => ({ + getPopularAd: jest.fn(() => Promise.resolve(mockBackendData)), +})); +export const getPopularAd = jest.fn().mockImplementation(() => { + const data = { + category: "Land Sale", + title: "Sample Land Ad", + description: "This is a land ad description", + }; + + // Log the data before returning it + console.log("Mocked API data:", data); + + return data; +}); +test("renders AdCard component with data", async () => { + // Render the AdCard component + const { getByText, getByAltText } = render( + + + + + + + + + + ); + + // Check if loading spinner is displayed + const loadingElement = getByText("Recent Advertisements"); + expect(loadingElement).toBeInTheDocument(); + + // Wait for the data to load (you might want to add a loading state to your component) + await waitFor(() => { + const title = screen.getByText("Land Sale"); + expect(title).toBeInTheDocument(); + }); + const title = screen.getByText("Sample Land Ad"); + const description = screen.getByText("This is a land ad description"); + const image = screen.getByAltText("Land Sale"); + + // You can add more assertions for other data elements + + expect(category).toBeInTheDocument(); + expect(title).toBeInTheDocument(); + expect(description).toBeInTheDocument(); + expect(image).toBeInTheDocument(); +}); diff --git a/src/__test__/category.test.js b/src/__test__/category.test.js new file mode 100644 index 0000000..2fab7db --- /dev/null +++ b/src/__test__/category.test.js @@ -0,0 +1,73 @@ +import React from "react"; +import { render, screen, waitFor } from "@testing-library/react"; +import CategoryDistribution from "layouts/graph/components/barCharts/categoryDist"; +import { getAdDistribution } from "api/graphViewer/adDistribution"; +import { BrowserRouter } from "react-router-dom"; +import { MaterialUIControllerProvider } from "context"; +import UserProvider from "utils/userContext"; +import theme from "assets/theme"; +import { ThemeProvider } from "@mui/material/styles"; + +// Mock the API function +jest.mock("api/graphViewer/adDistribution", () => ({ + getAdDistribution: jest.fn(), +})); + +describe("CategoryDistribution Component", () => { + it("renders the component with data", async () => { + const mockData = [ + { label: "Category 1", count: 10 }, + { label: "Category 2", count: 20 }, + // Add more data as needed + ]; + + // Mock the API function to return the data + getAdDistribution.mockResolvedValue(mockData); + + render( + + + + + + + + + + ); + + // Wait for the chart to be loaded + await waitFor(() => { + // Check if the chart is rendered with data + expect(screen.getByTestId("chart-container")).toBeInTheDocument(); + expect(screen.getByText("Distribution by Category")).toBeInTheDocument(); + const categoryText = screen.queryByText("Category 1"); + expect(categoryText).toBeInTheDocument(); + expect(screen.getByText("Category 2")).toBeInTheDocument(); + // You can add more assertions as needed + }); + }); + + it("renders the component with an error message on API failure", async () => { + // Mock the API function to simulate an error + getAdDistribution.mockRejectedValue(new Error("API Error")); + + render( + + + + + + + + + + ); + + // Wait for the error message to be displayed + await waitFor(() => { + expect(screen.getByText("Error fetching data:")).toBeInTheDocument(); + // You can add more assertions related to error handling + }); + }); +}); diff --git a/src/__test__/feedback.test.js b/src/__test__/feedback.test.js new file mode 100644 index 0000000..42fc2c1 --- /dev/null +++ b/src/__test__/feedback.test.js @@ -0,0 +1,122 @@ +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import FeedbackSection from "layouts/feedback/feedback"; +import { MaterialUIControllerProvider } from "context"; + +import theme from "assets/theme"; +import { ThemeProvider } from "@mui/material/styles"; +import UserProvider from "utils/userContext"; +import { BrowserRouter } from "react-router-dom"; + +jest.mock("react-router-dom", () => ({ + ...jest.requireActual("react-router-dom"), + useLocation: () => jest.fn(), +})); + +describe("FeedbackSection", () => { + test("renders the feedback form", () => { + render( + + + + + + + + + + ); + + // Check if important elements are present + expect(screen.getByText("Rate our Newspaper Advertisement Analyzer")).toBeInTheDocument(); + expect(screen.getByText("Your Comment is extremely valuable to us")).toBeInTheDocument(); + expect(screen.getByText("Submit Feedback")).toBeInTheDocument(); + }); + + test("handles rating change", () => { + render( + + + + + + + + + + ); + const ratingStars = screen.getAllByText("★"); // Find all the star icons + + fireEvent.click(ratingStars[2]); // Click the third star + + expect(ratingStars[2]).toHaveStyle("color: orange"); + }); + + test("handles feedback input", () => { + render( + + + + + + + + + + ); + const feedbackInput = screen.getByPlaceholderText("Your comments..."); + + fireEvent.change(feedbackInput, { target: { value: "This is my feedback." } }); + + expect(feedbackInput).toHaveValue("This is my feedback."); + }); + + test("handles publish checkbox", () => { + render( + + + + + + + + + + ); + const publishCheckbox = screen.getByLabelText( + "We value your privacy. Check the box if you like to publish your feedback" + ); + + fireEvent.click(publishCheckbox); + + expect(publishCheckbox).toBeChecked(); + }); + + test("submits feedback", () => { + render( + + + + + + + + + + ); + const submitButton = screen.getByText("Submit Feedback"); + const feedbackInput = screen.getByPlaceholderText("Your comments..."); + + // Simulate user interactions + fireEvent.click(screen.getAllByText("★")[4]); // Click the fifth star + fireEvent.change(feedbackInput, { target: { value: "Great experience!" } }); + fireEvent.click( + screen.getByLabelText( + "We value your privacy. Check the box if you like to publish your feedback" + ) + ); + fireEvent.click(submitButton); + + // Add your assertions here for what should happen after submitting feedback + }); +}); diff --git a/src/__test__/inputImage.test.js b/src/__test__/inputImage.test.js new file mode 100644 index 0000000..8c41ea0 --- /dev/null +++ b/src/__test__/inputImage.test.js @@ -0,0 +1,153 @@ +// Import necessary dependencies +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import ImageUploader from "layouts/upload/inputImage"; +import { BrowserRouter, MemoryRouter } from "react-router-dom"; +import { MaterialUIControllerProvider } from "context"; +import UserProvider from "utils/userContext"; +import { ThemeProvider } from "@mui/material"; +import theme from "assets/theme"; + +// Mock the user context +jest.mock("utils/userContext", () => ({ + useAppState: jest.fn(), +})); + +// Sample state for the mock user context +const mockUserContext = { + state: { + selectedFiles: [], + setSelectedFiles: jest.fn(), + imagePreviews: [], + setImagePreviews: jest.fn(), + imgBackendResponse: [], + setimgBackendResponse: jest.fn(), + }, +}; + +// Mock the useNavigate function from react-router-dom +const mockUseNavigate = jest.fn(); + +jest.mock("react-router-dom", () => ({ + useNavigate: () => mockUseNavigate, +})); + +// Mock the uploadImages function +jest.mock("api/sendImg", () => ({ + uploadImages: jest.fn(), +})); + +describe("ImageUploader Component", () => { + beforeEach(() => { + // Reset the mock functions and set the user context to the sample state + jest.clearAllMocks(); + mockUseNavigate.mockClear(); + mockUserContext.state.selectedFiles = []; + mockUserContext.state.imagePreviews = []; + mockUserContext.state.imgBackendResponse = []; + }); + + it("renders the component with initial instructions", () => { + // Use the sample user context in the test + jest + .spyOn(require("utils/userContext"), "useAppState") + .mockImplementation(() => mockUserContext); + + render( + + + + + + + + + + ); + + // Ensure the initial instructions are displayed + expect(screen.getByText(/Drag and drop images here/i)).toBeInTheDocument(); + }); + + it("allows file selection and displays selected files count", () => { + // Use the sample user context in the test + jest + .spyOn(require("utils/userContext"), "useAppState") + .mockImplementation(() => mockUserContext); + + render( + + + + + + + + + + ); + + // Mock a file input change event with two valid image files + const imageInput = screen.getByLabelText("Upload Images"); + fireEvent.change(imageInput, { + target: { + files: [ + new File(["file1 content"], "file1.jpg", { type: "image/jpeg" }), + new File(["file2 content"], "file2.png", { type: "image/png" }), + ], + }, + }); + + // Ensure the selected files count is displayed + expect(screen.getByText(/2 files selected/i)).toBeInTheDocument(); + }); + + it("handles submission correctly", async () => { + // Use the sample user context in the test + jest + .spyOn(require("utils/userContext"), "useAppState") + .mockImplementation(() => mockUserContext); + + // Mock the uploadImages function to resolve with a sample response + const uploadImages = require("api/sendImg").uploadImages; + uploadImages.mockResolvedValue({ message: [{}, {}] }); + + render( + + + + + + + + + + ); + + // Mock a file input change event with a valid image file + const imageInput = screen.getByLabelText("Upload Images"); + fireEvent.change(imageInput, { + target: { + files: [new File(["file1 content"], "file1.jpg", { type: "image/jpeg" })], + }, + }); + + // Trigger the submission button click + const submitButton = screen.getByText(/Submit/i); + fireEvent.click(submitButton); + + // Ensure the backend response is logged + await screen.findByText(/Image upload response:/i); + + // Ensure the backend response is displayed correctly + expect(screen.getByText(/Advertisement 1/i)).toBeInTheDocument(); + expect(screen.getByText(/Advertisement 2/i)).toBeInTheDocument(); + + // Ensure the "View Locations" button works + const viewLocationsButton = screen.getByText(/View Locations/i); + fireEvent.click(viewLocationsButton); + + // Ensure that the navigation function is called with the correct route + expect(mockUseNavigate).toHaveBeenCalledWith("/advertisement_map?locations=undefined"); + }); +}); diff --git a/src/__test__/selenium/signin.js b/src/__test__/selenium/signin.js new file mode 100644 index 0000000..21b9a34 --- /dev/null +++ b/src/__test__/selenium/signin.js @@ -0,0 +1,17 @@ +const { Builder, Browser, By, Key, until } = require("selenium-webdriver"); + +(async function example() { + let driver = await new Builder().forBrowser(Browser.FIREFOX).build(); + try { + await driver.get("localhost:3000/authentication/signin"); + await driver.findElement(By.id("email")).sendKeys("test@advizor.com"); + await driver.findElement(By.id("password")).sendKeys("test"); + const buttonElement = await driver.findElement(By.id("sign-in-button")); // Change to your button's identifier + + // Click the button + await buttonElement.click(); + await driver.wait(until.titleIs("New Page Title"), 10000); + } finally { + await driver.quit(); + } +})(); diff --git a/src/api/feedback/getFeedback.js b/src/api/feedback/getFeedback.js new file mode 100644 index 0000000..3bb48ae --- /dev/null +++ b/src/api/feedback/getFeedback.js @@ -0,0 +1,13 @@ +// api.js +import axios from "axios"; +import baseURL from "config"; + +export async function getFeedbackData() { + try { + const response = await axios.get(`${baseURL}/getFeedbackData`); // Adjust the endpoint URL + return response.data; + } catch (error) { + console.error("Error getting feedback data:", error); + throw error; + } +} diff --git a/src/api/feedback/saveFeedback.js b/src/api/feedback/saveFeedback.js new file mode 100644 index 0000000..b90d5f1 --- /dev/null +++ b/src/api/feedback/saveFeedback.js @@ -0,0 +1,13 @@ +// api.js +import axios from "axios"; +import baseURL from "config"; + +export async function submitFeedback(data) { + try { + const response = await axios.post(`${baseURL}/submitFeedback`, data); + return response.data; + } catch (error) { + console.error("Error submitting feedback:", error); + throw error; + } +} diff --git a/src/api/report/reportsdata.js b/src/api/report/reportsdata.js index ddb1cc1..cdbb26a 100644 --- a/src/api/report/reportsdata.js +++ b/src/api/report/reportsdata.js @@ -2,9 +2,9 @@ import axios from "axios"; import baseURL from "config"; // Function to fetch data from the backend -export async function getReportList() { +export async function getReportList(userID) { try { - const response = await axios.get(`${baseURL}/get-all-reports`); // Adjust the endpoint URL + const response = await axios.post(`${baseURL}/get-all-reports`, { userID }); // Adjust the endpoint URL console.log(response.data); return response.data; } catch (error) { diff --git a/src/api/updateUser/updateUser.js b/src/api/updateUser/updateUser.js new file mode 100644 index 0000000..b0873a9 --- /dev/null +++ b/src/api/updateUser/updateUser.js @@ -0,0 +1,14 @@ +import axios from "axios"; +import baseURL from "config"; + +// Function to update user information on the backend +export async function updateUser(userData) { + try { + const response = await axios.post(`${baseURL}/updateUser`, userData); // Adjust the endpoint URL + console.log(response.data); + return response.data; + } catch (error) { + console.error("Error updating user data on the backend:", error); + throw error; + } +} diff --git a/src/assets/images/socrates.jpeg b/src/assets/images/socrates.jpeg new file mode 100644 index 0000000..e8307fa Binary files /dev/null and b/src/assets/images/socrates.jpeg differ diff --git a/src/config.js b/src/config.js index beb0297..50706e1 100644 --- a/src/config.js +++ b/src/config.js @@ -1,5 +1,5 @@ // config.js -// const baseURL = "http://localhost:5000"; +const baseURL = "http://localhost:5000"; -const baseURL = "https://advizor-server-d27fd1ef5a20.herokuapp.com"; +// const baseURL = "https://advizor-server-d27fd1ef5a20.herokuapp.com"; export default baseURL; diff --git a/src/context/index.js b/src/context/index.js index c88bb6e..0a4c91f 100644 --- a/src/context/index.js +++ b/src/context/index.js @@ -76,7 +76,7 @@ function MaterialUIControllerProvider({ children }) { whiteSidenav: false, sidenavColor: "info", transparentNavbar: true, - fixedNavbar: true, + fixedNavbar: false, openConfigurator: false, direction: "ltr", layout: "dashboard", diff --git a/src/examples/Cards/InfoCards/ProfileInfoCard/index.js b/src/examples/Cards/InfoCards/ProfileInfoCard/index.js index 891ef8f..04df700 100644 --- a/src/examples/Cards/InfoCards/ProfileInfoCard/index.js +++ b/src/examples/Cards/InfoCards/ProfileInfoCard/index.js @@ -32,15 +32,18 @@ import MDTypography from "components/MDTypography"; // Material Dashboard 2 React base styles import colors from "assets/theme/base/colors"; import typography from "assets/theme/base/typography"; +import UpdateInfoModal from "./updateInfo"; +import { useState } from "react"; function ProfileInfoCard({ title, description, info, social, action, shadow }) { const labels = []; const values = []; const { socialMediaColors } = colors; const { size } = typography; + const [updatedInfo, setUpdatedInfo] = useState(info); // Convert this form `objectKey` of the object key in to this `object key` - Object.keys(info).forEach((el) => { + Object.keys(updatedInfo).forEach((el) => { if (el.match(/[A-Z\s]+/)) { const uppercaseLetter = Array.from(el).find((i) => i.match(/[A-Z]+/)); const newElement = el.replace(uppercaseLetter, ` ${uppercaseLetter.toLowerCase()}`); @@ -52,7 +55,7 @@ function ProfileInfoCard({ title, description, info, social, action, shadow }) { }); // Push the object values into the values array - Object.values(info).forEach((el) => values.push(el)); + Object.values(updatedInfo).forEach((el) => values.push(el)); // Render the card info items const renderItems = labels.map((label, key) => ( @@ -84,6 +87,22 @@ function ProfileInfoCard({ title, description, info, social, action, shadow }) { )); + const [isModalOpen, setIsModalOpen] = useState(false); + + const handleOpenModal = () => { + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + }; + + const handleSaveInfo = (updatedInformation) => { + // Handle saving updated info (e.g., make an API call) + console.log("Updated info:", updatedInformation); + setUpdatedInfo(updatedInformation); + }; + return ( @@ -92,9 +111,15 @@ function ProfileInfoCard({ title, description, info, social, action, shadow }) { - edit + edit + diff --git a/src/examples/Cards/InfoCards/ProfileInfoCard/updateInfo.js b/src/examples/Cards/InfoCards/ProfileInfoCard/updateInfo.js new file mode 100644 index 0000000..0ab3047 --- /dev/null +++ b/src/examples/Cards/InfoCards/ProfileInfoCard/updateInfo.js @@ -0,0 +1,119 @@ +import React, { useState } from "react"; +import PropTypes from "prop-types"; + +import Modal from "@mui/material/Modal"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Grid from "@mui/material/Grid"; +import MDTypography from "components/MDTypography"; +import MDInput from "components/MDInput"; +import MDButton from "components/MDButton"; +import { updateUser } from "api/updateUser/updateUser"; +import { useUser } from "utils/userContext"; + +function UpdateInfoModal({ open, onClose, onSave, initialValues }) { + const [formData, setFormData] = useState(initialValues); + const { user } = useUser(); + + const handleInputChange = (e) => { + const { name, value } = e.target; + setFormData({ + ...formData, + [name]: value, + }); + }; + + const handleSave = async () => { + onSave(formData); + try { + const userId = user.user_ID; // Extract the user ID from the form data + const { fullName, mobile, profession, location } = formData; + console.log(formData); + const userData = { fullName, mobile, profession, location, userId }; + await updateUser(userData); // Call the updateUser API function + + onClose(); // Close the modal after the update is successful + } catch (error) { + console.error("Error updating user information:", error); + // Handle the error as needed + } + }; + + return ( + + + + + + + Update Personal Information + + + +
+ +
+ +
+ +
+ + {/* Add more fields as needed */} + +
+ + + Save + +
+ + Cancel + +
+
+
+
+
+ ); +} + +UpdateInfoModal.propTypes = { + open: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, + onSave: PropTypes.func.isRequired, + initialValues: PropTypes.object.isRequired, +}; + +export default UpdateInfoModal; diff --git a/src/examples/Cards/ProjectCards/DefaultProjectCard/index.js b/src/examples/Cards/ProjectCards/DefaultProjectCard/index.js index 85cbc6e..3f7c523 100644 --- a/src/examples/Cards/ProjectCards/DefaultProjectCard/index.js +++ b/src/examples/Cards/ProjectCards/DefaultProjectCard/index.js @@ -29,6 +29,7 @@ import MDBox from "components/MDBox"; import MDTypography from "components/MDTypography"; import MDButton from "components/MDButton"; import MDAvatar from "components/MDAvatar"; +import { useRef, useState, useEffect } from "react"; function DefaultProjectCard({ image, label, title, description, action, authors }) { const renderAuthors = authors.map(({ image: media, name }) => ( @@ -51,8 +52,39 @@ function DefaultProjectCard({ image, label, title, description, action, authors )); + const cardRef = useRef(); + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + const checkVisibility = () => { + if (cardRef.current) { + const rect = cardRef.current.getBoundingClientRect(); + setIsVisible(rect.top < window.innerHeight); + } + }; + + // Initial check + checkVisibility(); + + // Add a scroll event listener to check if the card is in view + window.addEventListener("scroll", checkVisibility); + + return () => { + // Clean up the event listener when the component unmounts + window.removeEventListener("scroll", checkVisibility); + }; + }, []); + + const cardStyle = { + animation: "fadeIn 2s ease-out", + opacity: 0, // Initial opacity set to 0 + transform: "translateY(20px)", // Initial position below the viewport + }; + return ( { + const starArray = []; + for (let i = 0; i < rating; i++) { + starArray.push(); // Render a star character + } + return starArray; +}; function ManageFeedback() { - // Assuming feedbackData is an array of feedback objects - const feedbackData = [ - { - name: "John Doe", - email: "johndoe@example.com", - date: "2023-09-01", - message: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eget justo eu urna condimentum elementum vel eget enim.", - }, - { - name: "Jane Smith", - email: "janesmith@example.com", - date: "2023-09-02", - message: - "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas quis fringilla libero.", - }, - { - name: "Alice Johnson", - email: "alicejohnson@example.com", - date: "2023-09-03", - message: - "Vestibulum in metus eu ipsum finibus auctor. Curabitur feugiat urna eget elit dictum, eget elementum quam cursus.", - }, - // Add more feedback objects as needed - ]; + const [feedbackData, setFeedbackData] = useState([]); + + useEffect(() => { + // Fetch feedback data when the component mounts + async function fetchFeedbackData() { + try { + const data = await getFeedbackData(); + setFeedbackData(data); + } catch (error) { + console.error("Error fetching feedback data:", error); + } + } + fetchFeedbackData(); + }, []); return ( @@ -39,13 +38,20 @@ function ManageFeedback() {
- {feedback.name} + {feedback.user_name} + + + {feedback.email} - {feedback.email} | {feedback.date} + {feedback.rating && renderRatingStars(feedback.rating)} |{" "} + {feedback.date && new Date(feedback.date).toDateString()} + + + {feedback.feedback} - {feedback.message} + {feedback.timestamp && new Date(feedback.timestamp).toLocaleString()} {/* You can add buttons or actions here for managing feedback */}
diff --git a/src/layouts/advertisement/addetails.js b/src/layouts/advertisement/addetails.js index e9966b3..7e236cc 100644 --- a/src/layouts/advertisement/addetails.js +++ b/src/layouts/advertisement/addetails.js @@ -233,7 +233,7 @@ const Addetail = () => { - + General Information diff --git a/src/layouts/authentication/sign-in/index.js b/src/layouts/authentication/sign-in/index.js index b29969f..157669d 100644 --- a/src/layouts/authentication/sign-in/index.js +++ b/src/layouts/authentication/sign-in/index.js @@ -211,6 +211,7 @@ function Basic() { + + + Use "test@advizor.com" and "test" as demo-credentials + + - + Log in diff --git a/src/layouts/authentication/sign-up/VerificationDialog.js b/src/layouts/authentication/sign-up/VerificationDialog.js index d303454..fa1219a 100644 --- a/src/layouts/authentication/sign-up/VerificationDialog.js +++ b/src/layouts/authentication/sign-up/VerificationDialog.js @@ -8,6 +8,7 @@ import DialogContentText from "@mui/material/DialogContentText"; import DialogTitle from "@mui/material/DialogTitle"; import TextField from "@mui/material/TextField"; import Button from "@mui/material/Button"; +import baseURL from "config"; export default function VerificationDialog({ open, onClose, email, onSuccess }) { const [verificationCode, setVerificationCode] = useState(""); @@ -35,7 +36,7 @@ export default function VerificationDialog({ open, onClose, email, onSuccess }) const handleVerificationSubmit = () => { if (verificationCode) { axios - .post("/verify", { + .post(`${baseURL}/verify`, { email: email, verificationCode: verificationCode, }) @@ -60,7 +61,7 @@ export default function VerificationDialog({ open, onClose, email, onSuccess }) const handleCancel = () => { axios - .post("/verify", { + .post(`${baseURL}/verify`, { email: email, verificationCode: "", // Provide an empty code to indicate cancellation cancel: true, // Add a flag to indicate cancellation diff --git a/src/layouts/authentication/sign-up/index.js b/src/layouts/authentication/sign-up/index.js index 08de6ee..989f6c7 100644 --- a/src/layouts/authentication/sign-up/index.js +++ b/src/layouts/authentication/sign-up/index.js @@ -1,18 +1,3 @@ -/** -========================================================= -* Material Dashboard 2 React - v2.2.0 -========================================================= - -* Product Page: https://www.creative-tim.com/product/material-dashboard-react -* Copyright 2023 Creative Tim (https://www.creative-tim.com) - -Coded by www.creative-tim.com - - ========================================================= - -* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -*/ - // react-router-dom components import React, { useState } from "react"; // import axios from "axios"; @@ -40,6 +25,7 @@ import VerificationDialog from "./VerificationDialog"; import { useNavigate } from "react-router-dom"; import { useUser } from "utils/userContext"; import baseURL from "config"; +import TermModal from "./term"; function Cover() { const [email, setEmail] = useState(""); @@ -49,7 +35,13 @@ function Cover() { const [showSuccessAlert, setShowSuccessAlert] = useState(false); const { login } = useUser(); - const [verificationOpen, setVerificationOpen] = useState(false); // State to manage the dialog + const [verificationOpen, setVerificationOpen] = useState(false); + + const [emailError, setEmailError] = useState(""); + const [passwordError, setPasswordError] = useState(""); + const [nameError, setNameError] = useState(""); + + const [termsAccepted, setTermsAccepted] = useState(false); const handleRegister = () => { console.log("email: ", email); @@ -60,6 +52,29 @@ function Cover() { alert("Please fill all the fields"); return; } + + const namePattern = /^[A-Za-z0-9_.-]+( [A-Za-z0-9_.-]+)*$/; + if (!namePattern.test(name)) { + setNameError("Invalid name"); + return; + } else { + setNameError(""); + } + const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; + if (!emailPattern.test(email)) { + setEmailError("Invalid email address"); + return; + } else { + setEmailError(""); + } + + if (password.length < 6) { + setPasswordError("Password must be at least 6 characters long."); + return; + } else { + setPasswordError(""); + } + fetch(`${baseURL}/signup`, { method: "POST", headers: { @@ -81,6 +96,17 @@ function Cover() { console.log(data); // Handle success, e.g., show a success message to the user // alert(data.message); + const userData = data.user; + console.log(userData); + login({ + name: userData.User_Name, + full_name: userData.Full_Name, + user_ID: userData.UserID, + role: userData.Role, + email: userData.email, + phone_Number: userData.Contact_Number, + profession: userData.Profession, + }); setVerificationOpen(true); // navigate("/dashboard"); @@ -92,6 +118,15 @@ function Cover() { alert("An error occurred during registration."); }); }; + const [isModalOpen, setIsModalOpen] = useState(false); + + const handleOpenModal = () => { + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + }; return ( @@ -130,6 +165,7 @@ function Cover() { onChange={(e) => setName(e.target.value)} required /> + {nameError &&

{nameError}

}
setEmail(e.target.value)} required /> + {emailError &&

{emailError}

}
setPassword(e.target.value)} required /> + {passwordError &&

{passwordError}

}
- + setTermsAccepted(e.target.checked)} /> Terms and Conditions + - + sign up @@ -205,7 +251,6 @@ function Cover() { setShowSuccessAlert(true); setTimeout(() => { setShowSuccessAlert(false); - login({ name: name, role: "user" }); navigate("/dashboard"); }, 1000); }} diff --git a/src/layouts/authentication/sign-up/term.js b/src/layouts/authentication/sign-up/term.js new file mode 100644 index 0000000..09ece52 --- /dev/null +++ b/src/layouts/authentication/sign-up/term.js @@ -0,0 +1,107 @@ +import React from "react"; +import PropTypes from "prop-types"; + +import Modal from "@mui/material/Modal"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Grid from "@mui/material/Grid"; +import MDTypography from "components/MDTypography"; + +function TermModal({ open, onClose }) { + const cardContentStyle = { + // Add your desired width and height for the modal + width: "80%", // Adjust as needed + height: "80vh", // Adjust as needed + overflowY: "scroll", // Add a vertical scroll when the content exceeds the height + }; + return ( + + + + + + + Welcome to the Digital Newspaper Advertisement Analyzer. + + + Please read these Terms and Conditions ("Terms") carefully before using + this service. + + + Acceptance of Terms + + + By using the Digital Newspaper Advertisement Analyzer (hereafter referred to as + "the Service"), you agree to comply with and be bound by these Terms. If + you do not agree with any part of these Terms, you should not use the Service. +

+ + Use of the Service + + You must be at least 18 years old to use this Service. You are responsible for + maintaining the security of your account and password. The Service cannot and will + not be liable for any loss or damage from your failure to comply with this security + obligation.

+ + Privacy + + Your use of the Service is also governed by our Privacy Policy. Please review our + Privacy Policy to understand our data practices.

+ + User Content + + You retain the rights to your content, but you grant the Service a worldwide, + royalty-free, non-exclusive license to use, distribute, reproduce, modify, adapt, + and publish your content solely for the purpose of displaying, distributing, and + promoting the Service. You agree not to use the Service to submit or link to any + content which is defamatory, abusive, hateful, threatening, spam, or spam-like.{" "} +

+ + Intellectual Property + + The Service and its original content (excluding user-provided content) are protected + by copyright, trademark, patent, trade secret, and other laws. You may not modify, + reproduce, distribute, create derivative works or adaptations of, publicly display + or in any way exploit any of the content in whole or in part except as expressly + authorized by the Service. Trademarks, service marks, graphics, and logos used in + connection with the Service are trademarks or registered trademarks of the + Service's licensors. You are granted no right or license with respect to any of + the aforesaid trademarks.

+ + Termination + + We may terminate or suspend access to our Service immediately, without prior notice + or liability, for any reason whatsoever, including without limitation if you breach + the Terms.

+ + Changes to the Terms + + We reserve the right, at our sole discretion, to modify or replace these Terms at + any time. If a revision is material, we will try to provide at least 30 days' + notice prior to any new terms taking effect. What constitutes a material change will + be determined at our sole discretion.

+ + Contact Us{" "} + + If you have any questions about these Terms, please contact us.

By using + the Digital Newspaper Advertisement Analyzer, you agree to these Terms and + Conditions. Thank you for using our service! +
+
+
+
+
+
+ ); +} + +TermModal.propTypes = { + open: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, +}; + +export default TermModal; diff --git a/src/layouts/feedback/feedback.js b/src/layouts/feedback/feedback.js new file mode 100644 index 0000000..76d01af --- /dev/null +++ b/src/layouts/feedback/feedback.js @@ -0,0 +1,96 @@ +// FeedbackSection.jsx +import { Card, Checkbox, TextField } from "@mui/material"; +import MDBox from "components/MDBox"; +import MDButton from "components/MDButton"; +import MDTypography from "components/MDTypography"; +import React, { useState } from "react"; +import { submitFeedback } from "api/feedback/saveFeedback"; +import { useUser } from "utils/userContext"; + +const FeedbackSection = () => { + const [rating, setRating] = useState(0); + const [feedback, setFeedback] = useState(""); + const [publish, setPublish] = useState(false); + const { user } = useUser(); + const userID = user.user_ID; + + const handleRatingChange = (newRating) => { + setRating(newRating); + }; + + const handleFeedbackChange = (e) => { + setFeedback(e.target.value); + }; + + const handlePublishChange = (e) => { + setPublish(e.target.checked); + }; + + const handleSubmitFeedback = async () => { + try { + await submitFeedback({ rating, feedback, publish, userID }); // Using the submitFeedback function from the API + setRating(0); + setFeedback(""); + } catch (error) { + console.error("Error submitting feedback:", error); + } + }; + + return ( + + +
+ + Rate our Newspaper Advertisement Analyzer + + + {[1, 2, 3, 4, 5].map((star) => ( + handleRatingChange(star)} + style={{ + cursor: "pointer", + color: star <= rating ? "orange" : "gray", + fontSize: "50px", + }} + > + ★ + + ))} + +
+
+ Your Comment is extremely valuable to us + +
+
+ + +
+ + + Submit Feedback + + +
+
+ ); +}; + +export default FeedbackSection; diff --git a/src/layouts/feedback/index.js b/src/layouts/feedback/index.js new file mode 100644 index 0000000..6093f24 --- /dev/null +++ b/src/layouts/feedback/index.js @@ -0,0 +1,14 @@ +import DashboardLayout from "examples/LayoutContainers/DashboardLayout"; +import DashboardNavbar from "examples/Navbars/DashboardNavbar"; +import React from "react"; +import FeedbackSection from "./feedback"; +const Feedback = () => { + return ( + + + + + ); +}; + +export default Feedback; diff --git a/src/layouts/graph/components/barCharts/categoryDist.js b/src/layouts/graph/components/barCharts/categoryDist.js index ecedb51..4f32c1a 100644 --- a/src/layouts/graph/components/barCharts/categoryDist.js +++ b/src/layouts/graph/components/barCharts/categoryDist.js @@ -24,25 +24,27 @@ function CategoryDistribution() { return ( - data.label), - datasets: [ - { - label: "Distribution Count", - color: "primary", - data: adDistribution.map((data) => data.count), // Use the data from the API - }, - ], - }} - action={{ - type: "internal", // or "external" based on your use case - route: "/reports/Category Distribution", // Define the route - }} - /> +
+ data.label), + datasets: [ + { + label: "Distribution Count", + color: "primary", + data: adDistribution.map((data) => data.count), // Use the data from the API + }, + ], + }} + action={{ + type: "internal", // or "external" based on your use case + route: "/reports/Category Distribution", // Define the route + }} + /> +
); } diff --git a/src/layouts/landing/App.js b/src/layouts/landing/App.js index b948a8b..61747ea 100644 --- a/src/layouts/landing/App.js +++ b/src/layouts/landing/App.js @@ -2,24 +2,65 @@ import React from "react"; import Hero from "./Page/Hero"; import Snippets from "./Page/Snippets"; import Access from "./Page/Access"; -// import Supercharge from "./Page/Supercharge"; -// import Agents from "./Page/Agents"; -// import Action from "./Page/Action"; +import Supercharge from "./Page/Supercharge"; +import Agents from "./Page/Agents"; +import Action from "./Page/Action"; // import Footer from "./Page/Footer"; import "./index.css"; // import DashboardLayout from "examples/LayoutContainers/DashboardLayout"; // import DashboardNavbar from "examples/Navbars/DashboardNavbar"; +// import backgroundImage from "./Assets/images/background8.jpg"; +import DefaultNavbar from "examples/Navbars/DefaultNavbar"; +import Configurator from "examples/Configurator"; +import { useMaterialUIController, setOpenConfigurator } from "context"; +import Icon from "@mui/material/Icon"; +import MDBox from "components/MDBox"; function App() { + const containerStyle = { + // backgroundImage: `url(${backgroundImage})`, + backgroundSize: "cover", + backgroundRepeat: "no-repeat", + }; + const [controller, dispatch] = useMaterialUIController(); + const { openConfigurator } = controller; + const handleConfiguratorOpen = () => setOpenConfigurator(dispatch, !openConfigurator); + const configsButton = ( + + + settings + + + ); + return ( -
+
+ + + {configsButton} - {/* + - */} +
{/*
*/} diff --git a/src/layouts/landing/Assets/images/background2.jpg b/src/layouts/landing/Assets/images/background2.jpg new file mode 100644 index 0000000..795f044 Binary files /dev/null and b/src/layouts/landing/Assets/images/background2.jpg differ diff --git a/src/layouts/landing/Assets/images/background4.jpg b/src/layouts/landing/Assets/images/background4.jpg new file mode 100644 index 0000000..a982c79 Binary files /dev/null and b/src/layouts/landing/Assets/images/background4.jpg differ diff --git a/src/layouts/landing/Assets/images/background5.jpg b/src/layouts/landing/Assets/images/background5.jpg new file mode 100644 index 0000000..8fa11be Binary files /dev/null and b/src/layouts/landing/Assets/images/background5.jpg differ diff --git a/src/layouts/landing/Assets/images/background6.jpg b/src/layouts/landing/Assets/images/background6.jpg new file mode 100644 index 0000000..7082fe0 Binary files /dev/null and b/src/layouts/landing/Assets/images/background6.jpg differ diff --git a/src/layouts/landing/Assets/images/background7.jpg b/src/layouts/landing/Assets/images/background7.jpg new file mode 100644 index 0000000..77bf73c Binary files /dev/null and b/src/layouts/landing/Assets/images/background7.jpg differ diff --git a/src/layouts/landing/Assets/images/background8.jpg b/src/layouts/landing/Assets/images/background8.jpg new file mode 100644 index 0000000..999f930 Binary files /dev/null and b/src/layouts/landing/Assets/images/background8.jpg differ diff --git a/src/layouts/landing/Page/Hero.js b/src/layouts/landing/Page/Hero.js index 7a28e2b..ef45946 100644 --- a/src/layouts/landing/Page/Hero.js +++ b/src/layouts/landing/Page/Hero.js @@ -3,11 +3,15 @@ import Buttons from "../Components/Buttons"; import IMAGES from "../Assets/Images"; import MDTypography from "components/MDTypography"; import MDBox from "components/MDBox"; +import MDButton from "components/MDButton"; +import SendIcon from "@mui/icons-material/Send"; +import { Link } from "react-router-dom"; function Hero() { return (
+
logo
@@ -18,7 +22,20 @@ function Hero() { Discover the power of data-driven analysis with our Newspaper Advertisement Analyzer. Decode ad trends, demographics, and more with precision and ease. - + + } + > + Get Started + + +
diff --git a/src/layouts/landing/Page/Snippets.js b/src/layouts/landing/Page/Snippets.js index 88740ef..290738f 100644 --- a/src/layouts/landing/Page/Snippets.js +++ b/src/layouts/landing/Page/Snippets.js @@ -20,14 +20,26 @@ function Snippets() { computers
-

Graph Visulaization

-

Render detailed graphs and charts to visualize complex data

+ + Graph Visulaization + + + Render detailed graphs and charts to visualize complex data + -

Report Generation

-

Create and Download customized Reports

+ + Report Generation + + + Create and Download customized Reports + -

Reports History

-

Access your previous Reports easily

+ + Reports History + + + Access your previous Reports easily +
diff --git a/src/layouts/landing/index.css b/src/layouts/landing/index.css index 42fed55..01c6533 100644 --- a/src/layouts/landing/index.css +++ b/src/layouts/landing/index.css @@ -24,7 +24,7 @@ .landing-page body { font-family: "Bai Jamjuree", sans-serif; - background: url(./Assets/images/background.jpg) no-repeat; + background: url(./Assets/images/background2.jpg) no-repeat; background-size: 100%; font-size: 1.6rem; text-align: center; @@ -195,7 +195,8 @@ .landing-page .snippets__body{ display: flex; - gap: 5%; + gap: 10%; + margin-top: 5em; } .landing-page .snippets__body__text{ @@ -253,4 +254,75 @@ margin-left: auto; margin-right: auto; } +} +.btn { + transition: all 0.3s ease-in-out; + font-family: "Dosis", sans-serif; +} + +.btn { + width: 150px; + height: 60px; + border-radius: 50px; + background-image: linear-gradient(135deg, #feb692 0%, #ea5455 100%); + box-shadow: 0 20px 30px -6px rgba(238, 103, 97, 0.5); + outline: none; + cursor: pointer; + border: none; + font-size: 24px; + color: white; +} + +.btn:hover { + transform: translateY(3px); + box-shadow: none; +} + +.btn:active { + opacity: 0.5; +} + +.demo a { + padding-top: 70px; +} +.demo a span { + position: absolute; + top: 0; + left: 50%; + width: 24px; + height: 24px; + margin-left: -12px; + border-left: 1px solid #fff; + border-bottom: 1px solid #fff; + -webkit-transform: rotate(-45deg); + transform: rotate(-45deg); + -webkit-animation: sdb05 1.5s infinite; + animation: sdb05 1.5s infinite; + box-sizing: border-box; +} +@-webkit-keyframes sdb05 { + 0% { + -webkit-transform: rotate(-45deg) translate(0, 0); + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + -webkit-transform: rotate(-45deg) translate(-20px, 20px); + opacity: 0; + } +} +@keyframes sdb05 { + 0% { + transform: rotate(-45deg) translate(0, 0); + opacity: 0; + } + 50% { + opacity: 1; + } + 100% { + transform: rotate(-45deg) translate(-20px, 20px); + opacity: 0; + } } \ No newline at end of file diff --git a/src/layouts/profile/components/Header/index.js b/src/layouts/profile/components/Header/index.js index 9a8fc4c..1c93135 100644 --- a/src/layouts/profile/components/Header/index.js +++ b/src/layouts/profile/components/Header/index.js @@ -35,7 +35,7 @@ import MDAvatar from "components/MDAvatar"; import breakpoints from "assets/theme/base/breakpoints"; // Images -import burceMars from "assets/images/bruce-mars.jpg"; +import burceMars from "assets/images/socrates.jpeg"; import backgroundImage from "assets/images/bg-profile.jpeg"; import { useUser } from "utils/userContext"; diff --git a/src/layouts/reports/data/reportsdata.js b/src/layouts/reports/data/reportsdata.js index 2d40fe8..328e2fd 100644 --- a/src/layouts/reports/data/reportsdata.js +++ b/src/layouts/reports/data/reportsdata.js @@ -21,6 +21,7 @@ import MDTypography from "components/MDTypography"; import MDBadge from "components/MDBadge"; import { useEffect, useState } from "react"; import { getReportList } from "api/report/reportsdata"; +import { useUser } from "utils/userContext"; export default function Data() { const Job = ({ title, description }) => ( @@ -33,10 +34,12 @@ export default function Data() { ); const [reportDetails, setReportsDetails] = useState([]); + const { user } = useUser(); + const userID = user.user_ID; useEffect(() => { // Fetch average price data from the Flask API endpoint - getReportList() + getReportList(userID) .then((data) => { setReportsDetails(data); console.log(data); // Use 'data' instead of 'reportDetails' diff --git a/src/layouts/reports/reports.js b/src/layouts/reports/reports.js index f5ad1e1..8c6a434 100644 --- a/src/layouts/reports/reports.js +++ b/src/layouts/reports/reports.js @@ -3,9 +3,9 @@ import "jspdf-autotable"; import html2canvas from "html2canvas"; import * as XLSX from "xlsx"; -// import { savePdf } from "api/report/saveReport"; -// import { storage } from "../../firebase"; -// import { ref, uploadBytes, getDownloadURL } from "firebase/storage"; +import { savePdf } from "api/report/saveReport"; +import { storage } from "../../firebase"; +import { ref, uploadBytes, getDownloadURL } from "firebase/storage"; export const generateCSV = (data, filename) => { const csvContent = "data:text/csv;charset=utf-8," + data.map((row) => row.join(",")).join("\n"); @@ -55,24 +55,24 @@ const generatePDF = async (componentsToPrint, contentRef, title, user_ID) => { } doc.save(`${title}.pdf`); - // const pdfBlob = doc.output("blob"); + const pdfBlob = doc.output("blob"); const userID = user_ID; console.log(userID); - // const pdfRef = ref(storage, `Reports/${title}`); + const pdfRef = ref(storage, `Reports/${title}`); - // // Upload the PDF to Firebase Storage - // await uploadBytes(pdfRef, pdfBlob); + // Upload the PDF to Firebase Storage + await uploadBytes(pdfRef, pdfBlob); - // // Get the download URL of the uploaded PDF - // const downloadURL = await getDownloadURL(pdfRef); // Add this import: import { getDownloadURL } from "firebase/storage"; - // // Send the PDF URL to the backend using the savePdf function or do whatever you need with it - // const response = await savePdf(downloadURL, userID, title); + // Get the download URL of the uploaded PDF + const downloadURL = await getDownloadURL(pdfRef); // Add this import: import { getDownloadURL } from "firebase/storage"; + // Send the PDF URL to the backend using the savePdf function or do whatever you need with it + const response = await savePdf(downloadURL, userID, title); - // if (response && response.message) { - // console.log("PDF uploaded successfully!"); - // } else { - // console.error("Failed to upload PDF:", response.error); - // } + if (response && response.message) { + console.log("PDF uploaded successfully!"); + } else { + console.error("Failed to upload PDF:", response.error); + } } catch (error) { console.error("An error occurred while generating/uploading PDF:", error); } diff --git a/src/layouts/upload/guestindex.js b/src/layouts/upload/guestindex.js new file mode 100644 index 0000000..215a2e2 --- /dev/null +++ b/src/layouts/upload/guestindex.js @@ -0,0 +1,73 @@ +import React from "react"; + +import CenteredTabs from "./tabs"; +import MDBox from "components/MDBox"; +import DefaultNavbar from "examples/Navbars/DefaultNavbar"; +import Configurator from "examples/Configurator"; +import { useMaterialUIController, setOpenConfigurator } from "context"; +import Icon from "@mui/material/Icon"; +import SignInModal from "./guestsign"; +import { useEffect } from "react"; +import { useState } from "react"; + +function GuestExtractor() { + const [controller, dispatch] = useMaterialUIController(); + const { openConfigurator } = controller; + const handleConfiguratorOpen = () => setOpenConfigurator(dispatch, !openConfigurator); + const configsButton = ( + + + settings + + + ); + useEffect(() => { + const timer = setTimeout(() => { + handleOpenModal(); + }, 10000); // 5000 milliseconds (5 seconds) + + return () => { + clearTimeout(timer); + }; + }, []); + const [isModalOpen, setIsModalOpen] = useState(false); + + const handleOpenModal = () => { + setIsModalOpen(true); + }; + + const handleCloseModal = () => { + setIsModalOpen(false); + }; + return ( + <> + + + {configsButton} + + + + + + + + ); +} + +export default GuestExtractor; diff --git a/src/layouts/upload/guestsign.js b/src/layouts/upload/guestsign.js new file mode 100644 index 0000000..48f9459 --- /dev/null +++ b/src/layouts/upload/guestsign.js @@ -0,0 +1,59 @@ +import React from "react"; +import PropTypes from "prop-types"; + +import Modal from "@mui/material/Modal"; +import Card from "@mui/material/Card"; +import CardContent from "@mui/material/CardContent"; +import Grid from "@mui/material/Grid"; +import MDTypography from "components/MDTypography"; +import MDButton from "components/MDButton"; +import signinimage from "./signin.gif"; +import MDBox from "components/MDBox"; +import { Link } from "react-router-dom"; + +function SignInModal({ open, onClose }) { + return ( + + + + + + + Explore Extended Features Personalized For You. + + + Join With Us + + + undraw-Add-user-re-5oib + + + + + + Sign Up + + + + + + + ); +} + +SignInModal.propTypes = { + open: PropTypes.bool.isRequired, + onClose: PropTypes.func.isRequired, +}; + +export default SignInModal; diff --git a/src/layouts/upload/signin.gif b/src/layouts/upload/signin.gif new file mode 100644 index 0000000..f50c4c2 Binary files /dev/null and b/src/layouts/upload/signin.gif differ diff --git a/src/routes/routes.js b/src/routes/routes.js index 1df93a2..ddac5b7 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -22,6 +22,8 @@ import App from "layouts/landing/App"; import { useUser } from "utils/userContext"; import PropTypes from "prop-types"; import TBH from "layouts/TBI/tbi"; +import FeedbackSection from "layouts/feedback/index"; +import GuestExtractor from "layouts/upload/guestindex"; // ... @@ -106,7 +108,7 @@ const routes = [ key: "feedback", icon: feedback, route: "/feedback", - component: , + component: , }, { type: "collapse", @@ -148,6 +150,10 @@ const routes = [ route: "/landing", component: , }, + { + route: "/extractor", + component: , + }, { route: "/reports/:title", component: ,