Skip to content

Commit 6b660b0

Browse files
committed
add feedback
1 parent 2b12202 commit 6b660b0

File tree

6 files changed

+71
-13
lines changed

6 files changed

+71
-13
lines changed

app/layout.tsx

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
import './ui/global.css'
1+
import "./ui/global.css";
2+
import { Toaster } from "./ui/toaster";
23

34
export const metadata = {
4-
title: 'Next.js',
5-
description: 'Generated by Next.js',
6-
}
5+
title: "Next.js",
6+
description: "Generated by Next.js",
7+
};
78

89
export default function RootLayout({
910
children,
1011
}: {
11-
children: React.ReactNode
12+
children: React.ReactNode;
1213
}) {
1314
return (
1415
<html lang="en">
15-
<body>{children}</body>
16+
<body>
17+
{children}
18+
<Toaster />
19+
</body>
1620
</html>
17-
)
21+
);
1822
}

app/lib/actions.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import { VercelInviteUserEmail } from "../../emails/vercel-invite-user";
55

66
const resend = new Resend(process.env.RESEND_API_KEY);
77

8-
export async function send(prevState: string | undefined, formData: FormData) {
8+
type State = { error: string } | { data: string };
9+
10+
export async function send(prevState: State, formData: FormData) {
911
const email = formData.get("email") as string;
1012

1113
const { data, error } = await resend.emails.send({
@@ -16,10 +18,10 @@ export async function send(prevState: string | undefined, formData: FormData) {
1618
});
1719

1820
if (error) {
19-
return error.message;
21+
return { error: error.message };
2022
}
2123

2224
console.log(data);
2325

24-
return "Email sent!";
26+
return { data: "Email sent!" };
2527
}

app/page.tsx

+15-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,23 @@
33
import clsx from "clsx";
44
import { useFormState, useFormStatus } from "react-dom";
55
import { send } from "./lib/actions";
6-
import React from "react";
6+
import * as React from "react";
7+
import { toast } from "sonner";
78

89
export default function Page() {
9-
const [, dispatch] = useFormState(send, undefined);
10+
const [state, dispatch] = useFormState(send, undefined);
11+
12+
React.useEffect(() => {
13+
if (!state) {
14+
return;
15+
}
16+
17+
if ("data" in state) {
18+
toast(state.data);
19+
} else if ("error" in state) {
20+
toast(`Error when sending email: ${state.error}`);
21+
}
22+
}, [state]);
1023

1124
return (
1225
<div className="bg-zinc-950 p-8 min-h-screen flex justify-center items-center sm:items-start sm:p-24">

app/ui/toaster.tsx

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"use client";
2+
3+
import { Toaster as Sonner } from "sonner";
4+
5+
type ToasterProps = React.ComponentProps<typeof Sonner>;
6+
7+
const Toaster = ({ ...props }: ToasterProps) => {
8+
return (
9+
<Sonner
10+
theme="dark"
11+
className="toaster group"
12+
toastOptions={{
13+
classNames: {
14+
toast:
15+
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
16+
description: "group-[.toast]:text-muted-foreground",
17+
},
18+
}}
19+
{...props}
20+
/>
21+
);
22+
};
23+
24+
export { Toaster };

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"react": "18.2.0",
1313
"react-dom": "18.2.0",
1414
"react-email": "2.1.6",
15-
"resend": "4.0.0"
15+
"resend": "4.0.0",
16+
"sonner": "^1.5.0"
1617
},
1718
"devDependencies": {
1819
"@types/node": "22.4.1",

pnpm-lock.yaml

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)