From cf4161ca6e417d2c9c72eac47854a0ab04e442a3 Mon Sep 17 00:00:00 2001 From: Starstrike Date: Thu, 1 May 2025 10:04:56 -0400 Subject: [PATCH] Add manage needed items functionality to EventAdmin component and backend support --- backend/src/index.ts | 61 +++++++++++++++ frontend/src/components/EventAdmin.tsx | 101 ++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 3 deletions(-) diff --git a/backend/src/index.ts b/backend/src/index.ts index d36f9bd..4f91fa5 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -312,6 +312,67 @@ app.put('/api/events/:slug/rsvps/:id', async (req: Request, res: Response) => { } }); +// Update event +app.put('/api/events/:slug', async (req: Request, res: Response) => { + try { + const { slug } = req.params; + const { title, description, date, location, needed_items } = req.body; + + // Verify the event exists + const eventRows = await db.all('SELECT * FROM events WHERE slug = ?', [slug]); + + if (eventRows.length === 0) { + return res.status(404).json({ error: 'Event not found' }); + } + + // Ensure needed_items is properly formatted + let parsedNeededItems: string[] = []; + try { + if (typeof needed_items === 'string') { + parsedNeededItems = JSON.parse(needed_items); + } else if (Array.isArray(needed_items)) { + parsedNeededItems = needed_items; + } + } catch (e) { + console.error('Error parsing needed_items:', e); + } + + // Update the event + await db.run( + 'UPDATE events SET title = ?, description = ?, date = ?, location = ?, needed_items = ? WHERE slug = ?', + [ + title || eventRows[0].title, + description || eventRows[0].description, + date || eventRows[0].date, + location || eventRows[0].location, + JSON.stringify(parsedNeededItems), + slug + ] + ); + + // Get the updated event + const updatedEvent = await db.get('SELECT * FROM events WHERE slug = ?', [slug]); + + // Add the full path to the wallpaper + if (updatedEvent.wallpaper) { + updatedEvent.wallpaper = `/uploads/wallpapers/${updatedEvent.wallpaper}`; + } + + // Parse needed_items for response + try { + updatedEvent.needed_items = updatedEvent.needed_items ? JSON.parse(updatedEvent.needed_items) : []; + } catch (e) { + console.error('Error parsing needed_items in response:', e); + updatedEvent.needed_items = []; + } + + res.json(updatedEvent); + } catch (error) { + console.error('Error updating event:', error); + res.status(500).json({ error: 'Internal server error' }); + } +}); + // Initialize database tables async function initializeDatabase() { try { diff --git a/frontend/src/components/EventAdmin.tsx b/frontend/src/components/EventAdmin.tsx index 7a4808f..9f4b994 100644 --- a/frontend/src/components/EventAdmin.tsx +++ b/frontend/src/components/EventAdmin.tsx @@ -32,6 +32,7 @@ import { } from '@mui/material'; import DeleteIcon from '@mui/icons-material/Delete'; import EditIcon from '@mui/icons-material/Edit'; +import AddIcon from '@mui/icons-material/Add'; import axios from 'axios'; interface RSVP { @@ -77,6 +78,9 @@ const EventAdmin: React.FC = () => { items_bringing: [] as string[], }); const [deleteEventDialogOpen, setDeleteEventDialogOpen] = useState(false); + const [manageItemsDialogOpen, setManageItemsDialogOpen] = useState(false); + const [newItem, setNewItem] = useState(''); + const [itemToDelete, setItemToDelete] = useState(null); useEffect(() => { fetchEventAndRsvps(); @@ -282,6 +286,44 @@ const EventAdmin: React.FC = () => { } }; + const handleAddItem = async () => { + if (!event || !newItem.trim()) return; + + try { + const updatedItems = [...(Array.isArray(event.needed_items) ? event.needed_items : []), newItem.trim()]; + await axios.put(`/api/events/${slug}`, { + ...event, + needed_items: updatedItems + }); + + setEvent(prev => prev ? { ...prev, needed_items: updatedItems } : null); + setNeededItems(prev => [...prev, newItem.trim()]); + setNewItem(''); + } catch (error) { + setError('Failed to add item'); + } + }; + + const handleRemoveItem = async (itemToRemove: string) => { + if (!event) return; + + try { + const updatedItems = Array.isArray(event.needed_items) + ? event.needed_items.filter(item => item !== itemToRemove) + : []; + + await axios.put(`/api/events/${slug}`, { + ...event, + needed_items: updatedItems + }); + + setEvent(prev => prev ? { ...prev, needed_items: updatedItems } : null); + setNeededItems(prev => prev.filter(item => item !== itemToRemove)); + } catch (error) { + setError('Failed to remove item'); + } + }; + if (loading) { return ( @@ -333,9 +375,18 @@ const EventAdmin: React.FC = () => { {/* Add items status section */} - - Items Status - + + + Items Status + + + @@ -612,6 +663,50 @@ const EventAdmin: React.FC = () => { + + setManageItemsDialogOpen(false)} + maxWidth="sm" + fullWidth + > + Manage Needed Items + + + + setNewItem(e.target.value)} + fullWidth + /> + + + + Current Items: + + + {event?.needed_items && Array.isArray(event.needed_items) && event.needed_items.map((item, index) => ( + handleRemoveItem(item)} + color={claimedItems.includes(item) ? "success" : "primary"} + /> + ))} + + + + + + + );