auto-claude: subtask-1-4 - Create contact form server action with CSRF valida
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
'use server';
|
||||||
|
|
||||||
|
import { validateCsrfToken } from '@/lib/csrf/server';
|
||||||
|
|
||||||
|
interface ContactFormData {
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ContactFormResult {
|
||||||
|
success: boolean;
|
||||||
|
error?: string;
|
||||||
|
errors?: Partial<Record<keyof ContactFormData, string>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server action to handle contact form submissions
|
||||||
|
* Validates CSRF token and form data before processing
|
||||||
|
*/
|
||||||
|
export async function submitContactForm(
|
||||||
|
formData: FormData
|
||||||
|
): Promise<ContactFormResult> {
|
||||||
|
// Extract CSRF token from form data
|
||||||
|
const csrfToken = formData.get('csrfToken');
|
||||||
|
|
||||||
|
// Validate CSRF token
|
||||||
|
if (!csrfToken || typeof csrfToken !== 'string') {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'CSRF token is missing',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const isValidToken = await validateCsrfToken(csrfToken);
|
||||||
|
if (!isValidToken) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'Invalid CSRF token',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract and validate form fields
|
||||||
|
const name = formData.get('name')?.toString() || '';
|
||||||
|
const email = formData.get('email')?.toString() || '';
|
||||||
|
const message = formData.get('message')?.toString() || '';
|
||||||
|
|
||||||
|
// Validation
|
||||||
|
const errors: Partial<Record<keyof ContactFormData, string>> = {};
|
||||||
|
|
||||||
|
if (!name.trim()) {
|
||||||
|
errors.name = 'Name is required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!email.trim()) {
|
||||||
|
errors.email = 'Email is required';
|
||||||
|
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||||
|
errors.email = 'Invalid email format';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.trim()) {
|
||||||
|
errors.message = 'Message is required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(errors).length > 0) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
errors,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO: Implement actual email sending logic here
|
||||||
|
// For now, we'll simulate successful submission
|
||||||
|
// In production, this would integrate with an email service like:
|
||||||
|
// - Supabase Edge Functions
|
||||||
|
// - SendGrid
|
||||||
|
// - AWS SES
|
||||||
|
// - Resend
|
||||||
|
|
||||||
|
// Simulate processing delay
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500));
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error instanceof Error ? error.message : 'Failed to send message',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user