Add EventDetails component and types with proper type definitions

This commit is contained in:
Your Name
2025-04-29 18:16:10 -04:00
parent fb61fc3ffb
commit d85bcc7296
3 changed files with 123 additions and 0 deletions

View File

@@ -21,6 +21,8 @@
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/react-router-dom": "^5.3.3",
"@types/axios": "^0.14.0",
"typescript": "^4.9.5",
"react-scripts": "5.0.1"
},

View File

@@ -0,0 +1,101 @@
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import axios from 'axios';
import { Event, Rsvp } from '../types';
import { Button, Container, Typography, Box, Paper, List, ListItem, ListItemText, CircularProgress, Alert } from '@mui/material';
const EventDetails: React.FC = () => {
const { slug } = useParams<{ slug: string }>();
const navigate = useNavigate();
const [event, setEvent] = useState<Event | null>(null);
const [rsvps, setRsvps] = useState<Rsvp[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchEventDetails = async () => {
try {
const [eventResponse, rsvpsResponse] = await Promise.all([
axios.get<Event>(`/api/events/${slug}`),
axios.get<Rsvp[]>(`/api/events/${slug}/rsvps`)
]);
setEvent(eventResponse.data);
setRsvps(rsvpsResponse.data);
setLoading(false);
} catch (error) {
setError('Failed to load event details');
setLoading(false);
}
};
fetchEventDetails();
}, [slug]);
if (loading) {
return (
<Container>
<Box display="flex" justifyContent="center" alignItems="center" minHeight="100vh">
<CircularProgress />
</Box>
</Container>
);
}
if (error) {
return (
<Container>
<Alert severity="error">{error}</Alert>
</Container>
);
}
if (!event) {
return (
<Container>
<Alert severity="warning">Event not found</Alert>
</Container>
);
}
return (
<Container>
<Paper elevation={3} sx={{ p: 3, my: 3 }}>
<Typography variant="h4" gutterBottom>
{event.title}
</Typography>
<Typography variant="subtitle1" gutterBottom>
{event.date} at {event.location}
</Typography>
<Typography variant="body1" paragraph>
{event.description}
</Typography>
<Typography variant="h5" gutterBottom>
RSVPs
</Typography>
<List>
{rsvps.map((rsvp) => (
<ListItem key={rsvp.id}>
<ListItemText
primary={rsvp.name}
secondary={`${rsvp.email} - ${rsvp.status}`}
/>
</ListItem>
))}
</List>
<Box mt={3}>
<Button
variant="contained"
color="primary"
onClick={() => navigate('/')}
>
Back to Events
</Button>
</Box>
</Paper>
</Container>
);
};
export default EventDetails;

20
frontend/src/types.ts Normal file
View File

@@ -0,0 +1,20 @@
export interface Event {
id: number;
title: string;
description: string;
date: string;
location: string;
slug: string;
created_at: string;
updated_at: string;
}
export interface Rsvp {
id: number;
event_id: number;
name: string;
email: string;
status: 'attending' | 'not_attending' | 'maybe';
created_at: string;
updated_at: string;
}