Add RSVP modal and form components for event attendance
Introduced a new RSVP modal and form to enable guests to RSVP to events more seamlessly. Updated the invite page to integrate the new modal and handle guest attendance submissions. Refactored the RSVP functionality into reusable components for better maintainability.
This commit is contained in:
@@ -7,7 +7,7 @@ import { format, parseISO } from "date-fns";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Button } from "@/components/ui/button";
|
||||
// import { RSVP } from "@/components/rsvp";
|
||||
import { RSVPModal } from "@/components/rsvp/rsvp-modal";
|
||||
import { useParams } from "next/navigation";
|
||||
import { getServerFileUrl } from "@/lib/utils";
|
||||
|
||||
@@ -21,6 +21,7 @@ const InvitationPage = () => {
|
||||
const [notFound, setNotFound] = useState(false);
|
||||
const [showRSVP, setShowRSVP] = useState(false);
|
||||
const { themes, isLoadingThemes } = useEventThemes();
|
||||
const guestId = "current-guest-id-placeholder";
|
||||
|
||||
// Fetch event data when slug is available
|
||||
useEffect(() => {
|
||||
@@ -398,7 +399,7 @@ const InvitationPage = () => {
|
||||
}}
|
||||
onClick={() => setShowRSVP(true)}
|
||||
>
|
||||
PARTECIPO
|
||||
PRESENZA
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
@@ -456,6 +457,13 @@ const InvitationPage = () => {
|
||||
</div>
|
||||
|
||||
{/* RSVP Modal */}
|
||||
<RSVPModal
|
||||
eventId={event.id}
|
||||
guestId={guestId}
|
||||
open={showRSVP}
|
||||
setOpen={setShowRSVP}
|
||||
/>
|
||||
|
||||
{/*{showRSVP && (*/}
|
||||
{/* <RSVP*/}
|
||||
{/* eventId={event.id}*/}
|
||||
|
||||
126
frontend/src/components/rsvp/rsvp-form.tsx
Normal file
126
frontend/src/components/rsvp/rsvp-form.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
"use client";
|
||||
import React, { useState } from "react";
|
||||
import { useRSVPs } from "@/context/rsvp-context";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { RsvpStatus } from "@/client/types.gen";
|
||||
|
||||
interface RSVPProps {
|
||||
eventId: string;
|
||||
guestId: string;
|
||||
onRSVPSuccess?: () => void;
|
||||
}
|
||||
|
||||
export const RSVP: React.FC<RSVPProps> = ({
|
||||
eventId,
|
||||
guestId,
|
||||
onRSVPSuccess,
|
||||
}) => {
|
||||
const { createRsvp } = useRSVPs();
|
||||
|
||||
const [status, setStatus] = useState<RsvpStatus>(RsvpStatus.ATTENDING);
|
||||
const [number_of_guests, setNumberOfGuests] = useState<number>(1);
|
||||
const [response_message, setResponseMessage] = useState("");
|
||||
const [dietary_requirements, setDietaryRequirements] = useState("");
|
||||
|
||||
const submitRsvp = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
await createRsvp({
|
||||
event_id: eventId,
|
||||
guest_id: guestId,
|
||||
status,
|
||||
number_of_guests,
|
||||
response_message,
|
||||
dietary_requirements,
|
||||
});
|
||||
|
||||
if (onRSVPSuccess) {
|
||||
onRSVPSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={submitRsvp}
|
||||
className="rounded-lg bg-white p-6 flex flex-col gap-5"
|
||||
>
|
||||
<h2 className="text-2xl font-semibold text-gray-800">
|
||||
RSVP to this Event
|
||||
</h2>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="status" className="mb-2">
|
||||
Your Attendance
|
||||
</Label>
|
||||
<Select
|
||||
defaultValue={status}
|
||||
onValueChange={(val) => setStatus(val as any)}
|
||||
>
|
||||
<SelectTrigger id="status">
|
||||
<span className="capitalize">{status.replace("_", " ")}</span>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="attending">Attending</SelectItem>
|
||||
<SelectItem value="not_attending">Not Attending</SelectItem>
|
||||
<SelectItem value="maybe">Maybe</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="number_of_guests" className="mb-2">
|
||||
N. guests
|
||||
</Label>
|
||||
<Input
|
||||
id="number_of_guests"
|
||||
type="number"
|
||||
min={1}
|
||||
value={number_of_guests}
|
||||
onChange={(e) =>
|
||||
setNumberOfGuests(Math.max(1, Number(e.target.value)))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="response_message" className="mb-2">
|
||||
Message to Hosts (optional)
|
||||
</Label>
|
||||
<Textarea
|
||||
id="response_message"
|
||||
value={response_message}
|
||||
onChange={(e) => setResponseMessage(e.target.value)}
|
||||
placeholder="Write a short message to the hosts"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="dietary_requirements" className="mb-2">
|
||||
Dietary Requirements
|
||||
</Label>
|
||||
<Textarea
|
||||
id="dietary_requirements"
|
||||
value={dietary_requirements}
|
||||
onChange={(e) => setDietaryRequirements(e.target.value)}
|
||||
placeholder="Any dietary restrictions?"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button type="submit" className="w-full">
|
||||
Submit RSVP
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default RSVP;
|
||||
33
frontend/src/components/rsvp/rsvp-modal.tsx
Normal file
33
frontend/src/components/rsvp/rsvp-modal.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import RSVP from "@/components/rsvp/rsvp-form";
|
||||
|
||||
interface RSVPModalProps {
|
||||
eventId: string;
|
||||
guestId: string;
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
}
|
||||
|
||||
export function RSVPModal({ eventId, guestId, open, setOpen }: RSVPModalProps) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader className="">
|
||||
<DialogTitle></DialogTitle>
|
||||
</DialogHeader>
|
||||
<RSVP
|
||||
eventId={eventId}
|
||||
guestId={guestId}
|
||||
onRSVPSuccess={() => setOpen(false)}
|
||||
/>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user