This commit is contained in:
2025-07-17 13:31:55 -06:00
parent 1960a52c36
commit 1900091b99
15 changed files with 2250 additions and 1292 deletions

View File

@@ -8,8 +8,7 @@ if (!isset($_SESSION['usuario_id'])) {
// Obtener información del usuario
$tipoUsuario = $_SESSION['tipo_usuario'] ?? '';
$agenciaId = $_SESSION['agencia_id'] ?? null;
$usuarioId = $_SESSION['usuario_id'] ?? null;
$usuarioId = $_SESSION['usuario_id'] ?? null;
// Definir permisos por tipo de usuario
$permisos = [
@@ -82,6 +81,15 @@ function contarBitacorasDisponibles($permisosBitacoras) {
$cantidadBitacoras = contarBitacorasDisponibles($permisosBitacoras);
// Variables para detectar las vistas actuales
$currentPath = $_SERVER['REQUEST_URI'];
$esConfiguracion = $currentPath === '/IMPORTADORES/configuracion/index' || $currentPath === '/IMPORTADORES/configuracion';
$esVistaAutomatizaciones = strpos($currentPath, '/IMPORTADORES/automatizaciones/') === 0;
$esVistaPreferencias = strpos($currentPath, '/IMPORTADORES/preferencias/') === 0;
$esVistaSeguridad = strpos($currentPath, '/IMPORTADORES/seguridad/') === 0;
$esVistaBitacoras = strpos($currentPath, '/IMPORTADORES/bitacoras/') === 0 && $currentPath !== '/IMPORTADORES/configuracion';
$esVistaReset = strpos($currentPath, '/IMPORTADORES/reset/') === 0;
// Función para obtener el texto descriptivo según el permiso
function obtenerTextoPermiso($permiso, $tipoUsuario) {
$textos = [
@@ -98,22 +106,6 @@ function obtenerTextoPermiso($permiso, $tipoUsuario) {
return $textos[$permiso] ?? ucfirst(str_replace('_', ' ', $permiso));
}
// Función para obtener el icono según el permiso
function obtenerIconoPermiso($permiso) {
$iconos = [
'registro_accesos' => '🌐',
'registro_cambios' => '🔄',
'registro_usuarios' => '👥',
'registro_agencias' => '🏪',
'acceso_usuarios_agencia' => '👥',
'registro_vinculaciones' => '🔗',
'mi_actividad' => '👤',
'vinculaciones_usuario' => '🔗'
];
return $iconos[$permiso] ?? '📋';
}
// Función para obtener la URL según el permiso
function obtenerUrlPermiso($permiso) {
$urls = [
@@ -131,15 +123,52 @@ function obtenerUrlPermiso($permiso) {
}
?>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.nav .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; }
.nav .nav-link:hover,
.nav .nav-link.active { background-color: #495057; color: #fff; }
/* Estilo inverso solo para pantallas pequeñas (sidebar tipo offcanvas) */
@media (max-width: 767.98px) {
.nav .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.nav .nav-link:hover,
.nav .nav-link.active { background-color: #e9ecef; color: #212529; }
/* Estilos inspirados en Tailwind */
.sidebar-container { background-color: #f9fafb; border-right: 1px solid #e5e7eb; }
.sidebar-dark { background-color: #1f2937; border-right: 1px solid #374151; }
.sidebar-nav .nav-link { color: #374151; font-weight: 500; padding: 0.5rem 0.75rem; margin-bottom: 0.125rem;
border-radius: 0.5rem; transition: all 0.15s ease-in-out; display: flex; align-items: center; }
.sidebar-nav .nav-link:hover { background-color: #f3f4f6; color: #111827; }
.sidebar-nav .nav-link.active { background-color: #f3f4f6; color: #111827; }
.sidebar-nav .nav-link .icon { width: 1.25rem; height: 1.25rem; margin-right: 0.75rem; color: #6b7280; transition: color 0.15s ease-in-out; flex-shrink: 0; }
.sidebar-nav .nav-link:hover .icon,
.sidebar-nav .nav-link.active .icon { color: #374151; }
.sidebar-nav .badge { background-color: #f3f4f6; color: #374151; font-size: 0.75rem; font-weight: 500; padding: 0.25rem 0.5rem; border-radius: 9999px; margin-left: auto; }
.sidebar-nav .badge.badge-primary { background-color: #dbeafe; color: #1e40af; }
.submenu .nav-link { padding-left: 2.75rem; color: #6b7280; font-weight: 400; }
.submenu .nav-link:hover { background-color: #f3f4f6; color: #374151; }
.submenu .nav-link.active { background-color: #f3f4f6; color: #374151; }
.collapse-icon { width: 0.75rem; height: 0.75rem; margin-left: auto; transition: transform 0.15s ease-in-out; }
.nav-link[aria-expanded="true"] .collapse-icon { transform: rotate(180deg); }
/* Estilos para modo oscuro */
.sidebar-dark .sidebar-nav .nav-link { color: #d1d5db; }
.sidebar-dark .sidebar-nav .nav-link:hover { background-color: #374151; color: #ffffff; }
.sidebar-dark .sidebar-nav .nav-link.active { background-color: #374151; color: #ffffff; }
.sidebar-dark .sidebar-nav .nav-link .icon { color: #9ca3af; }
.sidebar-dark .sidebar-nav .nav-link:hover .icon,
.sidebar-dark .sidebar-nav .nav-link.active .icon { color: #ffffff; }
.sidebar-dark .sidebar-nav .badge { background-color: #374151; color: #d1d5db; }
.sidebar-dark .sidebar-nav .badge.badge-primary { background-color: #1e3a8a; color: #93c5fd; }
.sidebar-dark .submenu .nav-link { color: #9ca3af; }
.sidebar-dark .submenu .nav-link:hover { background-color: #374151; color: #d1d5db; }
.sidebar-dark .submenu .nav-link.active { background-color: #374151; color: #d1d5db; }
/* Navbar */
.navbar-brand { font-weight: 600; font-size: 1.125rem; }
.menu-toggle { border: 1px solid #6b7280; border-radius: 0.5rem; padding: 0.5rem; transition: all 0.15s ease-in-out; }
.menu-toggle:hover { background-color: #f3f4f6; }
/* Offcanvas para móviles */
.offcanvas { background-color: #ffffff; }
.offcanvas-header { border-bottom: 1px solid #e5e7eb; padding: 1rem 1.5rem; }
.offcanvas-title { font-weight: 600; font-size: 1.125rem; color: #111827; }
.offcanvas-body { padding: 1rem 1.5rem; }
/* Responsive adjustments */
@media (max-width: 767.98px) {
.sidebar-nav .nav-link { color: #374151; }
.sidebar-nav .nav-link:hover { background-color: #f3f4f6; color: #111827; }
.sidebar-nav .nav-link.active { background-color: #f3f4f6; color: #111827; }
.permission-scope { background-color: rgba(108, 117, 125, 0.2); }
.submenu-item:hover { background-color: rgba(233, 236, 239, 0.8) !important; }
}
@@ -154,7 +183,7 @@ function obtenerUrlPermiso($permiso) {
<nav class="navbar navbar-dark bg-dark fixed-top">
<div class="container-fluid">
<!-- Botón de menú para móviles -->
<button class="btn btn-outline-light d-md-none me-2" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu">
<button class="menu-toggle d-md-none me-3" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu">
</button>
<span class="navbar-brand">
@@ -180,309 +209,224 @@ function obtenerUrlPermiso($permiso) {
</nav>
<!-- SIDEBAR FIJA (escritorio) -->
<div class="d-none d-md-block bg-dark text-white position-fixed h-100 pt-5" style="width: 250px;">
<nav class="nav flex-column">
<!-- Definimos variables de ubicación -->
<?php
// Detecta si estamos en alguna parte de configuración
$esConfiguracion = str_contains($_SERVER['REQUEST_URI'], '/configuracion');
// Detecta si estamos en alguna parte de bitácoras
$esVistaBitacoras = str_contains($_SERVER['REQUEST_URI'], '/bitacoras');
// Detecta si estamos en alguna parta de seguridad
$esVistaSeguridad = str_contains($_SERVER['REQUEST_URI'], '/seguridad');
// Detecta si estamos en alguna parte de preferencias
$esVistaPreferencias = str_contains($_SERVER['REQUEST_URI'], '/preferencias');
// Detecta si estamos en alguna parte de automatizaciones
$esVistaAutomatizaciones = str_contains($_SERVER['REQUEST_URI'], '/automatizaciones');
// Detecta si estamos en alguna parte del reset
$esVistaReset = str_contains($_SERVER['REQUEST_URI'], '/reset');
?>
<!-- INFORMACIÓN GENERAL -->
<?php if ($permisosUsuario['informacion_general']): ?>
<a href="/IMPORTADORES/configuracion/index"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion/dashboard_configuracion') ? 'active' : '' ?>">
Información General
</a>
<?php endif; ?>
<!-- AUTOMATIZACIONES -->
<?php if ($permisosUsuario['automatizaciones']): ?>
<?php if ($esVistaAutomatizaciones): ?>
<?php $enDashboardAutomatizaciones = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/automatizaciones/index'; ?>
<a href="/IMPORTADORES/automatizaciones/index"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/automatizaciones/index') ? 'active' : '' ?>">
⚙️ Automatizaciones
</a>
<?php elseif ($esConfiguracion || $esVistaSeguridad || $esVistaPreferencias || $esVistaBitacoras || $esVistaReset): ?>
<a href="/IMPORTADORES/automatizaciones/index"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/automatizaciones/index') ? 'active' : '' ?>">
⚙️ Automatizaciones
</a>
<?php endif; ?>
<?php endif; ?>
<!-- PREFERENCIAS -->
<?php if ($permisosUsuario['preferencias']): ?>
<?php if ($esVistaPreferencias): ?>
<?php $enDashboardPreferencias = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/index'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaPreferencias ? 'active' : '' ?>"
href="<?= $enDashboardPreferencias ? '#submenuPreferencias' : '/IMPORTADORES/preferencias/index' ?>"
<?= $enDashboardPreferencias ? 'data-bd-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuPreferencias"
onclick="<? $enDashboardPreferencias ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/preferencias/index\';' ?>">
✅ Preferencias
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse show" id="submenuPreferencias">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/preferencias/notificaciones"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/notificaciones' ? 'active' : '' ?>">
• Gestión de Notificaciones
<div class="d-none d-md-block sidebar-container sidebar-dark position-fixed h-100" style="width: 250px; top: 0; padding-top: 4rem; z-index: 1000;">
<div class="px-3 py-4 h-100 overflow-y-auto">
<nav class="sidebar-nav">
<ul class="nav flex-column">
<!-- INFORMACIÓN GENERAL -->
<li class="nav-item">
<?php if ($permisosUsuario['informacion_general']): ?>
<a href="/IMPORTADORES/configuracion/index" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10c0 4.418-3.582 8-8 8s-8-3.582-8-8 3.582-8 8-8 8 3.582 8 8zm-8-4a1 1 0 100 2 1 1 0 000-2zm-1 4a1 1 0 000 2h1v3a1 1 0 102 0v-4a1 1 0 00-1-1h-2z" clip-rule="evenodd" />
</svg>
<span>Información general</span>
</a>
<a href="/IMPORTADORES/preferencias/catalogos"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/catalogos' ? 'active' : '' ?>">
• Visualización de Catálogos
<?php endif; ?>
</li>
<!-- AUTOMATIZACIONES -->
<li class="nav-item">
<?php if ($permisosUsuario['automatizaciones']): ?>
<a href="/IMPORTADORES/automatizaciones/index" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M13 7H7v6h6V7z" />
<path fill-rule="evenodd" d="M5 3a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2V9.586a1 1 0 00-.293-.707l-4.586-4.586A1 1 0 0012.414 4H5zm7 1.414L16.586 10H13a1 1 0 01-1-1V4.414z" clip-rule="evenodd"/>
</svg>
<span>Automatizaciones</span>
</a>
</nav>
</div>
<?php elseif ($esConfiguracion || $esVistaAutomatizaciones || $esVistaSeguridad || $esVistaBitacoras || $esVistaReset): ?>
<a href="/IMPORTADORES/preferencias/index"
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center">
✅ Preferencias
<span class="badge bg-secondary">2</span>
</a>
<?php endif; ?>
<?php endif; ?>
<!-- SEGURIDAD -->
<?php if ($permisosUsuario['seguridad']): ?>
<?php if ($esVistaSeguridad): ?>
<?php $enDashboardSeguridad = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/seguridad/index'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaSeguridad ? 'active' : '' ?>"
href="<?= $enDashboardSeguridad ? '#submenuSeguridad' : '/IMPORTADORES/seguridad/index' ?>"
<?= $enDashboardSeguridad ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuSeguridad"
onclick="<?= $enDashboardSeguridad ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/seguridad/index\';' ?>">
👮 Seguridad
<span class="badge bg-secondary">1</span>
</a>
<div class="collapse show" id="submenuSeguridad">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/seguridad/opciones"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/seguridad/opciones' ? 'active' : '' ?>">
• Opciones de Seguridad
<?php endif; ?>
</li>
<!-- PREFERENCIAS -->
<li class="nav-item">
<?php if ($permisosUsuario['preferencias']): ?>
<?php $enDashboardPreferencias = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/index'; ?>
<a class="nav-link <?= $esVistaPreferencias ? 'active' : '' ?>"
href="<?= $enDashboardPreferencias ? '#submenuPreferencias' : '/IMPORTADORES/preferencias/index' ?>"
<?= $enDashboardPreferencias ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="false" aria-controls="submenuPreferencias"
onclick="<?= $enDashboardPreferencias ? 'return true;' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/preferencias/index\';' ?>">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M11.3 1.046a1 1 0 00-2.6 0L7.528 3H4a1 1 0 000 2h1v10H4a1 1 0 000 2h3.528l1.172 1.954a1 1 0 001.6 0L12.472 17H16a1 1 0 000-2h-1V5h1a1 1 0 100-2h-3.528L11.3 1.046zM9 6a1 1 0 011 1v6a1 1 0 11-2 0V7a1 1 0 011-1z" clip-rule="evenodd"/>
</svg>
<span>Preferencias</span>
<svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</svg>
</a>
</nav>
</div>
<?php elseif ($esConfiguracion || $esVistaAutomatizaciones || $esVistaPreferencias || $esVistaBitacoras || $esVistaReset): ?>
<a href="/IMPORTADORES/seguridad/index"
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center">
👮 Seguridad
<span class="badge bg-secondary">1</span>
</a>
<?php endif; ?>
<?php endif; ?>
<!-- BITÁCORAS CON PERMISOS ESPECÍFICOS -->
<?php if (tieneAccesoBitacoras($permisosBitacoras)): ?>
<?php $enDashboardBitacoras = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/bitacoras/index'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaBitacoras ? 'active' : '' ?>"
href="<?= $enDashboardBitacoras ? '#submenuBitacoras' : '/IMPORTADORES/bitacoras/index' ?>"
<?= $enDashboardBitacoras ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuBitacoras"
onclick="<?= $enDashboardBitacoras ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/bitacoras/index\';' ?>">
📖 Bitácoras
<span class="badge bg-secondary"><?= $cantidadBitacoras ?></span>
</a>
<div class="collapse" id="submenuPreferencias">
<ul class="nav flex-column submenu">
<li class="nav-item">
<a href="/IMPORTADORES/preferencias/notificaciones" class="nav-link">
Gestión de Notificaciones
</a>
</li>
<li class="nav-item">
<a href="/IMPORTADORES/preferencias/catalogos" class="nav-link">
Visualización de Catálogos
</a>
</li>
</ul>
</div>
<?php endif; ?>
</li>
<!-- SEGURIDAD -->
<li class="nav-item">
<?php if ($permisosUsuario['seguridad']): ?>
<?php $enDashboardSeguridad = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/seguridad/index'; ?>
<a class="nav-link <?= $esVistaSeguridad ? 'active' : '' ?>"
href="<?= $enDashboardSeguridad ? '#submenuSeguridad' : '/IMPORTADORES/seguridad/index' ?>"
<?= $enDashboardSeguridad ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="false" aria-controls="submenuSeguridad"
onclick="<?= $enDashboardSeguridad ? 'return true;' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/seguridad/index\';' ?>">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 2a4 4 0 00-4 4v2H5a2 2 0 00-2 2v6a2 2 0 002 2h10a2 2 0 002-2v-6a2 2 0 00-2-2h-1V6a4 4 0 00-4-4zm2 6V6a2 2 0 10-4 0v2h4z" clip-rule="evenodd"/>
</svg>
<span>Seguridad</span>
<svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</svg>
</a>
<div class="collapse" id="submenuSeguridad">
<nav class="nav flex-column submenu">
<li class="nav-item">
<a href="/IMPORTADORES/seguridad/opciones" class="nav-link">
Opciones de Seguridad
</a>
</li>
</nav>
</div>
<?php endif; ?>
</li>
<!-- BITÁCORAS CON PERMISOS ESPECÍFICOS -->
<li class="nav-item">
<?php if (tieneAccesoBitacoras($permisosBitacoras)): ?>
<?php $enDashboardBitacoras = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/bitacoras/index'; ?>
<a class="nav-link <?= $esVistaBitacoras ? 'active' : '' ?>"
href="<?= $enDashboardBitacoras ? '#submenuBitacoras' : '/IMPORTADORES/bitacoras/index' ?>"
<?= $enDashboardBitacoras ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="<?= $enDashboardBitacoras ? 'false' : 'false' ?>" aria-controls="submenuBitacoras"
onclick="<?= $enDashboardBitacoras ? 'return true;' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/bitacoras/index\';' ?>">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M4 3a2 2 0 00-2 2v10a2 2 0 002 2h12a1 1 0 001-1V4a1 1 0 00-1-1H4zm0 2h11v10H4V5z"/>
<path d="M6 7h5v1H6V7zm0 3h8v1H6v-1z"/>
</svg>
<span>Bitácoras</span>
<svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</svg>
</a>
<div class="collapse" id="submenuBitacoras">
<nav class="nav flex-column submenu">
<?php foreach ($permisosBitacoras as $permiso => $tienePermiso): ?>
<li class="nav-item">
<?php if ($tienePermiso): ?>
<?php
$url = obtenerUrlPermiso($permiso);
$texto = obtenerTextoPermiso($permiso, $tipoUsuario);
$esActivo = $_SERVER['REQUEST_URI'] === $url;
<div class="collapse <?= $esVistaBitacoras ? 'show' : '' ?>" id="submenuBitacoras">
<nav class="nav flex-column ms-3">
<?php foreach ($permisosBitacoras as $permiso => $tienePermiso): ?>
<?php if ($tienePermiso): ?>
<?php
$url = obtenerUrlPermiso($permiso);
$texto = obtenerTextoPermiso($permiso, $tipoUsuario);
$icono = obtenerIconoPermiso($permiso);
$esActivo = $_SERVER['REQUEST_URI'] === $url;
// Scope según dashboard
$scope = '';
if ($tipoUsuario === 'super_admin') {
$scope = 'Global';
} elseif ($tipoUsuario === 'admin_agencia' || $tipoUsuario === 'agente_aduanal') {
if (in_array($permiso, ['acceso_usuarios_agencia', 'registro_vinculaciones'])) {
$scope = 'Agencia';
} elseif (in_array($permiso, ['mis_vinculaciones', 'mi_actividad'])) {
$scope = 'Personal';
}
} elseif ($tipoUsuario === 'importador') {
$scope = 'Personal';
}
?>
<a href="<?= $url ?>"
class="nav-link submenu-item px-3 py-2 d-flex justify-content-between align-items-center <?= $esActivo ? 'active' : '' ?>">
<span>
<?= $icono ?> <?= htmlspecialchars($texto) ?>
<?php if ($scope): ?>
<span class="permission-scope"><?= $scope ?></span>
<?php endif; ?>
</span>
</a>
<?php endif; ?>
<?php endforeach; ?>
</nav>
</div>
<?php endif; ?>
</nav>
// Scope según dashboard
$scope = '';
if ($tipoUsuario === 'super_admin') {
$scope = 'Global';
} elseif ($tipoUsuario === 'admin_agencia' || $tipoUsuario === 'agente_aduanal') {
if (in_array($permiso, ['acceso_usuarios_agencia', 'registro_vinculaciones'])) {
$scope = 'Agencia';
} elseif (in_array($permiso, ['mis_vinculaciones', 'mi_actividad'])) {
$scope = 'Personal';
}
} elseif ($tipoUsuario === 'importador') {
$scope = 'Personal';
}
?>
<a href="<?= $url ?>"
class="nav-link submenu-item px-3 py-2 d-flex justify-content-between align-items-center <?= $esActivo ? 'active' : '' ?>">
<span>
<?= htmlspecialchars($texto) ?>
<?php if ($scope): ?>
<span class="permission-scope"><?= $scope ?></span>
<?php endif; ?>
</span>
</a>
<?php endif; ?>
</li>
<?php endforeach; ?>
</nav>
</div>
<?php endif; ?>
</li>
</ul>
</nav>
</div>
</div>
<!-- OFFCANVAS PARA MÓVILES -->
<div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu" style="top: 56px;">
<div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu" style="top: 0; width: 250px;">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Menú</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<!-- INFORMACIÓN GENERAL -->
<?php if ($permisosUsuario['informacion_general']): ?>
<a href="/IMPORTADORES/configuracion/index"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion/dashboard_configuracion') ? 'active' : '' ?>">
Información General
</a>
<?php endif; ?>
<!-- AUTOMATIZACIONES -->
<?php if ($permisosUsuario['automatizaciones']): ?>
<?php if ($esVistaAutomatizaciones): ?>
<?php $enDashboardAutomatizaciones = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/automatizaciones/index'; ?>
<a href="/IMPORTADORES/automatizaciones/index"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/automatizaciones/index') ? 'active' : '' ?>">
⚙️ Automatizaciones
</a>
<?php elseif ($esConfiguracion || $esVistaSeguridad || $esVistaPreferencias || $esVistaBitacoras || $esVistaReset): ?>
<a href="/IMPORTADORES/automatizaciones/index"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/automatizaciones/index') ? 'active' : '' ?>">
⚙️ Automatizaciones
</a>
<?php endif; ?>
<?php endif; ?>
<!-- PREFERENCIAS -->
<?php if ($permisosUsuario['preferencias']): ?>
<?php if ($esVistaPreferencias): ?>
<?php $enDashboardPreferencias = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/index'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaPreferencias ? 'active' : '' ?>"
href="<?= $enDashboardPreferencias ? '#submenuPreferencias' : '/IMPORTADORES/preferencias/index' ?>"
<?= $enDashboardPreferencias ? 'data-bd-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuPreferencias"
onclick="<? $enDashboardPreferencias ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/preferencias/index\';' ?>">
✅ Preferencias
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse show" id="submenuPreferencias">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/preferencias/notificaciones"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/notificaciones' ? 'active' : '' ?>">
• Gestión de Notificaciones
</a>
<a href="/IMPORTADORES/preferencias/catalogos"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/catalogos' ? 'active' : '' ?>">
• Visualización de Catálogos
</a>
</nav>
</div>
<?php elseif ($esConfiguracion || $esVistaAutomatizaciones || $esVistaSeguridad || $esVistaBitacoras || $esVistaReset): ?>
<a href="/IMPORTADORES/preferencias/index"
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center">
✅ Preferencias
<span class="badge bg-secondary">2</span>
</a>
<?php endif; ?>
<?php endif; ?>
<!-- SEGURIDAD -->
<?php if ($permisosUsuario['seguridad']): ?>
<?php if ($esVistaSeguridad): ?>
<?php $enDashboardSeguridad = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/seguridad/index'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaSeguridad ? 'active' : '' ?>"
href="<?= $enDashboardSeguridad ? '#submenuSeguridad' : '/IMPORTADORES/seguridad/index' ?>"
<?= $enDashboardSeguridad ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuSeguridad"
onclick="<?= $enDashboardSeguridad ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/seguridad/index\';' ?>">
👮 Seguridad
<span class="badge bg-secondary">1</span>
</a>
<div class="collapse show" id="submenuSeguridad">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/seguridad/opciones"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/seguridad/opciones' ? 'active' : '' ?>">
• Opciones de Seguridad
</a>
</nav>
</div>
<?php elseif ($esConfiguracion || $esVistaAutomatizaciones || $esVistaPreferencias || $esVistaBitacoras || $esVistaReset): ?>
<a href="/IMPORTADORES/seguridad/index"
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center">
👮 Seguridad
<span class="badge bg-secondary">1</span>
</a>
<?php endif; ?>
<?php endif; ?>
<!-- BITÁCORAS CON PERMISOS ESPECÍFICOS -->
<?php if (tieneAccesoBitacoras($permisosBitacoras)): ?>
<?php $enDashboardBitacoras = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/bitacoras/index'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaBitacoras ? 'active' : '' ?>"
href="<?= $enDashboardBitacoras ? '#submenuBitacoras' : '/IMPORTADORES/bitacoras/index' ?>"
<?= $enDashboardBitacoras ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuBitacoras"
onclick="<?= $enDashboardBitacoras ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/bitacoras/index\';' ?>">
📖 Bitácoras
<span class="badge bg-secondary"><?= $cantidadBitacoras ?></span>
</a>
<div class="collapse <?= $esVistaBitacoras ? 'show' : '' ?>" id="submenuBitacoras">
<nav class="nav flex-column ms-3">
<?php foreach ($permisosBitacoras as $permiso => $tienePermiso): ?>
<?php if ($tienePermiso): ?>
<?php
$url = obtenerUrlPermiso($permiso);
$texto = obtenerTextoPermiso($permiso, $tipoUsuario);
$icono = obtenerIconoPermiso($permiso);
$esActivo = $_SERVER['REQUEST_URI'] === $url;
// Scope según dashboard
$scope = '';
if ($tipoUsuario === 'super_admin') {
$scope = 'Global';
} elseif ($tipoUsuario === 'admin_agencia' || $tipoUsuario === 'agente_aduanal') {
if (in_array($permiso, ['acceso_usuarios_agencia', 'registro_vinculaciones'])) {
$scope = 'Agencia';
} elseif (in_array($permiso, ['mis_vinculaciones', 'mi_actividad'])) {
$scope = 'Personal';
}
} elseif ($tipoUsuario === 'importador') {
$scope = 'Personal';
}
?>
<a href="<?= $url ?>"
class="nav-link submenu-item px-3 py-2 d-flex justify-content-between align-items-center <?= $esActivo ? 'active' : '' ?>">
<span>
<?= $icono ?> <?= htmlspecialchars($texto) ?>
<?php if ($scope): ?>
<span class="permission-scope"><?= $scope ?></span>
<?php endif; ?>
</span>
</a>
<?php endif; ?>
<?php endforeach; ?>
</nav>
</div>
<?php endif; ?>
<nav class="sidebar-nav">
<ul class="nav flex-column">
</ul>
</nav>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Detectar la ruta actual
const currentPath = window.location.pathname;
// Función para abrir collapse si la página actual está en esa sección
function inicializarCollapses() {
// Preferencias
if (currentPath.includes('/preferencias/')) {
const preferencesCollapse = document.getElementById('submenuPreferencias');
if (preferencesCollapse) {
preferencesCollapse.classList.add('show');
const trigger = document.querySelector('[aria-controls="submenuPreferencias"]');
if (trigger) trigger.setAttribute('aria-expanded', 'true');
}
}
// Seguridad
if (currentPath.includes('/seguridad/')) {
const securityCollapse = document.getElementById('submenuSeguridad');
if (securityCollapse) {
securityCollapse.classList.add('show');
const trigger = document.querySelector('[aria-controls="submenuSeguridad"]');
if (trigger) trigger.setAttribute('aria-expanded', 'true');
}
}
// Bitácoras
if (currentPath.includes('/bitacoras/')) {
const bitacorasCollapse = document.getElementById('submenuBitacoras');
if (bitacorasCollapse) {
bitacorasCollapse.classList.add('show');
const trigger = document.querySelector('[aria-controls="submenuBitacoras"]');
if (trigger) trigger.setAttribute('aria-expanded', 'true');
}
}
}
// Marcar enlaces activos
function marcarEnlacesActivos() {
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
const href = link.getAttribute('href');
if (href && currentPath === href) {
link.classList.add('active');
}
});
}
// Inicializar todo
inicializarCollapses();
marcarEnlacesActivos();
});
</script>