810 lines
31 KiB
JavaScript
810 lines
31 KiB
JavaScript
// 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'
|
|
]
|
|
};
|
|
|
|
// 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);
|
|
} 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);
|
|
});
|
|
// const selectElement = document.getElementById(selectElementId);
|
|
|
|
// // Clear existing options except the first empty one
|
|
// while (selectElement.options.length > 1) {
|
|
// selectElement.remove(1);
|
|
// }
|
|
|
|
// // Fetch states from API
|
|
// const states = await fetchStates(countryCode);
|
|
|
|
// // Add states as options
|
|
// states.forEach(state => {
|
|
// const option = document.createElement('option');
|
|
// option.value = state.code || state.name;
|
|
// option.textContent = state.name;
|
|
// selectElement.appendChild(option);
|
|
// });
|
|
}
|
|
|
|
// Function to detect user location
|
|
async function detectLocation() {
|
|
// Show loading indicators
|
|
document.getElementById('state-loading').style.display = 'block';
|
|
|
|
try {
|
|
const response = await fetch('https://ipapi.co/json/');
|
|
const data = await response.json();
|
|
|
|
// 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
|
|
await populateStates(data.country_code, 'state');
|
|
|
|
// Set the detected state
|
|
if (data.region) {
|
|
document.getElementById('state').value = data.region;
|
|
document.getElementById('state').dispatchEvent(new Event('change'));
|
|
}
|
|
|
|
// Also populate billing states dropdown
|
|
await 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
|
|
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();
|
|
}); |