Files
MVE/views/choferes/crear.php
2025-07-16 12:43:21 -06:00

483 lines
27 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'; ?>
<!-- views/choferes/crear.php -->
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title> Nuevo Chofer</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>
<!-- 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">
<!-- CSS de Flatpickr -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<!-- JS de Flatpickr -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<!-- Idioma español -->
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/es.js"></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; }
/* 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 TEXTO ========== */
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
.form-control:not(.no-animation):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); }
.form-control:not(.no-animation):not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-5px); }
75% { transform: translateX(5px); }
}
/* Floating labels para inputs texto */
.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; }
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
@keyframes inputPulse {
0% { transform: scale(1); }
50% { transform: scale(1.02); }
100% { transform: scale(1); }
}
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
.input-gradient:not(.no-animation)::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:not(.no-animation):focus::before { left: 100%; }
.form-control.valid:not(.no-animation) { 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); }
}
.input-typing:not(.no-animation) { position: relative; }
.input-typing:not(.no-animation)::after { content: '|'; position: absolute; right: 10px; top: 50%; transform: translateY(-50%); opacity: 0; animation: blink 1s infinite; color: #0d6efd; }
.input-typing:not(.no-animation):focus::after { opacity: 1; }
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
.input-ripple:not(.no-animation) { position: relative; overflow: hidden; }
.input-ripple:not(.no-animation)::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:not(.no-animation):focus::before { width: 300px; height: 300px; }
/* Animación para los campos del formulario */
.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; }
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
/* ========== ANIMACIONES 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; padding: 1rem 2.5rem 0.5rem 0.75rem; height: auto; min-height: 3.5rem; }
.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"); }
.form-select:not([value=""]):valid { 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"); }
.form-select[value=""] { border-color: #dee2e6; background-color: #fff; }
/* Floating labels para select */
.form-floating-custom .form-select ~ .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%); pointer-events: none;
transition: all 0.3s ease; color: #6c757d; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; opacity: 0; }
.form-floating-custom .form-select:focus ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
.form-floating-custom .form-select:not([value=""]):valid ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
.form-select.shake { animation: shake 0.5s ease-in-out; }
.select-pulse:hover { animation: inputPulse 0.6s ease-in-out; }
.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%; }
.form-select.valid { border-color: #198754; background-color: #f8fff9; animation: successGlow 1s ease-in-out; }
.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"); }
.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; }
.select-scale { transition: transform 0.2s ease; }
.select-scale:hover {transform: scale(1.02); }
.select-scale:focus { transform: scale(1.02) translateY(-2px); }
.form-select option { padding: 0.5rem; transition: all 0.2s ease; }
.form-select option:hover { background-color: #f8f9fa; }
.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; }
/* ========== ESTILOS PARA CAMPO FECHA ========== */
.form-floating-fecha { position: relative; margin-bottom: 1.5rem; }
.form-floating-fecha .form-control { padding: 1rem 0.75rem; transition: all 0.3s ease; border: 2px solid #dee2e6; }
.form-floating-fecha .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); }
.form-floating-fecha .form-control:not(:placeholder-shown) { border-color: #198754; background-color: #f8fff9; }
.form-floating-fecha .form-label { position: absolute; top: 50%; left: 0.75rem; transform: translateY(-50%);pointer-events: none;
transition: all 0.3s ease; color: #6c757d; opacity: 0; font-size: 0.875rem; background: white; padding: 0 0.25rem; z-index: 1; }
.form-floating-fecha .form-control:focus ~ .form-label,
.form-floating-fecha .form-control:not(:placeholder-shown) ~ .form-label { opacity: 1; top: 0; transform: translateY(-50%) scale(0.85); color: #0d6efd; font-weight: 600; }
.form-floating-fecha .form-control:focus, .form-floating-fecha .form-control:not(:placeholder-shown) { padding-top: 1.625rem; padding-bottom: 0.625rem; }
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
.no-animation, .no-border-style { transition: none !important; border: none; box-shadow: none !important; background: #fff !important; }
.no-animation:focus { transform: none !important; border: none; box-shadow: none !important; }
.no-animation:hover { animation: none !important; }
.no-animation::before, .no-animation::after { display: none !important; }
</style>
</head>
<body>
<div class="content">
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow"> Nuevo Chofer</h4>
<div class="card p-4 shadow-sm bg-white card-hover position-relative h-auto">
<!-- Se agrega enctype para subir archivos -->
<form action="/IMPORTADORES/choferes/guardar" method="POST" enctype="multipart/form-data" id="formAltaChoferes">
<div class="row mb-3">
<div class="col-md-12 form-group-animated">
<label for="" class="form-label">Transportista</label>
<div class="form-floating-custom">
<select name="transportista_id" id="transportista_id" class="form-select select-pulse select-gradient select-arrow-rotate select-status" required>
<option value="">-- Selecciona un transportista --</option>
<?php foreach ($transportistas as $t): ?>
<option value="<?= $t['id_transportista'] ?>">
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre'] . ' - ' . $t['ciudad_nombre'] . ' - ' . $t['domicilio']) ?>
</option>
<?php endforeach; ?>
</select>
<label for="transportista_id" class="form-label">Transportista</label>
</div>
</div>
<div class="col-md-6 form-group-animated">
<label for="" class="form-label">Nombre</label>
<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">Nombre</label>
</div>
</div>
<div class="col-md-6 form-group-animated">
<label for="" class="form-label">Apellidos</label>
<div class="form-floating-custom">
<input name="apellido" id="apellido" type="text" class="form-control input-pulse input-gradient" placeholder="" required>
<label for="apellido" class="form-label">Apellidos</label>
</div>
</div>
<div class="col-md-6 form-group-animated">
<label for="" class="form-label">Número de Licencia</label>
<div class="form-floating-custom">
<input name="numero_licencia" id="numero_licencia" type="text" maxlength="11" class="form-control input-pulse input-gradient" placeholder="" required>
<label for="numero_licencia" class="form-label">Número de Licencia</label>
</div>
</div>
<div class="col-md-6 form-group-animated">
<label for="" class="form-label">Número de Gafete</label>
<div class="form-floating-custom">
<input name="numero_gafete" id="numero_gafete" type="text" maxlength="24" class="form-control input-pulse input-gradient" placeholder="" required>
<label for="numero_gafete" class="form-label">Número de Gafete</label>
</div>
</div>
<div class="col-md-6 form-group-animated">
<label for="" class="form-label">Teléfono</label>
<div class="form-floating-custom">
<input name="telefono" id="telefono" type="tel" maxlength="11" class="form-control input-pulse input-gradient" placeholder="">
<label for="telefono" class="form-label">Teléfono</label>
</div>
</div>
<div class="col-md-6 form-group-animated">
<label for="" class="form-label">Email</label>
<div class="form-floating-custom">
<input name="email" id="email" type="email" class="form-control input-pulse input-typing" placeholder="">
<label for="email" class="form-label">Email</label>
</div>
</div>
<div class="col-md-6 form-group-animated">
<label for="" class="form-label">Fecha de Ingreso</label>
<div class="form-floating-fecha">
<input name="fecha_ingreso" id="fecha_ingreso" type="text" class="form-control input-pulse input-gradient" placeholder="dd/mm/aaaa">
<label for="fecha_ingreso" class="form-label">Fecha de Ingreso</label>
</div>
</div>
<!-- Nuevo campo para foto -->
<div class="col-md-6 form-group-animated">
<label for="foto" class="form-label">Foto del Chofer (Opcional)</label>
<div class="form-floating-custom">
<input name="foto" id="foto" type="file" class="form-control no-animation no-border-style" accept="image/*">
</div>
</div>
<div class="text-end mt-4 form-group-animated">
<button type="submit" class="btn btn-success mt-auto w-auto btn-animated">Guardar</button>
<a href="/IMPORTADORES/choferes/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
</div>
</div>
</form>
</div>
</div>
<script>
document.getElementById('formAltaChoferes').addEventListener('submit', function(e) {
e.preventDefault(); // Prevenir envío por defecto
// Obtener todos los campos correctamente
const transportista_id = document.getElementById('transportista_id').value;
const nombre = document.getElementById('nombre').value.trim();
const apellido = document.getElementById('apellido').value.trim();
const numero_licencia = document.getElementById('numero_licencia').value.trim();
const numero_gafete = document.getElementById('numero_gafete').value.trim();
const telefono = document.getElementById('telefono').value.trim();
const email = document.getElementById('email').value.trim();
const fecha_ingreso = document.getElementById('fecha_ingreso').value;
const foto = document.getElementById('foto').files[0];
// Expresiones regulares
const telefonoRegex = /^\d{3}\s\d{7}$/;
const emailRegex = /^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const soloNumerosRegex = /^[0-9]+$/;
const fechaRegex = /^\d{2}\/\d{2}\/\d{4}$/; // formato dd/mm/aaaa
// VALIDAR CAMPOS OBLIGATORIOS PRIMERO
if (!transportista_id) {
Swal.fire({ icon: 'warning', title: 'Transportista requerido', text: 'Por favor selecciona un transportista.', confirmButtonColor: '#dc3545' });
document.getElementById('transportista_id').focus();
return;
}
if (!nombre) {
Swal.fire({ icon: 'warning', title: 'Nombre requerido', text: 'Por favor ingresa el nombre.', confirmButtonColor: '#dc3545' });
document.getElementById('nombre').focus();
return;
}
if (!apellido) {
Swal.fire({ icon: 'warning', title: 'Apellido requerido', text: 'Por favor ingresa el apellido.', confirmButtonColor: '#dc3545' });
document.getElementById('apellido').focus();
return;
}
if (!numero_licencia) {
Swal.fire({ icon: 'warning', title: 'Número de Licencia requerido', text: 'Por favor ingresa el número de licencia.', confirmButtonColor: '#dc3545' });
document.getElementById('numero_licencia').focus();
return;
}
if (!numero_gafete) {
Swal.fire({ icon: 'warning', title: 'Número de Gafete requerido', text: 'Por favor ingresa el número de gafete.', confirmButtonColor: '#dc3545' });
document.getElementById('numero_gafete').focus();
return;
}
if (!soloNumerosRegex.test(numero_licencia)) {
Swal.fire({ icon: 'error', title: 'Número de Licencia inválido', text: 'El número de licencia solo puede contener números', confirmButtonColor: '#dc3545' });
document.getElementById('numero_licencia').focus();
return;
}
// VALIDAR CAMPOS OPCIONALES (solo si tienen contenido)
if (telefono && !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. Ejemplo: 123 4567890', confirmButtonColor: '#dc3545' });
document.getElementById('telefono').focus();
return;
}
if (email && !emailRegex.test(email)) {
Swal.fire({ icon: 'error', title: 'Email inválido', text: 'Por favor ingresa una dirección de email válida.', confirmButtonColor: '#dc3545' });
document.getElementById('email').focus();
return;
}
// VALIDAR FECHA DE INGRESO (solo si se proporciona)
if (fecha_ingreso) {
// Validar formato primero
if (!fechaRegex.test(fecha_ingreso)) {
Swal.fire({ icon: 'error', title: 'Formato de fecha inválido', text: 'La fecha debe tener el formato dd/mm/aaaa', confirmButtonColor: '#dc3545' });
document.getElementById('fecha_ingreso').focus();
return;
}
// Convertir fecha correctamente (dd/mm/aaaa -> mm/dd/aaaa)
const [dia, mes, año] = fecha_ingreso.split('/');
const fechaIngreso = new Date(año, mes - 1, dia); // mes - 1 porque Date usa 0-11
const fechaActual = new Date();
fechaActual.setHours(0, 0, 0, 0); // Normalizar a medianoche
if (fechaIngreso > fechaActual) {
Swal.fire({ icon: 'error', title: 'Fecha inválida', text: 'La fecha de ingreso no puede ser futura.', confirmButtonColor: '#dc3545' });
document.getElementById('fecha_ingreso').focus();
return;
}
}
// VALIDAR FOTO (solo si se seleccionó)
if (foto) {
// Validar tamaño (máximo 2 MB)
if (foto.size > 2 * 1024 * 1024) {
Swal.fire({ icon: 'error', title: 'Foto demasiado grande', text: 'La imagen no debe exceder 2 MB.', confirmButtonColor: '#dc3545' });
document.getElementById('foto').focus();
return;
}
// Validar tipo de archivo
const tiposPermitidos = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'];
if (!tiposPermitidos.includes(foto.type)) {
Swal.fire({ icon: 'error', title: 'Tipo de archivo inválido', text: 'Solo se permiten archivos de imagen (JPG, PNG, GIF).', confirmButtonColor: '#dc3545' });
document.getElementById('foto').focus();
return;
}
}
// VALIDACIÓN ASÍNCRONA DE DUPLICADO DE GAFETE
fetch(`/IMPORTADORES/choferes/validarNumeroGafete?numero_gafete=${encodeURIComponent(numero_gafete)}`)
.then(response => response.json())
.then(data => {
if (data.success && data.existe) {
Swal.fire({ icon: 'error', title: 'Número de Gafete duplicado', text: 'El número de gafete ya está en uso, por favor ingresa uno diferente.', confirmButtonColor: '#dc3545' });
document.getElementById('numero_gafete').focus();
} else {
// Si no existe, enviamos el formulario
e.target.submit();
}
})
.catch(error => {
console.error('Error validando el número de gafete:', error);
Swal.fire({ icon: 'error', title: 'Error de validación', text: 'No fue posible validar el número de gafete. Intenta de nuevo.', confirmButtonColor: '#dc3545' });
});
});
// 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('formAltaChoferes').addEventListener('submit', function(e) {
e.preventDefault();
let isValid = true;
const form = this;
inputs.forEach(input => {
if (!input.checkValidity()) {
input.classList.add('shake');
isValid = false;
}
});
});
});
// Manejo específico para selects
document.addEventListener('DOMContentLoaded', function() {
const selects = document.querySelectorAll('.form-select');
selects.forEach(select => {
// Manejar cambios en el select
select.addEventListener('change', function() {
updateSelectState(this);
});
// Estado inicial
updateSelectState(select);
});
function updateSelectState(select) {
// Actualizar el atributo value para que el CSS pueda detectarlo
select.setAttribute('value', select.value);
// Agregar/quitar clase valid basado en si hay valor seleccionado
if (select.value && select.value !== '') {
select.classList.add('valid');
select.classList.remove('invalid');
} else {
select.classList.remove('valid');
// Solo agregar invalid si el campo es required y se ha intentado enviar
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
select.classList.add('invalid');
}
}
}
});
// Inicializar Flatpickr para la fecha
flatpickr("#fecha_ingreso", {
dateFormat: "d/m/Y",
locale: "es",
maxDate: "today",
onChange: function(selectedDates, dateStr, instance) {
// Validar que la fecha no sea futura
const today = new Date();
today.setHours(0, 0, 0, 0);
if (selectedDates[0] > today) {
showNotification('La fecha de ingreso no puede ser futura.', 'error');
instance.clear();
}
}
});
</script>
</body>
</html>