Compare commits
4 Commits
2a1f13a5f0
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
678e1db0a3 | ||
|
|
a2c3f16dc7 | ||
|
|
44e6b2a6dc | ||
|
|
42508af610 |
@@ -1,11 +1,10 @@
|
|||||||
import uuid
|
|
||||||
|
|
||||||
from pydantic import BaseModel, EmailStr, ConfigDict
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional, Any, Dict
|
from typing import Optional, Any, Dict
|
||||||
from app.models.guest import GuestStatus
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
from pydantic import BaseModel, EmailStr, ConfigDict
|
||||||
|
|
||||||
|
from app.models.guest import GuestStatus
|
||||||
from app.schemas.rsvp import RSVPSchema, RSVPStatus
|
from app.schemas.rsvp import RSVPSchema, RSVPStatus
|
||||||
|
|
||||||
|
|
||||||
@@ -50,6 +49,8 @@ class GuestRead(GuestBase):
|
|||||||
is_blocked: bool
|
is_blocked: bool
|
||||||
model_config = ConfigDict(from_attributes=True)
|
model_config = ConfigDict(from_attributes=True)
|
||||||
invitation_code: str
|
invitation_code: str
|
||||||
|
rsvp: Optional[RSVPSchema] = None
|
||||||
|
|
||||||
|
|
||||||
class GuestWithRSVPResponse(BaseModel):
|
class GuestWithRSVPResponse(BaseModel):
|
||||||
"""
|
"""
|
||||||
@@ -62,6 +63,7 @@ class GuestWithRSVPResponse(BaseModel):
|
|||||||
class Config:
|
class Config:
|
||||||
from_attributes = True
|
from_attributes = True
|
||||||
|
|
||||||
|
|
||||||
def map_rsvp_status_to_guest_status(rsvp_status: RSVPStatus) -> GuestStatus:
|
def map_rsvp_status_to_guest_status(rsvp_status: RSVPStatus) -> GuestStatus:
|
||||||
if rsvp_status == RSVPStatus.ATTENDING:
|
if rsvp_status == RSVPStatus.ATTENDING:
|
||||||
return GuestStatus.CONFIRMED
|
return GuestStatus.CONFIRMED
|
||||||
@@ -70,4 +72,4 @@ def map_rsvp_status_to_guest_status(rsvp_status: RSVPStatus) -> GuestStatus:
|
|||||||
elif rsvp_status == RSVPStatus.MAYBE:
|
elif rsvp_status == RSVPStatus.MAYBE:
|
||||||
return GuestStatus.PENDING
|
return GuestStatus.PENDING
|
||||||
else:
|
else:
|
||||||
return GuestStatus.INVITED
|
return GuestStatus.INVITED
|
||||||
|
|||||||
@@ -2427,6 +2427,16 @@ export const GuestReadSchema = {
|
|||||||
type: "string",
|
type: "string",
|
||||||
title: "Invitation Code",
|
title: "Invitation Code",
|
||||||
},
|
},
|
||||||
|
rsvp: {
|
||||||
|
anyOf: [
|
||||||
|
{
|
||||||
|
$ref: "#/components/schemas/RSVPSchema",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "null",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
type: "object",
|
type: "object",
|
||||||
required: [
|
required: [
|
||||||
|
|||||||
@@ -370,6 +370,7 @@ export type GuestRead = {
|
|||||||
actual_additional_guests: number;
|
actual_additional_guests: number;
|
||||||
is_blocked: boolean;
|
is_blocked: boolean;
|
||||||
invitation_code: string;
|
invitation_code: string;
|
||||||
|
rsvp?: RsvpSchema | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type GuestStatus =
|
export type GuestStatus =
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
full_name: "",
|
full_name: "",
|
||||||
email: "",
|
email: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
max_additional_guests: 0,
|
max_additional_guests: 10,
|
||||||
dietary_restrictions: "",
|
dietary_restrictions: "",
|
||||||
notes: "",
|
notes: "",
|
||||||
can_bring_guests: true,
|
can_bring_guests: true,
|
||||||
@@ -293,7 +293,7 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
"Phone",
|
"Phone",
|
||||||
"Invitation Code",
|
"Invitation Code",
|
||||||
"Status",
|
"Status",
|
||||||
"Additional Guests",
|
"Max Additional Guests",
|
||||||
];
|
];
|
||||||
const csvContent = [
|
const csvContent = [
|
||||||
headers.join(","),
|
headers.join(","),
|
||||||
@@ -348,6 +348,12 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
}
|
}
|
||||||
}, [addGuestOpen, editGuestOpen, currentGuest]);
|
}, [addGuestOpen, editGuestOpen, currentGuest]);
|
||||||
|
|
||||||
|
const confirmedGuestCount =
|
||||||
|
guests?.filter((g) => g.status === GuestStatus.CONFIRMED).length || 0;
|
||||||
|
const confirmedAdditionalGuestsCount =
|
||||||
|
guests?.reduce((acc, g) => acc + (g.actual_additional_guests || 0), 0) || 0;
|
||||||
|
const totalConfirmedGuestsCount =
|
||||||
|
confirmedGuestCount + confirmedAdditionalGuestsCount;
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4 w-full">
|
<div className="space-y-4 w-full">
|
||||||
{error && (
|
{error && (
|
||||||
@@ -414,14 +420,14 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-4 items-center gap-4">
|
<div className="grid grid-cols-4 items-center gap-4">
|
||||||
<Label htmlFor="max_additional_guests" className="text-right">
|
<Label htmlFor="max_additional_guests" className="text-right">
|
||||||
Additional Guests
|
Max Add. Guests
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="max_additional_guests"
|
id="max_additional_guests"
|
||||||
name="max_additional_guests"
|
name="max_additional_guests"
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
min="0"
|
||||||
value={formData.max_additional_guests || 0}
|
value={formData.max_additional_guests || 10}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
className="col-span-3"
|
className="col-span-3"
|
||||||
/>
|
/>
|
||||||
@@ -578,8 +584,8 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
|
|
||||||
{/* Dietary Restrictions Column */}
|
{/* Dietary Restrictions Column */}
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{guest.dietary_restrictions &&
|
{guest.rsvp?.dietary_requirements &&
|
||||||
guest.dietary_restrictions.length > 0 ? (
|
guest.rsvp.dietary_requirements.length > 0 ? (
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@@ -592,7 +598,7 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="max-w-xs">
|
<PopoverContent className="max-w-xs">
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{guest.dietary_restrictions}
|
{guest.rsvp.dietary_requirements}
|
||||||
</p>
|
</p>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
@@ -603,7 +609,8 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
|
|
||||||
{/* Notes Column */}
|
{/* Notes Column */}
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{guest.notes && guest.notes.length > 0 ? (
|
{guest.rsvp?.response_message &&
|
||||||
|
guest.rsvp.response_message.length > 0 ? (
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
@@ -615,7 +622,9 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="max-w-xs">
|
<PopoverContent className="max-w-xs">
|
||||||
<p className="text-sm">{guest.notes}</p>
|
<p className="text-sm">
|
||||||
|
{guest.rsvp.response_message}
|
||||||
|
</p>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
) : (
|
) : (
|
||||||
@@ -682,14 +691,9 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
Showing {filteredGuests.length} of {guests?.length || 0} guests
|
Showing {filteredGuests.length} of {guests?.length || 0} guests
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
Total Confirmed:{" "}
|
Guests Confirmed: {confirmedGuestCount} | Additional Guests:{" "}
|
||||||
{guests?.filter((g) => g.status === GuestStatus.CONFIRMED).length ||
|
{confirmedAdditionalGuestsCount} | Total Guests:{" "}
|
||||||
0}{" "}
|
{totalConfirmedGuestsCount}
|
||||||
| Total Additional Guests:{" "}
|
|
||||||
{guests?.reduce(
|
|
||||||
(acc, g) => acc + (g.max_additional_guests || 0),
|
|
||||||
0,
|
|
||||||
) || 0}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -743,7 +747,7 @@ const GuestListTable = ({ event }: GuestListTableProps) => {
|
|||||||
htmlFor="edit_max_additional_guests"
|
htmlFor="edit_max_additional_guests"
|
||||||
className="text-right"
|
className="text-right"
|
||||||
>
|
>
|
||||||
Additional Guests
|
Max Add. Guests
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="edit_max_additional_guests"
|
id="edit_max_additional_guests"
|
||||||
|
|||||||
Reference in New Issue
Block a user