Move emails to dedicated package (#3542)
* Add new package * Add twenty-emails package * Use generated files from twenty-emails in twenty-server * Fix deleted file * Import emails templates properly
This commit is contained in:
@ -1,48 +0,0 @@
|
||||
const grayScale = {
|
||||
gray100: '#000000',
|
||||
gray90: '#141414',
|
||||
gray85: '#171717',
|
||||
gray80: '#1b1b1b',
|
||||
gray75: '#1d1d1d',
|
||||
gray70: '#222222',
|
||||
gray65: '#292929',
|
||||
gray60: '#333333',
|
||||
gray55: '#4c4c4c',
|
||||
gray50: '#666666',
|
||||
gray45: '#818181',
|
||||
gray40: '#999999',
|
||||
gray35: '#b3b3b3',
|
||||
gray30: '#cccccc',
|
||||
gray25: '#d6d6d6',
|
||||
gray20: '#ebebeb',
|
||||
gray15: '#f1f1f1',
|
||||
gray10: '#fcfcfc',
|
||||
gray0: '#ffffff',
|
||||
};
|
||||
|
||||
export const emailTheme = {
|
||||
font: {
|
||||
colors: {
|
||||
highlighted: grayScale.gray60,
|
||||
primary: grayScale.gray50,
|
||||
inverted: grayScale.gray0,
|
||||
},
|
||||
weight: {
|
||||
regular: 400,
|
||||
bold: 600,
|
||||
},
|
||||
size: {
|
||||
md: '13px',
|
||||
lg: '16px',
|
||||
},
|
||||
},
|
||||
background: {
|
||||
colors: { highlight: grayScale.gray15 },
|
||||
radialGradient: `radial-gradient(50% 62.62% at 50% 0%, #505050 0%, ${grayScale.gray60} 100%)`,
|
||||
radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, #505050 0%, ${grayScale.gray60} 100%)`,
|
||||
transparent: {
|
||||
medium: 'rgba(0, 0, 0, 0.08)',
|
||||
light: 'rgba(0, 0, 0, 0.04)',
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -1,17 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { Container, Html } from '@react-email/components';
|
||||
|
||||
import { BaseHead } from 'src/emails/components/BaseHead';
|
||||
import { Logo } from 'src/emails/components/Logo';
|
||||
|
||||
export const BaseEmail = ({ children }) => {
|
||||
return (
|
||||
<Html lang="en">
|
||||
<BaseHead />
|
||||
<Container width={290}>
|
||||
<Logo />
|
||||
{children}
|
||||
</Container>
|
||||
</Html>
|
||||
);
|
||||
};
|
||||
@ -1,22 +0,0 @@
|
||||
import { Font, Head } from '@react-email/components';
|
||||
import * as React from 'react';
|
||||
|
||||
import { emailTheme } from 'src/emails/common-style';
|
||||
|
||||
export const BaseHead = () => {
|
||||
return (
|
||||
<Head>
|
||||
<title>Twenty email</title>
|
||||
<Font
|
||||
fontFamily="Inter"
|
||||
fallbackFontFamily="sans-serif"
|
||||
webFont={{
|
||||
url: 'https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap',
|
||||
format: 'woff2',
|
||||
}}
|
||||
fontStyle="normal"
|
||||
fontWeight={emailTheme.font.weight.regular}
|
||||
/>
|
||||
</Head>
|
||||
);
|
||||
};
|
||||
@ -1,23 +0,0 @@
|
||||
import { Button } from '@react-email/button';
|
||||
import * as React from 'react';
|
||||
|
||||
import { emailTheme } from 'src/emails/common-style';
|
||||
const callToActionStyle = {
|
||||
display: 'flex',
|
||||
padding: '8px 32px',
|
||||
borderRadius: '8px',
|
||||
border: `1px solid ${emailTheme.background.transparent.light}`,
|
||||
background: emailTheme.background.radialGradient,
|
||||
boxShadow: `0px 2px 4px 0px ${emailTheme.background.transparent.light}, 0px 0px 4px 0px ${emailTheme.background.transparent.medium}`,
|
||||
color: emailTheme.font.colors.inverted,
|
||||
fontSize: emailTheme.font.size.md,
|
||||
fontWeight: emailTheme.font.weight.bold,
|
||||
};
|
||||
|
||||
export const CallToAction = ({ value, href }) => {
|
||||
return (
|
||||
<Button href={href} style={callToActionStyle}>
|
||||
{value}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@ -1,30 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { Row } from '@react-email/row';
|
||||
import { Text } from '@react-email/text';
|
||||
import { Column } from '@react-email/components';
|
||||
|
||||
import { emailTheme } from 'src/emails/common-style';
|
||||
|
||||
const rowStyle = {
|
||||
display: 'flex',
|
||||
};
|
||||
|
||||
const highlightedStyle = {
|
||||
borderRadius: '4px',
|
||||
background: emailTheme.background.colors.highlight,
|
||||
padding: '4px 8px',
|
||||
margin: 0,
|
||||
fontSize: emailTheme.font.size.lg,
|
||||
fontWeight: emailTheme.font.weight.bold,
|
||||
color: emailTheme.font.colors.highlighted,
|
||||
};
|
||||
|
||||
export const HighlightedText = ({ value }) => {
|
||||
return (
|
||||
<Row style={rowStyle}>
|
||||
<Column>
|
||||
<Text style={highlightedStyle}>{value}</Text>
|
||||
</Column>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
@ -1,17 +0,0 @@
|
||||
import { Img } from '@react-email/components';
|
||||
|
||||
const logoStyle = {
|
||||
marginBottom: '40px',
|
||||
};
|
||||
|
||||
export const Logo = () => {
|
||||
return (
|
||||
<Img
|
||||
src="https://app.twenty.com/icons/windows11/Square150x150Logo.scale-100.png"
|
||||
alt="Twenty logo"
|
||||
width="40"
|
||||
height="40"
|
||||
style={logoStyle}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -1,14 +0,0 @@
|
||||
import { Text } from '@react-email/text';
|
||||
import * as React from 'react';
|
||||
|
||||
import { emailTheme } from 'src/emails/common-style';
|
||||
|
||||
const mainTextStyle = {
|
||||
fontSize: emailTheme.font.size.md,
|
||||
fontWeight: emailTheme.font.weight.regular,
|
||||
color: emailTheme.font.colors.primary,
|
||||
};
|
||||
|
||||
export const MainText = ({ children }) => {
|
||||
return <Text style={mainTextStyle}>{children}</Text>;
|
||||
};
|
||||
@ -1,6 +0,0 @@
|
||||
import { Heading } from '@react-email/components';
|
||||
import * as React from 'react';
|
||||
|
||||
export const Title = ({ value }) => {
|
||||
return <Heading as="h1">{value}</Heading>;
|
||||
};
|
||||
@ -3,6 +3,10 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { render } from '@react-email/render';
|
||||
import { Repository } from 'typeorm';
|
||||
import {
|
||||
CleanInactiveWorkspaceEmail,
|
||||
DeleteInactiveWorkspaceEmail,
|
||||
} from 'twenty-emails';
|
||||
|
||||
import { MessageQueueJob } from 'src/integrations/message-queue/interfaces/message-queue-job.interface';
|
||||
|
||||
@ -12,14 +16,12 @@ import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
||||
import { DataSourceEntity } from 'src/metadata/data-source/data-source.entity';
|
||||
import { UserService } from 'src/core/user/services/user.service';
|
||||
import { EmailService } from 'src/integrations/email/email.service';
|
||||
import CleanInactiveWorkspaceEmail from 'src/workspace/cron/clean-inactive-workspaces/clean-inactive-workspaces.email';
|
||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||
import {
|
||||
FeatureFlagEntity,
|
||||
FeatureFlagKeys,
|
||||
} from 'src/core/feature-flag/feature-flag.entity';
|
||||
import { ObjectMetadataEntity } from 'src/metadata/object-metadata/object-metadata.entity';
|
||||
import DeleteInactiveWorkspaceEmail from 'src/workspace/cron/clean-inactive-workspaces/delete-inactive-workspaces.email';
|
||||
import { computeObjectTargetTable } from 'src/workspace/utils/compute-object-target-table.util';
|
||||
|
||||
const MILLISECONDS_IN_ONE_DAY = 1000 * 3600 * 24;
|
||||
|
||||
@ -1,50 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { HighlightedText } from 'src/emails/components/HighlightedText';
|
||||
import { MainText } from 'src/emails/components/MainText';
|
||||
import { Title } from 'src/emails/components/Title';
|
||||
import { BaseEmail } from 'src/emails/components/BaseEmail';
|
||||
import { CallToAction } from 'src/emails/components/CallToAction';
|
||||
|
||||
type CleanInactiveWorkspaceEmailData = {
|
||||
daysLeft: number;
|
||||
userName: string;
|
||||
workspaceDisplayName: string;
|
||||
};
|
||||
|
||||
export const CleanInactiveWorkspaceEmail = ({
|
||||
daysLeft,
|
||||
userName,
|
||||
workspaceDisplayName,
|
||||
}: CleanInactiveWorkspaceEmailData) => {
|
||||
const dayOrDays = daysLeft > 1 ? 'days' : 'day';
|
||||
const remainingDays = daysLeft > 1 ? `${daysLeft} ` : '';
|
||||
|
||||
const helloString = userName?.length > 1 ? `Hello ${userName}` : 'Hello';
|
||||
|
||||
return (
|
||||
<BaseEmail>
|
||||
<Title value="Inactive Workspace 😴" />
|
||||
<HighlightedText value={`${daysLeft} ${dayOrDays} left`} />
|
||||
<MainText>
|
||||
{helloString},
|
||||
<br />
|
||||
<br />
|
||||
It appears that there has been a period of inactivity on your{' '}
|
||||
<b>{workspaceDisplayName}</b> workspace.
|
||||
<br />
|
||||
<br />
|
||||
Please note that the account is due for deactivation soon, and all
|
||||
associated data within this workspace will be deleted.
|
||||
<br />
|
||||
<br />
|
||||
No need for concern, though! Simply create or edit a record within the
|
||||
next {remainingDays}
|
||||
{dayOrDays} to retain access.
|
||||
</MainText>
|
||||
<CallToAction href="https://app.twenty.com" value="Connect to Twenty" />
|
||||
</BaseEmail>
|
||||
);
|
||||
};
|
||||
|
||||
export default CleanInactiveWorkspaceEmail;
|
||||
@ -1,30 +0,0 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { HighlightedText } from 'src/emails/components/HighlightedText';
|
||||
import { MainText } from 'src/emails/components/MainText';
|
||||
import { Title } from 'src/emails/components/Title';
|
||||
import { BaseEmail } from 'src/emails/components/BaseEmail';
|
||||
import { CallToAction } from 'src/emails/components/CallToAction';
|
||||
|
||||
type DeleteInactiveWorkspaceEmailData = {
|
||||
daysSinceDead: number;
|
||||
workspaceId: string;
|
||||
};
|
||||
|
||||
export const DeleteInactiveWorkspaceEmail = ({
|
||||
daysSinceDead,
|
||||
workspaceId,
|
||||
}: DeleteInactiveWorkspaceEmailData) => {
|
||||
return (
|
||||
<BaseEmail>
|
||||
<Title value="Dead Workspace 😵" />
|
||||
<HighlightedText value={`Inactive since ${daysSinceDead} day(s)`} />
|
||||
<MainText>
|
||||
Workspace <b>{workspaceId}</b> should be deleted.
|
||||
</MainText>
|
||||
<CallToAction href="https://app.twenty.com" value="Connect to Twenty" />
|
||||
</BaseEmail>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteInactiveWorkspaceEmail;
|
||||
Reference in New Issue
Block a user