Refactor user collections view to categorize collections into available, in-progress, and finished; update templates for improved display of collection statuses and question rendering.

This commit is contained in:
Ross
2025-10-06 13:51:55 +01:00
parent 569ef760fa
commit 682e8160b5
8 changed files with 250 additions and 47 deletions
@@ -416,6 +416,13 @@
</ul>
</p>
{% if casedetail %}
{% include 'atlas/partials/collection_question_block.html' with case_detail=casedetail can_edit=can_edit %}
{% endif %}
<p class="pre-whitespace"><b>Previous case:</b> {{ case.previous_case.get_link }}</p>
@@ -158,35 +158,7 @@
{% if collection.collection_type == "QUE" %}
{% if question_completed %}
<h3>Answers</h3>
<div class="answer-block">
{% for value, user_answer, correct_answer, answer_is_correct, automark in answer.get_correct_json_answers %}
<div class="{% if answer_is_correct %}
correct
{% else %}
incorrect
{% endif %}
{% if automark %}
automark
{% endif %}
">
<h4>{{value.title}}</h4>
{{value.description}}
<div
>
Answer : {{user_answer}}
{% if not answer_is_correct %}
<br/>Correct answer: {{correct_answer}}
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% include "atlas/partials/collection_question_answer_block.html" %}
{% if collection.self_review %}
<div>
@@ -67,6 +67,10 @@
{% endfor %}
</details>
</div>
{# Hidden per-case question snippet to inject when case is loaded #}
<div class="question-block-snippet" style="display:none;">
{% include 'atlas/partials/collection_question_block.html' with case_detail=casedetail %}
</div>
{% if case.display_sets.all %}
<details class="displayset-detail"><summary>Display Sets:</summary>
{% for ds in case.display_sets.all %}
@@ -116,6 +120,7 @@
<div id="current-case-history"></div>
<div id="current-case-discussion"></div>
<div id="current-case-report"></div>
<div id="current-case-questions" class="mt-3"></div>
</div>
</div>
</div>
@@ -221,6 +226,14 @@
"viewerstate": viewerstate
});
// Inject the per-case question snippet into the current case panel
try {
var snippet = $(c).find('.question-block-snippet').html();
$('#current-case-questions').html(snippet || '');
} catch (e) {
console.warn('Unable to inject question snippet', e);
}
});
$('.open-displayset').click(function() {
let c = this;
@@ -242,6 +255,15 @@
"annotations": annotations
});
// Inject the per-case question snippet
try {
var caseItem = $(this).closest('.case-item');
var snippet = caseItem.find('.question-block-snippet').html();
$('#current-case-questions').html(snippet || '');
} catch (e) {
console.warn('Unable to inject question snippet for displayset', e);
}
});
$('.open-series-local').click(function() {
let c = $(this).closest(".case-item")[0];
@@ -264,6 +286,14 @@
"series": seriesPk,
"images": JSON.stringify(images),
});
// Inject the per-case question snippet
try {
var snippet = $(c).find('.question-block-snippet').html();
$('#current-case-questions').html(snippet || '');
} catch (e) {
console.warn('Unable to inject question snippet for series', e);
}
});
$('.open-case, .open-series').click(function() {
var url = $(this).data('target');
@@ -289,6 +319,14 @@
$('#current-case-series').html("<span class='title'>Series:</span> " + $(this).data('series'));
}
bc.postMessage({"type": "open", "url" : url});
// Inject question snippet for this case
try {
var caseItem = $(this).closest('.case-item');
var snippet = caseItem.find('.question-block-snippet').html();
$('#current-case-questions').html(snippet || '');
} catch (e) {
console.warn('Unable to inject question snippet', e);
}
//if (win2 == false || win2.closed) {
// win2 = openSecondaryWindow(url);
// console.log('opened', win2)
@@ -0,0 +1,27 @@
<div class="answer-block">
{% for value, user_answer, correct_answer, answer_is_correct, automark in answer.get_correct_json_answers %}
<div class="{% if answer_is_correct %}
correct
{% else %}
incorrect
{% endif %}
{% if automark %}
automark
{% endif %}
">
<h4>{{value.title}}</h4>
{{value.description}}
<div
>
Answer : {{user_answer}}
{% if not answer_is_correct %}
<br/>Correct answer: {{correct_answer}}
{% endif %}
</div>
</div>
{% endfor %}
</div>
@@ -0,0 +1,63 @@
{# Partial: render questions and answers as HTML. #}
{% if case_detail.question_schema %}
<div class="collection-question-block">
<h4>Questions</h4>
<dl class="row">
{% for name, prop in case_detail.question_schema.properties.items %}
<dt class="col-sm-4">{{ prop.title|default:name }}</dt>
<dd class="col-sm-8">
{% if prop.description %}
<div class="mb-1 text-muted small">{{ prop.description }}</div>
{% endif %}
{% if prop.type == "string" and prop.enum %}
<div class="mt-1 small text-muted">Options: {{ prop.enum|join:", " }}</div>
{% else %}
<div class="mt-1 small text-muted">Type: {{ prop.type }}</div>
{% endif %}
{# Safely fetch the stored/example answer using the project's `get_item` filter. #}
{% if case_detail.question_answers %}
{% with correct=case_detail.question_answers|get_item:name %}
<div class="mt-2">
<strong>Example / Correct:</strong>
{% if correct %}
<span class="ms-2">{{ correct }}</span>
{% else %}
<span class="text-muted ms-2">(no answer provided)</span>
{% endif %}
</div>
{% endwith %}
{% else %}
<div class="mt-2"><strong>Example / Correct:</strong> <span class="text-muted ms-2">(no answer provided)</span></div>
{% endif %}
{# Optionally render and compare a user's answer passed as `user_answer` in the context #}
{% if user_answer %}
{% if user_answer|get_item:name %}
{% with ua=user_answer|get_item:name %}
{% with correct=case_detail.question_answers|get_item:name %}
<div class="mt-1">
<strong>Your answer:</strong>
<span class="ms-2 {% if ua == correct %}text-success{% else %}text-danger{% endif %}">{{ ua }}</span>
{% if ua == correct %}
<span class="badge bg-success ms-2">Correct</span>
{% else %}
<span class="badge bg-danger ms-2">Incorrect</span>
{% endif %}
</div>
{% endwith %}
{% endwith %}
{% else %}
<div class="mt-1"><strong>Your answer:</strong> <span class="text-muted ms-2">(no answer)</span></div>
{% endif %}
{% endif %}
</dd>
{% endfor %}
</dl>
</div>
{% else %}
<div class="collection-question-block text-muted">No questions defined for this case.</div>
{% endif %}
+45 -10
View File
@@ -1,18 +1,53 @@
{% extends 'atlas/base.html' %}
{% block content %}
<h2>Collections</h2>
<h2>Collections</h2>
The following collections are available for you to view / take.
The following collections are available for you to view / take. If you received a directly link to a collection it will not appear here unless you have started it.
<h3>Available to start</h3>
<ul>
{% for collection in collections %}
<li>
<a href="{% url 'atlas:collection_take_start' collection.pk %}">{{collection}} {{collelction.is_complete}}</a>
</li>
{% endfor %}
{% for collection in available_collections %}
<li>
<a href="{% url 'atlas:collection_take_start' collection.pk %}">{{ collection.name }}</a>
{% if collection.description %}
<small class="text-muted">— {{ collection.description }}</small>
{% endif %}
</li>
{% empty %}
<li>No collections available to start.</li>
{% endfor %}
</ul>
<h3>In progress</h3>
<ul>
{% for collection in in_progress_collections %}
<li>
<a href="{% url 'atlas:collection_take_start' collection.pk %}">{{ collection.name }}</a>
<span class="badge bg-warning text-dark">In progress</span>
{% if collection.description %}
<small class="text-muted">— {{ collection.description }}</small>
{% endif %}
</li>
{% empty %}
<li>No in-progress collections.</li>
{% endfor %}
</ul>
<h3>Finished</h3>
<ul>
{% for collection in finished_collections %}
<li>
<a href="{% url 'atlas:collection_take_start' collection.pk %}">{{ collection.name }}</a>
<span class="badge bg-success">Completed</span>
{% if collection.description %}
<small class="text-muted">— {{ collection.description }}</small>
{% endif %}
</li>
{% empty %}
<li>No finished collections.</li>
{% endfor %}
</ul>
{% endblock %}