294 lines
13 KiB
HTML
294 lines
13 KiB
HTML
{% load i18n %}
|
|
<!DOCTYPE html>
|
|
<html lang="{% get_current_language as LANGUAGE_CODE %}{{ LANGUAGE_CODE }}" dir="{% if LANGUAGE_CODE == 'ar' %}rtl{% else %}ltr{% endif %}">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
<title>{% block title %}{% trans "PX360 - Patient Experience Management" %}{% endblock %}</title>
|
|
|
|
<!-- TailwindCSS -->
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
|
|
<!-- Lucide Icons -->
|
|
<script src="https://unpkg.com/lucide@latest"></script>
|
|
|
|
<!-- Google Fonts - Inter -->
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
|
|
<!-- ApexCharts -->
|
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts@3.45.1/dist/apexcharts.min.js"></script>
|
|
|
|
<!-- HTMX for dynamic updates -->
|
|
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
|
|
|
<!-- Tailwind Config -->
|
|
<script>
|
|
tailwind.config = {
|
|
theme: {
|
|
extend: {
|
|
fontFamily: {
|
|
'inter': ['Inter', 'sans-serif'],
|
|
},
|
|
colors: {
|
|
'navy': '#005696',
|
|
'blue': '#007bbd',
|
|
'light': '#eef6fb',
|
|
'slate': '#64748b',
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<!-- Custom Styles -->
|
|
<style>
|
|
body {
|
|
font-family: 'Inter', sans-serif;
|
|
}
|
|
|
|
/* Custom scrollbar */
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: #f1f5f9;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: #cbd5e1;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: #94a3b8;
|
|
}
|
|
|
|
/* Sidebar transitions */
|
|
.sidebar-transition {
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
}
|
|
|
|
/* Animation */
|
|
@keyframes fadeIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(20px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
.animate-in {
|
|
animation: fadeIn 0.5s ease-out forwards;
|
|
}
|
|
</style>
|
|
|
|
{% block extra_css %}{% endblock %}
|
|
</head>
|
|
<body class="bg-gradient-to-br from-light to-blue-50 min-h-screen">
|
|
<!-- Sidebar -->
|
|
<aside id="sidebar" class="fixed left-0 top-0 h-screen w-64 bg-gradient-to-b from-navy to-blue shadow-xl z-50 sidebar-transition overflow-y-auto">
|
|
<!-- Brand -->
|
|
<div class="p-6 border-b border-white/10">
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-10 h-10 bg-white/20 rounded-xl flex items-center justify-center">
|
|
<i data-lucide="radio" class="w-6 h-6 text-white"></i>
|
|
</div>
|
|
<div>
|
|
<h1 class="text-xl font-bold text-white">PX360</h1>
|
|
<p class="text-xs text-white/70">{% trans "Source Portal" %}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Navigation -->
|
|
<nav class="p-4 space-y-1">
|
|
<!-- Dashboard -->
|
|
<a href="{% url 'px_sources:source_user_dashboard' %}"
|
|
class="flex items-center gap-3 p-3 rounded-xl transition {% if request.resolver_match.url_name == 'source_user_dashboard' %}bg-white/20 text-white{% else %}text-white/80 hover:bg-white/10 hover:text-white{% endif %}">
|
|
<i data-lucide="layout-dashboard" class="w-5 h-5"></i>
|
|
<span class="font-medium text-sm">{% trans "Dashboard" %}</span>
|
|
</a>
|
|
|
|
<div class="my-4 border-t border-white/10"></div>
|
|
|
|
<!-- Create -->
|
|
<p class="px-3 text-xs font-semibold text-white/50 uppercase tracking-wider mb-2">{% trans "Create" %}</p>
|
|
|
|
{% if source_user.can_create_complaints %}
|
|
<a href="{% url 'px_sources:source_user_create_complaint' %}"
|
|
class="flex items-center gap-3 p-3 rounded-xl transition {% if request.resolver_match.url_name == 'source_user_create_complaint' %}bg-white/20 text-white{% else %}text-white/80 hover:bg-white/10 hover:text-white{% endif %}">
|
|
<i data-lucide="plus-circle" class="w-5 h-5"></i>
|
|
<span class="font-medium text-sm">{% trans "New Complaint" %}</span>
|
|
</a>
|
|
{% endif %}
|
|
|
|
{% if source_user.can_create_inquiries %}
|
|
<a href="{% url 'px_sources:source_user_create_inquiry' %}"
|
|
class="flex items-center gap-3 p-3 rounded-xl transition {% if request.resolver_match.url_name == 'source_user_create_inquiry' %}bg-white/20 text-white{% else %}text-white/80 hover:bg-white/10 hover:text-white{% endif %}">
|
|
<i data-lucide="plus-circle" class="w-5 h-5"></i>
|
|
<span class="font-medium text-sm">{% trans "New Inquiry" %}</span>
|
|
</a>
|
|
{% endif %}
|
|
|
|
<div class="my-4 border-t border-white/10"></div>
|
|
|
|
<!-- Lists -->
|
|
<p class="px-3 text-xs font-semibold text-white/50 uppercase tracking-wider mb-2">{% trans "My Feedback" %}</p>
|
|
|
|
<a href="{% url 'px_sources:source_user_complaint_list' %}"
|
|
class="flex items-center gap-3 p-3 rounded-xl transition {% if 'source_user_complaint_list' in request.path %}bg-white/20 text-white{% else %}text-white/80 hover:bg-white/10 hover:text-white{% endif %}">
|
|
<i data-lucide="file-text" class="w-5 h-5"></i>
|
|
<span class="font-medium text-sm">{% trans "Complaints" %}</span>
|
|
{% if total_complaints > 0 %}
|
|
<span class="ml-auto bg-white/20 text-white text-xs px-2 py-0.5 rounded-full">{{ total_complaints }}</span>
|
|
{% endif %}
|
|
</a>
|
|
|
|
<a href="{% url 'px_sources:source_user_inquiry_list' %}"
|
|
class="flex items-center gap-3 p-3 rounded-xl transition {% if 'source_user_inquiry_list' in request.path %}bg-white/20 text-white{% else %}text-white/80 hover:bg-white/10 hover:text-white{% endif %}">
|
|
<i data-lucide="help-circle" class="w-5 h-5"></i>
|
|
<span class="font-medium text-sm">{% trans "Inquiries" %}</span>
|
|
{% if total_inquiries > 0 %}
|
|
<span class="ml-auto bg-white/20 text-white text-xs px-2 py-0.5 rounded-full">{{ total_inquiries }}</span>
|
|
{% endif %}
|
|
</a>
|
|
|
|
<div class="my-4 border-t border-white/10"></div>
|
|
|
|
<!-- Account -->
|
|
<a href="{% url 'accounts:password_change' %}"
|
|
class="flex items-center gap-3 p-3 rounded-xl transition text-white/80 hover:bg-white/10 hover:text-white">
|
|
<i data-lucide="key" class="w-5 h-5"></i>
|
|
<span class="font-medium text-sm">{% trans "Change Password" %}</span>
|
|
</a>
|
|
|
|
<a href="{% url 'accounts:logout' %}"
|
|
class="flex items-center gap-3 p-3 rounded-xl transition text-red-300 hover:bg-red-500/20 hover:text-red-200">
|
|
<i data-lucide="log-out" class="w-5 h-5"></i>
|
|
<span class="font-medium text-sm">{% trans "Logout" %}</span>
|
|
</a>
|
|
</nav>
|
|
|
|
<!-- Source Info -->
|
|
{% if source %}
|
|
<div class="absolute bottom-0 left-0 right-0 p-4 border-t border-white/10 bg-white/5">
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-8 h-8 bg-gradient-to-br from-orange-400 to-red-500 rounded-lg flex items-center justify-center">
|
|
<i data-lucide="radio" class="w-4 h-4 text-white"></i>
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-xs font-semibold text-white truncate">{{ source.name_en }}</p>
|
|
<p class="text-[10px] text-white/50">{% trans "Your Source" %}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</aside>
|
|
|
|
<!-- Main Content -->
|
|
<main class="ml-64 min-h-screen">
|
|
<!-- Topbar -->
|
|
<header class="bg-white/80 backdrop-blur-sm border-b border-blue-100 sticky top-0 z-40">
|
|
<div class="px-6 py-4 flex items-center justify-between">
|
|
<!-- Hospital Info -->
|
|
{% if current_hospital %}
|
|
<div class="flex items-center gap-3">
|
|
<div class="w-10 h-10 bg-gradient-to-br from-blue to-navy rounded-xl flex items-center justify-center">
|
|
<i data-lucide="building-2" class="w-5 h-5 text-white"></i>
|
|
</div>
|
|
<div>
|
|
<p class="font-bold text-navy">{{ current_hospital.name|truncatewords:3 }}</p>
|
|
{% if current_hospital.city %}
|
|
<p class="text-xs text-slate">{{ current_hospital.city }}</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- User Menu -->
|
|
<div class="flex items-center gap-4">
|
|
<div class="flex items-center gap-3 px-4 py-2 bg-blue-50 rounded-xl border border-blue-100">
|
|
<div class="w-8 h-8 bg-gradient-to-br from-blue to-navy rounded-full flex items-center justify-center">
|
|
<span class="text-white font-bold text-xs">{{ request.user.first_name|first|default:"U" }}{{ request.user.last_name|first|default:"" }}</span>
|
|
</div>
|
|
<div class="hidden md:block">
|
|
<p class="text-sm font-bold text-navy">{{ request.user.get_full_name|default:request.user.email|truncatechars:20 }}</p>
|
|
<p class="text-xs text-slate">{% trans "Source User" %}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Page Content -->
|
|
<div class="p-6 md:p-8">
|
|
<!-- Flash Messages -->
|
|
{% if messages %}
|
|
<div class="space-y-3 mb-6">
|
|
{% for message in messages %}
|
|
<div class="flex items-center gap-3 p-4 rounded-xl {% if message.tags == 'error' %}bg-red-50 border border-red-200 text-red-700{% elif message.tags == 'success' %}bg-emerald-50 border border-emerald-200 text-emerald-700{% elif message.tags == 'warning' %}bg-orange-50 border border-orange-200 text-orange-700{% else %}bg-blue-50 border border-blue-200 text-blue-700{% endif %}">
|
|
<i data-lucide="{% if message.tags == 'error' %}alert-circle{% elif message.tags == 'success' %}check-circle{% elif message.tags == 'warning' %}alert-triangle{% else %}info{% endif %}" class="w-5 h-5"></i>
|
|
<p class="font-medium">{{ message }}</p>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% block content %}{% endblock %}
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Mobile Menu Toggle -->
|
|
<button id="mobileMenuToggle" class="lg:hidden fixed bottom-4 right-4 w-14 h-14 bg-gradient-to-br from-blue to-navy text-white rounded-full shadow-xl z-50 flex items-center justify-center hover:shadow-2xl transition">
|
|
<i data-lucide="menu" class="w-6 h-6"></i>
|
|
</button>
|
|
|
|
<!-- Mobile Sidebar Overlay -->
|
|
<div id="mobileSidebarOverlay" class="lg:hidden fixed inset-0 bg-black/50 z-40 hidden"></div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
lucide.createIcons();
|
|
|
|
// Mobile menu toggle
|
|
const mobileMenuToggle = document.getElementById('mobileMenuToggle');
|
|
const sidebar = document.getElementById('sidebar');
|
|
const mobileSidebarOverlay = document.getElementById('mobileSidebarOverlay');
|
|
|
|
if (mobileMenuToggle) {
|
|
mobileMenuToggle.addEventListener('click', function() {
|
|
const isClosed = sidebar.classList.contains('-translate-x-full');
|
|
if (isClosed) {
|
|
sidebar.classList.remove('-translate-x-full');
|
|
mobileSidebarOverlay.classList.remove('hidden');
|
|
} else {
|
|
sidebar.classList.add('-translate-x-full');
|
|
mobileSidebarOverlay.classList.add('hidden');
|
|
}
|
|
});
|
|
}
|
|
|
|
if (mobileSidebarOverlay) {
|
|
mobileSidebarOverlay.addEventListener('click', function() {
|
|
sidebar.classList.add('-translate-x-full');
|
|
mobileSidebarOverlay.classList.add('hidden');
|
|
});
|
|
}
|
|
|
|
// Initialize sidebar position for mobile
|
|
if (window.innerWidth < 1024) {
|
|
sidebar.classList.add('-translate-x-full');
|
|
}
|
|
});
|
|
</script>
|
|
|
|
{% block extra_js %}{% endblock %}
|
|
</body>
|
|
</html>
|