diff --git a/nevo_frontend/app/contact/page.tsx b/nevo_frontend/app/contact/page.tsx index d4b1830..731c7d7 100644 --- a/nevo_frontend/app/contact/page.tsx +++ b/nevo_frontend/app/contact/page.tsx @@ -2,6 +2,8 @@ import React, { useState } from 'react'; +const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + export default function ContactPage() { const [name, setName] = useState(''); const [email, setEmail] = useState(''); @@ -11,35 +13,62 @@ export default function ContactPage() { const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); + const [fieldErrors, setFieldErrors] = useState({ email: '', subject: '', message: '' }); - function validateEmail(e: string) { - return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e); + function validateEmail(value: string) { + return EMAIL_REGEX.test(value); } - async function handleSubmit(ev: React.FormEvent) { + function validateForm() { + const errors = { email: '', subject: '', message: '' }; + + if (!validateEmail(email)) { + errors.email = 'Please enter a valid email address.'; + } + + if (!subject || subject.trim().length < 3) { + errors.subject = 'Please enter a subject with at least 3 characters.'; + } + + if (!message || message.trim().length < 10) { + errors.message = 'Please enter a message with at least 10 characters.'; + } + + setFieldErrors(errors); + return !errors.email && !errors.subject && !errors.message; + } + + async function handleSubmit(ev: React.FormEvent) { ev.preventDefault(); setError(null); setSuccess(null); - if (!validateEmail(email)) return setError('Please enter a valid email address.'); - if (!subject || subject.trim().length < 3) return setError('Please enter a subject (3+ chars).'); - if (!message || message.trim().length < 10) return setError('Please enter a message (10+ chars).'); + if (!validateForm()) { + setError('Please fix the highlighted fields before sending.'); + return; + } setLoading(true); + try { const res = await fetch('/api/contact', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, email, subject, message, autoReply }), }); - const j = await res.json(); - if (!res.ok) throw new Error(j?.error || 'Submission failed'); + + const data = await res.json(); + if (!res.ok) { + throw new Error(data?.error || 'Submission failed'); + } + setSuccess('Thanks — your message was sent. We will respond shortly.'); setName(''); setEmail(''); setSubject(''); setMessage(''); setAutoReply(true); + setFieldErrors({ email: '', subject: '', message: '' }); } catch (err: any) { setError(err.message || 'Submission failed'); } finally { @@ -50,39 +79,116 @@ export default function ContactPage() { return (

Contact Support

-

Have a question, found an issue, or want to give feedback? Send us a message and we'll get back to you.

+

+ Have a question, found an issue, or want to give feedback? Send us a message and we'll get back to you. +

-
- {error &&
{error}
} - {success &&
{success}
} + +
+ {error &&

{error}

} + {success &&

{success}

} +
- - setName(e.target.value)} className="w-full rounded-xl border px-3 py-2 bg-[var(--color-surface)]" /> + + setName(e.target.value)} + className="w-full rounded-xl border px-3 py-2 bg-[var(--color-surface)]" + placeholder="Your name" + />
- - setEmail(e.target.value)} required className="w-full rounded-xl border px-3 py-2 bg-[var(--color-surface)]" type="email" /> + + setEmail(e.target.value)} + required + aria-invalid={!!fieldErrors.email} + aria-describedby="email-error" + className="w-full rounded-xl border px-3 py-2 bg-[var(--color-surface)]" + placeholder="you@example.com" + /> + {fieldErrors.email && ( +

+ {fieldErrors.email} +

+ )}
- - setSubject(e.target.value)} required className="w-full rounded-xl border px-3 py-2 bg-[var(--color-surface)]" /> + + setSubject(e.target.value)} + required + minLength={3} + aria-invalid={!!fieldErrors.subject} + aria-describedby="subject-error" + className="w-full rounded-xl border px-3 py-2 bg-[var(--color-surface)]" + placeholder="What can we help you with?" + /> + {fieldErrors.subject && ( +

+ {fieldErrors.subject} +

+ )}
- -