@@ -37,48 +37,48 @@ export default function CommunityCalendar() {
3737 const currentDate = new Date ( ) ;
3838
3939
40- useEffect ( ( ) => {
41- if ( process . env . NODE_ENV === 'test' ) {
42- setEvents ( MOCK_EVENTS ) ;
43- setIsLoading ( false ) ;
44- return ;
45- }
40+ useEffect ( ( ) => {
41+ const fetchEvents = async ( ) => {
42+ setIsLoading ( true ) ;
43+ try {
44+ const response = await axios . get ( ENDPOINTS . EVENTS ) ;
45+
46+ const apiEvents = response . data ?. events || response . data || [ ] ;
47+
48+ if ( ! apiEvents || apiEvents . length === 0 ) {
49+ console . warn ( 'API returned empty → using mock events' ) ;
50+ setEvents ( MOCK_EVENTS ) ;
51+ } else {
52+ setEvents ( apiEvents ) ;
53+ }
54+ } catch ( err ) {
55+ console . warn ( 'API failed → using mock events' ) ;
56+ setEvents ( MOCK_EVENTS ) ;
57+ } finally {
58+ setIsLoading ( false ) ;
59+ }
60+ } ;
4661
47- const fetchEvents = async ( ) => {
48- setIsLoading ( true ) ;
49- try {
50- const response = await axios . get ( ENDPOINTS . EVENTS ) ;
51- const apiEvents = response . data ?. events || response . data || [ ] ;
52-
53- setEvents ( apiEvents . length ? apiEvents : MOCK_EVENTS ) ;
54- } catch ( err ) {
55- setEvents ( MOCK_EVENTS ) ;
56- } finally {
57- setIsLoading ( false ) ;
58- }
59- } ;
62+ fetchEvents ( ) ;
63+ } , [ ] ) ;
6064
61- fetchEvents ( ) ;
62- } , [ ] ) ;
63-
64- const mappedEvents = useMemo ( ( ) => {
65- return events . map ( event => {
66- const eventDate = event . date ? new Date ( event . date ) : new Date ( ) ;
67-
68- return {
69- ...event ,
70- id : event . id || `${ event . title } -${ eventDate . getTime ( ) } ` ,
71- date : eventDate ,
72- type : event . type || 'General' ,
73- status : normalizeStatus ( event . status ) ,
74- time :
75- event . time ||
76- eventDate . toLocaleTimeString ( [ ] , { hour : '2-digit' , minute : '2-digit' } ) ,
77- description : event . description || `Join us for ${ event . title } ` ,
78- location : event . location || 'Online' ,
79- } ;
80- } ) ;
81- } , [ events ] ) ;
65+ const mappedEvents = useMemo ( ( ) => {
66+ return events . map ( event => {
67+ const eventDate = new Date ( event . date ) ;
68+ const timeString = eventDate . toLocaleTimeString ( [ ] , { hour : '2-digit' , minute : '2-digit' } ) ;
69+
70+ return {
71+ ...event ,
72+ id : event . id || `${ event . title } -${ eventDate . getTime ( ) } ` ,
73+ date : eventDate ,
74+ type : event . type || 'General' ,
75+ status : normalizeStatus ( event . status ) ,
76+ time : event . time || timeString ,
77+ description : event . description || `Join us for ${ event . title } ` ,
78+ location : event . location || 'Online' ,
79+ } ;
80+ } ) ;
81+ } , [ events ] ) ;
8282
8383 const filteredEvents = useMemo (
8484 ( ) =>
@@ -165,13 +165,13 @@ const mappedEvents = useMemo(() => {
165165 } ,
166166 [ getEventsForDate ] ,
167167 ) ;
168- const handleEventClick = useCallback ( event => {
169- setSelectedDate ( new Date ( event . date ) ) ;
168+ const handleEventClick = useCallback ( event => {
169+ setSelectedDate ( new Date ( event . date ) ) ;
170170
171- setSelectedEvent ( event ) ;
171+ setSelectedEvent ( event ) ;
172172
173- setShowEventModal ( true ) ;
174- } , [ ] ) ;
173+ setShowEventModal ( true ) ;
174+ } , [ ] ) ;
175175 const closeEventModal = useCallback ( ( ) => {
176176 setShowEventModal ( false ) ;
177177 setSelectedEvent ( null ) ;
@@ -347,51 +347,50 @@ const handleEventClick = useCallback(event => {
347347 const hiddenCount = events . length - 3 ;
348348
349349 return (
350-
351350 < div className = { styles . tileEvents } >
352- { visible . map ( e => {
353- const statusKey = statusMap [ e . status ] || 'statusNew' ;
351+ { visible . map ( e => {
352+ const statusKey = statusMap [ e . status ] || 'statusNew' ;
354353
355- return (
356- < button
357- key = { e . id }
358- type = "button"
359- className = { `${ styles . eventItem } ${ styles [ statusKey ] || '' } ` }
360- onClick = { e_obj => {
361- e_obj . stopPropagation ( ) ;
362- handleEventClick ( e ) ;
363- } }
364- onMouseEnter = { ( ) => setHoveredEventId ( e . id ) }
365- onMouseLeave = { ( ) => setHoveredEventId ( null ) }
366- aria-label = { `Click to view details for ${ e . title } ` }
367- >
368- < span className = { styles . eventContent } >
369- < span className = { styles . eventIcon } aria-label = { e . status } title = { e . status } >
370- { statusIconMap [ e . status ] || '⭐' }
371- </ span >
372- < span className = { styles . eventTitleText } > { e . title } </ span >
373- </ span >
374-
375- { hoveredEventId === e . id && (
376- < div
377- className = { `${ styles . eventTooltip } ${ darkMode ? styles . eventTooltipDark : '' } ` }
378- >
379- < strong > { e . title } </ strong >
380- < span className = { styles . tooltipDetail } >
381- < strong > Time:</ strong > { e . time }
382- </ span >
383- < span className = { styles . tooltipDetail } >
384- < strong > Location:</ strong > { e . location }
385- </ span >
386- < span className = { styles . tooltipDetail } >
387- < strong > Status:</ strong > { e . status }
354+ return (
355+ < button
356+ key = { e . id }
357+ type = "button"
358+ className = { `${ styles . eventItem } ${ styles [ statusKey ] || '' } ` }
359+ onClick = { e_obj => {
360+ e_obj . stopPropagation ( ) ;
361+ handleEventClick ( e ) ;
362+ } }
363+ onMouseEnter = { ( ) => setHoveredEventId ( e . id ) }
364+ onMouseLeave = { ( ) => setHoveredEventId ( null ) }
365+ aria-label = { `Click to view details for ${ e . title } ` }
366+ >
367+ < span className = { styles . eventContent } >
368+ < span className = { styles . eventIcon } aria-label = { e . status } title = { e . status } >
369+ { statusIconMap [ e . status ] || '⭐' }
388370 </ span >
389- < small > Click for more details</ small >
390- </ div >
391- ) }
392- </ button >
393- ) ;
394- } ) }
371+ < span className = { styles . eventTitleText } > { e . title } </ span >
372+ </ span >
373+
374+ { hoveredEventId === e . id && (
375+ < div
376+ className = { `${ styles . eventTooltip } ${ darkMode ? styles . eventTooltipDark : '' } ` }
377+ >
378+ < strong > { e . title } </ strong >
379+ < span className = { styles . tooltipDetail } >
380+ < strong > Time:</ strong > { e . time }
381+ </ span >
382+ < span className = { styles . tooltipDetail } >
383+ < strong > Location:</ strong > { e . location }
384+ </ span >
385+ < span className = { styles . tooltipDetail } >
386+ < strong > Status:</ strong > { e . status }
387+ </ span >
388+ < small > Click for more details</ small >
389+ </ div >
390+ ) }
391+ </ button >
392+ ) ;
393+ } ) }
395394 { hiddenCount > 0 && (
396395 < button
397396 type = "button"
@@ -634,7 +633,10 @@ const handleEventClick = useCallback(event => {
634633 </ li >
635634
636635 < li className = { styles . metaItem } >
637- < FontAwesomeIcon icon = { faLocationDot } className = { styles . metaIcon } />
636+ < FontAwesomeIcon
637+ icon = { faLocationDot }
638+ className = { styles . metaIcon }
639+ />
638640 < span > { event . location } </ span >
639641 </ li >
640642
@@ -644,7 +646,10 @@ const handleEventClick = useCallback(event => {
644646 </ li >
645647
646648 < li className = { styles . metaItem } >
647- < FontAwesomeIcon icon = { faCircleCheck } className = { styles . metaIcon } />
649+ < FontAwesomeIcon
650+ icon = { faCircleCheck }
651+ className = { styles . metaIcon }
652+ />
648653 < span className = { styles . statusInline } >
649654 { statusIconMap [ event . status ] || '' } { event . status }
650655 </ span >
@@ -778,4 +783,3 @@ const handleEventClick = useCallback(event => {
778783 </ div >
779784 ) ;
780785}
781-
0 commit comments