summaryrefslogtreecommitdiff
path: root/static/contact-script.js
diff options
context:
space:
mode:
authorRobby Zambito <contact@robbyzambito.me>2025-08-06 19:35:38 -0400
committerRobby Zambito <contact@robbyzambito.me>2025-08-06 19:38:52 -0400
commitd35903bf5b56cc40e3b61d34f57c192d6a8b3430 (patch)
tree93e234b499b497f070aab282aa4841b9588d44ee /static/contact-script.js
parent60716f3ebb54f8a8f8426611c2727737678c66fb (diff)
Added contact page
Prompt: Create a contact page
Diffstat (limited to 'static/contact-script.js')
-rw-r--r--static/contact-script.js399
1 files changed, 399 insertions, 0 deletions
diff --git a/static/contact-script.js b/static/contact-script.js
new file mode 100644
index 0000000..d436dd5
--- /dev/null
+++ b/static/contact-script.js
@@ -0,0 +1,399 @@
+// 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 = 'https://api.taskflow.com/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);
+});
+
+// Social media link handlers
+document.querySelectorAll('.social-icon').forEach(icon => {
+ icon.addEventListener('click', (e) => {
+ e.preventDefault();
+ const platform = icon.getAttribute('aria-label');
+ showToast(`Opening ${platform}...`, 'success');
+ });
+});
+
+// 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;
+});