From 663d97f6dc4d36e1f6e5d33ff9680c8e2ee2c5da Mon Sep 17 00:00:00 2001 From: "skillens.ai" Date: Thu, 30 Oct 2025 02:40:29 +0530 Subject: [PATCH] UI changes --- .firebase/hosting.YnVpbGQ.cache | 110 +-- src/component/Main/FuncHeader.jsx | 20 +- .../Student/Exams/AttemptExam/AttemptExam.css | 469 ++++++----- .../Student/Exams/AttemptExam/AttemptExam.js | 552 +++++++------ .../Exams/AttemptExam/QuestionDetail.js | 155 ++-- .../Student/Exams/LiveExams/LiveExams.js | 3 +- src/services/selectorService.js | 781 ++++++++++-------- 7 files changed, 1146 insertions(+), 944 deletions(-) diff --git a/.firebase/hosting.YnVpbGQ.cache b/.firebase/hosting.YnVpbGQ.cache index 44806f3..886e829 100644 --- a/.firebase/hosting.YnVpbGQ.cache +++ b/.firebase/hosting.YnVpbGQ.cache @@ -1,12 +1,12 @@ robots.txt,1761396900570,bfe106a3fb878dc83461c86818bf74fc1bdc7f28538ba613cd3e775516ce8b49 manifest.json,1761396900568,a9350a49aaac9fe94d3dd77b8270cc998c04ab97944a606189675022431faa51 favicon.svg,1761396900561,a2a4880301751061a600b0bfc5c26fc413aed41e581516c4fa976bcb7fff6663 -service-worker.js,1761576002341,023c58598eaf6728e3bbc8ed608e32fd608d37851fa12ce79816a48180c9cd31 -asset-manifest.json,1761576002341,d747a6089e42c15217b542311c92d5809e7cae25a755c6242d55d93072ac5281 -precache-manifest.816159c176bc481e03384d794646b865.js,1761576002341,8b8a70a80ada7aa8b5e21993a642189e9d1dbed0805111893a8ae9cdd5038c23 -static/media/sub-ques-icon.366b4f1e.svg,1761576002260,8e397611007ec5db7581a4c1bcca006950390ddf652cae209bb3973a645af425 -static/media/translate.610ad011.svg,1761576002262,c06f8a3d0c976b02429ce805d8a4944571ab0128ed2ce49c2d3ca134511ed120 -static/media/student-engaged.53fb7b0b.svg,1761576002257,5f8e01d1a5efcbdf3aa00ed07de843ab84404a28b672ca91f4d70d89fa8b37cf +service-worker.js,1761764783124,a4416108bc325f844ff2591db3c12fd9443bb2a3b4dedd09cee90e333e41bb51 +precache-manifest.f827a120dee6582417cfe4b1979f19d5.js,1761764783123,a4ff8d6cbb691d416e802893cc984f2135008b6167e99ee019b88d026a476a1f +static/media/tru-fals-icon.d0b962d8.svg,1761764783104,a1deab7e5db8e8a94a9c5812dcde5f8cbfbe5da790da8500bf106980b9c79c33 +asset-manifest.json,1761764783148,995b77288d91dfaddb18b8753357c286829de77928b93c12f5111f35a76670b8 +index.html,1761764783123,19c7a6e51b117070c55ac4aae347ca3434878b774a65a4a185b0914d2965a1c0 +static/media/translate.610ad011.svg,1761764783106,c06f8a3d0c976b02429ce805d8a4944571ab0128ed2ce49c2d3ca134511ed120 assets/images/locale-icon.svg,1761396900579,610498c7ca3b5800d268b1654473f0b1d79de2c6493a7c6982bef90456d35179 assets/images/icons/icon-96x96.png,1761396900602,43a8ac4df8945d7a44e3e4911032214f01eaea92267baa31a93e77942b424c73 assets/images/icons/icon-72x72.png,1761396900600,a42f1df8ab0a8fe921573976d49158e1a2c52fe430460c869947f221aba30a94 @@ -16,52 +16,52 @@ assets/images/icons/icon-192x192.png,1761396900592,ac9fe46fbeb4c54fb3c838b645380 assets/images/icons/icon-152x152.png,1761396900590,95a5a117fbd5640f1f1f13c9923398545e3f5b66734ff6c8ce67c942319a8b67 assets/images/icons/icon-144x144.png,1761396900588,e42168e0e1abb5bd7811ebe1b5a2183d0ce287bf266c2efd8d97a23d23ca8d00 assets/images/icons/icon-128x128.png,1761396900585,45b577c86e7c03fef868bfa3f96810c5b36f31156c32c0d85620d2e6fe1fc85b -index.html,1761576002341,7983b57b52860a70c9a6382d9b2bae797ed4b2b744dbd7af42a74464f9f5e2b2 -static/media/quizexam.5545802e.svg,1761576002242,dfc1278bfcd264264a4d0e0e0247c229335abf0573439c5e9829c8607aacd569 -static/media/question.0c505ed9.svg,1761576002242,29938066f93476c487414bb7a5dd5227d891c8ab8e115a74a7e7ffccd8d87b36 -static/media/questions-icon.3d3c1aaf.svg,1761576002254,197f459a359b00c1c44b6ddd71cbc9160f593d1fe08534e3711e9d72a2956ef1 -static/media/practice.f05e6f00.svg,1761576002244,13b094bcbbb8c50906b1ee0ce68305059e99319464dd4147b4c2194dbb460475 -static/media/PracticeKiaLogo.a8336af5.svg,1761576002241,1a592518bcfabb2f86669d06ae2fb7b2948bbdbfaf5a80d138ab30f4e482a0f8 -static/media/practice-icon.bf603115.svg,1761576002256,27b6a729d91914d899f4b3c1f817e26ac58d2ec0be54dc9b93c01f28adcdd00c -static/media/perf-icon.1597a235.svg,1761576002258,7183482b785de425506f49deb27bba02e906132ac7ce5af01f7da8452ef64f28 -static/media/performance.88855f12.svg,1761576002247,03fc1b19005084049382091745d3f1f29a447763091ad4a9bc5d097c338671c9 -static/media/tru-fals-icon.d0b962d8.svg,1761576002260,a1deab7e5db8e8a94a9c5812dcde5f8cbfbe5da790da8500bf106980b9c79c33 -static/media/mul-res-icon.8ef3b097.svg,1761576002257,1f0a79350cb5546361ef02af1657ad36efeff833fd7bb61db88a20e127a290b4 -static/media/mul-cho-icon.b3dc9ea9.svg,1761576002260,e8edbceb0eb49f7629cf0b8edf599f9347acbf0c6d1df2fa6145cbed03f37e1f -static/media/locale-icon.b3596424.svg,1761576002254,68618c76952aa4c5f2623bb010514871688960bb3b9edbcda0eab7eb75442054 -static/media/OdiSVGlogo.f0834bb1.svg,1761576002242,3ec1cab31a32db378894d796afedaee7c35f8ff99dfb1039b0bb757225a47235 -static/media/getFetch.2b2b7da4.cjs,1761576002242,b2d82abee5b8af22b81d67fc20b3feef1eaaf04585dbc24ec755e3304c469096 -static/media/exam-icon.10f48851.svg,1761576002256,b766e9975582af716870a844f8deabd4d80e33a47c400d36cee6bc4840062693 -static/media/GrayscalePKLogo.6bb74404.svg,1761576002242,576b38300e49eda6407adce420001e7ad0333cca317eb668aff457c3258dcca2 -static/media/delete-icon.da38c0f4.svg,1761576002263,8078772ee88a0588989eec477da1ca949430f3f06efaa9c2db860b74c65f6722 -static/media/dashboard.8ec7624b.svg,1761576002242,5a5b5d4bf416d414842bd5eac30432b592342a392450e52943f067db4077bec1 -static/media/classes.3b73dba0.svg,1761576002244,2abfbb7015d5bccb8640fd0614d3782c048672c9543fe17d127db63287ac141d -static/media/Checkmark.1356376c.svg,1761576002270,aa56f27c8198bcae3236a881a7134cd3b7d3dbb048ec75654e8ce2d4710ce027 -static/media/feature-2.36f8d7e2.webp,1761576002242,fc1c038517abf3b731ff3a4675cbaf1a6aa1150ca970762dd0ffc4199b92b75c -static/media/class-icon.6afd34b5.svg,1761576002254,a2f492c6c9c7b5201773062dfe90c238c12bc00bec097dc06141201f02b9588e -static/media/batch.3fcff66e.svg,1761576002244,f29038480286f091e3805a43f90ca5a70a13bbcef3076831e0b29b1fcb61d862 -static/media/auth-BG.2835584f.svg,1761576002241,238d3a2ff1aead1c4aaed0e07d23d2c1164f8be0ef2d5fced5c5ade370f3c5bf -static/media/add-circle.0011f2bc.svg,1761576002255,d9e5d90e8de1ce16df5720b43ca79543036fcf1a6cd6439a9b15c5a97d269f17 -static/media/batch-icon.bf664771.svg,1761576002260,7519e2a92f436a2f46ef7420d721e24df2837d7fce7fe8c30f4bc12980b3d1a0 -static/js/runtime-main.96ceaa04.js,1761576002273,455ae6008568041ddd40d50a96c614534f9c268f4d0fff4c2700d0d9646ddc57 -static/js/4.7247a6ee.chunk.js.map,1761576002344,e708b3fc1a1b324a3b6c468da749aaa4361b2f44d7c9b2e1614165faa04e072b -static/js/runtime-main.96ceaa04.js.map,1761576002341,454ee9efc7767f76d20d24cb4395b51fe7735f63f7ceb89ebbe56f138716b92b -static/js/4.7247a6ee.chunk.js,1761576002280,32fa7d3f8777fffae2bc6dc1de3608e836c27d9044fe4be8fab745f6c08cb373 -static/js/3.5470394c.chunk.js.map,1761576002343,0aed88423ebfa4792f1a2daf5809524a872b20f67a0ecb6e1becc7a52fa1c423 -static/js/3.5470394c.chunk.js,1761576002279,564d1d12db256f1c984a60c05dfc4e34c782c3c8b1b548447c5c30dd71aba0d6 -static/js/2.337cf2a6.chunk.js.LICENSE.txt,1761576002280,9c84bc4d2f8584d32d75e01e0317e22af1e39f5ac5ded3e2e4e34984704c172b -static/media/logo.0dd03933.png,1761576002242,b9716ed1f565a052edc1154a207334de81856339e8ca43d5d8f51041f3785085 -static/media/feature-1.ea5c34ea.svg,1761576002234,d802659785b69508e521d5543fca40a58cb9076521ffc3e6b006f4786b8079f8 -static/media/feature-3.3d5d81e9.svg,1761576002242,ba23393d89776cb78f7a559903baff48be76665abd99bdd4e5ea103c5e5ed88b -static/js/main.e80be951.chunk.js,1761576002272,b15fab5b06dc6f90c0f6677def9a66a9d9609026af14db6e2c114c27c1c22db9 -static/css/main.3624148f.chunk.css,1761576002265,6a13470e019853946811aebb68baac2e094470affc5520d835a986b420b1edab -static/css/4.629184c9.chunk.css,1761576002280,dfeba86da1256521df7a877a265d56d314f65016837f30878338c2b7fc62a6ab -static/css/2.561a8df6.chunk.css,1761576002273,c87247fc5cf38902aee0ee29244f6ab0c4bc14e5a0a1d6860cd771410dc826f8 -static/css/3.6c5a3051.chunk.css,1761576002280,1ae150a22b1d42322775be9055605f93c75188e7081cfbdb206a59fc2f5ab8f1 -static/js/main.e80be951.chunk.js.map,1761576002342,c7567119cb47238c88452f154ae648333c59cd204a9f3734b3b90ae2a422f534 -static/css/4.629184c9.chunk.css.map,1761576002292,b82aa57e6e357dbb20067334e544e9b30d20ed0d928c13e6c61e1747e6f5a205 -static/css/3.6c5a3051.chunk.css.map,1761576002289,bcc301c3b3b46c96afc0fc028a6aa3cd299ccda538d7c6cb9ebc87f8de535796 -static/css/2.561a8df6.chunk.css.map,1761576002281,ed9f46fc5b36bd835967cfd533fb33fd9ceec9c3aadcbe6c12bfb90b3ad1bc83 -static/css/main.3624148f.chunk.css.map,1761576002281,588c07ee54c0d7bc5ec65c6e4ab3890e922520cac4eac29b6fd638715a5ac5d1 -static/js/2.337cf2a6.chunk.js,1761576002282,e0edd93ede2589762ee74717e09fd5917dcb2660daa4ac6332bd8bc5b3c676ec -static/js/2.337cf2a6.chunk.js.map,1761576002358,b607efb90aec0e30321307c0738064e935f3d4b90d423885c732d57f1ebba603 +static/media/student-engaged.53fb7b0b.svg,1761764783104,5f8e01d1a5efcbdf3aa00ed07de843ab84404a28b672ca91f4d70d89fa8b37cf +static/media/quizexam.5545802e.svg,1761764783100,dfc1278bfcd264264a4d0e0e0247c229335abf0573439c5e9829c8607aacd569 +static/media/sub-ques-icon.366b4f1e.svg,1761764783106,8e397611007ec5db7581a4c1bcca006950390ddf652cae209bb3973a645af425 +static/media/questions-icon.3d3c1aaf.svg,1761764783104,197f459a359b00c1c44b6ddd71cbc9160f593d1fe08534e3711e9d72a2956ef1 +static/media/PracticeKiaLogo.a8336af5.svg,1761764783097,1a592518bcfabb2f86669d06ae2fb7b2948bbdbfaf5a80d138ab30f4e482a0f8 +static/media/practice.f05e6f00.svg,1761764783099,13b094bcbbb8c50906b1ee0ce68305059e99319464dd4147b4c2194dbb460475 +static/media/performance.88855f12.svg,1761764783101,03fc1b19005084049382091745d3f1f29a447763091ad4a9bc5d097c338671c9 +static/media/perf-icon.1597a235.svg,1761764783104,7183482b785de425506f49deb27bba02e906132ac7ce5af01f7da8452ef64f28 +static/media/mul-res-icon.8ef3b097.svg,1761764783104,1f0a79350cb5546361ef02af1657ad36efeff833fd7bb61db88a20e127a290b4 +static/media/OdiSVGlogo.f0834bb1.svg,1761764783097,3ec1cab31a32db378894d796afedaee7c35f8ff99dfb1039b0bb757225a47235 +static/media/practice-icon.bf603115.svg,1761764783104,27b6a729d91914d899f4b3c1f817e26ac58d2ec0be54dc9b93c01f28adcdd00c +static/media/question.0c505ed9.svg,1761764783097,29938066f93476c487414bb7a5dd5227d891c8ab8e115a74a7e7ffccd8d87b36 +static/media/mul-cho-icon.b3dc9ea9.svg,1761764783104,e8edbceb0eb49f7629cf0b8edf599f9347acbf0c6d1df2fa6145cbed03f37e1f +static/media/locale-icon.b3596424.svg,1761764783104,68618c76952aa4c5f2623bb010514871688960bb3b9edbcda0eab7eb75442054 +static/media/GrayscalePKLogo.6bb74404.svg,1761764783097,576b38300e49eda6407adce420001e7ad0333cca317eb668aff457c3258dcca2 +static/media/getFetch.2b2b7da4.cjs,1761764783097,b2d82abee5b8af22b81d67fc20b3feef1eaaf04585dbc24ec755e3304c469096 +static/media/exam-icon.10f48851.svg,1761764783104,b766e9975582af716870a844f8deabd4d80e33a47c400d36cee6bc4840062693 +static/media/feature-2.36f8d7e2.webp,1761764783097,fc1c038517abf3b731ff3a4675cbaf1a6aa1150ca970762dd0ffc4199b92b75c +static/media/delete-icon.da38c0f4.svg,1761764783107,8078772ee88a0588989eec477da1ca949430f3f06efaa9c2db860b74c65f6722 +static/media/dashboard.8ec7624b.svg,1761764783097,5a5b5d4bf416d414842bd5eac30432b592342a392450e52943f067db4077bec1 +static/media/classes.3b73dba0.svg,1761764783100,2abfbb7015d5bccb8640fd0614d3782c048672c9543fe17d127db63287ac141d +static/media/class-icon.6afd34b5.svg,1761764783103,a2f492c6c9c7b5201773062dfe90c238c12bc00bec097dc06141201f02b9588e +static/media/Checkmark.1356376c.svg,1761764783113,aa56f27c8198bcae3236a881a7134cd3b7d3dbb048ec75654e8ce2d4710ce027 +static/media/batch.3fcff66e.svg,1761764783097,f29038480286f091e3805a43f90ca5a70a13bbcef3076831e0b29b1fcb61d862 +static/media/auth-BG.2835584f.svg,1761764783094,238d3a2ff1aead1c4aaed0e07d23d2c1164f8be0ef2d5fced5c5ade370f3c5bf +static/media/batch-icon.bf664771.svg,1761764783104,7519e2a92f436a2f46ef7420d721e24df2837d7fce7fe8c30f4bc12980b3d1a0 +static/media/add-circle.0011f2bc.svg,1761764783104,d9e5d90e8de1ce16df5720b43ca79543036fcf1a6cd6439a9b15c5a97d269f17 +static/js/runtime-main.2bdeab81.js,1761764783115,5c04066aee33f757af11aff4783499664f995e641476c3c1552c373bf87171bb +static/js/4.568469c1.chunk.js.map,1761764783148,f626752d2d2cffe76387c84c314248f1ab02d9c6a79a16442a98e124c8f7d5fa +static/js/runtime-main.2bdeab81.js.map,1761764783148,a6cd518ca4773cf5562057dad7acb281edac1b802572abcdc6ee19c33f02b744 +static/js/4.568469c1.chunk.js,1761764783115,7f998d124bddb5cb8e916a7bb559ddd2f5c133920e79651382bbabf25affc9c4 +static/js/3.d75ced33.chunk.js.map,1761764783148,a12fbfb03ced36f6a8c055bf8b3961a9170b3676c8e4f545921152b23e9bc4dd +static/js/3.d75ced33.chunk.js,1761764783115,c68f66b973c4099ec168a05edb6212303bf31b91c57a2adc0a46595d31262355 +static/js/2.ac9f0d75.chunk.js.LICENSE.txt,1761764783115,9c84bc4d2f8584d32d75e01e0317e22af1e39f5ac5ded3e2e4e34984704c172b +static/media/logo.0dd03933.png,1761764783097,b9716ed1f565a052edc1154a207334de81856339e8ca43d5d8f51041f3785085 +static/media/feature-1.ea5c34ea.svg,1761764783097,d802659785b69508e521d5543fca40a58cb9076521ffc3e6b006f4786b8079f8 +static/media/feature-3.3d5d81e9.svg,1761764783097,ba23393d89776cb78f7a559903baff48be76665abd99bdd4e5ea103c5e5ed88b +static/js/main.962d5966.chunk.js,1761764783108,79a04f8bcc7d0c6dc396754ba1e4010597781782bc2743b2074a2c5a4107412b +static/css/main.b90ebd71.chunk.css,1761764783107,47c0c4a15920e9cea3ceba32d4bc59829a376a7f4347c15b82d7e8878d59008d +static/css/2.561a8df6.chunk.css,1761764783113,c87247fc5cf38902aee0ee29244f6ab0c4bc14e5a0a1d6860cd771410dc826f8 +static/css/4.629184c9.chunk.css,1761764783115,dfeba86da1256521df7a877a265d56d314f65016837f30878338c2b7fc62a6ab +static/css/3.6c5a3051.chunk.css,1761764783113,1ae150a22b1d42322775be9055605f93c75188e7081cfbdb206a59fc2f5ab8f1 +static/js/main.962d5966.chunk.js.map,1761764783148,c15e557e07ac2c5dd288726a7e260295a75111bcdd614be16ec21bb71dcb9e8c +static/css/4.629184c9.chunk.css.map,1761764783148,b82aa57e6e357dbb20067334e544e9b30d20ed0d928c13e6c61e1747e6f5a205 +static/css/3.6c5a3051.chunk.css.map,1761764783124,bcc301c3b3b46c96afc0fc028a6aa3cd299ccda538d7c6cb9ebc87f8de535796 +static/css/main.b90ebd71.chunk.css.map,1761764783116,bff960067cfb59c88b8ec495e5b5334532e05ae898ad3f3a78ee293f74fb7855 +static/css/2.561a8df6.chunk.css.map,1761764783122,ed9f46fc5b36bd835967cfd533fb33fd9ceec9c3aadcbe6c12bfb90b3ad1bc83 +static/js/2.ac9f0d75.chunk.js,1761764783116,a2f10af26647312232ac4cb0601a77496d561a7494b9db1206e2f8632813d0b6 +static/js/2.ac9f0d75.chunk.js.map,1761764783158,093171b5c14d2415bee5b4dbbf9caa643ee948acbb18398fbc5293ec5e9009aa diff --git a/src/component/Main/FuncHeader.jsx b/src/component/Main/FuncHeader.jsx index d44b29c..86a343c 100644 --- a/src/component/Main/FuncHeader.jsx +++ b/src/component/Main/FuncHeader.jsx @@ -32,7 +32,7 @@ const Headerc = (props) => { language_code: "", language_name: "", classID: "", - batchID: "", + batch_id: "", }); const [languages, setlanguages] = useState([]); @@ -114,13 +114,13 @@ const Headerc = (props) => { // Persist last selected batch if available const storedUser = JSON.parse(sessionStorage.getItem("currentUser")) || {}; - if (storedUser.batchID) { - setState(prev => ({ ...prev, batchID: storedUser.batchID })); + if (storedUser.batch_id) { + setState(prev => ({ ...prev, batch_id: storedUser.batch_id })); } else if (batchData.length > 0) { // Default to first batch - storedUser.batchID = batchData[0].id; - authenticationService.currentUserValue.batchID = batchData[0].id; - setState(prev => ({ ...prev, batchID: batchData[0].id })); + storedUser.batch_id = batchData[0].id; + authenticationService.currentUserValue.batch_id = batchData[0].id; + setState(prev => ({ ...prev, batch_id: batchData[0].id })); sessionStorage.setItem("currentUser", JSON.stringify(storedUser)); } @@ -166,11 +166,11 @@ const Headerc = (props) => { /** ✅ Handle Batch Change **/ const onClickBatchChange = (_, objectSelected) => { - authenticationService.currentUserValue.batchID = objectSelected.value; + authenticationService.currentUserValue.batch_id = objectSelected.value; const storedUser = JSON.parse(sessionStorage.getItem("currentUser")) || {}; - storedUser.batchID = objectSelected.value; + storedUser.batch_id = objectSelected.value; sessionStorage.setItem("currentUser", JSON.stringify(storedUser)); - setState(prev => ({ ...prev, batchID: objectSelected.value })); + setState(prev => ({ ...prev, batch_id: objectSelected.value })); }; function onClickLanguageChange(_, objectSelected) { @@ -246,7 +246,7 @@ const Headerc = (props) => { )} dropdownClassName="batch-select-dropdown" onChange={onClickBatchChange} - value={batches.length > 0 ? state.batchID : undefined} + value={batches.length > 0 ? state.batch_id : undefined} > {batches.map((batchItem) => ( th{ - border:none; - padding: 0 0 0 10px; - text-align: left; - font-weight: normal; +.exam-header-center { + flex: 1; + display: flex; + justify-content: center; } -div.MyExamDiv table tr> td{ - border:none; - padding: 0 0 0 10px; - text-align: left; - font-weight: bolder; +.exam-countdown .ant-statistic-title { + color: #555; + font-size: 14px; } -li.MyExam h4.ant-list-item-meta-title{ - padding: 0 0 0 10px; +.exam-countdown .ant-statistic-content { + font-size: 16px; + font-weight: 600; + color: #1677ff; } -li.MyExam span.MyExamSpan{ - padding: 0 0 0 10px; +.exam-header-right { + display: flex; + gap: 10px; } -.ExamNameHeader { - font-size: 18pt; - float: left; - color: white; -} -.ExamTimeHeader{ - font-size: 16pt; - float: right; - color: white; +.exam-header-right .ant-btn { + border-radius: 6px; } -.ExamTimeHeader div{ - font-size: 13pt; - float:none; - color: white; -} -.MainExamLayout{ - flex-direction: row; -} -.createExamLayoutLeft{ - display: flex; - flex: auto; - flex-direction: column; - background: #ffffff !important; - border-style: solid; - border-width: 1px; - border-color: rgb(231, 230, 230); - padding: 10px; - width:70%; -} -.createExamLayoutRight{ - display: flex; - flex: auto; - flex-direction: column; - background: #ffffff !important; - border-style: solid; - border-width: 1px; - border-color: rgb(231, 230, 230); - padding: 10px; - position:sticky; - position: -webkit-sticky; - top:0 +/* Card container */ +.create-exam-card { + background: #ffffff; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + padding: 24px; + margin: 24px; + transition: box-shadow 0.3s ease; } -.StatusLabel{ - padding: 5px; -} -.ExamAvatar{ - padding: 25px 0px 25px 0px; -} -.ExamStatusTable td{ - padding: 5px; -} -div.AttemptQuestionGrid{ - grid-template-columns: repeat(auto-fit, minmax(221px, 1fr)); - display: grid; - margin-left: 0px!important; - margin-right: 0px!important; +.create-exam-card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); } -div.AttemptQuestionGrid > div.ant-col{ - padding-right: 0px !important; - padding-left: 0px !important; -} -.QuestionCard{ - height: 336px; - margin: 12px; - max-width: 282px; - float: left; - border-radius: 16px; - cursor: pointer; - color:#150F2D; - font-size: 13px; - text-overflow: ellipsis; - width:90%; - box-shadow: 0 0 5px #e1e1e1; -} -.QuestionCard div.ant-card-head{ - border-bottom:none; - padding: 0 10px; -} -.QuestionCard div.ant-card-head div.ant-card-head-wrapper .ant-card-head-title -{ - display: flex; - align-items: center; - justify-content: space-between; -} -.QuestionCard div.ant-card-body{ - height: 67%; - padding:16px; -} -.QuestionCard ul.ant-card-actions{ - background: none; - border-top:none; - width: max-content; - background-color: #EAECF1; - height: 20px; - padding: 1px 4px; - box-sizing: border-box; - display: flex; - align-items: center; - justify-content: space-around; - border-radius: 4px; - float: right; - margin-right: 5px; -} -.QuestionCard ul.ant-card-actions > li > span{ - font-size: 12px; -} -.QuestionCard ul.ant-card-actions > li:not(:last-child) { - border-right: none; -} -.Options{ - margin-left:13px; +/* Tabs styling */ +.create-exam-tabs { + font-size: 16px; } -.QuesttionStatusNotVisited{ - background-color: #F0F0F0 +.create-exam-tabs .ant-tabs-nav { + margin-bottom: 20px; + border-bottom: 2px solid #f0f0f0; } -.QuesttionStatusNotAnswered{ - background-color: #FED911 -} -.QuesttionStatusAnswered{ - background-color: #54C51D -} -.QuesttionStatusReview{ - background-color: #A028FF -} -.QuesttionStatusAnsweredReview{ - background-color: #FFA500 +.create-exam-tabs .ant-tabs-tab { + font-weight: 500; + color: #555; + transition: color 0.2s ease; + padding: 10px 16px; + border-radius: 0; + background: transparent !important; } -.QuesttionStatusNotVisitedCard{ - border-color: #F0F0F0 +/* ✨ Hover effect – only text color changes */ +.create-exam-tabs .ant-tabs-tab:hover { + color: #1677ff; + background: transparent !important; } -.QuesttionStatusNotAnsweredCard{ - border-color: #FED911 -} -.QuesttionStatusAnsweredCard{ - border-color: #54C51D -} -.QuesttionStatusReviewCard{ - border-color: #A028FF -} -.QuesttionStatusAnsweredReviewCard{ - border-color: #FFA500 +/* Active tab – only bold text + blue ink bar */ +.create-exam-tabs .ant-tabs-tab-active { + color: #1677ff !important; + font-weight: 600; + background: transparent !important; } -div.QuestionStatusHeaderIcon{ - height: 8px; - width: 8px; - border-radius: 274.76px; - box-shadow: 0 0 15px 0 rgba(0,0,0,0.1); +/* Ink bar – thin blue underline */ +.create-exam-tabs .ant-tabs-ink-bar { + background: #1677ff; + height: 3px; + border-radius: 3px; } -div.HeaderQuestionStatusLabel{ - -webkit-font-smoothing: antialiased; - font-size: 12px; - line-height: 1.125rem; - font-weight: 500; - letter-spacing: .25px; - text-decoration: none; - text-transform: none; +.exam-status-card { + background: #ffffff; + border-radius: 12px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + padding: 24px; + margin: 24px; + transition: box-shadow 0.3s ease; } -.QuesttionStatusNotVisitedTitle{ - color: #F0F0F0 +.exam-status-card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12); } -.QuesttionStatusNotAnsweredTitle{ - color: #FED911 -} -.QuesttionStatusAnsweredTitle{ - color: #54C51D -} -.QuesttionStatusReviewTitle{ - color: #A028FF -} -.QuesttionStatusAnsweredReviewTitle{ - color: #FFA500 +.exam-status-section { + margin-bottom: 24px; } -.Outline{ display: flex; -justify-content: flex-end; -align-items: center; -width: 77%; -font-size: 14px; +.exam-status-table { + width: 100%; + border-collapse: separate; + border-spacing: 16px 12px; } -.MainExamQuestionLayout{ - padding: 20px; +.status-item { + display: flex; + align-items: center; + gap: 10px; +} + +.status-label { + font-size: 15px; + font-weight: 500; + color: #444; +} + +/* Avatar badges */ +.status-avatar { + font-weight: 600; + color: #fff; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); +} + +/* Individual colors for clarity */ +.status-avatar.not-visited { + background-color: #d9d9d9; +} + +.status-avatar.not-answered { + background-color: #ff7875; +} + +.status-avatar.answered { + background-color: #52c41a; +} + +.status-avatar.to-review { + background-color: #faad14; +} + +.status-avatar.answered-review { + background-color: #1890ff; +} + +/* Collapse styling */ +.exam-accordion .ant-collapse { + border: none; + background: #fafafa; + border-radius: 8px; +} + +.exam-accordion .ant-collapse-item { + border-bottom: 1px solid #f0f0f0; +} + +.exam-accordion .ant-collapse-header { + font-weight: 500; + color: #333; + transition: color 0.2s ease; +} + +.exam-accordion .ant-collapse-header:hover { + color: #1677ff; +} + +.AttemptQuestionGrid { + display: flex; + flex-wrap: wrap; + gap: 20px; /* space between cards */ + justify-content: flex-start; +} + +.question-col { + flex: 1 1 250px; /* make responsive */ + min-width: 250px; + max-width: 300px; +} + +.question-card { + margin: 10px; + border-radius: 12px !important; + overflow: hidden; + transition: all 0.2s ease-in-out; +} + +/* Add a subtle hover effect */ +.question-card:hover { + transform: translateY(-4px); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); +} + +/* Header (title + type tag) */ +.question-card-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 14px; +} + +/* Title (avatar + status label) */ +.question-title { + display: flex; + align-items: center; + gap: 10px; +} + +/* Question content */ +.question-content { + margin-top: 10px; + line-height: 1.6; + font-size: 15px; +} + +/* Tag styling */ +.question-type { + font-size: 12px; + border-radius: 8px; + padding: 2px 8px; +} + +.MainExamQuestionLayout { + background: #ffffff; + border-radius: 16px; + padding: 28px 36px; + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1); + margin: 30px 20px; /* ⬅️ More margin around the card */ + transition: box-shadow 0.3s ease, transform 0.2s ease; +} + +.MainExamQuestionLayout:hover { + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12); + transform: translateY(-2px); +} + +.question-header { + margin-bottom: 20px; +} + +.question-title { + font-size: 1.3rem; + font-weight: 600; + color: #1f1f1f; + line-height: 1.6; +} + +.question-options { + margin-top: 16px; + margin-bottom: 24px; +} + +.radio-group { + display: flex; + flex-direction: column; + gap: 12px; +} + +.radioStyle { + font-size: 16px; + line-height: 1.5; +} + +.review-switch { + margin-bottom: 28px; +} + +.question-actions { + display: flex; + justify-content: flex-end; +} + +.action-buttons { + display: flex; + gap: 12px; /* ⬅️ spacing between buttons */ +} + +.rounded-btn { + border-radius: 10px !important; /* ⬅️ rounded corners */ + font-size: 15px; + height: 40px; + padding: 0 20px; +} + +.ant-btn-primary { + background-color: #1677ff; + border-color: #1677ff; +} + +.ant-btn-primary:hover { + background-color: #3b89ff; + border-color: #3b89ff; } diff --git a/src/component/Student/Exams/AttemptExam/AttemptExam.js b/src/component/Student/Exams/AttemptExam/AttemptExam.js index 9aa5705..c669eed 100644 --- a/src/component/Student/Exams/AttemptExam/AttemptExam.js +++ b/src/component/Student/Exams/AttemptExam/AttemptExam.js @@ -1,9 +1,21 @@ import React from "react"; import "./AttemptExam.css"; -import { authenticationService } from '../../../../_services'; +import { authenticationService } from "../../../../_services"; import { selectorService } from "../../../../services/selectorService"; -import { Layout, Avatar, Button, List, Tabs, Card, Collapse, Statistic, Col, Row } from 'antd'; -import { Link } from 'react-router-dom'; +import { + Layout, + Avatar, + Button, + List, + Tabs, + Card, + Collapse, + Statistic, + Col, + Row, + Tag +} from "antd"; +import { Link } from "react-router-dom"; import QuestionDetail from "./QuestionDetail"; import parse from "html-react-parser"; @@ -12,24 +24,25 @@ const { Header } = Layout; const { TabPane } = Tabs; const { Panel } = Collapse; const { Countdown } = Statistic; + class AttemptExam extends React.Component { constructor(props) { super(props); this.state = { currentUser: authenticationService.currentUserValue, - exam_id: 'props.location.state.examId', + exam_id: "props.location.state.examId", showQuestion: false, - activeDetailQuestion:{}, - activeQuestionIndex:-1, - pauseUpdate: false + activeDetailQuestion: {}, + activeQuestionIndex: -1, + pauseUpdate: false, }; + this.onGetExamAttempt = this.onGetExamAttempt.bind(this); this.callbackFunction = this.callbackFunction.bind(this); this.callbackFunctionNext = this.callbackFunctionNext.bind(this); - this.sendExamUpdate =this.sendExamUpdate.bind(this); + this.sendHeartbeat = this.sendHeartbeat.bind(this); this.stopExamUpdate = this.stopExamUpdate.bind(this); - this.updateExamStatus = this.updateExamStatus.bind(this); this.onSubmitExam = this.onSubmitExam.bind(this); this.onPauseExam = this.onPauseExam.bind(this); this.getExamModelToUpdate = this.getExamModelToUpdate.bind(this); @@ -37,15 +50,13 @@ class AttemptExam extends React.Component { componentDidMount() { this.onGetExamAttempt(); - this.sendExamUpdate(); - + this.sendHeartbeat(); } - getExamModelToUpdate(){ + getExamModelToUpdate() { let tempAllQuestions = this.state.allQuestions; let questionsArray = []; - if(tempAllQuestions === undefined) - return; + if (tempAllQuestions === undefined) return; tempAllQuestions.map((question, index) => { let quest = {}; quest.question_id = question.id; @@ -53,138 +64,130 @@ class AttemptExam extends React.Component { quest.is_reviewed = question.isReviewMarked; quest.is_visited = question.isVisited; let options = question.options; - let answers =[]; + let answers = []; for (let i = 0; i < options.length; i++) { - if(options[i].isSelected){ - let ans = {} + if (options[i].isSelected) { + let ans = {}; ans.id = options[i].id; answers.push(ans); + } } - - } - quest.answers = answers; - if(quest.is_visited) - questionsArray.push(quest); - }) - return questionsArray; - } - - - onPauseExam(){ - - let questionsArray = this.getExamModelToUpdate(); - - this.stopExamUpdate(); - selectorService.pauseExam(this.state.attempt_id).then((data) => { - - console.log("Exam Paused"); - }); - - } - - onSubmitExam(){ - let questionsArray = this.getExamModelToUpdate(); - this.stopExamUpdate(); - selectorService.endExam(this.state.attempt_id,questionsArray).then((data) => { - console.log(data); - console.log("Exam Ended"); + quest.answers = answers; + if (quest.is_visited) questionsArray.push(quest); }); - - + + return questionsArray; } + onPauseExam() { + this.stopExamUpdate(); - stopExamUpdate(){ + selectorService.pauseExam(this.state.attempt_id) + .then((_data) => { + console.log("Exam Paused"); + // ✅ Go back to the previous page after pausing the exam + window.history.back(); + }) + .catch((error) => { + console.error("Error pausing exam:", error); + }); + } + + onSubmitExam() { + let questionsArray = this.getExamModelToUpdate(); + this.stopExamUpdate(); + + selectorService.endExam(this.state.attempt_id, questionsArray) + .then((_data) => { + console.log("Exam Ended"); + + // ✅ Go back to the previous page after exam ends + window.history.back(); + }) + .catch((error) => { + console.error("Error ending exam:", error); + }); + } + + stopExamUpdate() { clearInterval(this.interval); } - componentWillUnmount(){ - this.stopExamUpdate(); + componentWillUnmount() { + this.stopExamUpdate(); } - sendExamUpdate(){ - this.interval = setInterval(() => { - if(this.state.pauseUpdate){ + sendHeartbeat() { + this.interval = setInterval(() => { + if (this.state.pauseUpdate) { this.stopExamUpdate(); - } - else{ - this.updateExamStatus(); - console.log("UpdateAnswer"); - + } else { + selectorService + .heartbeat(this.state.attempt_id) + .then((data) => { + const result = data.result; + this.setState({ + time_left: result, + }); + }); } }, 60000); } - updateExamStatus(){ - let questionsArray = this.getExamModelToUpdate(); - - console.log(questionsArray); - - selectorService.updateExamStatus(this.state.attempt_id,questionsArray).then((data) => { - const result = data.result; - - this.setState({ - time_left: result, - }); - console.log(result); - }); - } - showDetailQuestion(question) { question.isVisited = true; - this.state.sections[question.sectionIndx].questions[question.secQIndex] = question; - this.state.allQuestions[question.index-1] = question; + this.state.sections[question.sectionIndx].questions[question.secQIndex] = + question; + this.state.allQuestions[question.index - 1] = question; let tempSections = this.state.sections; let tempAllQuestions = this.state.allQuestions; this.setState({ showQuestion: true, activeDetailQuestion: question, - activeQuestionIndex: question.index-1, + activeQuestionIndex: question.index - 1, sections: tempSections, - allQuestions: tempAllQuestions - }) + allQuestions: tempAllQuestions, + }); this.forceUpdate(); } - onQuestionClick(index){ - let q =this.state.allQuestions[index-1]; + onQuestionClick(index) { + let q = this.state.allQuestions[index - 1]; this.showDetailQuestion(q); } - onTabPaneClick(){ + onTabPaneClick() { this.setState({ showQuestion: false, activeDetailQuestion: {}, - activeQuestionIndex: -1 - }) + activeQuestionIndex: -1, + }); } - onGetExamAttempt() { var attemptId; - - selectorService.createExamAttempt(this.props.location.state.examId).then((data) => { + selectorService + .createExamAttempt(this.props.location.state.examId) + .then((data) => { const result = data.result; attemptId = result.attempt_id; let index1 = 0; selectorService.getExamAttempt(attemptId).then((data) => { const result = data.result; - let sections1 = []; let questionsArray = []; sections1 = result.sections.map((item, secIndex) => { let quest = []; quest = item.questions.map((question, index) => { - index1 = index1 + 1 + index1 = index1 + 1; question.index = index1; question.sectionIndx = secIndex; question.secQIndex = index; questionsArray.push(question); return question; - }) - + }); item.questions = quest; - return item + return item; }); this.setState({ attempt_id: attemptId, @@ -193,218 +196,295 @@ class AttemptExam extends React.Component { exam_name: result.exam_name, sections: sections1, time_left: result.time_left, - deadline: Date.now() + result.time_left*1000, - allQuestions:questionsArray + deadline: Date.now() + result.time_left * 1000, + allQuestions: questionsArray, }); - }); - }); - - - - }; + } callbackFunction = (question) => { - // console.log("Parent recieved Selector Data: "+ childData); let q = question; let indx = q.index; let secQuesIndx = q.secQIndex; - this.state.sections[q.sectionIndx].questions[secQuesIndx] =q; - this.state.allQuestions[indx-1] = q; + this.state.sections[q.sectionIndx].questions[secQuesIndx] = q; + this.state.allQuestions[indx - 1] = q; let tempSections = this.state.sections; let tempAllQuestions = this.state.allQuestions; this.setState({ showQuestion: true, sections: tempSections, - allQuestions: tempAllQuestions - }) - } + allQuestions: tempAllQuestions, + }); + }; + + callbackFunctionNext = (childData) => { + // ✅ Extract selected answer IDs (just numbers) + const selectedAnswers = childData.options + .filter(option => option.isSelected) + .map(option => option.id); // <-- plain IDs, not objects + + // ✅ Build the JSON object like your Kotlin version + const answerObject = { + question_id: childData.id, + answer_duration: childData.answer_duration || 10, + is_reviewed: childData.is_reviewed || false, + answers: selectedAnswers + }; + + // ✅ Send it (stringify the full object) + selectorService.updateExamStatus(this.state.attempt_id, JSON.stringify(answerObject)); + + // ✅ Load next question + const q = childData; + const indx = q.index; + const nxtQuestion = this.state.allQuestions[indx]; + this.showDetailQuestion(nxtQuestion); + }; + + callbackFunctionUpdateAnswer = (question) => { + console.log("Answer Updated", question); + } - callbackFunctionNext = (childData) => { - // console.log("Parent recieved Selector Data: "+ childData); - let q = childData; - let indx = q.index; - let nxtQuestion = this.state.allQuestions[(indx)]; - this.showDetailQuestion(nxtQuestion); -} render() { let listItems = ""; let accordions = ""; - let activeQuestion =""; + let activeQuestion = ""; let total_notVisited = 0; let total_notAnswered = 0; let total_Answered = 0; let total_AnsweredReviwed = 0; let total_Reviwed = 0; - let questionStatusLabel ={"QuesttionStatusNotAnswered":"Not Answered","QuesttionStatusAnswered":"Answered","QuesttionStatusReview":"To Review","QuesttionStatusAnsweredReview":"Answered and To Review"}; + + let questionStatusLabel = { + QuesttionStatusNotAnswered: "Not Answered", + QuesttionStatusAnswered: "Answered", + QuesttionStatusReview: "To Review", + QuesttionStatusAnsweredReview: "Answered and To Review", + }; + if (this.state.sections !== undefined) { - let tempSections = this.state.sections.map((item, index) =>{ + let tempSections = this.state.sections.map((item, index) => { let tempQuestions = item.questions.map((question) => { let isAnswered = false; let options = question.options; - let answered =[]; + let answered = []; for (let i = 0; i < options.length; i++) { - if(options[i].isSelected){ + if (options[i].isSelected) { answered.push(options[i]); + } } - } - if(answered.length>0) - isAnswered = true; - let classN = "QuesttionStatusNotVisited"; - if(question.isVisited) - classN = "QuesttionStatusNotAnswered"; - if(isAnswered && !question.isReviewMarked) - classN = "QuesttionStatusAnswered"; - if(question.isReviewMarked && isAnswered){ - classN = "QuesttionStatusAnsweredReview"; + if (answered.length > 0) isAnswered = true; + let classN = "QuesttionStatusNotVisited"; + if (question.isVisited) classN = "QuesttionStatusNotAnswered"; + if (isAnswered && !question.isReviewMarked) + classN = "QuesttionStatusAnswered"; + if (question.isReviewMarked && isAnswered) { + classN = "QuesttionStatusAnsweredReview"; } - if(question.isReviewMarked && !isAnswered){ + if (question.isReviewMarked && !isAnswered) { classN = "QuesttionStatusReview"; - } - question.classN = classN; - question.statusLabel = questionStatusLabel[classN]; - if(classN === "QuesttionStatusReview") - total_Reviwed=total_Reviwed+1; - if(classN === "QuesttionStatusAnsweredReview") - total_AnsweredReviwed=total_AnsweredReviwed+1; - if(classN === "QuesttionStatusAnswered") - total_Answered=total_Answered+1; - if(classN === "QuesttionStatusNotAnswered") - total_notAnswered=total_notAnswered+1; - if(classN === "QuesttionStatusNotVisited") - total_notVisited=total_notVisited+1; - return question; - }) + } + question.classN = classN; + question.statusLabel = questionStatusLabel[classN]; + if (classN === "QuesttionStatusReview") total_Reviwed += 1; + if (classN === "QuesttionStatusAnsweredReview") + total_AnsweredReviwed += 1; + if (classN === "QuesttionStatusAnswered") total_Answered += 1; + if (classN === "QuesttionStatusNotAnswered") total_notAnswered += 1; + if (classN === "QuesttionStatusNotVisited") total_notVisited += 1; + return question; + }); item.questions = tempQuestions; return item; - }) + }); this.state.sections = tempSections; let index1 = 0; - activeQuestion = ; - listItems = this.state.sections.map((item, index) => - - - { - this.state.showQuestion?activeQuestion: - - {item.questions.map((question, index) => { - let title = <>{question.index}
-
{question.statusLabel}
- -
- - return - -

{parse(question.question_text)}

- -
- - })} -
- } - - - - - - -
- - + activeQuestion = ( + + + ); - - - accordions = this.state.sections.map((item, index) => + listItems = this.state.sections.map((item, index) => ( + + {this.state.showQuestion ? ( + activeQuestion + ) : ( + + {item.questions.map((question, index) => { + let title = ( + <> + {question.index} +
+
+ {question.statusLabel} +
+
+ + ); + + return ( + + this.showDetailQuestion(question)} + > +
+ {title} + + {question.type_text} + +
+ +
+

{parse(question.question_text)}

+
+
+ + ); + + })} +
+ )} +
+ )); + + accordions = this.state.sections.map((item, index) => ( - {item.questions.map((question) => { - return - {question.index} - })} + {item.questions.map((question) => ( + + + {question.index} + + + ))} - - - - - - - - - ); + )); } + return ( <> -
-
- {this.state.exam_name} +
+
+ {this.state.exam_name}
-
- + +
+
-
- -
-
- + +
+ +
+ + - { - - { listItems } - - - } + + + {listItems} + - -
- - - - - - - - - - - - + +
+
{total_notVisited}{" Not Visited "}{total_notAnswered}{" Not Answered "}
{total_Answered}{" Answered "}{total_Reviwed}{" To Review "}
{total_AnsweredReviwed}{" Answered & To Review "}
+ + + + + + + + + + + + +
+
+ {total_notVisited} + Not Visited +
+
+
+ {total_notAnswered} + Not Answered +
+
+
+ {total_Answered} + Answered +
+
+
+ {total_Reviwed} + To Review +
+
+
+ {total_AnsweredReviwed} + Answered & To Review +
+
-
-
- - {accordions} - + +
+ {accordions}
+ - ) - }; -}; + ); + } +} export default AttemptExam; diff --git a/src/component/Student/Exams/AttemptExam/QuestionDetail.js b/src/component/Student/Exams/AttemptExam/QuestionDetail.js index cc8f782..16152fc 100644 --- a/src/component/Student/Exams/AttemptExam/QuestionDetail.js +++ b/src/component/Student/Exams/AttemptExam/QuestionDetail.js @@ -2,12 +2,11 @@ import React from "react"; import "./AttemptExam.css"; import { authenticationService } from '../../../../_services'; import { selectorService } from "../../../../services/selectorService"; -import { Layout, Avatar, Button, Radio,Switch, Tabs, Card, Collapse, Statistic, Col, Row } from 'antd'; +import { Layout, Avatar, Button, Radio, Switch, Tabs, Card, Collapse, Statistic, Col, Row } from 'antd'; import { Link } from 'react-router-dom'; import parse from "html-react-parser"; import { ButtonGroup } from "react-bootstrap"; - class QuestionDetail extends React.Component { constructor(props) { super(props); @@ -28,31 +27,33 @@ class QuestionDetail extends React.Component { loadNextQuestion = () => { this.props.parentCallbackNext(this.props.question); - } + }; + onReviewQuestion = (val) => { this.state.question.isReviewMarked = val; this.sendData(this.state.question); } - onAnswerChange = (event) =>{ + onAnswerChange = (event) => { let questionType = this.state.question.type_code; let id = event.target.value; let tempQuestion = this.state.question; - if(questionType ==='MCQ' || questionType ==='TNF'){ + if (questionType === 'MCQ' || questionType === 'TNF') { let options = this.state.question.options.map((option, index) => { - if(option.id === id) + if (option.id === id) option.isSelected = event.target.checked; else - option.isSelected = false; + option.isSelected = false; return option; }) tempQuestion.options = options; - } - + } + this.setState({ - question : tempQuestion + question: tempQuestion }) + this.sendData(this.state.question); } @@ -64,81 +65,81 @@ class QuestionDetail extends React.Component { let tempQuestion = this.state.question; tempQuestion.options = options; this.setState({ - question : tempQuestion + question: tempQuestion }) this.sendData(this.state.question); } - - - render() { - this.state.question = this.props.question; + const { question, totalQuestion } = this.props; + this.state.question = question; + let answer = ""; - let answerOption = this.state.question.options.map((option,i)=>{ - if(option.isSelected) - answer = option.id; - return - {option.text} - + const answerOptions = question.options.map((option) => { + if (option.isSelected) answer = option.id; + return ( + + {option.text} + + ); + }); - }) - let questionDetails= - - -

{this.props.question.index}. {parse(this.props.question.question_text)}

- -
- - -
- - { - answerOption - } - -
- -
- - -
- -
- -
- - -
-
- -
- - - -
- return ( - <> -{questionDetails} - - - ) - }; + + + +

+ {question.index}. {parse(question.question_text)} +

+ +
+ + + + + {answerOptions} + + + + + + + + + + + + +
+ + +
+ +
+
+ ); + } }; export default QuestionDetail; diff --git a/src/component/Student/Exams/LiveExams/LiveExams.js b/src/component/Student/Exams/LiveExams/LiveExams.js index d72de25..9c3696c 100644 --- a/src/component/Student/Exams/LiveExams/LiveExams.js +++ b/src/component/Student/Exams/LiveExams/LiveExams.js @@ -28,7 +28,8 @@ class LiveExams extends React.Component { const json = {}; json.pageSize = 10; json.pageNumber = 1; - json.batch = this.state.batch; + const storedUser = JSON.parse(sessionStorage.getItem("currentUser")) || {}; + json.batch = storedUser.batch_id || null; selectorService.loadLiveExams(json).then((data1) => { // console.log('Success:', data1); //data = $.parseJSON(data); diff --git a/src/services/selectorService.js b/src/services/selectorService.js index 9635eb0..456cc1c 100644 --- a/src/services/selectorService.js +++ b/src/services/selectorService.js @@ -5,7 +5,7 @@ import { TEACHER_API, INSTITUTE_API, LOAD_CLASSES, LOAD_LANGAUGES, LOAD_QUESTION // checking role from login - function checkRole() { const role = authenticationService.currentUserValue?.role_id; - const GATEWAY = role === 3? TEACHER_API : role === 2 && INSTITUTE_API; + const GATEWAY = role === 3 ? TEACHER_API : role === 2 && INSTITUTE_API; // console.log(role, GATEWAY); return GATEWAY; } @@ -101,6 +101,7 @@ export const selectorService = { createPracticeAttempt, getPracticeAttempt, stopPublishedExam, + heartbeat, }; async function stopPublishedExam(examId) { @@ -119,7 +120,7 @@ async function stopPublishedExam(examId) { try { const res = await fetch(`${checkRole()}/Exams/${examId}/StopExam`, requestOptions); const data = await res.json(); - if(res.ok && +data.status.code > 0) { + if (res.ok && +data.status.code > 0) { return 1; } throw "Something went wrong"; @@ -146,10 +147,10 @@ function loadReport(examId) { } return fetch( "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/ExamAttempts/" + - examId + - "/Report", + currentUser.language_code + + "/ExamAttempts/" + + examId + + "/Report", requestOptions ) .then((response) => { @@ -168,112 +169,159 @@ function loadReport(examId) { }); } -function pauseExam(attempt_id) { +async function pauseExam(attemptId) { const currentUser = authenticationService.currentUserValue; - const requestOptions = { - method: "PUT", - headers: { - "Access-Control-Allow-Origin": "*", - Accept: "application/json", - "Content-Type": "application/json", - Authorization: "Bearer ".concat(currentUser.jwtToken), - }, - //body: JSON.stringify(json) - // body: JSON.stringify(this.state) - //body: JSON.stringify({ emailId:"sa@odiware.com", userPassword:"aaaa" }) - }; - return fetch( - "https://api.odiprojects.com/api-institute/v1/en/ExamAttempts/" + - attempt_id + - "/Pause", - requestOptions - ) - .then((response) => { - if (response.ok) { - return response.json(); - } - // window.localStorage.clear(); - // history.push("/login"); - }) - .then((data) => { - console.log(data); - return data; - }) - .catch((error) => { - // console.error('Error:', error); + if (!currentUser?.jwtToken) { + console.error("❌ No valid user token found"); + return null; + } + + const languageCode = currentUser.language_code || "En"; + const url = `https://api.odiprojects.com/api-student/v1/${languageCode}/ExamAttempts/${attemptId}/Pause`; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: `Bearer ${currentUser.jwtToken}`, + }, }); + + if (!response.ok) { + console.error(`❌ Failed to pause exam (HTTP ${response.status})`); + // Optional: handle session expiration + // if (response.status === 401) { + // window.localStorage.clear(); + // history.push("/login"); + // } + return null; + } + + const data = await response.json(); + console.log("⏸️ Exam paused successfully:", data); + return data; + } catch (error) { + console.error("🚨 Error pausing exam:", error); + return null; + } } -function endExam(attempt_id, json) { +async function endExam(attemptId, payload) { const currentUser = authenticationService.currentUserValue; - const requestOptions = { - method: "PUT", - headers: { - "Access-Control-Allow-Origin": "*", - Accept: "application/json", - "Content-Type": "application/json", - Authorization: "Bearer ".concat(currentUser.jwtToken), - }, - body: JSON.stringify(json), - // body: JSON.stringify(this.state) - //body: JSON.stringify({ emailId:"sa@odiware.com", userPassword:"aaaa" }) - }; - return fetch( - "https://api.odiprojects.com/api-institute/v1/en/ExamAttempts/" + - attempt_id + - "/End", - requestOptions - ) - .then((response) => { - if (response.ok) { - return response.json(); - } - // window.localStorage.clear(); - // history.push("/login"); - }) - .then((data) => { - console.log(data); - return data; - }) - .catch((error) => { - // console.error('Error:', error); + if (!currentUser?.jwtToken) { + console.error("❌ No valid user token found"); + return null; + } + + const languageCode = currentUser.language_code || "En"; + const url = `https://api.odiprojects.com/api-student/v1/${languageCode}/ExamAttempts/${attemptId}/End`; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: `Bearer ${currentUser.jwtToken}`, + }, + body: JSON.stringify(payload), }); + + if (!response.ok) { + console.error(`❌ Failed to end exam (HTTP ${response.status})`); + // Optional: handle expired sessions + // if (response.status === 401) { + // window.localStorage.clear(); + // history.push("/login"); + // } + return null; + } + + const data = await response.json(); + console.log("✅ Exam ended successfully:", data); + return data; + } catch (error) { + console.error("🚨 Error ending exam:", error); + return null; + } } -function updateExamStatus(attempt_id, json) { +async function heartbeat(attemptId) { const currentUser = authenticationService.currentUserValue; - const requestOptions = { - method: "PUT", - headers: { - "Access-Control-Allow-Origin": "*", - Accept: "application/json", - "Content-Type": "application/json", - Authorization: "Bearer ".concat(currentUser.jwtToken), - }, - body: JSON.stringify(json), - // body: JSON.stringify(this.state) - //body: JSON.stringify({ emailId:"sa@odiware.com", userPassword:"aaaa" }) - }; - return fetch( - "https://api.odiprojects.com/api-institute/v1/ExamAttempts/" + - attempt_id + - "/HeartBeat", - requestOptions - ) - .then((response) => { - if (response.ok) { - return response.json(); - } - // window.localStorage.clear(); - // history.push("/login"); - }) - .then((data) => { - console.log(data); - return data; - }) - .catch((error) => { - // console.error('Error:', error); + if (!currentUser?.jwtToken) { + console.error("❌ No valid user token found"); + return null; + } + + const url = `https://api.odiprojects.com/api-student/v1/ExamAttempts/${attemptId}/Heartbeat`; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: `Bearer ${currentUser.jwtToken}`, + }, + body: JSON.stringify({ + attempt_id: attemptId, + timestamp: new Date().toISOString(), + }), }); + + if (!response.ok) { + console.error(`❌ Heartbeat failed (HTTP ${response.status})`); + return null; + } + + const data = await response.json(); + console.log("💓 Heartbeat sent successfully:", data); + return data; // ✅ Return the parsed response data + } catch (error) { + console.error("🚨 Error sending heartbeat:", error); + return null; + } +} + +async function updateExamStatus(attemptId, payload) { + const currentUser = authenticationService.currentUserValue; + if (!currentUser?.jwtToken) { + console.error("❌ No valid user token found"); + return null; + } + + const url = `https://api.odiprojects.com/api-student/v1/ExamAttempts/${attemptId}/UpdateAnswer`; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: `Bearer ${currentUser.jwtToken}`, + }, + body: payload, + }); + + if (!response.ok) { + console.error(`❌ Failed to update exam status (HTTP ${response.status})`); + // Optional: Handle unauthorized users + // if (response.status === 401) { + // window.localStorage.clear(); + // history.push("/login"); + // } + return null; + } + + const data = await response.json(); + console.log("✅ Exam status updated:", data); + return data; + } catch (error) { + console.error("🚨 Error updating exam status:", error); + return null; + } } function updateBatchName(obj) { @@ -330,10 +378,10 @@ function getPracticeAttempt(practiceId) { } return fetch( "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/PracticeAttempts/" + - practiceId + - "/Revision", + currentUser.language_code + + "/PracticeAttempts/" + + practiceId + + "/Revision", requestOptions ) .then((response) => { @@ -353,43 +401,45 @@ function getPracticeAttempt(practiceId) { } -function getExamAttempt(attemptId) { +async function getExamAttempt(attemptId) { const currentUser = authenticationService.currentUserValue; - const requestOptions = { - method: "GET", - headers: { - "Access-Control-Allow-Origin": "*", - Accept: "application/json", - "Content-Type": "application/json", - Authorization: "Bearer ".concat(currentUser.jwtToken), - }, - }; - if (currentUser.language_code === null) { - currentUser.language_code = "En"; - currentUser.language_name = "English"; + if (!currentUser?.jwtToken) { + console.error("❌ No valid user token found"); + return null; } - return fetch( - "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/ExamAttempts/" + - attemptId + - "/Questions", - requestOptions - ) - .then((response) => { - if (response.ok) { - return response.json(); - } - // window.localStorage.clear(); - // history.push("/login"); - }) - .then((data) => { - console.log(data); - return data; - }) - .catch((error) => { - // console.error('Error:', error); + + const languageCode = currentUser.language_code || "En"; + const languageName = currentUser.language_name || "English"; + + const url = `https://api.odiprojects.com/api-student/v1/${languageCode}/ExamAttempts/${attemptId}/Questions`; + + try { + const response = await fetch(url, { + method: "GET", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: `Bearer ${currentUser.jwtToken}`, + }, }); + + if (!response.ok) { + console.error(`❌ Request failed with status: ${response.status}`); + // Optional: handle unauthorized user + // if (response.status === 401) { + // window.localStorage.clear(); + // history.push("/login"); + // } + return null; + } + + const data = await response.json(); + console.log("✅ Exam attempt data:", data); + return data; + } catch (error) { + console.error("🚨 Error fetching exam attempt:", error); + return null; + } } function getAllUser(page_size, page_number) { @@ -404,7 +454,7 @@ function getAllUser(page_size, page_number) { }, }; return fetch( - checkRole() + "/users?"+ `pageNumber=${page_number}&pageSize=${page_size}`, + checkRole() + "/users?" + `pageNumber=${page_number}&pageSize=${page_size}`, requestOptions ) .then((response) => { @@ -420,8 +470,8 @@ function getAllUser(page_size, page_number) { return data; }) .catch((error) => { - console.error('Error:', error); - throw "Something went wrong"; + console.error('Error:', error); + throw "Something went wrong"; }); } @@ -441,7 +491,7 @@ function getAllBatch() { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/UserGroups/Classes/" + - currentClass, + currentClass, requestOptions ) .then((response) => { @@ -620,9 +670,9 @@ function createPracticeAttempt(practiceId) { } return fetch( "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/PracticeAttempts/" + - practiceId + "/CreateAttempt", + currentUser.language_code + + "/PracticeAttempts/" + + practiceId + "/CreateAttempt", requestOptions ) .then((response) => { @@ -641,42 +691,47 @@ function createPracticeAttempt(practiceId) { }); } -function createExamAttempt(examId) { +async function createExamAttempt(examId) { const currentUser = authenticationService.currentUserValue; - const requestOptions = { - method: "POST", - headers: { - "Access-Control-Allow-Origin": "*", - Accept: "application/json", - "Content-Type": "application/json", - Authorization: "Bearer ".concat(currentUser.jwtToken), - }, - }; - if (currentUser.language_code === null) { - currentUser.language_code = "En"; - currentUser.language_name = "English"; + if (!currentUser?.jwtToken) { + console.error("❌ No valid user token found"); + return null; } - return fetch( - "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/ExamAttempts/" + - examId, - requestOptions - ) - .then((response) => { - if (response.ok) { - return response.json(); - } - // window.localStorage.clear(); - // history.push("/login"); - }) - .then((data) => { - console.log(data); - return data; - }) - .catch((error) => { - // console.error('Error:', error); + + const languageCode = currentUser.language_code || "En"; + const languageName = currentUser.language_name || "English"; + + const url = `https://api.odiprojects.com/api-student/v1/${languageCode}/ExamAttempts/${examId}`; + + try { + const response = await fetch(url, { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: `Bearer ${currentUser.jwtToken}`, + }, }); + + console.log(response); + + if (!response.ok) { + console.error(`❌ Request failed with status: ${response.status}`); + // Optionally handle unauthorized user + // if (response.status === 401) { + // window.localStorage.clear(); + // history.push("/login"); + // } + return null; + } + + const data = await response.json(); + console.log("✅ Exam attempt created:", data); + return data; + } catch (error) { + console.error("🚨 Error creating exam attempt:", error); + return null; + } } function loadLiveExams(jsonObj) { @@ -701,12 +756,12 @@ function loadLiveExams(jsonObj) { currentUser.language_name = "English"; } return fetch( - "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/Batches/" + - jsonObj.batch + - "/LiveExams" + - queryStr, + "https://api.odiprojects.com/api-student/v1/" + + currentUser.language_code + + "/Batches/" + + jsonObj.batch + + "/LiveExams" + + queryStr, requestOptions ) .then((response) => { @@ -721,7 +776,7 @@ function loadLiveExams(jsonObj) { console.log(data); return data; }) - .catch((error) => {}); + .catch((error) => { }); } function loadUpcomingExam(jsonObj) { @@ -747,11 +802,11 @@ function loadUpcomingExam(jsonObj) { } return fetch( "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/Batches/" + - jsonObj.batch + - "/UpcomingExams" + - queryStr, + currentUser.language_code + + "/Batches/" + + jsonObj.batch + + "/UpcomingExams" + + queryStr, requestOptions ) .then((response) => { @@ -766,7 +821,7 @@ function loadUpcomingExam(jsonObj) { console.log(data); return data; }) - .catch((error) => {}); + .catch((error) => { }); } function getAllClass() { @@ -863,8 +918,8 @@ function publishPractice(practiceId, json) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Practices/" + - practiceId + - "/Publish", + practiceId + + "/Publish", requestOptions ) .then((response) => { @@ -902,8 +957,8 @@ function markQuestions(sectionId, questions) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/ExamSections/" + - sectionId + - "/MarkQuestions", + sectionId + + "/MarkQuestions", requestOptions ) .then((response) => { @@ -936,7 +991,7 @@ async function markQuestionsPractice(practiceId, questions) { }; try { - const res = await fetch(checkRole() + "/Practices/" + practiceId + + const res = await fetch(checkRole() + "/Practices/" + practiceId + "/ReviewQuestions", requestOptions); const data = await res.json(); return data; @@ -964,8 +1019,8 @@ function detachQuestion(sectionId, question) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/ExamSections/" + - sectionId + - "/DetachQuestions", + sectionId + + "/DetachQuestions", requestOptions ) .then((response) => { @@ -1077,8 +1132,8 @@ function deleteExamBatch(obj) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Exams/" + - obj.id + - "/DetachBatch", + obj.id + + "/DetachBatch", requestOptions ) .then((response) => { @@ -1116,8 +1171,8 @@ function addBatchToExam(obj) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Exams/" + - obj.id + - "/AttachBatch", + obj.id + + "/AttachBatch", requestOptions ) .then((response) => { @@ -1151,7 +1206,7 @@ async function addBatchToPractice(obj) { }; try { - const res = await fetch( checkRole() + "/Practices/" + obj.id + "/AttachBatch", requestOptions ); + const res = await fetch(checkRole() + "/Practices/" + obj.id + "/AttachBatch", requestOptions); const data = res.json(); return data; } catch (error) { @@ -1177,8 +1232,8 @@ function detachBatchesFromExam(obj) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Exams/" + - obj.id + - "/DetachBatch", + obj.id + + "/DetachBatch", requestOptions ) .then((response) => { @@ -1212,7 +1267,7 @@ async function detachBatchFromPractice(obj) { }; try { - const res = await fetch( checkRole() + "/Practices/" + obj.id + "/DetachBatch", requestOptions ); + const res = await fetch(checkRole() + "/Practices/" + obj.id + "/DetachBatch", requestOptions); const data = res.json(); return data; } catch (error) { @@ -1238,8 +1293,8 @@ function addBatchesToExam(obj) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Exams/" + - obj.id + - "/AttachBatch", + obj.id + + "/AttachBatch", requestOptions ) .then((response) => { @@ -1275,8 +1330,8 @@ function addSubjectToClass(obj) { }; return fetch( "https://api.odiprojects.com/api-institute/v1/Classes/" + - obj.id + - "/Subjects", + obj.id + + "/Subjects", requestOptions ) .then((response) => { @@ -1293,8 +1348,8 @@ function addSubjectToClass(obj) { return data; }) .catch((error) => { - console.error('Error:', error); - throw error; + console.error('Error:', error); + throw error; }); } @@ -1314,8 +1369,8 @@ async function removeSubjectFromClass(id) { }; try { - const res = await fetch(checkRole()+"/Subjects/"+id, requestOptions); - if(!res.ok) { + const res = await fetch(checkRole() + "/Subjects/" + id, requestOptions); + if (!res.ok) { throw "Something went wrong"; } const data = await res.json(); @@ -1342,8 +1397,8 @@ async function removeTopicFromClass(id) { }; try { - const res = await fetch(checkRole()+"/Categories/"+id, requestOptions); - if(!res.ok) { + const res = await fetch(checkRole() + "/Categories/" + id, requestOptions); + if (!res.ok) { throw "Something went wrong"; } const data = await res.json(); @@ -1370,8 +1425,8 @@ function addTopicToClass(obj) { }; return fetch( "https://api.odiprojects.com/api-institute/v1/Subjects/" + - obj.id + - "/Categories", + obj.id + + "/Categories", requestOptions ) .then((response) => { @@ -1445,7 +1500,7 @@ function createBatch(obj) { }; return fetch( checkRole() + "/UserGroups/Classes/" + - currentClass, + currentClass, requestOptions ) .then((response) => { @@ -1475,10 +1530,10 @@ function getAllBatchForClass(class_id) { "Content-Type": "application/json", Authorization: "Bearer ".concat(currentUser.jwtToken), }, - }; + }; return fetch( "https://api.odiprojects.com/api-institute/v1/UserGroups/Classes/" + - class_id, + class_id, requestOptions ) .then((response) => { @@ -1529,8 +1584,8 @@ function addToBatch(obj) { return data; }) .catch((error) => { - console.error('Error:', error); - throw "Something went wrong, please try again"; + console.error('Error:', error); + throw "Something went wrong, please try again"; }); } @@ -1550,8 +1605,8 @@ function deleteFromBatch(obj) { }; return fetch( "https://api.odiprojects.com/api-institute/v1/UserGroups/" + - obj.batch_id + - "/DetachUsers", + obj.batch_id + + "/DetachUsers", requestOptions ) .then((response) => { @@ -1660,8 +1715,8 @@ function loadReviewQuestions(sectionId) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/ExamSections/" + - sectionId + - "/Questions", + sectionId + + "/Questions", requestOptions ) .then((response) => { @@ -1675,7 +1730,7 @@ function loadReviewQuestions(sectionId) { // console.log(data) return data; }) - .catch((error) => {}); + .catch((error) => { }); } function loadReviewQuestionsPractice(practiceId) { @@ -1696,8 +1751,8 @@ function loadReviewQuestionsPractice(practiceId) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Practices/" + - practiceId + - "/Questions", + practiceId + + "/Questions", requestOptions ) .then((response) => { @@ -1747,7 +1802,7 @@ function loadSections(examId) { // console.log(data) return data; }) - .catch((error) => {}); + .catch((error) => { }); } function loadSectionsForPractice(practiceId) { @@ -1799,7 +1854,7 @@ function getQuestion(question_id, questionLang = undefined) { currentUser.language_code = "En"; currentUser.language_name = "English"; } - if(!questionLang) { + if (!questionLang) { return fetch(checkRole() + "/" + currentUser.language_code + "/Questions/" + question_id, requestOptions) .then((response) => { // console.log(response); @@ -1813,7 +1868,7 @@ function getQuestion(question_id, questionLang = undefined) { // console.log(data); return data; }) - .catch((error) => {}); + .catch((error) => { }); } else { return fetch(checkRole() + "/" + questionLang + "/Questions/" + question_id, requestOptions) .then((response) => { @@ -1828,7 +1883,7 @@ function getQuestion(question_id, questionLang = undefined) { // console.log(data); return data; }) - .catch((error) => {}); + .catch((error) => { }); } } @@ -1891,7 +1946,7 @@ function deleteQuestions(questionArray) { return data; }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -2008,17 +2063,17 @@ async function createQuestion(question) { // console.error('Error:', error); // throw error; // }); - try { - const res = await fetch(checkRole() + "/" + currentUser.language_code + "/Questions", requestOptions); - if(res.ok) { - const data = await res.json(); - return data; - } - // error handling here - throw "Something is wrong, please try again" - } catch (err) { - throw err; + try { + const res = await fetch(checkRole() + "/" + currentUser.language_code + "/Questions", requestOptions); + if (res.ok) { + const data = await res.json(); + return data; } + // error handling here + throw "Something is wrong, please try again" + } catch (err) { + throw err; + } } async function createBulkQuestion(questions) { @@ -2043,7 +2098,7 @@ async function createBulkQuestion(questions) { try { const res = await fetch(checkRole() + "/" + currentUser.language_code + "/AddBulkQuestions", requestOptions); - if(res.ok) { + if (res.ok) { const data = await res.json(); return data; } @@ -2074,17 +2129,17 @@ async function editQuestion(questionID, questionModifications) { currentUser.language_code = "en"; currentUser.language_name = "English"; } - try { - const res = await fetch(checkRole() + "/" + currentUser.language_code + "/Questions/" + questionID, requestOptions); - if(res.ok) { - const data = await res.json(); - return data; - } - // error handling here - throw "Something is wrong, please try again" - } catch (err) { - throw err; + try { + const res = await fetch(checkRole() + "/" + currentUser.language_code + "/Questions/" + questionID, requestOptions); + if (res.ok) { + const data = await res.json(); + return data; } + // error handling here + throw "Something is wrong, please try again" + } catch (err) { + throw err; + } } async function cloneQuestionToLanguage(questionID, questionObj) { @@ -2108,7 +2163,7 @@ async function cloneQuestionToLanguage(questionID, questionObj) { } try { const res = await fetch(checkRole() + "/" + currentUser.language_code + "/Questions/" + questionID + "/CloneQuestionLanguage", requestOptions); - if(res.ok) { + if (res.ok) { const data = await res.json(); return data; } @@ -2135,7 +2190,7 @@ function attachSectionToExam(examId, sections) { }; return fetch( // "https://api.odiprojects.com/api-institute/v1"+ - checkRole() + + checkRole() + "/Exams/" + examId + "/Sections", requestOptions ) @@ -2169,7 +2224,7 @@ function getExamDetails(examId) { } return fetch( // "https://api.odiprojects.com/api-institute/v1" + - checkRole() + + checkRole() + "/Exams/" + examId, requestOptions ) @@ -2184,7 +2239,7 @@ function getExamDetails(examId) { // console.log(data); return data; }) - .catch((error) => {}); + .catch((error) => { }); } function getPracticeDetails(practiceId) { @@ -2274,10 +2329,10 @@ function attachQuestionsToExam(examId, questions) { }; return fetch( // "https://api.odiprojects.com/api-institute/v"+ - checkRole()+ - "/ExamSections/" + - examId + - "/AttachQuestions", + checkRole() + + "/ExamSections/" + + examId + + "/AttachQuestions", requestOptions ) .then((response) => { @@ -2313,7 +2368,7 @@ function attachQuestionsToPractice(practiceId, questions) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Practices/" + practiceId + - "/AttachQuestions", + "/AttachQuestions", requestOptions ) .then((response) => { @@ -2354,10 +2409,10 @@ function createExam(exam) { return fetch( // "https://api.odiprojects.com/api-institute/v1/" + checkRole() + "/" + - currentUser.language_code + - "/Classes/" + - currentClass + - "/Exams", + currentUser.language_code + + "/Classes/" + + currentClass + + "/Exams", requestOptions ) .then((response) => { @@ -2374,7 +2429,7 @@ function createExam(exam) { return data; }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -2396,13 +2451,13 @@ function createPractise(obj) { if (currentUser.language_code === null) { currentUser.language_code = "En"; currentUser.language_name = "English"; - } + } return fetch( // "https://api.odiprojects.com/api-institute/v1" + checkRole() + "/" + currentUser.language_code + "/Classes/" + - currentClass + - "/Practices", + currentClass + + "/Practices", requestOptions ) .then((response) => { @@ -2445,9 +2500,9 @@ function updateExam(exam) { return fetch( // "https://api.odiprojects.com/api-institute/v1" + checkRole() + - // currentUser.language_code + - "/Exams/" + - exam.id, + // currentUser.language_code + + "/Exams/" + + exam.id, requestOptions ) .then((response) => { @@ -2461,7 +2516,7 @@ function updateExam(exam) { return data; }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -2487,17 +2542,17 @@ function updateBookMark(questionArray, isBookmarkValue) { currentUser.language_name = "English"; } return fetch(checkRole() + "/" + currentUser.language_code + "/Questions/Bookmark", requestOptions).then((response) => { - if (response.ok) { - return response.json(); - } - // window.localStorage.clear(); - // history.push("/login"); - }) + if (response.ok) { + return response.json(); + } + // window.localStorage.clear(); + // history.push("/login"); + }) .then((data) => { return data; }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -2614,9 +2669,9 @@ function loadSubCategory(category) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/" + currentUser.language_code + - "/Categories/" + - category + - "/SubCategories", + "/Categories/" + + category + + "/SubCategories", requestOptions ) .then((response) => { @@ -2681,8 +2736,8 @@ function loadQuestions(jsonObj) { } } if (jsonObj.translationMissing) { - queryStr === "" ? queryStr = "?"+"translation_missing="+jsonObj.translationMissing - : queryStr = queryStr+ "&translation_missing="+jsonObj.translationMissing + queryStr === "" ? queryStr = "?" + "translation_missing=" + jsonObj.translationMissing + : queryStr = queryStr + "&translation_missing=" + jsonObj.translationMissing } if (currentUser.language_code === null) { @@ -2691,11 +2746,11 @@ function loadQuestions(jsonObj) { } return fetch( checkRole() + "/" + - currentUser.language_code + - "/Classes/" + - currentClass + - "/Questions" + - queryStr, + currentUser.language_code + + "/Classes/" + + currentClass + + "/Questions" + + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -2719,7 +2774,7 @@ function loadQuestions(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -2750,16 +2805,16 @@ function draftExam(jsonObj) { return fetch( // "https://api.odiprojects.com/api-institute/v1" + checkRole() + - "/Classes/" + - currentClass + - "/DraftExams" + - queryStr, + "/Classes/" + + currentClass + + "/DraftExams" + + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) .then((response) => { if (!currentClass) { - throw new Error ("No class is set, please set a class and try again."); + throw new Error("No class is set, please set a class and try again."); } if (response.ok) { return response.json(); @@ -2776,7 +2831,7 @@ function draftExam(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -2808,7 +2863,7 @@ function draftPractice(jsonObj) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Classes/" + currentClass + "/DraftSubjectPractices" + - queryStr, + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -2829,8 +2884,8 @@ function draftPractice(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); - throw error; + console.error('Error:', error); + throw error; }); } @@ -2862,7 +2917,7 @@ function livePractice(jsonObj) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Classes/" + currentClass + "/LiveSubjectPractices" + - queryStr, + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -2912,9 +2967,9 @@ function upcomingPractice(jsonObj) { } return fetch( // "https://api.odiprojects.com/api-institute/v1"+ - checkRole()+ "/Classes/" + currentClass + + checkRole() + "/Classes/" + currentClass + "/UpcomingSubjectPractices" + - queryStr, + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -2965,8 +3020,8 @@ function draftPracticeCategory(jsonObj) { return fetch( // "https://api.odiprojects.com/api-institute/v1" + checkRole() + "/Classes/" + currentClass + - "/DraftCategoryPractices" + - queryStr, + "/DraftCategoryPractices" + + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -2986,7 +3041,7 @@ function draftPracticeCategory(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -3018,7 +3073,7 @@ function livePracticeCategory(jsonObj) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Classes/" + currentClass + "/LiveCategoryPractices" + - queryStr, + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -3070,7 +3125,7 @@ function upcomingPracticeCategory(jsonObj) { // "https://api.odiprojects.com/api-institute/v1"+ checkRole() + "/Classes/" + currentClass + "/UpcomingCategoryPractices" + - queryStr, + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -3090,7 +3145,7 @@ function upcomingPracticeCategory(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -3121,10 +3176,10 @@ function liveExam(jsonObj) { return fetch( // "https://api.odiprojects.com/api-institute/v1" + checkRole() + - "/Classes/" + - currentClass + - "/LiveExams" + - queryStr, + "/Classes/" + + currentClass + + "/LiveExams" + + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -3139,7 +3194,7 @@ function liveExam(jsonObj) { // history.push("/login"); }) .then((data) => { - if(!data) throw ("Something went wrong, please reload the page and try again."); + if (!data) throw ("Something went wrong, please reload the page and try again."); // console.log('Success:', data); return data; @@ -3148,8 +3203,8 @@ function liveExam(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); - throw error; + console.error('Error:', error); + throw error; }); } @@ -3167,8 +3222,8 @@ function livePracticeExams(module) { }; let queryStr = ""; queryStr = "?"; - queryStr = queryStr + `module=${module}`; - queryStr = queryStr + `&module_id=-1`; + queryStr = queryStr + `module=${module}`; + queryStr = queryStr + `&module_id=-1`; if (currentUser.language_code === null) { currentUser.language_code = "En"; @@ -3177,9 +3232,9 @@ function livePracticeExams(module) { return fetch( "https://api.odiprojects.com/api-institute/v1/" + "Classes/" + - currentClass + - "/LivePractices" + - queryStr, + currentClass + + "/LivePractices" + + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -3231,10 +3286,10 @@ function upcomingExam(jsonObj) { return fetch( // "https://api.odiprojects.com/api-institute/v1" + checkRole() + - "/Classes/" + - currentClass + - "/UpcomingExams" + - queryStr, + "/Classes/" + + currentClass + + "/UpcomingExams" + + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -3255,7 +3310,7 @@ function upcomingExam(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -3287,10 +3342,10 @@ function expiredExam(jsonObj) { return fetch( // "https://api.odiprojects.com/api-institute/v1" + checkRole() + - "/Classes/" + - currentClass + - "/HistoryExams" + - queryStr, + "/Classes/" + + currentClass + + "/HistoryExams" + + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -3313,7 +3368,7 @@ function expiredExam(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -3360,8 +3415,8 @@ function loadQuestionsBookmark(jsonObj) { } } if (jsonObj.translationMissing) { - queryStr === "" ? queryStr = "?"+"translation_missing="+jsonObj.translationMissing - : queryStr = queryStr+ "&translation_missing="+jsonObj.translationMissing + queryStr === "" ? queryStr = "?" + "translation_missing=" + jsonObj.translationMissing + : queryStr = queryStr + "&translation_missing=" + jsonObj.translationMissing } if (currentUser.language_code === null) { currentUser.language_code = "En"; @@ -3370,7 +3425,7 @@ function loadQuestionsBookmark(jsonObj) { return fetch( checkRole() + "/" + currentUser.language_code + "/Classes/" + currentClass + "/BookmarkedQuestions" + - queryStr, + queryStr, requestOptions //return fetch("https://api.odiprojects.com/api-institute/v1/en/Classes/1/Questions?module=subject&module_id=1", requestOptions ) @@ -3394,12 +3449,12 @@ function loadQuestionsBookmark(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } async function loadCategory(subject) { - if(subject != "") { + if (subject != "") { const currentUser = authenticationService.currentUserValue; // console.log(subject); const requestOptions = { @@ -3415,8 +3470,8 @@ async function loadCategory(subject) { } try { - const response= await fetch( `${checkRole()}/Subjects/` + subject + "/Categories", requestOptions ) - const data = await response.json(); + const response = await fetch(`${checkRole()}/Subjects/` + subject + "/Categories", requestOptions) + const data = await response.json(); return data; } catch (error) { console.error(error); @@ -3442,7 +3497,7 @@ async function loadSubjects(classes) { try { if (!currentClass) throw 'Class has not been set. Please set a class or try reloading the page again'; // error handling - const response = await fetch(`${checkRole()}/Classes` + "/" + currentClass +"/Subjects", requestOptions) + const response = await fetch(`${checkRole()}/Classes` + "/" + currentClass + "/Subjects", requestOptions) const data = await response.json(); return data; @@ -3497,9 +3552,9 @@ function myQuestion(jsonObj) { } return fetch( "https://api.odiprojects.com/api-institute/v1/en/Classes/" + - currentClass + - "/Questions?" + - queryStr, + currentClass + + "/Questions?" + + queryStr, requestOptions ) .then((response) => { @@ -3549,8 +3604,8 @@ function draftQuestion(jsonObj) { "?module_id=" + jsonObj.module_id + "&module=" + jsonObj.module; } if (jsonObj.complexity !== undefined && jsonObj.complexity !== "") { - queryStr !== ""? queryStr = queryStr + "&complexity=" + jsonObj.complexity - : queryStr = "?complexity=" + jsonObj.complexity; + queryStr !== "" ? queryStr = queryStr + "&complexity=" + jsonObj.complexity + : queryStr = "?complexity=" + jsonObj.complexity; } if (queryStr !== "") { queryStr = @@ -3564,10 +3619,10 @@ function draftQuestion(jsonObj) { jsonObj.pageSize; } if (jsonObj.translationMissing) { - queryStr === "" ? queryStr = "?"+"translation_missing="+jsonObj.translationMissing - : queryStr = queryStr+ "&translation_missing="+jsonObj.translationMissing + queryStr === "" ? queryStr = "?" + "translation_missing=" + jsonObj.translationMissing + : queryStr = queryStr + "&translation_missing=" + jsonObj.translationMissing } - + // console.log(queryStr); if (currentUser.language_code === null) { currentUser.language_code = "En"; @@ -3576,9 +3631,9 @@ function draftQuestion(jsonObj) { return fetch( checkRole() + "/" + currentUser.language_code + "/Classes/" + - currentClass + - "/DraftQuestions" + - queryStr, + currentClass + + "/DraftQuestions" + + queryStr, requestOptions ) .then((response) => { @@ -3598,7 +3653,7 @@ function draftQuestion(jsonObj) { // sessionStorage.setItem('token', data.result.jwtToken); }) .catch((error) => { - console.error('Error:', error); + console.error('Error:', error); }); } @@ -3623,9 +3678,9 @@ function savedDraftQuestion(id, content) { } return fetch( "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/Questions/" + - id, + currentUser.language_code + + "/Questions/" + + id, requestOptions ) .then((response) => { @@ -3664,9 +3719,9 @@ function submitcreateQuestion(id, content) { } return fetch( "https://api.odiprojects.com/api-institute/v1/" + - currentUser.language_code + - "/Questions/" + - id, + currentUser.language_code + + "/Questions/" + + id, requestOptions ) .then((response) => {