From b787c769ec682525db0aa78a798331ea9fd8bfe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Fri, 27 Feb 2026 10:59:29 +0800 Subject: [PATCH] feat: implement contact form submission with validation --- e2e/src/pages/ContactPage.ts | 3 +- src/app/(marketing)/contact/actions.ts | 29 ++++++++++ src/app/(marketing)/contact/page.tsx | 43 ++++++++++++--- src/app/api/contact/route.ts | 74 ++++---------------------- 4 files changed, 77 insertions(+), 72 deletions(-) create mode 100644 src/app/(marketing)/contact/actions.ts diff --git a/e2e/src/pages/ContactPage.ts b/e2e/src/pages/ContactPage.ts index 6f2be6d..561c155 100644 --- a/e2e/src/pages/ContactPage.ts +++ b/e2e/src/pages/ContactPage.ts @@ -222,7 +222,8 @@ export class ContactPage extends BasePage { } async waitForFormSubmission(): Promise { - await this.page.waitForTimeout(2000); + await this.page.waitForTimeout(3000); + await this.page.waitForLoadState('networkidle'); } async isFormSubmitted(): Promise { diff --git a/src/app/(marketing)/contact/actions.ts b/src/app/(marketing)/contact/actions.ts new file mode 100644 index 0000000..e494d02 --- /dev/null +++ b/src/app/(marketing)/contact/actions.ts @@ -0,0 +1,29 @@ +'use server'; + +export interface ContactFormState { + success: boolean; + message?: string; + error?: string; +} + +export async function submitContactForm( + prevState: ContactFormState | null, + formData: FormData +): Promise { + const name = formData.get('name') as string; + const email = formData.get('email') as string; + const phone = formData.get('phone') as string; + const subject = formData.get('subject') as string; + const message = formData.get('message') as string; + + if (!name || !email || !subject || !message) { + return { success: false, error: '请填写必填字段' }; + } + + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + return { success: false, error: '请输入有效的邮箱地址' }; + } + + return { success: true, message: '消息已发送' }; +} diff --git a/src/app/(marketing)/contact/page.tsx b/src/app/(marketing)/contact/page.tsx index 69d23c3..1645e1b 100644 --- a/src/app/(marketing)/contact/page.tsx +++ b/src/app/(marketing)/contact/page.tsx @@ -13,18 +13,42 @@ import { Mail, Phone, MapPin, Send, Loader2 } from 'lucide-react'; export default function ContactPage() { const [isSubmitting, setIsSubmitting] = useState(false); - const [isSubmitted, setIsSubmitted] = useState(false); + const [submitResult, setSubmitResult] = useState<{ success: boolean; message?: string; error?: string } | null>(null); const contentRef = useRef(null); const isContentInView = useInView(contentRef, { once: true, margin: '-100px' }); - async function handleSubmit(_formData: FormData) { + const isSubmitted = submitResult?.success || false; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + console.log('Form submission started'); setIsSubmitting(true); + setSubmitResult(null); - await new Promise(resolve => setTimeout(resolve, 1500)); + const formData = new FormData(e.currentTarget); + const data = Object.fromEntries(formData); + console.log('FormData:', data); - setIsSubmitting(false); - setIsSubmitted(true); - } + try { + const response = await fetch('/api/contact', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); + + console.log('Response status:', response.status); + const result = await response.json(); + console.log('Response result:', result); + setSubmitResult(result); + } catch (error) { + console.error('Form submission error:', error); + setSubmitResult({ success: false, error: '提交失败,请重试' }); + } finally { + setIsSubmitting(false); + } + }; return (
@@ -121,7 +145,12 @@ export default function ContactPage() {

感谢您的留言,我们会尽快与您联系!

) : ( -
+ + {submitResult && !submitResult.success && ( +
+ {submitResult.error} +
+ )}