@@ -2,59 +2,91 @@ import { useState, useEffect } from 'react';
22import { Container , Row , Col , Card , CardBody , Button , Input } from 'reactstrap' ;
33import './CPDashboard.css' ;
44import { FaCalendarAlt , FaMapMarkerAlt , FaUserAlt } from 'react-icons/fa' ;
5- import { toast } from 'react-toastify' ;
5+ import { ENDPOINTS } from '../../utils/URL' ;
6+ import axios from 'axios' ;
67
78export function CPDashboard ( ) {
89 const [ events , setEvents ] = useState ( [ ] ) ;
910 const [ search , setSearch ] = useState ( '' ) ;
10- const [ selectedDate , setSelectedDate ] = useState ( '' ) ;
11- const [ dateError , setDateError ] = useState ( '' ) ;
11+ const [ isLoading , setIsLoading ] = useState ( false ) ;
12+ const [ error , setError ] = useState ( null ) ;
13+ const [ pagination , setPagination ] = useState ( {
14+ currentPage : 1 ,
15+ totalPages : 5 ,
16+ total : 0 ,
17+ limit : 6 ,
18+ } ) ;
19+
20+ const FALLBACK_IMG =
21+ 'https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=600&q=60' ;
22+
23+ const FixedRatioImage = ( { src, alt, fallback } ) => (
24+ < div
25+ style = { {
26+ width : '100%' ,
27+ aspectRatio : '4 / 3' ,
28+ overflow : 'hidden' ,
29+ background : '#f2f2f2' ,
30+ } }
31+ >
32+ < img
33+ src = { src || fallback }
34+ alt = { alt }
35+ loading = "lazy"
36+ onError = { e => {
37+ if ( e . currentTarget . src !== fallback ) e . currentTarget . src = fallback ;
38+ } }
39+ style = { {
40+ width : '100%' ,
41+ height : '100%' ,
42+ objectFit : 'cover' ,
43+ display : 'block' ,
44+ } }
45+ />
46+ </ div >
47+ ) ;
1248
1349 useEffect ( ( ) => {
14- const mockEvents = [
15- {
16- id : 1 ,
17- title : 'PGSA Lunch Talks' ,
18- date : 'Friday, December 6 at 12:00PM EST' ,
19- location : 'Disque 919' ,
20- organizer : 'Physics Graduate Student Association' ,
21- image : 'https://via.placeholder.com/300' ,
22- } ,
23- {
24- id : 2 ,
25- title : 'Hot Chocolate/Bake Sale' ,
26- date : 'Friday, December 6 at 12:00PM EST' ,
27- location : 'G.C LeBow - Lobby Tabling Space 2' ,
28- organizer : 'Kappa Phi Gamma, Sorority Inc.' ,
29- image : 'https://via.placeholder.com/300' ,
30- } ,
31- {
32- id : 3 ,
33- title : 'Holiday Lunch' ,
34- date : 'Friday, December 6 at 12:00PM EST' ,
35- location : 'Hill Conference Room' ,
36- organizer : 'Chemical and Biological Engineering Graduate Society' ,
37- image : 'https://via.placeholder.com/300' ,
38- } ,
39- ] ;
40- setEvents ( mockEvents ) ;
50+ const fetchEvents = async ( ) => {
51+ setIsLoading ( true ) ;
52+
53+ try {
54+ const response = await axios . get ( ENDPOINTS . EVENTS ) ;
55+ console . log ( 'Fetched events:' , response . data . events ) ;
56+ setEvents ( response . data . events ) ;
57+ } catch ( err ) {
58+ console . error ( 'Here' , err ) ;
59+ setError ( 'Failed to load events' ) ;
60+ } finally {
61+ setIsLoading ( false ) ;
62+ }
63+ } ;
64+
65+ fetchEvents ( ) ;
4166 } , [ ] ) ;
4267
43- const handleDateChange = e => {
44- const value = e . target . value ;
45- setSelectedDate ( value ) ;
68+ const formatDate = dateStr => {
69+ if ( ! dateStr ) return 'Date TBD' ;
70+ const date = new Date ( dateStr ) ;
71+ return date . toLocaleString ( 'en-US' , {
72+ weekday : 'long' ,
73+ month : 'long' ,
74+ day : 'numeric' ,
75+ hour : 'numeric' ,
76+ minute : '2-digit' ,
77+ } ) ;
78+ } ;
4679
47- const today = new Date ( ) ;
48- today . setHours ( 0 , 0 , 0 , 0 ) ; // midnight today
80+ const filteredEvents = events . filter ( event =>
81+ event . title ?. toLowerCase ( ) . includes ( search . toLowerCase ( ) ) ,
82+ ) ;
4983
50- const chosen = new Date ( value ) ;
84+ const totalPages = Math . ceil ( filteredEvents . length / pagination . limit ) ;
5185
52- if ( chosen < today ) {
53- toast . error ( 'Past dates are not supported. Please select a future date.' ) ;
54- setSelectedDate ( '' ) ;
55- return ;
56- }
57- } ;
86+ const displayedEvents = filteredEvents . slice (
87+ ( pagination . currentPage - 1 ) * pagination . limit ,
88+ pagination . currentPage * pagination . limit ,
89+ ) ;
5890
5991 return (
6092 < Container fluid className = "dashboard-container" >
@@ -70,17 +102,6 @@ export function CPDashboard() {
70102 className = "dashboard-search"
71103 />
72104 </ div >
73- { /* <Dropdown isOpen={dropdownOpen} toggle={toggleDropdown} className="community-dropdown">
74- <DropdownToggle caret color="secondary">
75- Community Portal
76- </DropdownToggle>
77- <DropdownMenu>
78- <DropdownItem onClick={() => handleNavigation('/home')}>Home</DropdownItem>
79- <DropdownItem onClick={() => handleNavigation('/events')}>Events</DropdownItem>
80- <DropdownItem onClick={() => handleNavigation('/about')}>About Us</DropdownItem>
81- <DropdownItem onClick={() => handleNavigation('/contact')}>Contact</DropdownItem>
82- </DropdownMenu>
83- </Dropdown> */ }
84105 </ div >
85106 </ header >
86107
@@ -139,34 +160,81 @@ export function CPDashboard() {
139160
140161 < Col md = { 9 } className = "dashboard-main" >
141162 < h2 className = "section-title" > Events</ h2 >
142- < Row >
143- { events . length > 0 ? (
144- events . map ( event => (
145- < Col md = { 4 } key = { event . id } className = "event-card-col" >
146- < Card className = "event-card" >
163+
164+ { error && < div className = "alert alert-danger" > { error } </ div > }
165+
166+ { isLoading ? (
167+ < div className = "d-flex justify-content-center mt-4" > </ div >
168+ ) : displayedEvents . length > 0 ? (
169+ < Row >
170+ { displayedEvents . map ( event => (
171+ < Col md = { 4 } key = { event . _id || event . id } className = "event-card-col" >
172+ < Card
173+ className = "event-card"
174+ style = { {
175+ display : 'flex' ,
176+ flexDirection : 'column' ,
177+ borderRadius : 14 ,
178+ overflow : 'hidden' ,
179+ } }
180+ >
147181 < div className = "event-card-img-container" >
148- < img src = { event . image } alt = { event . title } className = "event-card-img" />
182+ < FixedRatioImage
183+ src = { event . coverImage }
184+ alt = { event . title }
185+ fallback = { FALLBACK_IMG }
186+ />
149187 </ div >
150- < CardBody >
188+ < CardBody style = { { flex : 1 , display : 'flex' , flexDirection : 'column' } } >
151189 < h5 className = "event-title" > { event . title } </ h5 >
152190 < p className = "event-date" >
153- < FaCalendarAlt className = "event-icon" /> { event . date }
191+ < FaCalendarAlt className = "event-icon" /> { formatDate ( event . date ) }
154192 </ p >
155193 < p className = "event-location" >
156- < FaMapMarkerAlt className = "event-icon" /> { event . location }
194+ < FaMapMarkerAlt className = "event-icon" /> { event . location || 'TBD' }
157195 </ p >
158196 < p className = "event-organizer" >
159- < FaUserAlt className = "event-icon" /> { event . organizer }
197+ < FaUserAlt className = "event-icon" /> { event . maxAttendees || 'No limit' } { ' ' }
198+ Attendees limit
160199 </ p >
161200 </ CardBody >
162201 </ Card >
163202 </ Col >
164- ) )
165- ) : (
166- < div className = "no-events" > No events available</ div >
167- ) }
168- </ Row >
169- < div className = "dashboard-actions" >
203+ ) ) }
204+ </ Row >
205+ ) : (
206+ < div className = "no-events" > No events available</ div >
207+ ) }
208+
209+ < div className = "d-flex justify-content-center mt-4" >
210+ < div className = "pagination-controls" >
211+ < Button
212+ color = "secondary"
213+ disabled = { pagination . currentPage === 1 }
214+ onClick = { ( ) =>
215+ setPagination ( prev => ( { ...prev , currentPage : prev . currentPage - 1 } ) )
216+ }
217+ >
218+ Previous
219+ </ Button >
220+
221+ < span className = "mx-3" >
222+ Page { pagination . currentPage } of { totalPages }
223+ </ span >
224+
225+ < Button
226+ color = "secondary"
227+ disabled = { pagination . currentPage === totalPages }
228+ onClick = { ( ) =>
229+ setPagination ( prev => ( { ...prev , currentPage : prev . currentPage + 1 } ) )
230+ }
231+ >
232+ Next
233+ </ Button >
234+ </ div >
235+ </ div >
236+
237+ < div className = "dashboard-actions text-center mt-4" >
170238 < Button color = "primary" > Show Past Events</ Button >
171239 </ div >
172240 </ Col >
0 commit comments