UI changes
This commit is contained in:
parent
d305baee71
commit
663d97f6dc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) => (
|
||||
<Select.Option
|
||||
|
|
|
|||
|
|
@ -1,242 +1,307 @@
|
|||
li.MyExam{
|
||||
-moz-box-shadow: 0 0 5px #888;
|
||||
-webkit-box-shadow: 0 0 5px#888;
|
||||
box-shadow: 0 0 5px #E1E1E1;
|
||||
margin-bottom: 10px;
|
||||
padding:5px 35px 5px 25px;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
li.MyExam table{
|
||||
width:80%;
|
||||
}
|
||||
|
||||
span.MyExamImage{
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
span.MyExamImage img{
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
|
||||
}
|
||||
|
||||
div.MyExamDiv table tr> th{
|
||||
border:none;
|
||||
padding: 0 0 0 10px;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
div.MyExamDiv table tr> td{
|
||||
border:none;
|
||||
padding: 0 0 0 10px;
|
||||
text-align: left;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
li.MyExam h4.ant-list-item-meta-title{
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
li.MyExam span.MyExamSpan{
|
||||
padding: 0 0 0 10px;
|
||||
}
|
||||
|
||||
.ExamNameHeader {
|
||||
font-size: 18pt;
|
||||
float: left;
|
||||
color: white;
|
||||
}
|
||||
.ExamTimeHeader{
|
||||
font-size: 16pt;
|
||||
float: right;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.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
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
.exam-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
padding: 0 24px;
|
||||
height: 64px;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
}
|
||||
.QuestionCard div.ant-card-body{
|
||||
height: 67%;
|
||||
padding:16px;
|
||||
|
||||
.exam-header-left .exam-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
.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;
|
||||
|
||||
.exam-header-center {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.exam-countdown .ant-statistic-title {
|
||||
color: #555;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.exam-countdown .ant-statistic-content {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1677ff;
|
||||
}
|
||||
|
||||
.exam-header-right {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.exam-header-right .ant-btn {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
.create-exam-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
/* Tabs styling */
|
||||
.create-exam-tabs {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.create-exam-tabs .ant-tabs-nav {
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* ✨ Hover effect – only text color changes */
|
||||
.create-exam-tabs .ant-tabs-tab:hover {
|
||||
color: #1677ff;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* Active tab – only bold text + blue ink bar */
|
||||
.create-exam-tabs .ant-tabs-tab-active {
|
||||
color: #1677ff !important;
|
||||
font-weight: 600;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
/* Ink bar – thin blue underline */
|
||||
.create-exam-tabs .ant-tabs-ink-bar {
|
||||
background: #1677ff;
|
||||
height: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.exam-status-card:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.exam-status-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.exam-status-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 16px 12px;
|
||||
}
|
||||
|
||||
.status-item {
|
||||
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;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.QuesttionStatusNotVisited{
|
||||
background-color: #F0F0F0
|
||||
}
|
||||
|
||||
.QuesttionStatusNotAnswered{
|
||||
background-color: #FED911
|
||||
}
|
||||
.QuesttionStatusAnswered{
|
||||
background-color: #54C51D
|
||||
}
|
||||
.QuesttionStatusReview{
|
||||
background-color: #A028FF
|
||||
}
|
||||
.QuesttionStatusAnsweredReview{
|
||||
background-color: #FFA500
|
||||
}
|
||||
|
||||
.QuesttionStatusNotVisitedCard{
|
||||
border-color: #F0F0F0
|
||||
}
|
||||
|
||||
.QuesttionStatusNotAnsweredCard{
|
||||
border-color: #FED911
|
||||
}
|
||||
.QuesttionStatusAnsweredCard{
|
||||
border-color: #54C51D
|
||||
}
|
||||
.QuesttionStatusReviewCard{
|
||||
border-color: #A028FF
|
||||
}
|
||||
.QuesttionStatusAnsweredReviewCard{
|
||||
border-color: #FFA500
|
||||
}
|
||||
|
||||
div.QuestionStatusHeaderIcon{
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
border-radius: 274.76px;
|
||||
box-shadow: 0 0 15px 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
div.HeaderQuestionStatusLabel{
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: 12px;
|
||||
line-height: 1.125rem;
|
||||
.status-label {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
letter-spacing: .25px;
|
||||
text-decoration: none;
|
||||
text-transform: none;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.QuesttionStatusNotVisitedTitle{
|
||||
color: #F0F0F0
|
||||
/* Avatar badges */
|
||||
.status-avatar {
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.QuesttionStatusNotAnsweredTitle{
|
||||
color: #FED911
|
||||
}
|
||||
.QuesttionStatusAnsweredTitle{
|
||||
color: #54C51D
|
||||
}
|
||||
.QuesttionStatusReviewTitle{
|
||||
color: #A028FF
|
||||
}
|
||||
.QuesttionStatusAnsweredReviewTitle{
|
||||
color: #FFA500
|
||||
/* Individual colors for clarity */
|
||||
.status-avatar.not-visited {
|
||||
background-color: #d9d9d9;
|
||||
}
|
||||
|
||||
.Outline{ display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
width: 77%;
|
||||
font-size: 14px;
|
||||
.status-avatar.not-answered {
|
||||
background-color: #ff7875;
|
||||
}
|
||||
|
||||
.MainExamQuestionLayout{
|
||||
padding: 20px;
|
||||
.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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
})
|
||||
if (quest.is_visited) questionsArray.push(quest);
|
||||
});
|
||||
|
||||
return questionsArray;
|
||||
}
|
||||
|
||||
|
||||
onPauseExam(){
|
||||
|
||||
let questionsArray = this.getExamModelToUpdate();
|
||||
|
||||
onPauseExam() {
|
||||
this.stopExamUpdate();
|
||||
selectorService.pauseExam(this.state.attempt_id).then((data) => {
|
||||
|
||||
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(){
|
||||
onSubmitExam() {
|
||||
let questionsArray = this.getExamModelToUpdate();
|
||||
this.stopExamUpdate();
|
||||
selectorService.endExam(this.state.attempt_id,questionsArray).then((data) => {
|
||||
console.log(data);
|
||||
|
||||
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(){
|
||||
stopExamUpdate() {
|
||||
clearInterval(this.interval);
|
||||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
componentWillUnmount() {
|
||||
this.stopExamUpdate();
|
||||
}
|
||||
|
||||
sendExamUpdate(){
|
||||
sendHeartbeat() {
|
||||
this.interval = setInterval(() => {
|
||||
if(this.state.pauseUpdate){
|
||||
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) => {
|
||||
// console.log("Parent recieved Selector Data: "+ childData);
|
||||
let q = childData;
|
||||
let indx = q.index;
|
||||
let nxtQuestion = this.state.allQuestions[(indx)];
|
||||
// ✅ 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);
|
||||
}
|
||||
|
||||
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;
|
||||
if (answered.length > 0) isAnswered = true;
|
||||
let classN = "QuesttionStatusNotVisited";
|
||||
if(question.isVisited)
|
||||
classN = "QuesttionStatusNotAnswered";
|
||||
if(isAnswered && !question.isReviewMarked)
|
||||
if (question.isVisited) classN = "QuesttionStatusNotAnswered";
|
||||
if (isAnswered && !question.isReviewMarked)
|
||||
classN = "QuesttionStatusAnswered";
|
||||
if(question.isReviewMarked && isAnswered){
|
||||
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;
|
||||
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 = <Layout><QuestionDetail totalQuestion={this.state.allQuestions.length} question={this.state.activeDetailQuestion} parentCallbackNext = {this.callbackFunctionNext} parentCallback = {this.callbackFunction}/></Layout>;
|
||||
listItems = this.state.sections.map((item, index) =>
|
||||
activeQuestion = (
|
||||
<Layout>
|
||||
<QuestionDetail
|
||||
totalQuestion={this.state.allQuestions.length}
|
||||
question={this.state.activeDetailQuestion}
|
||||
updateAnswerCallback={this.callbackFunctionUpdateAnswer}
|
||||
parentCallbackNext={this.callbackFunctionNext}
|
||||
parentCallback={this.callbackFunction}
|
||||
/>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
<TabPane tab={item.subject_name} key={index} >
|
||||
{
|
||||
this.state.showQuestion?activeQuestion:
|
||||
<Row gutter={40} className="AttemptQuestionGrid">
|
||||
listItems = this.state.sections.map((item, index) => (
|
||||
<TabPane tab={item.subject_name} key={index}>
|
||||
{this.state.showQuestion ? (
|
||||
activeQuestion
|
||||
) : (
|
||||
<Row gutter={40} className="AttemptQuestionGrid" style={{ padding: "20px" }}>
|
||||
{item.questions.map((question, index) => {
|
||||
let title = <><Avatar className={question.classN}>{question.index}</Avatar><div className='Outerline'>
|
||||
<div className={"HeaderQuestionStatusLabel "+question.classN+"Title"}>{question.statusLabel}</div>
|
||||
let title = (
|
||||
<>
|
||||
<Avatar className={question.classN}>{question.index}</Avatar>
|
||||
<div className="Outerline">
|
||||
<div
|
||||
className={
|
||||
"HeaderQuestionStatusLabel " +
|
||||
question.classN +
|
||||
"Title"
|
||||
}
|
||||
>
|
||||
{question.statusLabel}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
</div></>
|
||||
return (
|
||||
<Col key={question.id} className="question-col">
|
||||
<Card
|
||||
hoverable
|
||||
className={`question-card ${question.classN}-card`}
|
||||
onClick={() => this.showDetailQuestion(question)}
|
||||
>
|
||||
<div className="question-card-header">
|
||||
<span className="question-title">{title}</span>
|
||||
<Tag color="blue" className="question-type">
|
||||
{question.type_text}
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
return <Col key={question.id} >
|
||||
<Card title={title} actions={[
|
||||
question.type_text
|
||||
]} className={"QuestionCard "+question.classN+"Card"} onClick={this.showDetailQuestion.bind(this,question)}>
|
||||
<div className="question-content">
|
||||
<p>{parse(question.question_text)}</p>
|
||||
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
);
|
||||
|
||||
})}
|
||||
</Row>
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
)}
|
||||
</TabPane>
|
||||
));
|
||||
|
||||
|
||||
);
|
||||
|
||||
|
||||
|
||||
accordions = this.state.sections.map((item, index) =>
|
||||
accordions = this.state.sections.map((item, index) => (
|
||||
<Panel header={item.subject_name} key={index}>
|
||||
<Row gutter={20}>
|
||||
{item.questions.map((question) => {
|
||||
return <Col key={question.id}>
|
||||
<Avatar className={question.classN} onClick={this.onQuestionClick.bind(this,question.index)}>{question.index}</Avatar>
|
||||
</Col>})}
|
||||
{item.questions.map((question) => (
|
||||
<Col key={question.id}>
|
||||
<Avatar
|
||||
className={question.classN}
|
||||
onClick={this.onQuestionClick.bind(this, question.index)}
|
||||
>
|
||||
{question.index}
|
||||
</Avatar>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</Panel>
|
||||
|
||||
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout>
|
||||
<Layout>
|
||||
<Header className="header">
|
||||
<div style={{ paddingRight: 10, display: 'inline' }} className="ExamNameHeader">
|
||||
<span >{this.state.exam_name}</span>
|
||||
<Header className="exam-header">
|
||||
<div className="exam-header-left">
|
||||
<span className="exam-title">{this.state.exam_name}</span>
|
||||
</div>
|
||||
<div className="ExamTimeHeader">
|
||||
<Countdown title="Time Left" value={this.state.deadline} onFinish={this.onSubmitExam} />
|
||||
|
||||
<div className="exam-header-center">
|
||||
<Countdown
|
||||
title="Time Left"
|
||||
value={this.state.deadline}
|
||||
onFinish={this.onSubmitExam}
|
||||
className="exam-countdown"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ paddingLeft: 10, display: 'inline' }}>
|
||||
<Button onClick={this.onPauseExam} style={{ marginRight: 8 }}>Leave</Button>
|
||||
</div>
|
||||
<div style={{ paddingRight: 10, display: 'inline' }}>
|
||||
<Button type="primary" onClick={this.onSubmitExam}
|
||||
style={{ marginRight: 8 }}>Submit</Button>
|
||||
|
||||
<div className="exam-header-right">
|
||||
<Button onClick={this.onPauseExam}>Leave</Button>
|
||||
<Button type="primary" onClick={this.onSubmitExam}>
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
</Header>
|
||||
|
||||
|
||||
<Content
|
||||
className="site-layout-background"
|
||||
style={{
|
||||
padding: 24,
|
||||
margin: 0,
|
||||
}}
|
||||
style={{ padding: 24, margin: 0 }}
|
||||
>
|
||||
<Layout className="MainExamLayout">
|
||||
<Layout className="createExamLayoutLeft">{
|
||||
<Tabs defaultActiveKey="1" size={"large"} type={"line"} style={{ marginBottom: 32 }} onTabClick={this.onTabPaneClick.bind(this)}>
|
||||
{ listItems }</Tabs>
|
||||
|
||||
|
||||
}
|
||||
<Layout className="create-exam-card">
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
size="large"
|
||||
type="line"
|
||||
animated
|
||||
onTabClick={this.onTabPaneClick.bind(this)}
|
||||
className="create-exam-tabs"
|
||||
>
|
||||
{listItems}
|
||||
</Tabs>
|
||||
</Layout>
|
||||
<Layout className="createExamLayoutRight">
|
||||
<div>
|
||||
<table className="ExamStatusTable">
|
||||
<tbody>
|
||||
<tr >
|
||||
<td><span className="ExamAvatar"><Avatar className="StatusAvatar QuesttionStatusNotVisited" >{total_notVisited}</Avatar><span className="StatusLabel">{" Not Visited "}</span></span></td>
|
||||
<td><span className="ExamAvatar"><Avatar className="StatusAvatar QuesttionStatusNotAnswered" >{total_notAnswered}</Avatar><span className="StatusLabel">{" Not Answered "}</span></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span className="ExamAvatar"><Avatar className="StatusAvatar QuesttionStatusAnswered">{total_Answered}</Avatar><span className="StatusLabel">{" Answered "}</span></span></td>
|
||||
<td><span className="ExamAvatar"><Avatar className="StatusAvatar QuesttionStatusReview" >{total_Reviwed}</Avatar><span className="StatusLabel">{" To Review "}</span></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span className="ExamAvatar"><Avatar className="StatusAvatar QuesttionStatusAnsweredReview">{total_AnsweredReviwed}</Avatar><span className="StatusLabel">{" Answered & To Review "}</span></span></td>
|
||||
|
||||
<Layout className="exam-status-card">
|
||||
<div className="exam-status-section">
|
||||
<table className="exam-status-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div className="status-item">
|
||||
<Avatar className="status-avatar not-visited">{total_notVisited}</Avatar>
|
||||
<span className="status-label">Not Visited</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="status-item">
|
||||
<Avatar className="status-avatar not-answered">{total_notAnswered}</Avatar>
|
||||
<span className="status-label">Not Answered</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<div className="status-item">
|
||||
<Avatar className="status-avatar answered">{total_Answered}</Avatar>
|
||||
<span className="status-label">Answered</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div className="status-item">
|
||||
<Avatar className="status-avatar to-review">{total_Reviwed}</Avatar>
|
||||
<span className="status-label">To Review</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colSpan="2">
|
||||
<div className="status-item">
|
||||
<Avatar className="status-avatar answered-review">{total_AnsweredReviwed}</Avatar>
|
||||
<span className="status-label">Answered & To Review</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<Collapse accordion>
|
||||
{accordions}
|
||||
</Collapse>
|
||||
|
||||
<div className="exam-accordion">
|
||||
<Collapse accordion>{accordions}</Collapse>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
</Layout>
|
||||
</Content>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</>
|
||||
)
|
||||
};
|
||||
};
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AttemptExam;
|
||||
|
|
|
|||
|
|
@ -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,20 +27,21 @@ 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;
|
||||
|
|
@ -51,8 +51,9 @@ class QuestionDetail extends React.Component {
|
|||
}
|
||||
|
||||
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 <Radio className='radioStyle' key={option.id} value={option.id} checked={option.isSelected}>
|
||||
const answerOptions = question.options.map((option) => {
|
||||
if (option.isSelected) answer = option.id;
|
||||
return (
|
||||
<Radio className="radioStyle" key={option.id} value={option.id}>
|
||||
{option.text}
|
||||
</Radio>
|
||||
);
|
||||
});
|
||||
|
||||
})
|
||||
let questionDetails= <Layout className="MainExamQuestionLayout">
|
||||
<Row>
|
||||
return (
|
||||
<Layout className="MainExamQuestionLayout" style={{ background: "#fff" }}>
|
||||
<Row className="question-header">
|
||||
<Col>
|
||||
<h3>{this.props.question.index}. {parse(this.props.question.question_text)}</h3>
|
||||
<h3 className="question-title">
|
||||
{question.index}. {parse(question.question_text)}
|
||||
</h3>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="Options">
|
||||
<Col>
|
||||
<div> <Radio.Group onChange={this.onAnswerChange} value={answer}>
|
||||
|
||||
{
|
||||
answerOption
|
||||
}
|
||||
<Row className="question-options">
|
||||
<Col>
|
||||
<Radio.Group
|
||||
onChange={this.onAnswerChange}
|
||||
value={answer}
|
||||
className="radio-group"
|
||||
>
|
||||
{answerOptions}
|
||||
</Radio.Group>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row className="review-switch">
|
||||
<Col>
|
||||
<Switch
|
||||
checkedChildren="Review On"
|
||||
unCheckedChildren="Review Off"
|
||||
checked={question.isReviewMarked}
|
||||
onChange={this.onReviewQuestion}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row className="question-actions">
|
||||
<Col>
|
||||
<div className="action-buttons">
|
||||
<Button
|
||||
onClick={this.loadNextQuestion}
|
||||
type="primary"
|
||||
disabled={question.index >= totalQuestion}
|
||||
className="rounded-btn"
|
||||
>
|
||||
Next Question
|
||||
</Button>
|
||||
<Button
|
||||
onClick={this.onClearResponse}
|
||||
className="rounded-btn"
|
||||
>
|
||||
Clear Response
|
||||
</Button>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<br/>
|
||||
<Switch checkedChildren="Review On" unCheckedChildren="Review Off" checked={this.state.question.isReviewMarked} onChange={this.onReviewQuestion} />
|
||||
<br/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<br/>
|
||||
<br/>
|
||||
</Col>
|
||||
</Row>
|
||||
<ButtonGroup><Button
|
||||
onClick={this.loadNextQuestion}
|
||||
type="primary"
|
||||
disabled={this.props.question.index>=this.props.totalQuestion}
|
||||
style={{ marginRight: 8 }}
|
||||
>
|
||||
{" "}
|
||||
Next Question{" "}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={this.onClearResponse}
|
||||
style={{ marginRight: 8 }}
|
||||
>
|
||||
{" "}
|
||||
Clear Response{" "}
|
||||
</Button></ButtonGroup>
|
||||
</Layout>
|
||||
|
||||
return (
|
||||
<>
|
||||
{questionDetails}
|
||||
|
||||
</>
|
||||
)
|
||||
};
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default QuestionDetail;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
@ -168,112 +169,159 @@ function loadReport(examId) {
|
|||
});
|
||||
}
|
||||
|
||||
function pauseExam(attempt_id) {
|
||||
async function pauseExam(attemptId) {
|
||||
const currentUser = authenticationService.currentUserValue;
|
||||
const requestOptions = {
|
||||
method: "PUT",
|
||||
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: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer ".concat(currentUser.jwtToken),
|
||||
Authorization: `Bearer ${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();
|
||||
}
|
||||
});
|
||||
|
||||
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");
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("⏸️ Exam paused successfully:", data);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.error('Error:', error);
|
||||
});
|
||||
} 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",
|
||||
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: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer ".concat(currentUser.jwtToken),
|
||||
Authorization: `Bearer ${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();
|
||||
}
|
||||
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");
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("✅ Exam ended successfully:", data);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.error('Error:', error);
|
||||
});
|
||||
} 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",
|
||||
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: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer ".concat(currentUser.jwtToken),
|
||||
Authorization: `Bearer ${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();
|
||||
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");
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("✅ Exam status updated:", data);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.error('Error:', error);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("🚨 Error updating exam status:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function updateBatchName(obj) {
|
||||
|
|
@ -353,43 +401,45 @@ function getPracticeAttempt(practiceId) {
|
|||
}
|
||||
|
||||
|
||||
function getExamAttempt(attemptId) {
|
||||
async function getExamAttempt(attemptId) {
|
||||
const currentUser = authenticationService.currentUserValue;
|
||||
const requestOptions = {
|
||||
if (!currentUser?.jwtToken) {
|
||||
console.error("❌ No valid user token found");
|
||||
return null;
|
||||
}
|
||||
|
||||
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: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer ".concat(currentUser.jwtToken),
|
||||
Authorization: `Bearer ${currentUser.jwtToken}`,
|
||||
},
|
||||
};
|
||||
if (currentUser.language_code === null) {
|
||||
currentUser.language_code = "En";
|
||||
currentUser.language_name = "English";
|
||||
}
|
||||
return fetch(
|
||||
"https://api.odiprojects.com/api-institute/v1/" +
|
||||
currentUser.language_code +
|
||||
"/ExamAttempts/" +
|
||||
attemptId +
|
||||
"/Questions",
|
||||
requestOptions
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
});
|
||||
|
||||
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");
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("✅ Exam attempt data:", data);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.error('Error:', error);
|
||||
});
|
||||
} 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) => {
|
||||
|
|
@ -641,42 +691,47 @@ function createPracticeAttempt(practiceId) {
|
|||
});
|
||||
}
|
||||
|
||||
function createExamAttempt(examId) {
|
||||
async function createExamAttempt(examId) {
|
||||
const currentUser = authenticationService.currentUserValue;
|
||||
const requestOptions = {
|
||||
if (!currentUser?.jwtToken) {
|
||||
console.error("❌ No valid user token found");
|
||||
return null;
|
||||
}
|
||||
|
||||
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: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
Authorization: "Bearer ".concat(currentUser.jwtToken),
|
||||
Authorization: `Bearer ${currentUser.jwtToken}`,
|
||||
},
|
||||
};
|
||||
if (currentUser.language_code === null) {
|
||||
currentUser.language_code = "En";
|
||||
currentUser.language_name = "English";
|
||||
}
|
||||
return fetch(
|
||||
"https://api.odiprojects.com/api-institute/v1/" +
|
||||
currentUser.language_code +
|
||||
"/ExamAttempts/" +
|
||||
examId,
|
||||
requestOptions
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json();
|
||||
}
|
||||
});
|
||||
|
||||
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");
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
// }
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("✅ Exam attempt created:", data);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {
|
||||
// console.error('Error:', error);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("🚨 Error creating exam attempt:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function loadLiveExams(jsonObj) {
|
||||
|
|
@ -701,7 +756,7 @@ function loadLiveExams(jsonObj) {
|
|||
currentUser.language_name = "English";
|
||||
}
|
||||
return fetch(
|
||||
"https://api.odiprojects.com/api-institute/v1/" +
|
||||
"https://api.odiprojects.com/api-student/v1/" +
|
||||
currentUser.language_code +
|
||||
"/Batches/" +
|
||||
jsonObj.batch +
|
||||
|
|
@ -721,7 +776,7 @@ function loadLiveExams(jsonObj) {
|
|||
console.log(data);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {});
|
||||
.catch((error) => { });
|
||||
}
|
||||
|
||||
function loadUpcomingExam(jsonObj) {
|
||||
|
|
@ -766,7 +821,7 @@ function loadUpcomingExam(jsonObj) {
|
|||
console.log(data);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {});
|
||||
.catch((error) => { });
|
||||
}
|
||||
|
||||
function getAllClass() {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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();
|
||||
|
|
@ -1675,7 +1730,7 @@ function loadReviewQuestions(sectionId) {
|
|||
// console.log(data)
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {});
|
||||
.catch((error) => { });
|
||||
}
|
||||
|
||||
function loadReviewQuestionsPractice(practiceId) {
|
||||
|
|
@ -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) => { });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2010,7 +2065,7 @@ async function createQuestion(question) {
|
|||
// });
|
||||
try {
|
||||
const res = await fetch(checkRole() + "/" + currentUser.language_code + "/Questions", requestOptions);
|
||||
if(res.ok) {
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
return data;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -2076,7 +2131,7 @@ async function editQuestion(questionID, questionModifications) {
|
|||
}
|
||||
try {
|
||||
const res = await fetch(checkRole() + "/" + currentUser.language_code + "/Questions/" + questionID, requestOptions);
|
||||
if(res.ok) {
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
return data;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -2184,7 +2239,7 @@ function getExamDetails(examId) {
|
|||
// console.log(data);
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {});
|
||||
.catch((error) => { });
|
||||
}
|
||||
|
||||
function getPracticeDetails(practiceId) {
|
||||
|
|
@ -2274,7 +2329,7 @@ function attachQuestionsToExam(examId, questions) {
|
|||
};
|
||||
return fetch(
|
||||
// "https://api.odiprojects.com/api-institute/v"+
|
||||
checkRole()+
|
||||
checkRole() +
|
||||
"/ExamSections/" +
|
||||
examId +
|
||||
"/AttachQuestions",
|
||||
|
|
@ -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) {
|
||||
|
|
@ -2759,7 +2814,7 @@ function draftExam(jsonObj) {
|
|||
)
|
||||
.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();
|
||||
|
|
@ -2912,7 +2967,7 @@ function upcomingPractice(jsonObj) {
|
|||
}
|
||||
return fetch(
|
||||
// "https://api.odiprojects.com/api-institute/v1"+
|
||||
checkRole()+ "/Classes/" + currentClass +
|
||||
checkRole() + "/Classes/" + currentClass +
|
||||
"/UpcomingSubjectPractices" +
|
||||
queryStr,
|
||||
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;
|
||||
|
||||
|
|
@ -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";
|
||||
|
|
@ -3399,7 +3454,7 @@ function loadQuestionsBookmark(jsonObj) {
|
|||
}
|
||||
|
||||
async function loadCategory(subject) {
|
||||
if(subject != "") {
|
||||
if (subject != "") {
|
||||
const currentUser = authenticationService.currentUserValue;
|
||||
// console.log(subject);
|
||||
const requestOptions = {
|
||||
|
|
@ -3415,7 +3470,7 @@ async function loadCategory(subject) {
|
|||
}
|
||||
|
||||
try {
|
||||
const response= await fetch( `${checkRole()}/Subjects/` + subject + "/Categories", requestOptions )
|
||||
const response = await fetch(`${checkRole()}/Subjects/` + subject + "/Categories", requestOptions)
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (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;
|
||||
|
||||
|
|
@ -3549,7 +3604,7 @@ function draftQuestion(jsonObj) {
|
|||
"?module_id=" + jsonObj.module_id + "&module=" + jsonObj.module;
|
||||
}
|
||||
if (jsonObj.complexity !== undefined && jsonObj.complexity !== "") {
|
||||
queryStr !== ""? queryStr = queryStr + "&complexity=" + jsonObj.complexity
|
||||
queryStr !== "" ? queryStr = queryStr + "&complexity=" + jsonObj.complexity
|
||||
: queryStr = "?complexity=" + jsonObj.complexity;
|
||||
}
|
||||
if (queryStr !== "") {
|
||||
|
|
@ -3564,8 +3619,8 @@ 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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue