From 6d8b4d04670b07e322cfcb14f81abe536f9f0d40 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 29 Apr 2025 13:55:55 -0400 Subject: [PATCH] Add RSVP functionality with dynamic form and slug-based URLs --- frontend/src/App.tsx | 28 +++-- frontend/src/components/RSVPForm.tsx | 158 +++++++++++++++++++++++++++ src/index.ts | 74 ++++++++++++- 3 files changed, 247 insertions(+), 13 deletions(-) create mode 100644 frontend/src/components/RSVPForm.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 8b04066..a98f774 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -5,6 +5,8 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import { Container } from '@mui/material'; import EventList from './components/EventList'; import EventForm from './components/EventForm'; +import RSVPForm from './components/RSVPForm'; +import './App.css'; const darkTheme = createTheme({ palette: { @@ -22,20 +24,30 @@ const darkTheme = createTheme({ }, }); -function App() { +const App: React.FC = () => { return ( - - - } /> - } /> - - +
+
+
+

RSVP Manager

+
+
+
+
+ + } /> + } /> + } /> + +
+
+
); -} +}; export default App; \ No newline at end of file diff --git a/frontend/src/components/RSVPForm.tsx b/frontend/src/components/RSVPForm.tsx new file mode 100644 index 0000000..9da949e --- /dev/null +++ b/frontend/src/components/RSVPForm.tsx @@ -0,0 +1,158 @@ +import React, { useState } from 'react'; +import { useParams } from 'react-router-dom'; +import axios from 'axios'; + +interface RSVPFormData { + name: string; + attending: boolean; + bringing_guests: boolean; + guest_count: number; + guest_names: string; + items_bringing: string; +} + +const RSVPForm: React.FC = () => { + const { slug } = useParams<{ slug: string }>(); + const [formData, setFormData] = useState({ + name: '', + attending: false, + bringing_guests: false, + guest_count: 0, + guest_names: '', + items_bringing: '' + }); + const [isSubmitting, setIsSubmitting] = useState(false); + const [error, setError] = useState(null); + const [success, setSuccess] = useState(false); + + const handleChange = (e: React.ChangeEvent) => { + const { name, value, type } = e.target; + setFormData(prev => ({ + ...prev, + [name]: type === 'checkbox' ? (e.target as HTMLInputElement).checked : value + })); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsSubmitting(true); + setError(null); + + try { + await axios.post(`/api/events/${slug}/rsvp`, formData); + setSuccess(true); + } catch (err) { + setError('Failed to submit RSVP. Please try again.'); + } finally { + setIsSubmitting(false); + } + }; + + if (success) { + return ( +
+

Thank You!

+

Your RSVP has been submitted successfully.

+
+ ); + } + + return ( +
+

RSVP Form

+ {error &&
{error}
} + +
+
+ + +
+ +
+ +
+ + {formData.attending && ( + <> +
+ +
+ + {formData.bringing_guests && ( + <> +
+ + +
+ +
+ +