From dee9066c91ad4a560024e008f6c5761718b827a0 Mon Sep 17 00:00:00 2001 From: Brian Nelson Date: Sat, 28 Jun 2025 15:00:08 -0400 Subject: [PATCH] logic for eventGuests --- .../[eventId]/guests/[entryId]/route.ts | 18 ++++++++ .../[eventId]/guests/[entryId]/rsvp/route.ts | 20 +++++++++ app/api/events/[eventId]/guests/add/route.ts | 19 ++++++++ docker-compose.yml | 2 - lib/mutations.ts | 43 +++++++++++++++++++ lib/queries.ts | 42 ++++++++++++++++++ .../migration.sql | 19 ++++++++ prisma/schema.prisma | 13 ++++++ 8 files changed, 174 insertions(+), 2 deletions(-) create mode 100644 app/api/events/[eventId]/guests/[entryId]/route.ts create mode 100644 app/api/events/[eventId]/guests/[entryId]/rsvp/route.ts create mode 100644 app/api/events/[eventId]/guests/add/route.ts create mode 100644 prisma/migrations/20250628180402_add_event_guest_relations/migration.sql diff --git a/app/api/events/[eventId]/guests/[entryId]/route.ts b/app/api/events/[eventId]/guests/[entryId]/route.ts new file mode 100644 index 0000000..ce62720 --- /dev/null +++ b/app/api/events/[eventId]/guests/[entryId]/route.ts @@ -0,0 +1,18 @@ +import { NextResponse } from 'next/server' +import { mutations } from '@/lib/mutations' + +export async function DELETE(_: Request, { params }: { params: { eventId: string; entryId: string } }) { + const { eventId, entryId: guestBookEntryId } = params + + if (!eventId || !guestBookEntryId) { + return NextResponse.json({ message: 'Missing eventId or guestBookEntryId' }, { status: 400 }) + } + + try { + await mutations.removeEventGuest(eventId, guestBookEntryId) + return NextResponse.json({ success: true }) + } catch (error) { + console.error('Remove Guest Error:', error) + return NextResponse.json({ message: 'Failed to remove guest from event' }, { status: 500 }) + } +} diff --git a/app/api/events/[eventId]/guests/[entryId]/rsvp/route.ts b/app/api/events/[eventId]/guests/[entryId]/rsvp/route.ts new file mode 100644 index 0000000..1d4f999 --- /dev/null +++ b/app/api/events/[eventId]/guests/[entryId]/rsvp/route.ts @@ -0,0 +1,20 @@ +// app/api/events/[eventId]/guests/[entryId]/rsvp/route.ts +import { NextRequest, NextResponse } from 'next/server' +import { mutations } from '@/lib/mutations' + +export async function PATCH(req: NextRequest, { params }: { params: { eventId: string; entryId: string } }) { + const { eventId, entryId: guestBookEntryId } = params + const { rsvp } = await req.json() + + if (!['YES', 'NO', 'PENDING'].includes(rsvp)) { + return NextResponse.json({ message: 'Invalid RSVP status' }, { status: 400 }) + } + + try { + const updated = await mutations.updateEventGuestRsvp({ eventId, guestBookEntryId, rsvp }) + return NextResponse.json(updated) + } catch (error) { + console.error('RSVP Update Error:', error) + return NextResponse.json({ message: 'Failed to update RSVP status' }, { status: 500 }) + } +} diff --git a/app/api/events/[eventId]/guests/add/route.ts b/app/api/events/[eventId]/guests/add/route.ts new file mode 100644 index 0000000..2b5d8f5 --- /dev/null +++ b/app/api/events/[eventId]/guests/add/route.ts @@ -0,0 +1,19 @@ +import { NextRequest, NextResponse } from 'next/server' +import { mutations } from '@/lib/mutations' + +export async function POST(req: NextRequest, { params }: { params: { eventId: string } }) { + const eventId = params.eventId + const { guestBookEntryId } = await req.json() + + if (!eventId || !guestBookEntryId) { + return NextResponse.json({ message: 'Missing eventId or guestBookEntryId' }, { status: 400 }) + } + + try { + const added = await mutations.addEventGuest({ eventId, guestBookEntryId }) + return NextResponse.json(added) + } catch (error) { + console.error('Add Event Guest Error:', error) + return NextResponse.json({ message: 'Failed to add guest to event' }, { status: 500 }) + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 8e26742..21d5333 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: db: image: postgres:15 diff --git a/lib/mutations.ts b/lib/mutations.ts index 677e6d0..208e231 100644 --- a/lib/mutations.ts +++ b/lib/mutations.ts @@ -117,4 +117,47 @@ export const mutations = { }) }, + async addEventGuest({ + eventId, + guestBookEntryId, + }: { + eventId: string, + guestBookEntryId: string, + }) { + return await prisma.eventGuest.create({ + data: { + eventId, + guestBookEntryId, + rsvp: 'PENDING' + } + }) + }, + + async updateEventGuestRsvp({ + eventId, + guestBookEntryId, + rsvp, + }: { + eventId: string; + guestBookEntryId: string; + rsvp: 'YES' | 'NO' | 'PENDING'; + }) { + return await prisma.eventGuest.update({ + where: { + eventId_guestBookEntryId: { eventId, guestBookEntryId }, // compound unique constraint + }, + data: { + rsvp, + }, + }); + }, + + async removeEventGuest(eventId: string, guestBookEntryId: string) { + return await prisma.eventGuest.delete({ + where: { + eventId_guestBookEntryId: { eventId, guestBookEntryId }, + }, + }); + }, + }; \ No newline at end of file diff --git a/lib/queries.ts b/lib/queries.ts index e174f47..e162dd1 100644 --- a/lib/queries.ts +++ b/lib/queries.ts @@ -16,6 +16,48 @@ export const queries = { return allEvents; }, + async fetchEventGuests(eventId: string) { + return await prisma.eventGuest.findMany({ + where: { eventId }, + include: { + guestBookEntry: true, + }, + orderBy: [ + { + guestBookEntry: { + lName: 'asc', + }, + }, + { + guestBookEntry: { + fName: 'asc' + } + } + ], + }); + }, + + async fetchAvailableGuestBookEntriesForEvent(eventId: string) { + const invitedGuests = await prisma.eventGuest.findMany({ + where: { eventId }, + select: { guestBookEntryId: true } + }); + + const excludeIds = invitedGuests.map(g => g.guestBookEntryId); + + return prisma.guestBookEntry.findMany({ + where: { + id: { + notIn: excludeIds, + }, + }, + orderBy: [ + { lName: 'asc' }, + { fName: 'asc' } + ] + }) + }, + async singleEvent(id: string) { const event = await prisma.event.findUnique({ where: { id }, diff --git a/prisma/migrations/20250628180402_add_event_guest_relations/migration.sql b/prisma/migrations/20250628180402_add_event_guest_relations/migration.sql new file mode 100644 index 0000000..a59fc4d --- /dev/null +++ b/prisma/migrations/20250628180402_add_event_guest_relations/migration.sql @@ -0,0 +1,19 @@ +-- CreateTable +CREATE TABLE "EventGuest" ( + "id" TEXT NOT NULL, + "eventId" TEXT NOT NULL, + "guestBookEntryId" TEXT NOT NULL, + "rsvp" "RsvpStatus" NOT NULL DEFAULT 'PENDING', + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "EventGuest_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "EventGuest_eventId_guestBookEntryId_key" ON "EventGuest"("eventId", "guestBookEntryId"); + +-- AddForeignKey +ALTER TABLE "EventGuest" ADD CONSTRAINT "EventGuest_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "Event"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "EventGuest" ADD CONSTRAINT "EventGuest_guestBookEntryId_fkey" FOREIGN KEY ("guestBookEntryId") REFERENCES "GuestBookEntry"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 2e96698..998b0c4 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -32,6 +32,7 @@ model Event { creator User @relation("EventCreator", fields: [creatorId], references: [id]) creatorId String guests Guest[] + eventGuests EventGuest[] createdAt DateTime @default(now()) } @@ -70,7 +71,19 @@ model GuestBookEntry { address String? notes String? side String // e.g., "Brian", "Janice", etc. + eventGuests EventGuest[] createdAt DateTime @default(now()) } +model EventGuest { + id String @id @default(cuid()) + event Event @relation(fields: [eventId], references: [id]) + eventId String + guestBookEntry GuestBookEntry @relation(fields: [guestBookEntryId], references: [id]) + guestBookEntryId String + rsvp RsvpStatus @default(PENDING) + createdAt DateTime @default(now()) + + @@unique([eventId, guestBookEntryId]) +}