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
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>
<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">
<Button {type === 'invite' && (
pX={20} <Button
pY={12} pX={20}
className="rounded bg-[#A2E771] px-10 text-center text-[14px] font-medium text-black no-underline" pY={12}
href={signingLink} className="rounded bg-[#A2E771] px-10 text-center text-[14px] font-medium text-black no-underline"
> href={documentSigningLink}
Sign Document >
</Button> Sign Document
</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>
<Text className="text-[18px] leading-[24px] text-black"> {type === 'invite' && (
Thilo Konzok{' '} <>
<span className="font-semibold text-[#AFAFAF]">(thilo@konzok.com)</span> <Text className="text-[18px] leading-[24px] text-black">
</Text> {name} <span className="font-semibold text-[#AFAFAF]">({email})</span>
<Text className="mb-[80px] text-[16px] leading-[28px] text-[#AFAFAF]"> </Text>
Hi, <Text className="mb-[40px] text-[16px] leading-[28px] text-[#AFAFAF]">
<br /> Hi,
Please sign the attached document. Magna magna adipisicing dolore minim et aliquip <br />
ipsum esse ut nulla ad sint irure. Please sign the attached document. Magna magna adipisicing dolore minim et
<br /> - Thilo aliquip ipsum esse ut nulla ad sint irure.
</Text> <br /> - {firstName}
</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,
}); });
}; };