Stackless-Website/contact.js

107 lines
3.7 KiB
JavaScript
Raw Permalink Normal View History

2026-06-18 10:22:31 +00:00
// Stackless — contact form behaviour: step nav, validation, submit state
(function () {
var form = document.getElementById('contactForm');
if (!form) return;
var steps = Array.prototype.slice.call(form.querySelectorAll('.step'));
var dots = Array.prototype.slice.call(document.querySelectorAll('.progress .dot'));
var prevBtn = document.getElementById('prevBtn');
var nextBtn = document.getElementById('nextBtn');
var submitBtn = document.getElementById('submitBtn');
var successEl = document.getElementById('formSuccess');
var errBanner = document.getElementById('errBanner');
var current = 0;
function paint() {
steps.forEach(function (s, i) { s.classList.toggle('is-active', i === current); });
dots.forEach(function (d, i) {
d.classList.toggle('is-on', i === current);
d.classList.toggle('is-done', i < current);
});
prevBtn.disabled = current === 0;
if (current === steps.length - 1) {
nextBtn.style.display = 'none';
submitBtn.style.display = 'inline-flex';
} else {
nextBtn.style.display = 'inline-flex';
submitBtn.style.display = 'none';
}
}
function validateStep(idx) {
var step = steps[idx];
var fields = step.querySelectorAll('input[required], select[required], textarea[required]');
var ok = true;
fields.forEach(function (el) {
var bad = !el.checkValidity();
el.classList.toggle('is-invalid', bad);
el.parentElement.classList.toggle('is-invalid', bad);
if (bad) ok = false;
});
// Custom: at least one service checkbox picked if on step 1
if (idx === 0) {
var any = step.querySelectorAll('input[name="services"]:checked').length;
var servicesErr = document.getElementById('servicesErr');
if (any === 0) {
ok = false;
servicesErr.style.display = 'block';
} else {
servicesErr.style.display = 'none';
}
}
return ok;
}
function goto(i) {
if (i > current && !validateStep(current)) {
errBanner.style.display = 'flex';
return;
}
errBanner.style.display = 'none';
current = Math.max(0, Math.min(steps.length - 1, i));
paint();
// scroll the active step into view (only on mobile-ish where steps stack)
var active = steps[current];
if (active && window.innerWidth < 720) {
active.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
}
// live-clear invalid state as the user fixes it
form.addEventListener('input', function (e) {
var t = e.target;
if (t.classList && t.classList.contains('is-invalid') && t.checkValidity()) {
t.classList.remove('is-invalid');
if (t.parentElement) t.parentElement.classList.remove('is-invalid');
}
if (t.name === 'services') {
var any = form.querySelectorAll('input[name="services"]:checked').length;
var servicesErr = document.getElementById('servicesErr');
if (any > 0 && servicesErr) servicesErr.style.display = 'none';
}
});
prevBtn.addEventListener('click', function () { goto(current - 1); });
nextBtn.addEventListener('click', function () { goto(current + 1); });
// Submit (no real backend — show the success state, log the payload)
form.addEventListener('submit', function (e) {
e.preventDefault();
if (!validateStep(current)) { errBanner.style.display = 'flex'; return; }
var data = {};
new FormData(form).forEach(function (v, k) { data[k] = v; });
console.log('[Stackless] contact submission:', data);
submitBtn.disabled = true;
submitBtn.textContent = 'Sending…';
setTimeout(function () {
form.style.display = 'none';
successEl.style.display = 'block';
successEl.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, 700);
});
paint();
})();