/* ═══════════════════════════════════════════════════════════════ LISTIFY AGENCY — FORMS.JS Complete lead capture pipeline: 1. Collect full data (name, company, city, phone, email, services, budget, revenue, message, UTM, device, timestamp) 2. POST to Google Sheets (Apps Script endpoint) 3. Open WhatsApp on BOTH numbers with full message 4. Fire GA4 + Clarity analytics events 5. Show toast notification 6. Reveal success state Business WA: +91 9213450881 Owner WA: +91 7041310990 Email: listifyproagency@gmail.com SETUP: See docs/SETUP_SHEETS.md for Google Sheets config ═══════════════════════════════════════════════════════════════ */ 'use strict'; /* ── CONFIG ── */ var LISTIFY_CONFIG = { wa_business: '919213450881', wa_owner: '917600714121', email: 'listifyproagency@gmail.com', /* Replace with your deployed Google Apps Script URL */ sheets_endpoint: 'https://script.google.com/macros/s/AKfycbxu86SGLGPAvb34ir4kxGdB5mQI6aJ5dy1jPzYueMMJB_c_QWHzGieIGM7tEYqmnkKA/exec', }; /* ── HONEYPOT SPAM PROTECTION ── */ function checkHoneypot(formEl) { if (!formEl) return true; // pass if no form var hp = formEl.querySelector('.hp-field, [name="website_url_hp"], [data-hp]'); if (hp && hp.value && hp.value.trim() !== '') { console.warn('[Listify] Bot detected via honeypot'); return false; // bot filled it } // Time-based: form submitted too fast (< 2s) = likely bot var startTime = parseInt(formEl.dataset.startTime || '0'); if (startTime && (Date.now() - startTime) < 2000) { console.warn('[Listify] Bot detected via timing'); return false; } return true; } /* ── INPUT SANITIZER (prevent XSS in dynamic output) ── */ function sanitizeText(str) { if (typeof str !== 'string') return ''; return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, ''') .slice(0, 2000); // max 2000 chars } /* ── RATE LIMIT (client-side throttle, 3 submissions per session) ── */ var _submitCount = 0; var _lastSubmit = 0; function checkRateLimit() { var now = Date.now(); if (now - _lastSubmit < 30000 && _submitCount >= 3) { window._toast && window._toast({ title: 'Too many submissions', msg: 'Please wait 30 seconds before trying again.', type: 'error' }); return false; } _submitCount++; _lastSubmit = now; return true; } /* ── COLLECT FULL LEAD DATA ── */ function collectLeadData(formEl, extras) { var data = extras || {}; /* Form fields */ if (formEl) { var inputs = formEl.querySelectorAll('input, select, textarea'); inputs.forEach(function(inp) { var key = inp.id || inp.name; if (!key) return; if (inp.type === 'checkbox') { data[key] = inp.checked; return; } if (inp.type === 'radio') { if (inp.checked) data[key] = inp.value; return; } if (inp.value.trim()) { data[key] = inp.value.trim(); } }); } /* UTM parameters */ var params = new URLSearchParams(window.location.search); ['utm_source','utm_medium','utm_campaign','utm_term','utm_content'].forEach(function(k) { var v = params.get(k); if (v) data[k] = v; }); /* Meta */ data._timestamp = new Date().toISOString(); data._source_url = window.location.href; data._page_title = document.title; data._device = window.innerWidth <= 767 ? 'Mobile' : window.innerWidth <= 1024 ? 'Tablet' : 'Desktop'; data._referrer = document.referrer || 'Direct'; data._screen = window.innerWidth + 'x' + window.innerHeight; data._browser = navigator.userAgent.split(' ').slice(-2).join(' '); return data; } /* ── BUILD WHATSAPP MESSAGE ── */ function buildWAMessage(data) { var lines = ['\uD83D\uDE4F *New Lead \u2014 Listify Agency*', '']; var fields = [ ['f-name', 'name', 'Name'], ['f-biz', 'company', 'Business'], ['f-city', 'city', 'City'], ['f-phone', 'phone', 'Phone / WA'], ['f-email', 'email', 'Email'], ['services', null, 'Services'], ['budget', null, 'Budget'], ['revenue', null, 'Revenue Range'], ['f-desc', 'description', 'Situation'], ['f-ref', 'referral','How they heard'], ]; fields.forEach(function(f) { var val = data[f[0]] || (f[1] && data[f[1]]) || ''; if (val && val !== '') { lines.push('*' + f[2] + ':* ' + val); } }); lines.push(''); lines.push('\uD83D\uDCC4 Page: ' + data._page_title); lines.push('\uD83D\uDCF1 Device: ' + data._device); lines.push('\uD83D\uDD50 Time: ' + new Date().toLocaleString('en-IN')); if (data.utm_source) { lines.push('\uD83D\uDCCA Source: ' + data.utm_source + (data.utm_medium ? ' / ' + data.utm_medium : '')); } return encodeURIComponent(lines.join('\n')); } /* ── POST TO GOOGLE SHEETS ── */ function postToSheets(data) { var endpoint = LISTIFY_CONFIG.sheets_endpoint; if (endpoint.indexOf('YOUR_SCRIPT_ID') !== -1) { console.info('[Listify] Sheets not configured — skipping. See docs/SETUP_SHEETS.md'); return Promise.resolve(); } return fetch(endpoint, { method: 'POST', mode: 'no-cors', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }).catch(function(err) { console.warn('[Listify] Sheets post error (non-critical):', err.message); }); } /* ── FIRE ANALYTICS ── */ function fireAnalytics(eventName, data) { try { if (window.gtag) { window.gtag('event', eventName || 'generate_lead', { event_category: 'lead_form', event_label: data._page_title || document.title, device_type: data._device, value: 1, }); } if (window.clarity) { window.clarity('event', eventName || 'lead_submitted'); } } catch(e) {} } /* ── SHOW TOAST ── */ function showToast(title, msg, type) { if (window._toast) { window._toast({ title: title, msg: msg, type: type || 'success', duration: 5000 }); } } /* ── MAIN SUBMIT FUNCTION ── */ window.submitLead = function(config) { var formEl = config.formEl; var extras = config.extras || {}; var btnEl = config.btnEl; var successEl = config.successEl; var onSuccess = config.onSuccess; /* Security checks */ if (!checkHoneypot(formEl)) return; if (!checkRateLimit()) return; /* Loading state */ var origText = ''; if (btnEl) { origText = btnEl.textContent; btnEl.textContent = 'Sending\u2026'; btnEl.disabled = true; } /* Collect */ var data = collectLeadData(formEl, extras); /* Build WA message */ var waMsg = buildWAMessage(data); /* Submit pipeline */ Promise.all([ postToSheets(data), ]).then(function() { /* Analytics */ fireAnalytics('generate_lead', data); /* Toast */ showToast( 'Enquiry Received! \u2705', 'We\u2019ll reply on WhatsApp within 2 hours.', 'success' ); /* Open WhatsApp — business number */ setTimeout(function() { window.open( 'https://wa.me/' + LISTIFY_CONFIG.wa_business + '?text=' + waMsg, '_blank', 'noopener,noreferrer' ); }, 800); /* Populate success state */ if (successEl) { if (formEl) formEl.style.display = 'none'; successEl.style.display = 'block'; /* Match contact.html IDs: sd-name, sd-biz, wa-succ-link */ var nameEl = successEl.querySelector('#sd-name') || successEl.querySelector('[data-sd="name"]'); var bizEl = successEl.querySelector('#sd-biz') || successEl.querySelector('[data-sd="biz"]'); var waLink = successEl.querySelector('#wa-succ-link') || successEl.querySelector('.wa-succ-link') || successEl.querySelector('.succ-wa'); if (nameEl) nameEl.textContent = data['f-name'] || data.name || '\u2014'; if (bizEl) bizEl.textContent = data['f-biz'] || data.company || '\u2014'; if (waLink) waLink.href = 'https://wa.me/' + LISTIFY_CONFIG.wa_business + '?text=' + waMsg; } /* Restore button */ if (btnEl) { btnEl.textContent = origText; btnEl.disabled = false; } if (onSuccess) onSuccess(data); }).catch(function(err) { console.error('[Listify] Submit error:', err); showToast('Error', 'Something went wrong. Please WhatsApp us directly.', 'error'); if (btnEl) { btnEl.textContent = origText; btnEl.disabled = false; } }); }; /* ── QUICK WA CONTACT (single button CTA) ── */ window.quickWA = function(service, page) { var lines = [ '\uD83D\uDE4F Hi Listify! I want to know more.', service ? ('*Service Interested:* ' + service) : '', '*From page:* ' + (page || document.title), '*URL:* ' + window.location.href, '*Time:* ' + new Date().toLocaleString('en-IN'), ].filter(Boolean); var msg = encodeURIComponent(lines.join('\n')); window.open('https://wa.me/' + LISTIFY_CONFIG.wa_business + '?text=' + msg, '_blank', 'noopener'); fireAnalytics('wa_click', { _page_title: page || document.title }); }; /* ── FORM FIELD VALIDATION ── */ window.validateField = function(input, rules) { var group = input.closest('.form-group') || input.closest('.fg') || input.closest('.afield'); var errEl = group && group.querySelector('.form-error, .field-error'); var valid = true; var msg = ''; if (rules.required && !input.value.trim()) { valid = false; msg = 'This field is required.'; } else if (rules.phone && input.value && !/^[+]?[\d\s\-(]{8,16}$/.test(input.value)) { valid = false; msg = 'Enter a valid phone number.'; } else if (rules.email && input.value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.value)) { valid = false; msg = 'Enter a valid email address.'; } else if (rules.minLen && input.value.trim().length < rules.minLen) { valid = false; msg = 'Minimum ' + rules.minLen + ' characters required.'; } if (group) { group.classList.toggle('has-error', !valid); group.classList.toggle('is-valid', valid && input.value.trim() !== ''); } if (errEl) { errEl.textContent = msg; errEl.style.display = valid ? 'none' : 'block'; } return valid; }; /* ── REAL-TIME VALIDATION ON BLUR ── */ document.addEventListener('DOMContentLoaded', function() { var phoneInputs = document.querySelectorAll('input[type="tel"], #f-phone'); phoneInputs.forEach(function(inp) { inp.addEventListener('blur', function() { validateField(inp, { phone: true }); }); }); var emailInputs = document.querySelectorAll('input[type="email"], #f-email'); emailInputs.forEach(function(inp) { inp.addEventListener('blur', function() { validateField(inp, { email: true }); }); }); });