diff --git a/app/[slug]/site/invitation/[id]/page.tsx b/app/[slug]/site/invitation/[id]/page.tsx new file mode 100644 index 0000000..681b827 --- /dev/null +++ b/app/[slug]/site/invitation/[id]/page.tsx @@ -0,0 +1,119 @@ +/* Copyright (C) 2024-2025 LibreWeddingPlanner contributors*/ + +'use client' + +import { AbstractApi } from "@/app/api/abstract-api"; +import { Invitation, InvitationSerializer } from "@/app/lib/invitation"; +import { useParams } from "next/navigation"; +import { useEffect, useState } from "react"; +import { FloatLabel } from "primereact/floatlabel"; +import { Dropdown } from "primereact/dropdown"; +import { Guest, GuestSerializer, GuestStatus } from "@/app/lib/guest"; +import { Button } from "primereact/button"; + +type FormResponse = { + attendance: GuestStatus; +}; + +function GuestForm({ guest, idx }: { guest: Guest, idx: number }) { + const [response, setResponse] = useState({ + attendance: guest.status! + }); + + const [pendingChanges, setPendingChanges] = useState(false); + const [sending, setSending] = useState(false); + + console.log('GuestForm response', response.attendance); + + const attendanceOptions: { name: string, code: GuestStatus }[] = [ + { + name: 'Attending', + code: 'confirmed' + }, + { + name: 'Declined', + code: 'declined' + }, + { + name: 'Tentative', + code: 'tentative' + } + ]; + + const api = new AbstractApi(); + const serializer = new GuestSerializer(); + + const submitForm = () => { + setSending(true); + setPendingChanges(false); + api.update(serializer, { + id: guest.id!, + status: response.attendance, + }, () => setSending(false)); + } + + return ( +
+

{guest.name}

+ + { + setPendingChanges(true); + setResponse({ ...response, attendance: e.value }) + }} + /> + +
+ ) +} + +export default function Page() { + const params = useParams<{ slug: string, id: string }>() + + const [invitation, setInvitation] = useState(); + + useEffect(() => { + localStorage.setItem('slug', params.slug); + + const api = new AbstractApi(); + const serializer = new InvitationSerializer(); + + api.get(serializer, params.id, (invitation: Invitation) => { + setInvitation(invitation); + }); + }, []); + + return ( +
+

Invitation

+ {invitation ? ( +
+

We have reserved {invitation.guests.length} seats in your honor. Please, confirm attendance submitting the following form:

+ {invitation.guests.map((guest, idx) => ( + + ))} +
+ ) : ( +

Loading...

+ )} +
+ ); +} \ No newline at end of file diff --git a/app/[slug]/site/layout.tsx b/app/[slug]/site/layout.tsx index c93aadb..9190358 100644 --- a/app/[slug]/site/layout.tsx +++ b/app/[slug]/site/layout.tsx @@ -29,7 +29,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
{children} diff --git a/app/api/abstract-api.tsx b/app/api/abstract-api.tsx index e35256d..5f8ebc7 100644 --- a/app/api/abstract-api.tsx +++ b/app/api/abstract-api.tsx @@ -49,6 +49,7 @@ export class AbstractApi implements Api { body: serializable.toJson(object), headers: { 'Content-Type': 'application/json', + 'Accept': 'application/json', 'X-CSRF-TOKEN': getCsrfToken(), } }).then(callback) @@ -61,6 +62,7 @@ export class AbstractApi implements Api { body: serializable.toJson(object), headers: { 'Content-Type': 'application/json', + 'Accept': 'application/json', 'X-CSRF-TOKEN': getCsrfToken(), } })