// Email validation function function validateEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } // Card type detection function detectCardType(cardNumber) { // Remove spaces and dashes const cleanNumber = cardNumber.replace(/[\s-]/g, ''); const cardPatterns = { visa: /^4[0-9]{12}(?:[0-9]{3})?$/, mastercard: /^5[1-5][0-9]{14}$/, amex: /^3[47][0-9]{13}$/, discover: /^6(?:011|5[0-9]{2})[0-9]{12}$/, diners: /^3(?:0[0-5]|[68][0-9])[0-9]{11}$/, jcb: /^(?:2131|1800|35\d{3})\d{11}$/ }; for (const [type, pattern] of Object.entries(cardPatterns)) { if (pattern.test(cleanNumber)) { return type; } } return 'unknown'; } // Card number validation (Luhn algorithm) function validateCardNumber(cardNumber) { const cleanNumber = cardNumber.replace(/[\s-]/g, ''); // Check if it's all digits and has proper length if (!/^\d+$/.test(cleanNumber) || cleanNumber.length < 13 || cleanNumber.length > 19) { return false; } // Luhn algorithm let sum = 0; let isEven = false; for (let i = cleanNumber.length - 1; i >= 0; i--) { let digit = parseInt(cleanNumber.charAt(i)); if (isEven) { digit *= 2; if (digit > 9) { digit -= 9; } } sum += digit; isEven = !isEven; } return sum % 10 === 0; } // Expiry date validation function validateExpiryDate(expiryDate) { const expiryRegex = /^(0[1-9]|1[0-2])\/([0-9]{2})$/; if (!expiryRegex.test(expiryDate)) { return false; } const [month, year] = expiryDate.split('/'); const expiry = new Date(2000 + parseInt(year), parseInt(month)); const currentDate = new Date(); const currentMonth = new Date(currentDate.getFullYear(), currentDate.getMonth()); return expiry >= currentMonth; } // CVV validation function validateCVV(cvv, cardType) { if (!/^\d+$/.test(cvv)) { return false; } const cvvLengths = { visa: 3, mastercard: 3, amex: 4, discover: 3, diners: 3, jcb: 3 }; const expectedLength = cvvLengths[cardType] || 3; return cvv.length === expectedLength; } // ZIP code validation function validateZipCode(zipCode) { return /^\d{5}(-\d{4})?$/.test(zipCode); } // Bank account validation function validateBankAccount(accountNumber) { return /^\d{8,17}$/.test(accountNumber.replace(/\s/g, '')); } // Routing number validation (basic US routing number check) function validateRoutingNumber(routingNumber) { const cleanRouting = routingNumber.replace(/\s/g, ''); if (!/^\d{9}$/.test(cleanRouting)) { return false; } // Simple checksum validation const digits = cleanRouting.split('').map(Number); const sum = (3 * (digits[0] + digits[3] + digits[6])) + (7 * (digits[1] + digits[4] + digits[7])) + (digits[2] + digits[5] + digits[8]); return sum % 10 === 0; } 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', 'Australian Capital Territory', 'Northern Territory' ], 'IN': [ 'Andhra Pradesh', 'Arunachal Pradesh', 'Assam', 'Bihar', 'Chhattisgarh', 'Goa', 'Gujarat', 'Haryana', 'Himachal Pradesh', 'Jharkhand', 'Karnataka', 'Kerala', 'Madhya Pradesh', 'Maharashtra', 'Manipur', 'Meghalaya', 'Mizoram', 'Nagaland', 'Odisha', 'Punjab', 'Rajasthan', 'Sikkim', 'Tamil Nadu', 'Telangana', 'Tripura', 'Uttar Pradesh', 'Uttarakhand', 'West Bengal', 'Andaman and Nicobar Islands', 'Chandigarh', 'Dadra and Nagar Haveli and Daman and Diu', 'Delhi', 'Jammu and Kashmir', 'Ladakh', 'Lakshadweep', 'Puducherry' ], 'DE': [ 'Baden-Württemberg', 'Bavaria', 'Berlin', 'Brandenburg', 'Bremen', 'Hamburg', 'Hesse', 'Lower Saxony', 'Mecklenburg-Vorpommern', 'North Rhine-Westphalia', 'Rhineland-Palatinate', 'Saarland', 'Saxony', 'Saxony-Anhalt', 'Schleswig-Holstein', 'Thuringia' ], 'FR': [ 'Auvergne-Rhône-Alpes', 'Bourgogne-Franche-Comté', 'Brittany', 'Centre-Val de Loire', 'Corsica', 'Grand Est', 'Hauts-de-France', 'Île-de-France', 'Normandy', 'Nouvelle-Aquitaine', 'Occitanie', 'Pays de la Loire', 'Provence-Alpes-Côte d’Azur' ], 'IT': [ 'Abruzzo', 'Basilicata', 'Calabria', 'Campania', 'Emilia-Romagna', 'Friuli Venezia Giulia', 'Lazio', 'Liguria', 'Lombardy', 'Marche', 'Molise', 'Piedmont', 'Sardinia', 'Sicily', 'Trentino-Alto Adige', 'Tuscany', 'Umbria', 'Aosta Valley', 'Veneto' ], 'ES': [ 'Andalusia', 'Aragon', 'Asturias', 'Balearic Islands', 'Basque Country', 'Canary Islands', 'Cantabria', 'Castile and León', 'Castile-La Mancha', 'Catalonia', 'Extremadura', 'Galicia', 'La Rioja', 'Madrid', 'Murcia', 'Navarre', 'Valencia' ], 'BR': [ 'Acre', 'Alagoas', 'Amapá', 'Amazonas', 'Bahia', 'Ceará', 'Distrito Federal', 'Espírito Santo', 'Goiás', 'Maranhão', 'Mato Grosso', 'Mato Grosso do Sul', 'Minas Gerais', 'Pará', 'Paraíba', 'Paraná', 'Pernambuco', 'Piauí', 'Rio de Janeiro', 'Rio Grande do Norte', 'Rio Grande do Sul', 'Rondônia', 'Roraima', 'Santa Catarina', 'São Paulo', 'Sergipe', 'Tocantins' ], 'MX': [ 'Aguascalientes', 'Baja California', 'Baja California Sur', 'Campeche', 'Chiapas', 'Chihuahua', 'Coahuila', 'Colima', 'Durango', 'Guanajuato', 'Guerrero', 'Hidalgo', 'Jalisco', 'Mexico State', 'Michoacán', 'Morelos', 'Nayarit', 'Nuevo León', 'Oaxaca', 'Puebla', 'Querétaro', 'Quintana Roo', 'San Luis Potosí', 'Sinaloa', 'Sonora', 'Tabasco', 'Tamaulipas', 'Tlaxcala', 'Veracruz', 'Yucatán', 'Zacatecas' ], 'CN': [ 'Anhui', 'Beijing', 'Chongqing', 'Fujian', 'Gansu', 'Guangdong', 'Guangxi', 'Guizhou', 'Hainan', 'Hebei', 'Heilongjiang', 'Henan', 'Hubei', 'Hunan', 'Inner Mongolia', 'Jiangsu', 'Jiangxi', 'Jilin', 'Liaoning', 'Ningxia', 'Qinghai', 'Shaanxi', 'Shandong', 'Shanghai', 'Shanxi', 'Sichuan', 'Tianjin', 'Tibet', 'Xinjiang', 'Yunnan', 'Zhejiang' ], 'JP': [ 'Aichi', 'Akita', 'Aomori', 'Chiba', 'Ehime', 'Fukui', 'Fukuoka', 'Fukushima', 'Gifu', 'Gunma', 'Hiroshima', 'Hokkaido', 'Hyogo', 'Ibaraki', 'Ishikawa', 'Iwate', 'Kagawa', 'Kagoshima', 'Kanagawa', 'Kochi', 'Kumamoto', 'Kyoto', 'Mie', 'Miyagi', 'Miyazaki', 'Nagano', 'Nagasaki', 'Nara', 'Niigata', 'Oita', 'Okayama', 'Okinawa', 'Osaka', 'Saga', 'Saitama', 'Shiga', 'Shimane', 'Shizuoka', 'Tochigi', 'Tokushima', 'Tokyo', 'Tottori', 'Toyama', 'Wakayama', 'Yamagata', 'Yamaguchi', 'Yamanashi' ] }; // 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 = '#000000'; stepNumber.style.borderColor = '#000000'; 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) { if (step === 5) { const selectedPayment = document.querySelector('.payment-option.selected'); if (!selectedPayment) { isValid = false; alert('Please select a payment method'); return isValid; } const activePaymentDetails = document.querySelector('.payment-details.active'); if (activePaymentDetails) { const requiredFields = activePaymentDetails.querySelectorAll('[required]'); // Validate card payment if (formData.userDetails.paymentMethod === 'card') { // Card number validation const cardNumber = document.getElementById('card-number').value; if (!validateCardNumber(cardNumber)) { isValid = false; document.getElementById('card-number').style.border = '1px solid #ef4444'; alert('Please enter a valid card number'); } else { document.getElementById('card-number').style.border = ''; // Show card type const cardType = detectCardType(cardNumber); if (cardType !== 'unknown') { // You can display card type to user if needed console.log('Detected card type:', cardType); } } // Expiry date validation const expiryDate = document.getElementById('expiry-date').value; if (!validateExpiryDate(expiryDate)) { isValid = false; document.getElementById('expiry-date').style.border = '1px solid #ef4444'; alert('Please enter a valid expiry date (MM/YY)'); } else { document.getElementById('expiry-date').style.border = ''; } // CVV validation const cvv = document.getElementById('security-code').value; const cardType = detectCardType(cardNumber); if (!validateCVV(cvv, cardType)) { isValid = false; document.getElementById('security-code').style.border = '1px solid #ef4444'; alert(`Please enter a valid ${cardType === 'amex' ? '4-digit' : '3-digit'} CVV`); } else { document.getElementById('security-code').style.border = ''; } // ZIP code validation const zipCode = document.getElementById('card-zip').value; if (!validateZipCode(zipCode)) { isValid = false; document.getElementById('card-zip').style.border = '1px solid #ef4444'; alert('Please enter a valid ZIP code'); } else { document.getElementById('card-zip').style.border = ''; } } // Validate bank payment else if (formData.userDetails.paymentMethod === 'bank') { // Account number validation const accountNumber = document.getElementById('account-number').value; if (!validateBankAccount(accountNumber)) { isValid = false; document.getElementById('account-number').style.border = '1px solid #ef4444'; alert('Please enter a valid account number (8-17 digits)'); } else { document.getElementById('account-number').style.border = ''; } // Routing number validation const routingNumber = document.getElementById('routing-number').value; if (!validateRoutingNumber(routingNumber)) { isValid = false; document.getElementById('routing-number').style.border = '1px solid #ef4444'; alert('Please enter a valid routing number'); } else { document.getElementById('routing-number').style.border = ''; } // Basic validation for other bank fields requiredFields.forEach(field => { if (!field.value.trim()) { isValid = false; field.style.border = '1px solid #ef4444'; } else { field.style.border = ''; } }); } } } else if (step === 1) { const email = document.getElementById('email').value; if (!validateEmail(email)) { isValid = false; document.getElementById('email').style.border = '1px solid #ef4444'; alert('Please enter a valid email address'); } else { document.getElementById('email').style.border = ''; } // Validate other required fields const requiredFields = form.querySelectorAll('[required]'); requiredFields.forEach(field => { if (field.id !== 'email' && !field.value.trim()) { isValid = false; field.style.border = '1px solid #ef4444'; } else if (field.id !== 'email') { field.style.border = ''; } }); } else if (step === 3) { const email = document.getElementById('billing-email').value; if (!validateEmail(email)) { isValid = false; document.getElementById('billing-email').style.border = '1px solid #ef4444'; alert('Please enter a valid email address'); } else { document.getElementById('billing-email').style.border = ''; } // Validate other required fields const requiredFields = form.querySelectorAll('[required]'); requiredFields.forEach(field => { if (field.id !== 'email' && !field.value.trim()) { isValid = false; field.style.border = '1px solid #ef4444'; } else if (field.id !== 'email') { field.style.border = ''; } }); } else if (step === 4) { const email = document.getElementById('signatory-email').value; if (!validateEmail(email)) { isValid = false; document.getElementById('signatory-email').style.border = '1px solid #ef4444'; alert('Please enter a valid email address'); } else { document.getElementById('signatory-email').style.border = ''; } // Validate other required fields const requiredFields = form.querySelectorAll('[required]'); requiredFields.forEach(field => { if (field.id !== 'email' && !field.value.trim()) { isValid = false; field.style.border = '1px solid #ef4444'; } else if (field.id !== 'email') { field.style.border = ''; } }); } else { // For other steps, validate all required fields normally 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; } } // 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'); // Remove required attributes from all payment fields details.querySelectorAll('[required]').forEach(field => { field.removeAttribute('required'); }); }); // 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'; // Add required attributes only to card fields document.getElementById('card-number').setAttribute('required', 'true'); document.getElementById('expiry-date').setAttribute('required', 'true'); document.getElementById('security-code').setAttribute('required', 'true'); document.getElementById('card-zip').setAttribute('required', 'true'); } else if (type === 'bank') { document.getElementById('bank-details').classList.add('active'); formData.userDetails.paymentMethod = 'bank'; // Add required attributes only to bank fields document.getElementById('bank-name').setAttribute('required', 'true'); document.getElementById('account-number').setAttribute('required', 'true'); document.getElementById('routing-number').setAttribute('required', 'true'); document.getElementById('account-type').setAttribute('required', 'true'); document.getElementById('account-holder-name').setAttribute('required', 'true'); } } // 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 { // console.log('Submitting form data:', formData); // Send data to server using fetch const response = await fetch('/api/v1/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 = '#000000'; stepNumber.style.borderColor = '#000000'; stepNumber.style.color = 'white'; }); nextStep(6); setTimeout(() => { window.location.href = '/client/login'; }, 1000); } else { // Handle server errors if (response.status === 409) { alert('A user with this email already exists. Please use a different email.'); } else { 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 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 async 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 async function detectLocation() { // Show loading indicators const stateLoader = document.getElementById('state-loading'); if (stateLoader) stateLoader.style.display = 'block'; try { const response = await fetch('https://ipapi.co/json/'); const data = await response.json(); // Hide loading indicators if (stateLoader) stateLoader.style.display = 'none'; // const countryCode = data.country_code || 'US'; const supportedCountries = Object.keys(statesByCountry); const countryCode = supportedCountries.includes(data.country_code) ? data.country_code : 'US'; const region = data.region || ''; const city = data.city || ''; const zip = data.postal || ''; // Populate city and state based on detected location const cityInput = document.getElementById('city'); const zipInput = document.getElementById('zip'); if (cityInput) cityInput.value = city; if (zipInput) zipInput.value = zip; // Populate states dropdown for the detected country await populateStates(countryCode, 'state'); await populateStates(countryCode, 'billing-state'); const stateSelect = document.getElementById('state'); const billingStateSelect = document.getElementById('billing-state'); if (stateSelect && region) { const matchedState = Array.from(stateSelect.options).find( opt => opt.text.toLowerCase() === region.toLowerCase() ); if (matchedState) { stateSelect.value = matchedState.value; stateSelect.dispatchEvent(new Event('change')); } } if (billingStateSelect && region) { const matchedBillingState = Array.from(billingStateSelect.options).find( opt => opt.text.toLowerCase() === region.toLowerCase() ); if (matchedBillingState) { billingStateSelect.value = matchedBillingState.value; billingStateSelect.dispatchEvent(new Event('change')); } } } catch (error) { console.error('Error detecting location:', error); // Hide loading indicators if (stateLoader) stateLoader.style.display = 'none'; // Fallback to US states if detection fails await populateStates('US', 'state'); await populateStates('US', 'billing-state'); } } // Initialize form interactions document.addEventListener('DOMContentLoaded', function() { // Real-time card number formatting and validation const cardNumberInput = document.getElementById('card-number'); if (cardNumberInput) { cardNumberInput.addEventListener('input', function(e) { // Format card number with spaces let value = e.target.value.replace(/\s/g, ''); let formattedValue = ''; for (let i = 0; i < value.length; i++) { if (i > 0 && i % 4 === 0) { formattedValue += ' '; } formattedValue += value[i]; } e.target.value = formattedValue; // Real-time card type detection const cardType = detectCardType(value); if (cardType !== 'unknown') { // You can add visual feedback for card type here console.log('Card type:', cardType); } }); } // Real-time expiry date formatting const expiryInput = document.getElementById('expiry-date'); if (expiryInput) { expiryInput.addEventListener('input', function(e) { let value = e.target.value.replace(/\D/g, ''); if (value.length >= 2) { value = value.substring(0, 2) + '/' + value.substring(2, 4); } e.target.value = value; }); } // Real-time CVV validation const cvvInput = document.getElementById('security-code'); if (cvvInput) { cvvInput.addEventListener('input', function(e) { e.target.value = e.target.value.replace(/\D/g, '').substring(0, 4); }); } // Real-time email validation const emailInputs = document.querySelectorAll('input[type="email"]'); emailInputs.forEach(emailInput => { if (emailInput) { emailInput.addEventListener('blur', function(e) { if (e.target.value && !validateEmail(e.target.value)) { e.target.style.border = '1px solid #ef4444'; } else { e.target.style.border = ''; } }); } }); // 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 = '4px'; 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 = '4px'; 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 = '4px'; 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 = '4px'; 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.userDetails.email || ''; document.getElementById('billing-email').dispatchEvent(new Event('input')); } }); // Detect user location when the page loads detectLocation(); });