Files
MVE/views/transportistas/alta.php
2025-07-08 09:05:48 -06:00

476 lines
25 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_importador.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title> Alta de Transportista</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>
<!-- SweetAlert2 -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<!-- Animate.css para animaciones adicionales -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css">
<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; }
.navbar { position: fixed; top: 0; width: 100%; z-index: 1050; }
@media (min-width: 768px) { .content { margin-left: 250px; } }
@media (max-width: 767.98px) { .content { margin-left: 0; } }
.card { border-radius: 12px; }
/* Animaciones personalizadas */
.card-hover { transition: all 0.3s ease; cursor: pointer; }
.card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
.btn-pulse { animation: pulse 2s infinite; }
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
/* Responsive animations */
@media (max-width: 768px) { .card-hover:hover { transform: translateY(-4px) scale(1.01); } }
/* Efecto de glow para elementos activos */
.btn.active { box-shadow: 0 0 20px rgba(var(--bs-primary-rgb), 0.5); }
/* Animación para el título */
.title-glow { text-shadow: 0 0 10px rgba(0, 123, 255, 0.3); }
/* Efecto para botones */
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
.btn-animated:hover::before { left: 100%; }
/* ========== ANIMACIONES PARA INPUTS ========== */
/* 1. Animación al hacer focus */
.form-control { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
.form-control:focus { border-color: #0d6efd; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25), 0 0 20px rgba(13, 110, 253, 0.3); transform: translateY(-2px); }
/* 2. Animación al escribir */
.form-control:not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
/* 3. Efecto de shake en validación */
.form-control.shake { animation: shake 0.5s ease-in-out; }
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
/* 4. Floating labels con animación */
.form-floating-custom { position: relative; margin-bottom: 1.5rem; }
.form-floating-custom .form-control { padding: 1rem 0.75rem 0.5rem 0.75rem; height: auto; }
.form-floating-custom .form-label { position: absolute; top: 0.75rem; left: 0.75rem; transition: all 0.3s ease; pointer-events: none; color: #6c757d; z-index: 2; }
.form-floating-custom .form-control:focus ~ .form-label,
.form-floating-custom .form-control:not(:placeholder-shown) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
/* 5. Efecto de pulso en hover */
.input-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
@keyframes inputPulse {
0% { transform: scale(1); }
50% { transform: scale(1.02); }
100% { transform: scale(1); }
}
/* 6. Gradiente animado en el borde */
.input-gradient { position: relative; overflow: hidden; }
.input-gradient::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.3), transparent); transition: left 0.5s; pointer-events: none; z-index: 1; }
.input-gradient:focus::before { left: 100%; }
/* 7. Efecto de brillo en validación exitosa */
.form-control.valid { border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9); animation: successGlow 1s ease-in-out; }
@keyframes successGlow {
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
}
/* 8. Typing effect simulation */
.input-typing { position: relative; }
.input-typing::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
.input-typing:focus::after { opacity: 1; }
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
/* 9. Efecto de ondas */
.input-ripple { position: relative; overflow: hidden; }
.input-ripple::before { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(13, 110, 253, 0.2);
border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
.input-ripple:focus::before { width: 300px; height: 300px; }
/* 10. Slide-up animation para los campos */
.form-group-animated { opacity: 0; transform: translateY(20px); animation: slideUp 0.6s ease-out forwards; }
.form-group-animated:nth-child(1) { animation-delay: 0.1s; }
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
.form-group-animated:nth-child(3) { animation-delay: 0.3s; }
.form-group-animated:nth-child(4) { animation-delay: 0.4s; }
.form-group-animated:nth-child(5) { animation-delay: 0.5s; }
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
.form-group-animated:nth-child(7) { animation-delay: 0.7s; }
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
/* ========== ANIMACIONES PARA SELECT ========== */
/* 1. Estilos base para select */
.form-select {transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; cursor: pointer;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 6 7 7 7-7'/%3e%3c/svg%3e");
background-repeat: no-repeat; background-position: right 0.75rem center; background-size: 16px 12px; }
/* 2. Animación al hacer focus */
.form-select:focus { border-color: #0d6efd; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25), 0 0 20px rgba(13, 110, 253, 0.3); transform: translateY(-2px);
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%230d6efd' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 6 7 7 7-7'/%3e%3c/svg%3e"); }
/* 3. Animación cuando tiene valor seleccionado */
.form-select:not([value=""]):not(:invalid) { border-color: #198754; background-color: #f8fff9;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23198754' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 6 7 7 7-7'/%3e%3c/svg%3e"); padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
.form-floating-custom .form-select:focus ~ .form-label,
.form-floating-custom .form-select:not([value=""]) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
/* 5. Efecto de shake en validación para select */
.form-select.shake { animation: shake 0.5s ease-in-out; }
/* 6. Efecto de pulso en hover para select */
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
/* 7. Gradiente animado para select */
.select-gradient { position: relative; overflow: hidden; }
.select-gradient::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.3), transparent); transition: left 0.5s; pointer-events: none; z-index: 1; }
.select-gradient:focus::before { left: 100%; }
/* 8. Efecto de brillo en validación exitosa para select */
.form-select.valid { border-color: #198754; background-color: #f8fff9; animation: successGlow 1s ease-in-out; }
/* 9. Efecto de rotación de la flecha al abrir */
.select-arrow-rotate { transition: all 0.3s ease; }
.select-arrow-rotate:focus { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%230d6efd' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m1 10 7-7 7 7'/%3e%3c/svg%3e"); }
/* 10. Efecto de ondas para select */
.select-ripple { position: relative; overflow: hidden; }
.select-ripple::after { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0;
background: rgba(13, 110, 253, 0.2); border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; }
.select-ripple:focus::after { width: 300px; height: 300px; }
/* 11. Efecto de scale suave */
.select-scale { transition: transform 0.2s ease; }
.select-scale:hover { transform: scale(1.02); }
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
/* 12. Personalización de opciones (limitado en algunos navegadores) */
.form-select option { padding: 0.5rem; transition: all 0.2s ease; }
.form-select option:hover { background-color: #f8f9fa; }
/* 13. Indicador de estado */
.select-status { position: relative; }
.select-status::after { content: ''; position: absolute; right: 2.5rem; top: 50%; transform: translateY(-50%);
width: 8px; height: 8px; border-radius: 50%; background-color: #dc3545; opacity: 0; transition: opacity 0.3s ease; } .select-status.valid::after { background-color: #198754; opacity: 1; }
.select-status:invalid::after { background-color: #dc3545; opacity: 1; }
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow"> Alta de Transportista</h4>
<form action="/IMPORTADORES/transportistas/guardar" method="POST" class="card p-4 shadow-sm card-hover position-relative h-auto" id="formAltaTransportista">
<!-- Hidden para persona moral -->
<input type="hidden" name="es_persona_moral" id="es_persona_moral" value="0">
<!-- Switch Persona Moral -->
<div class="row mb-3">
<div class="col-md-4 d-flex align-items-end">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="personaMoralSwitch">
<label class="form-check-label" for="personaMoralSwitch">Es Persona Moral</label>
</div>
</div>
</div>
<div class="row g-3">
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<input name="clave" id="clave" type="text" class="form-control input-pulse input-gradient" maxlength="8" placeholder=" " required>
<label for="clave" class="form-label">Clave *</label>
</div>
</div>
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<input name="nombre" id="nombre" type="text" class="form-control input-pulse input-gradient" placeholder=" " required>
<label for="nombre" class="form-label" id="labelNombre">Nombre *</label>
</div>
</div>
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<input name="rfc" id="rfc" type="text" class="form-control input-pulse input-gradient" maxlength="13" placeholder=" " required>
<label for="rfc" class="form-label">RFC *</label>
</div>
</div>
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<input name="curp" id="curp" type="text" class="form-control input-pulse input-gradient" maxlength="18" placeholder=" ">
<label for="curp" class="form-label">CURP *</label>
</div>
</div>
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<input name="telefono" id="telefono" type="text" class="form-control input-pulse input-gradient" maxlength="11" placeholder=" " required>
<label for="telefono" class="form-label">Teléfono *</label>
</div>
</div>
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<input name="caat" id="caat" type="text" class="form-control input-pulse input-gradient" maxlength="20" placeholder=" " required>
<label for="caat" class="form-label">Código caat *</label>
</div>
</div>
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<select id="pais" name="pais" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
<option value=""></option>
<?php foreach($paises as $p): ?>
<option value="<?= $p['id_pais'] ?>"><?= htmlspecialchars($p['nombre']) ?></option>
<?php endforeach; ?>
</select>
<label for="pais" class="form-label">País</label>
</div>
</div>
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<select id="entidad" name="entidad" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required disabled>
<option value="">Primero país…</option>
</select>
<label for="entidad" class="form-label">Entidad</label>
</div>
</div>
<div class="col-md-4 form-group-animated">
<div class="form-floating-custom">
<select id="ciudad" name="ciudad" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required disabled>
<option value="">Primero estado…</option>
</select>
<label for="ciudad" class="form-label">Ciudad</label>
</div>
</div>
<div class="col-md-12 form-group-animated">
<div class="form-floating-custom">
<input name="domicilio" id="domicilio" type="text" class="form-control input-pulse input-gradient" maxlength="100" placeholder=" " required>
<label for="domicilio" class="form-label">Domicilio *</label>
</div>
</div>
</div>
<div class="text-end mt-4 form-group-animated">
<button class="btn btn-success px-4 mt-auto w-auto btn-animated">Guardar Transportista</button>
<a href="/IMPORTADORES/transportistas/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
</div>
</form>
</div>
<script>
document.getElementById('formAltaTransportista').addEventListener('submit', function(e) {
e.preventDefault();
const rfcInput = document.getElementById('rfc');
const curpInput = document.getElementById('curp');
const telefonoInput = document.getElementById('telefono');
const rfc = rfcInput.value.trim().toUpperCase();
const curp = curpInput.value.trim();
const telefono = telefonoInput.value.trim();
const clave = document.getElementById('clave').value.trim();
const nombre = document.getElementById('nombre').value.trim();
const caat = document.getElementById('caat').value.trim();
const pais = document.getElementById('pais').value;
const entidad = document.getElementById('entidad').value;
const ciudad = document.getElementById('ciudad').value;
const domicilio = document.getElementById('domicilio').value.trim();
const curpRegex = /^[A-Z]{4}[0-9]{6}[HM](AS|BC|BS|CC|CL|CM|CS|CH|DF|DG|GT|GR|HG|JC|MC|MN|MS|NT|NL|OC|PL|QT|QR|SP|SL|SR|TC|TS|TL|VZ|YN|ZS)[A-Z]{3}[A-Z0-9]{2}$/;
const rfcRegex = /^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/;
const telefonoRegex = /^\d{3}\s\d{7}$/;
if (!clave) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'La clave es obligatoria.', confirmButtonColor: '#dc3545'});
document.getElementById('clave').focus();
return;
}
if (clave.length>8) {
Swal.fire({ icon: 'error', title: 'Clave inválida', text: 'La clave no puede tener más de 8 caracteres.', confirmButtonColor: '#dc3545'});
document.getElementById('clave').focus();
return;
}
if (!nombre) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'El nombre es obligatorio.', confirmButtonColor: '#dc3545'});
document.getElementById('nombre').focus();
return;
}
if (!rfc) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'El RFC es obligatorio.', confirmButtonColor: '#dc3545'});
document.getElementById('rfc').focus();
return;
}
if (!rfcRegex.test(rfc)) {
Swal.fire({ icon: 'error', title: 'RFC inválido', text: 'El RFC debe tener 12 o 13 caracteres con el formato correcto (ej. ABC123456XYZ).', confirmButtonColor: '#dc3545'});
document.getElementById('rfc').focus();
return;
}
if (curp && !curpRegex.test(curp)) {
Swal.fire({ icon: 'error', title: 'CURP inválido', text: 'El CURP no tiene el formato correcto.', confirmButtonColor: '#dc3545'});
document.getElementById('curp').focus();
return;
}
if (!telefono) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'El teléfono es obligatorio.', confirmButtonColor: '#dc3545'});
document.getElementById('telefono').focus();
return;
}
if (!telefonoRegex.test(telefono)) {
Swal.fire({ icon: 'error', title: 'Teléfono inválido', text: 'Debe tener 10 dígitos en el formato: 3 dígitos (LADA), espacio, y 7 dígitos (ej. 123 4567890).', onfirmButtonColor:'#dc3545'});
document.getElementById('telefono').focus();
return;
}
if (telefono.length>11) {
Swal.fire({ icon: 'error', title: 'Teléfono inválido', text: 'El teléfono no puede tener más de 11 caracteres.', confirmButtonColor: '#dc3545'});
document.getElementById('telefono').focus();
return;
}
if (!caat) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'El código caat es obligatorio.', confirmButtonColor: '#dc3545'});
document.getElementById('caat').focus();
return;
}
if (!pais) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Debe seleccionar un país.', confirmButtonColor: '#dc3545'});
document.getElementById('pais').focus();
return;
}
if (!entidad) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Debe seleccionar un estado.', confirmButtonColor: '#dc3545'});
document.getElementById('entidad').focus();
return;
}
if (!ciudad) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Debe seleccionar una ciudad.', confirmButtonColor: '#dc3545'});
document.getElementById('ciudad').focus();
return;
}
if (!domicilio) {
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'El domicilio es obligatorio.', confirmButtonColor: '#dc3545'});
document.getElementById('domicilio').focus();
return;
}
document.getElementById('rfc').value = rfc;
document.getElementById('curp').value = curp;
this.submit();
});
document.getElementById('pais').addEventListener('change', e => {
const pid = e.target.value;
const estadoSelect = document.getElementById('entidad');
const ciudadSelect = document.getElementById('ciudad');
estadoSelect.innerHTML = '<option value="">Cargando…</option>';
estadoSelect.disabled = true;
ciudadSelect.innerHTML = '<option value="">Primero estado…</option>';
ciudadSelect.disabled = true;
if (!pid) { estadoSelect.innerHTML = '<option value="">Primero país…</option>'; return; }
fetch(`/IMPORTADORES/transportistas/estados?pais=${pid}`)
.then(r => { if (!r.ok) throw new Error('Error al cargar estados'); return r.json(); })
.then(list => {
estadoSelect.innerHTML = '<option value=""></option>';
list.forEach(st => estadoSelect.add(new Option(st.nombre, st.id_estado)));
estadoSelect.disabled = false;
})
.catch(() => {
estadoSelect.innerHTML = '<option value="">Error al cargar</option>';
Swal.fire({ icon:'error',title:'Error',text:'No se pudieron cargar los estados',confirmButtonColor:'#dc3545'});
});
});
document.getElementById('entidad').addEventListener('change', e => {
const eid = e.target.value;
const ciudadSelect = document.getElementById('ciudad');
ciudadSelect.innerHTML = '<option value="">Cargando…</option>';
ciudadSelect.disabled = true;
if (!eid) { ciudadSelect.innerHTML = '<option value="">Primero estado…</option>'; return; }
fetch(`/IMPORTADORES/transportistas/ciudades?estado=${eid}`)
.then(r => { if (!r.ok) throw new Error('Error al cargar ciudades'); return r.json(); })
.then(list => {
ciudadSelect.innerHTML = '<option value=""></option>';
list.forEach(ct => ciudadSelect.add(new Option(ct.nombre, ct.id_ciudad)));
ciudadSelect.disabled = false;
})
.catch(() => {
ciudadSelect.innerHTML = '<option value="">Error al cargar</option>';
Swal.fire({ icon:'error',title:'Error',text:'No se pudieron cargar las ciudades',confirmButtonColor:'#dc3545'});
});
});
// Switch Persona Moral
document.getElementById('personaMoralSwitch').addEventListener('change', function() {
const checked = this.checked;
const label = document.getElementById('labelNombre');
const curp = document.getElementById('curp');
const hidden = document.getElementById('es_persona_moral');
if (checked) {
label.textContent = 'Razón Social *';
curp.value = '';
curp.disabled = true;
curp.removeAttribute('required');
hidden.value = '1';
} else {
label.textContent = 'Nombre *';
curp.disabled = false;
curp.setAttribute('required', 'required');
hidden.value = '0';
}
});
// Script para manejar las animaciones de validación
document.addEventListener('DOMContentLoaded', function() {
const inputs = document.querySelectorAll('input.form-control, select.form_select');
inputs.forEach(input => {
// Validación en tiempo real
input.addEventListener('input', function() {
if (this.checkValidity()) {
this.classList.remove('shake');
this.classList.add('valid');
} else {
this.classList.remove('valid');
}
});
// Efecto shake en campos inválidos
input.addEventListener('invalid', function() {
this.classList.add('shake');
setTimeout(() => {
this.classList.remove('shake');
}, 500);
});
});
// Validación del formulario
document.getElementById('formAltaAgencias').addEventListener('submit', function(e) {
e.preventDefault();
let isValid = true;
inputs.forEach(input => {
if (!input.checkValidity()) {
input.classList.add('shake');
isValid = false;
}
});
if (isValid) {
// Aquí puedes agregar tu lógica de envío
Swal.fire({
icon: 'success',
title: '¡Éxito!',
text: 'Agencia registrada correctamente',
showConfirmButton: false,
timer: 1500
});
}
});
});
</script>
</body>
</html>