function formData() { return { products: [], selectedSeries: '', selectedProduct: '', selectedProductData: null, quantity: '0', selectedColor: null, addOns: { chains: false, customLogo: false }, formData: { firstName: '', lastName: '', email: '', company: '', project: '', phone: '', address: '', city: '', state: '', zip: '', comments: '' }, colors: [ { name: 'Black Gray', code: 'RDS #0051', value: '#46494b' }, { name: 'Forest Green', code: 'RDS #0023', value: '#2f3c33' }, { name: 'Light Gray', code: 'RDS #0034', value: '#70777b' }, { name: 'Charcoal', code: 'RDS #0045', value: '#312f33' }, { name: 'Rust Brown', code: 'RDS #0056', value: '#76372f' }, { name: 'Dark Brown', code: 'RDS #0067', value: '#513a2b' }, { name: 'Navy Blue', code: 'RDS #0078', value: '#245887' }, { name: 'Medium Gray', code: 'RDS #0089', value: '#535051' }, { name: 'Yellow', code: 'RDS #0090', value: '#f7cd33' }, { name: 'Slate Gray', code: 'RDS #0101', value: '#666569' }, { name: 'Light Slate', code: 'RDS #0112', value: '#a9aeb4' }, { name: 'Black', code: 'RDS #0123', value: '#252024' } ], currentSection: 1, get progressWidth() { return (this.currentSection / 3) * 100; }, init() { this.loadProducts(); // Set default selected color this.selectedColor = this.colors[0]; // Update progress based on scroll position this.updateProgressOnScroll(); }, updateProgressOnScroll() { const updateProgress = () => { const sections = ['section-1', 'section-2', 'section-3']; let visibleSection = 1; sections.forEach((sectionId, index) => { const section = document.getElementById(sectionId); if (section) { const rect = section.getBoundingClientRect(); const windowHeight = window.innerHeight; // If section is more than 30% visible in viewport if (rect.top < windowHeight * 0.3 && rect.bottom > windowHeight * 0.3) { visibleSection = index + 1; } } }); this.currentSection = visibleSection; }; window.addEventListener('scroll', updateProgress, { passive: true }); updateProgress(); // Initial check }, async loadProducts() { try { const response = await fetch('https://cdn.prod.website-files.com/68da8f826ef9ddae1e49e1f3/693b28b2fe9dadfe91c86c89_products.json.txt'); const data = await response.json(); this.products = data.products || []; } catch (error) { console.error('Error loading products:', error); // Fallback to empty array if file doesn't exist this.products = []; } }, get productSeries() { const series = new Set(); this.products.forEach(product => { // Extract series from catalog number (e.g., "CAST IRON 150-GT" -> "CAST IRON") const parts = product.catalog_number.split(' '); if (parts.length >= 2) { series.add(parts.slice(0, -1).join(' ')); } }); return Array.from(series).sort(); }, get filteredProducts() { if (!this.selectedSeries) return []; return this.products.filter(product => { return product.catalog_number.startsWith(this.selectedSeries); }); }, onSeriesChange() { this.selectedProduct = ''; this.selectedProductData = null; }, onProductChange() { this.selectedProductData = this.products.find(p => p.id == this.selectedProduct); }, scrollToSection(sectionId) { const section = document.getElementById(sectionId); if (section) { section.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }, resetForm() { // Reset form this.selectedSeries = ''; this.selectedProduct = ''; this.selectedProductData = null; this.quantity = '0'; this.selectedColor = this.colors[0]; this.addOns = { chains: false, customLogo: false }; this.formData = { firstName: '', lastName: '', email: '', company: '', project: '', phone: '', address: '', city: '', state: '', zip: '', comments: '' }; }, cancel() { if (confirm('Are you sure you want to cancel? All progress will be lost.')) { this.resetForm(); // Scroll back to top window.scrollTo({ top: 0, behavior: 'smooth' }); } }, async submitForm() { // Validate required fields if (!this.formData.firstName || !this.formData.lastName || !this.formData.email) { alert('Please fill in all required fields (Name and Email).'); return; } if (!this.selectedProductData) { alert('Please select a product.'); return; } if (this.quantity === '0' || !this.quantity) { alert('Please select a quantity.'); return; } // Build location string const locationParts = [ this.formData.address, this.formData.city, this.formData.state, this.formData.zip ].filter(part => part && part.trim()); const location = locationParts.join(', '); // Build contact name const contactName = `${this.formData.firstName} ${this.formData.lastName}`.trim(); // Build products array const products = []; let sortOrder = 0; // Add main product products.push({ product_id: parseInt(this.selectedProductData.id), quantity: parseInt(this.quantity), unit_type: this.selectedProductData.unit_type || 'EA', sort_order: sortOrder++ }); // Add color note if (this.selectedColor) { products.push({ is_product_note: true, unit_type: 'NOTE', product_id: null, custom_note: `Color: ${this.selectedColor.name} - ${this.selectedColor.code}`, sort_order: sortOrder++, price: '0.00', quantity: 1 }); } // Add add-ons as notes if (this.addOns.chains) { products.push({ is_product_note: true, unit_type: 'NOTE', product_id: null, custom_note: 'Add-on: Chains & EyeBolts', sort_order: sortOrder++, price: '0.00', quantity: 1 }); } if (this.addOns.customLogo) { products.push({ is_product_note: true, unit_type: 'NOTE', product_id: null, custom_note: 'Add-on: Custom logo', sort_order: sortOrder++, price: '0.00', quantity: 1 }); } // Prepare submission data const payload = { userInfo: { companyName: this.formData.company || '', location: location || '', contactName: contactName, contactEmail: this.formData.email, contactPhone: this.formData.phone || '', additionalNotes: this.formData.comments || '' }, project_name: this.formData.project || '', products: products }; // Show loading state const submitButton = document.querySelector('.btn-submit'); const originalText = submitButton ? submitButton.textContent : 'Submit Quote'; try { if (submitButton) { submitButton.disabled = true; submitButton.textContent = 'Submitting...'; } const response = await fetch('https://jr-hoe.test/api/2/quotes/userCreate', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(payload) }); const data = await response.json(); if (!response.ok) { throw new Error(data.message || 'Failed to submit quote'); } alert('Quote submitted successfully!'); console.log('Quote submitted:', data); // Reset form after successful submission this.resetForm(); window.scrollTo({ top: 0, behavior: 'smooth' }); } catch (error) { console.error('Error submitting quote:', error); alert(`Error submitting quote: ${error.message}`); } finally { // Restore button state if (submitButton) { submitButton.disabled = false; submitButton.textContent = originalText; } } } }; }