Windows case-insensitive but Linux case-sensitive. Git was tracking lowercase, causing 404s on server. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
344 lines
10 KiB
JavaScript
344 lines
10 KiB
JavaScript
/**
|
|
* Footer Contact Form Handler (Issue #37)
|
|
*
|
|
* Maneja la validación, envío y tracking del formulario de contacto del footer.
|
|
* Incluye:
|
|
* - Validaciones de email y WhatsApp
|
|
* - Envío a webhook
|
|
* - Google Analytics 4 tracking
|
|
* - Estados de loading y mensajes de feedback
|
|
*
|
|
* @package ROI_Theme
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
// Configuración del webhook
|
|
const WEBHOOK_URL = 'https://hook.us2.make.com/iq8p4q9w50a12crlb58d4h1o6lwu4f47';
|
|
const FORM_SOURCE = 'ROI Website - Footer Contact Form';
|
|
|
|
// Expresiones regulares para validación
|
|
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
const WHATSAPP_REGEX = /^\+?[\d\s-]{10,15}$/;
|
|
|
|
/**
|
|
* Inicializar el formulario cuando el DOM está listo
|
|
*/
|
|
function init() {
|
|
const form = document.getElementById('footerContactForm');
|
|
if (!form) return;
|
|
|
|
// Agregar event listeners
|
|
form.addEventListener('submit', handleSubmit);
|
|
|
|
// Validación en tiempo real para campos específicos
|
|
const emailInput = document.getElementById('footerEmail');
|
|
const whatsappInput = document.getElementById('footerWhatsapp');
|
|
|
|
if (emailInput) {
|
|
emailInput.addEventListener('blur', function() {
|
|
validateEmail(this);
|
|
});
|
|
emailInput.addEventListener('input', function() {
|
|
if (this.classList.contains('is-invalid')) {
|
|
validateEmail(this);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (whatsappInput) {
|
|
whatsappInput.addEventListener('blur', function() {
|
|
validateWhatsApp(this);
|
|
});
|
|
whatsappInput.addEventListener('input', function() {
|
|
if (this.classList.contains('is-invalid')) {
|
|
validateWhatsApp(this);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validar email
|
|
* @param {HTMLInputElement} input - Campo de input
|
|
* @returns {boolean} - True si es válido
|
|
*/
|
|
function validateEmail(input) {
|
|
const value = input.value.trim();
|
|
const isValid = EMAIL_REGEX.test(value);
|
|
|
|
if (value === '') {
|
|
input.classList.remove('is-valid', 'is-invalid');
|
|
return true; // Si está vacío pero no es requerido, es válido
|
|
}
|
|
|
|
if (isValid) {
|
|
input.classList.remove('is-invalid');
|
|
input.classList.add('is-valid');
|
|
} else {
|
|
input.classList.remove('is-valid');
|
|
input.classList.add('is-invalid');
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/**
|
|
* Validar WhatsApp (10-15 dígitos)
|
|
* @param {HTMLInputElement} input - Campo de input
|
|
* @returns {boolean} - True si es válido
|
|
*/
|
|
function validateWhatsApp(input) {
|
|
const value = input.value.trim();
|
|
// Remover espacios, guiones y signos + para contar solo dígitos
|
|
const digitsOnly = value.replace(/[\s\-+]/g, '');
|
|
const isValid = WHATSAPP_REGEX.test(value) && digitsOnly.length >= 10 && digitsOnly.length <= 15;
|
|
|
|
if (value === '') {
|
|
input.classList.remove('is-valid', 'is-invalid');
|
|
return false; // WhatsApp es requerido
|
|
}
|
|
|
|
if (isValid) {
|
|
input.classList.remove('is-invalid');
|
|
input.classList.add('is-valid');
|
|
} else {
|
|
input.classList.remove('is-valid');
|
|
input.classList.add('is-invalid');
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/**
|
|
* Validar todos los campos del formulario
|
|
* @param {HTMLFormElement} form - Formulario
|
|
* @returns {boolean} - True si todo es válido
|
|
*/
|
|
function validateForm(form) {
|
|
let isValid = true;
|
|
|
|
// Validar campos requeridos
|
|
const fullName = form.querySelector('#footerFullName');
|
|
const email = form.querySelector('#footerEmail');
|
|
const whatsapp = form.querySelector('#footerWhatsapp');
|
|
|
|
if (fullName && fullName.value.trim() === '') {
|
|
fullName.classList.add('is-invalid');
|
|
isValid = false;
|
|
} else if (fullName) {
|
|
fullName.classList.remove('is-invalid');
|
|
fullName.classList.add('is-valid');
|
|
}
|
|
|
|
if (email && !validateEmail(email)) {
|
|
isValid = false;
|
|
}
|
|
|
|
if (whatsapp && !validateWhatsApp(whatsapp)) {
|
|
isValid = false;
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/**
|
|
* Mostrar mensaje de feedback
|
|
* @param {string} message - Mensaje a mostrar
|
|
* @param {string} type - Tipo: 'success', 'danger', 'info'
|
|
*/
|
|
function showMessage(message, type) {
|
|
const messageDiv = document.getElementById('footerFormMessage');
|
|
if (!messageDiv) return;
|
|
|
|
messageDiv.className = 'col-12 mt-2 alert alert-' + type;
|
|
messageDiv.textContent = message;
|
|
messageDiv.style.display = 'block';
|
|
messageDiv.classList.add('show');
|
|
|
|
// Scroll suave al mensaje
|
|
messageDiv.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
|
|
// Auto-ocultar mensajes de éxito después de 5 segundos
|
|
if (type === 'success') {
|
|
setTimeout(function() {
|
|
hideMessage();
|
|
}, 5000);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Ocultar mensaje
|
|
*/
|
|
function hideMessage() {
|
|
const messageDiv = document.getElementById('footerFormMessage');
|
|
if (!messageDiv) return;
|
|
|
|
messageDiv.classList.remove('show');
|
|
setTimeout(function() {
|
|
messageDiv.style.display = 'none';
|
|
}, 150);
|
|
}
|
|
|
|
/**
|
|
* Trackear evento en Google Analytics 4
|
|
* @param {string} eventName - Nombre del evento
|
|
* @param {Object} params - Parámetros adicionales
|
|
*/
|
|
function trackGA4Event(eventName, params) {
|
|
if (typeof gtag === 'function') {
|
|
gtag('event', eventName, params);
|
|
} else if (typeof dataLayer !== 'undefined') {
|
|
dataLayer.push({
|
|
'event': eventName,
|
|
...params
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Preparar datos del formulario
|
|
* @param {HTMLFormElement} form - Formulario
|
|
* @returns {Object} - Datos del formulario
|
|
*/
|
|
function getFormData(form) {
|
|
return {
|
|
fullName: form.querySelector('#footerFullName').value.trim(),
|
|
company: form.querySelector('#footerCompany').value.trim() || 'N/A',
|
|
whatsapp: form.querySelector('#footerWhatsapp').value.trim(),
|
|
email: form.querySelector('#footerEmail').value.trim(),
|
|
comments: form.querySelector('#footerComments').value.trim() || 'Sin comentarios',
|
|
source: FORM_SOURCE,
|
|
timestamp: new Date().toISOString(),
|
|
pageUrl: window.location.href,
|
|
pageTitle: document.title
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Enviar datos al webhook
|
|
* @param {Object} data - Datos a enviar
|
|
* @returns {Promise} - Promesa de fetch
|
|
*/
|
|
async function sendToWebhook(data) {
|
|
const response = await fetch(WEBHOOK_URL, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Error en el servidor: ' + response.status);
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
/**
|
|
* Resetear el formulario
|
|
* @param {HTMLFormElement} form - Formulario
|
|
*/
|
|
function resetForm(form) {
|
|
form.reset();
|
|
|
|
// Remover todas las clases de validación
|
|
const inputs = form.querySelectorAll('.form-control');
|
|
inputs.forEach(function(input) {
|
|
input.classList.remove('is-valid', 'is-invalid');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Manejar el envío del formulario
|
|
* @param {Event} e - Evento de submit
|
|
*/
|
|
async function handleSubmit(e) {
|
|
e.preventDefault();
|
|
|
|
const form = e.target;
|
|
const submitBtn = form.querySelector('button[type="submit"]');
|
|
|
|
// Ocultar mensaje anterior
|
|
hideMessage();
|
|
|
|
// Validar formulario
|
|
if (!validateForm(form)) {
|
|
showMessage('Por favor, completa todos los campos requeridos correctamente.', 'danger');
|
|
|
|
// Track error de validación
|
|
trackGA4Event('form_validation_error', {
|
|
form_name: 'footer_contact',
|
|
form_source: FORM_SOURCE
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
// Deshabilitar botón y mostrar loading
|
|
submitBtn.disabled = true;
|
|
submitBtn.classList.add('loading');
|
|
const originalText = submitBtn.innerHTML;
|
|
|
|
// Track inicio de envío
|
|
trackGA4Event('form_submit_start', {
|
|
form_name: 'footer_contact',
|
|
form_source: FORM_SOURCE
|
|
});
|
|
|
|
try {
|
|
// Preparar y enviar datos
|
|
const formData = getFormData(form);
|
|
await sendToWebhook(formData);
|
|
|
|
// Éxito
|
|
showMessage('¡Gracias por tu mensaje! Nos pondremos en contacto contigo pronto.', 'success');
|
|
resetForm(form);
|
|
|
|
// Track éxito
|
|
trackGA4Event('form_submit_success', {
|
|
form_name: 'footer_contact',
|
|
form_source: FORM_SOURCE,
|
|
has_company: formData.company !== 'N/A',
|
|
has_comments: formData.comments !== 'Sin comentarios'
|
|
});
|
|
|
|
// Track conversión
|
|
trackGA4Event('generate_lead', {
|
|
currency: 'MXN',
|
|
value: 1,
|
|
form_name: 'footer_contact',
|
|
form_source: FORM_SOURCE
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Error al enviar el formulario:', error);
|
|
showMessage('Hubo un error al enviar tu mensaje. Por favor, intenta nuevamente.', 'danger');
|
|
|
|
// Track error
|
|
trackGA4Event('form_submit_error', {
|
|
form_name: 'footer_contact',
|
|
form_source: FORM_SOURCE,
|
|
error_message: error.message
|
|
});
|
|
|
|
} finally {
|
|
// Restaurar botón
|
|
submitBtn.disabled = false;
|
|
submitBtn.classList.remove('loading');
|
|
submitBtn.innerHTML = originalText;
|
|
}
|
|
}
|
|
|
|
// Inicializar cuando el DOM esté listo
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
|
|
})();
|