Create central dashboard with statistics and quick actions Build events management with filtering and CRUD UI Implement members management with bulk actions Develop video management with accessibility indicators Add document repository with visibility controls Create content management with WYSIWYG editor Add settings interface for site configuration Additional improvements: Implement full Events Management System with CRUD Enhance frontend architecture with TypeScript Improve accessibility in navigation menu Add comprehensive test suite for Events API
256 lines
6.9 KiB
TypeScript
256 lines
6.9 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import axios from 'axios';
|
|
|
|
// Define Event interface
|
|
export interface Event {
|
|
_id: string;
|
|
title: string;
|
|
description: string;
|
|
date: string;
|
|
time: string;
|
|
location: string;
|
|
category: 'social' | 'athletic' | 'board' | 'general' | 'educational';
|
|
status: 'published' | 'draft' | 'archived';
|
|
registrationRequired: boolean;
|
|
registeredCount: number;
|
|
maxAttendees?: number;
|
|
recurring?: boolean;
|
|
recurrencePattern?: string;
|
|
tags?: string[];
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
// Define filter interface
|
|
export interface EventFilter {
|
|
status?: string;
|
|
category?: string;
|
|
search?: string;
|
|
startDate?: string;
|
|
endDate?: string;
|
|
page?: number;
|
|
limit?: number;
|
|
}
|
|
|
|
// Define pagination interface
|
|
export interface Pagination {
|
|
total: number;
|
|
page: number;
|
|
limit: number;
|
|
pages: number;
|
|
}
|
|
|
|
// Define hook return interface
|
|
export interface UseEventsReturn {
|
|
events: Event[];
|
|
loading: boolean;
|
|
error: Error | null;
|
|
pagination: Pagination | null;
|
|
fetchEvents: (filters?: EventFilter) => Promise<void>;
|
|
getEventById: (id: string) => Promise<Event | null>;
|
|
createEvent: (eventData: Omit<Event, '_id' | 'createdAt' | 'updatedAt'>) => Promise<Event | null>;
|
|
updateEvent: (id: string, eventData: Partial<Event>) => Promise<Event | null>;
|
|
deleteEvent: (id: string) => Promise<boolean>;
|
|
registerForEvent: (id: string) => Promise<Event | null>;
|
|
cancelRegistration: (id: string) => Promise<Event | null>;
|
|
}
|
|
|
|
// API base URL
|
|
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000/api';
|
|
|
|
/**
|
|
* Hook for managing events data
|
|
*/
|
|
export function useEvents(): UseEventsReturn {
|
|
const [events, setEvents] = useState<Event[]>([]);
|
|
const [loading, setLoading] = useState<boolean>(false);
|
|
const [error, setError] = useState<Error | null>(null);
|
|
const [pagination, setPagination] = useState<Pagination | null>(null);
|
|
|
|
/**
|
|
* Fetch events with optional filtering
|
|
*/
|
|
const fetchEvents = useCallback(async (filters?: EventFilter) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
// Build query string from filters
|
|
const queryParams = new URLSearchParams();
|
|
if (filters) {
|
|
Object.entries(filters).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== null && value !== '') {
|
|
queryParams.append(key, String(value));
|
|
}
|
|
});
|
|
}
|
|
|
|
const response = await axios.get(`${API_URL}/events?${queryParams.toString()}`);
|
|
setEvents(response.data.events);
|
|
setPagination(response.data.pagination);
|
|
} catch (err) {
|
|
console.error('Error fetching events:', err);
|
|
setError(err instanceof Error ? err : new Error('Failed to fetch events'));
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
/**
|
|
* Get a single event by ID
|
|
*/
|
|
const getEventById = useCallback(async (id: string): Promise<Event | null> => {
|
|
try {
|
|
const response = await axios.get(`${API_URL}/events/${id}`);
|
|
return response.data.event;
|
|
} catch (err) {
|
|
console.error(`Error fetching event with ID ${id}:`, err);
|
|
return null;
|
|
}
|
|
}, []);
|
|
|
|
/**
|
|
* Create a new event
|
|
*/
|
|
const createEvent = useCallback(async (eventData: Omit<Event, '_id' | 'createdAt' | 'updatedAt'>): Promise<Event | null> => {
|
|
try {
|
|
const response = await axios.post(`${API_URL}/events`, eventData, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
// Add authorization header if needed
|
|
// 'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
// Refresh events list after creating
|
|
fetchEvents();
|
|
|
|
return response.data.event;
|
|
} catch (err) {
|
|
console.error('Error creating event:', err);
|
|
return null;
|
|
}
|
|
}, [fetchEvents]);
|
|
|
|
/**
|
|
* Update an existing event
|
|
*/
|
|
const updateEvent = useCallback(async (id: string, eventData: Partial<Event>): Promise<Event | null> => {
|
|
try {
|
|
const response = await axios.put(`${API_URL}/events/${id}`, eventData, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
// Add authorization header if needed
|
|
// 'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
// Update local state
|
|
setEvents(prevEvents =>
|
|
prevEvents.map(event =>
|
|
event._id === id ? { ...event, ...response.data.event } : event
|
|
)
|
|
);
|
|
|
|
return response.data.event;
|
|
} catch (err) {
|
|
console.error(`Error updating event with ID ${id}:`, err);
|
|
return null;
|
|
}
|
|
}, []);
|
|
|
|
/**
|
|
* Delete an event
|
|
*/
|
|
const deleteEvent = useCallback(async (id: string): Promise<boolean> => {
|
|
try {
|
|
await axios.delete(`${API_URL}/events/${id}`, {
|
|
headers: {
|
|
// Add authorization header if needed
|
|
// 'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
// Update local state
|
|
setEvents(prevEvents => prevEvents.filter(event => event._id !== id));
|
|
|
|
return true;
|
|
} catch (err) {
|
|
console.error(`Error deleting event with ID ${id}:`, err);
|
|
return false;
|
|
}
|
|
}, []);
|
|
|
|
/**
|
|
* Register for an event
|
|
*/
|
|
const registerForEvent = useCallback(async (id: string): Promise<Event | null> => {
|
|
try {
|
|
const response = await axios.post(`${API_URL}/events/${id}/register`, {}, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
// Add authorization header if needed
|
|
// 'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
// Update local state
|
|
setEvents(prevEvents =>
|
|
prevEvents.map(event =>
|
|
event._id === id ? { ...event, ...response.data.event } : event
|
|
)
|
|
);
|
|
|
|
return response.data.event;
|
|
} catch (err) {
|
|
console.error(`Error registering for event with ID ${id}:`, err);
|
|
return null;
|
|
}
|
|
}, []);
|
|
|
|
/**
|
|
* Cancel registration for an event
|
|
*/
|
|
const cancelRegistration = useCallback(async (id: string): Promise<Event | null> => {
|
|
try {
|
|
const response = await axios.post(`${API_URL}/events/${id}/cancel-registration`, {}, {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
// Add authorization header if needed
|
|
// 'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
// Update local state
|
|
setEvents(prevEvents =>
|
|
prevEvents.map(event =>
|
|
event._id === id ? { ...event, ...response.data.event } : event
|
|
)
|
|
);
|
|
|
|
return response.data.event;
|
|
} catch (err) {
|
|
console.error(`Error cancelling registration for event with ID ${id}:`, err);
|
|
return null;
|
|
}
|
|
}, []);
|
|
|
|
// Load events on initial render
|
|
useEffect(() => {
|
|
fetchEvents();
|
|
}, [fetchEvents]);
|
|
|
|
return {
|
|
events,
|
|
loading,
|
|
error,
|
|
pagination,
|
|
fetchEvents,
|
|
getEventById,
|
|
createEvent,
|
|
updateEvent,
|
|
deleteEvent,
|
|
registerForEvent,
|
|
cancelRegistration
|
|
};
|
|
}
|