WIP invitation layout
All checks were successful
Build Nginx-based docker image / build-static-assets (push) Successful in 1m52s
All checks were successful
Build Nginx-based docker image / build-static-assets (push) Successful in 1m52s
This commit is contained in:
parent
e23997e39a
commit
42d1de933f
@ -3,12 +3,76 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { AbstractApi } from '@/app/api/abstract-api';
|
import { AbstractApi } from '@/app/api/abstract-api';
|
||||||
|
import { Guest } from '@/app/lib/guest';
|
||||||
import { Invitation, InvitationSerializer } from '@/app/lib/invitation';
|
import { Invitation, InvitationSerializer } from '@/app/lib/invitation';
|
||||||
import { useParams } from 'next/navigation';
|
import { useParams } from 'next/navigation';
|
||||||
|
import { Dropdown } from 'primereact/dropdown';
|
||||||
import { TabPanel, TabView } from 'primereact/tabview';
|
import { TabPanel, TabView } from 'primereact/tabview';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
function GuestForm({ guest }: { guest: Guest }) {
|
||||||
|
const [formResponses, setFormResponses] = useState<Guest['formResponses']>(guest.formResponses || {});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<div>
|
||||||
|
<label className="block font-medium">Will you use the bus to get to the venue?</label>
|
||||||
|
<Dropdown
|
||||||
|
value={formResponses?.busNeeded ? 'Yes' : formResponses?.busNeeded === false ? 'No' : ''}
|
||||||
|
options={[
|
||||||
|
{ label: '', value: '' }, // Blank option as default
|
||||||
|
{ label: 'Yes', value: 'Yes' },
|
||||||
|
{ label: 'No', value: 'No' },
|
||||||
|
]}
|
||||||
|
onChange={(e) =>
|
||||||
|
setFormResponses((prev) => ({
|
||||||
|
...prev,
|
||||||
|
busNeeded: e.value === 'Yes',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder="Select an option"
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block font-medium">Dietary Restrictions</label>
|
||||||
|
<textarea
|
||||||
|
value={formResponses?.dietaryRestrictions}
|
||||||
|
onChange={(e) =>
|
||||||
|
setFormResponses((prev) => ({
|
||||||
|
...prev,
|
||||||
|
dietaryRestrictions: e.target.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
className="w-full p-2 border border-gray-300 rounded-md"
|
||||||
|
rows={3}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="block font-medium">Meal Preference</label>
|
||||||
|
<Dropdown
|
||||||
|
value={formResponses?.mealPreference}
|
||||||
|
options={[
|
||||||
|
{ label: '', value: '' }, // Blank option as default
|
||||||
|
{ label: 'Meat', value: 'Meat' },
|
||||||
|
{ label: 'Fish', value: 'Fish' },
|
||||||
|
]}
|
||||||
|
onChange={(e) =>
|
||||||
|
setFormResponses((prev) => ({
|
||||||
|
...prev,
|
||||||
|
mealPreference: e.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
placeholder="Select an option"
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const params = useParams<{ slug: string, id: string }>()
|
const params = useParams<{ slug: string, id: string }>()
|
||||||
|
|
||||||
@ -26,16 +90,20 @@ export default function Page() {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{invitation && (
|
{invitation && (
|
||||||
<TabView>
|
|
||||||
{invitation.guests.map((guest, index) => (
|
|
||||||
<TabPanel key={index} header={guest.name}>
|
|
||||||
<div>
|
<div>
|
||||||
<p><strong>Name:</strong> {guest.name}</p>
|
<p className="mb-4 font-medium">
|
||||||
</div>
|
{invitation.guests.length} seats have been reserved for this invitation.
|
||||||
|
</p>
|
||||||
|
<TabView className="border border-gray-300 rounded-md">
|
||||||
|
{invitation.guests.map((guest) => (
|
||||||
|
<TabPanel header={guest.name} >
|
||||||
|
<GuestForm guest={guest} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
))}
|
))}
|
||||||
</TabView>
|
</TabView>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div >
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -14,25 +14,72 @@ export class Guest implements Entity {
|
|||||||
color?: string;
|
color?: string;
|
||||||
status?: GuestStatus;
|
status?: GuestStatus;
|
||||||
children?: Guest[];
|
children?: Guest[];
|
||||||
|
formResponses?: {
|
||||||
|
busNeeded?: boolean;
|
||||||
|
dietaryRestrictions?: string;
|
||||||
|
mealPreference?: 'meat' | 'fish' | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
constructor(id?: string, name?: string, group_name?: string, groupId?: string, color?: string, status?: GuestStatus, children?: Guest[]) {
|
constructor(
|
||||||
|
id?: string,
|
||||||
|
name?: string,
|
||||||
|
groupName?: string,
|
||||||
|
groupId?: string,
|
||||||
|
color?: string,
|
||||||
|
status?: GuestStatus,
|
||||||
|
children?: Guest[],
|
||||||
|
formResponses?: {
|
||||||
|
busNeeded?: boolean;
|
||||||
|
dietaryRestrictions?: string;
|
||||||
|
mealPreference?: 'meat' | 'fish' | undefined;
|
||||||
|
}
|
||||||
|
) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.group_name = group_name;
|
this.group_name = groupName;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.children = children;
|
this.children = children;
|
||||||
|
this.formResponses = formResponses;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GuestSerializer implements Serializable<Guest> {
|
export class GuestSerializer implements Serializable<Guest> {
|
||||||
fromJson(data: any): Guest {
|
fromJson(data: any): Guest {
|
||||||
return new Guest(data.id, data.name, data.group?.name, data.group?.id, data.color, data.status, data.children);
|
return new Guest(
|
||||||
|
data.id,
|
||||||
|
data.name,
|
||||||
|
data.group?.name,
|
||||||
|
data.group?.id,
|
||||||
|
data.color,
|
||||||
|
data.status,
|
||||||
|
data.children,
|
||||||
|
data.form_responses
|
||||||
|
? {
|
||||||
|
busNeeded: data.form_responses.bus_needed,
|
||||||
|
dietaryRestrictions: data.form_responses.dietary_restrictions,
|
||||||
|
mealPreference: data.form_responses.meal_preference,
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toJson(guest: Guest): string {
|
toJson(guest: Guest): string {
|
||||||
return JSON.stringify({ guest: { name: guest.name, status: guest.status, group_id: guest.groupId } });
|
return JSON.stringify({
|
||||||
|
guest: {
|
||||||
|
name: guest.name,
|
||||||
|
status: guest.status,
|
||||||
|
group_id: guest.groupId,
|
||||||
|
form_responses: guest.formResponses
|
||||||
|
? {
|
||||||
|
bus_needed: guest.formResponses.busNeeded,
|
||||||
|
dietary_restrictions: guest.formResponses.dietaryRestrictions,
|
||||||
|
meal_preference: guest.formResponses.mealPreference,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
apiPath(): string {
|
apiPath(): string {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user