181 lines
6.7 KiB
JavaScript
181 lines
6.7 KiB
JavaScript
(function () {
|
||
const form = document.getElementById('contactForm');
|
||
if (!form) return;
|
||
|
||
const dropzone = document.getElementById('dropzone');
|
||
const photoInput = document.getElementById('photoInput');
|
||
const photoPreview = document.getElementById('photoPreview');
|
||
const photoError = document.getElementById('photoError');
|
||
const formAlert = document.getElementById('formAlert');
|
||
const submitBtn = document.getElementById('submitBtn');
|
||
const textarea = form.querySelector('textarea[name="message"]');
|
||
const phoneInput = form.querySelector('input[name="phone"]');
|
||
let selectedFiles = [];
|
||
|
||
// Textarea auto-resize
|
||
textarea.style.overflow = 'hidden';
|
||
textarea.addEventListener('input', function () {
|
||
this.style.height = 'auto';
|
||
this.style.height = this.scrollHeight + 'px';
|
||
});
|
||
|
||
// Phone auto-format
|
||
phoneInput.addEventListener('input', function () {
|
||
const digits = this.value.replace(/\D/g, '').slice(0, 10);
|
||
if (digits.length >= 7) this.value = '(' + digits.slice(0,3) + ') ' + digits.slice(3,6) + '-' + digits.slice(6);
|
||
else if (digits.length >= 4) this.value = '(' + digits.slice(0,3) + ') ' + digits.slice(3);
|
||
else this.value = digits;
|
||
});
|
||
|
||
// Clear inline errors on input
|
||
form.querySelectorAll('.input, .textarea').forEach(el => {
|
||
el.addEventListener('input', () => clearErr(el));
|
||
});
|
||
|
||
function setErr(input, msg) {
|
||
input.classList.add('is-danger');
|
||
const el = document.getElementById('err-' + input.name);
|
||
if (el) { el.textContent = msg; el.style.display = ''; }
|
||
}
|
||
|
||
function clearErr(input) {
|
||
input.classList.remove('is-danger');
|
||
const el = document.getElementById('err-' + input.name);
|
||
if (el) el.style.display = 'none';
|
||
}
|
||
|
||
function validate() {
|
||
let ok = true;
|
||
|
||
const firstName = form.querySelector('[name="firstName"]');
|
||
if (!firstName.value.trim()) { setErr(firstName, 'Please enter your first name.'); ok = false; }
|
||
else clearErr(firstName);
|
||
|
||
const lastName = form.querySelector('[name="lastName"]');
|
||
if (!lastName.value.trim()) { setErr(lastName, 'Please enter your last name.'); ok = false; }
|
||
else clearErr(lastName);
|
||
|
||
const email = form.querySelector('[name="email"]');
|
||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value.trim())) {
|
||
setErr(email, 'Please enter a valid email address.'); ok = false;
|
||
} else clearErr(email);
|
||
|
||
const phone = form.querySelector('[name="phone"]');
|
||
if (phone.value.replace(/\D/g, '').length < 10) {
|
||
setErr(phone, 'Please enter a valid 10-digit phone number.'); ok = false;
|
||
} else clearErr(phone);
|
||
|
||
const msg = form.querySelector('[name="message"]');
|
||
if (!msg.value.trim()) { setErr(msg, 'Please enter a message.'); ok = false; }
|
||
else clearErr(msg);
|
||
|
||
return ok;
|
||
}
|
||
|
||
// Dropzone
|
||
dropzone.addEventListener('click', () => photoInput.click());
|
||
dropzone.addEventListener('dragover', e => { e.preventDefault(); dropzone.classList.add('drag-over'); });
|
||
dropzone.addEventListener('dragleave', () => dropzone.classList.remove('drag-over'));
|
||
dropzone.addEventListener('drop', e => {
|
||
e.preventDefault();
|
||
dropzone.classList.remove('drag-over');
|
||
addFiles(Array.from(e.dataTransfer.files));
|
||
});
|
||
photoInput.addEventListener('change', () => {
|
||
addFiles(Array.from(photoInput.files));
|
||
photoInput.value = '';
|
||
});
|
||
|
||
function addFiles(newFiles) {
|
||
const images = newFiles.filter(f => f.type.startsWith('image/'));
|
||
const tooBig = images.filter(f => f.size > 10 * 1024 * 1024);
|
||
if (tooBig.length) showAlert('One or more photos exceed 10 MB and were skipped.', 'is-warning');
|
||
const ok = images.filter(f => f.size <= 10 * 1024 * 1024);
|
||
const combined = [...selectedFiles, ...ok];
|
||
photoError.style.display = combined.length > 3 ? '' : 'none';
|
||
selectedFiles = combined.slice(0, 3);
|
||
renderPreviews();
|
||
}
|
||
|
||
function renderPreviews() {
|
||
photoPreview.innerHTML = '';
|
||
selectedFiles.forEach((file, i) => {
|
||
const url = URL.createObjectURL(file);
|
||
const wrap = document.createElement('div');
|
||
wrap.className = 'preview-wrap';
|
||
const img = document.createElement('img');
|
||
img.src = url;
|
||
const btn = document.createElement('button');
|
||
btn.type = 'button';
|
||
btn.className = 'remove-btn';
|
||
btn.innerHTML = '×';
|
||
btn.addEventListener('click', () => {
|
||
URL.revokeObjectURL(url);
|
||
selectedFiles.splice(i, 1);
|
||
photoError.style.display = 'none';
|
||
renderPreviews();
|
||
});
|
||
wrap.appendChild(img);
|
||
wrap.appendChild(btn);
|
||
photoPreview.appendChild(wrap);
|
||
});
|
||
}
|
||
|
||
// Submit
|
||
form.addEventListener('submit', async e => {
|
||
e.preventDefault();
|
||
formAlert.style.display = 'none';
|
||
|
||
if (!validate()) {
|
||
showAlert('Please correct the errors below.', 'is-danger');
|
||
// Scroll to first error
|
||
const first = form.querySelector('.is-danger');
|
||
if (first) first.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||
return;
|
||
}
|
||
|
||
const fd = new FormData();
|
||
fd.append('firstName', form.querySelector('[name="firstName"]').value.trim());
|
||
fd.append('lastName', form.querySelector('[name="lastName"]').value.trim());
|
||
fd.append('email', form.querySelector('[name="email"]').value.trim());
|
||
fd.append('phone', form.querySelector('[name="phone"]').value.trim());
|
||
fd.append('message', form.querySelector('[name="message"]').value.trim());
|
||
const et = form.querySelector('[name="eventType"]');
|
||
if (et) fd.append('eventType', et.value);
|
||
const ed = form.querySelector('[name="eventDate"]');
|
||
if (ed) fd.append('eventDate', ed.value);
|
||
const hp = form.querySelector('[name="website"]');
|
||
if (hp) fd.append('website', hp.value);
|
||
selectedFiles.forEach(f => fd.append('photos', f));
|
||
|
||
submitBtn.classList.add('is-loading');
|
||
submitBtn.disabled = true;
|
||
|
||
try {
|
||
const res = await fetch('/api/contact', { method: 'POST', body: fd });
|
||
const data = await res.json();
|
||
if (data.success) {
|
||
showAlert("Message sent! We’ll get back to you soon. Check your email for a confirmation.", 'is-success');
|
||
form.reset();
|
||
selectedFiles = [];
|
||
renderPreviews();
|
||
textarea.style.height = 'auto';
|
||
} else {
|
||
showAlert(data.message || 'Something went wrong. Please try again.', 'is-danger');
|
||
}
|
||
} catch {
|
||
showAlert('Network error. Please try again or email us directly.', 'is-danger');
|
||
} finally {
|
||
submitBtn.classList.remove('is-loading');
|
||
submitBtn.disabled = false;
|
||
}
|
||
});
|
||
|
||
function showAlert(msg, cls) {
|
||
formAlert.className = 'notification ' + cls;
|
||
formAlert.textContent = msg;
|
||
formAlert.style.display = '';
|
||
formAlert.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||
}
|
||
})();
|