fix(structure): Rename assets and inc folders for Linux compatibility
- assets → Assets - inc → Inc Completes the case-sensitivity fixes for Linux servers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
343
Assets/js/footer-contact.js
Normal file
343
Assets/js/footer-contact.js
Normal file
@@ -0,0 +1,343 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user