Feature: Filter out claimed items and show items status

This commit is contained in:
2025-04-30 10:38:11 -04:00
parent 4c2a1f747d
commit 09afdfe9ef
2 changed files with 91 additions and 12 deletions

View File

@@ -28,6 +28,7 @@ import {
OutlinedInput, OutlinedInput,
ListItemText, ListItemText,
Checkbox, Checkbox,
Chip,
} from '@mui/material'; } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from '@mui/icons-material/Delete';
import EditIcon from '@mui/icons-material/Edit'; import EditIcon from '@mui/icons-material/Edit';
@@ -59,6 +60,7 @@ const EventAdmin: React.FC = () => {
const [event, setEvent] = useState<Event | null>(null); const [event, setEvent] = useState<Event | null>(null);
const [rsvps, setRsvps] = useState<RSVP[]>([]); const [rsvps, setRsvps] = useState<RSVP[]>([]);
const [neededItems, setNeededItems] = useState<string[]>([]); const [neededItems, setNeededItems] = useState<string[]>([]);
const [claimedItems, setClaimedItems] = useState<string[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
@@ -100,9 +102,9 @@ const EventAdmin: React.FC = () => {
items = []; items = [];
} }
} }
setNeededItems(items);
// Parse items_bringing for each RSVP // Get all claimed items from existing RSVPs
const claimed = new Set<string>();
const processedRsvps = rsvpsResponse.data.map((rsvp: RSVP) => { const processedRsvps = rsvpsResponse.data.map((rsvp: RSVP) => {
let itemsBringing: string[] = []; let itemsBringing: string[] = [];
try { try {
@@ -111,6 +113,7 @@ const EventAdmin: React.FC = () => {
: Array.isArray(rsvp.items_bringing) : Array.isArray(rsvp.items_bringing)
? rsvp.items_bringing ? rsvp.items_bringing
: []; : [];
itemsBringing.forEach(item => claimed.add(item));
} catch (e) { } catch (e) {
console.error('Error parsing items_bringing:', e); console.error('Error parsing items_bringing:', e);
itemsBringing = []; itemsBringing = [];
@@ -122,6 +125,11 @@ const EventAdmin: React.FC = () => {
}; };
}); });
// Filter out claimed items from needed items
const availableItems = items.filter(item => !claimed.has(item));
setNeededItems(availableItems);
setClaimedItems(Array.from(claimed));
setRsvps(processedRsvps); setRsvps(processedRsvps);
setLoading(false); setLoading(false);
} catch (error) { } catch (error) {
@@ -229,6 +237,54 @@ const EventAdmin: React.FC = () => {
</Button> </Button>
</Box> </Box>
{/* Add items status section */}
<Box sx={{ mb: 4 }}>
<Typography variant="h6" gutterBottom>
Items Status
</Typography>
<Box sx={{ display: 'flex', gap: 4 }}>
<Box>
<Typography variant="subtitle1" gutterBottom>
Still Needed:
</Typography>
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{neededItems.map((item, index) => (
<Chip
key={index}
label={item}
color="primary"
variant="outlined"
/>
))}
{neededItems.length === 0 && (
<Typography variant="body2" color="text.secondary">
All items have been claimed
</Typography>
)}
</Box>
</Box>
<Box>
<Typography variant="subtitle1" gutterBottom>
Claimed Items:
</Typography>
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1 }}>
{claimedItems.map((item, index) => (
<Chip
key={index}
label={item}
color="success"
/>
))}
{claimedItems.length === 0 && (
<Typography variant="body2" color="text.secondary">
No items have been claimed yet
</Typography>
)}
</Box>
</Box>
</Box>
</Box>
<Typography variant="h6" gutterBottom> <Typography variant="h6" gutterBottom>
RSVPs ({rsvps.length}) RSVPs ({rsvps.length})
</Typography> </Typography>

View File

@@ -38,6 +38,7 @@ const RSVPForm: React.FC = () => {
items_bringing: [] items_bringing: []
}); });
const [neededItems, setNeededItems] = useState<string[]>([]); const [neededItems, setNeededItems] = useState<string[]>([]);
const [claimedItems, setClaimedItems] = useState<string[]>([]);
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState(false); const [success, setSuccess] = useState(false);
@@ -46,26 +47,48 @@ const RSVPForm: React.FC = () => {
useEffect(() => { useEffect(() => {
const fetchEventDetails = async () => { const fetchEventDetails = async () => {
try { try {
const response = await axios.get(`/api/events/${slug}`); const [eventResponse, rsvpsResponse] = await Promise.all([
console.log('API Response:', response.data); axios.get(`/api/events/${slug}`),
axios.get(`/api/events/${slug}/rsvps`)
]);
console.log('API Response:', eventResponse.data);
// Ensure needed_items is an array // Process needed items
let items: string[] = []; let items: string[] = [];
if (response.data.needed_items) { if (eventResponse.data.needed_items) {
try { try {
items = typeof response.data.needed_items === 'string' items = typeof eventResponse.data.needed_items === 'string'
? JSON.parse(response.data.needed_items) ? JSON.parse(eventResponse.data.needed_items)
: Array.isArray(response.data.needed_items) : Array.isArray(eventResponse.data.needed_items)
? response.data.needed_items ? eventResponse.data.needed_items
: []; : [];
} catch (e) { } catch (e) {
console.error('Error parsing needed_items:', e); console.error('Error parsing needed_items:', e);
items = []; items = [];
} }
} }
// Get all claimed items from existing RSVPs
const claimed = new Set<string>();
rsvpsResponse.data.forEach((rsvp: any) => {
try {
const rsvpItems = typeof rsvp.items_bringing === 'string'
? JSON.parse(rsvp.items_bringing)
: Array.isArray(rsvp.items_bringing)
? rsvp.items_bringing
: [];
rsvpItems.forEach((item: string) => claimed.add(item));
} catch (e) {
console.error('Error parsing RSVP items:', e);
}
});
console.log('Processed needed items:', items); // Filter out claimed items
setNeededItems(items); const availableItems = items.filter(item => !claimed.has(item));
console.log('Available items:', availableItems);
setNeededItems(availableItems);
setClaimedItems(Array.from(claimed));
} catch (error) { } catch (error) {
console.error('Error fetching event details:', error); console.error('Error fetching event details:', error);
setError('Failed to load event details'); setError('Failed to load event details');