Implement individual guest name fields and array storage. Updated both frontend and backend to handle guest names as an array of strings instead of a single multiline string.
This commit is contained in:
@@ -214,7 +214,26 @@ app.get('/api/events/:slug/rsvps', async (req: Request, res: Response) => {
|
||||
|
||||
const eventId = eventRows[0].id;
|
||||
const rows = await db.all('SELECT * FROM rsvps WHERE event_id = ?', [eventId]);
|
||||
res.json(rows);
|
||||
|
||||
// Parse JSON arrays in each RSVP
|
||||
const parsedRows = rows.map(rsvp => {
|
||||
try {
|
||||
return {
|
||||
...rsvp,
|
||||
items_bringing: rsvp.items_bringing ? JSON.parse(rsvp.items_bringing) : [],
|
||||
guest_names: rsvp.guest_names ? JSON.parse(rsvp.guest_names) : []
|
||||
};
|
||||
} catch (e) {
|
||||
console.error('Error parsing RSVP JSON fields:', e);
|
||||
return {
|
||||
...rsvp,
|
||||
items_bringing: [],
|
||||
guest_names: []
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
res.json(parsedRows);
|
||||
} catch (error) {
|
||||
console.error('Error fetching RSVPs:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
@@ -234,7 +253,7 @@ app.post('/api/events/:slug/rsvp', async (req: Request, res: Response) => {
|
||||
|
||||
const eventId = eventRows[0].id;
|
||||
|
||||
// Ensure items_bringing is properly formatted
|
||||
// Parse items_bringing if it's a string
|
||||
let parsedItemsBringing: string[] = [];
|
||||
try {
|
||||
if (typeof items_bringing === 'string') {
|
||||
@@ -245,13 +264,25 @@ app.post('/api/events/:slug/rsvp', async (req: Request, res: Response) => {
|
||||
} catch (e) {
|
||||
console.error('Error parsing items_bringing:', e);
|
||||
}
|
||||
|
||||
// Parse guest_names if it's a string
|
||||
let parsedGuestNames: string[] = [];
|
||||
try {
|
||||
if (typeof guest_names === 'string') {
|
||||
parsedGuestNames = JSON.parse(guest_names);
|
||||
} else if (Array.isArray(guest_names)) {
|
||||
parsedGuestNames = guest_names;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error parsing guest_names:', e);
|
||||
}
|
||||
|
||||
const result = await db.run(
|
||||
'INSERT INTO rsvps (event_id, name, attending, bringing_guests, guest_count, guest_names, items_bringing) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||
[eventId, name, attending, bringing_guests, guest_count, guest_names, JSON.stringify(parsedItemsBringing)]
|
||||
[eventId, name, attending, bringing_guests, guest_count, JSON.stringify(parsedGuestNames), JSON.stringify(parsedItemsBringing)]
|
||||
);
|
||||
|
||||
// Return the complete RSVP data including the parsed items_bringing
|
||||
// Return the complete RSVP data including the parsed arrays
|
||||
res.status(201).json({
|
||||
id: result.lastID,
|
||||
event_id: eventId,
|
||||
@@ -259,7 +290,7 @@ app.post('/api/events/:slug/rsvp', async (req: Request, res: Response) => {
|
||||
attending,
|
||||
bringing_guests,
|
||||
guest_count,
|
||||
guest_names,
|
||||
guest_names: parsedGuestNames,
|
||||
items_bringing: parsedItemsBringing
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -315,10 +346,22 @@ app.put('/api/events/:slug/rsvps/:id', async (req: Request, res: Response) => {
|
||||
console.error('Error parsing items_bringing:', e);
|
||||
}
|
||||
|
||||
// Parse guest_names if it's a string
|
||||
let parsedGuestNames: string[] = [];
|
||||
try {
|
||||
if (typeof guest_names === 'string') {
|
||||
parsedGuestNames = JSON.parse(guest_names);
|
||||
} else if (Array.isArray(guest_names)) {
|
||||
parsedGuestNames = guest_names;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error parsing guest_names:', e);
|
||||
}
|
||||
|
||||
// Update the RSVP
|
||||
await db.run(
|
||||
'UPDATE rsvps SET name = ?, attending = ?, bringing_guests = ?, guest_count = ?, guest_names = ?, items_bringing = ? WHERE id = ? AND event_id = ?',
|
||||
[name, attending, bringing_guests, guest_count, guest_names, JSON.stringify(parsedItemsBringing), id, eventId]
|
||||
[name, attending, bringing_guests, guest_count, JSON.stringify(parsedGuestNames), JSON.stringify(parsedItemsBringing), id, eventId]
|
||||
);
|
||||
|
||||
// Get the updated RSVP to verify and return
|
||||
@@ -328,12 +371,14 @@ app.put('/api/events/:slug/rsvps/:id', async (req: Request, res: Response) => {
|
||||
return res.status(404).json({ error: 'RSVP not found after update' });
|
||||
}
|
||||
|
||||
// Parse items_bringing for response
|
||||
// Parse arrays for response
|
||||
try {
|
||||
updatedRsvp.items_bringing = updatedRsvp.items_bringing ? JSON.parse(updatedRsvp.items_bringing) : [];
|
||||
updatedRsvp.guest_names = updatedRsvp.guest_names ? JSON.parse(updatedRsvp.guest_names) : [];
|
||||
} catch (e) {
|
||||
console.error('Error parsing items_bringing in response:', e);
|
||||
console.error('Error parsing arrays in response:', e);
|
||||
updatedRsvp.items_bringing = [];
|
||||
updatedRsvp.guest_names = [];
|
||||
}
|
||||
|
||||
res.json(updatedRsvp);
|
||||
|
||||
@@ -26,7 +26,7 @@ interface RSVPFormData {
|
||||
attending: string;
|
||||
bringing_guests: string;
|
||||
guest_count: number;
|
||||
guest_names: string;
|
||||
guest_names: string[];
|
||||
items_bringing: string[];
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ const RSVPForm: React.FC = () => {
|
||||
attending: '',
|
||||
bringing_guests: '',
|
||||
guest_count: 1,
|
||||
guest_names: '',
|
||||
guest_names: [],
|
||||
items_bringing: []
|
||||
});
|
||||
const [neededItems, setNeededItems] = useState<string[]>([]);
|
||||
@@ -118,6 +118,63 @@ const RSVPForm: React.FC = () => {
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
if (name === 'attending') {
|
||||
// Reset guest-related fields when attendance changes to 'no' or 'maybe'
|
||||
if (value === 'no' || value === 'maybe') {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
bringing_guests: 'no',
|
||||
guest_count: 0,
|
||||
guest_names: [],
|
||||
items_bringing: []
|
||||
}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (name === 'bringing_guests') {
|
||||
// Reset guest fields when bringing_guests changes
|
||||
if (value === 'no') {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
guest_count: 0,
|
||||
guest_names: []
|
||||
}));
|
||||
return;
|
||||
} else if (value === 'yes') {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: value,
|
||||
guest_count: 1,
|
||||
guest_names: ['']
|
||||
}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (name === 'guest_count') {
|
||||
const count = parseInt(value) || 0;
|
||||
// Adjust guest_names array size based on count
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: count,
|
||||
guest_names: Array(count).fill('').map((_, i) => prev.guest_names[i] || '')
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.startsWith('guest_name_')) {
|
||||
const index = parseInt(name.split('_')[2]);
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
guest_names: prev.guest_names.map((name, i) => i === index ? value : name)
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
[name]: value
|
||||
@@ -159,8 +216,10 @@ const RSVPForm: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (formData.bringing_guests === 'yes' && (formData.guest_count < 1 || !formData.guest_names.trim())) {
|
||||
setError('Please provide the number and names of your guests');
|
||||
if (formData.bringing_guests === 'yes' &&
|
||||
(formData.guest_count < 1 ||
|
||||
formData.guest_names.some(name => !name.trim()))) {
|
||||
setError('Please provide names for all guests');
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
}
|
||||
@@ -387,20 +446,23 @@ const RSVPForm: React.FC = () => {
|
||||
helperText={formData.guest_count < 1 ? "Number of guests must be at least 1" : ""}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
label="Guest Names"
|
||||
name="guest_names"
|
||||
value={formData.guest_names}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
rows={3}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
required
|
||||
placeholder="Please list the names of your guests"
|
||||
error={!formData.guest_names.trim()}
|
||||
helperText={!formData.guest_names.trim() ? "Please enter the names of your guests" : ""}
|
||||
/>
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
Guest Names
|
||||
</Typography>
|
||||
{Array.from({ length: formData.guest_count }).map((_, index) => (
|
||||
<TextField
|
||||
key={index}
|
||||
fullWidth
|
||||
label={`Guest ${index + 1} Name`}
|
||||
name={`guest_name_${index}`}
|
||||
value={formData.guest_names[index] || ''}
|
||||
onChange={handleChange}
|
||||
margin="normal"
|
||||
required
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -442,7 +504,7 @@ const RSVPForm: React.FC = () => {
|
||||
!formData.name.trim() ||
|
||||
!formData.attending ||
|
||||
(formData.attending === 'yes' && !formData.bringing_guests) ||
|
||||
(formData.bringing_guests === 'yes' && (formData.guest_count < 1 || !formData.guest_names.trim()))}
|
||||
(formData.bringing_guests === 'yes' && (formData.guest_count < 1 || formData.guest_names.some(name => !name.trim())))}
|
||||
sx={{ mt: 2 }}
|
||||
>
|
||||
{isSubmitting ? 'Submitting...' : 'Submit RSVP'}
|
||||
|
||||
Reference in New Issue
Block a user