HH/templates/observations/public_track.html
2026-04-09 13:46:34 +03:00

281 lines
13 KiB
HTML

{% extends "layouts/public_base.html" %}
{% load i18n static %}
{% block title %}{% trans "Track Your Observation" %}{% endblock %}
{% block extra_css %}
<style>
header.glass-card {
display: none !important;
}
.lang-switcher {
position: fixed;
top: 1rem;
right: 1rem;
z-index: 100;
display: flex;
gap: 0.5rem;
}
.lang-switcher a {
padding: 0.5rem 1rem;
border-radius: 0.75rem;
border: 2px solid rgba(255,255,255,0.3);
background: rgba(255,255,255,0.1);
backdrop-filter: blur(10px);
color: white;
font-weight: 600;
font-size: 0.875rem;
transition: all 0.2s ease;
text-decoration: none;
display: flex;
align-items: center;
gap: 0.5rem;
}
.lang-switcher a:hover {
background: rgba(255,255,255,0.2);
border-color: rgba(255,255,255,0.5);
}
.lang-switcher a.active {
background: white;
color: #005696;
border-color: white;
}
[dir="rtl"] .lang-switcher {
right: auto;
left: 1rem;
}
.glass-effect {
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.timeline-dot::after {
content: '';
position: absolute;
width: 2px;
height: 100%;
background: #e2e8f0;
left: 50%;
transform: translateX(-50%);
top: 24px;
z-index: 0;
}
.timeline-item:last-child .timeline-dot::after {
display: none;
}
@keyframes subtle-float {
0% { transform: translateY(0px); }
50% { transform: translateY(-5px); }
100% { transform: translateY(0px); }
}
.float-icon { animation: subtle-float 3s ease-in-out infinite; }
</style>
{% endblock %}
{% block content %}
<!-- Language Switcher -->
<div class="lang-switcher">
{% get_available_languages as LANGUAGES %}
{% get_current_language as LANGUAGE_CODE %}
{% for lang_code, lang_name in LANGUAGES %}
<a href="{% url 'core:set_language' %}?language={{ lang_code }}"
class="{% if LANGUAGE_CODE == lang_code %}active{% endif %}">
<span>{% if lang_code == 'en' %}🇬🇧{% elif lang_code == 'ar' %}🇸🇦{% endif %}</span>
<span>{{ lang_name }}</span>
</a>
{% endfor %}
</div>
<div class="max-w-4xl mx-auto px-4 py-8 md:py-12">
<!-- Logo Banner -->
<div class="rounded-3xl shadow-2xl overflow-hidden mb-8 text-center animate-fade-in">
<div class="bg-white w-full py-8 px-6 flex items-center justify-center">
<img src="{% static 'img/hh-logo.png' %}" alt="Al Hammadi Hospital" class="max-h-16 w-auto object-contain">
</div>
<div class="bg-white p-8">
<h1 class="text-2xl font-bold text-navy mb-3">{% trans "Track Your Observation" %}</h1>
<p class="text-slate text-base max-w-xl mx-auto">
{% trans "Enter your tracking code below to see real-time updates on your observation." %}
</p>
</div>
</div>
<!-- Search Form -->
<div class="glass-card rounded-3xl shadow-2xl p-8 mb-8 animate-fade-in">
<form method="POST" class="max-w-lg mx-auto">
{% csrf_token %}
<div class="relative group">
<div class="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<i data-lucide="hash" class="w-5 h-5 text-slate/40 group-focus-within:text-blue transition-colors"></i>
</div>
<input
type="text"
name="tracking_code"
class="w-full pl-12 pr-6 py-5 border-2 border-slate-100 rounded-2xl text-navy text-lg focus:ring-4 focus:ring-blue/10 focus:border-blue transition-all duration-300 bg-white/80 placeholder:text-slate/30"
placeholder="{% trans 'e.g., OBS-ABC123' %}"
value="{{ tracking_code }}"
required
>
</div>
<button type="submit" class="w-full mt-4 bg-navy hover:bg-navy/90 text-white px-8 py-5 rounded-2xl font-bold text-lg transition-all duration-300 shadow-lg shadow-navy/20 hover:shadow-xl hover:-translate-y-1 flex items-center justify-center gap-3">
<i data-lucide="crosshair" class="w-5 h-5"></i>
{% trans "Track Status" %}
</button>
</form>
<p class="text-center text-slate/50 text-xs mt-6 uppercase tracking-widest font-semibold">
<i data-lucide="info" class="w-3 h-3 inline mr-1"></i>
{% trans "Found in your confirmation email" %}
</p>
</div>
{% if error_message %}
<div class="bg-white rounded-3xl shadow-lg p-6 mb-8 flex items-center gap-4 animate-shake">
<div class="w-12 h-12 bg-rose-100 rounded-xl flex items-center justify-center text-rose-600 shrink-0">
<i data-lucide="alert-circle" class="w-6 h-6"></i>
</div>
<div>
<h3 class="font-bold text-rose-900">{% trans "Tracking Code Not Found" %}</h3>
<p class="text-rose-700/80 text-sm">{{ error_message }}</p>
</div>
</div>
{% endif %}
{% if observation %}
<div class="animate-slide-up" style="animation-delay: 0.1s">
<div class="bg-white rounded-3xl shadow-2xl p-6 md:p-8 mb-6">
<div class="flex flex-col md:flex-row md:items-center justify-between gap-6">
<div>
<span class="text-xs font-bold text-slate/40 uppercase tracking-widest block mb-1">{% trans "Tracking Code" %}</span>
<h2 class="text-3xl font-black text-navy">{{ observation.tracking_code }}</h2>
</div>
<div class="flex items-center gap-3">
<div class="text-right hidden md:block">
<span class="text-xs font-bold text-slate/40 uppercase tracking-widest block mb-1">{% trans "Current Status" %}</span>
<p class="font-bold text-navy">{{ observation.get_status_display }}</p>
</div>
<div class="px-6 py-3 rounded-2xl text-sm font-black uppercase tracking-wider shadow-sm border-b-4
{% if observation.status == 'new' %}bg-sky-50 text-sky-700 border-sky-200
{% elif observation.status == 'triaged' %}bg-teal-50 text-teal-700 border-teal-200
{% elif observation.status == 'assigned' %}bg-teal-50 text-teal-700 border-teal-200
{% elif observation.status == 'in_progress' %}bg-blue-50 text-blue-700 border-blue-200
{% elif observation.status == 'resolved' %}bg-emerald-50 text-emerald-700 border-emerald-200
{% elif observation.status == 'closed' %}bg-slate-50 text-slate-700 border-slate-200
{% elif observation.status == 'rejected' %}bg-rose-50 text-rose-700 border-rose-200
{% elif observation.status == 'duplicate' %}bg-slate-50 text-slate-700 border-slate-200
{% else %}bg-slate-50 text-slate-700 border-slate-200{% endif %}">
{{ observation.status }}
</div>
</div>
</div>
<div class="mt-8 h-2 w-full bg-slate-100 rounded-full overflow-hidden">
<div class="h-full bg-navy transition-all duration-1000"
style="width: {% if observation.status == 'resolved' or observation.status == 'closed' %}100%{% elif observation.status == 'in_progress' or observation.status == 'assigned' %}50%{% elif observation.status == 'triaged' %}30%{% else %}15%{% endif %}">
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10">
<div class="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm transition-hover hover:shadow-md">
<i data-lucide="calendar" class="w-5 h-5 text-blue mb-3"></i>
<span class="block text-xs font-bold text-slate/50 uppercase">{% trans "Submitted" %}</span>
<p class="font-bold text-navy">{{ observation.created_at|date:"M d, Y" }}</p>
</div>
<div class="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm transition-hover hover:shadow-md">
<i data-lucide="tag" class="w-5 h-5 text-blue mb-3"></i>
<span class="block text-xs font-bold text-slate/50 uppercase">{% trans "Category" %}</span>
<p class="font-bold text-navy truncate">{{ observation.category.name|default:_("Not specified") }}</p>
</div>
<div class="bg-white p-6 rounded-2xl border border-slate-100 shadow-sm transition-hover hover:shadow-md">
<i data-lucide="activity" class="w-5 h-5
{% if observation.severity == 'critical' or observation.severity == 'high' %}text-rose-500
{% elif observation.severity == 'medium' %}text-amber-500
{% else %}text-blue{% endif %} mb-3"></i>
<span class="block text-xs font-bold text-slate/50 uppercase">{% trans "Severity" %}</span>
<p class="font-bold text-navy">{{ observation.get_severity_display }}</p>
</div>
</div>
<div class="bg-white rounded-3xl shadow-2xl p-8 md:p-10">
<h3 class="text-2xl font-bold text-navy mb-10 flex items-center gap-3">
<div class="p-2 bg-navy text-white rounded-lg">
<i data-lucide="list-checks" class="w-5 h-5"></i>
</div>
{% trans "Resolution Journey" %}
</h3>
{% if public_timeline %}
<div class="space-y-1">
{% for item in public_timeline %}
<div class="timeline-item flex gap-6 pb-10 relative">
<div class="timeline-dot shrink-0 relative z-10">
<div class="w-12 h-12 rounded-2xl flex items-center justify-center shadow-sm border-2 border-white
{% if item.type == 'status_change' %}bg-amber-100 text-amber-600
{% elif item.type == 'note' %}bg-blue-50 text-blue-600
{% else %}bg-emerald-100 text-emerald-600{% endif %}">
<i data-lucide="{% if item.type == 'status_change' %}refresh-cw{% elif item.type == 'note' %}message-square{% else %}check-circle-2{% endif %}" class="w-6 h-6"></i>
</div>
</div>
<div class="flex-1 pt-1">
<div class="flex flex-col md:flex-row md:items-center justify-between mb-2">
<h4 class="font-black text-navy text-lg">
{% if item.type == 'status_change' %}
{% trans "Status Updated" %}
{% if item.to_status %}
<span class="text-sm font-semibold text-slate/50 ms-2">→ {{ item.to_status }}</span>
{% endif %}
{% elif item.type == 'note' %}
{% trans "Update Received" %}
{% else %}
{% trans "Final Resolution" %}
{% endif %}
</h4>
<time class="text-sm font-medium text-slate/40">{{ item.created_at|date:"F j, Y • g:i A" }}</time>
</div>
{% if item.comment %}
<div class="bg-slate-50/50 rounded-2xl p-5 border border-slate-100 text-slate-700 leading-relaxed shadow-inner">
{{ item.comment|linebreaks }}
</div>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-12">
<div class="w-20 h-20 bg-slate-50 rounded-full flex items-center justify-center mx-auto mb-4">
<i data-lucide="loader" class="w-8 h-8 text-slate/30 animate-spin"></i>
</div>
<p class="text-slate/60 font-medium">{% trans "Your observation is being reviewed. Updates will appear here." %}</p>
</div>
{% endif %}
</div>
<!-- Privacy Note -->
<div class="bg-white/80 backdrop-blur rounded-2xl p-5 mt-6 flex items-start gap-3 border border-white/50">
<i data-lucide="shield" class="w-5 h-5 text-navy mt-0.5 shrink-0"></i>
<p class="text-sm text-slate/60">{% trans "For privacy reasons, detailed notes and internal communications are not shown here." %}</p>
</div>
</div>
{% endif %}
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
});
</script>
{% endblock %}