import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import axios from 'axios'; import { Box, Paper, Typography, TextField, Button, FormControl, InputLabel, Select, MenuItem, SelectChangeEvent, Container, Checkbox, ListItemText, OutlinedInput, Chip, } from '@mui/material'; import VisibilityIcon from '@mui/icons-material/Visibility'; import { Event } from '../types'; interface RSVPFormData { name: string; attending: string; bringing_guests: string; guest_count: number; guest_names: string; items_bringing: string[]; } const RSVPForm: React.FC = () => { const { slug } = useParams<{ slug: string }>(); const [formData, setFormData] = useState({ name: '', attending: '', bringing_guests: '', guest_count: 0, guest_names: '', items_bringing: [] }); const [neededItems, setNeededItems] = useState([]); const [claimedItems, setClaimedItems] = useState([]); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); const [success, setSuccess] = useState(false); const navigate = useNavigate(); const [event, setEvent] = useState(null); useEffect(() => { const fetchEventDetails = async () => { try { const [eventResponse, rsvpsResponse] = await Promise.all([ axios.get(`/api/events/${slug}`), axios.get(`/api/events/${slug}/rsvps`) ]); // Check if event is closed for RSVPs if (eventResponse.data.rsvp_cutoff_date) { const cutoffDate = new Date(eventResponse.data.rsvp_cutoff_date); if (new Date() > cutoffDate) { navigate(`/view/events/${slug}`); return; } } // Process needed items let items: string[] = []; if (eventResponse.data.needed_items) { items = Array.isArray(eventResponse.data.needed_items) ? eventResponse.data.needed_items : typeof eventResponse.data.needed_items === 'string' ? JSON.parse(eventResponse.data.needed_items) : []; } // Get all claimed items from existing RSVPs const claimed = new Set(); if (Array.isArray(rsvpsResponse.data)) { rsvpsResponse.data.forEach((rsvp: any) => { try { let rsvpItems: string[] = []; if (typeof rsvp.items_bringing === 'string') { try { const parsed = JSON.parse(rsvp.items_bringing); rsvpItems = Array.isArray(parsed) ? parsed : []; } catch (e) { console.error('Error parsing items_bringing JSON:', e); } } else if (Array.isArray(rsvp.items_bringing)) { rsvpItems = rsvp.items_bringing; } if (Array.isArray(rsvpItems)) { rsvpItems.forEach((item: string) => claimed.add(item)); } } catch (e) { console.error('Error processing RSVP items:', e); } }); } // Filter out claimed items from available items const availableItems = items.filter(item => !claimed.has(item)); setNeededItems(availableItems); setClaimedItems(Array.from(claimed)); setEvent(eventResponse.data); } catch (error) { console.error('Error fetching event details:', error); setError('Failed to load event details'); setNeededItems([]); } }; fetchEventDetails(); }, [slug]); const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; const handleSelectChange = (e: SelectChangeEvent) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; const handleItemsChange = (e: SelectChangeEvent) => { const { value } = e.target; const itemsArray = Array.isArray(value) ? value : []; setFormData(prev => ({ ...prev, items_bringing: itemsArray })); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsSubmitting(true); setError(null); try { const submissionData = { ...formData, items_bringing: formData.items_bringing }; const response = await axios.post(`/api/events/${slug}/rsvp`, submissionData); // Update the needed and claimed items const [eventResponse, rsvpsResponse] = await Promise.all([ axios.get(`/api/events/${slug}`), axios.get(`/api/events/${slug}/rsvps`) ]); // Process needed items let items: string[] = []; if (eventResponse.data.needed_items) { items = Array.isArray(eventResponse.data.needed_items) ? eventResponse.data.needed_items : typeof eventResponse.data.needed_items === 'string' ? JSON.parse(eventResponse.data.needed_items) : []; } // Get all claimed items from existing RSVPs including the new submission const claimed = new Set(); // First add items from the new submission const newRsvpItems = response.data.items_bringing; if (Array.isArray(newRsvpItems)) { newRsvpItems.forEach((item: string) => claimed.add(item)); } // Then add items from existing RSVPs if (Array.isArray(rsvpsResponse.data)) { rsvpsResponse.data.forEach((rsvp: { items_bringing: string | string[] }) => { try { let rsvpItems: string[] = []; if (typeof rsvp.items_bringing === 'string') { try { const parsed = JSON.parse(rsvp.items_bringing); rsvpItems = Array.isArray(parsed) ? parsed : []; } catch (e) { console.error('Error parsing items_bringing JSON:', e); rsvpItems = []; } } else if (Array.isArray(rsvp.items_bringing)) { rsvpItems = rsvp.items_bringing; } if (Array.isArray(rsvpItems)) { rsvpItems.forEach((item: string) => claimed.add(item)); } } catch (e) { console.error('Error processing RSVP items:', e); } }); } // Filter out claimed items const availableItems = items.filter(item => !claimed.has(item)); setNeededItems(availableItems); setClaimedItems(Array.from(claimed)); setSuccess(true); } catch (err) { console.error('Error submitting RSVP:', 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} )} {event?.rsvp_cutoff_date && ( Note: RSVPs will close on {new Date(event.rsvp_cutoff_date).toLocaleString()} )} Are you attending? {formData.attending === 'yes' && ( <> Are you bringing any guests? {formData.bringing_guests === 'yes' && ( <> )} {neededItems.length > 0 && ( What items are you bringing? )} )} ); }; export default RSVPForm;