// Sticky header compaction const header = document.getElementById('site-header'); if (header) { window.addEventListener('scroll', () => { header.classList.toggle('scrolled', window.scrollY > 40); }, { passive:true }); } // Mobile nav const hamburger = document.getElementById('hamburger'); const mobileNav = document.getElementById('mobileNav'); if (hamburger && mobileNav) { hamburger.addEventListener('click', () => { const open = mobileNav.classList.toggle('open'); hamburger.setAttribute('aria-expanded', open); }); mobileNav.querySelectorAll('a').forEach(a => a.addEventListener('click', () => { mobileNav.classList.remove('open'); hamburger.setAttribute('aria-expanded', false); })); } // Active nav state on scroll (home page anchor sections) const sections = document.querySelectorAll('main section[id]'); const navLinks = document.querySelectorAll('nav.primary a, .mobile-nav a'); if (sections.length) { const setActive = () => { let current = ''; sections.forEach(sec => { const top = sec.getBoundingClientRect().top; if (top < 140) current = sec.id; }); if (current) { navLinks.forEach(link => { const href = link.getAttribute('href') || ''; link.classList.toggle('active', href.endsWith('#' + current)); }); } }; window.addEventListener('scroll', setActive, { passive:true }); } // Scroll reveal const revealEls = document.querySelectorAll('.reveal'); if ('IntersectionObserver' in window) { const io = new IntersectionObserver(entries => { entries.forEach(e => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } }); }, { threshold:0.15 }); revealEls.forEach(el => io.observe(el)); } else { revealEls.forEach(el => el.classList.add('in')); } // Gallery / project filter const tabs = document.querySelectorAll('.gtab'); const items = document.querySelectorAll('.gitem'); if (tabs.length) { tabs.forEach(tab => { tab.addEventListener('click', () => { tabs.forEach(t => t.classList.remove('active')); tab.classList.add('active'); const cat = tab.dataset.cat; items.forEach(item => { item.classList.toggle('show', cat === 'all' || item.dataset.cat === cat); }); }); }); } // Contact / enquiry form validation + submit — wired to the Flask + PostgreSQL API // // Flask now serves this file, the templates, and the API from one app, so calls // are same-origin by default. Only set this if the API is split onto a different // domain (e.g. "https://api.aecindia.in") from the pages that serve this script. const AEC_API_BASE = ""; const form = document.getElementById('enquiryForm'); if (form) { const status = document.getElementById('formStatus'); form.addEventListener('submit', async (e) => { e.preventDefault(); // honeypot: if filled, silently drop (bot) if (form.website && form.website.value) { return; } let valid = true; const name = form.name.value.trim(); const email = form.email.value.trim(); const message = form.message.value.trim(); const emailOk = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); form.querySelectorAll('.field').forEach(f => f.classList.remove('error')); if (!name) { form.querySelector('[data-field="name"]').classList.add('error'); valid = false; } if (!email || !emailOk) { form.querySelector('[data-field="email"]').classList.add('error'); valid = false; } if (!message) { form.querySelector('[data-field="message"]').classList.add('error'); valid = false; } status.classList.remove('success','fail'); if (!valid) { status.textContent = 'Please fix the highlighted fields.'; status.classList.add('fail'); return; } const submitBtn = form.querySelector('button[type="submit"]'); submitBtn.disabled = true; try { const res = await fetch(`${AEC_API_BASE}/api/enquiries`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, email, company: form.company.value.trim(), phone: form.phone.value.trim(), message, website: form.website ? form.website.value : '', // honeypot passthrough source_page: window.location.pathname.split('/').pop() || 'index.html', }), }); if (res.ok) { status.textContent = 'Thank you — your enquiry has been noted. Our team will contact you shortly.'; status.classList.add('success'); form.reset(); } else if (res.status === 422) { const data = await res.json().catch(() => ({})); const firstError = data.errors ? Object.values(data.errors)[0] : null; status.textContent = firstError || 'Please check the form and try again.'; status.classList.add('fail'); } else if (res.status === 429) { status.textContent = 'Too many requests — please try again in a little while.'; status.classList.add('fail'); } else { status.textContent = 'Something went wrong sending your enquiry. Please call us directly at 8950382618.'; status.classList.add('fail'); } } catch (err) { status.textContent = 'Could not reach the server. Please call us directly at 8950382618.'; status.classList.add('fail'); } finally { submitBtn.disabled = false; } }); }