Skip to content

Commit 33c68e5

Browse files
fix: Ensure EventList component is used in JSX
Corrects an oversight in `app/(web)/verein/veranstaltungen/page.tsx` where the EventCalendar component was still referenced in the JSX after being replaced in imports and intent. This change ensures that the new EventList component is correctly rendered on the page.
1 parent a97f89f commit 33c68e5

File tree

5 files changed

+161
-154
lines changed

5 files changed

+161
-154
lines changed

app/(web)/verein/veranstaltungen/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import { BlockTitle } from "#/components/block-title/BlockTitle";
33
import { PageBase } from "#/components/page/PageBase";
4-
import { EventCalendar } from "#/components/calendar/Calendar";
4+
import { EventList } from "#/components/events/EventList";
55
import { Metadata } from "next";
66
import { getTitle } from "#/lib/page";
77
import { veranstaltungen } from "#/content/sitemap";
@@ -14,8 +14,8 @@ export default function Veranstaltungen() {
1414
return (
1515
<PageBase>
1616
<BlockTitle title={veranstaltungen.name} />
17-
<div className="bg-white shadow-2xl p-2 flex flex-col lg:flex-row gap-2">
18-
<EventCalendar />
17+
<div className="bg-white shadow-2xl p-2">
18+
<EventList />
1919
</div>
2020
</PageBase>
2121
);

components/calendar/Calendar.tsx

Lines changed: 0 additions & 149 deletions
This file was deleted.

components/events/EventCard.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Event } from '#/content/events';
2+
import Link from 'next/link';
3+
import { GrLocation } from 'react-icons/gr'; // Assuming react-icons is available
4+
5+
// Helper function for formatting date and time (can be basic for now)
6+
// It should handle allDay events appropriately.
7+
const formatEventDateTime = (start: Date, end: Date, allDay?: boolean): string => {
8+
const options: Intl.DateTimeFormatOptions = {
9+
weekday: 'short',
10+
year: 'numeric',
11+
month: 'short',
12+
day: 'numeric',
13+
hour: '2-digit',
14+
minute: '2-digit',
15+
hour12: false, // Use 24-hour format or true for 12-hour
16+
};
17+
18+
if (allDay) {
19+
return `${new Date(start).toLocaleDateString('de-DE', { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' })} (Ganztägig)`;
20+
}
21+
22+
const startDateStr = new Date(start).toLocaleDateString('de-DE', { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' });
23+
const startTimeStr = new Date(start).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', hour12: false });
24+
const endTimeStr = new Date(end).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', hour12: false });
25+
26+
// If start and end are on the same day
27+
if (new Date(start).toDateString() === new Date(end).toDateString()) {
28+
return `${startDateStr}, ${startTimeStr} - ${endTimeStr}`;
29+
} else {
30+
// If events span multiple days (less common for cards, but good to handle)
31+
const endDateStr = new Date(end).toLocaleDateString('de-DE', { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric' });
32+
return `${startDateStr}, ${startTimeStr} - ${endDateStr}, ${endTimeStr}`;
33+
}
34+
};
35+
36+
type EventCardProps = {
37+
event: Event;
38+
};
39+
40+
export function EventCard({ event }: EventCardProps) {
41+
return (
42+
<div className="bg-white shadow-lg rounded-lg p-4 mb-4 flex flex-col">
43+
<h3 className="text-xl font-semibold text-svw-blue-default mb-2">{event.title}</h3>
44+
<p className="text-sm text-gray-600 mb-1">
45+
{formatEventDateTime(event.start, event.end, event.allDay)}
46+
</p>
47+
{event.place && (
48+
<div className="flex items-center text-sm text-gray-600 mb-2">
49+
<GrLocation className="mr-1 flex-shrink-0" />
50+
<span className="font-medium">{event.place.name}</span>
51+
{event.place.address && <span className="ml-1">, {event.place.address}</span>}
52+
</div>
53+
)}
54+
{event.url && (
55+
<div className="mt-auto pt-2"> {/* Pushes link to the bottom */}
56+
<Link
57+
href={event.url}
58+
className="inline-block bg-svw-orange-default text-white px-4 py-2 rounded hover:bg-svw-orange-darker transition-colors text-sm font-medium"
59+
>
60+
Details ansehen
61+
</Link>
62+
</div>
63+
)}
64+
</div>
65+
);
66+
}

components/events/EventList.tsx

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
"use client";
2+
3+
import { useEffect, useState } from 'react';
4+
import { EventMatter, Event } from '#/content/events'; // Adjust import if Event is not directly under #/content/events
5+
import { EventCard } from './EventCard'; // Assuming EventCard is in the same directory
6+
import { Spinner } from '#/components/spinner/Spinner'; // Assuming Spinner component path
7+
8+
export function EventList() {
9+
const [eventMatters, setEventMatters] = useState<EventMatter[] | null>(null);
10+
const [isLoading, setIsLoading] = useState(true);
11+
const [error, setError] = useState<string | null>(null);
12+
13+
useEffect(() => {
14+
const fetchEvents = async () => {
15+
try {
16+
const response = await fetch('/api/events');
17+
if (!response.ok) {
18+
throw new Error(`HTTP error! status: ${response.status}`);
19+
}
20+
const data: EventMatter[] = await response.json();
21+
setEventMatters(data);
22+
} catch (e) {
23+
if (e instanceof Error) {
24+
setError(e.message);
25+
} else {
26+
setError('An unknown error occurred.');
27+
}
28+
} finally {
29+
setIsLoading(false);
30+
}
31+
};
32+
33+
fetchEvents();
34+
}, []);
35+
36+
if (isLoading) {
37+
return (
38+
<div className="w-full text-center py-10">
39+
<Spinner />
40+
</div>
41+
);
42+
}
43+
44+
if (error) {
45+
return (
46+
<div className="w-full text-center py-10 text-red-600">
47+
Fehler beim Laden der Veranstaltungen: {error}
48+
</div>
49+
);
50+
}
51+
52+
if (!eventMatters || eventMatters.length === 0) {
53+
return (
54+
<div className="w-full text-center py-10 text-gray-700">
55+
Zurzeit sind keine Veranstaltungen vorhanden.
56+
</div>
57+
);
58+
}
59+
60+
// Flatten all calendar entries from all event matters into a single list of events
61+
// and sort them by start date, earliest first.
62+
const allEvents = eventMatters
63+
.flatMap(em => em.calendarEntries.map(entry => ({
64+
...entry,
65+
// Ensure start and end are Date objects if they aren't already
66+
// The API sends them as strings, EventCard expects Date objects
67+
start: new Date(entry.start),
68+
end: new Date(entry.end),
69+
})))
70+
.sort((a, b) => a.start.getTime() - b.start.getTime());
71+
72+
if (allEvents.length === 0) {
73+
return (
74+
<div className="w-full text-center py-10 text-gray-700">
75+
Zurzeit sind keine Veranstaltungen vorhanden.
76+
</div>
77+
);
78+
}
79+
80+
return (
81+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
82+
{allEvents.map((eventItem, index) => (
83+
// Using slug + index as key if event items within calendarEntries don't have unique IDs
84+
// Ideally, each Event object should have a unique ID for the key.
85+
// For now, we'll use the title and index as a composite key.
86+
// The event object from calendarEntries might not have a slug.
87+
// The Event type itself doesn't have a slug.
88+
<EventCard key={`${eventItem.title}-${index}`} event={eventItem} />
89+
))}
90+
</div>
91+
);
92+
}

package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
"node-fetch": "2.7.0",
4242
"nodemailer": "^6.10.0",
4343
"react": "19.0.0",
44-
"react-big-calendar": "^1.17.1",
4544
"react-dom": "19.0.0",
4645
"react-hotkeys-hook": "^4.6.1",
4746
"react-icons": "^5.0.1",
@@ -69,7 +68,6 @@
6968
"@types/node-fetch": "^2.6.12",
7069
"@types/nodemailer": "^6.4.14",
7170
"@types/react": "19.0.10",
72-
"@types/react-big-calendar": "^1.16.1",
7371
"@types/react-dom": "19.0.4",
7472
"@types/ws": "^8.18.1",
7573
"@typescript-eslint/eslint-plugin": "^8.32.1",

0 commit comments

Comments
 (0)