Fixed issues and bugs
This commit is contained in:
parent
9429caacd6
commit
aecb4af2ac
|
|
@ -475,4 +475,43 @@ body {
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.step-error-container {
|
||||||
|
background-color: #fef2f2;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
animation: slideDown 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: #dc2626;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message::before {
|
||||||
|
content: "⚠";
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-error {
|
||||||
|
border: 1px solid #dc2626 !important;
|
||||||
|
background-color: #fef2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideDown {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -109,7 +109,22 @@
|
||||||
|
|
||||||
|
|
||||||
// Add input event listeners to handle label animation
|
// Add input event listeners to handle label animation
|
||||||
document.querySelectorAll('.input-field').forEach(input => {
|
document.querySelectorAll('.input-field:not(.dob)').forEach(input => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (input.value) {
|
||||||
|
input.nextElementSibling.style.top = '4px';
|
||||||
|
input.nextElementSibling.style.fontSize = '12px';
|
||||||
|
input.nextElementSibling.style.transform = 'none';
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
input.addEventListener('animationstart', function() {
|
||||||
|
if (this.value) {
|
||||||
|
this.nextElementSibling.style.top = '4px';
|
||||||
|
this.nextElementSibling.style.fontSize = '12px';
|
||||||
|
this.nextElementSibling.style.transform = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
input.addEventListener('input', function() {
|
input.addEventListener('input', function() {
|
||||||
if (this.value) {
|
if (this.value) {
|
||||||
this.nextElementSibling.style.top = '4px';
|
this.nextElementSibling.style.top = '4px';
|
||||||
|
|
@ -139,6 +154,13 @@
|
||||||
|
|
||||||
// Handle select field label animation
|
// Handle select field label animation
|
||||||
document.querySelectorAll('.select-field').forEach(select => {
|
document.querySelectorAll('.select-field').forEach(select => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (select.value) {
|
||||||
|
select.nextElementSibling.style.top = '4px';
|
||||||
|
select.nextElementSibling.style.fontSize = '12px';
|
||||||
|
select.nextElementSibling.style.transform = 'none';
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
select.addEventListener('change', function() {
|
select.addEventListener('change', function() {
|
||||||
if (this.value) {
|
if (this.value) {
|
||||||
this.nextElementSibling.style.top = '4px';
|
this.nextElementSibling.style.top = '4px';
|
||||||
|
|
@ -228,10 +250,14 @@
|
||||||
return maxStep;
|
return maxStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleNextStep(step) {
|
||||||
|
await nextStep(step);
|
||||||
|
}
|
||||||
|
|
||||||
// Function to navigate to next step
|
// Function to navigate to next step
|
||||||
function nextStep(step) {
|
async function nextStep(step) {
|
||||||
// Validate current step before proceeding
|
// Validate current step before proceeding
|
||||||
if (!validateStep(currentStep)) {
|
if (!(await validateStep(currentStep))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,9 +332,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to validate current step
|
// Function to validate current step
|
||||||
function validateStep(step) {
|
async function validateStep(step) {
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
const form = document.getElementById(getFormId(step));
|
const form = document.getElementById(getFormId(step));
|
||||||
|
|
||||||
|
// Hide any previous errors for this step
|
||||||
|
hideError(step);
|
||||||
|
clearFieldErrors();
|
||||||
|
|
||||||
if (form) {
|
if (form) {
|
||||||
// For account setup step
|
// For account setup step
|
||||||
|
|
@ -319,21 +349,31 @@
|
||||||
|
|
||||||
// Email validation
|
// Email validation
|
||||||
if (!validateEmail(email)) {
|
if (!validateEmail(email)) {
|
||||||
alert('Please enter a valid email address');
|
showError('Please enter a valid email address', 'email', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
|
} else {
|
||||||
|
// Email verification - wait for the result
|
||||||
|
const isEmailVerified = await verifyEmail(email);
|
||||||
|
if (!isEmailVerified) {
|
||||||
|
showError('Email already registered. Please use a different email address.', 'email', step);
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Password validation
|
// Password validation
|
||||||
if (password.length < 8) {
|
if (password.length < 8) {
|
||||||
alert('Password must be at least 8 characters long');
|
showError('Password must be at least 8 characters long', 'password', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password !== confirmPassword) {
|
if (password !== confirmPassword) {
|
||||||
document.getElementById('password-match-error').style.display = 'block';
|
document.getElementById('password-match-error').style.display = 'block';
|
||||||
|
document.getElementById('confirmPassword').classList.add('field-error');
|
||||||
|
showError('Passwords do not match', 'confirmPassword', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('password-match-error').style.display = 'none';
|
document.getElementById('password-match-error').style.display = 'none';
|
||||||
|
document.getElementById('confirmPassword').classList.remove('field-error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -342,15 +382,18 @@
|
||||||
const firstName = document.getElementById('firstName').value;
|
const firstName = document.getElementById('firstName').value;
|
||||||
if (!firstName) {
|
if (!firstName) {
|
||||||
document.getElementById('profile-incomplete').style.display = 'block';
|
document.getElementById('profile-incomplete').style.display = 'block';
|
||||||
|
document.getElementById('firstName').classList.add('field-error');
|
||||||
|
showError('First name is required', 'firstName', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('profile-incomplete').style.display = 'none';
|
document.getElementById('profile-incomplete').style.display = 'none';
|
||||||
|
document.getElementById('firstName').classList.remove('field-error');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Age validation
|
// Age validation
|
||||||
const age = document.getElementById('age').value;
|
const age = document.getElementById('age').value;
|
||||||
if (age && (age < 18 || age > 100)) {
|
if (age && (age < 18 || age > 100)) {
|
||||||
alert('You must be 18 years or older to register');
|
showError('You must be 18 years or older to register', 'dob', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -359,12 +402,12 @@
|
||||||
const state = document.getElementById('state').value;
|
const state = document.getElementById('state').value;
|
||||||
|
|
||||||
if (!country) {
|
if (!country) {
|
||||||
alert('Please select your country');
|
showError('Please select your country', 'country', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state) {
|
if (!state) {
|
||||||
alert('Please select your state/region');
|
showError('Please select your state/region', 'state', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,9 +416,40 @@
|
||||||
requiredFields.forEach(field => {
|
requiredFields.forEach(field => {
|
||||||
if (!field.value.trim()) {
|
if (!field.value.trim()) {
|
||||||
isValid = false;
|
isValid = false;
|
||||||
field.style.border = '1px solid #ef4444';
|
field.classList.add('field-error');
|
||||||
|
if (isValid === false) {
|
||||||
|
showError(`Please fill in ${field.labels[0]?.textContent || 'this field'}`, field.id, step);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
field.style.border = '';
|
field.classList.remove('field-error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step === 3) {
|
||||||
|
// Phone number validation
|
||||||
|
const phone = document.getElementById('phone').value;
|
||||||
|
if (!phone) {
|
||||||
|
showError('Please enter your phone number', 'phone', step);
|
||||||
|
isValid = false;
|
||||||
|
} else if (!validatePhoneNumberStrict(phone)) {
|
||||||
|
document.getElementById('phone-error').style.display = 'block';
|
||||||
|
document.getElementById('phone').classList.add('field-error');
|
||||||
|
showError('Please enter a valid phone number (10-15 digits)', 'phone', step);
|
||||||
|
isValid = false;
|
||||||
|
} else {
|
||||||
|
document.getElementById('phone-error').style.display = 'none';
|
||||||
|
document.getElementById('phone').classList.remove('field-error');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate other required fields in step 3
|
||||||
|
const requiredFields = form.querySelectorAll('[required]');
|
||||||
|
requiredFields.forEach(field => {
|
||||||
|
if (!field.value.trim()) {
|
||||||
|
isValid = false;
|
||||||
|
field.classList.add('field-error');
|
||||||
|
} else {
|
||||||
|
field.classList.remove('field-error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -384,20 +458,20 @@
|
||||||
if (step === 4) {
|
if (step === 4) {
|
||||||
const selectedPayment = document.querySelector('.payment-option.selected');
|
const selectedPayment = document.querySelector('.payment-option.selected');
|
||||||
if (!selectedPayment) {
|
if (!selectedPayment) {
|
||||||
alert('Please select a payment method');
|
showError('Please select a payment method', null, step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else {
|
} else {
|
||||||
const paymentMethod = selectedPayment.getAttribute('onclick').match(/'([^']+)'/)[1];
|
const paymentMethod = selectedPayment.getAttribute('onclick').match(/'([^']+)'/)[1];
|
||||||
if (paymentMethod === 'payoneer') {
|
if (paymentMethod === 'payoneer') {
|
||||||
const payoneerAccount = document.getElementById('payoneerAccount').value;
|
const payoneerAccount = document.getElementById('payoneerAccount').value;
|
||||||
if (!payoneerAccount) {
|
if (!payoneerAccount) {
|
||||||
alert('Please enter your Payoneer account number');
|
showError('Please enter your Payoneer account number', 'payoneerAccount', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
} else if (paymentMethod === 'veem') {
|
} else if (paymentMethod === 'veem') {
|
||||||
const veemAccount = document.getElementById('veemAccount').value;
|
const veemAccount = document.getElementById('veemAccount').value;
|
||||||
if (!veemAccount) {
|
if (!veemAccount) {
|
||||||
alert('Please enter your Veem account number');
|
showError('Please enter your Veem account number', 'veemAccount', step);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -410,9 +484,9 @@
|
||||||
requiredFields.forEach(field => {
|
requiredFields.forEach(field => {
|
||||||
if (!field.value.trim()) {
|
if (!field.value.trim()) {
|
||||||
isValid = false;
|
isValid = false;
|
||||||
field.style.border = '1px solid #ef4444';
|
field.classList.add('field-error');
|
||||||
} else {
|
} else {
|
||||||
field.style.border = '';
|
field.classList.remove('field-error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -598,12 +672,12 @@
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
// Handle server errors
|
// Handle server errors
|
||||||
alert('There was an error submitting your registration. Please try again.');
|
showError('There was an error submitting your registration. Please try again.', null, 4);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Handle network errors
|
// Handle network errors
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
alert('There was a network error. Please check your connection and try again.');
|
showError('There was a network error. Please check your connection and try again.', null, 4);
|
||||||
} finally {
|
} finally {
|
||||||
// Restore button state
|
// Restore button state
|
||||||
submitBtn.textContent = originalText;
|
submitBtn.textContent = originalText;
|
||||||
|
|
@ -611,3 +685,218 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function verifyEmail(email) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/v1/va/verify-va-email', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({"email": email})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Handle network errors
|
||||||
|
console.error('Error:', error);
|
||||||
|
showError('There was a network error. Please check your connection and try again.', null, 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to calculate age from date of birth
|
||||||
|
function calculateAge(dob) {
|
||||||
|
if (!dob) return '';
|
||||||
|
|
||||||
|
const birthDate = new Date(dob);
|
||||||
|
const today = new Date();
|
||||||
|
|
||||||
|
let age = today.getFullYear() - birthDate.getFullYear();
|
||||||
|
const monthDiff = today.getMonth() - birthDate.getMonth();
|
||||||
|
|
||||||
|
// Adjust age if birthday hasn't occurred this year yet
|
||||||
|
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
||||||
|
age--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to handle date of birth change and update age
|
||||||
|
function handleDOBChange() {
|
||||||
|
const dob = document.getElementById('dob').value;
|
||||||
|
const ageInput = document.getElementById('age');
|
||||||
|
|
||||||
|
if (dob) {
|
||||||
|
const age = calculateAge(dob);
|
||||||
|
ageInput.value = age;
|
||||||
|
|
||||||
|
// Trigger input event to update the label position
|
||||||
|
ageInput.dispatchEvent(new Event('input'));
|
||||||
|
|
||||||
|
// Validate age
|
||||||
|
if (age < 18) {
|
||||||
|
alert('You must be 18 years or older to register');
|
||||||
|
ageInput.style.border = '1px solid #ef4444';
|
||||||
|
} else if (age > 100) {
|
||||||
|
alert('Please enter a valid age');
|
||||||
|
ageInput.style.border = '1px solid #ef4444';
|
||||||
|
} else {
|
||||||
|
ageInput.style.border = '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Clear age if DOB is cleared
|
||||||
|
ageInput.value = '';
|
||||||
|
ageInput.dispatchEvent(new Event('input'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to handle age manual input and update DOB (optional)
|
||||||
|
function handleAgeChange() {
|
||||||
|
const age = document.getElementById('age').value;
|
||||||
|
const dobInput = document.getElementById('dob');
|
||||||
|
|
||||||
|
if (age && age >= 18 && age <= 100) {
|
||||||
|
// Calculate approximate DOB based on age
|
||||||
|
const today = new Date();
|
||||||
|
const birthYear = today.getFullYear() - age;
|
||||||
|
const approximateDOB = `${birthYear}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
|
||||||
|
|
||||||
|
// You can set this as the DOB or just leave it for reference
|
||||||
|
// dobInput.value = approximateDOB;
|
||||||
|
// dobInput.dispatchEvent(new Event('change'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to validate phone number in real-time
|
||||||
|
function validatePhoneNumber(input) {
|
||||||
|
const phoneError = document.getElementById('phone-error');
|
||||||
|
const value = input.value;
|
||||||
|
|
||||||
|
// Remove any non-digit characters
|
||||||
|
const digitsOnly = value.replace(/\D/g, '');
|
||||||
|
|
||||||
|
// Update the input value with digits only
|
||||||
|
if (value !== digitsOnly) {
|
||||||
|
input.value = digitsOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate length
|
||||||
|
if (digitsOnly.length > 0 && (digitsOnly.length < 10 || digitsOnly.length > 15)) {
|
||||||
|
phoneError.style.display = 'block';
|
||||||
|
input.style.border = '1px solid #ef4444';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
phoneError.style.display = 'none';
|
||||||
|
input.style.border = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to validate phone number on form submission
|
||||||
|
function validatePhoneNumberStrict(phone) {
|
||||||
|
const phoneRegex = /^[0-9]{10,15}$/;
|
||||||
|
return phoneRegex.test(phone);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to validate Payoneer account number
|
||||||
|
function validatePayoneerAccount(input) {
|
||||||
|
const payoneerError = document.getElementById('payoneer-error');
|
||||||
|
const value = input.value.trim();
|
||||||
|
|
||||||
|
// Payoneer typically uses email format or alphanumeric IDs
|
||||||
|
// Adjust validation rules based on Payoneer's actual format requirements
|
||||||
|
if (value.length > 0 && (value.length < 5 || value.length > 20)) {
|
||||||
|
payoneerError.textContent = 'Payoneer account must be 5-20 characters';
|
||||||
|
payoneerError.style.display = 'block';
|
||||||
|
input.style.border = '1px solid #ef4445';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
payoneerError.style.display = 'none';
|
||||||
|
input.style.border = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to validate Veem account number
|
||||||
|
function validateVeemAccount(input) {
|
||||||
|
const veemError = document.getElementById('veem-error');
|
||||||
|
const value = input.value.trim();
|
||||||
|
|
||||||
|
// Veem account numbers are typically longer alphanumeric strings
|
||||||
|
if (value.length > 0 && (value.length < 8 || value.length > 25)) {
|
||||||
|
veemError.textContent = 'Veem account must be 8-25 characters';
|
||||||
|
veemError.style.display = 'block';
|
||||||
|
input.style.border = '1px solid #ef4445';
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
veemError.style.display = 'none';
|
||||||
|
input.style.border = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showError(message, fieldId = null, step = null) {
|
||||||
|
// Determine the current step if not provided
|
||||||
|
const currentStep = step || getCurrentStep();
|
||||||
|
const errorContainer = document.getElementById(`step-${currentStep}-error`);
|
||||||
|
const errorMessage = document.getElementById(`step-${currentStep}-error-message`);
|
||||||
|
|
||||||
|
if (errorContainer && errorMessage) {
|
||||||
|
errorMessage.textContent = message;
|
||||||
|
errorContainer.style.display = 'block';
|
||||||
|
|
||||||
|
// Scroll to error container
|
||||||
|
errorContainer.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
|
|
||||||
|
// Highlight specific field if provided
|
||||||
|
if (fieldId) {
|
||||||
|
const field = document.getElementById(fieldId);
|
||||||
|
if (field) {
|
||||||
|
field.classList.add('field-error');
|
||||||
|
// Remove error after 5 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
field.classList.remove('field-error');
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-hide error after 8 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
hideError(currentStep);
|
||||||
|
}, 8000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideError(step = null) {
|
||||||
|
if (step) {
|
||||||
|
// Hide specific step error
|
||||||
|
const errorContainer = document.getElementById(`step-${step}-error`);
|
||||||
|
if (errorContainer) {
|
||||||
|
errorContainer.style.display = 'none';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Hide all step errors
|
||||||
|
for (let i = 1; i <= 5; i++) {
|
||||||
|
const errorContainer = document.getElementById(`step-${i}-error`);
|
||||||
|
if (errorContainer) {
|
||||||
|
errorContainer.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearFieldErrors() {
|
||||||
|
document.querySelectorAll('.field-error').forEach(field => {
|
||||||
|
field.classList.remove('field-error');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentStep() {
|
||||||
|
return currentStep;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { ClientModel } from "../../models/vaModel.js";
|
||||||
|
|
||||||
|
// Verify VA Email
|
||||||
|
async function client_verify_email(req, res) {
|
||||||
|
try {
|
||||||
|
// const payload = req.body ? JSON.parse(req.body) : {};
|
||||||
|
const payload = req.body || {};
|
||||||
|
const { email } = payload;
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
return res.status(400).json({ success: false, message: "Please provide email" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find user by email
|
||||||
|
const user = await ClientModel.findOne({ "userDetails.email": email });
|
||||||
|
if (!user) {
|
||||||
|
return res.status(404).json({ success: false, message: "Email not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return accessToken and user info
|
||||||
|
return res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
email: user.userDetails?.email,
|
||||||
|
message: "Email ID is already registerd"
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("va_register error:", error);
|
||||||
|
return res.status(500).json({ success: false, message: "Internal Server Error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { client_verify_email };
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { VAModel } from "../../../models/vaModel.js";
|
||||||
|
|
||||||
|
// Verify VA Email
|
||||||
|
async function va_verify_email(req, res) {
|
||||||
|
try {
|
||||||
|
// const payload = req.body ? JSON.parse(req.body) : {};
|
||||||
|
const payload = req.body || {};
|
||||||
|
const { email } = payload;
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
return res.status(400).json({ success: false, message: "Please provide email" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find user by email
|
||||||
|
const user = await VAModel.findOne({ "userDetails.email": email });
|
||||||
|
if (!user) {
|
||||||
|
return res.status(404).json({ success: false, message: "Invalid Email ID" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return accessToken and user info
|
||||||
|
return res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
email: user.userDetails?.email,
|
||||||
|
message: "Email verified successfully"
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("va_register error:", error);
|
||||||
|
return res.status(500).json({ success: false, message: "Internal Server Error" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { va_verify_email };
|
||||||
|
|
@ -9,13 +9,15 @@ import { client_refresh_token_callback } from "../../controllers/client/clientRe
|
||||||
import { client_request_password_reset } from "../../controllers/passwordReset.controllers.js";
|
import { client_request_password_reset } from "../../controllers/passwordReset.controllers.js";
|
||||||
import { clientAuthValidator } from "../../middlewares/auth.middleware.js";
|
import { clientAuthValidator } from "../../middlewares/auth.middleware.js";
|
||||||
import { client_dashboard } from "./../../controllers/client/dashboard/clientDashboard.controller.js";
|
import { client_dashboard } from "./../../controllers/client/dashboard/clientDashboard.controller.js";
|
||||||
import { client_dashboard_va_log } from "../../controllers/client/dashboard/clientDashboardVaLog.controller.js"
|
import { client_dashboard_va_log } from "../../controllers/client/dashboard/clientDashboardVaLog.controller.js";
|
||||||
|
import { client_verify_email } from "../../controllers/client/vaClientEmailVerify.controller.js";
|
||||||
|
|
||||||
// clients routes
|
// clients routes
|
||||||
clientRoutes.post("/register", va_register_client); // Register a new VA
|
clientRoutes.post("/register", va_register_client); // Register a new VA
|
||||||
clientRoutes.post("/login", va_login_client); // Login Client
|
clientRoutes.post("/login", va_login_client); // Login Client
|
||||||
clientRoutes.get("/refreshToken", client_refresh_token_callback); // Client Refresh Token
|
clientRoutes.get("/refreshToken", client_refresh_token_callback); // Client Refresh Token
|
||||||
clientRoutes.post("/forgot-password", client_request_password_reset);
|
clientRoutes.post("/forgot-password", client_request_password_reset);
|
||||||
|
clientRoutes.post("/verify-client-email", client_verify_email);
|
||||||
|
|
||||||
// clientRoutes.get("/:clientID?", va_clients_callback); // VA Clients Callback for getting all VA's or specific client by ID (NC)
|
// clientRoutes.get("/:clientID?", va_clients_callback); // VA Clients Callback for getting all VA's or specific client by ID (NC)
|
||||||
clientRoutes.get("/:clientId/projects/:projectId", va_clients_projects_callback); // VA Clients Projects Callback (NC)
|
clientRoutes.get("/:clientId/projects/:projectId", va_clients_projects_callback); // VA Clients Projects Callback (NC)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import { va_timesheet_summary_function } from "../../controllers/va/vaTimesheetA
|
||||||
import { va_timesheet_adjustment_function } from "../../controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js";
|
import { va_timesheet_adjustment_function } from "../../controllers/va/vaTimesheetAdjustment/vaTimesheetAdjustment.controller.js";
|
||||||
import { get_adjustment_requests_list } from "../../controllers/va/vaTimesheetAdjustment/vaAllTimesheetAdjustmentReuqest.controller.js"
|
import { get_adjustment_requests_list } from "../../controllers/va/vaTimesheetAdjustment/vaAllTimesheetAdjustmentReuqest.controller.js"
|
||||||
import { va_timesheet_manage_adjustment_request } from "../../controllers/va/vaTimesheetAdjustment/vaManageTimesheetAdjustment.controller.js"
|
import { va_timesheet_manage_adjustment_request } from "../../controllers/va/vaTimesheetAdjustment/vaManageTimesheetAdjustment.controller.js"
|
||||||
|
import { va_verify_email } from "../../controllers/va/vaAuth/vaVerifyEmail.controller.js";
|
||||||
|
|
||||||
vaRoutes.get("/", va_callback); // VA Callback for getting active VA
|
vaRoutes.get("/", va_callback); // VA Callback for getting active VA
|
||||||
|
|
||||||
|
|
@ -30,6 +31,7 @@ vaRoutes.get("/logout", authValidator, va_logout_callback); // VA Callback for l
|
||||||
vaRoutes.post("/refreshToken", va_refresh_token_callback); // VA Callback for refresh token
|
vaRoutes.post("/refreshToken", va_refresh_token_callback); // VA Callback for refresh token
|
||||||
vaRoutes.post("/register", va_register); // Register a new VA
|
vaRoutes.post("/register", va_register); // Register a new VA
|
||||||
vaRoutes.post("/forgot-password", va_request_password_reset);
|
vaRoutes.post("/forgot-password", va_request_password_reset);
|
||||||
|
vaRoutes.post("/verify-va-email", va_verify_email);
|
||||||
|
|
||||||
vaRoutes.get("/profile", authValidator, va_profile_callback); // Get VA Profile
|
vaRoutes.get("/profile", authValidator, va_profile_callback); // Get VA Profile
|
||||||
vaRoutes.patch("/profile", authValidator, va_profile_update_callback); // Update VA Profile
|
vaRoutes.patch("/profile", authValidator, va_profile_update_callback); // Update VA Profile
|
||||||
|
|
|
||||||
|
|
@ -92,12 +92,18 @@
|
||||||
<!-- Step 1: Create Account -->
|
<!-- Step 1: Create Account -->
|
||||||
<div class="form-step active" id="step-1">
|
<div class="form-step active" id="step-1">
|
||||||
<h2 class="form-title">Create Your Account</h2>
|
<h2 class="form-title">Create Your Account</h2>
|
||||||
|
<div class="step-error-container" id="step-1-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-1-error-message"></div>
|
||||||
|
</div>
|
||||||
<form id="account-form">
|
<form id="account-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="company-name" class="input-field" placeholder=" " required>
|
<input type="text" id="company-name" class="input-field" placeholder=" " oninput="validateCompanyName(this)" required>
|
||||||
<label for="company-name" class="input-label">Company / Client Name *</label>
|
<label for="company-name" class="input-label">Company / Client Name *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="company-name-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Company name should only contain letters, numbers, spaces, hyphens, apostrophes, ampersands, and periods
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
|
|
@ -107,7 +113,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<div></div> <!-- Empty div for spacing -->
|
<div></div> <!-- Empty div for spacing -->
|
||||||
<button type="button" class="btn btn-primary" onclick="nextStep(2)">Continue</button>
|
<button type="button" class="btn btn-primary" onclick="handleNextStep(2)">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -115,6 +121,9 @@
|
||||||
<!-- Step 2: Business Information -->
|
<!-- Step 2: Business Information -->
|
||||||
<div class="form-step" id="step-2">
|
<div class="form-step" id="step-2">
|
||||||
<h2 class="form-title">Business Information</h2>
|
<h2 class="form-title">Business Information</h2>
|
||||||
|
<div class="step-error-container" id="step-2-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-2-error-message"></div>
|
||||||
|
</div>
|
||||||
<form id="business-form">
|
<form id="business-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
|
|
@ -124,9 +133,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="city" class="input-field" placeholder=" " required>
|
<input type="text" id="city" class="input-field" placeholder=" " oninput="validateCity(this)" onkeypress="return preventInvalidCityChars(event)" required>
|
||||||
<label for="city" class="input-label">City *</label>
|
<label for="city" class="input-label">City *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="city-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
City name should contain letters and cannot be only numbers or special characters
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
|
|
@ -141,13 +153,16 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="zip" class="input-field" placeholder=" " required>
|
<input type="text" id="zip" class="input-field" placeholder=" " oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)" maxlength="10" required>
|
||||||
<label for="zip" class="input-label">ZIP *</label>
|
<label for="zip" class="input-label">ZIP *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="zip-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
ZIP code should contain only numbers
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="button" class="btn btn-secondary" onclick="prevStep(1)">Back</button>
|
<button type="button" class="btn btn-secondary" onclick="prevStep(1)">Back</button>
|
||||||
<button type="button" class="btn btn-primary" onclick="nextStep(3)">Continue</button>
|
<button type="button" class="btn btn-primary" onclick="handleNextStep(3)">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -155,6 +170,9 @@
|
||||||
<!-- Step 3: Billing Address -->
|
<!-- Step 3: Billing Address -->
|
||||||
<div class="form-step" id="step-3">
|
<div class="form-step" id="step-3">
|
||||||
<h2 class="form-title">Billing Address</h2>
|
<h2 class="form-title">Billing Address</h2>
|
||||||
|
<div class="step-error-container" id="step-3-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-3-error-message"></div>
|
||||||
|
</div>
|
||||||
<form id="billing-form">
|
<form id="billing-form">
|
||||||
<div class="checkbox-group">
|
<div class="checkbox-group">
|
||||||
<input type="checkbox" id="use-business-address">
|
<input type="checkbox" id="use-business-address">
|
||||||
|
|
@ -174,9 +192,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="billing-city" class="input-field" placeholder=" " required>
|
<input type="text" id="billing-city" class="input-field" placeholder=" " oninput="validateCity(this)" onkeypress="return preventInvalidCityChars(event)" required>
|
||||||
<label for="billing-city" class="input-label">City *</label>
|
<label for="billing-city" class="input-label">City *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="billing-city-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
City name should contain letters and cannot be only numbers or special characters
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
|
|
@ -190,9 +211,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="billing-zip" class="input-field" placeholder=" " required>
|
<input type="text" id="billing-zip" class="input-field" placeholder=" " oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)" maxlength="10" required>
|
||||||
<label for="billing-zip" class="input-label">ZIP *</label>
|
<label for="billing-zip" class="input-label">ZIP *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="billing-zip-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
ZIP code should contain only numbers
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox-group">
|
<div class="checkbox-group">
|
||||||
<input type="checkbox" id="use-account-email">
|
<input type="checkbox" id="use-account-email">
|
||||||
|
|
@ -206,7 +230,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="button" class="btn btn-secondary" onclick="prevStep(2)">Back</button>
|
<button type="button" class="btn btn-secondary" onclick="prevStep(2)">Back</button>
|
||||||
<button type="button" class="btn btn-primary" onclick="nextStep(4)">Continue</button>
|
<button type="button" class="btn btn-primary" onclick="handleNextStep(4)">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -214,21 +238,30 @@
|
||||||
<!-- Step 4: Authorized Signatory -->
|
<!-- Step 4: Authorized Signatory -->
|
||||||
<div class="form-step" id="step-4">
|
<div class="form-step" id="step-4">
|
||||||
<h2 class="form-title">Authorized Signatory</h2>
|
<h2 class="form-title">Authorized Signatory</h2>
|
||||||
|
<div class="step-error-container" id="step-4-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-4-error-message"></div>
|
||||||
|
</div>
|
||||||
<p style="margin-bottom: 20px; color: #6b7280; font-size: 14px;">
|
<p style="margin-bottom: 20px; color: #6b7280; font-size: 14px;">
|
||||||
We will use the details below in the agreement that we will send to your prior to entering the project.
|
We will use the details below in the agreement that we will send to your prior to entering the project.
|
||||||
</p>
|
</p>
|
||||||
<form id="signatory-form">
|
<form id="signatory-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="position" class="input-field" placeholder=" " required>
|
<input type="text" id="position" class="input-field" placeholder=" " oninput="validatePosition(this)" onkeypress="return preventInvalidPositionChars(event)" required>
|
||||||
<label for="position" class="input-label">Position (Owner / CEO / Manager / etc.) *</label>
|
<label for="position" class="input-label">Position (Owner / CEO / Manager / etc.) *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="position-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Position should only contain letters, spaces, and common punctuation
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="signatory-name" class="input-field" placeholder=" " required>
|
<input type="text" id="signatory-name" class="input-field" placeholder=" " oninput="validateSignatoryName(this)" onkeypress="return preventNumbers(event)" required>
|
||||||
<label for="signatory-name" class="input-label">Name *</label>
|
<label for="signatory-name" class="input-label">Name *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="signatory-name-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Name should not contain numbers
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
|
|
@ -238,7 +271,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="button" class="btn btn-secondary" onclick="prevStep(3)">Back</button>
|
<button type="button" class="btn btn-secondary" onclick="prevStep(3)">Back</button>
|
||||||
<button type="button" class="btn btn-primary" onclick="nextStep(5)">Continue</button>
|
<button type="button" class="btn btn-primary" onclick="handleNextStep(5)">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -246,6 +279,9 @@
|
||||||
<!-- Step 5: Payment Details -->
|
<!-- Step 5: Payment Details -->
|
||||||
<div class="form-step" id="step-5">
|
<div class="form-step" id="step-5">
|
||||||
<h2 class="form-title">Payment Details</h2>
|
<h2 class="form-title">Payment Details</h2>
|
||||||
|
<div class="step-error-container" id="step-5-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-5-error-message"></div>
|
||||||
|
</div>
|
||||||
<form id="payment-form">
|
<form id="payment-form">
|
||||||
<div class="payment-option" onclick="selectPaymentOption('card')">
|
<div class="payment-option" onclick="selectPaymentOption('card')">
|
||||||
<h4>Credit or Debit Card</h4>
|
<h4>Credit or Debit Card</h4>
|
||||||
|
|
@ -267,16 +303,22 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="security-code" class="input-field" placeholder=" " required>
|
<input type="text" id="security-code" class="input-field" placeholder=" " oninput="validateCVVVV(this)" nkeypress="return preventInvalidCVVChars(event)" maxlength="4" required>
|
||||||
<label for="security-code" class="input-label">Security Code *</label>
|
<label for="security-code" class="input-label">Security Code *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="security-code-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Please enter a valid security code
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="card-zip" class="input-field" placeholder=" " required>
|
<input type="text" id="card-zip" class="input-field" placeholder=" " oninput="validateZipCode(this)" onkeypress="return preventNonNumericZip(event)" maxlength="10" required>
|
||||||
<label for="card-zip" class="input-label">ZIP Code *</label>
|
<label for="card-zip" class="input-label">ZIP Code *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="card-zip-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
ZIP code should contain only numbers
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="payment-option" onclick="selectPaymentOption('bank')">
|
<div class="payment-option" onclick="selectPaymentOption('bank')">
|
||||||
|
|
@ -286,15 +328,21 @@
|
||||||
<div id="bank-details" class="payment-details">
|
<div id="bank-details" class="payment-details">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="bank-name" class="input-field" placeholder=" " required>
|
<input type="text" id="bank-name" class="input-field" placeholder=" " oninput="validateBankName(this)" onkeypress="return preventInvalidBankNameChars(event)" required>
|
||||||
<label for="bank-name" class="input-label">Bank Name *</label>
|
<label for="bank-name" class="input-label">Bank Name *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="bank-name-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Bank name should contain letters and cannot be only numbers or special characters
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="account-number" class="input-field" placeholder=" " required>
|
<input type="text" id="account-number" class="input-field" placeholder=" " oninput="validateAccountNumber(this)" onkeypress="return preventInvalidAccountNumberChars(event)" required>
|
||||||
<label for="account-number" class="input-label">Account Number *</label>
|
<label for="account-number" class="input-label">Account Number *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="account-number-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Please enter a valid account number
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
|
|
@ -314,9 +362,12 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="account-holder-name" class="input-field" placeholder=" " required>
|
<input type="text" id="account-holder-name" class="input-field" placeholder=" " oninput="validateAccountHolderName(this)" onkeypress="return preventInvalidAccountHolderChars(event)" required>
|
||||||
<label for="account-holder-name" class="input-label">Account Holder Name *</label>
|
<label for="account-holder-name" class="input-label">Account Holder Name *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="account-holder-name-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Account holder name should only contain letters and spaces
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
|
|
|
||||||
|
|
@ -165,17 +165,20 @@
|
||||||
<!-- Step 1: Account Setup -->
|
<!-- Step 1: Account Setup -->
|
||||||
<div class="form-step active" id="step-1">
|
<div class="form-step active" id="step-1">
|
||||||
<h2 class="form-title">Account Setup</h2>
|
<h2 class="form-title">Account Setup</h2>
|
||||||
|
<div class="step-error-container" id="step-1-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-1-error-message"></div>
|
||||||
|
</div>
|
||||||
<form id="account-form">
|
<form id="account-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="email" id="email" class="input-field" placeholder=" " required>
|
<input type="email" id="email" class="input-field" placeholder=" " required autocomplete="off">
|
||||||
<label for="email" class="input-label">Email Address *</label>
|
<label for="email" class="input-label">Email Address *</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="password" id="password" class="input-field" placeholder=" " required>
|
<input type="password" id="password" class="input-field" placeholder=" " required autocomplete="off">
|
||||||
<label for="password" class="input-label">Create Password *</label>
|
<label for="password" class="input-label">Create Password *</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="password-actions">
|
<div class="password-actions">
|
||||||
|
|
@ -186,7 +189,7 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="password" id="confirmPassword" class="input-field" placeholder=" " required>
|
<input type="password" id="confirmPassword" class="input-field" placeholder=" " required autocomplete="off">
|
||||||
<label for="confirmPassword" class="input-label">Confirm Password *</label>
|
<label for="confirmPassword" class="input-label">Confirm Password *</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="invalid-feedback" id="password-match-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">Passwords do not match</div>
|
<div class="invalid-feedback" id="password-match-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">Passwords do not match</div>
|
||||||
|
|
@ -194,7 +197,7 @@
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<div></div>
|
<div></div>
|
||||||
<button type="button" class="btn btn-primary" onclick="nextStep(2)">Continue</button>
|
<button type="button" class="btn btn-primary" onclick="handleNextStep(2)">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -202,7 +205,9 @@
|
||||||
<!-- Step 2: Personal Information -->
|
<!-- Step 2: Personal Information -->
|
||||||
<div class="form-step" id="step-2">
|
<div class="form-step" id="step-2">
|
||||||
<h2 class="form-title">Personal Information</h2>
|
<h2 class="form-title">Personal Information</h2>
|
||||||
|
<div class="step-error-container" id="step-2-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-2-error-message"></div>
|
||||||
|
</div>
|
||||||
<div class="profile-incomplete" id="profile-incomplete" style="display: none;">
|
<div class="profile-incomplete" id="profile-incomplete" style="display: none;">
|
||||||
Profile is not yet complete, first name is missing
|
Profile is not yet complete, first name is missing
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -232,7 +237,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="date" id="dob" class="input-field" placeholder=" ">
|
<input type="date" id="dob" class="input-field dob" placeholder=" " onchange="handleDOBChange()">
|
||||||
<label for="dob" class="input-label">Date of Birth</label>
|
<label for="dob" class="input-label">Date of Birth</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -274,7 +279,7 @@
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="button" class="btn btn-secondary" onclick="prevStep(1)">Back</button>
|
<button type="button" class="btn btn-secondary" onclick="prevStep(1)">Back</button>
|
||||||
<button type="button" class="btn btn-primary" onclick="nextStep(3)">Continue</button>
|
<button type="button" class="btn btn-primary" onclick="handleNextStep(3)">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -282,13 +287,19 @@
|
||||||
<!-- Step 3: Contact Information -->
|
<!-- Step 3: Contact Information -->
|
||||||
<div class="form-step" id="step-3">
|
<div class="form-step" id="step-3">
|
||||||
<h2 class="form-title">Contact Information</h2>
|
<h2 class="form-title">Contact Information</h2>
|
||||||
|
<div class="step-error-container" id="step-3-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-3-error-message"></div>
|
||||||
|
</div>
|
||||||
<form id="contact-form">
|
<form id="contact-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="phone" class="input-label">Phone Number *</label>
|
<label for="phone" class="input-label">Phone Number *</label>
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="tel" id="phone" class="input-field" placeholder=" " required>
|
<input type="tel" id="phone" class="input-field" placeholder=" " pattern="[0-9]*" minlength="10" maxlength="15" oninput="validatePhoneNumber(this)" required>
|
||||||
<label for="phone" class="input-label">+ Phone Number</label>
|
<label for="phone" class="input-label">+ Phone Number</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="phone-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Please enter a valid phone number (10-15 digits)
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
@ -300,7 +311,7 @@
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="button" class="btn btn-secondary" onclick="prevStep(2)">Back</button>
|
<button type="button" class="btn btn-secondary" onclick="prevStep(2)">Back</button>
|
||||||
<button type="button" class="btn btn-primary" onclick="nextStep(4)">Continue</button>
|
<button type="button" class="btn btn-primary" onclick="handleNextStep(4)">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -308,6 +319,9 @@
|
||||||
<!-- Step 4: Payment Details -->
|
<!-- Step 4: Payment Details -->
|
||||||
<div class="form-step" id="step-4">
|
<div class="form-step" id="step-4">
|
||||||
<h2 class="form-title">Payment Details</h2>
|
<h2 class="form-title">Payment Details</h2>
|
||||||
|
<div class="step-error-container" id="step-4-error" style="display: none;">
|
||||||
|
<div class="error-message" id="step-4-error-message"></div>
|
||||||
|
</div>
|
||||||
<form id="payment-form">
|
<form id="payment-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="payment-option" onclick="selectPaymentMethod('payoneer')">
|
<div class="payment-option" onclick="selectPaymentMethod('payoneer')">
|
||||||
|
|
@ -317,9 +331,12 @@
|
||||||
<div id="payoneer-details" class="payment-details">
|
<div id="payoneer-details" class="payment-details">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="payoneerAccount" class="input-field" placeholder=" " required>
|
<input type="text" id="payoneerAccount" class="input-field" placeholder=" " minlength="5" maxlength="20" oninput="validatePayoneerAccount(this)" required>
|
||||||
<label for="payoneerAccount" class="input-label">Payoneer Account Number *</label>
|
<label for="payoneerAccount" class="input-label">Payoneer Account Number *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="payoneer-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Account number must be 5-20 characters
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -330,9 +347,12 @@
|
||||||
<div id="veem-details" class="payment-details">
|
<div id="veem-details" class="payment-details">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input type="text" id="veemAccount" class="input-field" placeholder=" " required>
|
<input type="text" id="veemAccount" class="input-field" placeholder=" " minlength="8" maxlength="25" oninput="validateVeemAccount(this)" required>
|
||||||
<label for="veemAccount" class="input-label">Veem Account Number *</label>
|
<label for="veemAccount" class="input-label">Veem Account Number *</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="invalid-feedback" id="veem-error" style="display: none; color: #dc3545; font-size: 12px; margin-top: 5px;">
|
||||||
|
Account number must be 8-25 characters
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue