va-tracker-middleware/public/js/va-client-register.js

531 lines
20 KiB
JavaScript

// // 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();
});