diff --git a/README.md b/README.md index 0604def..9dc964f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,11 @@ My goal for this project is to be an all-in-one self hosted event planner for ma - Event type - Details - Location -- [ ] Guest book (contact information) +- [x] Guest book (contact information) + - [ ] Ability to switch between table or card view + - [ ] Add Guests to events + - [ ] Invite guests via email + - [ ] Create local account for guest - [ ] Managing RSVP lists - [ ] Guest accounts - [ ] Gift Registries @@ -44,6 +48,13 @@ My goal for this project is to be an all-in-one self hosted event planner for ma #### 6.25.25 - now able to see and edit event data from the individual event page +#### 6.26.25 +### The Guest Book +- added guest-book page, viewable by PLANNER and COUPLE accounts + - db query is secure behind PLANNER and COUPLE auth sessions +- added ability to add and edit guests to guest book +- save guest infomation (name, email, phone, address, side (which side of the couple), notes) + ## Getting Started This is very much a work in progress but this `README` will stay up to date on working features and steps to get it running **in its current state**. That being said if you're interested in starting it as is, you can follow these instructions. diff --git a/app/(auth)/events/page.tsx b/app/(auth)/events/page.tsx index b50e4b3..c257ba4 100644 --- a/app/(auth)/events/page.tsx +++ b/app/(auth)/events/page.tsx @@ -12,7 +12,7 @@ export default async function EventsPage() {
{allEvents.length == 0 ? ( <> - You don't have any events yet. Create One! + You don't have any events yet. Create One! ) : ( diff --git a/app/(auth)/guest-book/page.tsx b/app/(auth)/guest-book/page.tsx new file mode 100644 index 0000000..9dc5905 --- /dev/null +++ b/app/(auth)/guest-book/page.tsx @@ -0,0 +1,13 @@ +import { authOptions } from '@/app/api/auth/[...nextauth]/route' +import { queries } from '@/lib/queries' +import { getServerSession } from 'next-auth' +import GuestBookPageClient from '@/components/GuestBookPageClient' + +export default async function GuestBookPage() { + const session = await getServerSession(authOptions) + if (!session?.user) return

Unauthorized

+ + const entries = await queries.fetchGuestBookEntries() + + return +} diff --git a/app/api/guestbook/[id]/route.ts b/app/api/guestbook/[id]/route.ts new file mode 100644 index 0000000..78f44fa --- /dev/null +++ b/app/api/guestbook/[id]/route.ts @@ -0,0 +1,20 @@ +import { NextRequest, NextResponse } from 'next/server' +import { mutations } from '@/lib/mutations' +import { getServerSession } from 'next-auth' +import { authOptions } from '../../auth/[...nextauth]/route' + +export async function PATCH(req: NextRequest, { params }: { params: { id: string } }) { + const session = await getServerSession(authOptions) + if (!session?.user || !['COUPLE', 'PLANNER'].includes(session.user.role)) { + return new NextResponse('Unauthorized', { status: 403 }) + } + + try { + const data = await req.json() + const updated = await mutations.updateGuestBookEntry(params.id, data) + return NextResponse.json(updated) + } catch (err) { + console.error('[EDIT GUESTBOOK ENTRY]', err) + return new NextResponse('Failed to update guestbook entry', { status: 500 }) + } +} diff --git a/app/api/guestbook/add/route.ts b/app/api/guestbook/add/route.ts new file mode 100644 index 0000000..6bfacd5 --- /dev/null +++ b/app/api/guestbook/add/route.ts @@ -0,0 +1,20 @@ +import { NextRequest, NextResponse } from 'next/server' +import { mutations } from '@/lib/mutations' +import { getServerSession } from 'next-auth' +import { authOptions } from '../../auth/[...nextauth]/route' + +export async function POST(req: NextRequest) { + const session = await getServerSession(authOptions) + if (!session?.user || !['COUPLE', 'PLANNER'].includes(session.user.role)) { + return new NextResponse('Unauthorized', { status: 403 }) + } + + try { + const data = await req.json() + const entry = await mutations.createGuestBookEntry(data) + return NextResponse.json(entry) + } catch (err) { + console.error('[ADD GUESTBOOK ENTRY]', err) + return new NextResponse('Failed to create guestbook entry', { status: 500 }) + } +} diff --git a/bun.lockb b/bun.lockb index 81907f5..c2ebbb0 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/components/AddGuestBookEntryModal.tsx b/components/AddGuestBookEntryModal.tsx new file mode 100644 index 0000000..fc76a37 --- /dev/null +++ b/components/AddGuestBookEntryModal.tsx @@ -0,0 +1,127 @@ +'use client' +import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react' +import { Fragment, useState } from 'react' + +export default function AddGuestBookEntryModal({ isOpen, onClose, onSubmit }: { + isOpen: boolean + onClose: () => void + onSubmit: (data: { fName: string, lName: string, email: string, phone?: string, address?: string, side: string, notes?: string }) => void +}) { + const [fName, setFName] = useState(''); + const [lName, setLName] = useState(''); + const [email, setEmail] = useState(''); + const [phone, setPhone] = useState(''); + const [address, setAddress] = useState(''); + const [side, setSide] = useState(''); + const [notes, setNotes] = useState(''); + + function handleSubmit(e: React.FormEvent) { + e.preventDefault() + onSubmit({ fName, lName, email, phone, address, side, notes }) + setFName('') + setLName('') + setEmail('') + setPhone('') + setAddress('') + setSide('') + setNotes('') + onClose() + } + + return ( + + + +
+ + +
+ + + + Add Guest Entry + +
+ setFName(e.target.value)} + required + /> + setLName(e.target.value)} + required + /> + setEmail(e.target.value)} + /> + setPhone(e.target.value)} + /> + setAddress(e.target.value)} + /> + setSide(e.target.value)} + required + /> +