From 24dbadf5d621688fb99419fcb6614b5782f10875 Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 12:06:43 +0100 Subject: [PATCH] auto-claude: subtask-3-1 - Update ContactForm to call API route instead of simulating Changes: - Replaced simulated API call with real fetch() to /api/contact - Added errorMessage state for custom error messages - Implemented proper response handling for different status codes: * 200: Success message and form reset * 429: Rate limit error with time until retry * 400/500: Display API error messages - Enhanced rate limit error display with human-readable time formatting - Added VERIFICATION_STEPS.md for manual testing guidance Co-Authored-By: Claude Sonnet 4.5 --- VERIFICATION_STEPS.md | 55 ++++++++++++++++++++++++++ src/components/contact/ContactForm.tsx | 45 ++++++++++++++++++--- 2 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 VERIFICATION_STEPS.md diff --git a/VERIFICATION_STEPS.md b/VERIFICATION_STEPS.md new file mode 100644 index 0000000..e06b02b --- /dev/null +++ b/VERIFICATION_STEPS.md @@ -0,0 +1,55 @@ +# Verification Steps for ContactForm API Integration + +## Manual Verification Required + +The ContactForm has been updated to call the real API route at `/api/contact` instead of simulating the submission. + +### Test in Browser + +1. **Navigate to**: http://localhost:3000/en/contact + +2. **Test Successful Submission**: + - Fill in all form fields (name, email, message) + - Click "Send Message" + - Verify: Success message appears + - Verify: Form fields are cleared + - Verify: No console errors + +3. **Test Rate Limiting**: + - Submit the form 5 times rapidly + - On the 6th submission, verify: + - Error message appears with rate limit warning + - Message shows time until retry (e.g., "Too many requests. Please try again in 60 minutes.") + - Form is still functional (not broken) + +4. **Test Validation**: + - Try submitting with empty fields + - Verify validation errors appear + - Try submitting with invalid email + - Verify email validation error appears + +5. **Test Error Display**: + - Verify error messages are clearly visible + - Verify error messages disappear on successful submission + - Check that UI remains user-friendly + +### Expected Behavior + +- ✅ Form submits to `/api/contact` with POST request +- ✅ Success message displays on 200 response +- ✅ Rate limit error displays on 429 response with countdown +- ✅ Generic error message displays on other errors +- ✅ Form validation works before API call +- ✅ Loading state shows during submission +- ✅ Form is disabled during submission + +### Changes Made + +1. Added `errorMessage` state to store custom error messages +2. Replaced simulated API call with real `fetch()` to `/api/contact` +3. Added response status handling: + - 200 (OK): Success message, clear form + - 429 (Rate Limited): Display time until retry + - 400/500: Display API error message +4. Improved error message display with custom messages + diff --git a/src/components/contact/ContactForm.tsx b/src/components/contact/ContactForm.tsx index 15bbb4e..cd87b6c 100644 --- a/src/components/contact/ContactForm.tsx +++ b/src/components/contact/ContactForm.tsx @@ -17,6 +17,7 @@ export function ContactForm() { const [isSubmitting, setIsSubmitting] = useState(false); const [submitStatus, setSubmitStatus] = useState<'idle' | 'success' | 'error'>('idle'); + const [errorMessage, setErrorMessage] = useState(''); const [formData, setFormData] = useState({ name: '', email: '', @@ -62,14 +63,48 @@ export function ContactForm() { setIsSubmitting(true); setSubmitStatus('idle'); + setErrorMessage(''); try { - // Simulate API call - await new Promise(resolve => setTimeout(resolve, 1500)); - setSubmitStatus('success'); - setFormData({ name: '', email: '', message: '' }); + const response = await fetch('/api/contact', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(formData), + }); + + const data = await response.json(); + + if (response.ok) { + setSubmitStatus('success'); + setFormData({ name: '', email: '', message: '' }); + } else if (response.status === 429) { + // Rate limit exceeded + setSubmitStatus('error'); + const retryAfter = data.retryAfter || 0; + const minutes = Math.ceil(retryAfter / 60); + const hours = Math.floor(minutes / 60); + const remainingMinutes = minutes % 60; + + let timeMessage = ''; + if (hours > 0) { + timeMessage = `${hours} hour${hours > 1 ? 's' : ''}${remainingMinutes > 0 ? ` and ${remainingMinutes} minute${remainingMinutes > 1 ? 's' : ''}` : ''}`; + } else { + timeMessage = `${minutes} minute${minutes > 1 ? 's' : ''}`; + } + + setErrorMessage( + `Too many requests. Please try again in ${timeMessage}.` + ); + } else { + // Other errors (400, 500, etc.) + setSubmitStatus('error'); + setErrorMessage(data.error || t('contactForm.errorMessage')); + } } catch { setSubmitStatus('error'); + setErrorMessage(t('contactForm.errorMessage')); } finally { setIsSubmitting(false); } @@ -299,7 +334,7 @@ export function ContactForm() { className="p-3 bg-red-900/20 border border-red-900/50 rounded-lg" >

- {t('contactForm.errorMessage')} + {errorMessage || t('contactForm.errorMessage')}

)}