-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added email sending feature to template
- Loading branch information
1 parent
4131441
commit 1a366a5
Showing
16 changed files
with
344 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
"use client"; | ||
import Link from "next/link"; | ||
import { emailSchema } from "@/lib/email/utils"; | ||
import { useRef, useState } from "react"; | ||
import { z } from "zod"; | ||
import { Button } from "@/components/ui/button"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Label } from "@/components/ui/label"; | ||
|
||
type FormInput = z.infer<typeof emailSchema>; | ||
type Errors = { [K in keyof FormInput]: string[] }; | ||
|
||
export default function Page() { | ||
const [sending, setSending] = useState(false); | ||
const [errors, setErrors] = useState<Errors | null>(null); | ||
const nameInputRef = useRef<HTMLInputElement>(null); | ||
const emailInputRef = useRef<HTMLInputElement>(null); | ||
|
||
const sendEmail = async () => { | ||
setSending(true); | ||
setErrors(null); | ||
try { | ||
const payload = emailSchema.parse({ | ||
name: nameInputRef.current?.value, | ||
email: emailInputRef.current?.value, | ||
}); | ||
console.log(payload); | ||
const req = await fetch("/api/email", { | ||
method: "POST", | ||
body: JSON.stringify(payload), | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
}); | ||
const { id } = await req.json(); | ||
if (id) alert("Successfully sent!"); | ||
} catch (err) { | ||
if (err instanceof z.ZodError) { | ||
setErrors(err.flatten().fieldErrors as Errors); | ||
} | ||
} finally { | ||
setSending(false); | ||
} | ||
}; | ||
return ( | ||
<main className="max-w-2xl mx-auto p-4 md:p-0"> | ||
<div> | ||
<h1 className="text-2xl font-bold my-4">Send Email with Resend</h1> | ||
<div> | ||
<ol className="list-decimal list-inside space-y-1"> | ||
<li> | ||
<Link | ||
className="text-primary hover:text-muted-foreground underline" | ||
href="https://resend.com/signup" | ||
> | ||
Sign up | ||
</Link>{" "} | ||
or{" "} | ||
<Link | ||
className="text-primary hover:text-muted-foreground underline" | ||
href="https://resend.com/login" | ||
> | ||
Login | ||
</Link>{" "} | ||
to your Resend account | ||
</li> | ||
<li>Add and verify your domain</li> | ||
<li> | ||
Create an API Key and add to{" "} | ||
<span className="ml-1 font-mono font-thin bg-zinc-100 dark:bg-slate-800 p-0.5"> | ||
.env | ||
</span> | ||
</li> | ||
<li> | ||
Update "from:" in{" "} | ||
<span className="ml-1 font-mono font-thin bg-zinc-100 dark:bg-slate-800 p-0.5"> | ||
app/api/email/route.ts | ||
</span> | ||
</li> | ||
<li>Send email 🎉</li> | ||
</ol> | ||
</div> | ||
</div> | ||
<form | ||
onSubmit={(e) => e.preventDefault()} | ||
className="space-y-3 pt-4 border-t mt-4" | ||
> | ||
{errors && <p className="p-3">{JSON.stringify(errors, null, 2)}</p>} | ||
<div> | ||
<Label className="text-muted-foreground">Name</Label> | ||
<Input type="text" placeholder="Tim" name="name" ref={nameInputRef} /> | ||
</div> | ||
<div> | ||
<Label className="text-muted-foreground">Email</Label> | ||
<Input | ||
type="email" | ||
placeholder="tim@apple.com" | ||
name="email" | ||
ref={emailInputRef} | ||
/> | ||
</div> | ||
<Button onClick={() => sendEmail()} disabled={sending}> | ||
{sending ? "sending..." : "Send Email"} | ||
</Button> | ||
</form> | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { EmailTemplate } from "@/components/emails/FirstEmail"; | ||
import { resend } from "@/lib/email"; | ||
import { emailSchema } from "@/lib/email/utils"; | ||
import { NextResponse } from "next/server"; | ||
|
||
export async function POST(request: Request) { | ||
const body = await request.json(); | ||
const { name, email } = emailSchema.parse(body); | ||
try { | ||
const data = await resend.emails.send({ | ||
from: "EntApex App <noreply@entapex.com>", | ||
to: [email], | ||
subject: "Hello world!", | ||
react: EmailTemplate({ firstName: name }), | ||
text: "Email powered by Resend.", | ||
}); | ||
|
||
return NextResponse.json(data); | ||
} catch (error) { | ||
return NextResponse.json({ error }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import * as React from "react"; | ||
|
||
interface EmailTemplateProps { | ||
firstName: string; | ||
} | ||
|
||
export const EmailTemplate: React.FC<Readonly<EmailTemplateProps>> = ({ | ||
firstName, | ||
}) => ( | ||
<div> | ||
<h1>Welcome, {firstName}!</h1> | ||
<p> | ||
Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim | ||
labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. | ||
Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum | ||
Lorem est aliquip amet voluptate voluptate dolor minim nulla est proident. | ||
Nostrud officia pariatur ut officia. Sit irure elit esse ea nulla sunt ex | ||
occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat | ||
officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in | ||
Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non | ||
excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco | ||
ut ea consectetur et est culpa et culpa duis. | ||
</p> | ||
<hr /> | ||
<p>Sent with help from Resend and EntApex App 😊</p> | ||
</div> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { Resend } from "resend"; | ||
import { env } from "@/env.mjs"; | ||
|
||
export const resend = new Resend(env.RESEND_API); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { z } from "zod"; | ||
|
||
export const emailSchema = z.object({ | ||
name: z.string().min(3), | ||
email: z.string().email(), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
"use client"; | ||
import Link from "next/link"; | ||
import { emailSchema } from "@/lib/email/utils"; | ||
import { useRef, useState } from "react"; | ||
import { z } from "zod"; | ||
import { Button } from "@/components/ui/button"; | ||
import { Input } from "@/components/ui/input"; | ||
import { Label } from "@/components/ui/label"; | ||
|
||
type FormInput = z.infer<typeof emailSchema>; | ||
type Errors = { [K in keyof FormInput]: string[] }; | ||
|
||
export default function Page() { | ||
const [sending, setSending] = useState(false); | ||
const [errors, setErrors] = useState<Errors | null>(null); | ||
const nameInputRef = useRef<HTMLInputElement>(null); | ||
const emailInputRef = useRef<HTMLInputElement>(null); | ||
|
||
const sendEmail = async () => { | ||
setSending(true); | ||
setErrors(null); | ||
try { | ||
const payload = emailSchema.parse({ | ||
name: nameInputRef.current?.value, | ||
email: emailInputRef.current?.value, | ||
}); | ||
console.log(payload); | ||
const req = await fetch("/api/email", { | ||
method: "POST", | ||
body: JSON.stringify(payload), | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
}); | ||
const { id } = await req.json(); | ||
if (id) alert("Successfully sent!"); | ||
} catch (err) { | ||
if (err instanceof z.ZodError) { | ||
setErrors(err.flatten().fieldErrors as Errors); | ||
} | ||
} finally { | ||
setSending(false); | ||
} | ||
}; | ||
return ( | ||
<main className="max-w-2xl mx-auto p-4 md:p-0"> | ||
<div> | ||
<h1 className="text-2xl font-bold my-4">Send Email with Resend</h1> | ||
<div> | ||
<ol className="list-decimal list-inside space-y-1"> | ||
<li> | ||
<Link | ||
className="text-primary hover:text-muted-foreground underline" | ||
href="https://resend.com/signup" | ||
> | ||
Sign up | ||
</Link>{" "} | ||
or{" "} | ||
<Link | ||
className="text-primary hover:text-muted-foreground underline" | ||
href="https://resend.com/login" | ||
> | ||
Login | ||
</Link>{" "} | ||
to your Resend account | ||
</li> | ||
<li>Add and verify your domain</li> | ||
<li> | ||
Create an API Key and add to{" "} | ||
<span className="ml-1 font-mono font-thin bg-zinc-100 dark:bg-slate-800 p-0.5"> | ||
.env | ||
</span> | ||
</li> | ||
<li> | ||
Update "from:" in{" "} | ||
<span className="ml-1 font-mono font-thin bg-zinc-100 dark:bg-slate-800 p-0.5"> | ||
app/api/email/route.ts | ||
</span> | ||
</li> | ||
<li>Send email 🎉</li> | ||
</ol> | ||
</div> | ||
</div> | ||
<form | ||
onSubmit={(e) => e.preventDefault()} | ||
className="space-y-3 pt-4 border-t mt-4" | ||
> | ||
{errors && <p className="p-3">{JSON.stringify(errors, null, 2)}</p>} | ||
<div> | ||
<Label className="text-muted-foreground">Name</Label> | ||
<Input type="text" placeholder="Tim" name="name" ref={nameInputRef} /> | ||
</div> | ||
<div> | ||
<Label className="text-muted-foreground">Email</Label> | ||
<Input | ||
type="email" | ||
placeholder="tim@apple.com" | ||
name="email" | ||
ref={emailInputRef} | ||
/> | ||
</div> | ||
<Button onClick={() => sendEmail()} disabled={sending}> | ||
{sending ? "sending..." : "Send Email"} | ||
</Button> | ||
</form> | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { EmailTemplate } from "@/components/emails/FirstEmail"; | ||
import { resend } from "@/lib/email"; | ||
import { emailSchema } from "@/lib/email/utils"; | ||
import { NextResponse } from "next/server"; | ||
|
||
export async function POST(request: Request) { | ||
const body = await request.json(); | ||
const { name, email } = emailSchema.parse(body); | ||
try { | ||
const data = await resend.emails.send({ | ||
from: "EntApex App <noreply@entapex.com>", | ||
to: [email], | ||
subject: "Hello world!", | ||
react: EmailTemplate({ firstName: name }), | ||
text: "Email powered by Resend.", | ||
}); | ||
|
||
return NextResponse.json(data); | ||
} catch (error) { | ||
return NextResponse.json({ error }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
templates/entapex-app/src/components/emails/FirstEmail.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import * as React from "react"; | ||
|
||
interface EmailTemplateProps { | ||
firstName: string; | ||
} | ||
|
||
export const EmailTemplate: React.FC<Readonly<EmailTemplateProps>> = ({ | ||
firstName, | ||
}) => ( | ||
<div> | ||
<h1>Welcome, {firstName}!</h1> | ||
<p> | ||
Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim | ||
labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. | ||
Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum | ||
Lorem est aliquip amet voluptate voluptate dolor minim nulla est proident. | ||
Nostrud officia pariatur ut officia. Sit irure elit esse ea nulla sunt ex | ||
occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat | ||
officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in | ||
Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non | ||
excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco | ||
ut ea consectetur et est culpa et culpa duis. | ||
</p> | ||
<hr /> | ||
<p>Sent with help from Resend and EntApex App 😊</p> | ||
</div> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { Resend } from "resend"; | ||
import { env } from "@/env.mjs"; | ||
|
||
export const resend = new Resend(env.RESEND_API); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { z } from "zod"; | ||
|
||
export const emailSchema = z.object({ | ||
name: z.string().min(3), | ||
email: z.string().email(), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters