148 lines
6.8 KiB
HTML
148 lines
6.8 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{{ ticket.ticket_number }} · RelayDesk{% endblock %}
|
|
{% block meta_description %}Threaded replies and status tracking for {{ ticket.ticket_number }}.{% endblock %}
|
|
|
|
{% block content %}
|
|
<section class="page-hero py-5">
|
|
<div class="container">
|
|
<div class="row align-items-start g-4">
|
|
<div class="col-lg-8">
|
|
<div class="d-flex flex-wrap align-items-center gap-2 mb-3">
|
|
<span class="eyebrow">{{ ticket.ticket_number }}</span>
|
|
<span class="status-badge status-{{ ticket.status }}">{{ ticket.get_status_display }}</span>
|
|
<span class="priority-pill priority-{{ ticket.priority }}">{{ ticket.get_priority_display }}</span>
|
|
</div>
|
|
<h1 class="display-6 fw-bold">{{ ticket.subject }}</h1>
|
|
<p class="lead text-muted mb-0">Submitted by {{ ticket.requester_name }} in {{ ticket.get_category_display }} · Updated {{ ticket.updated_at|timesince }} ago</p>
|
|
</div>
|
|
<div class="col-lg-4 text-lg-end">
|
|
<a class="btn btn-outline-dark" href="{% url 'ticket_list' %}">Back to queue</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="container mb-5">
|
|
<div class="row g-4">
|
|
<div class="col-lg-8">
|
|
<article class="support-card mb-4">
|
|
<span class="section-kicker">Original request</span>
|
|
<p class="ticket-description mb-0">{{ ticket.description|linebreaksbr }}</p>
|
|
</article>
|
|
|
|
<div class="support-card mb-4">
|
|
<div class="d-flex justify-content-between align-items-center gap-3 mb-4">
|
|
<div>
|
|
<span class="section-kicker">Threaded replies</span>
|
|
<h2 class="h3 mb-0">Conversation</h2>
|
|
</div>
|
|
<span class="reply-count">{{ ticket.replies.count }} repl{{ ticket.replies.count|pluralize:"y,ies" }}</span>
|
|
</div>
|
|
|
|
<div class="timeline">
|
|
<div class="timeline-item requester">
|
|
<div class="timeline-dot" aria-hidden="true"></div>
|
|
<div class="reply-card">
|
|
<div class="reply-meta">
|
|
<strong>{{ ticket.requester_name }}</strong>
|
|
<span>opened this ticket · {{ ticket.created_at|date:"M j, Y g:i A" }}</span>
|
|
</div>
|
|
<p class="mb-0">{{ ticket.description|linebreaksbr }}</p>
|
|
</div>
|
|
</div>
|
|
{% for reply in ticket.replies.all %}
|
|
<div class="timeline-item {% if reply.is_staff_reply %}staff{% else %}requester{% endif %}">
|
|
<div class="timeline-dot" aria-hidden="true"></div>
|
|
<div class="reply-card">
|
|
<div class="reply-meta">
|
|
<strong>{{ reply.author_name }}</strong>
|
|
<span>{% if reply.is_staff_reply %}support agent{% else %}requester{% endif %} · {{ reply.created_at|date:"M j, Y g:i A" }}</span>
|
|
</div>
|
|
<p class="mb-0">{{ reply.body|linebreaksbr }}</p>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<div class="empty-thread">No replies yet. Add the first update below.</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="support-card">
|
|
<span class="section-kicker">Add update</span>
|
|
<h2 class="h3">Post a reply</h2>
|
|
<form method="post" novalidate>
|
|
{% csrf_token %}
|
|
<input type="hidden" name="reply_submit" value="1">
|
|
{% include "core/partials/form_errors.html" with form=reply_form %}
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ reply_form.author_name.id_for_label }}">{{ reply_form.author_name.label }}</label>
|
|
{{ reply_form.author_name }}
|
|
{% include "core/partials/field_errors.html" with field=reply_form.author_name %}
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label" for="{{ reply_form.author_email.id_for_label }}">{{ reply_form.author_email.label }}</label>
|
|
{{ reply_form.author_email }}
|
|
{% include "core/partials/field_errors.html" with field=reply_form.author_email %}
|
|
</div>
|
|
<div class="col-12">
|
|
<label class="form-label" for="{{ reply_form.body.id_for_label }}">{{ reply_form.body.label }}</label>
|
|
{{ reply_form.body }}
|
|
{% include "core/partials/field_errors.html" with field=reply_form.body %}
|
|
</div>
|
|
</div>
|
|
<button class="btn btn-primary mt-4" type="submit">Add reply</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<aside class="col-lg-4">
|
|
<div class="support-card sticky-summary mb-4">
|
|
<span class="section-kicker">Status tracking</span>
|
|
<dl class="ticket-facts">
|
|
<div><dt>Status</dt><dd><span class="status-badge status-{{ ticket.status }}">{{ ticket.get_status_display }}</span></dd></div>
|
|
<div><dt>Priority</dt><dd>{{ ticket.get_priority_display }}</dd></div>
|
|
<div><dt>Category</dt><dd>{{ ticket.get_category_display }}</dd></div>
|
|
<div><dt>Assigned</dt><dd>{% if ticket.assigned_to %}{{ ticket.assigned_to.get_username }}{% else %}Unassigned{% endif %}</dd></div>
|
|
<div><dt>Requester</dt><dd>{{ ticket.requester_name }}<br><a href="mailto:{{ ticket.requester_email }}">{{ ticket.requester_email }}</a></dd></div>
|
|
</dl>
|
|
</div>
|
|
|
|
{% if user.is_staff %}
|
|
<div class="support-card">
|
|
<span class="section-kicker">Agent controls</span>
|
|
<h2 class="h4">Triage ticket</h2>
|
|
<form method="post" novalidate>
|
|
{% csrf_token %}
|
|
<input type="hidden" name="triage_submit" value="1">
|
|
{% include "core/partials/form_errors.html" with form=triage_form %}
|
|
<div class="mb-3">
|
|
<label class="form-label" for="{{ triage_form.status.id_for_label }}">Status</label>
|
|
{{ triage_form.status }}
|
|
{% include "core/partials/field_errors.html" with field=triage_form.status %}
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label" for="{{ triage_form.priority.id_for_label }}">Priority</label>
|
|
{{ triage_form.priority }}
|
|
{% include "core/partials/field_errors.html" with field=triage_form.priority %}
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label" for="{{ triage_form.assigned_to.id_for_label }}">Assigned to</label>
|
|
{{ triage_form.assigned_to }}
|
|
{% include "core/partials/field_errors.html" with field=triage_form.assigned_to %}
|
|
</div>
|
|
<button class="btn btn-secondary w-100" type="submit">Update triage</button>
|
|
</form>
|
|
</div>
|
|
{% else %}
|
|
<div class="mini-panel">
|
|
<strong>Agent controls</strong>
|
|
<p class="mb-0">Staff can sign in through Admin to assign owners and update ticket status.</p>
|
|
</div>
|
|
{% endif %}
|
|
</aside>
|
|
</div>
|
|
</section>
|
|
{% endblock %}
|