@@ -3,10 +3,16 @@ import { useState, useEffect } from 'react';
33import { useSelector } from 'react-redux' ;
44import styles from './ActivityList.module.css' ;
55import { mockActivities } from './mockActivities' ;
6- // import { useHistory } from 'react-router-dom';
76
87function ActivityList ( ) {
9- const darkMode = useSelector ( state => state . theme . darkMode ) ;
8+ let darkMode = false ;
9+
10+ try {
11+ darkMode = useSelector ( state => state . theme ?. darkMode ) ;
12+ } catch ( error ) {
13+ darkMode = false ;
14+ }
15+
1016 const [ activities , setActivities ] = useState ( [ ] ) ;
1117 const [ loading , setLoading ] = useState ( true ) ;
1218 const [ error , setError ] = useState ( null ) ;
@@ -17,6 +23,7 @@ function ActivityList() {
1723 } ) ;
1824 const [ locationSuggestions , setLocationSuggestions ] = useState ( [ ] ) ;
1925 const [ showSuggestions , setShowSuggestions ] = useState ( false ) ;
26+ const [ sortOrder , setSortOrder ] = useState ( 'earliest' ) ;
2027
2128 useEffect ( ( ) => {
2229 if ( darkMode ) {
@@ -36,21 +43,10 @@ function ActivityList() {
3643 setLoading ( true ) ;
3744 setError ( null ) ;
3845
39- // TODO: Replace with actual API endpoint
40- // const response = await fetch('/api/activities');
41- // if (!response.ok) {
42- // throw new Error('Failed to fetch activities');
43- // }
44- // const data = await response.json();
45- // setActivities(data);
46-
47- // Simulating API call - remove this when real API is available
48- // For now, we'll use mock data directly
4946 throw new Error ( 'API not implemented yet' ) ;
5047 } catch ( err ) {
5148 console . warn ( 'Failed to fetch activities from API, using mock data:' , err . message ) ;
5249 setError ( err . message ) ;
53- // Fallback to mock data
5450 setActivities ( mockActivities ) ;
5551 } finally {
5652 setLoading ( false ) ;
@@ -60,43 +56,31 @@ function ActivityList() {
6056 fetchActivities ( ) ;
6157 } , [ ] ) ;
6258
63- // Get location suggestions with STRICT prefix-based matching only
6459 const getLocationSuggestions = input => {
65- if ( ! input . trim ( ) ) {
66- return [ ] ;
67- }
60+ if ( ! input . trim ( ) ) return [ ] ;
6861
69- // Get unique locations
7062 const uniqueLocations = [ ...new Set ( activities . map ( a => a . location ) ) ] ;
7163 const lowerInput = input . toLowerCase ( ) ;
7264
73- // ONLY return locations that START with the input (prefix matching)
74- const prefixMatches = uniqueLocations . filter ( loc => loc . toLowerCase ( ) . startsWith ( lowerInput ) ) ;
75-
76- // Limit to top 10 results
77- return prefixMatches . slice ( 0 , 10 ) ;
65+ return uniqueLocations
66+ . filter ( loc => loc . toLowerCase ( ) . startsWith ( lowerInput ) )
67+ . slice ( 0 , 10 ) ;
7868 } ;
7969
8070 const handleFilterChange = e => {
8171 const { name, value } = e . target ;
8272 setFilter ( { ...filter , [ name ] : value } ) ;
8373
84- // Update location suggestions when location input changes
8574 if ( name === 'location' ) {
8675 const suggestions = getLocationSuggestions ( value ) ;
8776 setLocationSuggestions ( suggestions ) ;
8877 setShowSuggestions ( true ) ;
8978 }
9079 } ;
9180
92- const filteredActivities = activities . filter ( activity => {
93- return (
94- ( ! filter . type || activity . type === filter . type ) &&
95- ( ! filter . date || activity . date === filter . date ) &&
96- ( ! filter . location ||
97- activity . location . toLowerCase ( ) . startsWith ( filter . location . toLowerCase ( ) ) )
98- ) ;
99- } ) ;
81+ const handleSortChange = e => {
82+ setSortOrder ( e . target . value ) ;
83+ } ;
10084
10185 const handleSuggestionClick = location => {
10286 setFilter ( { ...filter , location } ) ;
@@ -114,9 +98,26 @@ function ActivityList() {
11498 setShowSuggestions ( false ) ;
11599 } ;
116100
101+ const filteredActivities = activities
102+ . filter ( activity => {
103+ return (
104+ ( ! filter . type || activity . type === filter . type ) &&
105+ ( ! filter . date || activity . date === filter . date ) &&
106+ ( ! filter . location ||
107+ activity . location . toLowerCase ( ) . startsWith ( filter . location . toLowerCase ( ) ) )
108+ ) ;
109+ } )
110+ . sort ( ( a , b ) => {
111+ const dateA = new Date ( a . date ) ;
112+ const dateB = new Date ( b . date ) ;
113+ return sortOrder === 'earliest' ? dateA - dateB : dateB - dateA ;
114+ } ) ;
115+
117116 return (
118117 < div className = { `${ styles . activityListContainer } ${ darkMode ? 'bg-oxford-blue' : '' } ` } >
119- < h1 className = { `${ styles . heading } ${ darkMode ? 'text-light' : '' } ` } > Activity List</ h1 >
118+ < h1 className = { `${ styles . heading } ${ darkMode ? 'text-light' : '' } ` } >
119+ Activity List
120+ </ h1 >
120121
121122 < div className = { `${ styles . filters } ${ darkMode ? styles . darkModeFilters : '' } ` } >
122123 < label className = { darkMode ? 'text-light' : '' } >
@@ -142,6 +143,18 @@ function ActivityList() {
142143 />
143144 </ label >
144145
146+ < label className = { darkMode ? 'text-light' : '' } >
147+ Sort By:
148+ < select
149+ value = { sortOrder }
150+ onChange = { handleSortChange }
151+ className = { darkMode ? styles . darkModeInput : '' }
152+ >
153+ < option value = "earliest" > Start Time: Earliest to Latest</ option >
154+ < option value = "latest" > Start Time: Latest to Earliest</ option >
155+ </ select >
156+ </ label >
157+
145158 < label className = { darkMode ? 'text-light' : '' } >
146159 Location:
147160 < div style = { { position : 'relative' } } >
@@ -157,37 +170,26 @@ function ActivityList() {
157170 setShowSuggestions ( true ) ;
158171 }
159172 } }
160- onBlur = { ( ) => {
161- // Delay to allow click on suggestion
162- setTimeout ( ( ) => setShowSuggestions ( false ) , 200 ) ;
163- } }
173+ onBlur = { ( ) => setTimeout ( ( ) => setShowSuggestions ( false ) , 200 ) }
164174 placeholder = "Enter location"
165175 autoComplete = "off"
166176 className = { darkMode ? styles . darkModeInput : '' }
167177 />
178+
168179 { showSuggestions && locationSuggestions . length > 0 && (
169180 < div
170- className = { `${ styles . suggestions } ${ darkMode ? styles . darkSuggestions : '' } ` }
171- role = "listbox"
172- aria-label = "Location suggestions"
181+ className = { `${ styles . suggestions } ${
182+ darkMode ? styles . darkSuggestions : ''
183+ } ` }
173184 >
174185 { locationSuggestions . map ( ( location , index ) => (
175186 < div
176187 key = { index }
177188 className = { styles . suggestionItem }
178- role = "option"
179- tabIndex = { 0 }
180- aria-selected = "false"
181189 onMouseDown = { e => {
182- e . preventDefault ( ) ; // Prevent blur from firing
190+ e . preventDefault ( ) ;
183191 handleSuggestionClick ( location ) ;
184192 } }
185- onKeyDown = { e => {
186- if ( e . key === 'Enter' || e . key === ' ' ) {
187- e . preventDefault ( ) ;
188- handleSuggestionClick ( location ) ;
189- }
190- } }
191193 >
192194 { location }
193195 </ div >
@@ -196,6 +198,7 @@ function ActivityList() {
196198 ) }
197199 </ div >
198200 </ label >
201+
199202 < div className = { styles . clearButtonWrapper } >
200203 < button
201204 type = "button"
@@ -207,15 +210,23 @@ function ActivityList() {
207210 </ button >
208211 </ div >
209212 </ div >
213+
210214 < div className = { `${ styles . activityList } ${ darkMode ? styles . darkModeList : '' } ` } >
211215 { loading ? (
212216 < p className = { darkMode ? 'text-light' : '' } > Loading activities...</ p >
213217 ) : filteredActivities . length > 0 ? (
214218 < ul >
215219 { filteredActivities . map ( activity => (
216- < li key = { activity . id } className = { darkMode ? styles . darkModeItem : '' } >
217- < strong > { activity . name } </ strong > - { activity . type } - { activity . date } -{ ' ' }
218- { activity . location }
220+ < li
221+ key = { activity . id }
222+ className = { `${ styles . activityItem } ${
223+ darkMode ? styles . darkModeItem : ''
224+ } `}
225+ >
226+ < strong > { activity . name } </ strong >
227+ < span >
228+ { activity . type } – { activity . date } – { activity . location }
229+ </ span >
219230 </ li >
220231 ) ) }
221232 </ ul >
@@ -227,4 +238,4 @@ function ActivityList() {
227238 ) ;
228239}
229240
230- export default ActivityList ;
241+ export default ActivityList ;
0 commit comments