From 931c9a9095fcb21fd5791d064ea3c851ef649df2 Mon Sep 17 00:00:00 2001 From: null Date: Wed, 13 May 2026 18:10:04 -0500 Subject: [PATCH] feat: client-side form validation + Sonner feedback (v0.4.4) --- package.json | 2 +- src/pages/Contact.jsx | 69 ++++++++++++++++++++++++++++++++++++++-- src/pages/Support.jsx | 74 +++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 140 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 32041d8..767a4df 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "queuenorth-website", "private": true, - "version": "0.4.3", + "version": "0.4.4", "type": "module", "scripts": { "dev": "concurrently \"vite\" \"node server/index.js\"", diff --git a/src/pages/Contact.jsx b/src/pages/Contact.jsx index 4dac0c5..4768983 100644 --- a/src/pages/Contact.jsx +++ b/src/pages/Contact.jsx @@ -18,6 +18,12 @@ const Contact = () => { message: '', service_interest: '', }) + const [errors, setErrors] = useState({ + company: '', + name: '', + email: '', + message: '', + }) const mutation = useMutation({ mutationFn: (data) => api.post('/leads', data), @@ -32,20 +38,63 @@ const Contact = () => { message: '', service_interest: '', }) + setErrors({ + company: '', + name: '', + email: '', + message: '', + }) }, onError: (error) => { toast.error(error.message || 'Failed to submit form. Please try again.') }, }) + const validateForm = () => { + const newErrors = { + company: '', + name: '', + email: '', + message: '', + } + + // Validate required fields + if (!formState.company.trim()) newErrors.company = 'Company name is required' + if (!formState.name.trim()) newErrors.name = 'Name is required' + if (!formState.message.trim()) newErrors.message = 'Message is required' + + // Validate email format + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ + if (!formState.email.trim()) { + newErrors.email = 'Email is required' + } else if (!emailRegex.test(formState.email)) { + newErrors.email = 'Please enter a valid email address' + } + + const hasErrors = Object.values(newErrors).some(error => error !== '') + setErrors(newErrors) + + if (hasErrors) { + toast.error('Please fix the errors in the form') + return false + } + + return true + } + const handleSubmit = (e) => { e.preventDefault() + if (!validateForm()) return mutation.mutate(formState) } const handleChange = (e) => { const { name, value } = e.target setFormState(prev => ({ ...prev, [name]: value })) + // Clear error for this field as user types + if (errors[name]) { + setErrors(prev => ({ ...prev, [name]: '' })) + } } return ( @@ -101,7 +150,7 @@ const Contact = () => { {/* Right - Form */}
-
+
@@ -129,7 +182,11 @@ const Contact = () => { onChange={handleChange} required placeholder="Your full name" + className={errors.name ? 'border-red-500 focus-visible:ring-red-500' : ''} /> + {errors.name && ( +

{errors.name}

+ )}
@@ -144,7 +201,11 @@ const Contact = () => { onChange={handleChange} required placeholder="your.email@example.com" + className={errors.email ? 'border-red-500 focus-visible:ring-red-500' : ''} /> + {errors.email && ( +

{errors.email}

+ )}
@@ -200,7 +261,7 @@ const Contact = () => { -