313 lines
11 KiB
HTML
313 lines
11 KiB
HTML
{% extends "layouts/base.html" %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ title }} - PX360{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
:root {
|
|
--hh-navy: #005696;
|
|
--hh-blue: #007bbd;
|
|
--hh-light: #eef6fb;
|
|
--hh-slate: #64748b;
|
|
}
|
|
|
|
.page-header-gradient {
|
|
background: linear-gradient(135deg, #005696 0%, #0069a8 50%, #007bbd 100%);
|
|
color: white;
|
|
padding: 1.5rem 2rem;
|
|
border-radius: 1rem;
|
|
margin-bottom: 1.5rem;
|
|
box-shadow: 0 10px 15px -3px rgba(0, 86, 150, 0.2);
|
|
}
|
|
|
|
.section-card {
|
|
background: white;
|
|
border-radius: 1rem;
|
|
border: 2px solid #e2e8f0;
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
overflow: hidden;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.section-card:hover {
|
|
border-color: #005696;
|
|
box-shadow: 0 10px 25px -5px rgba(0, 86, 150, 0.15);
|
|
}
|
|
|
|
.section-header {
|
|
padding: 1rem 1.5rem;
|
|
border-bottom: 2px solid #e2e8f0;
|
|
background: linear-gradient(to right, #f8fafc, #f1f5f9);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
}
|
|
|
|
.section-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 0.75rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.section-icon.primary {
|
|
background: linear-gradient(135deg, #005696, #007bbd);
|
|
color: white;
|
|
}
|
|
|
|
.section-icon.secondary {
|
|
background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
|
|
color: #005696;
|
|
}
|
|
|
|
.btn-primary {
|
|
background: linear-gradient(135deg, var(--hh-navy) 0%, var(--hh-blue) 100%);
|
|
color: white;
|
|
padding: 0.625rem 1.25rem;
|
|
border-radius: 0.75rem;
|
|
font-weight: 600;
|
|
border: none;
|
|
cursor: pointer;
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 16px rgba(0, 86, 150, 0.3);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: white;
|
|
color: #475569;
|
|
padding: 0.625rem 1.25rem;
|
|
border-radius: 0.75rem;
|
|
font-weight: 600;
|
|
border: 2px solid #e2e8f0;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
text-decoration: none;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.btn-secondary:hover {
|
|
background: #f1f5f9;
|
|
border-color: #cbd5e1;
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.schedule-card {
|
|
background: white;
|
|
border-radius: 1rem;
|
|
border: 2px solid #e2e8f0;
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
overflow: hidden;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.schedule-card:hover {
|
|
border-color: #005696;
|
|
box-shadow: 0 10px 25px -5px rgba(0, 86, 150, 0.15);
|
|
}
|
|
|
|
.schedule-card-header {
|
|
padding: 1rem 1.5rem;
|
|
border-bottom: 2px solid #e2e8f0;
|
|
background: linear-gradient(to right, #f8fafc, #f1f5f9);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.icon-box {
|
|
width: 40px;
|
|
height: 40px;
|
|
border-radius: 0.75rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: linear-gradient(135deg, var(--hh-light), #e0f2fe);
|
|
color: var(--hh-navy);
|
|
}
|
|
|
|
.status-dot {
|
|
width: 10px;
|
|
height: 10px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.status-dot.active {
|
|
background: linear-gradient(135deg, #10b981, #059669);
|
|
}
|
|
|
|
.status-dot.inactive {
|
|
background: linear-gradient(135deg, #cbd5e1, #94a3b8);
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(20px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
.animate-in {
|
|
animation: fadeIn 0.5s ease-out forwards;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="px-4 py-6">
|
|
<!-- Page Header -->
|
|
<div class="page-header-gradient animate-in">
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center gap-4">
|
|
<a href="{% url 'complaints:oncall_dashboard' %}" class="text-white/80 hover:text-white transition">
|
|
<i data-lucide="arrow-left" class="w-6 h-6"></i>
|
|
</a>
|
|
<div>
|
|
<h1 class="text-2xl font-bold mb-2">
|
|
<i data-lucide="calendar-clock" class="w-7 h-7 inline-block me-2"></i>
|
|
{{ title }}
|
|
</h1>
|
|
<p class="text-white/90">{% trans "Configure working hours and on-call admin assignments" %}</p>
|
|
</div>
|
|
</div>
|
|
<a href="{% url 'complaints:oncall_schedule_create' %}" class="btn-secondary">
|
|
<i data-lucide="plus" class="w-4 h-4"></i>
|
|
{% trans "Create Schedule" %}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Schedules Grid -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{% for schedule in schedules %}
|
|
<div class="schedule-card animate-in">
|
|
<div class="schedule-card-header">
|
|
<div class="flex items-center gap-2">
|
|
{% if schedule.hospital %}
|
|
<span class="font-bold text-navy">{{ schedule.hospital.name }}</span>
|
|
{% else %}
|
|
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-bold bg-[#eef6fb] text-[#005696]">
|
|
{% trans "System-wide" %}
|
|
</span>
|
|
{% endif %}
|
|
</div>
|
|
{% if schedule.is_active %}
|
|
<span class="status-dot active" title="{% trans 'Active' %}"></span>
|
|
{% else %}
|
|
<span class="status-dot inactive" title="{% trans 'Inactive' %}"></span>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<div class="p-6">
|
|
<div class="space-y-4">
|
|
<!-- Working Hours -->
|
|
<div class="flex items-center gap-3">
|
|
<div class="icon-box">
|
|
<i data-lucide="clock" class="w-5 h-5"></i>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-slate font-medium">{% trans "Working Hours" %}</p>
|
|
<p class="font-bold text-gray-900">
|
|
{{ schedule.work_start_time|time:"H:i" }} - {{ schedule.work_end_time|time:"H:i" }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Working Days -->
|
|
<div class="flex items-center gap-3">
|
|
<div class="icon-box">
|
|
<i data-lucide="calendar" class="w-5 h-5"></i>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-slate font-medium">{% trans "Working Days" %}</p>
|
|
<p class="font-bold text-gray-900 text-sm">
|
|
{% for day in schedule.get_working_days_list %}
|
|
{% if day == 0 %}{% trans "Mon" %}{% elif day == 1 %}{% trans "Tue" %}{% elif day == 2 %}{% trans "Wed" %}{% elif day == 3 %}{% trans "Thu" %}{% elif day == 4 %}{% trans "Fri" %}{% elif day == 5 %}{% trans "Sat" %}{% elif day == 6 %}{% trans "Sun" %}{% endif %}{% if not forloop.last %}, {% endif %}
|
|
{% endfor %}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Timezone -->
|
|
<div class="flex items-center gap-3">
|
|
<div class="icon-box">
|
|
<i data-lucide="globe" class="w-5 h-5"></i>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-slate font-medium">{% trans "Timezone" %}</p>
|
|
<p class="font-bold text-gray-900 text-sm">{{ schedule.timezone }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- On-Call Admins Count -->
|
|
<div class="flex items-center gap-3">
|
|
<div class="icon-box">
|
|
<i data-lucide="users" class="w-5 h-5"></i>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-slate font-medium">{% trans "On-Call Admins" %}</p>
|
|
<p class="font-bold text-[#007bbd]">{{ schedule.on_call_admins.count }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="mt-6 pt-4 border-t border-slate-200 flex gap-2">
|
|
<a href="{% url 'complaints:oncall_schedule_detail' schedule.id %}"
|
|
class="flex-1 px-3 py-2 bg-[#005696] text-white text-sm rounded-lg hover:bg-[#007bbd] transition-colors text-center font-semibold">
|
|
{% trans "View" %}
|
|
</a>
|
|
<a href="{% url 'complaints:oncall_schedule_edit' schedule.id %}"
|
|
class="px-3 py-2 border-2 border-slate-200 text-slate-600 text-sm rounded-lg hover:bg-slate-50 transition-colors">
|
|
<i data-lucide="edit" class="w-4 h-4"></i>
|
|
</a>
|
|
<form method="post" action="{% url 'complaints:oncall_schedule_delete' schedule.id %}"
|
|
class="inline" onsubmit="return confirm('{% trans "Are you sure you want to delete this schedule?" %}')">
|
|
{% csrf_token %}
|
|
<button type="submit" class="px-3 py-2 border-2 border-red-200 text-red-600 text-sm rounded-lg hover:bg-red-50 transition-colors">
|
|
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<div class="col-span-full">
|
|
<div class="section-card p-12 text-center animate-in">
|
|
<div class="w-16 h-16 bg-slate-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
|
<i data-lucide="calendar-x" class="w-8 h-8 text-slate-400"></i>
|
|
</div>
|
|
<h3 class="text-lg font-bold text-navy mb-2">{% trans "No On-Call Schedules" %}</h3>
|
|
<p class="text-slate mb-6 max-w-md mx-auto">
|
|
{% trans "Create your first on-call schedule to configure working hours and assign on-call admins for after-hours complaint notifications." %}
|
|
</p>
|
|
<a href="{% url 'complaints:oncall_schedule_create' %}" class="btn-primary">
|
|
<i data-lucide="plus" class="w-5 h-5"></i>
|
|
{% trans "Create Schedule" %}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
lucide.createIcons();
|
|
});
|
|
</script>
|
|
{% endblock %}
|