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