-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement basic features trainings for the user
This commit allows users to take the test from settings. The quiz.html file loads all the content and questions for a module based on the order. All the data is hidden from user and gradually displayed as users go through the training We have two level of verifications of answers. the first one is done on quiz.html 1. When users go through the content and they will see the related questions and answer the questions. Users can go to next section or skip the question only if they have answered the question correctly previously. 2. We also have another verification done on view. Here if the users had correctly answered the questions a json string is generated at the end of module and sent via POST, we will then check the database to verify that the data in json string(question,answer) and match it with the database. This should help us stop someone from just sending a post request to complete the training. How the resume works? 1. When users go through the training module, we will track the contents, quiz that they have completed and store it in the database. 2. If the user clicks Next after completing a section or quiz, we will check if it was completed in previous session, 1. If not we will send a post request to the server to update the database, and then load the next section or quiz. 2. If yes we will just load the next section or quiz. 3. One the user reaches the end of the module, we will send submit the form and the server will check if the user has completed all the sections and quizzes. If yes, we will update the database and redirect the user to the training dashboard. Quick note: 1. Only multiple choice questions is supported yet.
- Loading branch information
1 parent
f2e16c1
commit 7409f5b
Showing
5 changed files
with
399 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
.eachQuiz{ | ||
display: none | ||
} | ||
|
||
.quizContainer { | ||
max-width: 100%; | ||
position: relative; | ||
margin: auto; | ||
display: block; | ||
} | ||
|
||
.alert { | ||
display: none | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
|
||
|
||
function changeSlide(n) { | ||
showSlide(slideIndex += n); | ||
} | ||
|
||
$('.next').on('click', function () { | ||
// move to next slide but keep track of start of partaining training | ||
|
||
// when next is clicked, update the progress of the user(for content and quiz) only if the content or quiz was not completed before | ||
if($(this).hasClass('completed') == false){ | ||
$(this).addClass('disabled'); | ||
const url = document.querySelector('input[name="data-update-url"]').value; | ||
const update_type = $(this).attr('data-update-type'); | ||
const update_type_id = $(this).attr('data-update-type-id'); | ||
const csrf_token = $(this).find('input[name="csrfmiddlewaretoken"]').val(); | ||
const module_id = document.querySelector('input[name="data-module-id"]').value; | ||
const training_id = document.querySelector('input[name="data-training-id"]').value; | ||
|
||
const data = { | ||
'update_type': update_type, | ||
'update_type_id': parseInt(update_type_id), | ||
'module_id': parseInt(module_id), | ||
'training_id': parseInt(training_id), | ||
} | ||
const $btn = $(this); | ||
$.ajax({ | ||
url: url, | ||
type: 'POST', | ||
data: data, | ||
headers: { | ||
'X-CSRFToken': csrf_token | ||
}, | ||
success: function (data) { | ||
console.log(data); | ||
$btn.addClass('completed'); | ||
console.log('ajax done'); | ||
let slidePosition = parseInt(sessionStorage.getItem("slidePosition")); | ||
sessionStorage.setItem("slidePosition", slidePosition - 1) | ||
changeSlide(1); | ||
}, | ||
error: function (data) { | ||
console.log(data); | ||
alertBox("<strong>Oops!</strong> Something went wrong, kindly try again.", "danger") | ||
} | ||
}); | ||
$(this).removeClass('disabled'); | ||
} | ||
else{ | ||
let slidePosition = parseInt(sessionStorage.getItem("slidePosition")); | ||
sessionStorage.setItem("slidePosition", slidePosition - 1) | ||
changeSlide(1); | ||
} | ||
}) | ||
|
||
$('.previous').on('click', function () { | ||
// move to next slide but keep track of start of partaining training | ||
let slidePosition = parseInt(sessionStorage.getItem("slidePosition")); | ||
sessionStorage.setItem("slidePosition", slidePosition - 2); | ||
changeSlide(-1); | ||
}) | ||
|
||
function showSlide(n) { | ||
|
||
let i; | ||
let slides = document.getElementsByClassName("eachQuiz"); | ||
if (n > slides.length) { | ||
alertBox("<strong>Congratulations</strong> You have come to the end of this module."); | ||
sessionStorage.clear(); | ||
|
||
let question_answers = {}; | ||
document.querySelectorAll('.question input[type="radio"]:checked').forEach(function (eachQuiz) { | ||
let question_id = eachQuiz.getAttribute("name"); | ||
let value = eachQuiz.value; | ||
question_answers[question_id] = parseInt(value); | ||
}); | ||
|
||
$('[name="question_answers"]').val(JSON.stringify(question_answers)); | ||
|
||
$('form').submit(); | ||
} | ||
if (n < 1) { slideIndex = slides.length } | ||
for (i = 0; i < slides.length; i++) { | ||
slides[i].style.display = "none"; | ||
} | ||
|
||
slides[slideIndex - 1].style.display = "block"; | ||
} | ||
// | ||
// $("input[type=radio]").on("click", function () { | ||
// // check if answer is correct and proceed, else take back to training | ||
// let id = $(this).attr("name") | ||
// let value = $(this).val(); | ||
// var slidePosition = parseInt(sessionStorage.getItem("slidePosition")) | ||
// | ||
// sessionStorage.setItem("slidePosition", 0) | ||
// | ||
// if (sessionStorage.getItem(id) == value) { | ||
// alertBox("<strong>Yay!</strong> You chose the correct answer.", "success") | ||
// changeSlide(1) | ||
// } else { | ||
// alertBox("<strong>Oops!</strong> You chose a wrong answer, kindly go through the training again.", "danger") | ||
// changeSlide(slidePosition) | ||
// } | ||
// }) | ||
|
||
$('.checkAnswer').on('click', function () { | ||
|
||
let question_id = $('input[type="radio"]:checked', $(this).parent()).attr("name"); | ||
if (question_id == undefined) { | ||
alertBox("<strong>Oops!</strong> You did not choose an answer, kindly choose an answer.", "danger"); | ||
return | ||
} | ||
let value = $('input[type="radio"]:checked', $(this).parent()).val(); | ||
// let slidePosition = parseInt(sessionStorage.getItem("slidePosition")); | ||
|
||
sessionStorage.setItem("slidePosition", 0); | ||
|
||
if (sessionStorage.getItem(question_id) == value) { | ||
alertBox("<strong>Yay!</strong> You chose the correct answer.", "success"); | ||
$('.next', $(this).parent().parent()).removeClass('disabled'); | ||
// changeSlide(1); | ||
} else { | ||
alertBox("<strong>Oops!</strong> You chose a wrong answer, kindly go through the previous sections again.", "danger"); | ||
// changeSlide(slidePosition); | ||
$('.next', $(this).parent().parent()).addClass('disabled'); | ||
} | ||
}); | ||
|
||
function alertBox(message, _class) { | ||
let alert = document.getElementById("alert"); | ||
alert.className = "alert alert-" + _class; | ||
alert.innerHTML = message; | ||
alert.style.display = "block"; | ||
setTimeout(function () { | ||
alert.style.display = "none"; | ||
}, 3000); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
{% extends "base.html" %} | ||
{% load static %} | ||
{% load physionet_templatetags %} | ||
{% block title %}{{ training.training_type.name }}{% endblock %} | ||
{% block local_css %} | ||
<link rel="stylesheet" | ||
type="text/css" | ||
href="{% static 'custom/css/quiz.css' %}"> | ||
{% endblock %} | ||
{% block content %} | ||
<div class="container my-3"> | ||
<div class="quizContainer"> | ||
<div class="quizHeader"> | ||
<h1><a href="{% url 'platform_training' training.training_type.id %}">{{ training.training_type.name }}</a></h1> | ||
</div> | ||
<hr> | ||
<h2>{{ module.name }}</h2> | ||
|
||
<form method="POST" class="training"> | ||
{% csrf_token %} | ||
<input type="text" hidden name="resume-from" value="{{ resume_content_or_quiz_from }}"/> | ||
<input type="text" hidden name="question_answers" value=""/> | ||
<input type="text" hidden name="data-update-url" value="{% url 'update_module_progress' %}"/> | ||
<input type="text" hidden name="data-module-id" value="{{ module.id }}"/> | ||
<input type="text" hidden name="data-training-id" value="{{ training.id }}"/> | ||
{% for item in quiz_content %} | ||
{% if item.body %} | ||
<div class="eachQuiz"> | ||
<div>{{ item.body | safe }}</div> | ||
<div class="row ml-1"> | ||
{% if forloop.counter != 1 %}<a class="btn btn-warning previous">Back</a>{% endif %} | ||
<a class="btn btn-success next text-white ml-auto mr-3 {% if item.id in completed_contents_ids %}completed{% endif %}" data-update-type="content" data-update-type-id="{{ item.id }}"> | ||
{% if forloop.last %} | ||
Submit Module | ||
{% else %} | ||
Next | ||
{% endif %} | ||
{% csrf_token %} | ||
</a> | ||
</div> | ||
</div> | ||
{% else %} | ||
<div class="eachQuiz question"> | ||
<div class="list-group"> | ||
<div class="list-group-item py-4">{{ item.question | safe }}</div> | ||
{% for choice in item.choices.all %} | ||
<label | ||
class="list-group-item list-group-item-action q_{{ item.id }} {{ item.id }}_{{ choice.id }} mb-0" | ||
for="{{ item.id }}_{{ choice.id }}"> | ||
<input type="radio" | ||
id="{{ item.id }}_{{ choice.id }}" | ||
name="{{ item.id }}" | ||
value="{{ choice.id }}"> | ||
{{ choice.body | safe }} | ||
</label> | ||
{# add a check answer button #} | ||
{% endfor %} | ||
<a type="button" | ||
class="btn btn-secondary text-white checkAnswer" | ||
data-question="{{ item.id }}" | ||
data-answer="{{ item.answer.id }}">Check Answer</a> | ||
</div> | ||
<br> | ||
<div class="row ml-1"> | ||
{% if forloop.counter != 1 %}<a class="btn btn-warning previous">Back</a>{% endif %} | ||
<a class="btn btn-success next text-white ml-auto mr-3 {% if item.id in completed_quizzes_ids %}completed{% else %}disabled{% endif %}" data-update-type="quiz" data-update-type-id="{{ item.id }}"> | ||
{% if forloop.last %} | ||
Submit Module | ||
{% else %} | ||
Next | ||
{% endif %} | ||
{% csrf_token %} | ||
</a> | ||
</div> | ||
</div> | ||
{% endif %} | ||
{% endfor %} | ||
</form> | ||
</div> | ||
<br> | ||
<div id="alert" class="alert" role="alert"></div> | ||
</div> | ||
{% endblock %} | ||
{% block local_js_bottom %} | ||
{% for quiz, answer in quiz_answer %} | ||
<script> | ||
sessionStorage.setItem({{quiz }}, {{answer }}); | ||
{% if quiz in completed_quizzes_ids %} | ||
document.querySelector("input[type='radio'][id='{{ quiz }}_{{ answer }}']").checked = true; | ||
{% endif %} | ||
</script> | ||
{% endfor %} | ||
<script src="{% static 'custom/js/quiz.js' %}"></script> | ||
<script> | ||
sessionStorage.setItem("slidePosition", 0); | ||
var slideIndex = parseInt(document.querySelector("input[name='resume-from']").value) || 0; | ||
showSlide(slideIndex); | ||
</script> | ||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.