feat(email): Ukrainian source labels, full lead details in email (guests, date, message)
Some checks are pending
CI / Type Check (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Unit Tests (push) Waiting to run
Deploy / Build & Push Image (push) Waiting to run
Deploy / Deploy to VPS (push) Blocked by required conditions

This commit is contained in:
Vadym Samoilenko 2026-06-03 16:26:56 +01:00
parent 65c47359d5
commit 04b28e7620
3 changed files with 116 additions and 27 deletions

View file

@ -86,6 +86,10 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
phone: data.phone,
email: data.email,
formSource: data.formSource,
groupSize: data.groupSize,
preferredDate: data.preferredDate,
message: data.message,
packageSlug: data.packageSlug,
utmSource: data.utmSource,
}

View file

@ -3,6 +3,7 @@ import {
Container,
Head,
Heading,
Hr,
Html,
Preview,
Section,
@ -14,54 +15,120 @@ interface LeadAlertEmailProps {
phone: string
email?: string
formSource: string
formSourceLabel: string
groupSize?: number
preferredDate?: string
message?: string
packageSlug?: string
utmSource?: string
submittedAt: string
}
function Row({ label, value, bold }: { label: string; value: string; bold?: boolean }) {
return (
<Text style={{ margin: '0 0 8px', fontSize: 15, color: '#272727' }}>
<span style={{ color: '#6b7280', fontSize: 13 }}>{label}:&nbsp;</span>
<span style={{ fontWeight: bold ? 700 : 400 }}>{value}</span>
</Text>
)
}
export function LeadAlertEmail({
name,
phone,
email,
formSource,
formSourceLabel,
groupSize,
preferredDate,
message,
packageSlug,
utmSource,
submittedAt,
}: LeadAlertEmailProps) {
const hasDetails = groupSize ?? preferredDate ?? packageSlug ?? message
return (
<Html>
<Head />
<Preview>Новий лід: {name}</Preview>
<Body style={{ fontFamily: 'sans-serif', backgroundColor: '#f4f4f5' }}>
<Preview>
{formSourceLabel}: {name} {phone}
</Preview>
<Body style={{ fontFamily: 'Arial, sans-serif', backgroundColor: '#f1fbeb' }}>
<Container
style={{
maxWidth: 480,
maxWidth: 520,
margin: '32px auto',
backgroundColor: '#fff',
padding: 24,
borderRadius: 8,
borderRadius: 12,
overflow: 'hidden',
boxShadow: '0 2px 16px rgba(57,104,23,0.12)',
}}
>
<Heading style={{ fontSize: 20, marginBottom: 16 }}>Новий лід з сайту Shumiland</Heading>
<Section>
<Text>
<strong>Ім&apos;я:</strong> {name}
</Text>
<Text>
<strong>Телефон:</strong> {phone}
</Text>
{email && (
<Text>
<strong>Email:</strong> {email}
{/* Header */}
<Section
style={{
background: 'linear-gradient(90deg,#f28b4a 0%,#fdcf54 100%)',
padding: '20px 28px',
}}
>
<Heading style={{ margin: 0, fontSize: 20, color: '#272727', fontWeight: 700 }}>
🌿 Нова заявка {formSourceLabel}
</Heading>
</Section>
{/* Contact */}
<Section style={{ padding: '20px 28px 8px' }}>
<Heading
style={{
fontSize: 12,
color: '#396817',
margin: '0 0 12px',
textTransform: 'uppercase',
letterSpacing: 1,
}}
>
Контактні дані
</Heading>
<Row label="Ім'я" value={name} />
<Row label="Телефон" value={phone} bold />
{email ? <Row label="Email" value={email} /> : null}
</Section>
{/* Details */}
{hasDetails ? (
<>
<Hr style={{ margin: '0 28px', borderColor: '#d8f0c2' }} />
<Section style={{ padding: '16px 28px 8px' }}>
<Heading
style={{
fontSize: 12,
color: '#396817',
margin: '0 0 12px',
textTransform: 'uppercase',
letterSpacing: 1,
}}
>
Деталі заявки
</Heading>
{groupSize ? <Row label="Кількість гостей" value={String(groupSize)} /> : null}
{preferredDate ? <Row label="Бажана дата" value={preferredDate} /> : null}
{packageSlug ? <Row label="Пакет" value={packageSlug} /> : null}
{message ? <Row label="Повідомлення" value={message} /> : null}
</Section>
</>
) : null}
{/* Footer */}
<Hr style={{ margin: '0 28px', borderColor: '#d8f0c2' }} />
<Section style={{ padding: '12px 28px 20px' }}>
{utmSource ? (
<Text style={{ margin: '0 0 4px', fontSize: 12, color: '#9ca3af' }}>
Джерело трафіку: {utmSource}
</Text>
)}
<Text>
<strong>Форма:</strong> {formSource}
) : null}
<Text style={{ margin: 0, fontSize: 12, color: '#9ca3af' }}>
Отримано: {submittedAt}
</Text>
{utmSource && (
<Text>
<strong>UTM Source:</strong> {utmSource}
</Text>
)}
<Text style={{ color: '#6b7280', fontSize: 12 }}>Отримано: {submittedAt}</Text>
</Section>
</Container>
</Body>

View file

@ -12,11 +12,26 @@ function getResend() {
const FROM = process.env['RESEND_FROM'] ?? 'noreply@shumiland.ua'
const MANAGER_EMAILS = (process.env['MANAGER_EMAILS'] ?? '').split(',').filter(Boolean)
const SOURCE_LABELS: Record<string, string> = {
'birthday-booking': 'Дні народження',
'group-request': 'Групові відвідування',
'ticket-purchase': 'Купівля квитків',
general: 'Загальна заявка',
}
function sourceLabel(formSource: string): string {
return SOURCE_LABELS[formSource] ?? formSource
}
export type LeadAlertData = {
name: string
phone: string
email?: string
formSource: string
groupSize?: number
preferredDate?: string
message?: string
packageSlug?: string
utmSource?: string
}
@ -26,9 +41,12 @@ export async function sendLeadAlert(lead: LeadAlertData): Promise<void> {
return
}
const label = sourceLabel(lead.formSource)
const html = await render(
LeadAlertEmail({
...lead,
formSourceLabel: label,
submittedAt: new Date().toLocaleString('uk-UA', { timeZone: 'Europe/Kyiv' }),
})
)
@ -43,7 +61,7 @@ export async function sendLeadAlert(lead: LeadAlertData): Promise<void> {
await resend.emails.send({
from: FROM,
to: MANAGER_EMAILS,
subject: `Новий лід: ${lead.name} (${lead.formSource})`,
subject: `Нова заявка — ${label}: ${lead.name} (${lead.phone})`,
html,
})
} catch (err) {