mi-proyecto/app/templates/base.html

306 lines
19 KiB
HTML

<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{{ site_settings.title or app_name }}{% endblock %}</title>
{% if site_settings.favicon_path %}
<link rel="icon" href="{{ url_for('static', filename=site_settings.favicon_path) }}">{% else %}
<link rel="icon" href="{{ url_for('static', filename='medilab/assets/img/favicon.png') }}">{% endif %}
{% if current_user.is_authenticated %}
<script>
(function(){
try {
var savedTheme = localStorage.getItem('adminTheme');
if (savedTheme === 'dark') {
document.documentElement.classList.add('admin-dark-preload');
document.documentElement.dataset.adminTheme = 'dark';
}
} catch (e) {}
})();
</script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css"
rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
{% else %}
<link href="https://fonts.googleapis.com" rel="preconnect">
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Poppins:wght@400;500;600;700&family=Raleway:wght@500;600;700&display=swap"
rel="stylesheet">
<link href="{{ url_for('static', filename='medilab/assets/vendor/bootstrap/css/bootstrap.min.css') }}"
rel="stylesheet">
<link href="{{ url_for('static', filename='medilab/assets/vendor/bootstrap-icons/bootstrap-icons.css') }}"
rel="stylesheet">
<link href="{{ url_for('static', filename='medilab/assets/vendor/aos/aos.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='medilab/assets/vendor/fontawesome-free/css/all.min.css') }}"
rel="stylesheet">
<link href="{{ url_for('static', filename='medilab/assets/vendor/glightbox/css/glightbox.min.css') }}"
rel="stylesheet">
<link href="{{ url_for('static', filename='medilab/assets/vendor/swiper/swiper-bundle.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='medilab/assets/css/main.css') }}" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
{% endif %}
<style>
:root {
--site-primary: {{ site_settings.primary_color or '#1977cc' }};
--site-secondary: {{ site_settings.secondary_color or '#0d6efd' }};
--site-accent: {{ site_settings.accent_color or '#0dcaf0' }};
--site-body-font: '{{ site_settings.body_font or 'Roboto' }}', sans-serif;
--site-heading-font: '{{ site_settings.heading_font or 'Poppins' }}', sans-serif;
--site-base-size: {{ site_settings.base_font_size or '16' }}px;
--site-topbar-bg: {{ site_settings.topbar_bg or '#1977cc' }};
--site-topbar-text: {{ site_settings.topbar_text or '#ffffff' }};
--site-header-bg: {{ site_settings.header_bg or '#ffffff' }};
--site-header-text: {{ site_settings.header_text or '#2c4964' }};
--site-nav-text: {{ site_settings.nav_text or '#2c4964' }};
--site-nav-hover: {{ site_settings.nav_hover or site_settings.primary_color or '#1977cc' }};
--site-hero-bg: {{ site_settings.hero_bg or '#f3f9fd' }};
--site-hero-surface: {{ site_settings.hero_surface or '#ffffff' }};
--site-section-bg: {{ site_settings.section_bg or '#ffffff' }};
--site-section-muted-bg: {{ site_settings.section_muted_bg or '#f7fbff' }};
--site-card-bg: {{ site_settings.card_bg or '#ffffff' }};
--site-card-text: {{ site_settings.card_text or '#444444' }};
--site-title-color: {{ site_settings.title_color or '#2c4964' }};
--site-footer-bg: {{ site_settings.footer_bg or '#0f2b45' }};
--site-footer-text: {{ site_settings.footer_text or '#ffffff' }};
--site-button-text: {{ site_settings.button_text or '#ffffff' }};
--site-radius: {{ site_settings.border_radius or '20' }}px;
}
body.index-page { font-family: var(--site-body-font); font-size: var(--site-base-size); }
body.index-page h1, body.index-page h2, body.index-page h3, body.index-page h4, body.index-page h5, body.index-page h6 { font-family: var(--site-heading-font); }
{% if current_user.is_authenticated %}
:root {
--admin-sidebar-bg: {{ site_settings.admin_style.sidebar_bg or '#111827' }};
--admin-sidebar-text: {{ site_settings.admin_style.sidebar_text or '#cbd5e1' }};
--admin-sidebar-active-bg: {{ site_settings.admin_style.sidebar_active_bg or '#243447' }};
--admin-sidebar-active-text: {{ site_settings.admin_style.sidebar_active_text or '#ffffff' }};
--admin-body-bg: {{ site_settings.admin_style.body_bg or '#f3f6fb' }};
--admin-surface-bg: {{ site_settings.admin_style.surface_bg or '#ffffff' }};
--admin-text-color: {{ site_settings.admin_style.text_color or '#1f2937' }};
--admin-muted-text-color: {{ site_settings.admin_style.muted_text_color or '#64748b' }};
--admin-primary-color: {{ site_settings.admin_style.primary_color or '#0d6efd' }};
--admin-radius: {{ site_settings.admin_style.border_radius or '18' }}px;
--admin-font-family: {{ site_settings.admin_style.font_family or 'Inter, Roboto, system-ui, sans-serif' }};
--admin-font-size: {{ site_settings.admin_style.font_size or '15' }}px;
--admin-title-color: {{ site_settings.admin_style.title_color or '#0f172a' }};
--admin-footer-bg: {{ site_settings.admin_style.footer_bg or '#ffffff' }};
--admin-modal-bg: {{ site_settings.admin_style.modal_bg or '#ffffff' }};
--admin-section-bg: {{ site_settings.admin_style.section_bg or '#ffffff' }};
--admin-input-bg: {{ site_settings.admin_style.input_bg or '#ffffff' }};
--admin-input-border: {{ site_settings.admin_style.input_border or '#dbe4f0' }};
}
{% endif %}
.notification-pill { min-width: 22px; height: 22px; display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; }
</style>
</head>
<body data-csrf-token="{{ csrf_token }}" class="{% if current_user.is_authenticated %}admin-body{% else %}index-page{% endif %}" data-admin-theme="light" {% if
current_user.is_authenticated and current_user.role in ['admin', 'receptionist', 'professional', 'accounting']
%}data-chat-enabled="1" data-chat-user-id="{{ current_user.id }}" data-chat-user-name="{{ current_user.full_name }}"
data-chat-url="{{ url_for('admin_chat') }}" {% endif %}>
{% if current_user.is_authenticated %}
<div class="admin-shell" id="adminShell">
<aside class="sidebar" id="sidebarNav">
<div class="sidebar-brand d-flex align-items-center gap-3">
{% if site_settings.logo_path %}<img src="{{ url_for('static', filename=site_settings.logo_path) }}" alt="logo"
class="site-mini-logo">{% endif %}
<div class="sidebar-brand-text">
<div class="fw-bold">{{ site_settings.title or app_name }}</div>
<div class="small sidebar-user">{{ current_user.full_name }} · {{ current_user.role }}</div>
</div>
</div>
<nav class="sidebar-nav">
{% if current_user.role == 'client' %}
<a class="sidebar-link" href="{{ url_for('client_portal') }}"><i
class="bi bi-speedometer2"></i><span>Clientes</span></a>
<a class="sidebar-link" href="{{ url_for('client_portal', tab='appointments') }}"><i
class="bi bi-calendar3"></i><span>Mis turnos</span></a>
<a class="sidebar-link" href="{{ url_for('client_portal', tab='clinical') }}"><i
class="bi bi-journal-medical"></i><span>Mi historia clínica</span></a>
<a class="sidebar-link" href="{{ url_for('client_portal', tab='prescriptions') }}"><i
class="bi bi-file-earmark-medical"></i><span>Mis recetas</span></a>
<a class="sidebar-link" href="{{ url_for('client_portal', tab='profile') }}"><i
class="bi bi-person-vcard"></i><span>Mis datos</span></a>
<a class="sidebar-link" href="{{ url_for('booking') }}"><i class="bi bi-plus-circle"></i><span>Solicitar
turno</span></a>
{% else %}
<a class="sidebar-link" href="{{ url_for('dashboard') }}"><i
class="bi bi-speedometer2"></i><span>Dashboard</span></a>
{% if current_user.role in ['admin', 'accounting'] %}
<a class="sidebar-link" href="{{ url_for('admin_accounting') }}"><i class="bi bi-cash-coin"></i><span>Contabilidad</span></a>
{% endif %}
{% if current_user.role in ['admin', 'receptionist'] and current_user.institution_id %}
<a class="sidebar-link" href="{{ url_for('institution_billing') }}"><i class="bi bi-receipt-cutoff"></i><span>Mi facturación</span></a>
{% endif %}
{% if current_user.role in ['admin', 'receptionist', 'professional'] %}
<a class="sidebar-link" href="{{ url_for('admin_calendar') }}"><i
class="bi bi-calendar3"></i><span>Calendario</span></a>
<a class="sidebar-link" href="{{ url_for('admin_appointments') }}"><i
class="bi bi-journal-check"></i><span>Turnos</span></a>
{% endif %}
{% if current_user.role in ['admin', 'professional'] %}
<a class="sidebar-link" href="{{ url_for('admin_recipes', kind='recipe') }}"><i class="bi bi-folder2-open"></i><span>Ordenes</span></a>
<a class="sidebar-link" href="{{ url_for('admin_clinical_records') }}"><i
class="bi bi-journal-medical"></i><span>Historia clínica</span></a>
{% endif %}
<a class="sidebar-link" href="{{ url_for('admin_reports') }}"><i
class="bi bi-graph-up-arrow"></i><span>Reportes</span></a>
{% if current_user.role in ['admin', 'receptionist', 'professional'] %}
<a class="sidebar-link" href="{{ url_for('admin_reminders') }}"><i
class="bi bi-bell"></i><span>Recordatorios</span></a>
<a class="sidebar-link" href="{{ url_for('admin_chat') }}"><i
class="bi bi-chat-square-text"></i><span>Chat</span><span
class="badge text-bg-danger ms-2 {% if not chat_unread_count %}d-none{% endif %}" id="sidebarChatBadge">{{
chat_unread_count or 0 }}</span></a>
{% endif %}
<div class="sidebar-divider with-label"><span>Operación</span></div>
{% if current_user.role in ['admin', 'receptionist'] %}
<a class="sidebar-link" href="{{ url_for('admin_professionals') }}"><i
class="bi bi-person-badge"></i><span>Profesionales</span></a>
<a class="sidebar-link" href="{{ url_for('admin_services') }}"><i
class="bi bi-briefcase"></i><span>Servicios</span></a>
<a class="sidebar-link" href="{{ url_for('admin_consultas') }}"><i
class="bi bi-chat-dots"></i><span>Consultas</span></a>
<a class="sidebar-link" href="{{ url_for('admin_patients') }}"><i
class="bi bi-people"></i><span>Pacientes</span></a>
{% endif %}
{% if current_user.role == 'admin' %}
<a class="sidebar-link" href="{{ url_for('admin_specialties') }}"><i
class="bi bi-heart-pulse"></i><span>Especialidades</span></a>
<a class="sidebar-link" href="{{ url_for('admin_users') }}"><i
class="bi bi-person-gear"></i><span>Usuarios</span></a>
{% endif %}
{% if current_user.role == 'admin' %}
<div class="sidebar-divider with-label"><span>Administrador</span></div>
<a class="sidebar-link" href="{{ url_for('admin_institutions') }}"><i class="bi bi-buildings"></i><span>Instituciones</span></a>
<a class="sidebar-link" href="{{ url_for('admin_site_settings') }}"><i class="bi bi-globe2"></i><span>Sitio Web</span></a>
<a class="sidebar-link" href="{{ url_for('admin_obras_sociales') }}"><i class="bi bi-hospital"></i><span>Obra
social</span></a>
<a class="sidebar-link" href="{{ url_for('admin_config_sisa') }}"><i class="bi bi-diagram-3"></i><span>Config.
SISA</span></a>
<a class="sidebar-link" href="{{ url_for('admin_ai_chatbot') }}"><i class="bi bi-robot"></i><span>Chatbot IA</span></a>
<a class="sidebar-link" href="{{ url_for('admin_whatsapp_bot') }}"><i class="bi bi-whatsapp"></i><span>WhatsApp Bot</span></a>
<a class="sidebar-link" href="{{ url_for('admin_messaging') }}"><i
class="bi bi-envelope-paper"></i><span>Mensajería</span></a>
<a class="sidebar-link" href="{{ url_for('admin_backups') }}"><i
class="bi bi-hdd-stack"></i><span>Backups</span></a>
<a class="sidebar-link" href="{{ url_for('admin_integration') }}"><i
class="bi bi-box-arrow-up-right"></i><span>Integración</span></a>
<a class="sidebar-link" href="{{ url_for('admin_logs') }}"><i
class="bi bi-exclamation-octagon"></i><span>Logs</span></a>
<a class="sidebar-link" href="{{ url_for('admin_audit') }}"><i
class="bi bi-shield-check"></i><span>Auditoría</span></a>
{% endif %}
<div class="sidebar-divider"></div>
{% if current_user.role == 'professional' and current_user.professional_profile %}
<a class="sidebar-link" href="{{ url_for('my_profile') }}"><i class="bi bi-person-vcard"></i><span>Mi
perfil</span></a>
<a class="sidebar-link"
href="{{ url_for('admin_professional_schedule', professional_id=current_user.professional_profile.id) }}"><i
class="bi bi-clock-history"></i><span>Mi disponibilidad</span></a>
<a class="sidebar-link"
href="{{ url_for('admin_professional_leaves', professional_id=current_user.professional_profile.id) }}"><i
class="bi bi-calendar-x"></i><span>Mis bloqueos</span></a>
{% endif %}
{% endif %}
</nav>
</aside>
<div class="sidebar-overlay" id="sidebarOverlay"></div>
<div class="admin-main">
<header class="topbar">
<div class="d-flex align-items-center gap-2 flex-wrap">
<button class="btn btn-sm btn-outline-secondary" type="button" id="sidebarToggle"
aria-label="Mostrar u ocultar menú"><i class="bi bi-list"></i></button>
{% if current_user.role != 'client' %}<a class="btn btn-sm btn-outline-primary"
href="{{ url_for('booking') }}" target="_blank">Ver reserva pública</a>{% else %}<a
class="btn btn-sm btn-outline-primary" href="{{ url_for('booking') }}">Reservar turno</a>{% endif %}
<a class="btn btn-sm btn-outline-success" href="{{ url_for('public_verify_recipe') }}"
target="_blank">Verificar receta</a>
</div>
<div class="d-flex align-items-center gap-2 flex-wrap justify-content-end">
{% if current_user.role in ['admin', 'receptionist', 'professional'] %}
<a class="btn btn-sm btn-outline-secondary position-relative" href="{{ url_for('admin_chat') }}"
id="topbarChatButton"><i class="bi bi-chat-square-text"></i><span
class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-bg-danger notification-pill {% if not chat_unread_count %}d-none{% endif %}"
id="topbarChatBadge">{{ chat_unread_count or 0 }}</span></a>
{% endif %}
{% if site_settings.phone %}<span class="small text-muted d-none d-md-inline"><i class="bi bi-telephone"></i>
{{ site_settings.phone }}</span>{% endif %}
<button class="btn btn-sm btn-outline-secondary" type="button" id="adminThemeToggle" title="Modo oscuro"><i class="bi bi-moon-stars"></i></button>
<a class="btn btn-sm btn-outline-secondary" href="{{ url_for('change_password') }}">Contraseña</a>
<a class="btn btn-sm btn-warning" href="{{ url_for('logout') }}" data-confirm="¿Deseás cerrar la sesión actual?" data-confirm-title="Confirmar salida">Salir</a>
</div>
</header>
<main class="admin-content">
{% else %}
<header id="header" class="header sticky-top"></header>
<main class="main">
{% endif %}
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="floating-alerts" aria-live="polite">
{% for category, message in messages %}
<div class="alert alert-{{ category }} alert-dismissible fade show shadow-sm compact-alert" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
{% if current_user.is_authenticated %}
</main>
</div>
</div>
{% else %}
</main>
<footer></footer>
{% endif %}
{% if current_user.is_authenticated %}
<div id="chatToastContainer" class="toast-container position-fixed top-0 end-0 p-3" style="z-index:1085;"></div>
<div class="modal fade" id="confirmActionModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="confirmActionTitle">Confirmar acción</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Cerrar"></button>
</div>
<div class="modal-body">
<p class="mb-0" id="confirmActionMessage">¿Deseás continuar con esta acción?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="button" class="btn btn-primary" id="confirmActionAccept">Continuar</button>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
{% if current_user.role in ['admin', 'receptionist', 'professional'] %}
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>{% endif %}
{% else %}
<script src="{{ url_for('static', filename='medilab/assets/vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='medilab/assets/vendor/aos/aos.js') }}"></script>
<script src="{{ url_for('static', filename='medilab/assets/vendor/glightbox/js/glightbox.min.js') }}"></script>
<script src="{{ url_for('static', filename='medilab/assets/vendor/swiper/swiper-bundle.min.js') }}"></script>
<script src="{{ url_for('static', filename='medilab/assets/vendor/purecounter/purecounter_vanilla.js') }}"></script>
<script src="{{ url_for('static', filename='medilab/assets/js/main.js') }}"></script>
{% endif %}
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
{% block scripts %}{% endblock %}
</body>
</html>