CRUD gestión de locaciones

This commit is contained in:
2025-06-09 08:50:23 -06:00
parent 2eb3ec6061
commit 55fb7c0bf4
28 changed files with 1982 additions and 234 deletions

View File

@@ -14,7 +14,7 @@
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
.sidebar .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }

View File

@@ -1,58 +0,0 @@
<?php
require_once __DIR__ . '/../../app/helpers/crypto.php';
include __DIR__ . '/../partials/sidebar_agente.php';
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Dashboard | Agente Aduanal</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 60px; }
.sidebar .nav-link { color: #ccc; padding: 12px 20px; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-left: 220px; padding: 40px 20px; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1000; }
.card { border-radius: 12px; }
</style>
</head>
<body>
<!-- 📄 CONTENIDO -->
<div class="content">
<h4 class="mb-4">Panel principal del agente</h4>
<div class="row g-4">
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-primary">Importadores activos</h5>
<p>Consulta los que ya fueron autorizados.</p>
<a href="/IMPORTADORES/AGENTES/activos" class="btn btn-primary btn-sm mt-2">Ver importadores</a>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-success">Solicitudes pendientes</h5>
<p>Valida nuevas solicitudes de registro.</p>
<a href="/IMPORTADORES/AGENTES/solicitudes_pendientes" class="btn btn-success btn-sm mt-2">Ver solicitudes</a>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-warning">Bitácora del sistema</h5>
<p>Revisa los accesos y acciones recientes.</p>
<a href="/IMPORTADORES/agentes/bitacora" class="btn btn-warning btn-sm mt-2">Ver bitácora</a>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,88 @@
<?php
require_once __DIR__ . '/../../app/helpers/crypto.php';
include __DIR__ . '/../partials/sidebar_agente.php';
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Dashboard | Agente Aduanal</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
.btn-orange { background-color: orangeRed; color: white;}
.btn-orange:hover { background-color: #ff3600; color: white;}
.text-orange { color: orangeRed;}
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content { margin-left: 0; }
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card { border-radius: 12px; }
</style>
</head>
<body>
<!-- 📄 CONTENIDO -->
<div class="content">
<h4 class="mb-4">📦 Panel del Agente Aduanal</h4>
<div class="row g-4">
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-primary">Importadores activos</h5>
<p>Consulta los que ya fueron autorizados.</p>
<a href="/IMPORTADORES/AGENTES/activos" class="btn btn-primary btn-sm mt-2">Ver importadores</a>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-success">Solicitudes pendientes</h5>
<p>Valida nuevas solicitudes de registro.</p>
<a href="/IMPORTADORES/AGENTES/solicitudes_pendientes" class="btn btn-success btn-sm mt-2">Ver solicitudes</a>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-warning">Bitácora del sistema</h5>
<p>Revisa los accesos y acciones recientes.</p>
<a href="/IMPORTADORES/agentes/bitacora" class="btn btn-warning btn-sm mt-2">Ver bitácora</a>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-orange">Locaciones</h5>
<p>Gestiona la locaciones validas para nuevos registros.</p>
<a href="/IMPORTADORES/agentes/lista" class="btn btn-orange btn-sm mt-2">Gestionar locaciones</a>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-danger">Cerrar sesión</h5>
<p>Salir del sistema de forma segura.</p>
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-danger btn-sm mt-2">Logout</a>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,7 +1,4 @@
<?php
require_once __DIR__ . '/../../app/helpers/crypto.php';
include __DIR__ . '/../partials/sidebar_agente.php';
?>
<?php include __DIR__ . '/../partials/sidebar_agente.php'; ?>
<html>
<head>
@@ -12,47 +9,62 @@ include __DIR__ . '/../partials/sidebar_agente.php';
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 60px; }
.sidebar .nav-link { color: #ccc; padding: 12px 20px; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-left: 220px; padding: 40px 20px; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1000; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content { margin-left: 0; }
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card { border-radius: 12px; }
.table thead th { background: #343a40; color: #fff; }
</style>
</head>
<body>
<div class="content px-4 pt-5 mt-4">
<div class="content">
<h4>✅ Importadores Activos</h4>
<table class="table table-hover mt-3 align-middle">
<thead class="table-dark">
<tr>
<th>#</th>
<th>Nombre</th>
<th>Correo</th>
<th>Fecha Registro</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach ($importadores as $i): ?>
<tr>
<td><?= $i['id_usuario'] ?></td>
<td><?= htmlspecialchars(($i['nombre'])) ?></td>
<td><?= htmlspecialchars($i['email']) ?></td>
<td><?= isset($i['creado_en']) && $i['creado_en'] instanceof DateTime ? $i['creado_en']->format('Y-m-d H:i') : '' ?></td>
<td>
<?php if (isset($i['activo']) && $i['activo'] == 1): ?>
<a href="/IMPORTADORES/agentes/toggle_estado?id=<?= $i['id_usuario'] ?>&success=1" class="btn btn-sm btn-danger">Suspender</a>
<?php else: ?>
<a href="/IMPORTADORES/agentes/toggle_estado?id=<?= $i['id_usuario'] ?>&success=1" class="btn btn-sm btn-success">Activar</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="card p-3 shadow-sm">
<div class="table-responsive">
<table class="table table-striped" id="tabla-activos">
<thead>
<tr>
<th>#</th>
<th>Nombre</th>
<th>Correo</th>
<th>Fecha Registro</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach ($importadores as $i): ?>
<tr>
<td><?= $i['id_usuario'] ?></td>
<td><?= htmlspecialchars(($i['nombre'])) ?></td>
<td><?= htmlspecialchars($i['email']) ?></td>
<td><?= isset($i['creado_en']) && $i['creado_en'] instanceof DateTime ? $i['creado_en']->format('Y-m-d H:i') : '' ?></td>
<td>
<?php if (isset($i['activo']) && $i['activo'] == 1): ?>
<a href="/IMPORTADORES/agentes/toggle_estado?id=<?= $i['id_usuario'] ?>&success=1" class="btn btn-sm btn-danger">Suspender</a>
<?php else: ?>
<a href="/IMPORTADORES/agentes/toggle_estado?id=<?= $i['id_usuario'] ?>&success=1" class="btn btn-sm btn-success">Activar</a>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<?php if (isset($_GET['success'])): ?>

View File

@@ -1,7 +1,4 @@
<?php
require_once __DIR__ . '/../../app/helpers/crypto.php';
include __DIR__ . '/../partials/sidebar_agente.php';
?>
<?php include __DIR__ . '/../partials/sidebar_agente.php'; ?>
<html>
<head>
@@ -11,55 +8,70 @@ include __DIR__ . '/../partials/sidebar_agente.php';
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 60px; }
.sidebar .nav-link { color: #ccc; padding: 12px 20px; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-left: 220px; padding: 40px 20px; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1000; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content { margin-left: 0; }
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card { border-radius: 12px; }
.table thead th { background: #343a40; color: #fff; }
</style>
</head>
<body>
<div class="content px-4 pt-5 mt-4">
<div class="content">
<h4>📥 Solicitudes Pendientes</h4>
<table class="table table-hover mt-3 align-middle">
<thead class="table-dark">
<tr>
<th>#</th>
<th>Empresa</th>
<th>RFC</th>
<th>Correo</th>
<th>Teléfono</th>
<th>Fecha</th>
<th>Archivo SAT</th>
<th>Acción</th>
</tr>
</thead>
<tbody>
<?php foreach ($solicitudes as $s): ?>
<tr>
<td><?= $s['request_id'] ?></td>
<td><?= htmlspecialchars(decrypt($s['company_name'])) ?></td>
<td><?= htmlspecialchars(decrypt($s['rfc'])) ?></td>
<td><?= htmlspecialchars($s['email']) ?></td>
<td><?= htmlspecialchars($s['phone']) ?></td>
<td><?= $s['request_date'] ? $s['request_date']->format('Y-m-d H:i') : '' ?></td>
<td>
<?php if (!empty($s['opinion_file'])): ?>
<a href="/IMPORTADORES/ver_opinion.php?file=<?= urlencode($s['opinion_file']) ?>" target="_blank" class="btn btn-sm btn-outline-secondary">Ver PDF</a>
<?php else: ?>
<span class="text-muted">No adjunto</span>
<?php endif; ?>
</td>
<td>
<a href="/IMPORTADORES/agentes/aprobar_solicitud?id=<?= $s['request_id'] ?>" class="btn btn-sm btn-success">Aprobar</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="card p-3 shadow-sm">
<div class="table-responsive">
<table class="table table-striped" id="tabla-pendientes">
<thead>
<tr>
<th>#</th>
<th>Empresa</th>
<th>RFC</th>
<th>Correo</th>
<th>Teléfono</th>
<th>Fecha</th>
<th>Archivo SAT</th>
<th>Acción</th>
</tr>
</thead>
<tbody>
<?php foreach ($solicitudes as $s): ?>
<tr>
<td><?= $s['request_id'] ?></td>
<td><?= htmlspecialchars(decrypt($s['company_name'])) ?></td>
<td><?= htmlspecialchars(decrypt($s['rfc'])) ?></td>
<td><?= htmlspecialchars($s['email']) ?></td>
<td><?= htmlspecialchars($s['phone']) ?></td>
<td><?= $s['request_date'] ? $s['request_date']->format('Y-m-d H:i') : '' ?></td>
<td>
<?php if (!empty($s['opinion_file'])): ?>
<a href="/IMPORTADORES/ver_opinion.php?file=<?= urlencode($s['opinion_file']) ?>" target="_blank" class="btn btn-sm btn-outline-secondary">Ver PDF</a>
<?php else: ?>
<span class="text-muted">No adjunto</span>
<?php endif; ?>
</td>
<td>
<a href="/IMPORTADORES/agentes/aprobar_solicitud?id=<?= $s['request_id'] ?>" class="btn btn-sm btn-success">Aprobar</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</body>

View File

@@ -75,7 +75,7 @@
$(document).ready(function () {
$('#tabla-logins').DataTable({
language: {
url: '//cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
url: 'https://cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
}
});
});

View File

@@ -18,7 +18,10 @@
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
.btn-indigo { background-color: #6610f2; color: white;}
.btn-indigo:hover { background-color: #520dc2; color: white;}
.text-indigo { color: #6610f2;}
.text-indigo { color: orangeRed;}
.btn-orange { background-color: orangeRed; color: white;}
.btn-orange:hover { background-color: #ff3600; color: white;}
.text-orange { color: orangeRed;}
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
/* En móviles, sin margen lateral */
@@ -92,6 +95,17 @@
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-orange">Locaciones</h5>
<p>Visualiza las locaciones registradas.</p>
<a href="/IMPORTADORES/importadores/lista"
class="btn btn-orange btn-sm mt-2 <?= str_contains($_SERVER['REQUEST_URI'], '/importadores/lista') ? 'active' : '' ?>">
Ver locaciones
</a>
</div>
</div>
<div class="col-md-4">
<div class="card shadow-sm p-3">
<h5 class="text-danger">Cerrar sesión</h5>

View File

@@ -0,0 +1,286 @@
<?php include __DIR__ . '/../partials/sidebar_agente.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Dashboard | Agente Aduanal</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<style>
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease; }
@media (min-width: 768px) { .content { margin-left: 250px; } }
@media (max-width: 767.98px) {
.content { margin-left: 0; }
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover, .sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card { border-radius: 12px; }
.hide { display: none !important; }
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4">🗺️ Nuevas Locaciones</h4>
<div class="row g-3">
<!-- Nuevo Estado -->
<div class="col-md">
<div class="card p-4 bg-white shadow-sm">
<form id="estadoForm">
<h4 class="mb-4 text-dark"> Nuevo Estado</h4><br>
<!-- País -->
<div class="col-md-12">
<label for="paisEstado" class="form-label">País *</label>
<select id="paisEstado" name="pais" class="form-select" required>
<option value="">Selecciona país</option>
<?php foreach($paises as $p): ?>
<option value="<?= $p['id_pais'] ?>">
<?= htmlspecialchars($p['nombre']) ?>
</option>
<?php endforeach; ?>
</select>
</div><br><br><br>
<!-- Estado -->
<div class="col-md-12">
<label for="entidadEstado" class="form-label">Entidad / Provincia *</label>
<input id="entidadEstado" name="entidad" class="form-control" required>
</div><br><br>
<div class="col-md-4 d-flex align-items-end">
<button type="submit" class="btn btn-success w-100">
<i class="fas fa-plus"></i> Registrar Estado
</button>
<a href="/IMPORTADORES/agentes/lista" class="btn btn-secondary ms-2">Cancelar</a>
</div>
</form>
</div>
</div>
<!-- Nueva Ciudad -->
<div class="col-md">
<div class="card p-4 bg-white shadow-sm">
<form id="ciudadForm" action="/IMPORTADORES/agentes/guadarCiudad" method="POST" enctype="multipart/form-data">
<h4 class="mb-4 text-dark"> Nueva Ciudad</h4>
<!-- País -->
<div class="col-md-12">
<label for="paisCiudad" class="form-label">País *</label>
<select id="paisCiudad" name="pais" class="form-select" required>
<option value="">Selecciona país</option>
<?php foreach($paises as $p): ?>
<option value="<?= $p['id_pais'] ?>">
<?= htmlspecialchars($p['nombre']) ?>
</option>
<?php endforeach; ?>
</select>
</div><br>
<!-- Estado -->
<div class="col-md-12">
<label for="entidadCiudad" class="form-label">Entidad / Provincia *</label>
<select id="estadoCiudad" name="entidad" class="form-select" required disabled>
<option value="">Primero país…</option>
</select>
</div><br>
<!-- Ciudad -->
<div class="col-md-12">
<label for="nombreCiudad" class="form-label">Ciudad *</label>
<input id="nombreCiudad" name="ciudad" class="form-control" required>
</div><br>
<div class="col-md-4 d-flex align-items-end">
<button type="submit" class="btn btn-success w-100">
<i class="fas fa-plus"></i> Registrar Ciudad
</button>
<a href="/IMPORTADORES/agentes/lista" class="btn btn-secondary ms-2">Cancelar</a>
</div>
</form>
</div>
</div>
</div>
</div>
<script>
// Función para cargar estados
function cargarEstados(paisId, selectElement) {
selectElement.innerHTML = '<option>Cargando...</option>';
selectElement.disabled = true;
fetch(`/IMPORTADORES/agentes/estados?pais=${paisId}`)
.then(response => response.json())
.then(estados => {
selectElement.innerHTML = '<option value="">Selecciona estado</option>';
estados.forEach(estado => {
const option = new Option(estado.nombre, estado.id_estado);
selectElement.add(option);
});
selectElement.disabled = false;
})
.catch(error => {
console.error('Error:', error);
selectElement.innerHTML = '<option value="">Error al cargar</option>';
});
}
// Evento para cargar estados cuando se selecciona país en formulario de ciudad
document.getElementById('paisCiudad').addEventListener('change', function(e) {
const paisId = e.target.value;
const estadoSelect = document.getElementById('estadoCiudad');
if (paisId) {
cargarEstados(paisId, estadoSelect);
} else {
estadoSelect.innerHTML = '<option value="">Primero selecciona país</option>';
estadoSelect.disabled = true;
}
});
// Formulario de nuevo estado
document.getElementById('estadoForm').addEventListener('submit', function(e) {
e.preventDefault();
// Obtener valores directamente
const paisSelect = document.getElementById('paisEstado');
const entidadInput = document.getElementById('entidadEstado');
const paisValue = paisSelect.value;
const entidadValue = entidadInput.value.trim();
// Validación en frontend
if (!paisValue) {
Swal.fire({
icon: 'warning',
title: 'Campo requerido',
text: 'Debe seleccionar un país'
});
return;
}
if (!entidadValue) {
Swal.fire({
icon: 'warning',
title: 'Campo requerido',
text: 'Debe ingresar el nombre del estado'
});
return;
}
// Crear FormData manualmente
const formData = new FormData();
formData.append('pais', paisValue);
formData.append('entidad', entidadValue);
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Guardando...';
submitBtn.disabled = true;
// Debug: mostrar lo que se va a enviar
console.log('Enviando:', {
pais: paisValue,
entidad: entidadValue
});
fetch('/IMPORTADORES/agentes/guardarEstado', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: '¡Éxito!',
text: data.message,
timer: 2000,
showConfirmButton: false
});
this.reset();
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: data.message
});
}
})
.catch(error => {
console.error('Error:', error);
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Ocurrió un error al procesar la solicitud'
});
})
.finally(() => {
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
});
});
// Formulario de nueva ciudad
document.getElementById('ciudadForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Guardando...';
submitBtn.disabled = true;
fetch('/IMPORTADORES/agentes/guardarCiudad', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: '¡Éxito!',
text: data.message,
timer: 2000,
showConfirmButton: false
});
this.reset();
// Resetear el select de estados
document.getElementById('estadoCiudad').innerHTML = '<option value="">Primero selecciona país</option>';
document.getElementById('estadoCiudad').disabled = true;
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: data.message
});
}
})
.catch(error => {
console.error('Error:', error);
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Ocurrió un error al procesar la solicitud'
});
})
.finally(() => {
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,492 @@
<?php include __DIR__ . '/../partials/sidebar_agente.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Dashboard | Agente Aduanal</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<style>
table.dataTable thead th { background:#343a40; color:#fff; }
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease;}
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content { margin-left: 0; }
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card { border-radius: 12px; }
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4">🌍 Locaciones</h4>
<a href="/IMPORTADORES/agentes/alta" class="btn btn-success mb-3"> Agregar Locación</a>
<div class="card p-3 shadow-sm">
<div class="table-responsive">
<table class="table table-striped" id="tabla-locaciones">
<thead class="table-dark">
<tr>
<th>ID País</th>
<th>País</th>
<th>ISO3</th>
<th>ID Estado</th>
<th>Estado</th>
<th>ID Ciudad</th>
<th>Ciudad</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach ($locaciones as $loc): ?>
<tr>
<td><?= htmlspecialchars($loc['id_pais']) ?></td>
<td><?= htmlspecialchars($loc['nombre_pais']) ?></td>
<td><?= htmlspecialchars($loc['iso3']) ?></td>
<td><?= htmlspecialchars($loc['id_estado']) ?></td>
<td><?= htmlspecialchars($loc['nombre_estado']) ?></td>
<td><?= htmlspecialchars($loc['id_ciudad']) ?></td>
<td><?= htmlspecialchars($loc['nombre_ciudad']) ?></td>
<td>
<!-- Botones de acción (editar/eliminar) -->
<?php if (!empty($loc['id_ciudad'])): ?>
<!-- Es una ciudad -->
<button class="btn btn-sm btn-primary"
onclick="editarItem('ciudad', <?= $loc['id_ciudad'] ?>, '<?= htmlspecialchars($loc['nombre_ciudad'], ENT_QUOTES) ?>', '', '', '', <?= $loc['id_estado'] ?>)">
✏️
</button>
<button class="btn btn-sm btn-danger"
onclick="eliminarItem('ciudad', <?= $loc['id_ciudad'] ?>, '<?= htmlspecialchars($loc['nombre_ciudad'], ENT_QUOTES) ?>')">
🗑️
</button>
<?php elseif (!empty($loc['id_estado'])): ?>
<!-- Es un estado - CORREGIDO: Obtener abreviatura correctamente -->
<button class="btn btn-sm btn-primary"
onclick="editarItem('estado', <?= $loc['id_estado'] ?>, '<?= htmlspecialchars($loc['nombre_estado'], ENT_QUOTES) ?>', '', '', '<?= htmlspecialchars($loc['abreviatura'] ?? '', ENT_QUOTES) ?>', <?= $loc['id_pais'] ?>)">
✏️
</button>
<button class="btn btn-sm btn-danger"
onclick="eliminarItem('estado', <?= $loc['id_estado'] ?>, '<?= htmlspecialchars($loc['nombre_estado'], ENT_QUOTES) ?>')">
🗑️
</button>
<?php else: ?>
<!-- Es un país -->
<button class="btn btn-sm btn-primary"
onclick="editarItem('pais', <?= $loc['id_pais'] ?>, '<?= htmlspecialchars($loc['nombre_pais'], ENT_QUOTES) ?>', '<?= htmlspecialchars($loc['iso2'] ?? '', ENT_QUOTES) ?>', '<?= htmlspecialchars($loc['iso3'] ?? '', ENT_QUOTES) ?>')">
✏️
</button>
<button class="btn btn-sm btn-danger"
onclick="eliminarItem('pais', <?= $loc['id_pais'] ?>, '<?= htmlspecialchars($loc['nombre_pais'], ENT_QUOTES) ?>')">
🗑️
</button>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<!-- Modal para Editar -->
<div class="modal fade" id="editarModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">✏️ Editar <span id="tipoItem"></span></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="editarForm">
<div class="modal-body">
<input name="editTipo" type="hidden" id="editTipo">
<input name="editId" type="hidden" id="editId">
<!-- Campos para País -->
<div id="camposPais" style="display: none;">
<div class="mb-3">
<label for="editNombrePais" class="form-label">Nombre del País *</label>
<input name="editNombrePais" type="text" class="form-control" id="editNombrePais">
</div>
<div class="row">
<div class="col-md-6">
<label for="editIso2" class="form-label">ISO2</label>
<input name="editIso2" type="text" class="form-control" id="editIso2" maxlength="2">
</div>
<div class="col-md-6">
<label for="editIso3" class="form-label">ISO3</label>
<input name="editIso3" type="text" class="form-control" id="editIso3" maxlength="3">
</div>
</div>
</div>
<!-- Campos para Estado -->
<div id="camposEstado" style="display: none;">
<div class="mb-3">
<label for="editPaisEstado" class="form-label">País *</label>
<select name="editPaisEstado" class="form-select" id="editPaisEstado">
<option value="">Selecciona país</option>
<?php foreach($paises as $p): ?>
<option value="<?= $p['id_pais'] ?>"><?= htmlspecialchars($p['nombre']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label for="editNombreEstado" class="form-label">Nombre del Estado *</label>
<input name="editNombreEstado" type="text" class="form-control" id="editNombreEstado">
</div>
<div class="mb-3">
<label for="editAbreviatura" class="form-label">Abreviatura</label>
<input name="editAbreviatura" type="text" class="form-control" id="editAbreviatura" maxlength="10">
</div>
</div>
<!-- Campos para Ciudad -->
<div id="camposCiudad" style="display: none;">
<div class="mb-3">
<label for="editPaisCiudad" class="form-label">País *</label>
<select name="editPaisCiudad" class="form-select" id="editPaisCiudad">
<option value="">Selecciona país</option>
<?php foreach($paises as $p): ?>
<option value="<?= $p['id_pais'] ?>"><?= htmlspecialchars($p['nombre']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label for="editEstadoCiudad" class="form-label">Estado *</label>
<select name="editEstadoCiudad" class="form-select" id="editEstadoCiudad">
<option value="">Primero selecciona país</option>
</select>
</div>
<div class="mb-3">
<label for="editNombreCiudad" class="form-label">Nombre de la Ciudad *</label>
<input name="editNombreCiudad" type="text" class="form-control" id="editNombreCiudad">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary">Guardar Cambios</button>
</div>
</form>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#tabla-locaciones').DataTable({
order: [],
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
}
});
});
// Función para cargar estados
function cargarEstados(paisId, selectElement, estadoSeleccionado = null) {
selectElement.innerHTML = '<option>Cargando...</option>';
selectElement.disabled = true;
fetch(`/IMPORTADORES/agentes/estados?pais=${paisId}`)
.then(response => response.json())
.then(estados => {
selectElement.innerHTML = '<option value="">Selecciona estado</option>';
estados.forEach(estado => {
const option = new Option(estado.nombre, estado.id_estado);
if (estadoSeleccionado && estado.id_estado == estadoSeleccionado) {
option.selected = true;
}
selectElement.add(option);
});
selectElement.disabled = false;
})
.catch(error => {
console.error('Error:', error);
selectElement.innerHTML = '<option value="">Error al cargar</option>';
});
}
// Evento para cargar estados en modal de edición
document.getElementById('editPaisCiudad').addEventListener('change', function(e) {
const paisId = e.target.value;
const estadoSelect = document.getElementById('editEstadoCiudad');
if (paisId) {
cargarEstados(paisId, estadoSelect);
} else {
estadoSelect.innerHTML = '<option value="">Primero selecciona país</option>';
estadoSelect.disabled = true;
}
});
// Función para abrir modal de edición
function editarItem(tipo, id, nombre, iso2 = '', iso3 = '', abreviatura = '', padreId = null) {
document.getElementById('editTipo').value = tipo;
document.getElementById('editId').value = id;
document.getElementById('tipoItem').textContent = tipo.charAt(0).toUpperCase() + tipo.slice(1);
// Ocultar todos los campos
document.getElementById('camposPais').style.display = 'none';
document.getElementById('camposEstado').style.display = 'none';
document.getElementById('camposCiudad').style.display = 'none';
if (tipo === 'pais') {
document.getElementById('camposPais').style.display = 'block';
document.getElementById('editNombrePais').value = nombre;
document.getElementById('editIso2').value = iso2;
document.getElementById('editIso3').value = iso3;
} else if (tipo === 'estado') {
document.getElementById('camposEstado').style.display = 'block';
document.getElementById('editNombreEstado').value = nombre;
document.getElementById('editAbreviatura').value = abreviatura;
document.getElementById('editPaisEstado').value = padreId;
} else if (tipo === 'ciudad') {
document.getElementById('camposCiudad').style.display = 'block';
document.getElementById('editNombreCiudad').value = nombre;
// Necesitamos obtener el país del estado para cargar los estados
if (padreId) {
fetch(`/IMPORTADORES/agentes/obtenerPaisPorEstado?estado=${padreId}`)
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
document.getElementById('editPaisCiudad').value = data.pais_id;
cargarEstados(data.pais_id, document.getElementById('editEstadoCiudad'), padreId);
} else {
console.error('Error al obtener país:', data.message);
Swal.fire({
icon: 'error',
title: 'Error',
text: 'No se pudo cargar la información del país' + data.message
});
}
})
.catch(error => {
console.error('Error:', error);
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Error al cargar la información'
});
});
}
}
new bootstrap.Modal(document.getElementById('editarModal')).show();
}
// Función para eliminar item
function eliminarItem(tipo, id, nombre) {
Swal.fire({
title: '¿Estás seguro?',
text: `¿Deseas eliminar el ${tipo} "${nombre}"?`,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
confirmButtonText: 'Sí, eliminar',
cancelButtonText: 'Cancelar'
}).then((result) => {
if (result.isConfirmed) {
fetch('/IMPORTADORES/agentes/eliminar', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
tipo: tipo,
id: id
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: '¡Eliminado!',
text: data.message,
timer: 2000,
showConfirmButton: false
}).then(() => {
location.reload();
});
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: data.message
});
}
})
.catch(error => {
console.error('Error:', error);
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Ocurrió un error al eliminar'
});
});
}
});
}
// REEMPLAZA tu función de submit del formulario con esta versión corregida
document.getElementById('editarForm').addEventListener('submit', function(e) {
e.preventDefault();
const tipo = document.getElementById('editTipo').value;
const id = document.getElementById('editId').value;
// VALIDACIÓN BÁSICA
if (!tipo || !id) {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Faltan datos requeridos'
});
return;
}
let formData = new FormData();
formData.append('tipo', tipo);
formData.append('id', id);
// Determinar endpoint y datos según el tipo
let endpoint = '';
let isValid = true;
if (tipo === 'pais') {
const nombre = document.getElementById('editNombrePais').value.trim();
if (!nombre) {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'El nombre del país es obligatorio'
});
return;
}
endpoint = '/IMPORTADORES/agentes/actualizarPais';
formData.append('nombre', nombre);
formData.append('iso2', document.getElementById('editIso2').value.trim());
formData.append('iso3', document.getElementById('editIso3').value.trim());
} else if (tipo === 'estado') {
const nombre = document.getElementById('editNombreEstado').value.trim();
const paisId = document.getElementById('editPaisEstado').value;
if (!nombre || !paisId) {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'El nombre del estado y el país son obligatorios'
});
return;
}
endpoint = '/IMPORTADORES/agentes/actualizarEstado';
formData.append('nombre', nombre);
formData.append('abreviatura', document.getElementById('editAbreviatura').value.trim());
formData.append('pais_id', paisId);
} else if (tipo === 'ciudad') {
const nombre = document.getElementById('editNombreCiudad').value.trim();
const estadoId = document.getElementById('editEstadoCiudad').value;
if (!nombre || !estadoId) {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'El nombre de la ciudad y el estado son obligatorios'
});
return;
}
endpoint = '/IMPORTADORES/agentes/actualizarCiudad';
formData.append('nombre', nombre);
formData.append('estado_id', estadoId);
}
const submitBtn = this.querySelector('button[type="submit"]');
const originalText = submitBtn.innerHTML;
// INDICADOR DE CARGA
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Guardando...';
submitBtn.disabled = true;
// ENVÍO AJAX al endpoint específico
fetch(endpoint, {
method: 'POST',
body: formData
})
.then(response => {
// VERIFICAR QUE LA RESPUESTA SEA OK
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: '¡Éxito!',
text: data.message,
timer: 2000,
showConfirmButton: false
}).then(() => {
// CERRAR MODAL Y RECARGAR
const modal = bootstrap.Modal.getInstance(document.getElementById('editarModal'));
if (modal) {
modal.hide();
}
location.reload();
});
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: data.message || 'Error desconocido'
});
}
})
.catch(error => {
console.error('Error completo:', error);
Swal.fire({
icon: 'error',
title: 'Error de conexión',
text: 'No se pudo procesar la solicitud. Verifique su conexión.'
});
})
.finally(() => {
// RESTAURAR BOTÓN
submitBtn.innerHTML = originalText;
submitBtn.disabled = false;
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,85 @@
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>🌍 Locaciones</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<style>
table.dataTable thead th { background:#343a40; color:#fff; }
body { font-family: 'Segoe UI', sans-serif; background-color: #f4f6f9; }
.sidebar { width: 220px; height: 100vh; background-color: #343a40; position: fixed; top: 0; left: 0; padding-top: 56px; z-index: 1040; }
.sidebar .nav-link { font-weight: bold; color: white; transition: all 0.3s ease; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; position: relative; z-index: 1; background-color: #f4f6f9; transition: margin-left 0.3s ease;}
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
@media (min-width: 768px) { .content { margin-left: 250px; /* Ancho del sidebar */ } }
/* En móviles, sin margen lateral */
@media (max-width: 767.98px) {
.content { margin-left: 0; }
.sidebar .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #e9ecef; color: #212529; }
}
.card { border-radius: 12px; }
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4">🗺️ Locaciones</h4>
<div class="card p-3 shadow-sm">
<div class="table-responsive">
<table class="table table-striped" id="tabla-locaciones">
<thead class="table-dark">
<tr>
<th>ID País</th>
<th>País</th>
<th>ISO3</th>
<th>ID Estado</th>
<th>Estado</th>
<th>ID Ciudad</th>
<th>Ciudad</th>
</tr>
</thead>
<tbody>
<?php foreach ($locaciones as $loc): ?>
<tr>
<td><?= htmlspecialchars($loc['id_pais']) ?></td>
<td><?= htmlspecialchars($loc['nombre_pais']) ?></td>
<td><?= htmlspecialchars($loc['iso3']) ?></td>
<td><?= htmlspecialchars($loc['id_estado']) ?></td>
<td><?= htmlspecialchars($loc['nombre_estado']) ?></td>
<td><?= htmlspecialchars($loc['id_ciudad']) ?></td>
<td><?= htmlspecialchars($loc['nombre_ciudad']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#tabla-locaciones').DataTable({
order: [],
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
}
});
});
</script>
</body>
</html>

View File

@@ -119,16 +119,7 @@ if (!isset($_SESSION['email_recuperacion'])) {
<i class="fas fa-key me-2"></i>Código de verificación
</label>
<div class="input-group">
<input type="text"
id="codigo"
name="codigo"
class="form-control"
required
pattern="\d{6}"
maxlength="6"
placeholder="000000"
autocomplete="off"
inputmode="numeric">
<input type="text" id="codigo" name="codigo" class="form-control" required pattern="\d{6}" maxlength="6" placeholder="000000" autocomplete="off" inputmode="numeric">
<button type="button" class="clear-input" id="clearCode" title="Limpiar código">
<i class="fas fa-times"></i>
</button>

View File

@@ -1,30 +1,146 @@
<?php
session_start();
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') {
header('Location: /IMPORTADORES/login');
exit;
}
$nombreAgente = $_SESSION['usuario_nombre'];
?>
<style>
.nav .nav-link { font-weight: normal; color: white; transition: all 0.3s ease; }
.nav .nav-link:hover,
.nav .nav-link.active { background-color: #495057; color: #fff; }
/* Estilo inverso solo para pantallas pequeñas (sidebar tipo offcanvas) */
@media (max-width: 767.98px) {
.nav .nav-link { font-weight: normal; color: #343a40; background-color: transparent; }
.nav .nav-link:hover,
.nav .nav-link.active { background-color: #e9ecef; color: #212529; }
}
</style>
<!-- 🔷 NAVBAR -->
<nav class="navbar navbar-dark bg-dark">
<nav class="navbar navbar-dark bg-dark fixed-top">
<div class="container-fluid">
<!-- Botón de menú para móviles -->
<button class="btn btn-outline-light d-md-none me-2" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu">
</button>
<span class="navbar-brand">SIIH | Agente Aduanal</span>
<div class="d-flex text-white">
Bienvenido, <?= htmlspecialchars($nombreAgente) ?>&nbsp;&nbsp;
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm">Cerrar sesión</a>
<div class="d-flex ms-auto text-white">
<?php
// Verifica si estás en el dashboard principal del importador
$esDashboard = str_contains($_SERVER['REQUEST_URI'], '/agentes/dashboard');
if ($esDashboard): ?>
Bienvenido, <?= htmlspecialchars($_SESSION['usuario_nombre']) ?>
<?php else: ?>
<a href="/IMPORTADORES/sistemas/logout" class="btn btn-outline-light btn-sm">Cerrar Sesión</a>
<?php endif; ?>
</div>
</div>
</nav>
<!-- 📘 SIDEBAR -->
<div class="sidebar d-none d-lg-block">
<!-- SIDEBAR FIJA (escritorio) -->
<div class="d-none d-md-block bg-dark text-white position-fixed h-100 pt-5" style="width: 250px;">
<nav class="nav flex-column">
<a href="/IMPORTADORES/AGENTES/dashboard" class="nav-link active">📊 Dashboard</a>
<a href="/IMPORTADORES/AGENTES/activos" class="nav-link">✅ Importadores Activos</a>
<a href="/IMPORTADORES/AGENTES/solicitudes_pendientes" class="nav-link">📥 Solicitudes de Registro</a>
<a href="/IMPORTADORES/AGENTES/bitacora" class="nav-link">🕓 Bitácora</a>
<!-- INICIO -->
<a href="/IMPORTADORES/agentes/dashboard"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/dashboard' ? 'active' : '' ?>">
🏠 Inicio
</a>
<!-- IMPORTADORES ACTIVOS -->
<a href="/IMPORTADORES/agentes/activos"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/activos' ? 'active' : '' ?>">
✅ Importadores Activos
</a>
<!-- SOLICITUDES PENDIENTES -->
<a href="/IMPORTADORES/agentes/solicitudes_pendientes"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/solicitudes_pendientes' ? 'active' : '' ?>">
📥 Solicitudes de Registro
</a>
<!-- BITÁCORA -->
<a href="/IMPORTADORES/agentes/bitacora"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/bitacora' ? 'active' : '' ?>">
🕓 Bitácora
</a>
<!-- LOCACIONES -->
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
<?= str_contains($_SERVER['REQUEST_URI'], '/agentes') ? 'active' : '' ?>"
data-bs-toggle="collapse" href="#submenuLocaciones" role="button" aria-expanded="false">
🗺️ Locaciones
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/agentes') ? 'show' : '' ?>" id="submenuLocaciones">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/agentes/lista"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/lista' ? 'active' : '' ?>">
• Ver Locaciones
</a>
<a href="/IMPORTADORES/agentes/alta"
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/agentes/alta') ? 'active' : '' ?>">
• Agregar Locaciones
</a>
</nav>
</div>
</nav>
</div>
<!-- OFFCANVAS PARA MÓVILES -->
<div class="offcanvas offcanvas-start d-md-none" tabindex="-1" id="sidebarMenu" style="top: 75px;">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Menú</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<!-- INICIO -->
<a href="/IMPORTADORES/agentes/dashboard"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/dashboard' ? 'active' : '' ?>">
🏠 Inicio
</a>
<!-- IMPORTADORES ACTIVOS -->
<a href="/IMPORTADORES/agentes/activos"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/activos' ? 'active' : '' ?>">
✅ Importadores Activos
</a>
<!-- SOLICITUDES PENDIENTES -->
<a href="/IMPORTADORES/agentes/solicitudes_pendientes"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/solicitudes_pendientes' ? 'active' : '' ?>">
📥 Solicitudes de Registro
</a>
<!-- BITÁCORA -->
<a href="/IMPORTADORES/agentes/bitacora"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/bitacora' ? 'active' : '' ?>">
🕓 Bitácora
</a>
<!-- LOCACIONES -->
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
<?= str_contains($_SERVER['REQUEST_URI'], '/agentes') ? 'active' : '' ?>"
data-bs-toggle="collapse" href="#submenuLocaciones" role="button" aria-expanded="false">
🗺️ Locaciones
<span class="badge bg-secondary">2</span>
</a>
<div class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/agentes') ? 'show' : '' ?>" id="submenuLocaciones">
<nav class="nav flex-column ms-3">
<a href="/IMPORTADORES/agentes/lista"
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/agentes/lista' ? 'active' : '' ?>">
• Ver Locaciones
</a>
<a href="/IMPORTADORES/agentes/alta"
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/agentes/alta') ? 'active' : '' ?>">
• Agregar Locaciones
</a>
</nav>
</div>
</div>
</div>

View File

@@ -50,6 +50,12 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
🏠 Inicio
</a>
<!-- LOCACIONES -->
<a href="/IMPORTADORES/importadores/lista"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/importadores/lista' ? 'active' : '' ?>">
🗺️ Locaciones
</a>
<!-- TRANSPORTISTAS -->
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
<?= str_contains($_SERVER['REQUEST_URI'], '/transportistas') ? 'active' : '' ?>"
@@ -194,6 +200,12 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
🏠 Inicio
</a>
<!-- LOCACIONES -->
<a href="/IMPORTADORES/importadores/lista"
class="nav-link px-3 py-2 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/importadores/lista' ? 'active' : '' ?>">
🗺️ Locaciones
</a>
<!-- TRANSPORTISTAS -->
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
<?= str_contains($_SERVER['REQUEST_URI'], '/transportistas') ? 'active' : '' ?>"

View File

@@ -50,7 +50,7 @@
</div>
<div class="col-md-3 mb-3">
<label for="proveedor_id" class="form-label">Proveedor</label>
<select id="proveedor_id" name="proveedor_id" class="form-select searchable" required>
<select id="proveedor_id" name="proveedor_id" class="form-select searchable">
<option value="">Cargando proveedores...</option>
</select>
</div>

View File

@@ -63,6 +63,7 @@
</div>
<div class="text-end mt-4">
<button type="submit" class="btn btn-success">Guardar</button>
<a href="/IMPORTADORES/transportes/lista" class="btn btn-secondary ms-2">Cancelar</a>
</div>
</form>
</div>

View File

@@ -75,6 +75,7 @@
</div>
<div class="text-end mt-4">
<button type="submit" class="btn btn-primary">Actualizar</button>
<a href="/IMPORTADORES/transportes/lista" class="btn btn-secondary ms-2">Cancelar</a>
</div>
</form>
</div>

View File

@@ -62,6 +62,7 @@
📥 Descargar plantilla
</a><br>
<button type="submit" class="btn btn-primary">Importar</button>
<a href="/IMPORTADORES/transportes/lista" class="btn btn-secondary ms-2">Cancelar</a>
</form>
</div>
</div>

View File

@@ -95,6 +95,7 @@
<div class="text-end mt-4">
<button class="btn btn-success px-4">Guardar Transportista</button>
<a href="/IMPORTADORES/transportistas/lista" class="btn btn-secondary ms-2">Cancelar</a>
</div>
</form>
</div>

View File

@@ -61,6 +61,7 @@ unset($_SESSION['import_errors'], $_SESSION['import_success']);
<input type="file" id="archivo_csv" name="archivo_csv" class="form-control" accept=".csv" required>
</div>
<button type="submit" class="btn btn-primary">🚀 Cargar Transportistas</button>
<a href="/IMPORTADORES/transportistas/lista" class="btn btn-secondary ms-2">Cancelar</a>
</form>
</div>
</div>

View File

@@ -110,6 +110,7 @@
</div>
<div class="text-end mt-4">
<button class="btn btn-success px-4">💾 Guardar Cambios</button>
<a href="/IMPORTADORES/transportistas/lista" class="btn btn-secondary ms-2">Cancelar</a>
</div>
</form>
</div>

View File

@@ -1,4 +1,3 @@
<!-- views/transportistas/lista.php -->
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
<!DOCTYPE html>