From 32245f66100727bfc3f682672e3d716c85bc6cbd Mon Sep 17 00:00:00 2001 From: Raphico Date: Wed, 19 Jun 2024 18:34:18 +0100 Subject: [PATCH] feat: add workshop registration --- .../_components/register-button.tsx | 21 ++++++++ src/app/(app)/workshop/[workshopId]/page.tsx | 22 ++++---- src/app/api/email/new-participant/route.ts | 39 -------------- src/server/actions/registration.ts | 51 +++++++++++++++++-- src/server/actions/workshop.ts | 4 +- src/server/data/workshop.ts | 1 + 6 files changed, 84 insertions(+), 54 deletions(-) create mode 100644 src/app/(app)/workshop/[workshopId]/_components/register-button.tsx delete mode 100644 src/app/api/email/new-participant/route.ts diff --git a/src/app/(app)/workshop/[workshopId]/_components/register-button.tsx b/src/app/(app)/workshop/[workshopId]/_components/register-button.tsx new file mode 100644 index 0000000..0365038 --- /dev/null +++ b/src/app/(app)/workshop/[workshopId]/_components/register-button.tsx @@ -0,0 +1,21 @@ +"use client" + +import { useFormStatus } from "react-dom" + +import { Button } from "@/components/ui/button" +import { Icons } from "@/components/icons" + +export function RegisterButton() { + const { pending } = useFormStatus() + return ( + + ) +} diff --git a/src/app/(app)/workshop/[workshopId]/page.tsx b/src/app/(app)/workshop/[workshopId]/page.tsx index 8f43ad9..f3652fa 100644 --- a/src/app/(app)/workshop/[workshopId]/page.tsx +++ b/src/app/(app)/workshop/[workshopId]/page.tsx @@ -5,6 +5,7 @@ import { env } from "@/env" import { eq } from "drizzle-orm" import { redirects } from "@/config/constants" +import { registerUserAndNotifyAction } from "@/server/actions/registration" import { getUserSession } from "@/server/data/user" import { getWorkshop } from "@/server/data/workshop" import { db } from "@/server/db" @@ -19,6 +20,7 @@ import { Shell } from "@/components/shell" import { OrganizerSection } from "./_components/organizer-section" import { OrganizerSectionSkeleton } from "./_components/organizer-section-skeleton" +import { RegisterButton } from "./_components/register-button" import { WorkshopSettings } from "./_components/workshop-settings" interface WorkshopPageProps { @@ -68,6 +70,12 @@ export default async function WorkshopPage({ params }: WorkshopPageProps) { const isCurrentUserWorkshop = workshop.organizerId === user.id + const registerUserAndNotify = registerUserAndNotifyAction.bind(null, { + workshopId: workshop.id, + workshopTitle: workshop.title, + participantId: user.id, + }) + return (
@@ -122,16 +130,10 @@ export default async function WorkshopPage({ params }: WorkshopPageProps) {
- {!isCurrentUserWorkshop ? ( - + {isCurrentUserWorkshop ? ( +
+ + ) : ( )} diff --git a/src/app/api/email/new-participant/route.ts b/src/app/api/email/new-participant/route.ts deleted file mode 100644 index 92890db..0000000 --- a/src/app/api/email/new-participant/route.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { env } from "@/env" -import { z } from "zod" - -import { unknownError } from "@/config/constants" -import { resend } from "@/lib/resend" -import { newParticipantEmailSchema } from "@/lib/zod/schemas/email" -import NewParticipantEmail from "@/components/emails/new-participant-email" - -export async function POST(req: Request) { - try { - const input = newParticipantEmailSchema.parse(await req.json()) - - const { error } = await resend.emails.send({ - from: env.EMAIL_FROM_ADDRESS, - to: ["raphicogit@gmail.com"], - subject: "New Registration for your workshop", - react: NewParticipantEmail({ - WorkshopTitle: input.workshopTitle, - organizerUsername: input.organizerUsername, - }), - }) - - if (error) { - return new Response(error.message, { status: 500 }) - } - - return new Response(null, { status: 200 }) - } catch (error) { - if (error instanceof z.ZodError) { - return new Response(error.message, { status: 422 }) - } - - if (error instanceof Error) { - return new Response(error.message, { status: 500 }) - } - - return new Response(unknownError, { status: 500 }) - } -} diff --git a/src/server/actions/registration.ts b/src/server/actions/registration.ts index f1e0e4e..c30ffcb 100644 --- a/src/server/actions/registration.ts +++ b/src/server/actions/registration.ts @@ -1,17 +1,62 @@ "use server" import { revalidateTag } from "next/cache" +import { env } from "@/env" import { and, eq } from "drizzle-orm" -import { getErrorMessage } from "@/utils/handle-error" +import { resend } from "@/lib/resend" +import { getErrorMessage, showErrorToast } from "@/utils/handle-error" +import NewParticipantEmail from "@/components/emails/new-participant-email" +import { getWorkshopOrganizer } from "../data/workshop" import { db } from "../db" import { registrations } from "../db/schema" -export async function addParticipantAction(input: { +interface RegisterUserProps { workshopId: string participantId: string -}) { +} + +export async function registerUserAndNotifyAction( + input: RegisterUserProps & { + workshopTitle: string + } +) { + const { error } = await registerUserAction({ + workshopId: input.workshopId, + participantId: input.participantId, + }) + + if (!error) { + showErrorToast(error) + } + + try { + const organizer = await getWorkshopOrganizer(input.workshopId) + + if (!organizer) { + throw new Error("Workshop must have an organizer") + } + + const { error } = await resend.emails.send({ + from: env.EMAIL_FROM_ADDRESS, + to: ["raphicogit@gmail.com"], + subject: "New Registration for your workshop", + react: NewParticipantEmail({ + WorkshopTitle: input.workshopTitle, + organizerUsername: organizer.username, + }), + }) + + if (error) { + console.error(getErrorMessage(error)) + } + } catch (err) { + console.error(getErrorMessage(err)) + } +} + +export async function registerUserAction(input: RegisterUserProps) { try { const checkUserRegistered = await db.query.registrations.findFirst({ where: and( diff --git a/src/server/actions/workshop.ts b/src/server/actions/workshop.ts index 3daea05..00ab843 100644 --- a/src/server/actions/workshop.ts +++ b/src/server/actions/workshop.ts @@ -72,7 +72,7 @@ export async function updateWorkshopAction( } } -export async function deleteWorkshopAction(id: string) { +export async function deleteWorkshopAction(workshopId: string) { try { const { user } = await getUserSession() @@ -82,7 +82,7 @@ export async function deleteWorkshopAction(id: string) { await db .delete(workshops) - .where(and(eq(workshops.organizerId, user.id), eq(workshops.id, id))) + .where(and(eq(workshops.organizerId, user.id), eq(workshops.id, workshopId))) revalidateTag(`workshops-${user.id}`) diff --git a/src/server/data/workshop.ts b/src/server/data/workshop.ts index 07b5780..6e880ec 100644 --- a/src/server/data/workshop.ts +++ b/src/server/data/workshop.ts @@ -91,6 +91,7 @@ export async function getWorkshopOrganizer(organizerId: string) { return await db.query.users.findFirst({ columns: { id: true, + email: true, username: true, image: true, },