Fix needed_items handling in backend and frontend
This commit is contained in:
@@ -4,6 +4,8 @@ import sqlite3 from 'sqlite3';
|
|||||||
import { open } from 'sqlite';
|
import { open } from 'sqlite';
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import multer from 'multer';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
@@ -45,26 +47,62 @@ app.get('/api/events/:slug', async (req: Request, res: Response) => {
|
|||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
return res.status(404).json({ error: 'Event not found' });
|
return res.status(404).json({ error: 'Event not found' });
|
||||||
}
|
}
|
||||||
res.json(rows[0]);
|
|
||||||
|
// Parse needed_items from JSON string to array
|
||||||
|
const event = rows[0];
|
||||||
|
try {
|
||||||
|
event.needed_items = event.needed_items ? JSON.parse(event.needed_items) : [];
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error parsing needed_items:', e);
|
||||||
|
event.needed_items = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json(event);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching event:', error);
|
console.error('Error fetching event:', error);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/events', async (req: Request, res: Response) => {
|
app.post('/api/events', multer().single('wallpaper'), async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const { title, description, date, location, needed_items } = req.body;
|
const { title, description, date, location, needed_items } = req.body;
|
||||||
|
const wallpaperPath = req.file ? `/uploads/wallpapers/${req.file.filename}` : null;
|
||||||
|
|
||||||
// Generate a slug from the title
|
// Generate a slug from the title
|
||||||
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await db.run(
|
const result = await db.run(
|
||||||
'INSERT INTO events (title, description, date, location, slug, needed_items) VALUES (?, ?, ?, ?, ?, ?)',
|
'INSERT INTO events (title, description, date, location, slug, needed_items, wallpaper) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||||
[title, description, date, location, slug, JSON.stringify(needed_items || [])]
|
[title, description, date, location, slug, JSON.stringify(parsedNeededItems), wallpaperPath]
|
||||||
);
|
);
|
||||||
res.status(201).json({ ...result, slug });
|
|
||||||
|
res.status(201).json({
|
||||||
|
...result,
|
||||||
|
slug,
|
||||||
|
wallpaper: wallpaperPath,
|
||||||
|
needed_items: parsedNeededItems
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating event:', error);
|
console.error('Error creating event:', error);
|
||||||
|
if (req.file) {
|
||||||
|
// Clean up uploaded file if there was an error
|
||||||
|
fs.unlink(req.file.path, (err) => {
|
||||||
|
if (err) console.error('Error deleting file:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
OutlinedInput,
|
OutlinedInput,
|
||||||
Chip,
|
Chip,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
import { Event } from '../types';
|
||||||
|
|
||||||
interface RSVPFormData {
|
interface RSVPFormData {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -49,23 +50,18 @@ const RSVPForm: React.FC = () => {
|
|||||||
const fetchEventDetails = async () => {
|
const fetchEventDetails = async () => {
|
||||||
try {
|
try {
|
||||||
const [eventResponse, rsvpsResponse] = await Promise.all([
|
const [eventResponse, rsvpsResponse] = await Promise.all([
|
||||||
axios.get(`/api/events/${slug}`),
|
axios.get<Event>(`/api/events/${slug}`),
|
||||||
axios.get(`/api/events/${slug}/rsvps`)
|
axios.get(`/api/events/${slug}/rsvps`)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Process needed items
|
// Process needed items
|
||||||
let items: string[] = [];
|
let items: string[] = [];
|
||||||
if (eventResponse.data.needed_items) {
|
if (eventResponse.data.needed_items) {
|
||||||
try {
|
items = Array.isArray(eventResponse.data.needed_items)
|
||||||
items = typeof eventResponse.data.needed_items === 'string'
|
? eventResponse.data.needed_items
|
||||||
|
: typeof eventResponse.data.needed_items === 'string'
|
||||||
? JSON.parse(eventResponse.data.needed_items)
|
? JSON.parse(eventResponse.data.needed_items)
|
||||||
: Array.isArray(eventResponse.data.needed_items)
|
: [];
|
||||||
? eventResponse.data.needed_items
|
|
||||||
: [];
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error parsing needed_items:', e);
|
|
||||||
items = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all claimed items from existing RSVPs
|
// Get all claimed items from existing RSVPs
|
||||||
@@ -74,26 +70,18 @@ const RSVPForm: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
let rsvpItems: string[] = [];
|
let rsvpItems: string[] = [];
|
||||||
if (typeof rsvp.items_bringing === 'string') {
|
if (typeof rsvp.items_bringing === 'string') {
|
||||||
try {
|
rsvpItems = JSON.parse(rsvp.items_bringing);
|
||||||
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)) {
|
} else if (Array.isArray(rsvp.items_bringing)) {
|
||||||
rsvpItems = rsvp.items_bringing;
|
rsvpItems = rsvp.items_bringing;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(rsvpItems)) {
|
rsvpItems.forEach((item: string) => claimed.add(item));
|
||||||
rsvpItems.forEach((item: string) => claimed.add(item));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error processing RSVP items:', e);
|
console.error('Error processing RSVP items:', e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Filter out claimed items
|
// Filter out claimed items from available items
|
||||||
const availableItems = items.filter(item => !claimed.has(item));
|
const availableItems = items.filter(item => !claimed.has(item));
|
||||||
|
|
||||||
setNeededItems(availableItems);
|
setNeededItems(availableItems);
|
||||||
@@ -153,17 +141,11 @@ const RSVPForm: React.FC = () => {
|
|||||||
// Process needed items
|
// Process needed items
|
||||||
let items: string[] = [];
|
let items: string[] = [];
|
||||||
if (eventResponse.data.needed_items) {
|
if (eventResponse.data.needed_items) {
|
||||||
try {
|
items = Array.isArray(eventResponse.data.needed_items)
|
||||||
if (typeof eventResponse.data.needed_items === 'string') {
|
? eventResponse.data.needed_items
|
||||||
const parsed = JSON.parse(eventResponse.data.needed_items);
|
: typeof eventResponse.data.needed_items === 'string'
|
||||||
items = Array.isArray(parsed) ? parsed : [];
|
? JSON.parse(eventResponse.data.needed_items)
|
||||||
} else if (Array.isArray(eventResponse.data.needed_items)) {
|
: [];
|
||||||
items = eventResponse.data.needed_items;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error parsing needed_items:', e);
|
|
||||||
items = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all claimed items from existing RSVPs including the new submission
|
// Get all claimed items from existing RSVPs including the new submission
|
||||||
@@ -179,12 +161,7 @@ const RSVPForm: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
let rsvpItems: string[] = [];
|
let rsvpItems: string[] = [];
|
||||||
if (typeof rsvp.items_bringing === 'string') {
|
if (typeof rsvp.items_bringing === 'string') {
|
||||||
try {
|
rsvpItems = JSON.parse(rsvp.items_bringing);
|
||||||
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)) {
|
} else if (Array.isArray(rsvp.items_bringing)) {
|
||||||
rsvpItems = rsvp.items_bringing;
|
rsvpItems = rsvp.items_bringing;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user