256 lines
7.8 KiB
JavaScript
256 lines
7.8 KiB
JavaScript
document.addEventListener("DOMContentLoaded", () => {
|
||
|
||
if (serverErrors.length > 0) mostrarErrores(serverErrors);
|
||
if (serverSuccess.length > 0) mostrarSuccess(serverSuccess);
|
||
|
||
const form = document.getElementById("form-crear-usuario") || document.getElementById("form-editar-usuario");
|
||
if (!form) return;
|
||
|
||
// Si no hay submit (operador), no validar
|
||
|
||
if (!form.querySelector("button[type='submit']")) return;
|
||
|
||
// Funciones utilitarias
|
||
|
||
function isEmpty(value) {
|
||
return !value || value.trim() === '';
|
||
}
|
||
|
||
function hasNoSpaces(value) {
|
||
return !value.includes(' ');
|
||
}
|
||
|
||
function isValidEmail(email) {
|
||
return /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email);
|
||
}
|
||
|
||
function isValidName(value) {
|
||
return /^[A-ZÁÉÍÓÚÑ][a-záéíóúñ]+(?: [A-ZÁÉÍÓÚÑ][a-záéíóúñ]+)*$/.test(value);
|
||
}
|
||
|
||
function isValidUsername(value) {
|
||
return /^(?=.*[a-zA-Z])(?!.*[._]{2})[a-zA-Z0-9._]{5,30}$/.test(value);
|
||
}
|
||
|
||
function isValidPassword(value) {
|
||
return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{6,}$/.test(value);
|
||
}
|
||
|
||
// Submit
|
||
|
||
form.addEventListener("submit", (e) => {
|
||
|
||
let errores = [];
|
||
|
||
const nombre = form.querySelector("input[name='nombre']");
|
||
const apellido = form.querySelector("input[name='apellido']");
|
||
const usuario = form.querySelector("input[name='usuario']");
|
||
const telefono = form.querySelector("input[name='telefono']");
|
||
const email = form.querySelector("input[name='email']");
|
||
const password = form.querySelector("input[name='password']");
|
||
|
||
// Limpiar estados previos
|
||
|
||
form.querySelectorAll(".is-invalid").forEach(el =>
|
||
el.classList.remove("is-invalid")
|
||
);
|
||
|
||
// NOMBRE
|
||
|
||
if (nombre) {
|
||
if (isEmpty(nombre.value)) {
|
||
errores.push("El nombre es obligatorio.");
|
||
nombre.classList.add("is-invalid");
|
||
} else if (!isValidName(nombre.value)) {
|
||
errores.push("El nombre debe comenzar con mayúscula y solo contener letras.");
|
||
nombre.classList.add("is-invalid");
|
||
} else if (nombre.value.length < 2) {
|
||
errores.push("El nombre debe tener al menos 2 caracteres.");
|
||
nombre.classList.add("is-invalid");
|
||
} else if (nombre.value.length > 50) {
|
||
errores.push("El nombre no puede superar los 50 caracteres.");
|
||
nombre.classList.add("is-invalid");
|
||
}
|
||
}
|
||
|
||
// APELLIDO
|
||
|
||
if (apellido) {
|
||
if (isEmpty(apellido.value)) {
|
||
errores.push("El apellido es obligatorio.");
|
||
apellido.classList.add("is-invalid");
|
||
} else if (!isValidName(apellido.value)) {
|
||
errores.push("El apellido debe comenzar con mayúscula y solo contener letras.");
|
||
apellido.classList.add("is-invalid");
|
||
} else if (apellido.value.length < 2) {
|
||
errores.push("El apellido debe tener al menos 2 caracteres.");
|
||
apellido.classList.add("is-invalid");
|
||
} else if (apellido.value.length > 50) {
|
||
errores.push("El apellido no puede superar los 50 caracteres.");
|
||
apellido.classList.add("is-invalid");
|
||
}
|
||
}
|
||
|
||
// USUARIO
|
||
|
||
if (isEmpty(usuario)) {
|
||
errores.push("El usuario es obligatorio.");
|
||
usuarioInput.classList.add("is-invalid");
|
||
} else if (!isValidUsername(usuario)) {
|
||
errores.push("El usuario debe tener 5–30 caracteres, incluir al menos una letra y solo usar letras, números, puntos o guiónes bajos no consecutivos.");
|
||
usuarioInput.classList.add("is-invalid");
|
||
}
|
||
|
||
// TELÉFONO
|
||
|
||
if (telefono) {
|
||
if (isEmpty(telefono.value)) {
|
||
errores.push("El teléfono es obligatorio.");
|
||
telefono.classList.add("is-invalid");
|
||
} else if (telefono.value.length != 10) {
|
||
errores.push("El teléfono debe poseer 10 dígitos.");
|
||
telefono.classList.add("is-invalid");
|
||
}
|
||
}
|
||
|
||
// EMAIL
|
||
|
||
if (email) {
|
||
if (isEmpty(email.value)) {
|
||
errores.push("El email es obligatorio.");
|
||
email.classList.add("is-invalid");
|
||
} else if (!isValidEmail(email.value)) {
|
||
errores.push("El email no tiene un formato válido.");
|
||
email.classList.add("is-invalid");
|
||
} else if (email.value.length > 100) {
|
||
errores.push("El email no puede superar los 100 caracteres.");
|
||
email.classList.add("is-invalid");
|
||
}
|
||
}
|
||
|
||
// PASSWORD
|
||
|
||
if (isEmpty(password)) {
|
||
errores.push("La contraseña es obligatoria.");
|
||
passInput.classList.add("is-invalid");
|
||
} else if (!hasNoSpaces(password)) {
|
||
errores.push("La contraseña no puede contener espacios.");
|
||
passInput.classList.add("is-invalid");
|
||
} else if (!isValidPassword(password)) {
|
||
errores.push("La contraseña debe tener al menos una mayúscula, una minúscula y un número, y mínimo 6 caracteres.");
|
||
passInput.classList.add("is-invalid");
|
||
}
|
||
|
||
// Resultado
|
||
|
||
if (errores.length > 0) {
|
||
e.preventDefault();
|
||
mostrarErrores(errores);
|
||
}
|
||
});
|
||
|
||
// FUNCIÓN PARA MOSTRAR ERRORES
|
||
|
||
function mostrarErrores(errores) {
|
||
|
||
// Buscar si hay un toast previo
|
||
|
||
const viejo = document.getElementById("toastErrores");
|
||
|
||
// Si existe, se elimina (evita duplicados)
|
||
|
||
if (viejo) viejo.remove();
|
||
|
||
// Crea el contenedor del toast
|
||
|
||
const toast = document.createElement("div");
|
||
|
||
// Se le asigna ID para identificarlo
|
||
|
||
toast.id = "toastErrores";
|
||
|
||
// Clases de estilo (Bootstrap + CSS)
|
||
|
||
toast.className = "toast-flotante alert alert-danger";
|
||
|
||
// Inserta el contenido dinámico (lista de errores)
|
||
|
||
toast.innerHTML = `
|
||
<strong>Se encontraron errores:</strong>
|
||
<ul class="mb-0 mt-2">
|
||
${errores.map(e => `<li>${e}</li>`).join("")} <!-- convierte array a <li> -->
|
||
</ul>
|
||
`;
|
||
|
||
// Agrega el toast al body (lo hace visible)
|
||
|
||
document.body.appendChild(toast);
|
||
|
||
// Auto-cierre
|
||
|
||
setTimeout(() => {
|
||
|
||
// Agrega clase para animación de salida (CSS)
|
||
|
||
toast.classList.add("toast-out");
|
||
|
||
// Elimina el elemento después de la animación
|
||
|
||
setTimeout(() => {
|
||
toast.remove(); // Elimina el DOM
|
||
}, 350);
|
||
|
||
}, 5000); // Visible durante 5 segundos
|
||
}
|
||
});
|
||
|
||
// FUNCIÓN PARA MOSTRAR SUCCESS
|
||
|
||
function mostrarSuccess(mensajes) {
|
||
|
||
// Elimina toast previo de éxito si existe
|
||
|
||
const viejo = document.getElementById("toastSuccess");
|
||
if (viejo) viejo.remove();
|
||
|
||
// Crea el contenedor del toast
|
||
|
||
const toast = document.createElement("div");
|
||
|
||
// Se le asigna ID único
|
||
|
||
toast.id = "toastSuccess";
|
||
|
||
// Estilo
|
||
|
||
toast.className = "toast-flotante alert alert-success";
|
||
|
||
// Inserta mensajes dinámicos
|
||
|
||
toast.innerHTML = `
|
||
<strong>Mensajes de éxito:</strong>
|
||
<ul class="mb-0 mt-2">
|
||
${mensajes.map(m => `<li>${m}</li>`).join("")}
|
||
</ul>
|
||
`;
|
||
|
||
// Agrega al DOM
|
||
|
||
document.body.appendChild(toast);
|
||
|
||
// Auto-cierre a los 5 segundos
|
||
|
||
setTimeout(() => {
|
||
|
||
// Animación de salida
|
||
|
||
toast.classList.add("toast-out");
|
||
|
||
// Eliminación final
|
||
|
||
setTimeout(() => {
|
||
toast.remove();
|
||
}, 350);
|
||
|
||
}, 5000);
|
||
} |