feat: make email template reusable for signed, invite and completed

This commit is contained in:
Ephraim Atta-Duncan
2023-06-21 13:20:07 +00:00
parent 590344f793
commit 02569619f9
10 changed files with 1662 additions and 59 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

View File

@ -15,6 +15,8 @@ export default function Send() {
console.log('clicked'); console.log('clicked');
await sendMail({ email: 'duncan@documenso.com' }); await sendMail({ email: 'duncan@documenso.com' });
alert('sent');
}} }}
> >
Send Send

1503
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,6 @@ import {
Button, Button,
Container, Container,
Head, Head,
Heading,
Html, Html,
Img, Img,
Link, Link,
@ -16,75 +15,157 @@ import {
render, render,
} from '@react-email/components'; } from '@react-email/components';
interface DocumensoSigningInviteEmailProps { interface DocumensoEmailProps {
username?: string; email?: string;
userImage?: string; name?: string;
invitedByUsername?: string; firstName?: string;
invitedByEmail?: string; documentSigningLink?: string;
teamName?: string; documentName?: string;
teamImage?: string; downloadLink?: string;
signingLink?: string; reviewLink?: string;
inviteFromIp?: string; numberOfSigners?: number;
inviteFromLocation?: string; type: 'invite' | 'signed' | 'completed';
} }
export const DocumensoSigningInviteEmail = ({ export const DocumensoEmail = ({
signingLink = 'https://documenso.com', documentSigningLink = 'https://documenso.com',
}: DocumensoSigningInviteEmailProps) => { downloadLink = 'https://documenso.com',
reviewLink = 'https://documenso.com',
email = 'duncan@documenso.com',
name = 'Ephraim Atta-Duncan',
firstName = 'Ephraim',
documentName = 'Open Source Pledge.pdf',
numberOfSigners = 2,
type = 'signed',
}: DocumensoEmailProps) => {
const previewText = type === 'completed' ? 'Completed Document' : `Sign Document`;
return ( return (
<Html> <Html>
<Head /> <Head />
<Preview>Sign Document</Preview> <Preview>{previewText}</Preview>
<Tailwind> <Tailwind>
<Body className="mx-auto my-auto font-sans"> <Body className="mx-auto my-auto ml-auto mr-auto font-sans">
<Section className="bg-white"> <Section className="bg-white">
<Container className="mx-auto mb-[10px] mt-[40px] w-[600px] rounded-lg border-2 border-solid border-[#eaeaea] p-[20px] backdrop-blur-sm"> <Container
<Section> style={{
border: '2px solid #eaeaea',
}}
className="mx-auto mb-[10px] ml-auto mr-auto mt-[40px] w-[600px] rounded-lg p-[10px] backdrop-blur-sm"
>
<Section> <Section>
<Img <Img
src={`http://localhost:3000/static/logo.png`} src={`http://localhost:3000/static/logo.png`}
alt="Documenso Logo" alt="Documenso Logo"
width={120} width={120}
/> />
</Section>
<Section className="mt-4 flex items-center justify-center"> <Section className="mt-4 flex-row items-center justify-center">
<Section className="flex justify-center"> <div className="my-3 flex items-center justify-center">
<Img src={`http://localhost:3000/static/document.png`} alt="Documenso" /> <Img
</Section> className="ml-[160px]" // Works on most of the email clients
src={`http://localhost:3000/static/document.png`}
alt="Documenso"
/>
</div>
<Heading className="mx-0 mb-0 text-center text-[18px] font-semibold text-[#27272A]"> {type === 'completed' && (
Thilo Konzok has invited you to sign Document.pdf <Text className="mb-4 text-center text-[16px] font-semibold text-[#7AC455]">
</Heading> <Img
src="http://localhost:3000/static/completed.png"
className="-mb-0.5 mr-1.5 inline"
/>
Completed
</Text>
)}
{type === 'signed' && (
<Text className="mb-4 text-center text-[16px] font-semibold text-[#3879C5]">
<Img
src="http://localhost:3000/static/clock.png"
className="-mb-0.5 mr-1.5 inline"
/>
Waiting for {numberOfSigners} {numberOfSigners === 1 ? 'person' : 'people'} to
sign
</Text>
)}
<Text className="mx-0 mb-0 text-center text-[18px] font-semibold text-[#27272A]">
{type === 'invite'
? `${name} has invited you to sign “${documentName}`
: `${documentName}” was signed by ${name}`}
</Text>
<Text className="my-1 text-center text-[16px] text-[#AFAFAF]"> <Text className="my-1 text-center text-[16px] text-[#AFAFAF]">
Continue by signing the document. {type === 'invite'
? 'Continue by signing the document.'
: 'Continue by downloading or reviewing the document.'}
</Text> </Text>
<Section className="mb-[24px] mt-[32px] text-center"> <Section className="mb-[24px] mt-[32px] text-center">
{type === 'invite' && (
<Button <Button
pX={20} pX={20}
pY={12} pY={12}
className="rounded bg-[#A2E771] px-10 text-center text-[14px] font-medium text-black no-underline" className="rounded bg-[#A2E771] px-10 text-center text-[14px] font-medium text-black no-underline"
href={signingLink} href={documentSigningLink}
> >
Sign Document Sign Document
</Button> </Button>
)}
{type !== 'invite' && (
<Section>
<Button
pX={18}
pY={10}
style={{
border: '1px solid #E9E9E9',
}}
className="mr-4 rounded-lg text-center text-[14px] font-medium text-black no-underline"
href={reviewLink}
>
<Img
src="http://localhost:3000/static/review.png"
className="-mb-0.5 mr-1 inline"
/>
Review
</Button>
<Button
pX={18}
pY={10}
style={{
border: '1px solid #E9E9E9',
}}
className="rounded-lg text-center text-[14px] font-medium text-black no-underline"
href={downloadLink}
>
<Img
src="http://localhost:3000/static/download.png"
className="-mb-0.5 mr-1 inline"
/>
Download
</Button>
</Section>
)}
</Section> </Section>
</Section> </Section>
</Section> </Section>
</Container> </Container>
<Container className="mx-auto w-[600px]"> <Container className="mx-auto ml-auto mr-auto w-[600px]">
<Section> <Section>
{type === 'invite' && (
<>
<Text className="text-[18px] leading-[24px] text-black"> <Text className="text-[18px] leading-[24px] text-black">
Thilo Konzok{' '} {name} <span className="font-semibold text-[#AFAFAF]">({email})</span>
<span className="font-semibold text-[#AFAFAF]">(thilo@konzok.com)</span>
</Text> </Text>
<Text className="mb-[80px] text-[16px] leading-[28px] text-[#AFAFAF]"> <Text className="mb-[40px] text-[16px] leading-[28px] text-[#AFAFAF]">
Hi, Hi,
<br /> <br />
Please sign the attached document. Magna magna adipisicing dolore minim et aliquip Please sign the attached document. Magna magna adipisicing dolore minim et
ipsum esse ut nulla ad sint irure. aliquip ipsum esse ut nulla ad sint irure.
<br /> - Thilo <br /> - {firstName}
</Text> </Text>
</>
)}
<Text className="my-[40px] text-[14px] text-[#AFAFAF]"> <Text className="my-[40px] text-[14px] text-[#AFAFAF]">
This document was sent using{' '} This document was sent using{' '}
@ -107,9 +188,12 @@ export const DocumensoSigningInviteEmail = ({
); );
}; };
export default DocumensoSigningInviteEmail; export const emailHtml = (props: DocumensoEmailProps) =>
render(<DocumensoEmail {...props} />, {
pretty: true,
});
export const emailHtml = render(<DocumensoSigningInviteEmail />); export const emailText = (props: DocumensoEmailProps) =>
export const emailText = render(<DocumensoSigningInviteEmail />, { render(<DocumensoEmail {...props} />, {
plainText: true, plainText: true,
}); });

View File

@ -31,11 +31,25 @@ export const sendMail = async ({ email }: { email: string }) => {
); );
} }
const html = emailHtml({
email: 'lucas@documenso.com',
name: 'Lucas Smith',
documentName: 'NDA.pdf',
firstName: 'Lucas',
type: 'signed',
});
await transporter.sendMail({ await transporter.sendMail({
from: 'Documenso <hi@documenso.com>', from: 'Documenso <hi@documenso.com>',
to: email, to: email,
subject: 'Welcome to Documenso!', subject: 'Welcome to Documenso!',
text: emailText, text: emailText({
html: emailHtml, email: 'lucas@documenso.com',
name: 'Lucas Smith',
documentName: 'NDA.pdf',
firstName: 'Lucas',
type: 'completed',
}),
html,
}); });
}; };