Skip to content

Commit

Permalink
feat: Auth emails
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-dalmet committed Oct 10, 2023
1 parent e58aa06 commit 561b083
Show file tree
Hide file tree
Showing 16 changed files with 272 additions and 165 deletions.
2 changes: 1 addition & 1 deletion src/emails/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const Footer = () => {
return (
<Section style={styles.footer}>
<Link style={styles.link} href="https://start-ui.com" target="_blank">
Start UI
🚀 Start UI
</Link>
<br />
Opinionated UI starters
Expand Down
15 changes: 12 additions & 3 deletions src/emails/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,32 @@ export const styles = {
text: {
color: theme.colors.text,
fontFamily: theme.fontFamily.sans,
fontSize: '16px',
margin: '8px 0',
lineHeight: '1.5',
},
textMuted: {
color: theme.colors.textMuted,
fontFamily: theme.fontFamily.sans,
fontSize: '14px',
margin: '8px 0',
lineHeight: '1.5',
},
code: {
display: 'inline-block',
padding: '12px 16px',
width: '100%',
wordBreak: 'break-all',
fontSize: '12px',
letterSpacing: '2px',
margin: '8px 0',
fontSize: '32px',
fontFamily: theme.fontFamily.code,
backgroundColor: '#f4f4f4',
borderRadius: '5px',
border: '1px solid #eee',
color: theme.colors.text,
},
footer: {
color: '#898989',
color: theme.colors.textMuted,
fontFamily: theme.fontFamily.sans,
fontSize: '12px',
lineHeight: '22px',
Expand Down
64 changes: 0 additions & 64 deletions src/emails/templates/activate-account.tsx

This file was deleted.

38 changes: 19 additions & 19 deletions src/emails/templates/login-code.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
import {
Button,
Container,
Heading,
Section,
Text,
} from '@react-email/components';
import { Container, Heading, Section, Text } from '@react-email/components';

import { Footer } from '@/emails/components/Footer';
import { Layout } from '@/emails/components/Layout';
import { styles } from '@/emails/styles';
import { VALIDATION_TOKEN_EXPIRATION_IN_MINUTES } from '@/features/auth/utils';
import i18n from '@/lib/i18n/server';

type EmailLoginCodeProps = {
language: string;
name: string;
code: string;
};

export const EmailLoginCode = ({ language, code }: EmailLoginCodeProps) => {
export const EmailLoginCode = ({
language,
name,
code,
}: EmailLoginCodeProps) => {
i18n.changeLanguage(language);
return (
<Layout preview="TODO">
<Layout preview={i18n.t('emails:loginCode.preview')}>
<Container style={styles.container}>
<Heading style={styles.h1}>{code}</Heading>
<Heading style={styles.h1}>{i18n.t('emails:loginCode.title')}</Heading>
<Section style={styles.section}>
<Text style={styles.text}>
"TODO"
{i18n.t('emails:loginCode.hello', { name: name ?? '' })}
<br />
"TODO"
{i18n.t('emails:loginCode.intro')}
</Text>
<Text style={styles.code}>{code}</Text>
<Text style={styles.textMuted}>
{i18n.t('emails:loginCode.validityTime', {
expiration: VALIDATION_TOKEN_EXPIRATION_IN_MINUTES,
})}
<br />
{i18n.t('emails:loginCode.ignoreHelper')}
</Text>
<Button pY={12} pX={20} style={styles.button} target="_blank">
"TODO"
</Button>
</Section>
<Section style={styles.section}>
<Text style={styles.text}>"TODO"</Text>
<Text style={styles.text}>"TODO" email.</Text>
</Section>
<Footer />
</Container>
Expand Down
50 changes: 50 additions & 0 deletions src/emails/templates/login-not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
Button,
Container,
Heading,
Section,
Text,
} from '@react-email/components';

import { Footer } from '@/emails/components/Footer';
import { Layout } from '@/emails/components/Layout';
import { styles } from '@/emails/styles';
import { env } from '@/env.mjs';
import i18n from '@/lib/i18n/server';

type EmailLoginNotFoundProps = {
language: string;
};

export const EmailLoginNotFound = ({ language }: EmailLoginNotFoundProps) => {
i18n.changeLanguage(language);
return (
<Layout preview={i18n.t('emails:loginNotFound.preview')}>
<Container style={styles.container}>
<Heading style={styles.h1}>
{i18n.t('emails:loginNotFound.title')}
</Heading>
<Section style={styles.section}>
<Text style={styles.text}>
{i18n.t('emails:loginNotFound.intro')}
</Text>
<Button
pY={12}
pX={20}
style={styles.button}
href={`${env.NEXT_PUBLIC_BASE_URL}/login`}
target="_blank"
>
{i18n.t('emails:loginNotFound.button')}
</Button>
<Text style={styles.textMuted}>
{i18n.t('emails:loginNotFound.ignoreHelper')}
</Text>
</Section>
<Footer />
</Container>
</Layout>
);
};

export default EmailLoginNotFound;
48 changes: 48 additions & 0 deletions src/emails/templates/register-code.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Container, Heading, Section, Text } from '@react-email/components';

import { Footer } from '@/emails/components/Footer';
import { Layout } from '@/emails/components/Layout';
import { styles } from '@/emails/styles';
import { VALIDATION_TOKEN_EXPIRATION_IN_MINUTES } from '@/features/auth/utils';
import i18n from '@/lib/i18n/server';

type EmailRegisterCodeProps = {
language: string;
name?: string;
code: string;
};

export const EmailRegisterCode = ({
language,
name,
code,
}: EmailRegisterCodeProps) => {
i18n.changeLanguage(language);
return (
<Layout preview={i18n.t('emails:registerCode.preview')}>
<Container style={styles.container}>
<Heading style={styles.h1}>
{i18n.t('emails:registerCode.title')}
</Heading>
<Section style={styles.section}>
<Text style={styles.text}>
{i18n.t('emails:registerCode.hello', { name: name ?? '' })}
<br />
{i18n.t('emails:registerCode.intro')}
</Text>
<Text style={styles.code}>{code}</Text>
<Text style={styles.textMuted}>
{i18n.t('emails:registerCode.validityTime', {
expiration: VALIDATION_TOKEN_EXPIRATION_IN_MINUTES,
})}
<br />
{i18n.t('emails:registerCode.ignoreHelper')}
</Text>
</Section>
<Footer />
</Container>
</Layout>
);
};

export default EmailRegisterCode;
4 changes: 3 additions & 1 deletion src/emails/theme.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
export const theme = {
fontFamily: {
sans: "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
code: 'monospace',
},
colors: {
white: '#ffffff',
black: '#000000',
text: '#333',
text: '#222',
textMuted: '#666',
brand: '#2563eb',
},
} as const;
3 changes: 3 additions & 0 deletions src/locales/ar/auth.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
"login": "تسجيل الدخول",
"needAccount": "هل تحتاج إلى حساب؟",
"register": "سجل الآن!"
},
"code": {
"title": "تحقق من صندوق الوارد الخاص بك للحصول على الرمز"
}
},
"resetPassword": {
Expand Down
38 changes: 22 additions & 16 deletions src/locales/ar/emails.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
{
"resetPassword": {
"copyPastHelper": "أو انسخ هذا الرابط والصقه في متصفحك:",
"ignoreHelper": "إذا لم تحاول إعادة تعيين كلمة المرور الخاصة بك، فيمكنك تجاهل هذا البريد الإلكتروني بأمان.",
"link": "إعادة تعيين كلمة المرور",
"preview": "رابط لتحديث كلمة المرور الخاصة بك",
"subject": "اعد ضبط كلمه السر",
"title": "إعادة تعيين كلمة المرور",
"hello": "مرحبًا {{اسم}}،",
"intro": "طلب شخص ما مؤخرًا تغيير كلمة المرور لحسابك. \nإذا كنت أنت، فيمكنك تعيين كلمة مرور جديدة هنا:"
"loginCode": {
"hello": "مرحبًا بعودتك {{اسم}}،",
"ignoreHelper": "إذا لم تحاول تسجيل الدخول، فيمكنك تجاهل هذه الرسالة الإلكترونية بأمان.",
"intro": "هذا هو رمز التحقق الخاص بك:",
"preview": "رمز التحقق لتسجيل الدخول",
"subject": "تسجيل الدخول رمز التحقق",
"title": "تسجيل الدخول رمز التحقق",
"validityTime": "سيكون هذا الرمز صالحًا فقط لمدة {{expiration}} الدقائق التالية."
},
"loginNotFound": {
"button": "جرب بريدًا إلكترونيًا مختلفًا",
"ignoreHelper": "إذا لم تحاول تسجيل الدخول، فيمكنك تجاهل هذه الرسالة الإلكترونية بأمان.",
"intro": "يبدو أنه لا يوجد حساب مرتبط بعنوان البريد الإلكتروني هذا.",
"preview": "هل هذا هو البريد الإلكتروني الصحيح؟",
"subject": "الحساب غير موجود",
"title": "هل هذا هو البريد الإلكتروني الصحيح؟"
},
"activateAccount": {
"copyPastHelper": "أو انسخ هذا الرابط والصقه في متصفحك:",
"registerCode": {
"validityTime": "سيكون هذا الرمز صالحًا فقط لمدة {{expiration}} الدقائق التالية.",
"hello": "مرحبًا {{اسم}}،",
"ignoreHelper": "إذا لم تحاول التسجيل، يمكنك تجاهل هذه الرسالة الإلكترونية بأمان.",
"intro": "مرحبًا، حسابك جاهز تقريبًا، قم بتفعيله للبدء:",
"link": "تفعيل حساب",
"preview": "رابط لتفعيل حسابك",
"subject": "فعل حسابك",
"title": "تفعيل حساب"
"intro": "حسابك جاهز تقريبًا! \nهذا هو رمز التحقق الخاص بك:",
"preview": "رمز التحقق",
"subject": "تحقق من حسابك",
"title": "تحقق من حسابك"
}
}
2 changes: 1 addition & 1 deletion src/locales/en/auth.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"register": "Register Now!"
},
"code": {
"title": "Check your email for a code"
"title": "Check your inbox for the code"
}
},
"register": {
Expand Down
43 changes: 24 additions & 19 deletions src/locales/en/emails.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
{
"resetPassword": {
"subject": "Reset your password",
"preview": "Link to update your password",
"hello": "Hi {{name}},",
"intro": "Someone recently requested a password change for you account. If this was you, you can set a new password here:",
"title": "Reset password",
"link": "Reset password",
"copyPastHelper": "Or, copy and paste this link to your browser:",
"ignoreHelper": "If you didn't try to reset your password, you can safely ignore this email."
},
"activateAccount": {
"subject": "Activate your account",
"preview": "Link to activate your account",
"title": "Activate account",
"hello": "Hi {{name}},",
"intro": "Welcome, you account is almost ready, activate it to start:",
"link": "Activate account",
"copyPastHelper": "Or, copy and paste this link to your browser:",
"registerCode": {
"subject": "Verify your account",
"preview": "Your verification code",
"title": "Verify your account",
"hello": "Welcome {{name}},",
"intro": "Your account is almost ready! This is your verification code:",
"validityTime": "This code will only be valid for the next {{expiration}} minutes.",
"ignoreHelper": "If you didn't try to register, you can safely ignore this email."
},
"loginCode": {}
"loginCode": {
"subject": "Sign in verification code",
"preview": "Verification code to sign in",
"title": "Sign in verification code",
"hello": "Welcome back {{name}},",
"intro": "This is your verification code:",
"validityTime": "This code will only be valid for the next {{expiration}} minutes.",
"ignoreHelper": "If you didn't try to sign in, you can safely ignore this email."
},
"loginNotFound": {
"subject": "Account not found",
"preview": "Is this the right email?",
"title": "Is this the right email?",
"intro": "It looks like there isn't an account tied to this email address.",
"button": "Try a different email",
"ignoreHelper": "If you didn't try to sign in, you can safely ignore this email."
}
}
Loading

0 comments on commit 561b083

Please sign in to comment.