Files
klimat24/app/kontakt/actions.ts
T

138 lines
6.3 KiB
TypeScript

"use server";
import { z } from "zod";
import { escapeHtml, rateLimit, verifyRecaptcha } from "@/lib/security";
import { getMailClient } from "@/lib/mail";
import { headers } from "next/headers";
const contactFormSchema = z.object({
name: z.string().min(2, "Imię musi mieć min. 2 znaki"),
phone: z.string().min(9, "Wprowadź poprawny numer telefonu"),
email: z.union([z.literal(''), z.string().email("Niepoprawny adres e-mail")]).optional(),
city: z.string().min(1, "Wybierz miasto"),
subject: z.string().optional(),
message: z.string().optional(),
consent: z.boolean().refine((val) => val === true, "Zgoda RODO jest wymagana"),
});
export async function submitContactForm(prevState: unknown, formData: FormData) {
try {
const ip = (await headers()).get('x-forwarded-for') || 'unknown';
if (!rateLimit(ip)) {
return { success: false, message: 'Wysłano zbyt wiele zapytań. Spróbuj ponownie później.' };
}
if (process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY && process.env.RECAPTCHA_SECRET_KEY) {
const token = formData.get('recaptchaToken') as string;
if (!token) {
return { success: false, message: "Weryfikacja bezpieczeństwa nie powiodła się. Odśwież stronę i spróbuj ponownie." };
}
const success = await verifyRecaptcha(token);
if (!success) {
return { success: false, message: "Weryfikacja bezpieczeństwa nie powiodła się. Odśwież stronę i spróbuj ponownie." };
}
}
const rawData = {
name: formData.get("name"),
phone: formData.get("phone"),
email: formData.get("email"),
city: formData.get("city"),
subject: formData.get("subject"),
message: formData.get("message"),
consent: formData.get("consent") === "true" || formData.get("consent") === "on",
};
const validatedData = contactFormSchema.parse(rawData);
const mailClient = getMailClient();
if (!mailClient) {
return {
success: false,
message: "Funkcja wysyłania wiadomości jest tymczasowo niedostępna.",
};
}
// 2. Wysłanie e-maila przez Resend
const { data, error } = await mailClient.resend.emails.send({
from: process.env.RESEND_FROM_EMAIL || "[email protected]",
to: process.env.RESEND_TO_EMAIL || "[email protected]", // Docelowy e-mail (odbiorca)
replyTo: validatedData.email,
subject: `Nowa wiadomość ze strony: ${validatedData.subject}`,
html: `
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; background-color: #ffffff;">
<div style="background-color: #0F2A47; padding: 20px; text-align: center;">
<h1 style="color: #ffffff; margin: 0; font-size: 24px;">Nowe zapytanie z formularza</h1>
<p style="color: #2BA8E0; margin: 5px 0 0 0; font-size: 14px;">Domena: thermcool.pl</p>
</div>
<div style="padding: 24px; color: #1e293b;">
<h2 style="font-size: 18px; margin-top: 0; border-bottom: 2px solid #f1f5f9; padding-bottom: 10px;">Dane kontaktowe:</h2>
<table style="width: 100%; border-collapse: collapse; margin-bottom: 20px;">
<tr>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9; width: 120px;"><strong>Imię:</strong></td>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;">${escapeHtml(validatedData.name)}</td>
</tr>
<tr>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;"><strong>Telefon:</strong></td>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;"><a href="tel:${escapeHtml(validatedData.phone)}" style="color: #0F2A47; text-decoration: none;">${escapeHtml(validatedData.phone)}</a></td>
</tr>
<tr>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;"><strong>E-mail:</strong></td>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;"><a href="mailto:${escapeHtml(validatedData.email || '')}" style="color: #0F2A47; text-decoration: none;">${escapeHtml(validatedData.email || '')}</a></td>
</tr>
<tr>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;"><strong>Miasto:</strong></td>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;">${escapeHtml(validatedData.city)}</td>
</tr>
<tr>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;"><strong>Temat:</strong></td>
<td style="padding: 8px 0; border-bottom: 1px solid #f1f5f9;">${escapeHtml(validatedData.subject || '')}</td>
</tr>
</table>
<h2 style="font-size: 18px; border-bottom: 2px solid #f1f5f9; padding-bottom: 10px;">Treść wiadomości:</h2>
<div style="background-color: #f8fafc; padding: 15px; border-radius: 6px; font-size: 15px; line-height: 1.6; white-space: pre-wrap;">
${escapeHtml(validatedData.message || '')}
</div>
<p style="margin-top: 24px; font-size: 12px; color: #64748b; text-align: center;">
Zgoda RODO została zaakceptowana: <strong>${validatedData.consent ? "Tak" : "Nie"}</strong>
</p>
</div>
<div style="background-color: #f1f5f9; padding: 15px; text-align: center; font-size: 12px; color: #64748b;">
Wiadomość wygenerowana automatycznie z formularza kontaktowego na stronie thermcool.pl
</div>
</div>
`,
});
if (error) {
console.error("Resend Error:", error);
return {
success: false,
message: "Nie udało się wysłać wiadomości ze względu na błąd serwera pocztowego.",
};
}
console.log("Wysłano e-mail (ID):", data?.id);
return {
success: true,
message: "Dziękujemy za wiadomość! Skontaktujemy się z Tobą najszybciej jak to możliwe.",
};
} catch (error) {
if (error instanceof z.ZodError) {
return {
success: false,
message: "Wystąpił błąd walidacji. Sprawdź poprawność danych.",
errors: error.flatten().fieldErrors,
};
}
return {
success: false,
message: "Wystąpił nieoczekiwany błąd serwera. Spróbuj ponownie później.",
};
}
}