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

@@ -237,6 +237,154 @@ function aprobar_usuario()
exit; exit;
} }
function denegar_usuario()
{
$conn = getConnection();
$id = $_GET['id'] ?? null;
$motivo = trim($_POST['motivo'] ?? '');
// Definir motivo por defecto si no se ingresó uno
if ($motivo === '') {
$motivo = 'La solicitud ha sido rechazada por no cumplir con los requisitos establecidos.';
}
// Validar parámetros
if (!$id || !is_numeric($id)) {
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=invalid_id");
exit;
}
if (!$motivo || trim($motivo) === '') {
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=motivo_required");
exit;
}
// Verificar sesión del usuario administrador
if (!isset($_SESSION['usuario_id']) || empty($_SESSION['usuario_id'])) {
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=session_error");
exit;
}
try {
// Obtener la solicitud
$sql = "SELECT * FROM solicitudes_importadores WHERE request_id = ?";
$stmt = sqlsrv_query($conn, $sql, [$id]);
if (!$stmt) {
throw new Exception("Error en consulta de solicitud: " . print_r(sqlsrv_errors(), true));
}
$solicitud = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (!$solicitud) {
throw new Exception("Solicitud no encontrada");
}
// Validar que no haya sido procesada ya
if ($solicitud['request_status'] === 'denied') {
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=already_denied");
exit;
}
if ($solicitud['request_status'] === 'approved') {
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=already_approved");
exit;
}
// Preparar datos para el correo
$nombre = !empty($solicitud['company_name']) ? decrypt($solicitud['company_name']) : 'Usuario';
$email = $solicitud['email'] ?? null;
if (empty($email)) {
throw new Exception("Email no disponible en la solicitud");
}
// Actualizar solicitud como denegada
$sqlUpdate = "UPDATE solicitudes_importadores
SET request_status = 'denied',
approval_date = GETDATE(),
approved_by = ?
WHERE request_id = ?
";
$stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$_SESSION['usuario_id'], $id]);
if (!$stmtUpdate) {
throw new Exception("Error al actualizar solicitud: " . print_r(sqlsrv_errors(), true));
}
// Enviar correo de notificación de denegación
$mail = new PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = 'secure.emailsrvr.com';
$mail->SMTPAuth = true;
$mail->Username = 'noreply@aduanasoft.com.mx';
$mail->Password = $_ENV['SMTP_PASS'] ?? '';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos');
$mail->addAddress($email);
$mail->CharSet = 'UTF-8';
$mail->isHTML(true);
$mail->Subject = 'Solicitud de registro denegada - SIIH';
$mail->Body = "
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 40px;'>
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;'>
<div style='background: linear-gradient(to right, #dc3545, #c82333); padding: 20px; text-align: center;'>
<h2 style='color: white;'>Solicitud Denegada</h2>
</div>
<div style='padding: 30px; color: #333; font-size: 16px;'>
<p>Estimado(a) <strong>$nombre</strong>,</p>
<p>Lamentamos informarte que tu solicitud de registro como importador en el sistema SIIH ha sido denegada.</p>
<div style='background: #f8f9fa; padding: 15px; border-left: 4px solid #dc3545; margin: 20px 0;'>
<p style='margin: 0; font-weight: bold; color: #dc3545;'>Motivo de la denegación:</p>
<p style='margin: 10px 0 0 0;'>$motivo</p>
</div>
<p>Si consideras que esta decisión es incorrecta o deseas obtener más información, puedes contactarnos para revisar tu caso.</p>
<p>Agradecemos tu interés en formar parte del Sistema Integral para Importadores de Hidrocarburos.</p>
</div>
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
&copy; " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
</div>
</div>
</div>";
$mail->send();
// Éxito completo (solicitud denegada y correo enviado)
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?success=denied");
} catch (Exception $mailException) {
// Error en el correo, pero la solicitud fue denegada exitosamente
error_log("Error al enviar correo de denegación: " . $mailException->getMessage());
// Redirigir con mensaje de éxito parcial
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?success=denied&warning=email_failed");
}
} catch (Exception $e) {
// Log del error para debugging
error_log("Error al denegar usuario: " . $e->getMessage());
// Redirigir con error específico basado en el tipo de error
if (strpos($e->getMessage(), 'Solicitud no encontrada') !== false) {
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=invalid_request");
} elseif (strpos($e->getMessage(), 'Email no disponible') !== false) {
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=email_unavailable");
} else {
header("Location: /IMPORTADORES/administrador/aprobarUsuarios?error=process_failed");
}
}
exit;
}
function altaUsuarios() function altaUsuarios()
{ {
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') { if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {
@@ -649,6 +797,123 @@ function aprobar_agencia()
exit; exit;
} }
function denegar_agencia()
{
$conn = getConnection();
$id = $_GET['id'] ?? null;
$motivo = trim($_POST['motivo'] ?? '');
$usuario_id = $_SESSION['usuario_id'];
// Definir motivo por defecto si no se ingresó uno
if ($motivo === '') {
$motivo = 'La solicitud ha sido rechazada por no cumplir con los requisitos establecidos.';
}
// Validar parámetros
if (!$id || !is_numeric($id)) {
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=invalid_id");
exit;
}
if (!$motivo || trim($motivo) === '') {
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=motivo_required");
exit;
}
// Obtener la solicitud
$sql = "SELECT * FROM solicitudes_agencias WHERE request_id = ?";
$stmt = sqlsrv_query($conn, $sql, [$id]);
$solicitud = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if (!$solicitud) {
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=invalid_request");
exit;
}
// Validar que no haya sido procesada ya
if ($solicitud['request_status'] === 'denied') {
die("⚠️ Esta solicitud ya fue denegada.");
}
if ($solicitud['request_status'] === 'approved') {
die("⚠️ Esta solicitud ya fue aprobada y no se puede denegar.");
}
// Preparar datos para el correo
$nombre = decrypt($solicitud['agencia_name']);
$admin_name = decrypt($solicitud['admin_name']);
$admin_email = $solicitud['admin_email'];
// Actualizar solicitud como denegada
$sqlUpdate = "UPDATE solicitudes_agencias
SET request_status = 'denied',
approval_date = GETDATE(),
approved_by = ?
WHERE request_id = ?
";
$stmtUpdate = sqlsrv_query($conn, $sqlUpdate, [$usuario_id, $id]);
if (!$stmtUpdate) {
header("Location: /IMPORTADORES/administrador/aprobarAgencias?error=update_request_failed");
exit;
}
// Enviar correo de notificación de denegación
$mail = new PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = 'secure.emailsrvr.com';
$mail->SMTPAuth = true;
$mail->Username = 'noreply@aduanasoft.com.mx';
$mail->Password = $_ENV['SMTP_PASS'];
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
$mail->setFrom('noreply@aduanasoft.com.mx', 'SIIH | Sistema Integral para Importadores de Hidrocarburos');
$mail->addAddress($admin_email);
$mail->CharSet = 'UTF-8';
$mail->isHTML(true);
$mail->Subject = 'Solicitud de agencia denegada - SIIH';
$mail->Body = "
<div style='font-family: Segoe UI, sans-serif; background-color: #f4f6f9; padding: 40px;'>
<div style='max-width: 600px; margin: auto; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden;'>
<div style='background: linear-gradient(to right, #dc3545, #c82333); padding: 20px; text-align: center;'>
<h2 style='color: white;'>Solicitud Denegada</h2>
</div>
<div style='padding: 30px; color: #333; font-size: 16px;'>
<p>Estimado(a) <strong>$admin_name</strong>,</p>
<p>Lamentamos informarte que tu solicitud para registrar la agencia <strong>$nombre</strong> en el sistema SIIH ha sido denegada.</p>
<div style='background: #f8f9fa; padding: 15px; border-left: 4px solid #dc3545; margin: 20px 0;'>
<p style='margin: 0; font-weight: bold; color: #dc3545;'>Motivo de la denegación:</p>
<p style='margin: 10px 0 0 0;'>$motivo</p>
</div>
<p>Si consideras que esta decisión es incorrecta o deseas obtener más información, puedes contactarnos para revisar tu caso.</p>
<p>Agradecemos tu interés en formar parte del Sistema Integral para Importadores de Hidrocarburos.</p>
</div>
<div style='background: #e9ecef; text-align: center; padding: 15px; font-size: 13px; color: #666;'>
&copy; " . date('Y') . " SIIH · Sistema Integral para Importadores de Hidrocarburos
</div>
</div>
</div>";
$mail->send();
} catch (Exception $e) {
error_log("Error al enviar correo de denegación: {$mail->ErrorInfo}");
}
// Registrar en bitácora (opcional - crear función específica para denegaciones)
registrar_bitacora_agencia($id, $nombre, 'DENEGACION', $usuario_id);
header("Location: /IMPORTADORES/administrador/aprobarAgencias?success=denied");
exit;
}
function altaAgencias() function altaAgencias()
{ {
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') { if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'super_admin') {

View File

@@ -289,6 +289,8 @@ function desvincularUsuario()
$conn = getConnection(); $conn = getConnection();
try { try {
$stmtActualizarAgencia = null;
// Iniciar transacción // Iniciar transacción
sqlsrv_begin_transaction($conn); sqlsrv_begin_transaction($conn);
@@ -357,9 +359,16 @@ function desvincularUsuario()
} }
// Limpiar statements // Limpiar statements
sqlsrv_free_stmt($stmtVerificar); if (isset($stmtVerificar) && is_resource($stmtVerificar)) {
sqlsrv_free_stmt($stmtDesactivar); sqlsrv_free_stmt($stmtVerificar);
sqlsrv_free_stmt($stmtActualizarAgencia); }
if (isset($stmtDesactivar) && is_resource($stmtDesactivar)) {
sqlsrv_free_stmt($stmtDesactivar);
}
if (isset($stmtActualizarAgencia) && is_resource($stmtActualizarAgencia)) {
sqlsrv_free_stmt($stmtActualizarAgencia);
}
// Confirmar transacción // Confirmar transacción
sqlsrv_commit($conn); sqlsrv_commit($conn);

View File

@@ -98,7 +98,7 @@
<td><?= htmlspecialchars(decrypt($ag['nombre_admin'] ?? '')) ?></td> <td><?= htmlspecialchars(decrypt($ag['nombre_admin'] ?? '')) ?></td>
<td> <td>
<?php if (isset($ag['activo']) && $ag['activo'] == 1): ?> <?php if (isset($ag['activo']) && $ag['activo'] == 1): ?>
<a href="/IMPORTADORES/administrador/suspenderAgencia?id=<?= $ag['id_agencia'] ?>&success=1" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Suspender</a> <a href="#" onclick="confirmSuspencion(<?= (int) ($ag['id_agencia'] ?? 0) ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Suspender</a>
<?php endif; ?> <?php endif; ?>
</td> </td>
</tr> </tr>
@@ -119,6 +119,21 @@
} }
}); });
}); });
function confirmSuspencion(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Solo se suspenderá el perfil del usuario.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, suspender',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/administrador/suspenderAgencia?id=${id}`;
}
});
}
</script> </script>
<?php if (isset($_GET['success'])): ?> <?php if (isset($_GET['success'])): ?>

View File

@@ -228,7 +228,7 @@
<td><?= isset($u['creado_en']) && $u['creado_en'] instanceof DateTime ? $u['creado_en']->format('Y-m-d H:i') : '' ?></td> <td><?= isset($u['creado_en']) && $u['creado_en'] instanceof DateTime ? $u['creado_en']->format('Y-m-d H:i') : '' ?></td>
<td> <td>
<?php if (isset($u['activo']) && $u['activo'] == 1): ?> <?php if (isset($u['activo']) && $u['activo'] == 1): ?>
<a href="/IMPORTADORES/administrador/suspender?id=<?= $u['id_usuario'] ?>&success=1" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Suspender</a> <a href="#" onclick="confirmSuspencion(<?= (int) ($u['id_usuario'] ?? 0) ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Suspender</a>
<?php endif; ?> <?php endif; ?>
</td> </td>
</tr> </tr>
@@ -252,7 +252,8 @@
// Script para manejar las animaciones de validación // Script para manejar las animaciones de validación
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const inputs = document.querySelectorAll('input.form-control, select.form_select'); const inputs = document.querySelectorAll('input.form-control, select.form_select');
const selects = document.querySelectorAll('select.form_select');
inputs.forEach(input => { inputs.forEach(input => {
// Validación en tiempo real // Validación en tiempo real
@@ -309,6 +310,21 @@
}); });
}); });
}); });
function confirmSuspencion(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Esta acción no se puede deshacer.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, suspender',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/administrador/suspender?id=${id}`;
}
});
}
</script> </script>
<?php if (isset($_GET['success'])): ?> <?php if (isset($_GET['success'])): ?>

View File

@@ -106,7 +106,8 @@
<?php endif; ?> <?php endif; ?>
</td> </td>
<td> <td>
<a href="/IMPORTADORES/administrador/aprobar_agencia?id=<?= $s['request_id'] ?>" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Aprobar</a> <a href="#" onclick="confirmAprobacion(<?= $s['request_id'] ?>)" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Aprobar</a>
<a href="#" onclick="denegateRequest(<?= $s['request_id'] ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Denegar</a>
</td> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
@@ -117,6 +118,14 @@
</div> </div>
</div> </div>
<?php if (isset($_GET['success'])): ?>
<script>
<?php if ($_GET['success'] === 'denied'): ?>
Swal.fire({ icon: 'success', title: 'Registro de Agencia denegado', text: 'La solicitud fue denegada.', confirmButtonColor: '#198754' });
<?php endif; ?>
</script>
<?php endif; ?>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$('#tabla-agencias-pendientes').DataTable({ $('#tabla-agencias-pendientes').DataTable({
@@ -126,6 +135,36 @@
} }
}); });
}); });
function confirmAprobacion(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Se creará el perfil y se notificará al usuario.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, aprobar',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/administrador/aprobar_agencia?id=${id}`;
}
});
}
function denegateRequest(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Se denegara la solicitud de registro de la agencia.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, denegar',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/administrador/denegar_agencia?id=${id}`;
}
});
}
</script> </script>
<?php if (isset($_GET['error'])): ?> <?php if (isset($_GET['error'])): ?>

View File

@@ -103,7 +103,8 @@
<?php endif; ?> <?php endif; ?>
</td> </td>
<td> <td>
<a href="/IMPORTADORES/administrador/aprobar_usuario?id=<?= $s['request_id'] ?>" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Aprobar</a> <a href="#" onclick="confirmAprobacion(<?= $s['request_id'] ?>)" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Aprobar</a>
<a href="#" onclick="denegateRequest(<?= $s['request_id'] ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Denegar</a>
</td> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
@@ -123,14 +124,46 @@
} }
}); });
}); });
function confirmAprobacion(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Se creará el perfil y se notificará al usuario.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, aprobar',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/administrador/aprobar_usuario?id=${id}`;
}
});
}
function denegateRequest(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Se denegara la solicitud de registro del usuario.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, denegar',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/administrador/denegar_usuario?id=${id}`;
}
});
}
</script> </script>
<?php if (isset($_GET['success'])): ?> <?php if (isset($_GET['success'])): ?>
<script> <script>
<?php if ($_GET['success'] === 'approved'): ?> <?php if ($_GET['success'] === 'approved'): ?>
Swal.fire({ icon: 'success', title: 'Usuario aprobado', Swal.fire({ icon: 'success', title: 'Usuario aprobado', text: 'El usuario ha sido aprobado correctamente y se ha enviado un correo con las credenciales.', confirmButtonColor: '#198754' });
text: 'El usuario ha sido aprobado correctamente y se ha enviado un correo con las credenciales.', <?php endif; ?>
confirmButtonColor: '#198754' });
<?php if ($_GET['success'] === 'denied'): ?>
Swal.fire({ icon: 'success', title: 'Registro de Usuario denegado', text: 'La solicitud fue denegada.', confirmButtonColor: '#198754' });
<?php endif; ?> <?php endif; ?>
</script> </script>
<?php endif; ?> <?php endif; ?>

View File

@@ -95,8 +95,8 @@
<td><?= isset($u['creado_en']) && $u['creado_en'] instanceof DateTime ? $u['creado_en']->format('Y-m-d H:i') : '' ?></td> <td><?= isset($u['creado_en']) && $u['creado_en'] instanceof DateTime ? $u['creado_en']->format('Y-m-d H:i') : '' ?></td>
<td> <td>
<?php if (isset($u['activo']) && $u['activo'] == 0): ?> <?php if (isset($u['activo']) && $u['activo'] == 0): ?>
<a href="/IMPORTADORES/administrador/activar?id=<?= $u['id_usuario'] ?>&success=1" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Activar</a> <a href="#" onclick="confirmActivacion(<?= (int) ($u['id_usuario'] ?? 0) ?>)" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Activar</a>
<a href="/IMPORTADORES/administrador/reset_password?id=<?= $u['id_usuario'] ?>" class="btn btn-sm btn-secondary mt-auto w-auto btn-animated">Nueva Contraseña</a> <a href="#" onclick="changePassword(<?= (int) ($u['id_usuario'] ?? 0) ?>)" class="btn btn-sm btn-secondary mt-auto w-auto btn-animated">Restablecer</a>
<?php endif; ?> <?php endif; ?>
</td> </td>
</tr> </tr>
@@ -117,6 +117,36 @@
} }
}); });
}); });
function confirmActivacion(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Se reactivara el perfil del usuario.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, reactivar',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/administrador/activar?id=${id}`;
}
});
}
function changePassword(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Se restablecera la contraseña del usuario.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, restablecer',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/administrador/reset_password?id=${id}`;
}
});
}
</script> </script>
<?php if (isset($_GET['success'])): ?> <?php if (isset($_GET['success'])): ?>

View File

@@ -1,179 +1,315 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style> <style>
.nav .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; } /* Estilos inspirados en Tailwind */
.nav .nav-link:hover, .sidebar-container { background-color: #f9fafb; border-right: 1px solid #e5e7eb; }
.nav .nav-link.active { background-color: #495057; color: #fff; } .sidebar-dark { background-color: #1f2937; border-right: 1px solid #374151; }
/* Estilo inverso solo para pantallas pequeñas (sidebar tipo offcanvas) */ .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) { @media (max-width: 767.98px) {
.nav .nav-link { font-weight: normal; color: #343a40; background-color: transparent; } .sidebar-nav .nav-link { color: #374151; }
.nav .nav-link:hover, .sidebar-nav .nav-link:hover { background-color: #f3f4f6; color: #111827; }
.nav .nav-link.active { background-color: #e9ecef; color: #212529; } .sidebar-nav .nav-link.active { background-color: #f3f4f6; color: #111827; }
} }
</style> </style>
<!-- 🔷 NAVBAR --> <!-- NAVBAR -->
<nav class="navbar navbar-dark bg-dark fixed-top"> <nav class="navbar navbar-dark bg-dark fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<!-- Botón de menú para móviles --> <!-- 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">
<svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path clip-rule="evenodd" fill-rule="evenodd" d="M2 4.75A.75.75 0 012.75 4h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 4.75zm0 10.5a.75.75 0 01.75-.75h7.5a.75.75 0 010 1.5h-7.5a.75.75 0 01-.75-.75zM2 10a.75.75 0 01.75-.75h14.5a.75.75 0 010 1.5H2.75A.75.75 0 012 10z"></path>
</svg>
</button> </button>
<span class="navbar-brand">SIIH | Administrador</span> <span class="navbar-brand">SIIH | Administrador</span>
<div class="d-flex ms-auto text-white"> <div class="d-flex ms-auto text-white">
<?php <div id="navbar-content">
// Verifica si estás en el dashboard principal del administrador <?php
$esDashboard = str_contains($_SERVER['REQUEST_URI'], '/administrador/dashboard'); // Verifica si estás en el dashboard principal del administrador
$esDashboard = str_contains($_SERVER['REQUEST_URI'], '/administrador/dashboard');
if ($esDashboard): ?> if ($esDashboard): ?>
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?> <span id="welcome-text">Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?></span>
<?php else: ?> <?php else: ?>
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a> <a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated" id="logout-btn">Cerrar Sesión</a>
<?php endif; ?> <?php endif; ?>
</div>
</div> </div>
</div> </div>
</nav> </nav>
<!-- SIDEBAR FIJA (escritorio) --> <!-- SIDEBAR FIJA (escritorio) -->
<div class="d-none d-md-block bg-dark text-white position-fixed h-100 pt-5" style="width: 250px;"> <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;">
<nav class="nav flex-column"> <div class="px-3 py-4 h-100 overflow-y-auto">
<nav class="sidebar-nav">
<!-- INICIO --> <ul class="nav flex-column">
<a href="/IMPORTADORES/administrador/dashboard" <!-- INICIO -->
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/dashboard') ? 'active' : '' ?>"> <li class="nav-item">
🏠 Inicio <a href="/IMPORTADORES/administrador/dashboard" class="nav-link active">
</a> <svg class="icon" fill="currentColor" viewBox="0 0 22 21">
<path d="M16.975 11H10V4.025a1 1 0 0 0-1.066-.998 8.5 8.5 0 1 0 9.039 9.039.999.999 0 0 0-1-1.066h.002Z"/>
<!-- AGENCIAS --> <path d="M12.5 0c-.157 0-.311.01-.565.027A1 1 0 0 0 11 1.02V10h8.975a1 1 0 0 0 1-.935c.013-.188.028-.374.028-.565A8.51 8.51 0 0 0 12.5 0Z"/>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center </svg>
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador') ? 'active' : '' ?>" <span>Inicio</span>
data-bs-toggle="collapse" href="#submenuAgencias" role="button" aria-expanded="false"> </a>
🏪 Agencias </li>
<span class="badge bg-secondary">3</span> <!-- AGENCIAS -->
</a> <li class="nav-item">
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/administrador') ? 'show' : '' ?>" id="submenuAgencias"> <a class="nav-link" data-bs-toggle="collapse" href="#submenuAgencias" role="button" aria-expanded="false">
<nav class="nav flex-column ms-3"> <svg class="icon" fill="currentColor" viewBox="0 0 18 21">
<a href="/IMPORTADORES/administrador/aprobarAgencias" <path d="M15 12a1 1 0 0 0 .962-.726l2-7A1 1 0 0 0 17 3H3.77L3.175.745A1 1 0 0 0 2.208 0H1a1 1 0 0 0 0 2h.438l.6 2.255v.019l2 7 .746 2.986A3 3 0 1 0 9 17a2.966 2.966 0 0 0-.184-1h2.368c-.118.32-.18.659-.184 1a3 3 0 1 0 3-3H6.78l-.5-2H15Z"/>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/aprobarAgencias') ? 'active' : '' ?>"> </svg>
• Aprobar agencias <span>Agencias</span>
</a> <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
<a href="/IMPORTADORES/administrador/altaAgencias" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/altaAgencias') ? 'active' : '' ?>"> </svg>
• Alta de agencia </a>
</a> <div class="collapse" id="submenuAgencias">
<a href="/IMPORTADORES/administrador/agenciasActivas" <ul class="nav flex-column submenu">
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/agenciasActivas') ? 'active' : '' ?>"> <li class="nav-item">
• Ver agencias <a href="/IMPORTADORES/administrador/aprobarAgencias" class="nav-link">
</a> Aprobar agencias
</nav> </a>
</div> </li>
<li class="nav-item">
<!-- USUARIOS --> <a href="/IMPORTADORES/administrador/altaAgencias" class="nav-link">
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center Alta de agencia
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador') ? 'active' : '' ?>" </a>
data-bs-toggle="collapse" href="#submenuUsuarios" role="button" aria-expanded="false"> </li>
👥 Usuarios <li class="nav-item">
<span class="badge bg-secondary">3</span> <a href="/IMPORTADORES/administrador/agenciasActivas" class="nav-link">
</a> Ver agencias
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/administrador') ? 'show' : '' ?>" id="submenuUsuarios"> </a>
<nav class="nav flex-column ms-3"> </li>
<a href="/IMPORTADORES/administrador/aprobarUsuarios" </ul>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/aprobarUsuarios') ? 'active' : '' ?>"> </div>
• Aprobar usuarios </li>
</a> <!-- USUARIOS -->
<a href="/IMPORTADORES/administrador/altaUsuarios" <li class="nav-item">
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/altaUsuarios') ? 'active' : '' ?>"> <a class="nav-link" data-bs-toggle="collapse" href="#submenuUsuarios" role="button" aria-expanded="false">
• Ver usuarios <svg class="icon" fill="currentColor" viewBox="0 0 20 18">
</a> <path d="M14 2a3.963 3.963 0 0 0-1.4.267 6.439 6.439 0 0 1-1.331 6.638A4 4 0 1 0 14 2Zm1 9h-1.264A6.957 6.957 0 0 1 15 15v2a2.97 2.97 0 0 1-.184 1H19a1 1 0 0 0 1-1v-1a5.006 5.006 0 0 0-5-5ZM6.5 9a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM8 10H5a5.006 5.006 0 0 0-5 5v2a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-2a5.006 5.006 0 0 0-5-5Z"/>
<a href="/IMPORTADORES/administrador/usuariosInactivos" </svg>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/usuariosInactivos') ? 'active' : '' ?>"> <span>Usuarios</span>
• Usuarios inactivos <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
</a> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</nav> </svg>
</div> </a>
<div class="collapse" id="submenuUsuarios">
<!-- CONFIGURACIÓN --> <ul class="nav flex-column submenu">
<a href="/IMPORTADORES/administrador/configuracion" <li class="nav-item">
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/configuracion') ? 'active' : '' ?>"> <a href="/IMPORTADORES/administrador/aprobarUsuarios" class="nav-link">
⚙️ Configuración Aprobar usuarios
</a> </a>
</li>
</nav> <li class="nav-item">
<a href="/IMPORTADORES/administrador/altaUsuarios" class="nav-link">
Alta de usuario
</a>
</li>
<li class="nav-item">
<a href="/IMPORTADORES/administrador/usuariosInactivos" class="nav-link">
Usuarios inactivos
</a>
</li>
</ul>
</div>
</li>
<!-- CONFIGURACIÓN -->
<li class="nav-item">
<a href="/IMPORTADORES/administrador/configuracion" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z"/>
<path d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z"/>
</svg>
<span>Configuración</span>
</a>
</li>
</ul>
</nav>
</div>
</div> </div>
<!-- OFFCANVAS PARA MÓVILES --> <!-- OFFCANVAS PARA MÓVILES -->
<div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu" style="top: 75px;"> <div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu" style="top: 0; width: 250px;">
<div class="offcanvas-header"> <div class="offcanvas-header">
<h5 class="offcanvas-title">Menú</h5> <h5 class="offcanvas-title">Menú</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button> <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div> </div>
<div class="offcanvas-body"> <div class="offcanvas-body">
<nav class="sidebar-nav">
<!-- INICIO --> <ul class="nav flex-column">
<a href="/IMPORTADORES/administrador/dashboard" <!-- INICIO -->
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/dashboard') ? 'active' : '' ?>"> <li class="nav-item">
🏠 Inicio <a href="/IMPORTADORES/administrador/dashboard" class="nav-link active">
</a> <svg class="icon" fill="currentColor" viewBox="0 0 22 21">
<path d="M16.975 11H10V4.025a1 1 0 0 0-1.066-.998 8.5 8.5 0 1 0 9.039 9.039.999.999 0 0 0-1-1.066h.002Z"/>
<!-- AGENCIAS --> <path d="M12.5 0c-.157 0-.311.01-.565.027A1 1 0 0 0 11 1.02V10h8.975a1 1 0 0 0 1-.935c.013-.188.028-.374.028-.565A8.51 8.51 0 0 0 12.5 0Z"/>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center </svg>
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador') ? 'active' : '' ?>" <span>Inicio</span>
data-bs-toggle="collapse" href="#submenuAgencias" role="button" </a>
aria-expanded="<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador') ? 'true' : 'false' ?>" </li>
aria-controls="submenuAgencias"> <!-- AGENCIAS -->
🏪 Agencias <li class="nav-item">
<span class="badge bg-secondary">3</span> <a class="nav-link" data-bs-toggle="collapse" href="#submenuAgenciasMobile" role="button" aria-expanded="false">
</a> <svg class="icon" fill="currentColor" viewBox="0 0 18 21">
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/administrador') ? 'show' : '' ?>" id="submenuAgencias"> <path d="M15 12a1 1 0 0 0 .962-.726l2-7A1 1 0 0 0 17 3H3.77L3.175.745A1 1 0 0 0 2.208 0H1a1 1 0 0 0 0 2h.438l.6 2.255v.019l2 7 .746 2.986A3 3 0 1 0 9 17a2.966 2.966 0 0 0-.184-1h2.368c-.118.32-.18.659-.184 1a3 3 0 1 0 3-3H6.78l-.5-2H15Z"/>
<nav class="nav flex-column ms-3"> </svg>
<a href="/IMPORTADORES/administrador/aprobarAgencias" <span>Agencias</span>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/aprobarAgencias') ? 'active' : '' ?>"> <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
• Aprobar agencias <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</a> </svg>
<a href="/IMPORTADORES/administrador/altaAgencias" </a>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/altaAgencias') ? 'active' : '' ?>"> <div class="collapse" id="submenuAgenciasMobile">
• Alta de agencia <ul class="nav flex-column submenu">
</a> <li class="nav-item">
<a href="/IMPORTADORES/administrador/agenciasActivas" <a href="/IMPORTADORES/administrador/aprobarAgencias" class="nav-link">
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/agenciasActivas') ? 'active' : '' ?>"> Aprobar agencias
• Ver agencias </a>
</a> </li>
</nav> <li class="nav-item">
</div> <a href="/IMPORTADORES/administrador/altaAgencias" class="nav-link">
Alta de agencia
<!-- USUARIOS --> </a>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center </li>
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador') ? 'active' : '' ?>" <li class="nav-item">
data-bs-toggle="collapse" href="#submenuUsuarios" role="button" <a href="/IMPORTADORES/administrador/agenciasActivas" class="nav-link">
aria-expanded="<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador') ? 'true' : 'false' ?>" Ver agencias
aria-controls="submenuUsuarios"> </a>
👥 Usuarios </li>
<span class="badge bg-secondary">4</span> </ul>
</a> </div>
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/administrador') ? 'show' : '' ?>" id="submenuUsuarios"> </li>
<nav class="nav flex-column ms-3"> <!-- USUARIOS -->
<a href="/IMPORTADORES/administrador/aprobarUsuarios" <li class="nav-item">
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/aprobarUsuarios') ? 'active' : '' ?>"> <a class="nav-link" data-bs-toggle="collapse" href="#submenuUsuariosMobile" role="button" aria-expanded="false">
• Aprobar usuarios <svg class="icon" fill="currentColor" viewBox="0 0 20 18">
</a> <path d="M14 2a3.963 3.963 0 0 0-1.4.267 6.439 6.439 0 0 1-1.331 6.638A4 4 0 1 0 14 2Zm1 9h-1.264A6.957 6.957 0 0 1 15 15v2a2.97 2.97 0 0 1-.184 1H19a1 1 0 0 0 1-1v-1a5.006 5.006 0 0 0-5-5ZM6.5 9a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM8 10H5a5.006 5.006 0 0 0-5 5v2a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-2a5.006 5.006 0 0 0-5-5Z"/>
<a href="/IMPORTADORES/administrador/altaUsuarios" </svg>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/altaUsuarios') ? 'active' : '' ?>"> <span>Usuarios</span>
• Alta de usuario <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
</a> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
<a href="/IMPORTADORES/administrador/usuariosActivos" </svg>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/usuariosActivos') ? 'active' : '' ?>"> </a>
• Ver usuarios <div class="collapse" id="submenuUsuariosMobile">
</a> <ul class="nav flex-column submenu">
<a href="/IMPORTADORES/administrador/usuariosInactivos" <li class="nav-item">
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/usuariosInactivos') ? 'active' : '' ?>"> <a href="/IMPORTADORES/administrador/aprobarUsuarios" class="nav-link">
• Usuarios inactivos Aprobar usuarios
</a> </a>
</nav> </li>
</div> <li class="nav-item">
<a href="/IMPORTADORES/administrador/altaUsuarios" class="nav-link">
<!-- CONFIGURACIÓN --> Alta de usuario
<a href="/IMPORTADORES/administrador/configuracion" </a>
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/administrador/configuracion') ? 'active' : '' ?>"> </li>
⚙️ Configuración <li class="nav-item">
</a> <a href="/IMPORTADORES/administrador/usuariosInactivos" class="nav-link">
Usuarios inactivos
</a>
</li>
</ul>
</div>
</li>
<!-- CONFIGURACIÓN -->
<li class="nav-item">
<a href="/IMPORTADORES/administrador/configuracion" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z"/>
<path d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z"/>
</svg>
<span>Configuración</span>
</a>
</li>
</ul>
</nav>
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Simular lógica de dashboard
document.addEventListener('DOMContentLoaded', function() {
const esDashboard = window.location.pathname.includes('/administrador/dashboard');
const welcomeText = document.getElementById('welcome-text');
const logoutBtn = document.getElementById('logout-btn');
if (!esDashboard) {
welcomeText.style.display = 'none';
logoutBtn.style.display = 'inline-block';
}
// Manejar estados activos basados en URL actual
const currentPath = window.location.pathname;
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
const href = link.getAttribute('href');
if (href && currentPath.includes(href)) {
link.classList.add('active');
}
});
// Manejar collapse manualmente
document.querySelectorAll('[data-bs-toggle="collapse"]').forEach(trigger => {
trigger.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);
const isExpanded = this.getAttribute('aria-expanded') === 'true';
if (targetElement) {
if (isExpanded) {
// Cerrar
targetElement.classList.remove('show');
this.setAttribute('aria-expanded', 'false');
} else {
// Abrir
targetElement.classList.add('show');
this.setAttribute('aria-expanded', 'true');
}
}
});
// Remover el atributo data-bs-toggle para evitar conflictos
trigger.removeAttribute('data-bs-toggle');
});
});
</script>

View File

@@ -1,12 +1,49 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style> <style>
.nav .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; } /* Estilos inspirados en Tailwind */
.nav .nav-link:hover, .sidebar-container { background-color: #f9fafb; border-right: 1px solid #e5e7eb; }
.nav .nav-link.active { background-color: #495057; color: #fff; } .sidebar-dark { background-color: #1f2937; border-right: 1px solid #374151; }
/* Estilo inverso solo para pantallas pequeñas (sidebar tipo offcanvas) */ .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) { @media (max-width: 767.98px) {
.nav .nav-link { font-weight: normal; color: #343a40; background-color: transparent; } .sidebar-nav .nav-link { color: #374151; }
.nav .nav-link:hover, .sidebar-nav .nav-link:hover { background-color: #f3f4f6; color: #111827; }
.nav .nav-link.active { background-color: #e9ecef; color: #212529; } .sidebar-nav .nav-link.active { background-color: #f3f4f6; color: #111827; }
} }
</style> </style>
@@ -14,233 +51,299 @@
<nav class="navbar navbar-dark bg-dark fixed-top"> <nav class="navbar navbar-dark bg-dark fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<!-- Botón de menú para móviles --> <!-- 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> </button>
<span class="navbar-brand">SIIH | Agencia Aduanal</span> <span class="navbar-brand">SIIH | Agencia Aduanal</span>
<div class="d-flex ms-auto text-white"> <div class="d-flex ms-auto text-white">
<?php <div class="navbar-content">
// Verifica si estás en el dashboard principal del importador <?php
$esDashboard = str_contains($_SERVER['REQUEST_URI'], '/agencias/dashboard'); // Verifica si estás en el dashboard principal del importador
$esDashboard = str_contains($_SERVER['REQUEST_URI'], '/agencias/dashboard');
if ($esDashboard): ?> if ($esDashboard): ?>
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?> <span id="welcome-text">Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?></span>
<?php else: ?> <?php else: ?>
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a> <a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a>
<?php endif; ?> <?php endif; ?>
</div>
</div> </div>
</div> </div>
</nav> </nav>
<!-- SIDEBAR FIJA (escritorio) --> <!-- SIDEBAR FIJA (escritorio) -->
<div class="d-none d-md-block bg-dark text-white position-fixed h-100 pt-5" style="width: 250px;"> <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;">
<nav class="nav flex-column"> <div class="px-3 py-4 h-100 overflow-y-auto">
<nav class="sidebar-nav">
<?php <ul class="nav flex-column">
// Detecta si estamos en alguna parte de locaciones <!-- INICIO -->
$esVistaLocaciones = str_contains($_SERVER['REQUEST_URI'], '/locaciones'); <li class="nav-item">
// Detecta si estamos en alguna parte de agentes <a href="/IMPORTADORES/agencias/dashboard" class="nav-link active">
$esVistaAdmin = str_contains($_SERVER['REQUEST_URI'], '/agencias'); <svg class="icon" fill="currentColor" viewBox="0 0 22 21">
// Detecta si estamos en alguna parte de agente aduanal <path d="M16.975 11H10V4.025a1 1 0 0 0-1.066-.998 8.5 8.5 0 1 0 9.039 9.039.999.999 0 0 0-1-1.066h.002Z"/>
$esVistaPatente = str_contains($_SERVER['REQUEST_URI'], '/patente'); <path d="M12.5 0c-.157 0-.311.01-.565.027A1 1 0 0 0 11 1.02V10h8.975a1 1 0 0 0 1-.935c.013-.188.028-.374.028-.565A8.51 8.51 0 0 0 12.5 0Z"/>
// Detecta si estamos en alguna parte de vinculación </svg>
$esVistaVinculacion = str_contains($_SERVER['REQUEST_URI'], '/vinculaciones'); <span>Inicio</span>
?>
<!-- INICIO -->
<a href="/IMPORTADORES/agencias/dashboard"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/agencias/dashboard') ? 'active' : '' ?>">
🏠 Inicio
</a>
<!-- SOLICITUDES VINCULACIÓN -->
<a href="/IMPORTADORES/vinculaciones/solicitudesVinculacion"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/vinculaciones/solicitudesVinculacion') ? 'active' : '' ?>">
🔗 Vinculación
</a>
<!-- USUARIOS ACTIVOS -->
<a href="/IMPORTADORES/vinculaciones/vinculacionesAgencia"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/vinculaciones/vinculacionesAgencia') ? 'active' : '' ?>">
👥 Usuarios Vinculados
</a>
<!-- PATENTES -->
<?php if ($esVistaPatente): ?>
<?php $enDashboardPatente = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/dashboard'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaPatente ? 'active' : '' ?>"
href="<?= $enDashboardPatente ? '#submenuAgentesAduanales' : 'IMPORTADORES/patente/dashboard' ?>"
<?= $enDashboardPatente ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuAgentesAduanales"
onclick="<?= $enDashboardPatente ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/patente/dashboard\';' ?>">
📑 Patentes
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse show" id="submenuAgentesAduanales">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/patente/lista"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/lista' ? 'active' : '' ?>">
• Ver Patentes
</a> </a>
<a href="/IMPORTADORES/patente/alta" </li>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/patente/alta') ? 'active' : '' ?>"> <!-- SOLICITUDES VINCULACIÓN -->
• Nueva Patente <li class="nav-item">
<a href="/IMPORTADORES/vinculaciones/solicitudesVinculacion" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5z"/>
<path d="M7.414 15.414a2 2 0 01-2.828-2.828l3-3a2 2 0 012.828 0 1 1 0 001.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5z"/>
</svg>
<span>Vinculación</span>
</a> </a>
</nav> </li>
</div> <!-- USUARIOS VINCULADOS -->
<?php elseif ($esVistaAdmin || $esVistaLocaciones || $esVistaVinculacion): ?> <li class="nav-item">
<a href="/IMPORTADORES/patente/dashboard" <a href="/IMPORTADORES/vinculaciones/vinculacionesAgencia" class="nav-link">
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
📑 Patentes <path d="M14 2a3.963 3.963 0 0 0-1.4.267 6.439 6.439 0 0 1-1.331 6.638A4 4 0 1 0 14 2Zm1 9h-1.264A6.957 6.957 0 0 1 15 15v2a2.97 2.97 0 0 1-.184 1H19a1 1 0 0 0 1-1v-1a5.006 5.006 0 0 0-5-5ZM6.5 9a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM8 10H5a5.006 5.006 0 0 0-5 5v2a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-2a5.006 5.006 0 0 0-5-5Z"/>
<span class="badge bg-secondary">2</span> </svg>
</a> <span>Usuarios Vinculados</span>
<?php endif; ?> </a>
</li>
<!-- LOCACIONES --> <!-- Patentes -->
<?php if ($esVistaLocaciones): ?> <li class="nav-item">
<?php $enDashboardLocaciones = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista'; ?> <a class="nav-link" data-bs-toggle="collapse" href="#submenuPatentes" role="button" aria-expanded="false">
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaLocaciones ? 'active' : '' ?>" <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
href="<?= $enDashboardLocaciones ? '#submenuLocaciones' : '/IMPORTADORES/locaciones/lista' ?>" <path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z" clip-rule="evenodd"/>
<?= $enDashboardLocaciones ? 'data-bs-toggle="collapse"' : '' ?> </svg>
role="button" aria-expanded="true" aria-controls="submenuLocaciones" <span>Patentes</span>
onclick="<?= $enDashboardLocaciones ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/locaciones/lista\';' ?>"> <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
🗺️ Locaciones <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
<span class="badge bg-secondary">2</span> </svg>
</a> </a>
<div class="collapse show" id="submenuLocaciones"> <div class="collapse" id="submenuPatentes">
<nav class="nav flex-column ms-3"> <ul class="nav flex-column submenu">
<a href="/IMPORTADORES/locaciones/lista" <li class="nav-item">
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista' ? 'active' : '' ?>"> <a href="/IMPORTADORES/patente/lista" class="nav-link">
Ver Locaciones Ver Patentes
</a> </a>
<a href="/IMPORTADORES/locaciones/alta" </li>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/locaciones/alta') ? 'active' : '' ?>"> <li class="nav-item">
• Agregar Locaciones <a href="/IMPORTADORES/patente/alta" class="nav-link">
</a> Nueva Patente
</nav> </a>
</div> </li>
<?php elseif ($esVistaAdmin || $esVistaPatente || $esVistaVinculacion): ?> </ul>
<a href="/IMPORTADORES/locaciones/lista" </div>
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> </li>
🗺️ Locaciones <!-- LOCACIONES -->
<span class="badge bg-secondary">2</span> <li class="nav-item">
</a> <a class="nav-link" data-bs-toggle="collapse" href="#submenuLocaciones" role="button" aria-expanded="false">
<?php endif; ?> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 2C6.686 2 4 4.686 4 8c0 5.25 6 12 6 12s6-6.75 6-12c0-3.314-2.686-6-6-6zm0 8c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2z"/>
<!-- ALTA DE AGENTES --> </svg>
<a href="/IMPORTADORES/agencias/alta" <span>Locaciones</span>
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/agencias/alta') ? 'active' : '' ?>"> <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
📥 Alta de Agentes <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</a> </svg>
</a>
<!-- CONFIGURACIÓN --> <div class="collapse" id="submenuLocaciones">
<a href="/IMPORTADORES/configuracion" <ul class="nav flex-column submenu">
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion') ? 'active' : '' ?>"> <li class="nav-item">
⚙️ Configuración <a href="/IMPORTADORES/locaciones/lista" class="nav-link">
</a> Ver Locaciones
</a>
</nav> </li>
<li class="nav-item">
<a href="/IMPORTADORES/locaciones/alta" class="nav-link">
Agregar Locaciones
</a>
</li>
</ul>
</div>
</li>
<!-- ALTA DE AGENTES -->
<li class="nav-item">
<a href="/IMPORTADORES/agencias/alta" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"/>
</svg>
<span>Alta de agentes</span>
</a>
</li>
<!-- CONFIGURACIÓN -->
<li class="nav-item">
<a href="/IMPORTADORES/configuracion" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z"/>
<path d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z"/>
</svg>
<span>Configuración</span>
</a>
</li>
</ul>
</nav>
</div>
</div> </div>
<!-- OFFCANVAS PARA MÓVILES --> <!-- 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"> <div class="offcanvas-header">
<h5 class="offcanvas-title">Menú</h5> <h5 class="offcanvas-title">Menú</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button> <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div> </div>
<div class="offcanvas-body"> <div class="offcanvas-body">
<nav class="sidebar-nav">
<!-- INICIO --> <ul class="nav flex-column">
<a href="/IMPORTADORES/agencias/dashboard" <!-- INICIO -->
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/agencias/dashboard') ? 'active' : '' ?>"> <li class="nav-item">
🏠 Inicio <a href="/IMPORTADORES/agentes/dashboard" class="nav-link active">
</a> <svg class="icon" fill="currentColor" viewBox="0 0 22 21">
<path d="M16.975 11H10V4.025a1 1 0 0 0-1.066-.998 8.5 8.5 0 1 0 9.039 9.039.999.999 0 0 0-1-1.066h.002Z"/>
<!-- SOLICITUDES VINCULACIÓN --> <path d="M12.5 0c-.157 0-.311.01-.565.027A1 1 0 0 0 11 1.02V10h8.975a1 1 0 0 0 1-.935c.013-.188.028-.374.028-.565A8.51 8.51 0 0 0 12.5 0Z"/>
<a href="/IMPORTADORES/vinculaciones/solicitudesVinculacion" </svg>
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/vinculaciones/solicitudesVinculacion') ? 'active' : '' ?>"> <span>Inicio</span>
🔗 Vinculación
</a>
<!-- USUARIOS ACTIVOS -->
<a href="/IMPORTADORES/vinculaciones/vinculacionesAgencia"
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/vinculaciones/vinculacionesAgencia') ? 'active' : '' ?>">
👥 Usuarios Vinculados
</a>
<!-- PATENTES -->
<?php if ($esVistaPatente): ?>
<?php $enDashboardPatente = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/dashboard'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaPatente ? 'active' : '' ?>"
href="<?= $enDashboardPatente ? '#submenuAgentesAduanales' : 'IMPORTADORES/patente/dashboard' ?>"
<?= $enDashboardPatente ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuAgentesAduanales"
onclick="<?= $enDashboardPatente ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/patente/dashboard\';' ?>">
📑 Patentes
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse show" id="submenuAgentesAduanales">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/patente/lista"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/lista' ? 'active' : '' ?>">
• Ver Patentes
</a> </a>
<a href="/IMPORTADORES/patente/alta" </li>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/patente/alta') ? 'active' : '' ?>"> <!-- SOLICITUDES VINCULACIÓN -->
• Nueva Patente <li class="nav-item">
<a href="/IMPORTADORES/vinculaciones/solicitudesVinculacion" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5z"/>
<path d="M7.414 15.414a2 2 0 01-2.828-2.828l3-3a2 2 0 012.828 0 1 1 0 001.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5z"/>
</svg>
<span>Vinculación</span>
</a> </a>
</nav> </li>
</div> <!-- USUARIOS VINCULADOS -->
<?php elseif ($esVistaAdmin || $esVistaLocaciones || $esVistaVinculacion): ?> <li class="nav-item">
<a href="/IMPORTADORES/patente/dashboard" <a href="/IMPORTADORES/vinculaciones/vinculacionesAgencia" class="nav-link">
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
📑 Patentes <path d="M14 2a3.963 3.963 0 0 0-1.4.267 6.439 6.439 0 0 1-1.331 6.638A4 4 0 1 0 14 2Zm1 9h-1.264A6.957 6.957 0 0 1 15 15v2a2.97 2.97 0 0 1-.184 1H19a1 1 0 0 0 1-1v-1a5.006 5.006 0 0 0-5-5ZM6.5 9a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM8 10H5a5.006 5.006 0 0 0-5 5v2a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-2a5.006 5.006 0 0 0-5-5Z"/>
<span class="badge bg-secondary">2</span> </svg>
</a> <span>Usuarios Vinculados</span>
<?php endif; ?> </a>
</li>
<!-- LOCACIONES --> <!-- Patentes -->
<?php if ($esVistaLocaciones): ?> <li class="nav-item">
<?php $enDashboardLocaciones = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista'; ?> <a class="nav-link" data-bs-toggle="collapse" href="#submenuPatentes" role="button" aria-expanded="false">
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaLocaciones ? 'active' : '' ?>" <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
href="<?= $enDashboardLocaciones ? '#submenuLocaciones' : '/IMPORTADORES/locaciones/lista' ?>" <path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z" clip-rule="evenodd"/>
<?= $enDashboardLocaciones ? 'data-bs-toggle="collapse"' : '' ?> </svg>
role="button" aria-expanded="true" aria-controls="submenuLocaciones" <span>Patentes</span>
onclick="<?= $enDashboardLocaciones ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/locaciones/lista\';' ?>"> <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
🗺️ Locaciones <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
<span class="badge bg-secondary">2</span> </svg>
</a> </a>
<div class="collapse show" id="submenuLocaciones"> <div class="collapse" id="submenuPatentes">
<nav class="nav flex-column ms-3"> <ul class="nav flex-column submenu">
<a href="/IMPORTADORES/locaciones/lista" <li class="nav-item">
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista' ? 'active' : '' ?>"> <a href="/IMPORTADORES/patente/lista" class="nav-link">
Ver Locaciones Ver Patentes
</a> </a>
<a href="/IMPORTADORES/locaciones/alta" </li>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/locaciones/alta') ? 'active' : '' ?>"> <li class="nav-item">
• Agregar Locaciones <a href="/IMPORTADORES/patente/alta" class="nav-link">
</a> Nueva Patente
</nav> </a>
</div> </li>
<?php elseif ($esVistaAdmin || $esVistaPatente || $esVistaVinculacion): ?> </ul>
<a href="/IMPORTADORES/locaciones/lista" </div>
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> </li>
🗺️ Locaciones <!-- LOCACIONES -->
<span class="badge bg-secondary">2</span> <li class="nav-item">
</a> <a class="nav-link" data-bs-toggle="collapse" href="#submenuLocaciones" role="button" aria-expanded="false">
<?php endif; ?> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 2C6.686 2 4 4.686 4 8c0 5.25 6 12 6 12s6-6.75 6-12c0-3.314-2.686-6-6-6zm0 8c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2z"/>
<!-- ALTA DE AGENTES --> </svg>
<a href="/IMPORTADORES/agencias/alta" <span>Locaciones</span>
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/agencias/alta') ? 'active' : '' ?>"> <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
📥 Alta de Agentes <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</a> </svg>
</a>
<!-- CONFIGURACIÓN --> <div class="collapse" id="submenuLocaciones">
<a href="/IMPORTADORES/configuracion" <ul class="nav flex-column submenu">
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion') ? 'active' : '' ?>"> <li class="nav-item">
⚙️ Configuración <a href="/IMPORTADORES/locaciones/lista" class="nav-link">
</a> Ver Locaciones
</a>
</li>
<li class="nav-item">
<a href="/IMPORTADORES/locaciones/alta" class="nav-link">
Agregar Locaciones
</a>
</li>
</ul>
</div>
</li>
<!-- ALTA DE AGENTES -->
<li class="nav-item">
<a href="/IMPORTADORES/agencias/alta" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clip-rule="evenodd"/>
</svg>
<span>Alta de agentes</span>
</a>
</li>
<!-- CONFIGURACIÓN -->
<li class="nav-item">
<a href="/IMPORTADORES/configuracion" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z"/>
<path d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z"/>
</svg>
<span>Configuración</span>
</a>
</li>
</ul>
</nav>
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Simular lógica de dashboard
document.addEventListener('DOMContentLoaded', function() {
const esDashboard = window.location.pathname.includes('/administrador/dashboard');
const welcomeText = document.getElementById('welcome-text');
const logoutBtn = document.getElementById('logout-btn');
if (!esDashboard) {
welcomeText.style.display = 'none';
logoutBtn.style.display = 'inline-block';
}
// Manejar estados activos basados en URL actual
const currentPath = window.location.pathname;
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
const href = link.getAttribute('href');
if (href && currentPath.includes(href)) {
link.classList.add('active');
}
});
// Manejar collapse manualmente
document.querySelectorAll('[data-bs-toggle="collapse"]').forEach(trigger => {
trigger.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);
const isExpanded = this.getAttribute('aria-expanded') === 'true';
if (targetElement) {
if (isExpanded) {
// Cerrar
targetElement.classList.remove('show');
this.setAttribute('aria-expanded', 'false');
} else {
// Abrir
targetElement.classList.add('show');
this.setAttribute('aria-expanded', 'true');
}
}
});
// Remover el atributo data-bs-toggle para evitar conflictos
trigger.removeAttribute('data-bs-toggle');
});
});
</script>

View File

@@ -1,12 +1,49 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style> <style>
.nav .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; } /* Estilos inspirados en Tailwind */
.nav .nav-link:hover, .sidebar-container { background-color: #f9fafb; border-right: 1px solid #e5e7eb; }
.nav .nav-link.active { background-color: #495057; color: #fff; } .sidebar-dark { background-color: #1f2937; border-right: 1px solid #374151; }
/* Estilo inverso solo para pantallas pequeñas (sidebar tipo offcanvas) */ .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) { @media (max-width: 767.98px) {
.nav .nav-link { font-weight: normal; color: #343a40; background-color: transparent; } .sidebar-nav .nav-link { color: #374151; }
.nav .nav-link:hover, .sidebar-nav .nav-link:hover { background-color: #f3f4f6; color: #111827; }
.nav .nav-link.active { background-color: #e9ecef; color: #212529; } .sidebar-nav .nav-link.active { background-color: #f3f4f6; color: #111827; }
} }
</style> </style>
@@ -14,207 +51,263 @@
<nav class="navbar navbar-dark bg-dark fixed-top"> <nav class="navbar navbar-dark bg-dark fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<!-- Botón de menú para móviles --> <!-- 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> </button>
<span class="navbar-brand">SIIH | Agente Aduanal</span> <span class="navbar-brand">SIIH | Agente Aduanal</span>
<div class="d-flex ms-auto text-white"> <div class="d-flex ms-auto text-white">
<?php <div class="navbar-content">
// Verifica si estás en el dashboard principal del importador <?php
$esDashboard = str_contains($_SERVER['REQUEST_URI'], '/agentes/dashboard'); // Verifica si estás en el dashboard principal del importador
$esDashboard = str_contains($_SERVER['REQUEST_URI'], '/agentes/dashboard');
if ($esDashboard): ?> if ($esDashboard): ?>
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?> <span id="welcome-text">Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?></span>
<?php else: ?> <?php else: ?>
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a> <a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm ms-2 W-auto btn-animated">Cerrar Sesión</a>
<?php endif; ?> <?php endif; ?>
</div>
</div> </div>
</div> </div>
</nav> </nav>
<!-- SIDEBAR FIJA (escritorio) --> <!-- SIDEBAR FIJA (escritorio) -->
<div class="d-none d-md-block bg-dark text-white position-fixed h-100 pt-5" style="width: 250px;"> <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;">
<nav class="nav flex-column"> <div class="px-3 py-4 h-100 overflow-y-auto">
<nav class="sidebar-nav">
<?php <ul class="nav flex-column">
// Detecta si estamos en alguna parte de locaciones <!-- INICIO -->
$esVistaLocaciones = str_contains($_SERVER['REQUEST_URI'], '/locaciones'); <li class="nav-item">
// Detecta si estamos en alguna parte de agentes <a href="/IMPORTADORES/agentes/dashboard" class="nav-link active">
$esVistaAgentes = str_contains($_SERVER['REQUEST_URI'], '/agentes'); <svg class="icon" fill="currentColor" viewBox="0 0 22 21">
// Detecta si estamos en alguna parte de agente aduanal <path d="M16.975 11H10V4.025a1 1 0 0 0-1.066-.998 8.5 8.5 0 1 0 9.039 9.039.999.999 0 0 0-1-1.066h.002Z"/>
$esVistaPatente = str_contains($_SERVER['REQUEST_URI'], '/patente'); <path d="M12.5 0c-.157 0-.311.01-.565.027A1 1 0 0 0 11 1.02V10h8.975a1 1 0 0 0 1-.935c.013-.188.028-.374.028-.565A8.51 8.51 0 0 0 12.5 0Z"/>
?> </svg>
<span>Inicio</span>
<!-- INICIO -->
<a href="/IMPORTADORES/agentes/dashboard"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/dashboard' ? 'active' : '' ?>">
🏠 Inicio
</a>
<!-- IMPORTADORES VINCULADOS -->
<a href="/IMPORTADORES/agentes/vinculados"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/vinculados' ? 'active' : '' ?>">
🔗 Vinculados
</a>
<!-- Patentes -->
<?php if ($esVistaPatente): ?>
<?php $enDashboardPatente = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/dashboard'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaPatente ? 'active' : '' ?>"
href="<?= $enDashboardPatente ? '#submenuAgentesAduanales' : 'IMPORTADORES/patente/dashboard' ?>"
<?= $enDashboardPatente ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuAgentesAduanales"
onclick="<?= $enDashboardPatente ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/patente/dashboard\';' ?>">
📑 Patentes
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse show" id="submenuAgentesAduanales">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/patente/lista"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/lista' ? 'active' : '' ?>">
• Ver Patentes
</a> </a>
<a href="/IMPORTADORES/patente/alta" </li>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/patente/alta') ? 'active' : '' ?>"> <!-- IMPORTADORES VINCULADOS -->
• Nueva Patente <li class="nav-item">
<a href="/IMPORTADORES/agentes/vinculados" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5z"/>
<path d="M7.414 15.414a2 2 0 01-2.828-2.828l3-3a2 2 0 012.828 0 1 1 0 001.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5z"/>
</svg>
<span>Vinculación</span>
</a> </a>
</nav> </li>
</div> <!-- Patentes -->
<?php elseif ($esVistaAgentes || $esVistaLocaciones): ?> <li class="nav-item">
<a href="/IMPORTADORES/patente/dashboard" <a class="nav-link" data-bs-toggle="collapse" href="#submenuPatentes" role="button" aria-expanded="false">
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
📑 Patentes <path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z" clip-rule="evenodd"/>
<span class="badge bg-secondary">2</span> </svg>
</a> <span>Patentes</span>
<?php endif; ?> <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"/>
<!-- LOCACIONES --> </svg>
<?php if ($esVistaLocaciones): ?> </a>
<?php $enDashboardLocaciones = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista'; ?> <div class="collapse" id="submenuPatentes">
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaLocaciones ? 'active' : '' ?>" <ul class="nav flex-column submenu">
href="<?= $enDashboardLocaciones ? '#submenuLocaciones' : '/IMPORTADORES/locaciones/lista' ?>" <li class="nav-item">
<?= $enDashboardLocaciones ? 'data-bs-toggle="collapse"' : '' ?> <a href="/IMPORTADORES/patente/lista" class="nav-link">
role="button" aria-expanded="true" aria-controls="submenuLocaciones" Ver Patentes
onclick="<?= $enDashboardLocaciones ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/locaciones/lista\';' ?>"> </a>
🗺️ Locaciones </li>
<span class="badge bg-secondary">2</span> <li class="nav-item">
</a> <a href="/IMPORTADORES/patente/alta" class="nav-link">
<div class="collapse show" id="submenuLocaciones"> Nueva Patente
<nav class="nav flex-column ms-3"> </a>
<a href="/IMPORTADORES/locaciones/lista" </li>
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista' ? 'active' : '' ?>"> </ul>
• Ver Locaciones </div>
</a> </li>
<a href="/IMPORTADORES/locaciones/alta" <!-- LOCACIONES -->
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/locaciones/alta') ? 'active' : '' ?>"> <li class="nav-item">
• Agregar Locaciones <a class="nav-link" data-bs-toggle="collapse" href="#submenuLocaciones" role="button" aria-expanded="false">
</a> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
</nav> <path d="M10 2C6.686 2 4 4.686 4 8c0 5.25 6 12 6 12s6-6.75 6-12c0-3.314-2.686-6-6-6zm0 8c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2z"/>
</div> </svg>
<?php elseif ($esVistaAgentes || $esVistaPatente): ?> <span>Locaciones</span>
<a href="/IMPORTADORES/locaciones/lista" <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
🗺️ Locaciones </svg>
<span class="badge bg-secondary">2</span> </a>
</a> <div class="collapse" id="submenuLocaciones">
<?php endif; ?> <ul class="nav flex-column submenu">
<li class="nav-item">
<!-- CONFIGURACIÓN --> <a href="/IMPORTADORES/locaciones/lista" class="nav-link">
<a href="/IMPORTADORES/configuracion" Ver Locaciones
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion') ? 'active' : '' ?>"> </a>
⚙️ Configuración </li>
</a> <li class="nav-item">
<a href="/IMPORTADORES/locaciones/alta" class="nav-link">
</nav> Agregar Locaciones
</a>
</li>
</ul>
</div>
</li>
<!-- CONFIGURACIÓN -->
<li class="nav-item">
<a href="/IMPORTADORES/configuracion" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z"/>
<path d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z"/>
</svg>
<span>Configuración</span>
</a>
</li>
</ul>
</nav>
</div>
</div> </div>
<!-- OFFCANVAS PARA MÓVILES --> <!-- 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"> <div class="offcanvas-header">
<h5 class="offcanvas-title">Menú</h5> <h5 class="offcanvas-title">Menú</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button> <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div> </div>
<div class="offcanvas-body"> <div class="offcanvas-body">
<nav class="sidebar-nav">
<!-- INICIO --> <ul class="nav flex-column">
<a href="/IMPORTADORES/agentes/dashboard" <!-- INICIO -->
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/dashboard' ? 'active' : '' ?>"> <li class="nav-item">
🏠 Inicio <a href="/IMPORTADORES/agentes/dashboard" class="nav-link active">
</a> <svg class="icon" fill="currentColor" viewBox="0 0 22 21">
<path d="M16.975 11H10V4.025a1 1 0 0 0-1.066-.998 8.5 8.5 0 1 0 9.039 9.039.999.999 0 0 0-1-1.066h.002Z"/>
<!-- IMPORTADORES VINCULADOS --> <path d="M12.5 0c-.157 0-.311.01-.565.027A1 1 0 0 0 11 1.02V10h8.975a1 1 0 0 0 1-.935c.013-.188.028-.374.028-.565A8.51 8.51 0 0 0 12.5 0Z"/>
<a href="/IMPORTADORES/agentes/vinculados" </svg>
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/vinculados' ? 'active' : '' ?>"> <span>Inicio</span>
🔗 Vinculados
</a>
<!-- Patentes -->
<?php if ($esVistaPatente): ?>
<?php $enDashboardPatente = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/dashboard'; ?>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaPatente ? 'active' : '' ?>"
href="<?= $enDashboardPatente ? '#submenuAgentesAduanales' : 'IMPORTADORES/patente/dashboard' ?>"
<?= $enDashboardPatente ? 'data-bs-toggle="collapse"' : '' ?>
role="button" aria-expanded="true" aria-controls="submenuAgentesAduanales"
onclick="<?= $enDashboardPatente ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/patente/dashboard\';' ?>">
📑 Patentes
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse show" id="submenuAgentesAduanales">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/patente/lista"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/patente/lista' ? 'active' : '' ?>">
• Ver Patentes
</a> </a>
<a href="/IMPORTADORES/patente/alta" </li>
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/patente/alta') ? 'active' : '' ?>"> <!-- IMPORTADORES VINCULADOS -->
• Nueva Patente <li class="nav-item">
<a href="/IMPORTADORES/agentes/vinculados" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5z"/>
<path d="M7.414 15.414a2 2 0 01-2.828-2.828l3-3a2 2 0 012.828 0 1 1 0 001.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5z"/>
</svg>
<span>Vinculación</span>
</a> </a>
</nav> </li>
</div> <!-- Patentes -->
<?php elseif ($esVistaAgentes || $esVistaLocaciones): ?> <li class="nav-item">
<a href="/IMPORTADORES/patente/dashboard" <a class="nav-link" data-bs-toggle="collapse" href="#submenuPatentes" role="button" aria-expanded="false">
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
📑 Patentes <path fill-rule="evenodd" d="M4 4a2 2 0 012-2h4.586A2 2 0 0112 2.586L15.414 6A2 2 0 0116 7.414V16a2 2 0 01-2 2H6a2 2 0 01-2-2V4zm2 6a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7z" clip-rule="evenodd"/>
<span class="badge bg-secondary">2</span> </svg>
</a> <span>Patentes</span>
<?php endif; ?> <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"/>
<!-- LOCACIONES --> </svg>
<?php if ($esVistaLocaciones): ?> </a>
<?php $enDashboardLocaciones = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista'; ?> <div class="collapse" id="submenuPatentes">
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaLocaciones ? 'active' : '' ?>" <ul class="nav flex-column submenu">
href="<?= $enDashboardLocaciones ? '#submenuLocaciones' : '/IMPORTADORES/locaciones/lista' ?>" <li class="nav-item">
<?= $enDashboardLocaciones ? 'data-bs-toggle="collapse"' : '' ?> <a href="/IMPORTADORES/patente/lista" class="nav-link">
role="button" aria-expanded="true" aria-controls="submenuLocaciones" Ver Patentes
onclick="<?= $enDashboardLocaciones ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/locaciones/lista\';' ?>"> </a>
🗺️ Locaciones </li>
<span class="badge bg-secondary">2</span> <li class="nav-item">
</a> <a href="/IMPORTADORES/patente/alta" class="nav-link">
<div class="collapse show" id="submenuLocaciones"> Nueva Patente
<nav class="nav flex-column ms-3"> </a>
<a href="/IMPORTADORES/locaciones/lista" </li>
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/locaciones/lista' ? 'active' : '' ?>"> </ul>
• Ver Locaciones </div>
</a> </li>
<a href="/IMPORTADORES/locaciones/alta" <!-- LOCACIONES -->
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/locaciones/alta') ? 'active' : '' ?>"> <li class="nav-item">
• Agregar Locaciones <a class="nav-link" data-bs-toggle="collapse" href="#submenuLocaciones" role="button" aria-expanded="false">
</a> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
</nav> <path d="M10 2C6.686 2 4 4.686 4 8c0 5.25 6 12 6 12s6-6.75 6-12c0-3.314-2.686-6-6-6zm0 8c-1.105 0-2-.895-2-2s.895-2 2-2 2 .895 2 2-.895 2-2 2z"/>
</div> </svg>
<?php elseif ($esVistaAgentes || $esVistaPatente): ?> <span>Locaciones</span>
<a href="/IMPORTADORES/locaciones/lista" <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
🗺️ Locaciones </svg>
<span class="badge bg-secondary">2</span> </a>
</a> <div class="collapse" id="submenuLocaciones">
<?php endif; ?> <ul class="nav flex-column submenu">
<li class="nav-item">
<!-- CONFIGURACIÓN --> <a href="/IMPORTADORES/locaciones/lista" class="nav-link">
<a href="/IMPORTADORES/configuracion" Ver Locaciones
class="nav-link px-3 py-2 <?= str_contains($_SERVER['REQUEST_URI'], '/configuracion') ? 'active' : '' ?>"> </a>
⚙️ Configuración </li>
</a> <li class="nav-item">
<a href="/IMPORTADORES/locaciones/alta" class="nav-link">
Agregar Locaciones
</a>
</li>
</ul>
</div>
</li>
<!-- CONFIGURACIÓN -->
<li class="nav-item">
<a href="/IMPORTADORES/configuracion" class="nav-link">
<svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<path d="M5 5V.13a2.96 2.96 0 0 0-1.293.749L.879 3.707A2.96 2.96 0 0 0 .13 5H5Z"/>
<path d="M6.737 11.061a2.961 2.961 0 0 1 .81-1.515l6.117-6.116A4.839 4.839 0 0 1 16 2.141V2a1.97 1.97 0 0 0-1.933-2H7v5a2 2 0 0 1-2 2H0v11a1.969 1.969 0 0 0 1.933 2h12.134A1.97 1.97 0 0 0 16 18v-3.093l-1.546 1.546c-.413.413-.94.695-1.513.81l-3.4.679a2.947 2.947 0 0 1-1.85-.227 2.96 2.96 0 0 1-1.635-3.257l.681-3.397Z"/>
</svg>
<span>Configuración</span>
</a>
</li>
</ul>
</nav>
</div> </div>
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Simular lógica de dashboard
document.addEventListener('DOMContentLoaded', function() {
const esDashboard = window.location.pathname.includes('/administrador/dashboard');
const welcomeText = document.getElementById('welcome-text');
const logoutBtn = document.getElementById('logout-btn');
if (!esDashboard) {
welcomeText.style.display = 'none';
logoutBtn.style.display = 'inline-block';
}
// Manejar estados activos basados en URL actual
const currentPath = window.location.pathname;
const navLinks = document.querySelectorAll('.nav-link');
navLinks.forEach(link => {
const href = link.getAttribute('href');
if (href && currentPath.includes(href)) {
link.classList.add('active');
}
});
// Manejar collapse manualmente
document.querySelectorAll('[data-bs-toggle="collapse"]').forEach(trigger => {
trigger.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
const targetId = this.getAttribute('href');
const targetElement = document.querySelector(targetId);
const isExpanded = this.getAttribute('aria-expanded') === 'true';
if (targetElement) {
if (isExpanded) {
// Cerrar
targetElement.classList.remove('show');
this.setAttribute('aria-expanded', 'false');
} else {
// Abrir
targetElement.classList.add('show');
this.setAttribute('aria-expanded', 'true');
}
}
});
// Remover el atributo data-bs-toggle para evitar conflictos
trigger.removeAttribute('data-bs-toggle');
});
});
</script>

View File

@@ -8,8 +8,7 @@ if (!isset($_SESSION['usuario_id'])) {
// Obtener información del usuario // Obtener información del usuario
$tipoUsuario = $_SESSION['tipo_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 // Definir permisos por tipo de usuario
$permisos = [ $permisos = [
@@ -82,6 +81,15 @@ function contarBitacorasDisponibles($permisosBitacoras) {
$cantidadBitacoras = 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 // Función para obtener el texto descriptivo según el permiso
function obtenerTextoPermiso($permiso, $tipoUsuario) { function obtenerTextoPermiso($permiso, $tipoUsuario) {
$textos = [ $textos = [
@@ -98,22 +106,6 @@ function obtenerTextoPermiso($permiso, $tipoUsuario) {
return $textos[$permiso] ?? ucfirst(str_replace('_', ' ', $permiso)); 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 // Función para obtener la URL según el permiso
function obtenerUrlPermiso($permiso) { function obtenerUrlPermiso($permiso) {
$urls = [ $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> <style>
.nav .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; } /* Estilos inspirados en Tailwind */
.nav .nav-link:hover, .sidebar-container { background-color: #f9fafb; border-right: 1px solid #e5e7eb; }
.nav .nav-link.active { background-color: #495057; color: #fff; } .sidebar-dark { background-color: #1f2937; border-right: 1px solid #374151; }
/* Estilo inverso solo para pantallas pequeñas (sidebar tipo offcanvas) */ .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) { @media (max-width: 767.98px) {
.nav .nav-link { font-weight: normal; color: #343a40; background-color: transparent; } .sidebar-nav .nav-link { color: #374151; }
.nav .nav-link:hover, .sidebar-nav .nav-link:hover { background-color: #f3f4f6; color: #111827; }
.nav .nav-link.active { background-color: #e9ecef; color: #212529; } .sidebar-nav .nav-link.active { background-color: #f3f4f6; color: #111827; }
.permission-scope { background-color: rgba(108, 117, 125, 0.2); } .permission-scope { background-color: rgba(108, 117, 125, 0.2); }
.submenu-item:hover { background-color: rgba(233, 236, 239, 0.8) !important; } .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"> <nav class="navbar navbar-dark bg-dark fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<!-- Botón de menú para móviles --> <!-- 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> </button>
<span class="navbar-brand"> <span class="navbar-brand">
@@ -180,309 +209,224 @@ function obtenerUrlPermiso($permiso) {
</nav> </nav>
<!-- SIDEBAR FIJA (escritorio) --> <!-- SIDEBAR FIJA (escritorio) -->
<div class="d-none d-md-block bg-dark text-white position-fixed h-100 pt-5" style="width: 250px;"> <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;">
<nav class="nav flex-column"> <div class="px-3 py-4 h-100 overflow-y-auto">
<nav class="sidebar-nav">
<!-- Definimos variables de ubicación --> <ul class="nav flex-column">
<?php <!-- INFORMACIÓN GENERAL -->
// Detecta si estamos en alguna parte de configuración <li class="nav-item">
$esConfiguracion = str_contains($_SERVER['REQUEST_URI'], '/configuracion'); <?php if ($permisosUsuario['informacion_general']): ?>
// Detecta si estamos en alguna parte de bitácoras <a href="/IMPORTADORES/configuracion/index" class="nav-link">
$esVistaBitacoras = str_contains($_SERVER['REQUEST_URI'], '/bitacoras'); <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
// Detecta si estamos en alguna parta de seguridad <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" />
$esVistaSeguridad = str_contains($_SERVER['REQUEST_URI'], '/seguridad'); </svg>
// Detecta si estamos en alguna parte de preferencias <span>Información general</span>
$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
</a> </a>
<a href="/IMPORTADORES/preferencias/catalogos" <?php endif; ?>
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/catalogos' ? 'active' : '' ?>"> </li>
• Visualización de Catálogos <!-- 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> </a>
</nav> <?php endif; ?>
</div> </li>
<?php elseif ($esConfiguracion || $esVistaAutomatizaciones || $esVistaSeguridad || $esVistaBitacoras || $esVistaReset): ?> <!-- PREFERENCIAS -->
<a href="/IMPORTADORES/preferencias/index" <li class="nav-item">
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> <?php if ($permisosUsuario['preferencias']): ?>
✅ Preferencias <?php $enDashboardPreferencias = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/preferencias/index'; ?>
<span class="badge bg-secondary">2</span> <a class="nav-link <?= $esVistaPreferencias ? 'active' : '' ?>"
</a> href="<?= $enDashboardPreferencias ? '#submenuPreferencias' : '/IMPORTADORES/preferencias/index' ?>"
<?php endif; ?> <?= $enDashboardPreferencias ? 'data-bs-toggle="collapse"' : '' ?>
<?php endif; ?> role="button" aria-expanded="false" aria-controls="submenuPreferencias"
onclick="<?= $enDashboardPreferencias ? 'return true;' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/preferencias/index\';' ?>">
<!-- SEGURIDAD --> <svg class="icon" fill="currentColor" viewBox="0 0 20 20">
<?php if ($permisosUsuario['seguridad']): ?> <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"/>
<?php if ($esVistaSeguridad): ?> </svg>
<?php $enDashboardSeguridad = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/seguridad/index'; ?> <span>Preferencias</span>
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaSeguridad ? 'active' : '' ?>" <svg class="collapse-icon" fill="none" stroke="currentColor" viewBox="0 0 10 6">
href="<?= $enDashboardSeguridad ? '#submenuSeguridad' : '/IMPORTADORES/seguridad/index' ?>" <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
<?= $enDashboardSeguridad ? 'data-bs-toggle="collapse"' : '' ?> </svg>
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> </a>
</nav> <div class="collapse" id="submenuPreferencias">
</div> <ul class="nav flex-column submenu">
<?php elseif ($esConfiguracion || $esVistaAutomatizaciones || $esVistaPreferencias || $esVistaBitacoras || $esVistaReset): ?> <li class="nav-item">
<a href="/IMPORTADORES/seguridad/index" <a href="/IMPORTADORES/preferencias/notificaciones" class="nav-link">
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center"> Gestión de Notificaciones
👮 Seguridad </a>
<span class="badge bg-secondary">1</span> </li>
</a> <li class="nav-item">
<?php endif; ?> <a href="/IMPORTADORES/preferencias/catalogos" class="nav-link">
<?php endif; ?> 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;
<!-- BITÁCORAS CON PERMISOS ESPECÍFICOS --> // Scope según dashboard
<?php if (tieneAccesoBitacoras($permisosBitacoras)): ?> $scope = '';
<?php $enDashboardBitacoras = $_SERVER['REQUEST_URI'] === '/IMPORTADORES/bitacoras/index'; ?> if ($tipoUsuario === 'super_admin') {
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= $esVistaBitacoras ? 'active' : '' ?>" $scope = 'Global';
href="<?= $enDashboardBitacoras ? '#submenuBitacoras' : '/IMPORTADORES/bitacoras/index' ?>" } elseif ($tipoUsuario === 'admin_agencia' || $tipoUsuario === 'agente_aduanal') {
<?= $enDashboardBitacoras ? 'data-bs-toggle="collapse"' : '' ?> if (in_array($permiso, ['acceso_usuarios_agencia', 'registro_vinculaciones'])) {
role="button" aria-expanded="true" aria-controls="submenuBitacoras" $scope = 'Agencia';
onclick="<?= $enDashboardBitacoras ? '' : 'event.preventDefault(); window.location.href = \'/IMPORTADORES/bitacoras/index\';' ?>"> } elseif (in_array($permiso, ['mis_vinculaciones', 'mi_actividad'])) {
📖 Bitácoras $scope = 'Personal';
<span class="badge bg-secondary"><?= $cantidadBitacoras ?></span> }
</a> } elseif ($tipoUsuario === 'importador') {
$scope = 'Personal';
<div class="collapse <?= $esVistaBitacoras ? 'show' : '' ?>" id="submenuBitacoras"> }
<nav class="nav flex-column ms-3"> ?>
<?php foreach ($permisosBitacoras as $permiso => $tienePermiso): ?> <a href="<?= $url ?>"
<?php if ($tienePermiso): ?> class="nav-link submenu-item px-3 py-2 d-flex justify-content-between align-items-center <?= $esActivo ? 'active' : '' ?>">
<?php <span>
$url = obtenerUrlPermiso($permiso); <?= htmlspecialchars($texto) ?>
$texto = obtenerTextoPermiso($permiso, $tipoUsuario); <?php if ($scope): ?>
$icono = obtenerIconoPermiso($permiso); <span class="permission-scope"><?= $scope ?></span>
$esActivo = $_SERVER['REQUEST_URI'] === $url; <?php endif; ?>
</span>
// Scope según dashboard </a>
$scope = ''; <?php endif; ?>
if ($tipoUsuario === 'super_admin') { </li>
$scope = 'Global'; <?php endforeach; ?>
} elseif ($tipoUsuario === 'admin_agencia' || $tipoUsuario === 'agente_aduanal') { </nav>
if (in_array($permiso, ['acceso_usuarios_agencia', 'registro_vinculaciones'])) { </div>
$scope = 'Agencia'; <?php endif; ?>
} elseif (in_array($permiso, ['mis_vinculaciones', 'mi_actividad'])) { </li>
$scope = 'Personal'; </ul>
} </nav>
} elseif ($tipoUsuario === 'importador') { </div>
$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>
</div> </div>
<!-- OFFCANVAS PARA MÓVILES --> <!-- 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"> <div class="offcanvas-header">
<h5 class="offcanvas-title">Menú</h5> <h5 class="offcanvas-title">Menú</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button> <button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div> </div>
<div class="offcanvas-body"> <div class="offcanvas-body">
<nav class="sidebar-nav">
<ul class="nav flex-column">
<!-- INFORMACIÓN GENERAL --> </ul>
<?php if ($permisosUsuario['informacion_general']): ?> </nav>
<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; ?>
</div> </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>

File diff suppressed because it is too large Load Diff

View File

@@ -89,7 +89,7 @@
<td><?= htmlspecialchars($v['telefono']) ?></td> <td><?= htmlspecialchars($v['telefono']) ?></td>
<td><?= isset($v['fecha_vinculacion']) && $v['fecha_vinculacion'] instanceof DateTime ? $v['fecha_vinculacion']->format('Y-m-d H:i') : '' ?></td> <td><?= isset($v['fecha_vinculacion']) && $v['fecha_vinculacion'] instanceof DateTime ? $v['fecha_vinculacion']->format('Y-m-d H:i') : '' ?></td>
<td> <td>
<a href="/IMPORTADORES/agentes/desvincularAgente?id=<?= $v['id_relacion'] ?>" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Desvincular</a> <a href="#" onclick="confirmUnlink(<?= $v['id_relacion'] ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Desvincular</a>
</td> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
@@ -108,6 +108,21 @@
} }
}); });
}); });
function confirmUnlink(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Esta acción no se puede deshacer.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, desvincular',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/agentes/desvincularAgente?id=${id}`;
}
});
}
</script> </script>
<?php if (isset($_GET['success'])): ?> <?php if (isset($_GET['success'])): ?>

View File

@@ -94,10 +94,10 @@
<td><?= htmlspecialchars(ucfirst($v['tipo_vinculacion'] ?? '')) ?></td> <td><?= htmlspecialchars(ucfirst($v['tipo_vinculacion'] ?? '')) ?></td>
<td><?= !empty($v['fecha_vinculacion']) ? $v['fecha_vinculacion']->format('Y-m-d H:i') : '' ?></td> <td><?= !empty($v['fecha_vinculacion']) ? $v['fecha_vinculacion']->format('Y-m-d H:i') : '' ?></td>
<td> <td>
<?php if (in_array($v['tipo_usuario_sistema'], ['importador', 'agente_aduanal'])): ?> <?php if ($v['tipo_usuario_sistema'] === 'importador'): ?>
<a href="/IMPORTADORES/vinculaciones/desvincularAgencia?id=<?= $v['id_relacion'] ?>&tipo=<?= $v['tipo_vinculacion'] ?>" class="btn btn-sm btn-danger mt-auto w-auto btn-animated"> <button onclick="confirmUnlink(<?= $v['id_relacion'] ?>, 'importador')" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Desvincular</button>
Desvincular <?php elseif ($v['tipo_usuario_sistema'] === 'agente_aduanal'): ?>
</a> <button onclick="confirmUnlink(<?= $v['id_relacion'] ?>, 'agente')" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Desvincular</button>
<?php else: ?> <?php else: ?>
<span class="text-muted small">N/A</span> <span class="text-muted small">N/A</span>
<?php endif; ?> <?php endif; ?>
@@ -120,6 +120,21 @@
} }
}); });
}); });
function confirmUnlink(id, tipo) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Esta acción no se puede deshacer.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, desvincular',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/vinculaciones/desvincularAgencia?id=${id}&tipo=${tipo}`;
}
});
}
</script> </script>
<?php if (isset($_GET['success'])): ?> <?php if (isset($_GET['success'])): ?>

View File

@@ -103,7 +103,7 @@
<?php else: ?> <?php else: ?>
<a href="/IMPORTADORES/importadores/cambiarAgenciaActiva?id=<?= $v['id_agencia'] ?>" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Usar Agencia</a> <a href="/IMPORTADORES/importadores/cambiarAgenciaActiva?id=<?= $v['id_agencia'] ?>" class="btn btn-sm btn-success mt-auto w-auto btn-animated">Usar Agencia</a>
<?php endif; ?> <?php endif; ?>
<a href="/IMPORTADORES/importadores/desvincularUsuario?id=<?= $v['id_relacion'] ?>" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Desvincular</a> <button onclick="confirmUnlink(<?= $v['id_relacion'] ?>)" class="btn btn-sm btn-danger mt-auto w-auto btn-animated">Desvincular</button>
</td> </td>
</tr> </tr>
<?php endforeach; ?> <?php endforeach; ?>
@@ -123,6 +123,21 @@
} }
}); });
}); });
function confirmUnlink(id) {
Swal.fire({
title: '¿Estás seguro?',
text: 'Esta acción no se puede deshacer.',
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Sí, desvincular',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
window.location.href = `/IMPORTADORES/importadores/desvincularUsuario?id=${id}`;
}
});
}
</script> </script>
<?php if (isset($_GET['success'])): ?> <?php if (isset($_GET['success'])): ?>