feat: Implement user messages inbox with message acknowledgment tracking and UI updates
This commit is contained in:
@@ -94,6 +94,7 @@
|
||||
</div>
|
||||
<div class="mt-2 d-flex flex-wrap gap-2 justify-content-md-end">
|
||||
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:collection_history' collection.pk %}">Open History</a>
|
||||
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:user_messages_inbox' %}">Global Inbox</a>
|
||||
</div>
|
||||
|
||||
{% if user_message_rows %}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{% extends 'atlas/exams.html' %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{{collection.name}}</h2>
|
||||
<div class="d-flex flex-wrap justify-content-between align-items-center gap-2 mb-3">
|
||||
<h2 class="mb-0">{{collection.name}}</h2>
|
||||
<a class="btn btn-sm btn-outline-secondary" href="{% url 'atlas:user_messages_inbox' %}">Global Messages Inbox</a>
|
||||
</div>
|
||||
|
||||
|
||||
{% if userexams %}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
{% extends 'atlas/exams.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex flex-wrap justify-content-between align-items-start gap-3 mb-4">
|
||||
<div>
|
||||
<h2 class="h4 mb-1">Messages Inbox</h2>
|
||||
<div class="text-muted small">All accessible conversation threads across collections.</div>
|
||||
</div>
|
||||
<div class="card border-secondary" style="min-width: 320px;">
|
||||
<div class="card-body py-2 px-3">
|
||||
<div class="small text-muted">Pending acknowledgements</div>
|
||||
<div class="fw-semibold {% if total_outstanding %}text-danger{% endif %}">
|
||||
{{ total_outstanding }} unacknowledged message{{ total_outstanding|pluralize }}
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
{% if show_all %}
|
||||
<a class="btn btn-sm btn-outline-primary" href="?">Show outstanding first</a>
|
||||
{% else %}
|
||||
<a class="btn btn-sm btn-primary" href="?show=all">Load full history</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if inbox_rows %}
|
||||
<div class="d-flex flex-column gap-3">
|
||||
{% for row in inbox_rows %}
|
||||
<section class="card {% if row.outstanding_count %}border-danger-subtle{% else %}border-secondary-subtle{% endif %}">
|
||||
<div class="card-header d-flex flex-wrap justify-content-between align-items-center gap-2">
|
||||
<div>
|
||||
<strong>{{ row.collection.name }}</strong>
|
||||
<span class="text-muted small ms-2">{{ row.target_label }}</span>
|
||||
{% if row.viewer_role == 'moderator' %}
|
||||
<span class="badge bg-dark ms-1">Supervisor</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary ms-1">Learner</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-2 align-items-center">
|
||||
{% if row.outstanding_count %}
|
||||
<span class="badge bg-danger">{{ row.outstanding_count }} unacknowledged</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">No outstanding</span>
|
||||
{% endif %}
|
||||
<a class="btn btn-sm btn-outline-secondary" href="{{ row.detail_url }}">Open user message page</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
{% if row.outstanding_rows %}
|
||||
<div class="mb-3">
|
||||
<div class="small fw-semibold mb-2">Outstanding</div>
|
||||
<div class="d-flex flex-column gap-2">
|
||||
{% for case_row in row.outstanding_rows %}
|
||||
<details open>
|
||||
<summary class="small fw-semibold d-flex flex-wrap align-items-center gap-2">
|
||||
<span>Case {{ case_row.casedetail.sort_order|add:1 }}</span>
|
||||
{% if row.collection.show_title_post %}
|
||||
<span class="text-muted">{{ case_row.casedetail.case.title|default:case_row.casedetail.case.pk|truncatechars:90 }}</span>
|
||||
{% endif %}
|
||||
<span class="badge bg-danger">{{ case_row.stats.outstanding_total_count }} unacknowledged</span>
|
||||
</summary>
|
||||
<div class="mt-2"
|
||||
hx-get="{{ case_row.thread_url }}{% if case_row.cid %}?cid={{ case_row.cid }}{% endif %}"
|
||||
hx-trigger="load"
|
||||
hx-target="this"
|
||||
hx-swap="innerHTML">
|
||||
<div class="small text-muted">Loading conversation...</div>
|
||||
</div>
|
||||
</details>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if show_all and row.history_rows %}
|
||||
<div>
|
||||
<div class="small fw-semibold mb-2">History</div>
|
||||
<div class="accordion" id="history-{{ row.attempt.id }}">
|
||||
{% for case_row in row.history_rows %}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="history-heading-{{ row.attempt.id }}-{{ case_row.casedetail.case.id }}">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#history-collapse-{{ row.attempt.id }}-{{ case_row.casedetail.case.id }}" aria-expanded="false" aria-controls="history-collapse-{{ row.attempt.id }}-{{ case_row.casedetail.case.id }}">
|
||||
Case {{ case_row.casedetail.sort_order|add:1 }}
|
||||
{% if row.collection.show_title_post %}
|
||||
: {{ case_row.casedetail.case.title|default:case_row.casedetail.case.pk|truncatechars:90 }}
|
||||
{% endif %}
|
||||
<span class="badge bg-secondary ms-2">{{ case_row.stats.message_count }} messages</span>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="history-collapse-{{ row.attempt.id }}-{{ case_row.casedetail.case.id }}" class="accordion-collapse collapse" aria-labelledby="history-heading-{{ row.attempt.id }}-{{ case_row.casedetail.case.id }}" data-bs-parent="#history-{{ row.attempt.id }}">
|
||||
<div class="accordion-body pt-0">
|
||||
<div hx-get="{{ case_row.thread_url }}{% if case_row.cid %}?cid={{ case_row.cid }}{% endif %}"
|
||||
hx-trigger="revealed once"
|
||||
hx-target="this"
|
||||
hx-swap="innerHTML">
|
||||
<div class="small text-muted">Open section to load conversation history...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="card border-secondary">
|
||||
<div class="card-body text-muted small">No message threads available for your account.</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user