diff --git a/src/components/CommunityPortal/Reports/Participation/CreateEventModal.jsx b/src/components/CommunityPortal/Reports/Participation/CreateEventModal.jsx index b74bce285f..2caac4b900 100644 --- a/src/components/CommunityPortal/Reports/Participation/CreateEventModal.jsx +++ b/src/components/CommunityPortal/Reports/Participation/CreateEventModal.jsx @@ -5,7 +5,7 @@ import moment from 'moment-timezone'; import { createEvent } from '../../../../actions/communityPortal/eventActions'; import '../../../Header/DarkMode.module.css'; -function CreateEventModal({ isOpen, toggle }) { +function CreateEventModal({ isOpen, toggle, onEventCreated = () => {} }) { const dispatch = useDispatch(); const darkMode = useSelector(state => state.theme.darkMode); const [loading, setLoading] = useState(false); @@ -169,11 +169,11 @@ function CreateEventModal({ isOpen, toggle }) { try { const result = await dispatch(createEvent(eventData)); if (result?.success) { + onEventCreated(); handleToggle(); - // The events list will be refreshed when the component re-renders } } catch (error) { - // Error handling is done in the action + setErrors('Unable to create a new event. Please try again later.'); } finally { setLoading(false); } diff --git a/src/components/CommunityPortal/Reports/Participation/MyCases.jsx b/src/components/CommunityPortal/Reports/Participation/MyCases.jsx index 0b795b9845..0e3e405695 100644 --- a/src/components/CommunityPortal/Reports/Participation/MyCases.jsx +++ b/src/components/CommunityPortal/Reports/Participation/MyCases.jsx @@ -1,78 +1,127 @@ -import { useState } from 'react'; +import { useState, useEffect, useCallback } from 'react'; import { useSelector } from 'react-redux'; +import axios from 'axios'; import styles from './MyCases.module.css'; -import mockEvents from './mockData'; import CreateEventModal from './CreateEventModal'; +import { ENDPOINTS } from '../../../../utils/URL'; + +const INITIAL_DISPLAY = 10; + +const normalizeEvent = e => ({ + id: e._id, + eventType: e.type || 'Workshop', + eventDate: e.startTime, + eventTime: e.startTime + ? new Date(e.startTime).toLocaleString('en-US', { + hour: 'numeric', + minute: 'numeric', + hour12: true, + month: 'short', + day: 'numeric', + year: 'numeric', + }) + : '', + eventName: e.title, + attendees: e.currentAttendees ?? 0, + location: e.location || 'TBD', +}); function MyCases() { const [view, setView] = useState('card'); const [filter, setFilter] = useState('all'); - const [expanded, setExpanded] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); + const [showAll, setShowAll] = useState(false); + + const [allEvents, setAllEvents] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [fetchError, setFetchError] = useState(null); const isExporting = - typeof document !== 'undefined' && document.documentElement?.dataset?.exporting === 'true'; // Sonar: prefer .dataset + typeof document !== 'undefined' && document.documentElement?.dataset?.exporting === 'true'; - const filterEvents = events => { - const now = new Date(); + const darkMode = useSelector(state => state.theme.darkMode); - const nowTime = now.getTime(); + const fetchEvents = useCallback(async () => { + setIsLoading(true); + setFetchError(null); + try { + const response = await axios.get(ENDPOINTS.EVENTS); + const raw = response.data?.events || response.data || []; + setAllEvents(raw.map(normalizeEvent)); + } catch { + setFetchError('Failed to load events.'); + } finally { + setIsLoading(false); + } + }, []); - const upcomingEvents = events.filter(event => { - const eventTime = new Date(event.eventDate).getTime(); - return eventTime >= nowTime; - }); + useEffect(() => { + fetchEvents(); + }, [fetchEvents]); + + const handleFilterChange = e => { + setFilter(e.target.value); + setShowAll(false); + }; + + const handleEventCreated = () => { + fetchEvents(); + setShowAll(false); + }; + + const applyFilter = allEvts => { + const now = new Date(); if (filter === 'today') { - return upcomingEvents.filter(event => { - const eventDate = new Date(event.eventDate); + return allEvts.filter(e => { + const d = new Date(e.eventDate); return ( - eventDate.getDate() === now.getDate() && - eventDate.getMonth() === now.getMonth() && - eventDate.getFullYear() === now.getFullYear() + d.getDate() === now.getDate() && + d.getMonth() === now.getMonth() && + d.getFullYear() === now.getFullYear() ); }); } if (filter === 'thisWeek') { - const startOfWeek = new Date(now.setDate(now.getDate() - now.getDay())); + const startOfWeek = new Date(now); + startOfWeek.setDate(now.getDate() - now.getDay()); + startOfWeek.setHours(0, 0, 0, 0); const endOfWeek = new Date(startOfWeek); - endOfWeek.setDate(endOfWeek.getDate() + 6); - return upcomingEvents.filter(event => { - const eventDate = new Date(event.eventTime); - return eventDate >= startOfWeek && eventDate <= endOfWeek; + endOfWeek.setDate(startOfWeek.getDate() + 6); + endOfWeek.setHours(23, 59, 59, 999); + return allEvts.filter(e => { + const d = new Date(e.eventDate); + return d >= startOfWeek && d <= endOfWeek && d >= new Date(); }); } if (filter === 'thisMonth') { const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); - const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0); - return upcomingEvents.filter(event => { - const eventDate = new Date(event.eventTime); - return eventDate >= startOfMonth && eventDate <= endOfMonth; + const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59, 999); + return allEvts.filter(e => { + const d = new Date(e.eventDate); + return d >= startOfMonth && d <= endOfMonth && d >= new Date(); }); } - return upcomingEvents; + return allEvts.filter(e => { + const d = new Date(e.eventDate); + return d > new Date(); + }); }; - const darkMode = useSelector(state => state.theme.darkMode); - const filteredEvents = filterEvents(mockEvents); + const filteredSorted = applyFilter(allEvents).sort( + (a, b) => new Date(a.eventDate).getTime() - new Date(b.eventDate).getTime(), + ); - filteredEvents.sort((a, b) => new Date(a.eventDate).getTime() - new Date(b.eventDate).getTime()); + const displayEvents = + isExporting || showAll ? filteredSorted : filteredSorted.slice(0, INITIAL_DISPLAY); - // Sonar: extract nested ternary into independent statement - let visibleEvents = filteredEvents; - if (!isExporting) { - visibleEvents = expanded ? filteredEvents.slice(0, 40) : filteredEvents.slice(0, 10); - } + const hasMore = !showAll && filteredSorted.length > INITIAL_DISPLAY; - const placeholderAvatar = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; + const placeholderAvatar = 'https://picsum.photos/id/201/200/300'; const renderCardView = () => ( -
Loading events...
; + if (fetchError) return{fetchError}
; + return (