// // Example: Basic client-side validation or UX improvements // document.addEventListener("DOMContentLoaded", function () { // const form = document.querySelector("form"); // form.addEventListener("submit", async (e) => { // e.preventDefault(); // handleSubmit(); // }); // }); // function handleSubmit() { // // Example: collect form data manually // const form = document.querySelector("form"); // const formData = new FormData(form); // const payload = { userDetails: {} }; // formData.forEach((value, key) => { // // handle nested names like userDetails[firstName] // if (key.startsWith("userDetails[")) { // const innerKey = key.match(/userDetails\[(.*?)\]/)[1]; // payload.userDetails[innerKey] = value; // } else { // payload[key] = value; // } // }); // // You could then send it via fetch: // fetch("/api/v1/va/client/register", { // method: "POST", // body: JSON.stringify(payload), // }) // .then((res) => res.json()) // .then((data) => { // console.log("Server Response:", data); // alert("Form submitted successfully!"); // }) // .catch((err) => console.error("Error:", err)); // } const formData = { userDetails: {} }; // Current step tracking let currentStep = 1; // const statesByCountry = { // 'US': [ // 'Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California', 'Colorado', 'Connecticut', 'Delaware', // 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', // 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', // 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', // 'New York', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', // 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', // 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming' // ], // 'CA': [ // 'Alberta', 'British Columbia', 'Manitoba', 'New Brunswick', 'Newfoundland and Labrador', // 'Nova Scotia', 'Ontario', 'Prince Edward Island', 'Quebec', 'Saskatchewan' // ], // 'UK': [ // 'England', 'Scotland', 'Wales', 'Northern Ireland' // ], // 'AU': [ // 'New South Wales', 'Queensland', 'South Australia', 'Tasmania', 'Victoria', 'Western Australia' // ] // }; // Function to navigate to any step (for tab navigation) function goToStep(step) { // Only allow navigation to completed steps or the next step if (step > currentStep && step > getMaxCompletedStep() + 1) { return; } // Hide current step document.getElementById(`step-${currentStep}`).classList.remove('active'); document.querySelectorAll(`.step[data-step="${currentStep}"]`).forEach(el => { el.classList.remove('active'); }); // Show target step document.getElementById(`step-${step}`).classList.add('active'); document.querySelectorAll(`.step[data-step="${step}"]`).forEach(el => { el.classList.add('active'); }); currentStep = step; } // Function to get the maximum completed step function getMaxCompletedStep() { const completedSteps = document.querySelectorAll('.step.completed'); let maxStep = 0; completedSteps.forEach(step => { const stepNum = parseInt(step.getAttribute('data-step')); if (stepNum > maxStep) maxStep = stepNum; }); return maxStep; } // Function to navigate to next step function nextStep(step) { // Validate current step before proceeding if (!validateStep(currentStep)) { return; } // Save current step data saveStepData(currentStep); // Mark current step as completed document.querySelectorAll(`.step[data-step="${currentStep}"]`).forEach(el => { el.classList.add('completed'); const stepNumber = el.querySelector('.step-number'); stepNumber.textContent = '✓'; stepNumber.style.backgroundColor = '#070065'; stepNumber.style.borderColor = '#070065'; stepNumber.style.color = 'white'; }); // Hide current step document.getElementById(`step-${currentStep}`).classList.remove('active'); document.querySelectorAll(`.step[data-step="${currentStep}"]`).forEach(el => { el.classList.remove('active'); }); // Show next step document.getElementById(`step-${step}`).classList.add('active'); document.querySelectorAll(`.step[data-step="${step}"]`).forEach(el => { el.classList.add('active'); }); currentStep = step; } // Function to navigate to previous step function prevStep(step) { // Hide current step document.getElementById(`step-${currentStep}`).classList.remove('active'); document.querySelectorAll(`.step[data-step="${currentStep}"]`).forEach(el => { el.classList.remove('active'); }); // Show previous step document.getElementById(`step-${step}`).classList.add('active'); document.querySelectorAll(`.step[data-step="${step}"]`).forEach(el => { el.classList.add('active'); }); currentStep = step; } // Function to validate current step function validateStep(step) { let isValid = true; const form = document.getElementById(getFormId(step)); if (form) { const requiredFields = form.querySelectorAll('[required]'); requiredFields.forEach(field => { if (!field.value.trim()) { isValid = false; field.style.border = '1px solid #ef4444'; } else { field.style.border = ''; } }); } return isValid; } // Function to get form ID based on step function getFormId(step) { switch(step) { case 1: return 'account-form'; case 2: return 'business-form'; case 3: return 'billing-form'; case 4: return 'signatory-form'; case 5: return 'payment-form'; default: return ''; } } // Function to save step data to formData object function saveStepData(step) { switch(step) { case 1: formData.userDetails.name = document.getElementById('company-name').value; formData.userDetails.email = document.getElementById('email').value; break; case 2: formData.userDetails.address = document.getElementById('address').value; formData.userDetails.city = document.getElementById('city').value; formData.userDetails.state = document.getElementById('state').value; formData.userDetails.zip = document.getElementById('zip').value; break; case 3: formData.userDetails.billingName = document.getElementById('billing-name').value; formData.userDetails.billingAddress = document.getElementById('billing-address').value; formData.userDetails.billingCity = document.getElementById('billing-city').value; formData.userDetails.billingState = document.getElementById('billing-state').value; formData.userDetails.billingZip = document.getElementById('billing-zip').value; formData.userDetails.billingEmail = document.getElementById('billing-email').value; break; case 4: formData.userDetails.position = document.getElementById('position').value; formData.userDetails.signatoryName = document.getElementById('signatory-name').value; formData.userDetails.signatoryEmail = document.getElementById('signatory-email').value; break; case 5: // Payment method already handled in selectPaymentOption break; case 6: formData.userDetails.paymentMethod = formData.payment?.type || ''; break; } } // Function to select payment option function selectPaymentOption(type) { // Remove selected class from all options document.querySelectorAll('.payment-option').forEach(option => { option.classList.remove('selected'); }); document.querySelectorAll('.payment-details').forEach(details => { details.classList.remove('active'); }); // Add selected class to clicked option event.currentTarget.classList.add('selected'); if (type === 'card') { document.getElementById('card-details').classList.add('active'); formData.userDetails.paymentMethod = 'card'; formData.userDetails.cardNumber = ''; formData.userDetails.expiryDate = ''; formData.userDetails.securityCode = ''; formData.userDetails.cardZip = ''; } else if (type === 'bank') { document.getElementById('bank-details').classList.add('active'); formData.userDetails.paymentMethod = 'bank'; formData.userDetails.bankName = ''; formData.userDetails.accountNumber = ''; formData.userDetails.routingNumber = ''; formData.userDetails.accountType = ''; formData.userDetails.accountHolderName = ''; } } // Function to submit the form async function submitForm() { // Validate current step if (!validateStep(currentStep)) { return; } // Save current step data saveStepData(currentStep); // Save payment details based on selected method if (formData.userDetails.paymentMethod === 'card') { formData.userDetails.cardNumber = document.getElementById('card-number').value; formData.userDetails.expiryDate = document.getElementById('expiry-date').value; formData.userDetails.securityCode = document.getElementById('security-code').value; formData.userDetails.cardZip = document.getElementById('card-zip').value; } else if (formData.userDetails.paymentMethod === 'bank') { formData.userDetails.bankName = document.getElementById('bank-name').value; formData.userDetails.accountNumber = document.getElementById('account-number').value; formData.userDetails.routingNumber = document.getElementById('routing-number').value; formData.userDetails.accountType = document.getElementById('account-type').value; formData.userDetails.accountHolderName = document.getElementById('account-holder-name').value; } // Show loading state const submitBtn = document.querySelector('#payment-form .btn-primary'); const originalText = submitBtn.textContent; submitBtn.textContent = 'Submitting...'; submitBtn.disabled = true; try { // Send data to server using fetch const response = await fetch('/api/v1/va/client/register', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(formData) }); if (response.ok) { // Success - move to success step // Mark current step as completed document.querySelectorAll(`.step[data-step="${currentStep}"]`).forEach(el => { el.classList.add('completed'); const stepNumber = el.querySelector('.step-number'); stepNumber.textContent = '✓'; stepNumber.style.backgroundColor = '#070065'; stepNumber.style.borderColor = '#070065'; stepNumber.style.color = 'white'; }); nextStep(6); } else { // Handle server errors alert('There was an error submitting your registration. Please try again.'); } } catch (error) { // Handle network errors console.error('Error:', error); alert('There was a network error. Please check your connection and try again.'); } finally { // Restore button state submitBtn.textContent = originalText; submitBtn.disabled = false; } } // Function to reset the form function resetForm() { // Reset all form fields document.querySelectorAll('input').forEach(input => { input.value = ''; input.style.border = ''; }); document.querySelectorAll('select').forEach(select => { select.value = ''; select.style.border = ''; }); // Reset payment selection document.querySelectorAll('.payment-option').forEach(option => { option.classList.remove('selected'); }); document.querySelectorAll('.payment-details').forEach(details => { details.classList.remove('active'); }); // Reset form data formData.userDetails = {}; document.querySelectorAll('.step').forEach(step => { step.classList.remove('completed', 'active'); const stepNumber = step.querySelector('.step-number'); if (stepNumber) { stepNumber.textContent = step.getAttribute('data-step'); stepNumber.style.backgroundColor = ''; stepNumber.style.borderColor = '#a1a1aa'; stepNumber.style.color = '#a1a1aa'; } }); // Go back to step 1 document.getElementById('step-1').classList.add('active'); document.querySelectorAll('.step[data-step="1"]').forEach(el => { el.classList.add('active'); }); currentStep = 1; } // Function to fetch states from API async function fetchStates(countryCode) { try { // Replace with your actual API endpoint const response = await fetch(`/api/states/${countryCode}`); if (response.ok) { const states = await response.json(); return states; } else { console.error('Failed to fetch states'); return []; } } catch (error) { console.error('Error fetching states:', error); return []; } } // Function to populate states dropdown function populateStates(countryCode, selectElementId) { const selectElement = document.getElementById(selectElementId); const states = statesByCountry[countryCode] || []; // Clear existing options except the first empty one while (selectElement.options.length > 1) { selectElement.remove(1); } // Add states as options states.forEach(state => { const option = document.createElement('option'); option.value = state; option.textContent = state; selectElement.appendChild(option); }); } // Function to detect user location function detectLocation() { // Show loading indicators document.getElementById('state-loading').style.display = 'block'; // Using a free IP geolocation API fetch('https://ipapi.co/json/') .then(response => response.json()) .then(data => { // Hide loading indicators document.getElementById('state-loading').style.display = 'none'; // Populate city and state based on detected location document.getElementById('city').value = data.city || ''; document.getElementById('zip').value = data.postal || ''; // Populate states dropdown for the detected country populateStates(data.country_code, 'state'); // Set the detected state if (data.region) { document.getElementById('state').value = data.region; } // Also populate billing states dropdown populateStates(data.country_code, 'billing-state'); }) .catch(error => { console.error('Error detecting location:', error); // Hide loading indicators document.getElementById('state-loading').style.display = 'none'; // Fallback to US states if detection fails populateStates('US', 'state'); populateStates('US', 'billing-state'); }); } // Initialize form interactions document.addEventListener('DOMContentLoaded', function() { // Add input event listeners to handle label animation document.querySelectorAll('.input-field').forEach(input => { input.addEventListener('input', function() { if (this.value) { this.nextElementSibling.style.top = '2px'; this.nextElementSibling.style.fontSize = '12px'; this.nextElementSibling.style.transform = 'none'; } else { this.nextElementSibling.style.top = '50%'; this.nextElementSibling.style.fontSize = '14px'; this.nextElementSibling.style.transform = 'translateY(-50%)'; } }); input.addEventListener('focus', function() { this.nextElementSibling.style.top = '2px'; this.nextElementSibling.style.fontSize = '12px'; this.nextElementSibling.style.transform = 'none'; }); input.addEventListener('blur', function() { if (!this.value) { this.nextElementSibling.style.top = '50%'; this.nextElementSibling.style.fontSize = '14px'; this.nextElementSibling.style.transform = 'translateY(-50%)'; } }); }); // Handle select field label animation document.querySelectorAll('.select-field').forEach(select => { select.addEventListener('change', function() { if (this.value) { this.nextElementSibling.style.top = '2px'; this.nextElementSibling.style.fontSize = '12px'; this.nextElementSibling.style.transform = 'none'; } else { this.nextElementSibling.style.top = '50%'; this.nextElementSibling.style.fontSize = '14px'; this.nextElementSibling.style.transform = 'translateY(-50%)'; } }); select.addEventListener('focus', function() { this.nextElementSibling.style.top = '2px'; this.nextElementSibling.style.fontSize = '12px'; this.nextElementSibling.style.transform = 'none'; }); select.addEventListener('blur', function() { if (!this.value) { this.nextElementSibling.style.top = '50%'; this.nextElementSibling.style.fontSize = '14px'; this.nextElementSibling.style.transform = 'translateY(-50%)'; } }); }); // Handle use business address checkbox document.getElementById('use-business-address').addEventListener('change', function() { if (this.checked) { document.getElementById('billing-name').value = formData.userDetails.name || ''; document.getElementById('billing-address').value = formData.userDetails.address || ''; document.getElementById('billing-city').value = formData.userDetails.city || ''; document.getElementById('billing-state').value = formData.userDetails.state || ''; document.getElementById('billing-zip').value = formData.userDetails.zip || ''; // Trigger input events to update labels document.querySelectorAll('#billing-form .input-field').forEach(input => { input.dispatchEvent(new Event('input')); }); // Trigger change event for select document.getElementById('billing-state').dispatchEvent(new Event('change')); } }); // Handle use account email checkbox document.getElementById('use-account-email').addEventListener('change', function() { if (this.checked) { document.getElementById('billing-email').value = formData.account.email || ''; document.getElementById('billing-email').dispatchEvent(new Event('input')); } }); // Detect user location when the page loads detectLocation(); });