@@ -26,6 +26,51 @@ import {
2626 CardTitle ,
2727} from "@/components/ui/card" ;
2828
29+ function eventsSection ( isLoading : boolean , error : string | null , events : EventProps [ ] ) : React . ReactElement {
30+ const today = new Date ( ) ;
31+
32+ // Conditional rendering for loading, error, and no events
33+ if ( isLoading ) {
34+ return < div className = "text-center py-20" > Loading events...</ div > ;
35+ }
36+
37+ if ( error ) {
38+ return < div className = "text-center py-20 text-red-500" > Error: Could not load events.</ div > ;
39+ }
40+
41+ if ( events . length === 0 ) {
42+ return < div className = "text-center py-20 dark:text-gray-300" > No scheduled events found.</ div > ;
43+ }
44+
45+ return < >
46+ { /* Past Events */ }
47+ < div className = "space-y-4" >
48+ < h3 className = "text-xl font-semibold dark:text-white text-gray-900 mb-4 flex items-center" >
49+ < Users2 className = "w-5 h-5 mr-2 dark:text-blue-400 text-blue-500" />
50+ Vergangene Treffen
51+ </ h3 >
52+ { events
53+ . filter ( ( event ) => event . endTimestamp < today . getTime ( ) )
54+ . map ( ( event ) => (
55+ < Event key = { event . title + event . startTimestamp } { ...event } />
56+ ) ) }
57+ </ div >
58+
59+ { /* Future Events */ }
60+ < div className = "space-y-4" >
61+ < h3 className = "text-xl font-semibold dark:text-white text-gray-900 mb-4 flex items-center" >
62+ < CalendarIcon className = "w-5 h-5 mr-2 text-blue-400" />
63+ Kommende Events
64+ </ h3 >
65+ { events
66+ . filter ( ( event ) => event . endTimestamp >= today . getTime ( ) )
67+ . map ( ( event ) => (
68+ < Event key = { event . title + event . startTimestamp } { ...event } />
69+ ) ) }
70+ </ div >
71+ </ >
72+ }
73+
2974export default function HomePage ( ) {
3075 // Define the URL for the JSON data
3176 const eventsUrl = "https://raw.githubusercontent.com/TUM-Dev/Website/refs/heads/event-data/scheduled_events.json" ;
@@ -235,66 +280,49 @@ export default function HomePage() {
235280 tech : [ "To" , "Be" , "Decided" ] ,
236281 } ,
237282 ] ;
238-
239-
283+
284+
240285 // Use the useEffect hook to fetch data when the component mounts
241286 useEffect ( ( ) => {
242287 const fetchEvents = async ( ) => {
243- try {
244- // Fetch the JSON data from the URL
245- const response = await fetch ( eventsUrl ) ;
246- if ( ! response . ok ) {
247- throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
248- }
249- const data = await response . json ( ) ;
288+ try {
289+ // Fetch the JSON data from the URL
290+ const response = await fetch ( eventsUrl ) ;
291+ if ( ! response . ok ) {
292+ throw new Error ( `HTTP error! status: ${ response . status } ` ) ;
293+ }
294+ const data = await response . json ( ) ;
250295
251- // Convert timestamps from string to Date objects
252- const formattedEvents : EventProps [ ] = data . map ( ( event : any ) => ( {
253- ...event ,
254- title : event . name ,
255- description : event . description ,
256- location : event . entity_metadata ?. location || "Online" , // Use optional chaining for safety
257- startTimestamp : new Date ( event . scheduled_start_time ) . getTime ( ) ,
258- endTimestamp : new Date ( event . scheduled_end_time ) . getTime ( ) ,
259- // Derive the type based on the name
260- type : event . name . toLowerCase ( ) . includes ( "coding" ) ? "coding" :
261- event . name . toLowerCase ( ) . includes ( "meeting" ) ? "meeting" :
262- "event"
263- } ) ) ;
296+ // Convert timestamps from string to Date objects
297+ const formattedEvents : EventProps [ ] = data . map ( ( event : any ) => ( {
298+ ...event ,
299+ title : event . name ,
300+ description : event . description ,
301+ location : event . entity_metadata ?. location || "Online" , // Use optional chaining for safety
302+ startTimestamp : new Date ( event . scheduled_start_time ) . getTime ( ) ,
303+ endTimestamp : new Date ( event . scheduled_end_time ) . getTime ( ) ,
304+ // Derive the type based on the name
305+ type : event . name . toLowerCase ( ) . includes ( "coding" ) ? "coding" :
306+ event . name . toLowerCase ( ) . includes ( "meeting" ) ? "meeting" :
307+ "event"
308+ } ) ) ;
264309
265- // Set the events state with the fetched data, sorted by start time
266- setEvents ( formattedEvents . sort ( ( a , b ) => a . startTimestamp - b . startTimestamp ) ) ;
267- } catch ( e ) {
268- // Set the error state if fetching fails
269- if ( e instanceof Error ) {
270- setError ( e . message ) ;
310+ // Set the events state with the fetched data, sorted by start time
311+ setEvents ( formattedEvents . sort ( ( a , b ) => a . startTimestamp - b . startTimestamp ) ) ;
312+ } catch ( e ) {
313+ // Set the error state if fetching fails
314+ if ( e instanceof Error ) {
315+ setError ( e . message ) ;
316+ }
317+ } finally {
318+ // Set loading to false once the request is complete
319+ setIsLoading ( false ) ;
271320 }
272- } finally {
273- // Set loading to false once the request is complete
274- setIsLoading ( false ) ;
275- }
276321 } ;
277322
278323 fetchEvents ( ) ;
279324 } , [ ] ) ; // The empty array ensures this effect runs only once
280325
281- const today = new Date ( ) ;
282-
283- // Conditional rendering for loading, error, and no events
284- if ( isLoading ) {
285- return < div className = "text-center py-20" > Loading events...</ div > ;
286- }
287-
288- if ( error ) {
289- return < div className = "text-center py-20 text-red-500" > Error: Could not load events.</ div > ;
290- }
291-
292- if ( events . length === 0 ) {
293- // You might want to handle this case more gracefully
294- // For example, by showing a "No upcoming events" message
295- return < div className = "text-center py-20 dark:text-gray-300" > No scheduled events found.</ div > ;
296- }
297-
298326 return (
299327 < div >
300328 < section className = "py-20 px-4" >
@@ -415,42 +443,18 @@ export default function HomePage() {
415443 id = "events"
416444 >
417445 < div className = "container mx-auto max-w-6xl" >
418- < div className = "text-center mb-12" >
419- < h2 className = "text-3xl font-bold dark:text-white text-gray-900 mb-4" >
420- Termine
421- </ h2 >
422- < p className = "dark:text-gray-300 text-gray-600" >
423- Verpasse keine unserer Veranstaltungen und Treffen
424- </ p >
425- </ div >
426-
427- < div className = "grid lg:grid-cols-2 gap-8" >
428- { /* Past Events */ }
429- < div className = "space-y-4" >
430- < h3 className = "text-xl font-semibold dark:text-white text-gray-900 mb-4 flex items-center" >
431- < Users2 className = "w-5 h-5 mr-2 dark:text-blue-400 text-blue-500" />
432- Vergangene Treffen
433- </ h3 >
434- { events
435- . filter ( ( event ) => event . endTimestamp < today . getTime ( ) )
436- . map ( ( event ) => (
437- < Event key = { event . title + event . startTimestamp } { ...event } />
438- ) ) }
446+ < div className = "text-center mb-12" >
447+ < h2 className = "text-3xl font-bold dark:text-white text-gray-900 mb-4" >
448+ Termine
449+ </ h2 >
450+ < p className = "dark:text-gray-300 text-gray-600" >
451+ Verpasse keine unserer Veranstaltungen und Treffen
452+ </ p >
439453 </ div >
440454
441- { /* Future Events */ }
442- < div className = "space-y-4" >
443- < h3 className = "text-xl font-semibold dark:text-white text-gray-900 mb-4 flex items-center" >
444- < CalendarIcon className = "w-5 h-5 mr-2 text-blue-400" />
445- Kommende Events
446- </ h3 >
447- { events
448- . filter ( ( event ) => event . endTimestamp >= today . getTime ( ) )
449- . map ( ( event ) => (
450- < Event key = { event . title + event . startTimestamp } { ...event } />
451- ) ) }
455+ < div className = "grid lg:grid-cols-2 gap-8" >
456+ { eventsSection ( isLoading , error , events ) }
452457 </ div >
453- </ div >
454458 </ div >
455459 </ section >
456460
0 commit comments