Files
rsvp-manager/frontend/src/components/EventList.tsx

168 lines
5.4 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Box,
Button,
Card,
CardContent,
Typography,
Grid,
CardActions,
Container,
Chip,
Stack,
} from '@mui/material';
import AdminPanelSettingsIcon from '@mui/icons-material/AdminPanelSettings';
import VisibilityIcon from '@mui/icons-material/Visibility';
import HowToRegIcon from '@mui/icons-material/HowToReg';
import axios from 'axios';
interface Event {
id: number;
title: string;
description: string;
date: string;
location: string;
slug: string;
rsvp_cutoff_date?: string;
}
const EventList: React.FC = () => {
const [events, setEvents] = useState<Event[]>([]);
const navigate = useNavigate();
useEffect(() => {
fetchEvents();
}, []);
const fetchEvents = async () => {
try {
const response = await axios.get('/api/events');
setEvents(response.data);
} catch (error) {
console.error('Error fetching events:', error);
}
};
const isEventOpen = (event: Event) => {
if (!event.rsvp_cutoff_date) return true;
const cutoffDate = new Date(event.rsvp_cutoff_date);
return new Date() < cutoffDate;
};
const handleAdminClick = (event: Event, e: React.MouseEvent) => {
e.stopPropagation();
window.location.href = `/admin/events/${event.slug}`;
};
const handleViewClick = (event: Event, e: React.MouseEvent) => {
e.stopPropagation();
navigate(`/view/events/${event.slug}`);
};
return (
<Box>
<Container maxWidth="md" sx={{ textAlign: 'center', mb: 8 }}>
<Typography variant="h2" component="h1" sx={{ mb: 4 }}>
RSVP Manager
</Typography>
<Typography variant="h6" component="p" sx={{ mb: 6, color: 'text.secondary' }}>
Welcome to RSVP Manager! Create and manage your events with ease.
Organize gatherings, track attendance, and coordinate items that guests can bring.
Perfect for parties, meetings, and any event that needs RSVP coordination.
</Typography>
<Button
variant="contained"
color="primary"
onClick={() => window.location.href = '/create'}
size="large"
sx={{
py: 2,
px: 6,
fontSize: '1.2rem'
}}
>
Create Event
</Button>
</Container>
<Container maxWidth="lg">
<Grid container spacing={4}>
{events.map((event) => (
<Grid item xs={12} sm={6} md={6} key={event.id}>
<Card
sx={{
height: '100%',
display: 'flex',
flexDirection: 'column',
opacity: isEventOpen(event) ? 1 : 0.7,
'& .MuiCardContent-root': {
padding: 3
}
}}
>
<CardContent sx={{ flexGrow: 1 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 2 }}>
<Typography variant="h5" component="h2" sx={{ flexGrow: 1 }}>
{event.title}
</Typography>
<Chip
label={isEventOpen(event) ? "Open" : "Closed"}
color={isEventOpen(event) ? "success" : "error"}
size="small"
/>
</Box>
{event.description && (
<Typography variant="body2" color="text.secondary">
<strong>Info:</strong> {event.description}
</Typography>
)}
<Typography variant="body2" color="text.secondary">
<strong>Date:</strong> {new Date(event.date).toLocaleString()}
</Typography>
<Typography variant="body2" color="text.secondary">
<strong>Location:</strong> {event.location}
</Typography>
{event.rsvp_cutoff_date && (
<Typography variant="body2" color="text.secondary">
<strong>RSVP cut-off date:</strong> {new Date(event.rsvp_cutoff_date).toLocaleString()}
</Typography>
)}
</CardContent>
<CardActions sx={{ justifyContent: 'space-between', px: 3, pb: 2 }}>
<Stack direction="row" spacing={1}>
{isEventOpen(event) && (
<Button
size="small"
startIcon={<HowToRegIcon />}
onClick={() => navigate(`/rsvp/events/${event.slug}`)}
>
Submit RSVP
</Button>
)}
<Button
size="small"
startIcon={<VisibilityIcon />}
onClick={(e) => handleViewClick(event, e)}
>
View RSVPs
</Button>
</Stack>
<Button
size="small"
startIcon={<AdminPanelSettingsIcon />}
onClick={(e) => handleAdminClick(event, e)}
>
Manage
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</Box>
);
};
export default EventList;