// DOM Elements const contactForm = document.getElementById('contactForm'); const submitBtn = document.getElementById('submitBtn'); const toast = document.getElementById('toast'); const formSuccess = document.getElementById('formSuccess'); const formError = document.getElementById('formError'); const messageTextarea = document.getElementById('message'); const charCount = document.getElementById('charCount'); // Form validation const validateEmail = (email) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }; const validatePhone = (phone) => { const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/; return phone === '' || phoneRegex.test(phone.replace(/[\s\-\(\)]/g, '')); }; const showError = (fieldId, message) => { const errorElement = document.getElementById(fieldId + 'Error'); const inputElement = document.getElementById(fieldId); if (errorElement) { errorElement.textContent = message; } if (inputElement) { inputElement.classList.add('error'); } }; const clearError = (fieldId) => { const errorElement = document.getElementById(fieldId + 'Error'); const inputElement = document.getElementById(fieldId); if (errorElement) { errorElement.textContent = ''; } if (inputElement) { inputElement.classList.remove('error'); } }; const clearAllErrors = () => { const errorElements = document.querySelectorAll('.error-message'); const inputElements = document.querySelectorAll('.error'); errorElements.forEach(el => el.textContent = ''); inputElements.forEach(el => el.classList.remove('error')); }; // Character counter for message textarea messageTextarea.addEventListener('input', () => { const length = messageTextarea.value.length; charCount.textContent = length; if (length > 1000) { charCount.style.color = 'var(--error)'; messageTextarea.style.borderColor = 'var(--error)'; } else { charCount.style.color = 'var(--text-secondary)'; messageTextarea.style.borderColor = 'var(--border)'; } }); // Real-time validation document.getElementById('email').addEventListener('blur', (e) => { const email = e.target.value.trim(); if (email && !validateEmail(email)) { showError('email', 'Please enter a valid email address'); } else { clearError('email'); } }); document.getElementById('phone').addEventListener('blur', (e) => { const phone = e.target.value.trim(); if (phone && !validatePhone(phone)) { showError('phone', 'Please enter a valid phone number'); } else { clearError('phone'); } }); // Clear errors on input ['firstName', 'lastName', 'email', 'phone', 'subject', 'message'].forEach(fieldId => { const element = document.getElementById(fieldId); if (element) { element.addEventListener('input', () => clearError(fieldId)); } }); // Set loading state const setLoadingState = (loading) => { if (loading) { submitBtn.classList.add('loading'); submitBtn.disabled = true; } else { submitBtn.classList.remove('loading'); submitBtn.disabled = false; } }; // Show toast notification const showToast = (message, type = 'success') => { const toastMessage = toast.querySelector('.toast-message'); const toastIcon = toast.querySelector('.toast-icon'); toastMessage.textContent = message; if (type === 'success') { toast.style.background = 'var(--success)'; toastIcon.textContent = '✓'; } else { toast.style.background = 'var(--error)'; toastIcon.textContent = '✕'; } toast.classList.add('show'); setTimeout(() => { toast.classList.remove('show'); }, 4000); }; // API Configuration const API_BASE_URL = '/api/v1'; const CONTACT_ENDPOINT = `${API_BASE_URL}/contact`; // Submit contact form const submitContactForm = async (formData) => { try { const response = await fetch(CONTACT_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, body: JSON.stringify(formData) }); const data = await response.json(); if (!response.ok) { throw new Error(data.message || `HTTP error! status: ${response.status}`); } return data; } catch (error) { if (error.name === 'TypeError' && error.message.includes('fetch')) { throw new Error('Network error. Please check your connection and try again.'); } throw error; } }; // Form submission handler contactForm.addEventListener('submit', async (e) => { e.preventDefault(); // Clear previous states clearAllErrors(); formSuccess.classList.remove('show'); formError.classList.remove('show'); // Get form data const formData = new FormData(contactForm); const data = { firstName: formData.get('firstName').trim(), lastName: formData.get('lastName').trim(), email: formData.get('email').trim(), phone: formData.get('phone').trim(), company: formData.get('company').trim(), subject: formData.get('subject'), priority: formData.get('priority'), message: formData.get('message').trim(), newsletter: formData.get('newsletter') === 'on', privacy: formData.get('privacy') === 'on' }; // Validate required fields let hasErrors = false; if (!data.firstName) { showError('firstName', 'First name is required'); hasErrors = true; } if (!data.lastName) { showError('lastName', 'Last name is required'); hasErrors = true; } if (!data.email) { showError('email', 'Email address is required'); hasErrors = true; } else if (!validateEmail(data.email)) { showError('email', 'Please enter a valid email address'); hasErrors = true; } if (data.phone && !validatePhone(data.phone)) { showError('phone', 'Please enter a valid phone number'); hasErrors = true; } if (!data.subject) { showError('subject', 'Please select a subject'); hasErrors = true; } if (!data.message) { showError('message', 'Message is required'); hasErrors = true; } else if (data.message.length > 1000) { showError('message', 'Message must be 1000 characters or less'); hasErrors = true; } if (!data.privacy) { showError('privacy', 'You must agree to the Privacy Policy and Terms of Service'); hasErrors = true; } if (hasErrors) { return; } // Set loading state setLoadingState(true); try { // Submit form data const response = await submitContactForm(data); // Show success message formSuccess.classList.add('show'); showToast('Message sent successfully! We\'ll get back to you soon.', 'success'); // Reset form contactForm.reset(); charCount.textContent = '0'; // Scroll to success message formSuccess.scrollIntoView({ behavior: 'smooth', block: 'center' }); } catch (error) { console.error('Contact form error:', error); // Show error message const errorMessage = document.getElementById('errorMessage'); errorMessage.textContent = error.message || 'Something went wrong. Please try again.'; formError.classList.add('show'); showToast('Failed to send message. Please try again.', 'error'); // Scroll to error message formError.scrollIntoView({ behavior: 'smooth', block: 'center' }); } finally { setLoadingState(false); } }); // FAQ functionality document.querySelectorAll('.faq-question').forEach(question => { question.addEventListener('click', () => { const faqId = question.dataset.faq; const answer = document.getElementById(`faq-${faqId}`); const isActive = question.classList.contains('active'); // Close all other FAQs document.querySelectorAll('.faq-question').forEach(q => { q.classList.remove('active'); }); document.querySelectorAll('.faq-answer').forEach(a => { a.classList.remove('active'); }); // Toggle current FAQ if (!isActive) { question.classList.add('active'); answer.classList.add('active'); } }); }); // Contact option handlers document.getElementById('liveChatBtn').addEventListener('click', () => { showToast('Opening live chat...', 'success'); // In a real app, this would open a chat widget setTimeout(() => { alert('Live chat would open here.\n\nThis would integrate with a service like Intercom, Zendesk Chat, or similar.'); }, 1000); }); document.getElementById('scheduleDemoBtn').addEventListener('click', () => { showToast('Opening demo scheduler...', 'success'); // In a real app, this would open a calendar booking widget setTimeout(() => { alert('Demo scheduler would open here.\n\nThis would integrate with Calendly, Acuity Scheduling, or similar.'); }, 1000); }); // Navbar background on scroll window.addEventListener('scroll', () => { const navbar = document.querySelector('.navbar'); if (window.scrollY > 50) { navbar.style.background = 'rgba(255, 255, 255, 0.98)'; } else { navbar.style.background = 'rgba(255, 255, 255, 0.95)'; } }); // Intersection Observer for animations const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; } }); }, observerOptions); // Observe elements for animation document.querySelectorAll('.contact-card, .contact-detail, .faq-item').forEach(el => { el.style.opacity = '0'; el.style.transform = 'translateY(30px)'; el.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; observer.observe(el); }); // Hero animation on load window.addEventListener('load', () => { const heroTitle = document.querySelector('.hero-title'); const heroSubtitle = document.querySelector('.hero-subtitle'); [heroTitle, heroSubtitle].forEach((element, index) => { if (element) { element.style.opacity = '0'; element.style.transform = 'translateY(30px)'; element.style.transition = 'opacity 0.8s ease, transform 0.8s ease'; setTimeout(() => { element.style.opacity = '1'; element.style.transform = 'translateY(0)'; }, 300 + (index * 200)); } }); }); // Button click handlers document.querySelectorAll('.btn').forEach(btn => { btn.addEventListener('click', (e) => { const buttonText = btn.textContent.toLowerCase(); if (buttonText.includes('trial') || buttonText.includes('start')) { if (!btn.closest('form')) { // Don't interfere with form submission e.preventDefault(); showToast('Starting your free trial! Redirecting...', 'success'); setTimeout(() => { window.location.href = 'signup.html'; }, 2000); } } }); }); // Auto-resize textarea messageTextarea.addEventListener('input', function() { this.style.height = 'auto'; this.style.height = Math.min(this.scrollHeight, 200) + 'px'; }); // Phone number formatting (optional enhancement) document.getElementById('phone').addEventListener('input', function(e) { let value = e.target.value.replace(/\D/g, ''); if (value.length >= 6) { value = value.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3'); } else if (value.length >= 3) { value = value.replace(/(\d{3})(\d{0,3})/, '($1) $2'); } e.target.value = value; });