-
Notifications
You must be signed in to change notification settings - Fork 419
feat: add react email implementation #574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e24f137
83c3a09
ebeea58
1d9e429
57304d9
13e3dc4
1fddd94
0fcf496
654ade3
4d12572
8c0dc52
a333e39
2e97336
a8b0e42
d00c427
bfb2348
b377549
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { initConfig } from '../../config/init'; | ||
| import { runCommand } from '../../lib/runCommand'; | ||
| import { BaseCommand } from '../../baseCommand'; | ||
|
|
||
| export default class EmailsPreview extends BaseCommand<typeof EmailsPreview> { | ||
| static description = 'Runs emails preview'; | ||
|
|
||
| static examples = [`$ <%= config.bin %> <%= command.id %>`]; | ||
|
|
||
| async run(): Promise<void> { | ||
| await initConfig(this, {}); | ||
|
|
||
| await runCommand('pnpm', ['nx', 'run', 'webapp-emails:preview']); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,16 +7,16 @@ SaaS Boilerplate offers an email system functionality out of the box, providing | |
| engage users through email. This functionality covers everything from creating and sending email templates to scheduling | ||
| emails and sending test emails for debugging purposes. | ||
|
|
||
| ### Lively email templates in React using Storybooks | ||
| ### Lively email templates in React using React.Email | ||
|
|
||
| The email system functionality allows developers to build lively templates in React using Storybooks, allowing them to | ||
| get creative with their email designs. Storybooks provide a live development environment for building UI components, | ||
| The email system functionality allows developers to build lively templates in React using React.Email, allowing them to | ||
| get creative with their email designs. React.Email provide a live development environment for building UI components, | ||
| making it easier to develop and test email templates before they are sent. | ||
|
|
||
| ### Standard email templates | ||
|
|
||
| The functionality includes a set of ready-to-send transactional emails, such as *new user verification*, *password | ||
| recovery*, *subscription renewals* making it easy for developers to get started. | ||
| The functionality includes a set of ready-to-send transactional emails, such as _new user verification_, _password | ||
| recovery_, _subscription renewals_ making it easy for developers to get started. | ||
|
|
||
| ### Creating new email templates | ||
|
|
||
|
|
@@ -29,7 +29,7 @@ emails at the most optimal time for their users. | |
|
|
||
| ### Sending test emails | ||
|
|
||
| Sending test emails is made easy with the ability to send test emails directly from a Storybook to Mailcatcher service. | ||
| Sending test emails is made easy with the ability to send test emails directly from a React.Email via Resend. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Built-in Resend works fine, but I haven't managed to send the image (logo). |
||
| This allows developers to debug and test their email templates before they are sent to users. | ||
|
|
||
| ### Internationalization Support | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // jest.polyfills.js | ||
| /** | ||
| * @note The block below contains polyfills for Node.js globals | ||
| * required for Jest to function when running JSDOM tests. | ||
| * These HAVE to be require's and HAVE to be in this exact | ||
| * order, since "undici" depends on the "TextEncoder" global API. | ||
| * | ||
| * Consider migrating to a more modern test runner if | ||
| * you don't want to deal with this. | ||
| */ | ||
|
|
||
| const { TextDecoder, TextEncoder } = require('node:util'); | ||
|
|
||
| // eslint-disable-next-line no-undef | ||
| Object.defineProperties(globalThis, { | ||
| TextDecoder: { value: TextDecoder }, | ||
| TextEncoder: { value: TextEncoder }, | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,13 +6,18 @@ | |
| "test": "jest", | ||
| "test:watch": "jest --watch", | ||
| "lint": "eslint .", | ||
| "type-check": "tsc --noEmit --project tsconfig.lib.json" | ||
| "type-check": "tsc --noEmit --project tsconfig.lib.json", | ||
| "preview": "email dev --dir src/preview -p 1081 " | ||
| }, | ||
| "dependencies": { | ||
| "@react-email/components": "0.0.18", | ||
| "@react-email/font": "0.0.6", | ||
| "@react-email/tailwind": "0.0.17", | ||
| "@sb/webapp-api-client": "workspace:*", | ||
| "@sb/webapp-core": "workspace:*", | ||
| "@sb/webapp-finances": "workspace:*", | ||
| "juice": "^8.1.0" | ||
| "juice": "^8.1.0", | ||
| "react-email": "2.1.3" | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. niticking: I'm thinking of moving |
||
| }, | ||
| "devDependencies": { | ||
| "@esbuild-plugins/node-globals-polyfill": "^0.2.3", | ||
|
|
||
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,3 @@ | ||
| export * from './base.styles'; | ||
|
|
||
| export { Image } from './image'; | ||
| export { Layout } from './layout'; | ||
| export { Button } from './button'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,3 @@ | ||
| export { Layout } from './layout.component'; | ||
| import Layout from './layout.component'; | ||
|
|
||
| export { Layout }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,35 +1,69 @@ | ||
| import { Body, Container, Font, Head, Heading, Html, Section, Tailwind, Text } from '@react-email/components'; | ||
| import { ENV } from '@sb/webapp-core/config/env'; | ||
| import { fontFamily, fontWeight } from '@sb/webapp-core/theme'; | ||
| import { ReactNode } from 'react'; | ||
|
|
||
| import { Image } from '../image'; | ||
| import { Container, Table, Td, Text, Title, Tr } from './layout.styles'; | ||
|
|
||
| export type LayoutProps = { | ||
| title: ReactNode; | ||
| text: ReactNode; | ||
| children?: ReactNode; | ||
| }; | ||
|
|
||
| export const Layout = ({ title, text, children }: LayoutProps) => { | ||
| const baseURL = ENV.EMAIL_ASSETS_URL || `/static`; | ||
|
|
||
| export default function Layout({ title, text, children }: LayoutProps) { | ||
| return ( | ||
| <Container> | ||
| <Table> | ||
| <Tr> | ||
| <Td> | ||
| <Image style={{ display: 'block', margin: '0 auto', width: 256 }} src="logo.png" /> | ||
| </Td> | ||
| </Tr> | ||
| <Tr> | ||
| <Title>{title}</Title> | ||
| </Tr> | ||
|
|
||
| <Tr> | ||
| <Text>{text}</Text> | ||
| </Tr> | ||
|
|
||
| <Tr> | ||
| <Td>{children}</Td> | ||
| </Tr> | ||
| </Table> | ||
| </Container> | ||
| <Html> | ||
| <Head> | ||
| <Font | ||
| fontFamily={fontFamily.primary} | ||
| fallbackFontFamily="Verdana" | ||
| webFont={{ | ||
| url: `${baseURL}/Inter-Regular.woff`, | ||
| format: 'woff', | ||
| }} | ||
| fontWeight={fontWeight.regular} | ||
| fontStyle="normal" | ||
| /> | ||
|
|
||
| <Font | ||
| fontFamily={fontFamily.primary} | ||
| fallbackFontFamily="Verdana" | ||
| webFont={{ | ||
| url: `${baseURL}/Inter-SemiBold.woff`, | ||
| format: 'woff', | ||
| }} | ||
| fontWeight={fontWeight.bold} | ||
| fontStyle="normal" | ||
| /> | ||
| </Head> | ||
| <Tailwind | ||
| config={{ | ||
| theme: { | ||
| extend: { | ||
| fontFamily: { | ||
| custom: [fontFamily.primary], | ||
| }, | ||
| }, | ||
| }, | ||
| }} | ||
| > | ||
| <Body className="bg-white my-auto mx-auto font-sans p-8"> | ||
| <Container className="border border-solid border-[#eaeaea] rounded mx-auto max-w-[548px] p-10"> | ||
| <Image src="logo.png" width={256} className="mt-0 mx-auto" /> | ||
|
|
||
| <Heading className="text-black text-[24px] text-center p-0 my-[30px] mx-0 font-custom font-bold"> | ||
| {title} | ||
| </Heading> | ||
|
|
||
| <Text className="text-black text-[14px] leading-[24px] text-center font-custom">{text}</Text> | ||
|
|
||
| <Section className="text-center">{children}</Section> | ||
| </Container> | ||
| </Body> | ||
| </Tailwind> | ||
| </Html> | ||
| ); | ||
| }; | ||
| } |
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.