205 lines
6.2 KiB
JavaScript
205 lines
6.2 KiB
JavaScript
// ═══════════════════════════════════════════════
|
|
// A2P Compliance Wizard - Form Handler
|
|
// ═══════════════════════════════════════════════
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const form = document.getElementById('wizardForm');
|
|
const submitBtn = document.getElementById('submitBtn');
|
|
const overlay = document.getElementById('loadingOverlay');
|
|
const errorBanner = document.getElementById('errorBanner');
|
|
const logoInput = document.getElementById('logoInput');
|
|
const logoUpload = document.querySelector('.logo-upload');
|
|
const logoPreview = document.getElementById('logoPreview');
|
|
const logoUploadText = document.querySelector('.logo-upload-text');
|
|
|
|
// Logo upload preview
|
|
logoUpload.addEventListener('click', () => logoInput.click());
|
|
logoUpload.addEventListener('dragover', (e) => {
|
|
e.preventDefault();
|
|
logoUpload.style.borderColor = '#2563EB';
|
|
logoUpload.style.background = '#EFF6FF';
|
|
});
|
|
logoUpload.addEventListener('dragleave', () => {
|
|
logoUpload.style.borderColor = '';
|
|
logoUpload.style.background = '';
|
|
});
|
|
logoUpload.addEventListener('drop', (e) => {
|
|
e.preventDefault();
|
|
logoUpload.style.borderColor = '';
|
|
logoUpload.style.background = '';
|
|
if (e.dataTransfer.files.length) {
|
|
logoInput.files = e.dataTransfer.files;
|
|
handleLogoSelect();
|
|
}
|
|
});
|
|
|
|
logoInput.addEventListener('change', handleLogoSelect);
|
|
|
|
function handleLogoSelect() {
|
|
const file = logoInput.files[0];
|
|
if (!file) return;
|
|
|
|
if (!file.type.startsWith('image/')) {
|
|
showError('Please upload an image file (PNG, JPG, SVG, WebP)');
|
|
return;
|
|
}
|
|
|
|
if (file.size > 5 * 1024 * 1024) {
|
|
showError('Logo must be under 5MB');
|
|
return;
|
|
}
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
logoPreview.src = e.target.result;
|
|
logoPreview.style.display = 'block';
|
|
logoUpload.classList.add('has-file');
|
|
logoUploadText.textContent = file.name;
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
|
|
// Form submission
|
|
form.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
hideError();
|
|
|
|
// Validate
|
|
if (!validateForm()) return;
|
|
|
|
// Show loading
|
|
overlay.classList.add('active');
|
|
submitBtn.disabled = true;
|
|
updateProgress(0, 'Preparing your request...');
|
|
|
|
try {
|
|
const formData = new FormData(form);
|
|
|
|
// Simulate progress during generation
|
|
const progressInterval = simulateProgress();
|
|
|
|
const response = await fetch('/api/generate', {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
|
|
clearInterval(progressInterval);
|
|
|
|
const result = await response.json();
|
|
|
|
if (!result.success) {
|
|
throw new Error(result.error || 'Generation failed');
|
|
}
|
|
|
|
// Show completion
|
|
updateProgress(100, 'Complete!');
|
|
setStepDone(0);
|
|
setStepDone(1);
|
|
setStepDone(2);
|
|
setStepDone(3);
|
|
|
|
// Redirect to results
|
|
setTimeout(() => {
|
|
window.location.href = result.resultsUrl;
|
|
}, 800);
|
|
|
|
} catch (err) {
|
|
overlay.classList.remove('active');
|
|
submitBtn.disabled = false;
|
|
showError(err.message || 'Something went wrong. Please try again.');
|
|
}
|
|
});
|
|
|
|
function validateForm() {
|
|
const required = ['agencyName', 'agencyEmail', 'businessName', 'businessAddress', 'businessEmail', 'businessPhone', 'businessDescription'];
|
|
|
|
for (const field of required) {
|
|
const input = form.querySelector(`[name="${field}"]`);
|
|
if (!input || !input.value.trim()) {
|
|
showError(`Please fill in all required fields`);
|
|
input?.focus();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Validate email
|
|
const email = form.querySelector('[name="agencyEmail"]').value;
|
|
if (!email.includes('@') || !email.includes('.')) {
|
|
showError('Please enter a valid email address');
|
|
return false;
|
|
}
|
|
|
|
// Validate checkbox
|
|
const checkbox = form.querySelector('[name="tcpaConsent"]');
|
|
if (!checkbox || !checkbox.checked) {
|
|
showError('Please confirm TCPA compliance to continue');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function simulateProgress() {
|
|
let progress = 0;
|
|
const steps = [
|
|
{ at: 10, msg: 'Generating AI content...' },
|
|
{ at: 45, msg: 'Building website pages...' },
|
|
{ at: 65, msg: 'Taking screenshots...' },
|
|
{ at: 85, msg: 'Assembling compliance packet...' },
|
|
];
|
|
let stepIndex = 0;
|
|
|
|
return setInterval(() => {
|
|
if (progress < 90) {
|
|
progress += Math.random() * 3 + 0.5;
|
|
progress = Math.min(progress, 92);
|
|
updateProgress(progress);
|
|
|
|
if (stepIndex < steps.length && progress >= steps[stepIndex].at) {
|
|
setStepActive(stepIndex);
|
|
if (stepIndex > 0) setStepDone(stepIndex - 1);
|
|
document.querySelector('.loading-message').textContent = steps[stepIndex].msg;
|
|
stepIndex++;
|
|
}
|
|
}
|
|
}, 500);
|
|
}
|
|
|
|
function updateProgress(pct, msg) {
|
|
const fill = document.querySelector('.progress-fill');
|
|
if (fill) fill.style.width = `${pct}%`;
|
|
if (msg) {
|
|
const el = document.querySelector('.loading-message');
|
|
if (el) el.textContent = msg;
|
|
}
|
|
}
|
|
|
|
function setStepActive(index) {
|
|
const steps = document.querySelectorAll('.progress-step');
|
|
if (steps[index]) {
|
|
steps[index].classList.remove('done');
|
|
steps[index].classList.add('active');
|
|
}
|
|
}
|
|
|
|
function setStepDone(index) {
|
|
const steps = document.querySelectorAll('.progress-step');
|
|
if (steps[index]) {
|
|
steps[index].classList.remove('active');
|
|
steps[index].classList.add('done');
|
|
const icon = steps[index].querySelector('.progress-step-icon');
|
|
if (icon) icon.innerHTML = '<svg width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg>';
|
|
}
|
|
}
|
|
|
|
function showError(msg) {
|
|
errorBanner.textContent = msg;
|
|
errorBanner.classList.add('visible');
|
|
errorBanner.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
}
|
|
|
|
function hideError() {
|
|
errorBanner.classList.remove('visible');
|
|
}
|
|
});
|