updated contact form logic

This commit is contained in:
becarta
2025-03-04 00:59:40 +01:00
parent e9d3d8a2fb
commit 85a819ed15
8 changed files with 553 additions and 29 deletions

View File

@@ -465,12 +465,22 @@ import { UI } from 'astrowind:config';
// Fetch CSRF token from the server
async function fetchCsrfToken() {
console.log('Fetching CSRF token');
try {
const response = await fetch('/api/contact?csrf=true');
console.log('CSRF response status:', response.status);
if (!response.ok) {
console.error('CSRF request failed:', response.statusText);
return '';
}
const data = await response.json();
console.log('CSRF token received:', data.csrfToken ? 'yes' : 'no');
return data.csrfToken;
} catch (error) {
console.error('Error fetching CSRF token:', error);
console.error('Error details:', error.message);
return '';
}
}
@@ -489,15 +499,19 @@ import { UI } from 'astrowind:config';
// Form validation and submission
contactForm.addEventListener('submit', async function(e) {
e.preventDefault();
console.log('Form submitted');
// Reset previous error messages
resetFormErrors();
// Client-side validation
if (!validateForm(contactForm)) {
console.log('Form validation failed');
return;
}
console.log('Form validation passed');
// Show loading state
const submitButton = contactForm.querySelector('button[type="submit"]');
const originalButtonText = submitButton.innerHTML;
@@ -507,9 +521,16 @@ import { UI } from 'astrowind:config';
try {
const formData = new FormData(contactForm);
// Log form data
console.log('Form data:');
for (const [key, value] of formData.entries()) {
console.log(`${key}: ${value}`);
}
// Add timestamp to help prevent duplicate submissions
formData.append('timestamp', Date.now().toString());
console.log('Sending form data to /api/contact');
const response = await fetch('/api/contact', {
method: 'POST',
body: formData,
@@ -518,23 +539,40 @@ import { UI } from 'astrowind:config';
}
});
console.log('Response status:', response.status);
const result = await response.json();
console.log('Response data:', result);
if (result.success) {
console.log('Form submission successful');
// Show success message
document.getElementById('form-success').classList.remove('hidden');
contactForm.reset();
// Get a new CSRF token for next submission
console.log('Getting new CSRF token');
const newToken = await fetchCsrfToken();
console.log('New CSRF token:', newToken ? 'received' : 'not received');
if (csrfTokenInput) {
csrfTokenInput.value = newToken;
}
} else {
// Show error messages
document.getElementById('form-error').classList.remove('hidden');
console.log('Form submission failed:', result);
// Show specific error messages instead of generic form error
if (result.errors) {
console.log('Form errors:', result.errors);
// Only show the generic error if there are no field-specific errors
// or if there's a server error not related to a specific field
const hasFieldErrors = Object.keys(result.errors).some(field =>
['name', 'email', 'message', 'disclaimer', 'csrf'].includes(field)
);
if (!hasFieldErrors) {
document.getElementById('form-error').classList.remove('hidden');
}
// Display field-specific errors
Object.keys(result.errors).forEach(field => {
const inputElement = contactForm.querySelector(`[name="${field}"]`);
if (inputElement) {
@@ -543,13 +581,25 @@ import { UI } from 'astrowind:config';
feedbackElement.textContent = result.errors[field];
feedbackElement.classList.remove('hidden');
inputElement.classList.add('border-red-500');
// Special handling for checkbox
if (field === 'disclaimer') {
const checkboxContainer = inputElement.closest('.flex.items-start');
if (checkboxContainer) {
checkboxContainer.classList.add('checkbox-error');
}
}
}
}
});
} else {
// If no specific errors, show the generic error
document.getElementById('form-error').classList.remove('hidden');
}
// If CSRF token is invalid, get a new one
if (result.errors && result.errors.csrf) {
console.log('CSRF token invalid, getting new token');
const newToken = await fetchCsrfToken();
if (csrfTokenInput) {
csrfTokenInput.value = newToken;
@@ -558,6 +608,7 @@ import { UI } from 'astrowind:config';
}
} catch (error) {
console.error('Error submitting form:', error);
console.error('Error details:', error.message);
document.getElementById('form-error').classList.remove('hidden');
} finally {
// Restore button state
@@ -608,6 +659,30 @@ import { UI } from 'astrowind:config';
}
input.classList.remove('border-red-500');
// Checkbox validation (special case for disclaimer)
if (input.type === 'checkbox') {
if (input.required && !input.checked) {
isValid = false;
if (feedbackElement) {
feedbackElement.textContent = 'Please check the required consent box before submitting';
feedbackElement.classList.remove('hidden');
}
input.classList.add('border-red-500');
// Add red border to the checkbox container for better visibility
const checkboxContainer = input.closest('.flex.items-start');
if (checkboxContainer) {
checkboxContainer.classList.add('checkbox-error');
}
} else {
// Remove error styling when checkbox is checked
const checkboxContainer = input.closest('.flex.items-start');
if (checkboxContainer) {
checkboxContainer.classList.remove('checkbox-error');
}
}
return isValid;
}
// Check if empty
if (input.required && !input.value.trim()) {
isValid = false;
@@ -655,6 +730,11 @@ import { UI } from 'astrowind:config';
input.classList.remove('border-red-500');
});
// Remove checkbox container error styling
document.querySelectorAll('.flex.items-start').forEach(container => {
container.classList.remove('checkbox-error');
});
// Hide form-level messages
document.getElementById('form-success')?.classList.add('hidden');
document.getElementById('form-error')?.classList.add('hidden');

View File

@@ -5,6 +5,16 @@ import Button from '~/components/ui/Button.astro';
const { inputs, textarea, disclaimer, button = 'Contact us', description = '' } = Astro.props;
---
<style>
/* Checkbox error styling */
.checkbox-error {
border: 2px solid #ef4444;
border-radius: 0.5rem;
padding: 0.5rem;
background-color: rgba(239, 68, 68, 0.05);
}
</style>
<form id="contact-form" action="/api/contact" method="POST" class="needs-validation" novalidate>
<!-- Form status messages -->
@@ -13,7 +23,7 @@ const { inputs, textarea, disclaimer, button = 'Contact us', description = '' }
</div>
<div id="form-error" class="hidden mb-6 p-4 bg-red-100 border border-red-200 text-red-700 rounded-lg">
There was an error sending your message. Please try again.
There was an error sending your message. Please check all fields and try again.
</div>
<!-- CSRF Token - Will be populated via JavaScript -->