Files
MVE/views/locaciones/gestion_locaciones.php
2025-06-09 08:50:23 -06:00

492 lines
20 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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>