From 3dab20cbc17c91a46b5dba4404a5f889b27ab8ee Mon Sep 17 00:00:00 2001
From: jonkurtis
Date: Thu, 19 Sep 2024 20:54:21 -0400
Subject: [PATCH 1/4] add emails, resend and react-email
---
.env.example | 3 +-
emails/invite.tsx | 138 ++++++++++++++++++++++++++++++++++++++
emails/reset-password.tsx | 98 +++++++++++++++++++++++++++
lib/resend.ts | 3 +
package.json | 11 ++-
5 files changed, 251 insertions(+), 2 deletions(-)
create mode 100644 emails/invite.tsx
create mode 100644 emails/reset-password.tsx
create mode 100644 lib/resend.ts
diff --git a/.env.example b/.env.example
index aa45b7c727..7ef845dc6b 100644
--- a/.env.example
+++ b/.env.example
@@ -4,4 +4,5 @@ POSTGRES_URL=postgresql://***
STRIPE_SECRET_KEY=sk_test_***
STRIPE_WEBHOOK_SECRET=whsec_***
BASE_URL=http://localhost:3000
-AUTH_SECRET=***
\ No newline at end of file
+AUTH_SECRET=***
+RESEND_API_KEY=re_***
\ No newline at end of file
diff --git a/emails/invite.tsx b/emails/invite.tsx
new file mode 100644
index 0000000000..c9daf28b13
--- /dev/null
+++ b/emails/invite.tsx
@@ -0,0 +1,138 @@
+import {
+ Body,
+ Button,
+ Container,
+ Column,
+ Head,
+ Heading,
+ Hr,
+ Html,
+ Img,
+ Link,
+ Preview,
+ Row,
+ Section,
+ Text,
+ Tailwind,
+} from "@react-email/components";
+import { CircleIcon } from "lucide-react";
+import * as React from "react";
+
+interface InviteUserEmailProps {
+ username?: string;
+ userImage?: string;
+ invitedByUsername?: string;
+ invitedByEmail?: string;
+ teamName?: string;
+ teamImage?: string;
+ inviteLink?: string;
+ inviteFromIp?: string;
+ inviteFromLocation?: string;
+}
+
+export const InviteUserEmail = ({
+ username = "ACME user",
+ userImage = "https://demo.react.email/static/vercel-user.png",
+ invitedByUsername = "ACME",
+ invitedByEmail = "acme@acme.com",
+ teamName = "ACME Team",
+ teamImage = "https://demo.react.email/static/vercel-team.png",
+ inviteLink = "https://vercel.com/teams/invite/foo",
+ inviteFromIp = "204.13.186.218",
+ inviteFromLocation = "São Paulo, Brazil",
+}: InviteUserEmailProps) => {
+ const previewText = `Join ${invitedByUsername} on Vercel`;
+
+ return (
+
+
+ {previewText}
+
+
+
+
+
+ Join {teamName} on Vercel
+
+
+ Hello {username},
+
+
+ {invitedByUsername} (
+
+ {invitedByEmail}
+
+ ) has invited you to the {teamName} team on{" "}
+ Vercel.
+
+
+
+
+ or copy and paste this URL into your browser:{" "}
+
+ {inviteLink}
+
+
+
+
+ This invitation was intended for{" "}
+ {username}. This invite was
+ sent from {inviteFromIp}{" "}
+ located in{" "}
+ {inviteFromLocation}. If you
+ were not expecting this invitation, you can ignore this email. If
+ you are concerned about your account's safety, please reply to
+ this email to get in touch with us.
+
+
+
+
+
+ );
+};
+
+export default InviteUserEmail;
diff --git a/emails/reset-password.tsx b/emails/reset-password.tsx
new file mode 100644
index 0000000000..6a89d42fbf
--- /dev/null
+++ b/emails/reset-password.tsx
@@ -0,0 +1,98 @@
+import {
+ Body,
+ Button,
+ Container,
+ Column,
+ Head,
+ Heading,
+ Hr,
+ Html,
+ Img,
+ Link,
+ Preview,
+ Row,
+ Section,
+ Text,
+ Tailwind,
+} from "@react-email/components";
+import * as React from "react";
+import { CircleIcon } from "lucide-react";
+interface ResetPasswordEmailProps {
+ username?: string;
+ userImage?: string;
+ userEmail?: string;
+ resetPasswordLink?: string;
+ resetFromIp?: string;
+ resetFromLocation?: string;
+}
+
+export const ResetPasswordEmail = ({
+ username = "alanturing",
+ userImage = "https://demo.react.email/static/vercel-user.png",
+ userEmail = "alan.turing@example.com",
+ resetPasswordLink = "https://vercel.com/teams/invite/foo",
+ resetFromIp = "204.13.186.218",
+ resetFromLocation = "São Paulo, Brazil",
+}: ResetPasswordEmailProps) => {
+ const previewText = `Reset your password on ACME`;
+
+ return (
+
+