Реалізація контактної форми
Контактна форма — базовий елемент зв'язку з користувачами. Мінімальний набір: поля (імʼя, email, повідомлення), захист від спаму, підтвердження відправки, email-сповіщення одержувачу.
Laravel: обробка форми
class ContactController extends Controller
{
public function store(ContactRequest $request): RedirectResponse|JsonResponse
{
// Зберегти звернення в БД
$inquiry = ContactInquiry::create([
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone,
'subject' => $request->subject,
'message' => $request->message,
'ip' => $request->ip(),
'user_agent' => $request->userAgent(),
]);
// Відправити сповіщення менеджерам
Mail::to(config('mail.contact_recipients'))
->send(new ContactInquiryMail($inquiry));
// Автоответ відправнику
Mail::to($inquiry->email)
->send(new ContactAutoReplyMail($inquiry));
if ($request->expectsJson()) {
return response()->json(['message' => 'Ваше повідомлення відправлено']);
}
return back()->with('success', 'Дякуємо! Ми зв\'яжемося з вами протягом 24 годин.');
}
}
// app/Http/Requests/ContactRequest.php
class ContactRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:100',
'email' => 'required|email:rfc,dns|max:255',
'phone' => 'nullable|string|max:20',
'subject' => 'nullable|string|max:200',
'message' => 'required|string|min:10|max:5000',
];
}
public function messages(): array
{
return [
'name.required' => 'Введіть ваше імʼя',
'email.required' => 'Введіть email',
'email.email' => 'Некоректний формат email',
'message.required' => 'Напишіть повідомлення',
'message.min' => 'Повідомлення занадто коротке (мінімум 10 символів)',
];
}
}
Rate limiting та захист від спаму
// routes/web.php
Route::post('/contact', [ContactController::class, 'store'])
->middleware(['throttle:5,60']); // 5 відправок на годину з одної IP
// У ContactRequest
public function withValidator(Validator $validator): void
{
$validator->after(function (Validator $v) {
// Honeypot поле: боти заповняють приховані поля
if ($this->input('website')) { // приховане поле, люди не заповнюють
$v->errors()->add('spam', 'Виявлено спам');
}
});
}
React: форма з валідацією
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(2, 'Введіть імʼя').max(100),
email: z.string().email('Некоректний email'),
message: z.string().min(10, 'Мінімум 10 символів').max(5000),
website: z.string().max(0), // honeypot
});
type FormData = z.infer<typeof schema>;
export function ContactForm() {
const { register, handleSubmit, formState: { errors, isSubmitting }, reset } = useForm<FormData>({
resolver: zodResolver(schema),
});
const [success, setSuccess] = useState(false);
const onSubmit = async (data: FormData) => {
await api.post('/contact', data);
setSuccess(true);
reset();
};
if (success) {
return <p role="status">Дякуємо! Ми зв\'яжемося з вами протягом 24 годин.</p>;
}
return (
<form onSubmit={handleSubmit(onSubmit)} noValidate>
{/* Honeypot */}
<div style={{ display: 'none' }} aria-hidden>
<input {...register('website')} tabIndex={-1} autoComplete="off" />
</div>
<div>
<label htmlFor="name">Імʼя *</label>
<input id="name" {...register('name')} aria-describedby={errors.name ? 'name-error' : undefined} />
{errors.name && <p id="name-error" role="alert">{errors.name.message}</p>}
</div>
<div>
<label htmlFor="email">Email *</label>
<input id="email" type="email" {...register('email')} />
{errors.email && <p role="alert">{errors.email.message}</p>}
</div>
<div>
<label htmlFor="message">Повідомлення *</label>
<textarea id="message" rows={5} {...register('message')} />
{errors.message && <p role="alert">{errors.message.message}</p>}
</div>
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Відправка...' : 'Відправити'}
</button>
</form>
);
}
Строк реалізації
Контактна форма з валідацією, honeypot, email-сповіщенням та автоответом для Laravel + React: 1–2 дні. З збереженням у БД та панеллю управління зверненнями: 2–3 дні.







