mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
improve email formatting and invite flow for new users
This commit is contained in:
@@ -6,6 +6,7 @@ import logger from "@server/logger";
|
||||
export async function sendEmail(
|
||||
template: ReactElement,
|
||||
opts: {
|
||||
name: string | undefined;
|
||||
from: string | undefined;
|
||||
to: string | undefined;
|
||||
subject: string;
|
||||
@@ -23,14 +24,15 @@ export async function sendEmail(
|
||||
|
||||
const emailHtml = await render(template);
|
||||
|
||||
const options = {
|
||||
from: opts.from,
|
||||
await emailClient.sendMail({
|
||||
from: {
|
||||
name: opts.name || "Pangolin Proxy",
|
||||
address: opts.from,
|
||||
},
|
||||
to: opts.to,
|
||||
subject: opts.subject,
|
||||
html: emailHtml,
|
||||
};
|
||||
|
||||
await emailClient.sendMail(options);
|
||||
});
|
||||
}
|
||||
|
||||
export default sendEmail;
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Tailwind
|
||||
} from "@react-email/components";
|
||||
import * as React from "react";
|
||||
import LetterHead from "./components/LetterHead";
|
||||
|
||||
interface Props {
|
||||
email: string;
|
||||
@@ -35,15 +36,7 @@ export const ConfirmPasswordReset = ({ email }: Props) => {
|
||||
>
|
||||
<Body className="font-sans relative">
|
||||
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8 rounded-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm font-bold text-orange-500">
|
||||
Pangolin
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-gray-500">
|
||||
{new Date().toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<LetterHead />
|
||||
|
||||
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
||||
Password Reset Confirmation
|
||||
@@ -56,10 +49,6 @@ export const ConfirmPasswordReset = ({ email }: Props) => {
|
||||
reset. If you made this change, no further action is
|
||||
required.
|
||||
</Text>
|
||||
<Text className="text-base text-gray-700">
|
||||
If you did not request this change, please contact
|
||||
our support team immediately.
|
||||
</Text>
|
||||
<Text className="text-base text-gray-700 mt-2">
|
||||
Thank you for keeping your account secure.
|
||||
</Text>
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Tailwind
|
||||
} from "@react-email/components";
|
||||
import * as React from "react";
|
||||
import LetterHead from "./components/LetterHead";
|
||||
|
||||
interface Props {
|
||||
email: string;
|
||||
@@ -18,7 +19,7 @@ interface Props {
|
||||
}
|
||||
|
||||
export const ResetPasswordCode = ({ email, code, link }: Props) => {
|
||||
const previewText = `Reset your password, ${email}`;
|
||||
const previewText = `Your password reset code is ${code}`;
|
||||
|
||||
return (
|
||||
<Html>
|
||||
@@ -37,15 +38,7 @@ export const ResetPasswordCode = ({ email, code, link }: Props) => {
|
||||
>
|
||||
<Body className="font-sans">
|
||||
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8 rounded-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm font-bold text-orange-500">
|
||||
Pangolin
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-gray-500">
|
||||
{new Date().toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<LetterHead />
|
||||
|
||||
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
||||
Password Reset Request
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Tailwind
|
||||
} from "@react-email/components";
|
||||
import * as React from "react";
|
||||
import LetterHead from "./components/LetterHead";
|
||||
|
||||
interface ResourceOTPCodeProps {
|
||||
email?: string;
|
||||
@@ -24,7 +25,7 @@ export const ResourceOTPCode = ({
|
||||
orgName: organizationName,
|
||||
otp
|
||||
}: ResourceOTPCodeProps) => {
|
||||
const previewText = `Your one-time password for ${resourceName} is ready!`;
|
||||
const previewText = `Your one-time password for ${resourceName} is ${otp}`;
|
||||
|
||||
return (
|
||||
<Html>
|
||||
@@ -43,27 +44,18 @@ export const ResourceOTPCode = ({
|
||||
>
|
||||
<Body className="font-sans">
|
||||
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8 rounded-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm font-bold text-orange-500">
|
||||
Pangolin
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-gray-500">
|
||||
{new Date().toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<LetterHead />
|
||||
|
||||
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
||||
Your One-Time Password
|
||||
Your One-Time Password for {resourceName}
|
||||
</Heading>
|
||||
<Text className="text-base text-gray-700 mt-4">
|
||||
Hi {email || "there"},
|
||||
</Text>
|
||||
<Text className="text-base text-gray-700 mt-2">
|
||||
You’ve requested a one-time password (OTP) to
|
||||
authenticate with the resource{" "}
|
||||
You’ve requested a one-time password to access{" "}
|
||||
<strong>{resourceName}</strong> in{" "}
|
||||
<strong>{organizationName}</strong>. Use the OTP
|
||||
<strong>{organizationName}</strong>. Use the code
|
||||
below to complete your authentication:
|
||||
</Text>
|
||||
<Section className="text-center">
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
Button
|
||||
} from "@react-email/components";
|
||||
import * as React from "react";
|
||||
import LetterHead from "./components/LetterHead";
|
||||
|
||||
interface SendInviteLinkProps {
|
||||
email: string;
|
||||
@@ -27,7 +28,7 @@ export const SendInviteLink = ({
|
||||
inviterName,
|
||||
expiresInDays
|
||||
}: SendInviteLinkProps) => {
|
||||
const previewText = `${inviterName} invited to join ${orgName}`;
|
||||
const previewText = `${inviterName} invited you to join ${orgName}`;
|
||||
|
||||
return (
|
||||
<Html>
|
||||
@@ -46,18 +47,10 @@ export const SendInviteLink = ({
|
||||
>
|
||||
<Body className="font-sans">
|
||||
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8 rounded-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm font-bold text-orange-500">
|
||||
Pangolin
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-gray-500">
|
||||
{new Date().toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<LetterHead />
|
||||
|
||||
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
||||
You're Invite to Join {orgName}
|
||||
Invited to Join {orgName}
|
||||
</Heading>
|
||||
<Text className="text-base text-gray-700 mt-4">
|
||||
Hi {email || "there"},
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Tailwind
|
||||
} from "@react-email/components";
|
||||
import * as React from "react";
|
||||
import LetterHead from "./components/LetterHead";
|
||||
|
||||
interface Props {
|
||||
email: string;
|
||||
@@ -36,15 +37,7 @@ export const TwoFactorAuthNotification = ({ email, enabled }: Props) => {
|
||||
>
|
||||
<Body className="font-sans">
|
||||
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8 rounded-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm font-bold text-orange-500">
|
||||
Pangolin
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-gray-500">
|
||||
{new Date().toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<LetterHead />
|
||||
|
||||
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
||||
Two-Factor Authentication{" "}
|
||||
@@ -71,10 +64,6 @@ export const TwoFactorAuthNotification = ({ email, enabled }: Props) => {
|
||||
enabling it to protect your account.
|
||||
</Text>
|
||||
)}
|
||||
<Text className="text-base text-gray-700 mt-2">
|
||||
If you did not make this change, please contact our
|
||||
support team immediately.
|
||||
</Text>
|
||||
<Text className="text-sm text-gray-500 mt-6">
|
||||
Best regards,
|
||||
<br />
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Tailwind
|
||||
} from "@react-email/components";
|
||||
import * as React from "react";
|
||||
import LetterHead from "./components/LetterHead";
|
||||
|
||||
interface VerifyEmailProps {
|
||||
username?: string;
|
||||
@@ -22,7 +23,7 @@ export const VerifyEmail = ({
|
||||
verificationCode,
|
||||
verifyLink
|
||||
}: VerifyEmailProps) => {
|
||||
const previewText = `Verify your email, ${username}`;
|
||||
const previewText = `Your verification code is ${verificationCode}`;
|
||||
|
||||
return (
|
||||
<Html>
|
||||
@@ -41,15 +42,7 @@ export const VerifyEmail = ({
|
||||
>
|
||||
<Body className="font-sans">
|
||||
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8 rounded-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="text-sm font-bold text-orange-500">
|
||||
Pangolin
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-gray-500">
|
||||
{new Date().toLocaleDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<LetterHead />
|
||||
|
||||
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
||||
Please Verify Your Email
|
||||
|
||||
36
server/emails/templates/components/LetterHead.tsx
Normal file
36
server/emails/templates/components/LetterHead.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React from "react";
|
||||
|
||||
export function LetterHead() {
|
||||
return (
|
||||
<table
|
||||
role="presentation"
|
||||
width="100%"
|
||||
style={{
|
||||
marginBottom: "24px"
|
||||
}}
|
||||
>
|
||||
<tr>
|
||||
<td
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
fontWeight: "bold",
|
||||
color: "#F97317"
|
||||
}}
|
||||
>
|
||||
Pangolin
|
||||
</td>
|
||||
<td
|
||||
style={{
|
||||
fontSize: "14px",
|
||||
textAlign: "right",
|
||||
color: "#6B7280"
|
||||
}}
|
||||
>
|
||||
{new Date().getFullYear()}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
export default LetterHead;
|
||||
Reference in New Issue
Block a user