From cb84b434d36a7e2ab29c5a91e488b5e87fa1ebd1 Mon Sep 17 00:00:00 2001 From: Paul Smith <3070332s@student.gla.ac.uk> Date: Mon, 24 Mar 2025 15:51:05 +0000 Subject: [PATCH] Updated Quiz Take Quiz & Results Formats --- .../templates/flashcard/quiz_results.html | 141 ++++++++---------- flashcard/templates/flashcard/quiz_take.html | 126 ++++++++-------- flashcard/views.py | 8 +- 3 files changed, 132 insertions(+), 143 deletions(-) diff --git a/flashcard/templates/flashcard/quiz_results.html b/flashcard/templates/flashcard/quiz_results.html index feebaaf..1086891 100644 --- a/flashcard/templates/flashcard/quiz_results.html +++ b/flashcard/templates/flashcard/quiz_results.html @@ -1,91 +1,82 @@ <!-- flashcard/quiz_results.html --> -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Quiz Results - {{ quiz_attempt.quiz.deck.name }}</title> - <style> - body { font-family: Arial, sans-serif; margin: 20px; } - h1, h2 { color: #333; } - .question { border: 1px solid #ddd; padding: 15px; margin-bottom: 15px; border-radius: 4px; } - .correct { color: green; font-weight: bold; } - .incorrect { color: red; font-weight: bold; } - .message { padding: 10px; margin-bottom: 10px; border-radius: 4px; } - .success { background-color: #d4edda; color: #155724; } - .error { background-color: #f8d7da; color: #721c24; } - .score { margin-bottom: 20px; } - button { padding: 10px 20px; background-color: #007BFF; color: white; border: none; border-radius: 4px; cursor: pointer; } - button:hover { background-color: #0056b3; } - </style> -</head> -<body> - <h1>Quiz Results: {{ quiz_attempt.quiz.deck.name }}</h1> - +{% extends 'base.html' %} +{% load static %} + +{% block title %}Quiz Results - {{ quiz_attempt.quiz.deck.name }}{% endblock %} + +{% block content %} + <h1 class="mb-3">Quiz Results: {{ quiz_attempt.quiz.deck.name }}</h1> + {% if messages %} {% for message in messages %} - <div class="message {% if message.tags %}{{ message.tags }}{% endif %}"> + <div class="alert alert-{{ message.tags }} mb-3" role="alert"> {{ message }} </div> {% endfor %} {% endif %} - <div class="score"> - <p><strong>Score:</strong> {{ correct_answers }} / {{ total_questions }} ({{ score_percentage|floatformat:2 }}%)</p> + <div class="card mb-4"> + <div class="card-body"> + <h2 class="card-title">Score</h2> + <p><strong>Score:</strong> {{ correct_answers }} / {{ total_questions }} ({{ score_percentage|floatformat:2 }}%)</p> + </div> </div> - <h2>Your Answers</h2> + <h2 class="mb-3">Your Answers</h2> {% for item in question_attempts %} {% with attempt=item.attempt correct_answer=item.correct_answer %} - <div class="question"> - <p>{{ attempt.question.text }}</p> - {% if attempt.question.question_type == 1 %} - <!-- Multiple Choice --> - <p><strong>Your Answer:</strong> - {% if attempt.choice %} - {{ attempt.choice.text }} - <span class="{% if attempt.is_correct %}correct{% else %}incorrect{% endif %}"> - ({{ attempt.is_correct|yesno:"Correct,Incorrect" }}) - </span> - {% else %} - Not answered <span class="incorrect">(Incorrect)</span> - {% endif %} - </p> - <p><strong>Correct Answer:</strong> {{ correct_answer }}</p> - {% elif attempt.question.question_type == 2 %} - <!-- True/False --> - <p><strong>Your Answer:</strong> - {% if attempt.answer %} - {{ attempt.answer }} - <span class="{% if attempt.is_correct %}correct{% else %}incorrect{% endif %}"> - ({{ attempt.is_correct|yesno:"Correct,Incorrect" }}) - </span> - {% else %} - Not answered <span class="incorrect">(Incorrect)</span> - {% endif %} - </p> - <p><strong>Correct Answer:</strong> {{ correct_answer }}</p> - {% elif attempt.question.question_type == 3 %} - <!-- Short Answer --> - <p><strong>Your Answer:</strong> - {% if attempt.answer %} - {{ attempt.answer }} - <span class="{% if attempt.is_correct %}correct{% else %}incorrect{% endif %}"> - ({{ attempt.is_correct|yesno:"Correct,Incorrect" }}) - </span> - {% else %} - Not answered <span class="incorrect">(Incorrect)</span> - {% endif %} - </p> - <p><strong>Correct Answer:</strong> {{ correct_answer }}</p> - {% endif %} + <div class="card mb-3"> + <div class="card-body"> + <p class="card-text">{{ attempt.question.text }}</p> + {% if attempt.question.question_type == 1 %} + <!-- Multiple Choice --> + <p><strong>Your Answer:</strong> + {% if attempt.choice %} + {{ attempt.choice.text }} + <span class="badge {% if attempt.is_correct %}bg-success{% else %}bg-danger{% endif %}"> + {{ attempt.is_correct|yesno:"Correct,Incorrect" }} + </span> + {% else %} + Not answered <span class="badge bg-danger">Incorrect</span> + {% endif %} + </p> + <p><strong>Correct Answer:</strong> {{ correct_answer }}</p> + {% elif attempt.question.question_type == 2 %} + <!-- True/False --> + <p><strong>Your Answer:</strong> + {% if attempt.answer %} + {{ attempt.answer }} + <span class="badge {% if attempt.is_correct %}bg-success{% else %}bg-danger{% endif %}"> + {{ attempt.is_correct|yesno:"Correct,Incorrect" }} + </span> + {% else %} + Not answered <span class="badge bg-danger">Incorrect</span> + {% endif %} + </p> + <p><strong>Correct Answer:</strong> {{ correct_answer }}</p> + {% elif attempt.question.question_type == 3 %} + <!-- Short Answer --> + <p><strong>Your Answer:</strong> + {% if attempt.answer %} + {{ attempt.answer }} + <span class="badge {% if attempt.is_correct %}bg-success{% else %}bg-danger{% endif %}"> + {{ attempt.is_correct|yesno:"Correct,Incorrect" }} + </span> + {% else %} + Not answered <span class="badge bg-danger">Incorrect</span> + {% endif %} + </p> + <p><strong>Correct Answer:</strong> {{ correct_answer }}</p> + {% endif %} + </div> </div> {% endwith %} {% endfor %} - <p><a href="{% url 'deck_detail' pk=quiz_attempt.quiz.deck.pk %}">Back to Deck Details</a></p> - <form method="get" action="{% url 'start_quiz' quiz_id=quiz_attempt.quiz.id %}"> - <button type="submit">Retake Quiz</button> - </form> -</body> -</html> \ No newline at end of file + <div class="d-flex justify-content-between"> + <a href="{% url 'deck_detail' pk=quiz_attempt.quiz.deck.pk %}" class="btn btn-primary">Back to Deck Details</a> + <form method="get" action="{% url 'start_quiz' quiz_id=quiz_attempt.quiz.id %}" class="d-inline"> + <button type="submit" class="btn btn-success">Retake Quiz</button> + </form> + </div> +{% endblock %} \ No newline at end of file diff --git a/flashcard/templates/flashcard/quiz_take.html b/flashcard/templates/flashcard/quiz_take.html index 91715c1..8d2ef75 100644 --- a/flashcard/templates/flashcard/quiz_take.html +++ b/flashcard/templates/flashcard/quiz_take.html @@ -1,91 +1,83 @@ <!-- flashcard/quiz_take.html --> -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Taking Quiz - {{ quiz_attempt.quiz.deck.name }}</title> - <style> - body { font-family: Arial, sans-serif; margin: 20px; } - h1, h2 { color: #333; } - .question { border: 1px solid #ddd; padding: 15px; margin-bottom: 15px; border-radius: 4px; } - .message { padding: 10px; margin-bottom: 10px; border-radius: 4px; } - .success { background-color: #d4edda; color: #155724; } - .error { background-color: #f8d7da; color: #721c24; } - button { padding: 10px 20px; background-color: #007BFF; color: white; border: none; border-radius: 4px; cursor: pointer; margin: 5px; } - button:hover { background-color: #0056b3; } - button:disabled { background-color: #ccc; cursor: not-allowed; } - input[type="radio"], input[type="text"], select { margin: 5px 0; } - .progress { margin-bottom: 20px; } - .question-list { margin-bottom: 20px; } - .question-list a { margin-right: 10px; text-decoration: none; } - .answered { color: black; } - .unanswered { color: gray; } - </style> -</head> -<body> - <h1>Taking Quiz: {{ quiz_attempt.quiz.deck.name }}</h1> - +{% extends 'base.html' %} +{% load static %} + +{% block title %}Taking Quiz - {{ quiz_attempt.quiz.deck.name }}{% endblock %} + +{% block content %} + <h1 class="mb-3">Taking Quiz: {{ quiz_attempt.quiz.deck.name }}</h1> + {% if messages %} {% for message in messages %} - <div class="message {% if message.tags %}{{ message.tags }}{% endif %}"> + <div class="alert alert-{{ message.tags }} mb-3" role="alert"> {{ message }} </div> {% endfor %} {% endif %} - <div class="progress"> - <p>Question {{ question_index|add:1 }} of {{ total_questions }}</p> + <div class="progress mb-3"> + <div class="progress-bar" role="progressbar" + style="width: {{ progress_percentage }}%;" + aria-valuenow="{{ question_index|add:1 }}" + aria-valuemin="1" + aria-valuemax="{{ total_questions }}"> + Question {{ question_index|add:1 }} of {{ total_questions }} + </div> </div> - <div class="question-list"> + <div class="question-list mb-4"> {% for qa in question_attempts %} <a href="{% url 'take_quiz' attempt_id=quiz_attempt.id question_index=forloop.counter0 %}" - class="{% if qa.answer or qa.choice %}answered{% else %}unanswered{% endif %}"> + class="btn btn-sm {% if qa.answer or qa.choice %}btn-dark{% else %}btn-outline-secondary{% endif %} me-2"> {{ forloop.counter }} </a> {% endfor %} </div> {% if question_attempt %} - <div class="question"> - <h2>{{ question_attempt.question.text }}</h2> - <form method="post" action="{% url 'take_quiz' attempt_id=quiz_attempt.id question_index=question_index %}"> - {% csrf_token %} - <input type="hidden" name="question_index" value="{{ question_index }}"> - - {% if question_attempt.question.question_type == 1 %} - <p>Select one option:</p> - {% for choice in choices %} + <div class="card"> + <div class="card-body"> + <h2 class="card-title">{{ question_attempt.question.text }}</h2> + <form method="post" action="{% url 'take_quiz' attempt_id=quiz_attempt.id question_index=question_index %}"> + {% csrf_token %} + <input type="hidden" name="question_index" value="{{ question_index }}"> + + {% if question_attempt.question.question_type == 1 %} + <p class="mb-2">Select one option:</p> + <div class="list-group mb-3"> + {% for choice in choices %} + <label class="list-group-item"> + <input type="radio" name="choice" value="{{ choice.id }}" id="choice_{{ choice.id }}" + {% if question_attempt.choice.id == choice.id %}checked{% endif %}> + {{ choice.text }} + </label> + {% endfor %} + </div> + {% elif question_attempt.question.question_type == 2 %} + <p class="mb-2">Select True or False:</p> + <select name="answer" class="form-select mb-3"> + <option value="">-- Select an answer --</option> + <option value="True" {% if question_attempt.answer == "True" %}selected{% endif %}>True</option> + <option value="False" {% if question_attempt.answer == "False" %}selected{% endif %}>False</option> + </select> + {% elif question_attempt.question.question_type == 3 %} + <p class="mb-2">Your answer:</p> + <input type="text" name="answer" value="{{ question_attempt.answer|default:'' }}" class="form-control mb-3"> + {% endif %} + + <div class="d-flex justify-content-between"> + <button type="submit" name="previous" class="btn btn-outline-secondary" {% if prev_index is none %}disabled{% endif %}>Previous</button> <div> - <input type="radio" name="choice" value="{{ choice.id }}" id="choice_{{ choice.id }}" - {% if question_attempt.choice.id == choice.id %}checked{% endif %}> - <label for="choice_{{ choice.id }}">{{ choice.text }}</label> + <button type="submit" name="next" class="btn btn-primary me-2" {% if next_index is none %}disabled{% endif %}>Next</button> + <button type="submit" name="complete_quiz" class="btn btn-success">Complete Quiz</button> </div> - {% endfor %} - {% elif question_attempt.question.question_type == 2 %} - <p>Select True or False:</p> - <select name="answer"> - <option value="">-- Select an answer --</option> - <option value="True" {% if question_attempt.answer == "True" %}selected{% endif %}>True</option> - <option value="False" {% if question_attempt.answer == "False" %}selected{% endif %}>False</option> - </select> - {% elif question_attempt.question.question_type == 3 %} - <p>Your answer:</p> - <input type="text" name="answer" value="{{ question_attempt.answer|default:'' }}"> - {% endif %} - - <div> - <button type="submit" name="previous" {% if prev_index is none %}disabled{% endif %}>Previous</button> - <button type="submit" name="next" {% if next_index is none %}disabled{% endif %}>Next</button> - <button type="submit" name="complete_quiz">Complete Quiz</button> - </div> - </form> + </div> + </form> + </div> </div> {% else %} - <p>No questions available for this quiz.</p> + <p class="text-muted">No questions available for this quiz.</p> {% endif %} - <p><a href="{% url 'deck_detail' pk=quiz_attempt.quiz.deck.pk %}">Abandon Quiz and Return to Deck</a></p> -</body> -</html> \ No newline at end of file + <p class="mt-3"><a href="{% url 'deck_detail' pk=quiz_attempt.quiz.deck.pk %}" class="btn btn-warning">Abandon Quiz and Return to Deck</a></p> +{% endblock %} \ No newline at end of file diff --git a/flashcard/views.py b/flashcard/views.py index 5217c7d..c06aec1 100644 --- a/flashcard/views.py +++ b/flashcard/views.py @@ -337,14 +337,20 @@ class TakeQuizView(LoginRequiredMixin, View): current_question_attempt = question_attempts[question_index] choices = Choice.objects.filter(question=current_question_attempt.question) if current_question_attempt.question.question_type == 1 else [] + # Calculate progress percentage + total_questions = question_attempts.count() + progress_percentage = ((question_index + 1) / total_questions * 100) if total_questions > 0 else 0 + logger.info(f"Attempt ID: {attempt_id}, Question Index: {question_index}, Total Questions: {total_questions}, Progress: {progress_percentage}%") + return render(request, self.template_name, { 'quiz_attempt': quiz_attempt, 'question_attempt': current_question_attempt, 'choices': choices, 'question_index': question_index, - 'total_questions': question_attempts.count(), + 'total_questions': total_questions, 'prev_index': question_index - 1 if question_index > 0 else None, 'next_index': question_index + 1 if question_index < question_attempts.count() - 1 else None, + 'progress_percentage': progress_percentage, 'question_attempts': question_attempts, }) -- GitLab