From c5c14d2fad9881c26bc192b34fe0ac8808a7be79 Mon Sep 17 00:00:00 2001 From: Jezza Hehn Date: Mon, 13 Apr 2026 18:41:41 +0000 Subject: [PATCH] Add functional contact form with API backend - Replaced placeholder form submission with real POST to /api/contact - Added honeypot field for spam protection - Success/error feedback states - Rate limiting handled by backend --- contact.html | 5 ++++ js/main.js | 65 ++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/contact.html b/contact.html index 2456f40..cb0cfda 100644 --- a/contact.html +++ b/contact.html @@ -42,6 +42,11 @@
+ +
diff --git a/js/main.js b/js/main.js index e64e85d..10893ec 100644 --- a/js/main.js +++ b/js/main.js @@ -39,13 +39,70 @@ document.getElementById('nav-toggle').addEventListener('click', function() { menu.classList.toggle('is-active'); }); -// Contact form (placeholder) +// Contact form - sends to backend API var form = document.getElementById('contact-form'); if (form) { form.addEventListener('submit', function(e) { e.preventDefault(); + var status = document.getElementById('form-status'); - status.style.display = 'block'; - form.querySelector('button[type="submit"]').disabled = true; + var submitBtn = form.querySelector('button[type="submit"]'); + var originalBtnText = submitBtn.textContent; + + // Collect form data + var formData = new FormData(form); + var data = { + name: formData.get('name'), + email: formData.get('email'), + service: formData.get('service'), + message: formData.get('message') + }; + + // Honeypot for spam + var honeypot = formData.get('website') || formData.get('url') || formData.get('honey'); + if (honeypot) { + // Bot detected - pretend success + status.className = 'notification is-success'; + status.textContent = 'Message received. We\'ll respond within 48 hours.'; + status.style.display = 'block'; + form.reset(); + return; + } + + // Disable button and show sending state + submitBtn.disabled = true; + submitBtn.textContent = 'Sending...'; + status.style.display = 'none'; + + // Send to API + fetch('/api/contact', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }) + .then(function(response) { + return response.json(); + }) + .then(function(result) { + if (result.success) { + status.className = 'notification is-success'; + status.textContent = result.message || 'Message received. We\'ll respond within 48 hours.'; + status.style.display = 'block'; + form.reset(); + } else { + throw new Error(result.error || 'Failed to send message'); + } + }) + .catch(function(error) { + status.className = 'notification is-danger'; + status.textContent = error.message || 'Failed to send message. Please try again.'; + status.style.display = 'block'; + }) + .finally(function() { + submitBtn.disabled = false; + submitBtn.textContent = originalBtnText; + }); }); -} +} \ No newline at end of file