/* HOA LedgerIQ — Frontend form handler + countdown */ // ── Dynamic Countdown ──────────────────────────────────── // Launch date = March 1, 2026 + 60 days = April 30, 2026 // On 3/1/2026 the banner shows "60 days", then counts down daily. (function initCountdown() { const launchDate = new Date('2026-04-30T00:00:00'); const now = new Date(); const msPerDay = 1000 * 60 * 60 * 24; const daysLeft = Math.max(0, Math.ceil((launchDate - now) / msPerDay)); const label = daysLeft === 1 ? 'Day' : 'Days'; const text = daysLeft > 0 ? `Launching in ${daysLeft} ${label}` : 'Now Live!'; const bannerEl = document.getElementById('bannerCountdown'); const signupEl = document.getElementById('signupCountdown'); if (bannerEl) bannerEl.textContent = text; if (signupEl) signupEl.textContent = text; })(); // ── Form Handler ───────────────────────────────────────── document.addEventListener('DOMContentLoaded', () => { const form = document.getElementById('signupForm'); const submitBtn = document.getElementById('submitBtn'); const btnText = submitBtn?.querySelector('.btn-text'); const btnLoading = submitBtn?.querySelector('.btn-loading'); const successDiv = document.getElementById('signupSuccess'); if (!form) return; form.addEventListener('submit', async (e) => { e.preventDefault(); const firstName = form.firstName.value.trim(); const lastName = form.lastName.value.trim(); const email = form.email.value.trim(); const orgName = form.orgName?.value.trim() || ''; const state = form.state?.value || ''; // Basic client-side validation if (!firstName || !lastName || !email || !orgName || !state) { highlightEmpty(form); return; } if (!isValidEmail(email)) { form.email.style.borderColor = '#ef4444'; form.email.focus(); return; } // Show loading state setLoading(true); const payload = { firstName, lastName, email, orgName: form.orgName?.value.trim() || '', state: form.state?.value || '', role: form.role.value, unitCount: form.unitCount.value, betaInterest: form.betaInterest?.checked || false, source: 'landing_page', timestamp: new Date().toISOString(), }; try { const res = await fetch('/api/leads', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (res.ok) { showSuccess(); } else { const data = await res.json().catch(() => ({})); if (res.status === 409) { // Already registered showSuccess('You\'re already on the list! We\'ll be in touch soon.'); } else { alert(data.error || 'Something went wrong. Please try again.'); setLoading(false); } } } catch (err) { // Network error — fall back to localStorage so we don't lose the lead saveLocally(payload); showSuccess(); } }); function setLoading(on) { if (!btnText || !btnLoading) return; submitBtn.disabled = on; btnText.classList.toggle('hidden', on); btnLoading.classList.toggle('hidden', !on); } function showSuccess(msg) { form.classList.add('hidden'); if (msg && successDiv) { const p = successDiv.querySelector('p'); if (p) p.textContent = msg; } successDiv?.classList.remove('hidden'); } function highlightEmpty(f) { ['firstName', 'lastName', 'email', 'orgName', 'state'].forEach(name => { const el = f[name]; if (el && !el.value.trim()) { el.style.borderColor = '#ef4444'; el.addEventListener('input', () => { el.style.borderColor = ''; }, { once: true }); el.addEventListener('change', () => { el.style.borderColor = ''; }, { once: true }); } }); } function isValidEmail(email) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); } function saveLocally(payload) { try { const existing = JSON.parse(localStorage.getItem('hoa_leads') || '[]'); existing.push(payload); localStorage.setItem('hoa_leads', JSON.stringify(existing)); } catch (_) { /* best-effort */ } } });