feat: create email template for TTO reservation confirmation

feat: implement order notifications service with TTO reservation confirmation handling

feat: create migration for TTO booking email webhook trigger
This commit is contained in:
Danel Kungla
2025-09-30 16:05:43 +03:00
parent 4003284f3a
commit 72f6f2b716
56 changed files with 3692 additions and 294 deletions

View File

@@ -6,22 +6,28 @@ import { EmailFooter } from './footer';
export default function CommonFooter({ t }: { t: TFunction }) {
const namespace = 'common';
const lines = [
t(`${namespace}:footer.lines1`),
t(`${namespace}:footer.lines2`),
t(`${namespace}:footer.lines3`),
t(`${namespace}:footer.lines4`),
];
return (
<EmailFooter>
{lines.map((line, index) => (
<Text
key={index}
className="text-[16px] leading-[24px] text-[#242424]"
dangerouslySetInnerHTML={{ __html: line }}
/>
))}
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:footer.title`)}
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:footer.emailField`)}{' '}
<a href={`mailto:${t(`${namespace}:footer.title`)}`}>
{t(`${namespace}:footer.email`)}
</a>
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:footer.phoneField`)}{' '}
<a href={`tel:${t(`${namespace}:footer.phone`)}`}>
{t(`${namespace}:footer.phone`)}
</a>
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
<a href={`https://${t(`${namespace}:footer.website`)}`}>
{t(`${namespace}:footer.website`)}
</a>
</Text>
</EmailFooter>
);
}

View File

@@ -1,11 +1,11 @@
import { Container, Text } from '@react-email/components';
import { Container, Section } from '@react-email/components';
export function EmailFooter(props: React.PropsWithChildren) {
return (
<Container className="mt-[24px]">
<Text className="px-4 text-[12px] leading-[20px] text-gray-300">
<Section className="px-4 text-[12px] leading-[20px] text-gray-300">
{props.children}
</Text>
</Section>
</Container>
);
}

View File

@@ -0,0 +1,8 @@
import React from 'react';
const Email = () => {
return <div>Email</div>;
};
export default Email;
Email.PreviewProps = {};

View File

@@ -0,0 +1,137 @@
import {
Body,
Head,
Html,
Link,
Preview,
Tailwind,
Text,
render,
} from '@react-email/components';
import { BodyStyle } from '../components/body-style';
import CommonFooter from '../components/common-footer';
import { EmailContent } from '../components/content';
import { EmailHeader } from '../components/header';
import { EmailHeading } from '../components/heading';
import { EmailWrapper } from '../components/wrapper';
import { initializeEmailI18n } from '../lib/i18n';
export async function renderTtoReservationConfirmationEmail({
language,
recipientName,
startTime,
orderName,
locationName,
locationAddress,
orderId,
serviceProviderName,
serviceProviderEmail,
serviceProviderPhone,
}: {
language: string;
recipientName: string;
startTime: string;
orderName: string;
locationName?: string;
locationAddress?: string | null;
orderId: string;
serviceProviderName?: string;
serviceProviderEmail?: string | null;
serviceProviderPhone?: string | null;
}) {
const namespace = 'tto-reservation-confirmation-email';
const { t } = await initializeEmailI18n({
language,
namespace: [namespace, 'common'],
});
const previewText = t(`${namespace}:previewText`, {
reservation: orderName,
});
const subject = t(`${namespace}:subject`, {
reservation: orderName,
});
const email = (
<Html>
<Head>
<BodyStyle />
</Head>
<Preview>{previewText}</Preview>
<Tailwind>
<Body>
<EmailWrapper>
<EmailContent>
<EmailHeader>
<EmailHeading>{previewText}</EmailHeading>
</EmailHeader>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:helloName`, { name: recipientName })}
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:thankYou`)}
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{orderName}, {new Date(startTime).toLocaleString()},{' '}
{locationAddress}, {locationName}
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
<Link
href={`${process.env.NEXT_PUBLIC_SITE_URL}/home/order/${orderId}`}
>
{t(`${namespace}:viewOrder`)}
</Link>
</Text>
<Text className="mt-10 text-[16px] leading-[24px] text-[#242424]">
{serviceProviderName}
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:customerSupport`)}
<Link href={`tel:${serviceProviderPhone})}`}>
{serviceProviderPhone}
</Link>
</Text>
<Link href={`mailto:${serviceProviderEmail}`}>
{serviceProviderEmail}
</Link>
<CommonFooter t={t} />
</EmailContent>
</EmailWrapper>
</Body>
</Tailwind>
</Html>
);
const html = await render(email);
return {
html,
subject,
email,
};
}
const PreviewEmail = async () => {
const { email } = await renderTtoReservationConfirmationEmail({
language: 'et',
recipientName: 'John Doe',
startTime: '2025-09-27 05:45:00+00',
orderName: 'Hambaarst',
locationName: 'Tallinn',
locationAddress: 'Põhja puiestee, 2/3A',
orderId: '123123',
serviceProviderName: 'Dentas OÜ',
serviceProviderEmail: 'email@example.ee',
serviceProviderPhone: '+372111111',
});
return email;
};
export default PreviewEmail;
PreviewEmail.PreviewProps = {};

View File

@@ -11,3 +11,4 @@ export * from './emails/order-processing.email';
export * from './emails/patient-first-results-received.email';
export * from './emails/patient-full-results-received.email';
export * from './emails/book-time-failed.email';
export * from './emails/tto-reservation-confirmation.email';

View File

@@ -0,0 +1,8 @@
{
"previewText": "Your booking is confirmed! - {{reservation}}",
"subject": "Your booking is confirmed! - {{reservation}}",
"helloName": "Hello, {{name}}!",
"thankYou": "Thank you for your order!",
"viewOrder": "See booking",
"customerSupport": "Customer support: "
}

View File

@@ -1,9 +1,11 @@
{
"footer": {
"lines1": "MedReport",
"lines2": "E-mail: <a href=\"mailto:info@medreport.ee\">info@medreport.ee</a>",
"lines3": "Klienditugi: <a href=\"tel:+37258871517\">+372 5887 1517</a>",
"lines4": "<a href=\"https://www.medreport.ee\">www.medreport.ee</a>"
"title": "MedReport",
"emailField": "E-mail:",
"email": "info@medreport.ee",
"phoneField": "Klienditugi:",
"phone": "+372 5887 1517",
"website": "www.medreport.ee"
},
"helloName": "Tere, {{name}}",
"hello": "Tere"

View File

@@ -0,0 +1,8 @@
{
"previewText": "Teie broneering on kinnitatud! - {{reservation}}",
"subject": "Teie broneering on kinnitatud! - {{reservation}}",
"helloName": "Tere, {{name}}!",
"thankYou": "Täname tellimuse eest!",
"viewOrder": "Vaata broneeringut",
"customerSupport": "Klienditugi: "
}

View File

@@ -0,0 +1,8 @@
{
"previewText": "Your booking is confirmed! - {{reservation}}",
"subject": "Your booking is confirmed! - {{reservation}}",
"helloName": "Hello, {{name}}!",
"thankYou": "Thank you for your order!",
"viewOrder": "See booking",
"customerSupport": "Customer support: "
}