<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Panel de Administración - ImagingPro</title>
<link rel="icon" type="image/png" href="{{ asset('images/favicon-32-2.png') }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
:root {
--primary-color: #3498db;
--secondary-color: #2c3e50;
--accent-color: #e74c3c;
--success-color: #27ae60;
--warning-color: #f39c12;
--light-color: #ecf0f1;
--dark-color: #34495e;
--admin-bg: #f8f9fa;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: var(--admin-bg);
color: #333;
line-height: 1.6;
overflow-x: hidden; /* Previene scroll horizontal global */
}
/* ===== LAYOUT PRINCIPAL ===== */
.admin-container {
display: flex;
min-height: 100vh;
overflow-x: hidden; /* Previene scroll horizontal */
}
/* ===== SIDEBAR ===== */
.admin-sidebar {
width: 280px;
background: linear-gradient(135deg, var(--secondary-color) 0%, var(--dark-color) 100%);
color: white;
transition: all 0.3s ease;
box-shadow: 2px 0 10px rgba(0,0,0,0.1);
z-index: 1000;
position: fixed;
left: 0;
top: 0;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden; /* Previene scroll horizontal en el sidebar */
}
.admin-main-content {
margin-left: 280px;
transition: all 0.3s ease;
min-height: 100vh;
width: calc(100% - 280px);
overflow-x: hidden; /* Previene scroll horizontal en el contenido */
}
/* Header del Sidebar */
.admin-sidebar-header {
padding: 1.5rem;
border-bottom: 1px solid rgba(255,255,255,0.1);
text-align: center;
flex-shrink: 0;
}
.admin-sidebar-header h2 {
font-size: 1.5rem;
margin-bottom: 1rem;
}
.admin-user-info {
text-align: center;
}
.admin-avatar {
width: 70px;
height: 70px;
background: linear-gradient(135deg, var(--primary-color), #2980b9);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 1.8rem;
margin: 0 auto 1rem;
border: 3px solid rgba(255,255,255,0.2);
}
.admin-user-name {
font-weight: 600;
margin-bottom: 0.25rem;
}
.admin-user-email {
font-size: 0.85rem;
color: rgba(255,255,255,0.7);
}
/* Navegación del Sidebar - Área con scroll */
.admin-nav-container {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
width: 100%; /* Asegura que no se desborde */
}
.admin-nav {
padding: 1.5rem 0;
flex: 1;
overflow-y: auto;
overflow-x: hidden; /* Elimina scroll horizontal */
max-height: calc(100vh - 280px);
width: 100%; /* Asegura que ocupe todo el ancho disponible */
}
.admin-nav-section {
margin-bottom: 1.5rem;
width: 100%; /* Asegura que no cause desbordamiento */
}
.admin-nav-title {
font-size: 0.8rem;
text-transform: uppercase;
padding: 0.5rem 1.5rem;
color: rgba(255,255,255,0.6);
letter-spacing: 1px;
margin-bottom: 0.5rem;
width: 100%;
overflow: hidden; /* Previene desbordamiento de texto */
}
.admin-nav-item {
display: flex;
align-items: center;
padding: 0.75rem 1.5rem;
color: rgba(255,255,255,0.9);
text-decoration: none;
transition: all 0.3s ease;
border-left: 3px solid transparent;
position: relative;
width: 100%; /* Ocupa todo el ancho disponible */
white-space: nowrap; /* Evita que el texto se divida en varias líneas */
overflow: hidden; /* Oculta cualquier contenido que se desborde */
}
.admin-nav-item:hover {
background: rgba(255,255,255,0.1);
color: white;
border-left-color: var(--primary-color);
transform: translateX(5px);
}
.admin-nav-item.active {
background: rgba(52, 152, 219, 0.2);
color: white;
border-left-color: var(--primary-color);
}
.admin-nav-icon {
width: 20px;
margin-right: 12px;
font-size: 1.1rem;
text-align: center;
flex-shrink: 0; /* Evita que el icono se reduzca */
}
.admin-nav-badge {
background: var(--accent-color);
color: white;
border-radius: 10px;
padding: 2px 8px;
font-size: 0.7rem;
margin-left: auto;
flex-shrink: 0; /* Evita que la badge se reduzca */
}
/* Submenú para Agenda de Citas */
.admin-nav-item.has-submenu {
cursor: pointer;
}
.admin-submenu {
list-style: none;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
background: rgba(0, 0, 0, 0.2);
width: 100%; /* Asegura que ocupe todo el ancho */
}
.admin-submenu.open {
max-height: 300px;
}
.admin-submenu-item {
padding: 0.6rem 1.5rem 0.6rem 3rem;
color: rgba(255, 255, 255, 0.8);
text-decoration: none;
display: block;
transition: all 0.2s ease;
border-left: 3px solid transparent;
font-size: 0.9rem;
width: 100%; /* Ocupa todo el ancho */
white-space: nowrap; /* Evita división de texto */
overflow: hidden; /* Oculta desbordamiento */
}
.admin-submenu-item:hover {
background: rgba(255, 255, 255, 0.05);
color: white;
border-left-color: rgba(255, 255, 255, 0.3);
}
.admin-submenu-item.active {
background: rgba(52, 152, 219, 0.15);
color: white;
border-left-color: var(--primary-color);
}
.admin-nav-arrow {
transition: transform 0.3s ease;
margin-left: auto;
font-size: 0.8rem;
flex-shrink: 0; /* Evita que la flecha se reduzca */
}
.admin-nav-arrow.rotated {
transform: rotate(180deg);
}
/* Footer del Sidebar - Siempre visible en la parte inferior */
.admin-sidebar-footer {
padding: 1rem 1.5rem;
border-top: 1px solid rgba(255,255,255,0.1);
background: rgba(0,0,0,0.1);
flex-shrink: 0;
width: 100%; /* Asegura que ocupe todo el ancho */
}
/* Scroll personalizado para el sidebar */
.admin-nav::-webkit-scrollbar {
width: 6px;
}
.admin-nav::-webkit-scrollbar-track {
background: rgba(255,255,255,0.1);
border-radius: 3px;
}
.admin-nav::-webkit-scrollbar-thumb {
background: rgba(255,255,255,0.3);
border-radius: 3px;
}
.admin-nav::-webkit-scrollbar-thumb:hover {
background: rgba(255,255,255,0.5);
}
/* ===== CONTENIDO PRINCIPAL ===== */
.admin-header {
background: white;
border-bottom: 1px solid #e9ecef;
padding: 1rem 1.5rem;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
display: flex;
align-items: center;
justify-content: space-between;
width: 100%; /* Asegura que no cause desbordamiento */
overflow: hidden; /* Previene desbordamiento */
}
.admin-mobile-toggle {
display: none;
background: transparent;
border: 2px solid #e9ecef;
border-radius: 6px;
padding: 8px 12px;
color: var(--secondary-color);
transition: all 0.3s ease;
margin-right: 15px;
flex-shrink: 0; /* Evita que el botón se reduzca */
}
.admin-mobile-toggle:hover {
background: var(--primary-color);
color: white;
border-color: var(--primary-color);
}
.admin-content {
padding: 1.5rem;
width: 100%; /* Asegura que ocupe todo el ancho disponible */
overflow-x: hidden; /* Elimina scroll horizontal */
}
/* ===== OVERLAY PARA MÓVIL ===== */
.admin-sidebar-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 999;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
}
.admin-sidebar-overlay.show {
opacity: 1;
visibility: visible;
}
/* ===== RESPONSIVE ===== */
@media (max-width: 768px) {
.admin-sidebar {
left: -280px;
}
.admin-sidebar.mobile-open {
left: 0;
}
.admin-main-content {
margin-left: 0;
width: 100%;
}
.admin-mobile-toggle {
display: block;
}
/* Ajustes adicionales para móviles */
.admin-nav-item,
.admin-submenu-item {
white-space: normal; /* Permite que el texto se divida en móviles */
padding: 0.75rem 1rem;
}
.admin-submenu-item {
padding-left: 2.5rem;
}
}
@media (min-width: 769px) and (max-width: 1024px) {
.admin-sidebar {
width: 240px;
}
.admin-main-content {
margin-left: 240px;
width: calc(100% - 240px);
}
}
.admin-header {
background: #fff;
border-bottom: 1px solid #dee2e6;
padding: 1rem 1.5rem;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.admin-mobile-toggle {
background: none;
border: none;
color: #6c757d;
font-size: 1.2rem;
padding: 0.5rem;
border-radius: 0.375rem;
transition: all 0.2s ease;
}
.admin-mobile-toggle:hover {
background: #f8f9fa;
color: #495057;
}
.admin-page-title {
font-size: 1.1rem;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 300px; /* Limita el ancho del título */
}
.admin-mobile-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 0.8rem;
flex-shrink: 0;
}
/* Para móviles muy pequeños */
@media (max-width: 576px) {
.admin-header {
padding: 0.75rem 1rem;
}
.admin-page-title {
font-size: 1rem;
max-width: 200px;
}
.admin-mobile-avatar {
width: 32px;
height: 32px;
font-size: 0.7rem;
}
.admin-nav-item,
.admin-submenu-item {
padding: 0.6rem 1rem;
}
}
</style>
</head>
<body>
<div class="admin-container">
<!-- Overlay para móviles -->
<div class="admin-sidebar-overlay" id="adminSidebarOverlay"></div>
<!-- Sidebar del Admin -->
<aside class="admin-sidebar" id="adminSidebar">
<div class="admin-sidebar-header">
<h2>Panel Admin</h2>
<div class="admin-user-info">
<div class="admin-avatar">
{{ app.user.name|first|upper }}{{ app.user.lastName|first|upper }}
</div>
<div class="admin-user-name">{{ app.user.name }} {{ app.user.lastName }}</div>
<div class="admin-user-email">{{ app.user.email }}</div>
</div>
</div>
<!-- Contenedor para la navegación con scroll -->
<div class="admin-nav-container">
<nav class="admin-nav">
<div class="admin-nav-section">
<a href="{{ path('admin_index') }}" class="admin-nav-item {% if app.request.attributes.get('_route') == 'admin_index' %}active{% endif %}">
<i class="fas fa-tachometer-alt admin-nav-icon"></i>
Dashboard
</a>
<a href="{{ path('admin_pacientes') }}" class="admin-nav-item {% if app.request.attributes.get('_route') == 'admin_pacientes' %}active{% endif %}">
<i class="fas fa-user-injured admin-nav-icon"></i>
Pacientes
</a>
<a href="{{ path('admin_proveedores') }}" class="admin-nav-item {% if app.request.attributes.get('_route') == 'admin_proveedores' %}active{% endif %}">
<i class="fas fa-user-md admin-nav-icon"></i>
Proveedores
</a>
<!-- Agenda de Citas con Submenú -->
<div class="admin-nav-item has-submenu {% if 'admin_appointment' in app.request.attributes.get('_route') %}active{% endif %}" id="appointmentsMenu">
<div class="d-flex align-items-center w-100">
<i class="fas fa-calendar-check admin-nav-icon"></i>
<span>Agenda de Citas</span>
<i class="fas fa-chevron-down admin-nav-arrow ms-auto" id="appointmentsArrow"></i>
</div>
</div>
<ul class="admin-submenu" id="appointmentsSubmenu">
<li>
<a href="{{ path('admin_appointment') }}" class="admin-submenu-item {% if app.request.attributes.get('_route') == 'admin_appointment' and not app.request.query.has('filter') %}active{% endif %}">
<i class="fas fa-list-ul me-2"></i>
Todas las Citas
</a>
</li>
<li>
<a href="{{ path('admin_appointment') }}?filter=confirmed" class="admin-submenu-item {% if app.request.query.get('filter') == 'confirmed' %}active{% endif %}">
<i class="fas fa-calendar-check me-2 text-success"></i>
Citas Confirmadas
</a>
</li>
<li>
<a href="{{ path('admin_appointment') }}?filter=completed" class="admin-submenu-item {% if app.request.query.get('filter') == 'completed' %}active{% endif %}">
<i class="fas fa-clipboard-check me-2 text-primary"></i>
Citas Finalizadas
</a>
</li>
<li>
<a href="{{ path('admin_appointment') }}?filter=cancelled" class="admin-submenu-item {% if app.request.query.get('filter') == 'cancelled' %}active{% endif %}">
<i class="fas fa-calendar-times me-2 text-danger"></i>
Citas Canceladas
</a>
</li>
</ul>
<a href="{{ path('admin_horario') }}" class="admin-nav-item {% if app.request.attributes.get('_route') == 'admin_horario' %}active{% endif %}">
<i class="fas fa-clock admin-nav-icon"></i>
Horarios Médicos
</a>
<a href="{{ path('admin_profile') }}" class="admin-nav-item {% if app.request.attributes.get('_route') == 'admin_profile' %}active{% endif %}">
<i class="fas fa-user-cog admin-nav-icon"></i>
Perfil
</a>
</div>
</nav>
</div>
<!-- Footer fijo en la parte inferior -->
<div class="admin-sidebar-footer">
<a href="{{ path('home_index') }}" class="admin-nav-item">
<i class="fas fa-home admin-nav-icon"></i>
Volver al Sitio
</a>
<a href="{{ path('app_logout') }}" class="admin-nav-item">
<i class="fas fa-sign-out-alt admin-nav-icon"></i>
Cerrar Sesión
</a>
</div>
</aside>
<!-- Contenido Principal -->
<main class="admin-main-content" id="adminMainContent">
<header class="admin-header">
<div class="d-flex align-items-center justify-content-between w-100">
<!-- Lado izquierdo: Toggle + Título -->
<div class="d-flex align-items-center">
<button class="admin-mobile-toggle me-2 me-md-3" id="adminMobileToggle">
<i class="fas fa-bars"></i>
</button>
<!-- Título responsive sin truncar -->
<h4 class="mb-0 text-dark admin-page-title">
<span class="d-none d-md-inline">Panel de Administración</span>
<span class="d-md-none">Panel de Admon</span>
</h4>
</div>
<!-- Lado derecho: Información del usuario -->
<div class="d-flex align-items-center">
<!-- Versión móvil compacta -->
<div class="d-md-none admin-mobile-user me-2">
<div class="admin-mobile-avatar">
{{ app.user.name|first|upper }}{{ app.user.lastName|first|upper }}
</div>
</div>
<!-- Versión desktop completa -->
<div class="d-none d-md-block">
<span class="text-muted">Bienvenido, {{ app.user.name }} {{ app.user.lastName }}</span>
</div>
<!-- Versión tablet intermedia -->
<div class="d-none d-sm-block d-md-none">
<span class="text-muted">Hola, {{ app.user.name }}</span>
</div>
</div>
</div>
</header>
<div class="admin-content">
{% block content %}{% endblock %}
</div>
</main>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
{% block javascripts %}
{% endblock %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const adminMobileToggle = document.getElementById('adminMobileToggle');
const adminSidebar = document.getElementById('adminSidebar');
const adminSidebarOverlay = document.getElementById('adminSidebarOverlay');
// Elementos del submenú de citas
const appointmentsMenu = document.getElementById('appointmentsMenu');
const appointmentsSubmenu = document.getElementById('appointmentsSubmenu');
const appointmentsArrow = document.getElementById('appointmentsArrow');
// Control del submenú de citas
if (appointmentsMenu && appointmentsSubmenu) {
appointmentsMenu.addEventListener('click', function(e) {
e.preventDefault();
appointmentsSubmenu.classList.toggle('open');
appointmentsArrow.classList.toggle('rotated');
});
}
// Control del menú móvil
if (adminMobileToggle && adminSidebar) {
function toggleAdminSidebar() {
adminSidebar.classList.toggle('mobile-open');
adminSidebarOverlay.classList.toggle('show');
document.body.style.overflow = adminSidebar.classList.contains('mobile-open') ? 'hidden' : '';
}
adminMobileToggle.addEventListener('click', toggleAdminSidebar);
adminSidebarOverlay.addEventListener('click', toggleAdminSidebar);
// Cerrar menú al hacer clic en un enlace (en móviles)
const adminNavLinks = adminSidebar.querySelectorAll('.admin-nav-item, .admin-submenu-item');
adminNavLinks.forEach(link => {
link.addEventListener('click', function() {
if (window.innerWidth <= 768) {
toggleAdminSidebar();
}
});
});
// Cerrar con tecla Escape
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && adminSidebar.classList.contains('mobile-open')) {
toggleAdminSidebar();
}
});
// Ajustar el layout en resize
window.addEventListener('resize', function() {
if (window.innerWidth > 768) {
adminSidebar.classList.remove('mobile-open');
adminSidebarOverlay.classList.remove('show');
document.body.style.overflow = '';
}
});
}
});
</script>
{# Notificaciones globales - se convierten automáticamente a SweetAlert2 #}
{% include 'partials/_flashes.html.twig' %}
</body>
</html>