MED-88: add doctor email notifications (#65)

* MED-88: add doctor email notifications

* add logging, send open jobs notification on partial analysis response

* update permissions

* fix import, permissions

* casing, let email be null

* unused import
This commit is contained in:
Helena
2025-09-02 12:14:01 +03:00
committed by GitHub
parent 56a832b96b
commit 3498406a0c
41 changed files with 751 additions and 69 deletions

View File

@@ -0,0 +1,82 @@
import {
Body,
Head,
Html,
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 { EmailButton } from '../components/email-button';
import { EmailHeader } from '../components/header';
import { EmailHeading } from '../components/heading';
import { EmailWrapper } from '../components/wrapper';
import { initializeEmailI18n } from '../lib/i18n';
export async function renderAllResultsReceivedEmail({
language,
analysisOrderId,
}: {
language: string;
analysisOrderId: number;
}) {
const namespace = 'all-results-received-email';
const { t } = await initializeEmailI18n({
language,
namespace: [namespace, 'common'],
});
const previewText = t(`${namespace}:previewText`);
const subject = t(`${namespace}:subject`);
const html = await render(
<Html>
<Head>
<BodyStyle />
</Head>
<Preview>{previewText}</Preview>
<Tailwind>
<Body>
<EmailWrapper>
<EmailHeader>
<EmailHeading>{previewText}</EmailHeading>
</EmailHeader>
<EmailContent>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:hello`)}
</Text>
<Text className="text-[16px] leading-[24px] font-semibold text-[#242424]">
{t(`${namespace}:openOrdersHeading`)}
</Text>
<EmailButton
href={`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/analysis/${analysisOrderId}`}
>
{t(`${namespace}:linkText`)}
</EmailButton>
<Text>
{t(`${namespace}:ifLinksDisabled`)}{' '}
{`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/analysis/${analysisOrderId}`}
</Text>
<CommonFooter t={t} />
</EmailContent>
</EmailWrapper>
</Body>
</Tailwind>
</Html>,
);
return {
html,
subject,
};
}

View File

@@ -19,14 +19,12 @@ import { initializeEmailI18n } from '../lib/i18n';
export async function renderDoctorSummaryReceivedEmail({
language,
recipientEmail,
recipientName,
orderNr,
orderId,
}: {
language?: string;
recipientName: string;
recipientEmail: string;
orderNr: string;
orderId: number;
}) {
@@ -37,8 +35,6 @@ export async function renderDoctorSummaryReceivedEmail({
namespace: [namespace, 'common'],
});
const to = recipientEmail;
const previewText = t(`${namespace}:previewText`, {
orderNr,
});
@@ -92,6 +88,5 @@ export async function renderDoctorSummaryReceivedEmail({
return {
html,
subject,
to,
};
}

View File

@@ -0,0 +1,86 @@
import {
Body,
Head,
Html,
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 { EmailButton } from '../components/email-button';
import { EmailHeader } from '../components/header';
import { EmailHeading } from '../components/heading';
import { EmailWrapper } from '../components/wrapper';
import { initializeEmailI18n } from '../lib/i18n';
export async function renderFirstResultsReceivedEmail({
language,
analysisOrderId,
}: {
language: string;
analysisOrderId: number;
}) {
const namespace = 'first-results-received-email';
const { t } = await initializeEmailI18n({
language,
namespace: [namespace, 'common'],
});
const previewText = t(`${namespace}:previewText`);
const subject = t(`${namespace}:subject`);
const html = await render(
<Html>
<Head>
<BodyStyle />
</Head>
<Preview>{previewText}</Preview>
<Tailwind>
<Body>
<EmailWrapper>
<EmailHeader>
<EmailHeading>{previewText}</EmailHeading>
</EmailHeader>
<EmailContent>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:hello`)}
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:resultsReceivedForOrders`)}
</Text>
<Text className="text-[16px] leading-[24px] font-semibold text-[#242424]">
{t(`${namespace}:openOrdersHeading`)}
</Text>
<EmailButton
href={`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/analysis/${analysisOrderId}`}
>
{t(`${namespace}:linkText`)}
</EmailButton>
<Text>
{t(`${namespace}:ifLinksDisabled`)}{' '}
{`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/analysis/${analysisOrderId}`}
</Text>
<CommonFooter t={t} />
</EmailContent>
</EmailWrapper>
</Body>
</Tailwind>
</Html>,
);
return {
html,
subject,
};
}

View File

@@ -0,0 +1,99 @@
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 renderNewJobsAvailableEmail({
language,
analysisResponseIds,
}: {
language?: string;
analysisResponseIds: number[];
}) {
const namespace = 'new-jobs-available-email';
const { t } = await initializeEmailI18n({
language,
namespace: [namespace, 'common'],
});
const previewText = t(`${namespace}:previewText`, {
nr: analysisResponseIds.length,
});
const subject = t(`${namespace}:subject`, {
nr: analysisResponseIds.length,
});
const html = await render(
<Html>
<Head>
<BodyStyle />
</Head>
<Preview>{previewText}</Preview>
<Tailwind>
<Body>
<EmailWrapper>
<EmailHeader>
<EmailHeading>{previewText}</EmailHeading>
</EmailHeader>
<EmailContent>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:hello`)}
</Text>
<Text className="text-[16px] leading-[24px] text-[#242424]">
{t(`${namespace}:resultsReceivedForOrders`, {
nr: analysisResponseIds.length,
})}
</Text>
<Text className="text-[16px] leading-[24px] font-semibold text-[#242424]">
{t(`${namespace}:openOrdersHeading`, {
nr: analysisResponseIds.length,
})}
</Text>
<ul className="list-none text-[16px] leading-[24px]">
{analysisResponseIds.map((analysisResponseId, index) => (
<li>
<Link
key={analysisResponseId}
href={`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/analysis/${analysisResponseId}`}
>
{t(`${namespace}:linkText`, { nr: index + 1 })}
</Link>
</li>
))}
</ul>
<Text>
{t(`${namespace}:ifLinksDisabled`)}{' '}
{`${process.env.NEXT_PUBLIC_SITE_URL}/doctor/open-jobs`}
</Text>
<CommonFooter t={t} />
</EmailContent>
</EmailWrapper>
</Body>
</Tailwind>
</Html>,
);
return {
html,
subject,
};
}

View File

@@ -71,7 +71,7 @@ export async function renderOtpEmail(props: Props) {
<Section className="mb-[16px] mt-[16px] text-center">
<Button className={'w-full rounded bg-neutral-950 text-center'}>
<Text className="text-[16px] font-medium font-semibold leading-[16px] text-white">
<Text className="text-[16px] font-semibold leading-[16px] text-white">
{props.otp}
</Text>
</Button>

View File

@@ -9,12 +9,12 @@ import {
} 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';
import CommonFooter from '../components/common-footer';
interface Props {
analysisPackageName: string;
@@ -31,7 +31,10 @@ export async function renderSynlabAnalysisPackageEmail(props: Props) {
namespace: [namespace, 'common'],
});
const previewText = t(`${namespace}:previewText`);
const previewText = t(`${namespace}:previewText`, {
analysisPackageName: props.analysisPackageName,
});
const subject = t(`${namespace}:subject`, {
analysisPackageName: props.analysisPackageName,
});