HH/templates/organizations/department_manager_review.html
ismail 7369d08012
All checks were successful
Build and Push Docker Image / build (push) Successful in 4m14s
feat: unified reference numbers + feedback modules QA audit
Reference numbers (unified scheme PREFIX-YYYYMM-HOSP-NNNN, e.g. CMP-202606-HHN-0001):
- new ReferenceSequence model + generate_reference() helper (apps/core)
- Complaint/Inquiry/Observation/Appreciation/Suggestion emit unified refs via save()
- prefix-based auto-routing in public track API (CMP/INQ/OBS trackable; APR/SGT internal-only)
- removed legacy CMP-/INQ- generators in ui_views, integrations, px_sources
- migrations: core.0003_referencesequence, appreciation.0006, feedback.0008, observations.0012
- unit tests (format, sanitization, monthly reset, 40-thread concurrency)

QA audit:
- isolated E2E hospital sandbox mirroring HH-N + 10 role users (create_e2e_isolated_env)
- feedback-modules-audit.spec.ts + audit helper (headed, run-to-completion)
- reports/feedback-modules-qa-report.md

Also bundles accumulated in-progress work across complaints, observations,
organizations, templates, and other modules.
2026-06-14 14:29:23 +03:00

185 lines
9.8 KiB
HTML

{% extends "layouts/base.html" %}
{% load i18n %}
{% block title %}{% trans "Manager Review" %} - {{ complaint.reference_number }} - PX360{% endblock %}
{% block content %}
<div class="p-6 max-w-4xl mx-auto">
<div class="flex items-center gap-2 text-sm text-slate-500 mb-4">
<a href="{% url 'organizations:department_list' %}" class="hover:text-navy transition">{% trans "Departments" %}</a>
<i data-lucide="chevron-right" class="w-4 h-4"></i>
<a href="{% url 'organizations:department_detail' department.pk %}" class="hover:text-navy transition">{{ department.get_localized_name }}</a>
<i data-lucide="chevron-right" class="w-4 h-4"></i>
<span class="text-navy font-semibold">{% trans "Manager Review" %}</span>
</div>
<div class="flex items-center gap-3 mb-6">
<div class="w-10 h-10 bg-amber-50 rounded-xl flex items-center justify-center">
<i data-lucide="shield-check" class="w-5 h-5 text-amber-600"></i>
</div>
<div>
<h1 class="text-xl font-bold text-navy">{% trans "Review Champion Response" %}</h1>
<p class="text-sm text-slate-500">{{ complaint.reference_number }} &middot; {{ department.get_localized_name }}</p>
</div>
</div>
<div class="space-y-6">
{% if complaint.title %}
<div class="bg-white rounded-2xl border border-slate-200 p-6">
<h3 class="text-sm font-bold text-navy mb-2 flex items-center gap-2">
<i data-lucide="file-text" class="w-4 h-4"></i> {% trans "Complaint" %}
</h3>
<p class="text-sm text-slate-700">{{ complaint.title }}</p>
{% if complaint.description %}
<p class="text-sm text-slate-500 mt-2 whitespace-pre-wrap">{{ complaint.description }}</p>
{% endif %}
</div>
{% endif %}
<div class="bg-white rounded-2xl border border-slate-200 p-6">
<h3 class="text-sm font-bold text-navy mb-3 flex items-center gap-2">
<i data-lucide="message-square" class="w-4 h-4"></i> {% trans "Champion Response" %}
</h3>
{% if involved_dept.response_notes_en %}
<div class="bg-slate-50 rounded-xl p-4 border border-slate-200 mb-3">
<p class="text-[10px] text-slate-400 uppercase font-bold mb-1">{% trans "English" %}</p>
<p class="text-sm text-slate-700 whitespace-pre-wrap">{{ involved_dept.response_notes_en }}</p>
</div>
{% endif %}
{% if involved_dept.response_notes_ar %}
<div class="bg-slate-50 rounded-xl p-4 border border-slate-200">
<p class="text-[10px] text-slate-400 uppercase font-bold mb-1">{% trans "Arabic" %}</p>
<p class="text-sm text-slate-700 whitespace-pre-wrap" dir="rtl">{{ involved_dept.response_notes_ar }}</p>
</div>
{% endif %}
{% if involved_dept.response_submitted_at %}
<p class="text-xs text-slate-400 mt-2">
{% trans "Submitted" %}: {{ involved_dept.response_submitted_at|date:"Y-m-d H:i" }}
</p>
{% endif %}
</div>
<form method="post" id="managerReviewForm">
{% csrf_token %}
<input type="hidden" name="review_action" id="reviewAction" value="">
{% if questions %}
<div class="bg-white rounded-2xl border border-slate-200 p-6">
<h3 class="text-sm font-bold text-navy mb-4 flex items-center gap-2">
<i data-lucide="clipboard-list" class="w-4 h-4"></i> {% trans "Review Questions" %}
</h3>
<div class="space-y-5">
{% for q in questions %}
<div class="border-b border-slate-100 pb-4 last:border-0 last:pb-0">
<label class="block text-sm font-semibold text-slate-700 mb-2">
{{ q.get_localized_text }}
<span class="text-red-500">*</span>
</label>
{% if q.question_type == 'text' %}
<input type="text" name="question_{{ q.pk }}" required
class="w-full px-4 py-2.5 border-2 border-slate-200 rounded-xl text-sm focus:outline-none focus:border-navy focus:ring-2 focus:ring-navy/20">
{% elif q.question_type == 'textarea' %}
<textarea name="question_{{ q.pk }}" rows="3" required
class="w-full px-4 py-3 border-2 border-slate-200 rounded-xl text-sm focus:outline-none focus:border-navy focus:ring-2 focus:ring-navy/20 resize-none"></textarea>
{% elif q.question_type == 'yes_no' %}
<div class="flex gap-4 mt-1">
<label class="flex items-center gap-2 cursor-pointer">
<input type="radio" name="question_{{ q.pk }}" value="yes" required
class="w-4 h-4 text-navy border-slate-300 focus:ring-navy">
<span class="text-sm text-slate-700">{% trans "Yes" %}</span>
</label>
<label class="flex items-center gap-2 cursor-pointer">
<input type="radio" name="question_{{ q.pk }}" value="no"
class="w-4 h-4 text-navy border-slate-300 focus:ring-navy">
<span class="text-sm text-slate-700">{% trans "No" %}</span>
</label>
</div>
{% elif q.question_type == 'rating' %}
<div class="flex gap-2 mt-1">
{% for i in "12345" %}
<label class="cursor-pointer">
<input type="radio" name="question_{{ q.pk }}" value="{{ i }}" required
class="hidden peer">
<div class="w-10 h-10 rounded-lg border-2 border-slate-200 flex items-center justify-center text-sm font-bold text-slate-400 peer-checked:bg-navy peer-checked:text-white peer-checked:border-navy transition hover:border-navy">
{{ i }}
</div>
</label>
{% endfor %}
</div>
{% elif q.question_type == 'multiple_choice' %}
<div class="space-y-2 mt-1">
{% for choice in q.choices_json %}
<label class="flex items-center gap-2 cursor-pointer">
<input type="radio" name="question_{{ q.pk }}" value="{{ choice }}" required
class="w-4 h-4 text-navy border-slate-300 focus:ring-navy">
<span class="text-sm text-slate-700">{{ choice }}</span>
</label>
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endif %}
<div id="rejectionReasonBox" class="hidden bg-white rounded-2xl border border-red-200 p-6">
<h3 class="text-sm font-bold text-red-700 mb-2 flex items-center gap-2">
<i data-lucide="alert-circle" class="w-4 h-4"></i> {% trans "Rejection Reason" %}
</h3>
<textarea name="rejection_reason" id="rejectionReason" rows="3"
class="w-full px-4 py-3 border-2 border-red-200 rounded-xl text-sm focus:outline-none focus:border-red-400 focus:ring-2 focus:ring-red-200/40 resize-none"
placeholder="{% trans 'Please explain why you are rejecting this response...' %}"></textarea>
</div>
<div class="flex gap-3 pt-2">
<button type="button" onclick="submitReview('approve')"
class="flex-1 px-4 py-3 bg-green-600 text-white font-semibold rounded-xl hover:bg-green-700 transition flex items-center justify-center gap-2">
<i data-lucide="check-circle" class="w-5 h-5"></i> {% trans "Approve & Forward to PX Team" %}
</button>
<button type="button" onclick="handleReject()"
class="flex-1 px-4 py-3 bg-red-600 text-white font-semibold rounded-xl hover:bg-red-700 transition flex items-center justify-center gap-2">
<i data-lucide="x-circle" class="w-5 h-5"></i> {% trans "Reject & Return to Champion" %}
</button>
<a href="{% url 'organizations:department_detail' department.pk %}"
class="px-4 py-3 bg-slate-100 text-slate-700 font-semibold rounded-xl hover:bg-slate-200 transition text-center">
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
<script>
function submitReview(action) {
document.getElementById('reviewAction').value = action;
document.getElementById('managerReviewForm').submit();
}
function handleReject() {
var box = document.getElementById('rejectionReasonBox');
box.classList.remove('hidden');
document.getElementById('rejectionReason').focus();
box.scrollIntoView({ behavior: 'smooth', block: 'center' });
var reasonEl = document.getElementById('rejectionReason');
reasonEl.setAttribute('required', 'required');
var submitBtn = box.closest('form').querySelectorAll('button')[1];
submitBtn.onclick = function() {
var reason = reasonEl.value.trim();
if (!reason) {
alert('{% trans "Please provide a rejection reason." %}');
return;
}
submitReview('reject');
};
}
</script>
{% endblock %}