Files
MVE/views/proveedores/crear.php
2025-07-18 12:21:26 -06:00

358 lines
18 KiB
PHP
Raw Permalink 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.

<!-- views/proveedores/crear.php -->
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title> Registro de Proveedor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- 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 { color: #ccc; padding: 12px 20px; }
.sidebar .nav-link:hover,
.sidebar .nav-link.active { background-color: #495057; color: #fff; }
.content { margin-top: 56px; padding: 40px 20px; background-color: #f4f6f9; transition: margin-left .3s ease; }
@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 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); }
}
/* 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); } }
</style>
</head>
<body>
<?php
// Mostrar alerta si hay error en sesión
if (!empty($_SESSION['flash_error'])):
?>
<script>
Swal.fire({
icon: 'error',
title: 'Error al registrar',
text: '<?= addslashes($_SESSION['flash_error']) ?>'
});
</script>
<?php
unset($_SESSION['flash_error']);
endif;
?>
<div class="content">
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow"> Registro de Proveedor</h4>
<div class="card p-4 shadow-sm card-hover position-relative h-auto fade-in-up">
<form action="/IMPORTADORES/proveedores/guardar" method="POST" enctype="multipart/form-data" id="formAltaProveedores">
<div class="row g-3">
<div class="col-md-4 form-group-animated">
<label for="Clave" class="form-label">Clave *</label>
<input type="text" name="Clave" id="Clave" class="form-control" maxlength="20" required>
</div>
<div class="col-md-8 form-group-animated">
<label for="Nombre" class="form-label">Nombre *</label>
<input type="text" name="Nombre" id="Nombre" class="form-control" required>
</div>
<div class="col-md-4 form-group-animated">
<label for="RFC" class="form-label">RFC *</label>
<input type="text" name="RFC" id="RFC" class="form-control" maxlength="13" required>
</div>
<div class="col-md-4 form-group-animated">
<label for="Ciudad" class="form-label">Ciudad *</label>
<input type="text" name="Ciudad" id="Ciudad" class="form-control" required>
</div>
<div class="col-md-4 form-group-animated">
<label for="Telefono" class="form-label">Teléfono</label>
<input type="tel" name="Telefono" id="Telefono" maxlength="11" class="form-control">
</div>
<div class="col-md-6 form-group-animated">
<label for="Pais" class="form-label">País</label>
<input type="text" name="Pais" id="Pais" class="form-control">
</div>
<div class="col-md-6 form-group-animated">
<label for="EntidadFederativa" class="form-label">Entidad Federativa</label>
<input type="text" name="EntidadFederativa" id="EntidadFederativa" class="form-control">
</div>
<div class="col-md-4 form-group-animated">
<label for="Municipio" class="form-label">Municipio</label>
<input type="text" name="Municipio" id="Municipio" class="form-control">
</div>
<div class="col-md-4 form-group-animated">
<label for="Colonia" class="form-label">Colonia</label>
<input type="text" name="Colonia" id="Colonia" class="form-control">
</div>
<div class="col-md-4 form-group-animated">
<label for="CodigoPostal" class="form-label">Código Postal</label>
<input type="text" name="CodigoPostal" id="CodigoPostal" maxlength="5" class="form-control">
</div>
</div>
<div class="mt-4 text-end form-group-animated">
<a href="/IMPORTADORES/proveedores" class="btn btn-secondary me-2 mt-auto w-auto btn-animated">Cancelar</a>
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Guardar Proveedor</button>
</div>
</form>
</div>
</div>
<!-- Bootstrap JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.getElementById('formAltaProveedores').addEventListener('submit', function(e) {
e.preventDefault(); // Prevenir envío por defecto
// Obtener todos los campos
const clave = document.getElementById('Clave').value.trim();
const nombre = document.getElementById('Nombre').value.trim();
const rfc = document.getElementById('RFC').value.trim().toUpperCase();
const ciudad = document.getElementById('Ciudad').value.trim();
const telefono = document.getElementById('Telefono').value.trim();
const pais = document.getElementById('Pais').value.trim();
const entidadFederativa = document.getElementById('EntidadFederativa').value.trim();
const municipio = document.getElementById('Municipio').value.trim();
const colonia = document.getElementById('Colonia').value.trim();
const codigoPostal = document.getElementById('CodigoPostal').value.trim();
// Expresiones regulares
const rfcRegex = /^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/;
const telefonoRegex = /^\d{3}\s\d{7}$/;
const codigoPostalRegex = /^\d{5}$/;
const soloLetrasRegex = /^[a-zA-ZáéíóúÁÉÍÓÚñÑ\s]+$/;
const alfanumericoRegex = /^[a-zA-Z0-9áéíóúÁÉÍÓÚñÑ\s]+$/;
// VALIDAR CAMPOS OBLIGATORIOS
if (!clave) {
Swal.fire({ icon: 'warning', title: 'Clave requerida', text: 'Por favor ingresa la clave del proveedor.', confirmButtonColor: '#dc3545' });
document.getElementById('Clave').focus();
return;
}
if (clave.length < 2 || clave.length > 20) {
Swal.fire({ icon: 'error', title: 'Clave inválida', text: 'La clave debe tener entre 2 y 20 caracteres.', confirmButtonColor: '#dc3545' });
document.getElementById('Clave').focus();
return;
}
if (!alfanumericoRegex.test(clave)) {
Swal.fire({ icon: 'error', title: 'Clave inválida', text: 'La clave solo puede contener letras, números y espacios.', confirmButtonColor: '#dc3545'
});
document.getElementById('Clave').focus();
return;
}
if (!nombre) {
Swal.fire({ icon: 'warning', title: 'Nombre requerido', text: 'Por favor ingresa el nombre del proveedor.', confirmButtonColor: '#dc3545' });
document.getElementById('Nombre').focus();
return;
}
if (nombre.length < 2 || nombre.length > 100) {
Swal.fire({ icon: 'error', title: 'Nombre inválido', text: 'El nombre debe tener entre 2 y 100 caracteres.', confirmButtonColor: '#dc3545' });
document.getElementById('Nombre').focus();
return;
}
if (!rfc) {
Swal.fire({ icon: 'warning', title: 'RFC requerido', text: 'Por favor ingresa el RFC del proveedor.', 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 (!ciudad) {
Swal.fire({ icon: 'warning', title: 'Ciudad requerida', text: 'Por favor ingresa la ciudad del proveedor.', confirmButtonColor: '#dc3545' });
document.getElementById('Ciudad').focus();
return;
}
if (!soloLetrasRegex.test(ciudad)) {
Swal.fire({ icon: 'error', title: 'Ciudad inválida', text: 'La ciudad solo puede contener letras y espacios.', confirmButtonColor: '#dc3545' });
document.getElementById('Ciudad').focus();
return;
}
// VALIDAR CAMPOS OPCIONALES (solo si tienen contenido)
if (telefono) {
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. Ejemplo: 123 4567890', confirmButtonColor: '#dc3545' });
document.getElementById('Telefono').focus();
return;
}
}
if (pais) {
if (!soloLetrasRegex.test(pais)) {
Swal.fire({ icon: 'error', title: 'País inválido', text: 'El país solo puede contener letras y espacios.', confirmButtonColor: '#dc3545' });
document.getElementById('Pais').focus();
return;
}
if (pais.length < 2 || pais.length > 50) {
Swal.fire({ icon: 'error', title: 'País inválido', text: 'El país debe tener entre 2 y 50 caracteres.', confirmButtonColor: '#dc3545'
});
document.getElementById('Pais').focus();
return;
}
}
if (entidadFederativa) {
if (!soloLetrasRegex.test(entidadFederativa)) {
Swal.fire({ icon: 'error', title: 'Entidad Federativa inválida', text: 'La entidad federativa solo puede contener letras y espacios.', confirmButtonColor: '#dc3545' });
document.getElementById('EntidadFederativa').focus();
return;
}
if (entidadFederativa.length < 2 || entidadFederativa.length > 50) {
Swal.fire({ icon: 'error', title: 'Entidad Federativa inválida', text: 'La entidad federativa debe tener entre 2 y 50 caracteres.', confirmButtonColor: '#dc3545' });
document.getElementById('EntidadFederativa').focus();
return;
}
}
if (municipio) {
if (!soloLetrasRegex.test(municipio)) {
Swal.fire({ icon: 'error', title: 'Municipio inválido', text: 'El municipio solo puede contener letras y espacios.', confirmButtonColor: '#dc3545' });
document.getElementById('Municipio').focus();
return;
}
if (municipio.length < 2 || municipio.length > 50) {
Swal.fire({ icon: 'error', title: 'Municipio inválido', text: 'El municipio debe tener entre 2 y 50 caracteres.', confirmButtonColor: '#dc3545' });
document.getElementById('Municipio').focus();
return;
}
}
if (colonia) {
if (!alfanumericoRegex.test(colonia)) {
Swal.fire({ icon: 'error', title: 'Colonia inválida', text: 'La colonia solo puede contener letras, números y espacios.', confirmButtonColor: '#dc3545'
});
document.getElementById('Colonia').focus();
return;
}
if (colonia.length < 2 || colonia.length > 50) {
Swal.fire({ icon: 'error', title: 'Colonia inválida', text: 'La colonia debe tener entre 2 y 50 caracteres.', confirmButtonColor: '#dc3545' });
document.getElementById('Colonia').focus();
return;
}
}
if (codigoPostal) {
if (!codigoPostalRegex.test(codigoPostal)) {
Swal.fire({ icon: 'error', title: 'Código Postal inválido', text: 'El código postal debe tener exactamente 5 dígitos.', confirmButtonColor: '#dc3545' });
document.getElementById('CodigoPostal').focus();
return;
}
}
// Actualizar el valor del RFC en mayúsculas antes de enviar
document.getElementById('RFC').value = rfc;
// SI TODAS LAS VALIDACIONES PASAN, ENVIAR EL FORMULARIO
this.submit();
});
// Script para manejar las animaciones de validación
document.addEventListener('DOMContentLoaded', function() {
const inputs = document.querySelectorAll('input.form-control');
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('formAltaProveedores').addEventListener('submit', function(e) {
e.preventDefault();
let isValid = true;
inputs.forEach(input => {
if (!input.checkValidity()) {
input.classList.add('shake');
isValid = false;
}
});
});
});
</script>
</body>
</html>