mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 00:03:33 +10:00
feat: email templates
adds email templates using `react-email` which will be used for invites, signing and document completion. authored by @dephraiim
This commit is contained in:
6577
package-lock.json
generated
6577
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,7 @@
|
|||||||
"packageManager": "npm@8.19.2",
|
"packageManager": "npm@8.19.2",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"apps/*",
|
"apps/*",
|
||||||
"packages/*"
|
"packages/*",
|
||||||
|
"packages/email/.react-email"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/email/.gitignore
vendored
Normal file
1
packages/email/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.react-email/
|
||||||
1
packages/email/ambient.d.ts
vendored
Normal file
1
packages/email/ambient.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
declare module '@documenso/tailwind-config';
|
||||||
1
packages/email/index.ts
Normal file
1
packages/email/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { render, renderAsync } from '@react-email/components';
|
||||||
22
packages/email/package.json
Normal file
22
packages/email/package.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "@documenso/email",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "./index.ts",
|
||||||
|
"types": "./index.ts",
|
||||||
|
"license": "MIT",
|
||||||
|
"files": [
|
||||||
|
"templates/"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"dev": "email dev --port 3002 --dir templates"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@documenso/tsconfig": "*",
|
||||||
|
"@documenso/tailwind-config": "*",
|
||||||
|
"@documenso/ui": "*",
|
||||||
|
"@react-email/components": "^0.0.7"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"react-email": "^1.9.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
packages/email/static/clock.png
Normal file
BIN
packages/email/static/clock.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
packages/email/static/completed.png
Normal file
BIN
packages/email/static/completed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
packages/email/static/document.png
Normal file
BIN
packages/email/static/document.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
packages/email/static/download.png
Normal file
BIN
packages/email/static/download.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 784 B |
BIN
packages/email/static/logo.png
Normal file
BIN
packages/email/static/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
BIN
packages/email/static/review.png
Normal file
BIN
packages/email/static/review.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 708 B |
11
packages/email/tailwind.config.js
Normal file
11
packages/email/tailwind.config.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
const baseConfig = require('@documenso/tailwind-config');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...baseConfig,
|
||||||
|
content: [
|
||||||
|
`templates/**/*.{ts,tsx}`,
|
||||||
|
`${path.join(require.resolve('@documenso/ui'), '..')}/**/*.{ts,tsx}`,
|
||||||
|
],
|
||||||
|
};
|
||||||
129
packages/email/templates/document-completed.tsx
Normal file
129
packages/email/templates/document-completed.tsx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Head,
|
||||||
|
Html,
|
||||||
|
Img,
|
||||||
|
Link,
|
||||||
|
Preview,
|
||||||
|
Section,
|
||||||
|
Tailwind,
|
||||||
|
Text,
|
||||||
|
} from '@react-email/components';
|
||||||
|
|
||||||
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
interface DocumentCompletedEmailTemplateProps {
|
||||||
|
downloadLink?: string;
|
||||||
|
reviewLink?: string;
|
||||||
|
documentName?: string;
|
||||||
|
assetBaseUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DocumentCompletedEmailTemplate = ({
|
||||||
|
downloadLink = 'https://documenso.com',
|
||||||
|
reviewLink = 'https://documenso.com',
|
||||||
|
documentName = 'Open Source Pledge.pdf',
|
||||||
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
|
}: DocumentCompletedEmailTemplateProps) => {
|
||||||
|
const previewText = `Completed Document`;
|
||||||
|
|
||||||
|
const getAssetUrl = (path: string) => {
|
||||||
|
return new URL(path, assetBaseUrl).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Html>
|
||||||
|
<Head />
|
||||||
|
<Preview>{previewText}</Preview>
|
||||||
|
<Tailwind
|
||||||
|
config={{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: config.theme.extend.colors,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Body className="mx-auto my-auto font-sans">
|
||||||
|
<Section className="bg-white">
|
||||||
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||||
|
<Section className="p-2">
|
||||||
|
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||||
|
|
||||||
|
<Section className="mt-4 flex-row items-center justify-center">
|
||||||
|
<div className="flex items-center justify-center p-4">
|
||||||
|
<Img
|
||||||
|
className="h-42"
|
||||||
|
src={getAssetUrl('/static/document.png')}
|
||||||
|
alt="Documenso"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-[#7AC455]">
|
||||||
|
<Img
|
||||||
|
src={getAssetUrl('/static/completed.png')}
|
||||||
|
className="-mb-0.5 mr-2 inline h-7 w-7"
|
||||||
|
/>
|
||||||
|
Completed
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||||
|
“{documentName}” was signed by all signers
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
|
Continue by downloading or reviewing the document.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Section className="mb-6 mt-8 text-center">
|
||||||
|
<Button
|
||||||
|
className="mr-4 inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||||
|
href={reviewLink}
|
||||||
|
>
|
||||||
|
<Img
|
||||||
|
src={getAssetUrl('/static/review.png')}
|
||||||
|
className="-mb-1 mr-2 inline h-5 w-5"
|
||||||
|
/>
|
||||||
|
Review
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="inline-flex items-center justify-center rounded-lg border border-solid border-slate-200 px-4 py-2 text-center text-sm font-medium text-black no-underline"
|
||||||
|
href={downloadLink}
|
||||||
|
>
|
||||||
|
<Img
|
||||||
|
src={getAssetUrl('/static/download.png')}
|
||||||
|
className="-mb-1 mr-2 inline h-5 w-5"
|
||||||
|
/>
|
||||||
|
Download
|
||||||
|
</Button>
|
||||||
|
</Section>
|
||||||
|
</Section>
|
||||||
|
</Section>
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Container className="mx-auto max-w-xl">
|
||||||
|
<Section>
|
||||||
|
<Text className="my-4 text-base text-slate-400">
|
||||||
|
This document was sent using{' '}
|
||||||
|
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||||
|
Documenso.
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="my-8 text-sm text-slate-400">
|
||||||
|
Documenso
|
||||||
|
<br />
|
||||||
|
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||||
|
</Text>
|
||||||
|
</Section>
|
||||||
|
</Container>
|
||||||
|
</Section>
|
||||||
|
</Body>
|
||||||
|
</Tailwind>
|
||||||
|
</Html>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DocumentCompletedEmailTemplate;
|
||||||
127
packages/email/templates/document-invite.tsx
Normal file
127
packages/email/templates/document-invite.tsx
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Head,
|
||||||
|
Hr,
|
||||||
|
Html,
|
||||||
|
Img,
|
||||||
|
Link,
|
||||||
|
Preview,
|
||||||
|
Section,
|
||||||
|
Tailwind,
|
||||||
|
Text,
|
||||||
|
} from '@react-email/components';
|
||||||
|
|
||||||
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
interface DocumentInviteEmailTemplateProps {
|
||||||
|
inviterName?: string;
|
||||||
|
inviterEmail?: string;
|
||||||
|
documentName?: string;
|
||||||
|
signDocumentLink?: string;
|
||||||
|
assetBaseUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DocumentInviteEmailTemplate = ({
|
||||||
|
inviterName = 'Lucas Smith',
|
||||||
|
inviterEmail = 'lucas@documenso.com',
|
||||||
|
documentName = 'Open Source Pledge.pdf',
|
||||||
|
signDocumentLink = 'https://documenso.com',
|
||||||
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
|
}: DocumentInviteEmailTemplateProps) => {
|
||||||
|
const previewText = `Completed Document`;
|
||||||
|
|
||||||
|
const getAssetUrl = (path: string) => {
|
||||||
|
return new URL(path, assetBaseUrl).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Html>
|
||||||
|
<Head />
|
||||||
|
<Preview>{previewText}</Preview>
|
||||||
|
<Tailwind
|
||||||
|
config={{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: config.theme.extend.colors,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Body className="mx-auto my-auto bg-white font-sans">
|
||||||
|
<Section>
|
||||||
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||||
|
<Section className="p-2">
|
||||||
|
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||||
|
|
||||||
|
<Section className="mt-4 flex-row items-center justify-center">
|
||||||
|
<div className="flex items-center justify-center p-4">
|
||||||
|
<Img
|
||||||
|
className="h-42"
|
||||||
|
src={getAssetUrl('/static/document.png')}
|
||||||
|
alt="Documenso"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Text className="text-primary mx-auto mb-0 max-w-[80%] text-center text-lg font-semibold">
|
||||||
|
{inviterName} has invited you to sign "{documentName}"
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="my-1 text-center text-base text-slate-400">
|
||||||
|
Continue by signing the document.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Section className="mb-6 mt-8 text-center">
|
||||||
|
<Button
|
||||||
|
className="bg-documenso-500 inline-flex items-center justify-center rounded-lg px-6 py-3 text-center text-sm font-medium text-black no-underline"
|
||||||
|
href={signDocumentLink}
|
||||||
|
>
|
||||||
|
Sign Document
|
||||||
|
</Button>
|
||||||
|
</Section>
|
||||||
|
</Section>
|
||||||
|
</Section>
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Container className="mx-auto mt-12 max-w-xl">
|
||||||
|
<Section>
|
||||||
|
<Text className="my-4 text-base font-semibold">
|
||||||
|
{inviterName}{' '}
|
||||||
|
<Link className="font-normal text-slate-400" href="mailto:{inviterEmail}">
|
||||||
|
({inviterEmail})
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="mt-2 text-base text-slate-400">
|
||||||
|
{inviterName} has invited you to sign the document "{documentName}".
|
||||||
|
</Text>
|
||||||
|
</Section>
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Hr className="mx-auto mt-12 max-w-xl" />
|
||||||
|
|
||||||
|
<Container className="mx-auto max-w-xl">
|
||||||
|
<Section>
|
||||||
|
<Text className="my-4 text-base text-slate-400">
|
||||||
|
This document was sent using{' '}
|
||||||
|
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||||
|
Documenso.
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="my-8 text-sm text-slate-400">
|
||||||
|
Documenso
|
||||||
|
<br />
|
||||||
|
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||||
|
</Text>
|
||||||
|
</Section>
|
||||||
|
</Container>
|
||||||
|
</Section>
|
||||||
|
</Body>
|
||||||
|
</Tailwind>
|
||||||
|
</Html>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DocumentInviteEmailTemplate;
|
||||||
104
packages/email/templates/document-pending.tsx
Normal file
104
packages/email/templates/document-pending.tsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Button,
|
||||||
|
Container,
|
||||||
|
Head,
|
||||||
|
Html,
|
||||||
|
Img,
|
||||||
|
Link,
|
||||||
|
Preview,
|
||||||
|
Section,
|
||||||
|
Tailwind,
|
||||||
|
Text,
|
||||||
|
} from '@react-email/components';
|
||||||
|
|
||||||
|
import * as config from '@documenso/tailwind-config';
|
||||||
|
|
||||||
|
interface DocumentPendingEmailTemplateProps {
|
||||||
|
documentName?: string;
|
||||||
|
assetBaseUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DocumentPendingEmailTemplate = ({
|
||||||
|
documentName = 'Open Source Pledge.pdf',
|
||||||
|
assetBaseUrl = 'http://localhost:3002',
|
||||||
|
}: DocumentPendingEmailTemplateProps) => {
|
||||||
|
const previewText = `Pending Document`;
|
||||||
|
|
||||||
|
const getAssetUrl = (path: string) => {
|
||||||
|
return new URL(path, assetBaseUrl).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Html>
|
||||||
|
<Head />
|
||||||
|
<Preview>{previewText}</Preview>
|
||||||
|
<Tailwind
|
||||||
|
config={{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: config.theme.extend.colors,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Body className="mx-auto my-auto font-sans">
|
||||||
|
<Section className="bg-white">
|
||||||
|
<Container className="mx-auto mb-2 mt-8 max-w-xl rounded-lg border border-solid border-slate-200 p-2 backdrop-blur-sm">
|
||||||
|
<Section className="p-2">
|
||||||
|
<Img src={getAssetUrl('/static/logo.png')} alt="Documenso Logo" className="h-6" />
|
||||||
|
|
||||||
|
<Section className="mt-4 flex-row items-center justify-center">
|
||||||
|
<div className="flex items-center justify-center p-4">
|
||||||
|
<Img
|
||||||
|
className="h-42"
|
||||||
|
src={getAssetUrl('/static/document.png')}
|
||||||
|
alt="Documenso"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Text className="mb-4 flex items-center justify-center text-center text-base font-semibold text-blue-500">
|
||||||
|
<Img
|
||||||
|
src={getAssetUrl('/static/clock.png')}
|
||||||
|
className="-mb-0.5 mr-2 inline h-7 w-7"
|
||||||
|
/>
|
||||||
|
Waiting for others
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="text-primary mb-0 text-center text-lg font-semibold">
|
||||||
|
“{documentName}” has been signed
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="mx-auto mb-6 mt-1 max-w-[80%] text-center text-base text-slate-400">
|
||||||
|
We're still waiting for other signers to sign this document.
|
||||||
|
<br />
|
||||||
|
We'll notify you as soon as it's ready.
|
||||||
|
</Text>
|
||||||
|
</Section>
|
||||||
|
</Section>
|
||||||
|
</Container>
|
||||||
|
|
||||||
|
<Container className="mx-auto max-w-xl">
|
||||||
|
<Section>
|
||||||
|
<Text className="my-4 text-base text-slate-400">
|
||||||
|
This document was sent using{' '}
|
||||||
|
<Link className="text-[#7AC455]" href="https://documenso.com">
|
||||||
|
Documenso.
|
||||||
|
</Link>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text className="my-8 text-sm text-slate-400">
|
||||||
|
Documenso
|
||||||
|
<br />
|
||||||
|
2261 Market Street, #5211, San Francisco, CA 94114, USA
|
||||||
|
</Text>
|
||||||
|
</Section>
|
||||||
|
</Container>
|
||||||
|
</Section>
|
||||||
|
</Body>
|
||||||
|
</Tailwind>
|
||||||
|
</Html>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DocumentPendingEmailTemplate;
|
||||||
5
packages/email/tsconfig.json
Normal file
5
packages/email/tsconfig.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"extends": "@documenso/tsconfig/react-library.json",
|
||||||
|
"include": ["."],
|
||||||
|
"exclude": ["dist", "build", "node_modules"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user