Last
Some checks are pending
Deploy Volleyball CMS / deploy (push) Waiting to run

This commit is contained in:
2025-06-02 18:56:22 +02:00
parent 8f62885a45
commit 33181acf83
1443 changed files with 286102 additions and 12 deletions

View File

@@ -79,6 +79,7 @@ const Navbar = () => {
<Link to="/teams/1" className="block px-3 py-1 text-gray-700 hover:text-frog-600">Herren 1</Link>
<Link to="/teams/2" className="block px-3 py-1 text-gray-700 hover:text-frog-600">Herren 2</Link>
<Link to="/teams/9" className="block px-3 py-1 text-gray-700 hover:text-frog-600">Mixed</Link>
<Link to="/teams/9" className="block px-3 py-1 text-gray-700 hover:text-frog-600">TestTeam</Link>
</div>
)}
</div>

View File

@@ -22,6 +22,11 @@ const Datenschutz = () => {
Wir erheben personenbezogene Daten nur, wenn du uns diese im Rahmen einer Anfrage über unser Kontaktformular mitteilst oder dich einloggst.
</p>
<p className="mb-4">
Beim Besuch dieser Website werden aus Sicherheitsgründen und zur Analyse der Nutzung automatisch Informationen über die IP-Adresse sowie das zugehörige Land (basierend auf öffentlich zugänglichen Geo-Datenbanken) erfasst. Diese Daten werden ausschließlich anonymisiert ausgewertet und nach spätestens 7 Tagen gelöscht. Eine Weitergabe an Dritte erfolgt nicht.
</p>
<h2 className="text-xl font-semibold mt-6 mb-2">3. Kontaktformular</h2>
<p className="mb-4">
Wenn du uns über das Kontaktformular kontaktierst, werden deine Angaben inklusive der von dir dort angegebenen Kontaktdaten zum Zweck der Bearbeitung der Anfrage und für den Fall von Anschlussfragen bei uns gespeichert.
@@ -59,6 +64,12 @@ const Datenschutz = () => {
<p className="mb-4">
Wir behalten uns vor, diese Datenschutzerklärung bei Bedarf anzupassen, um sie stets aktuell zu halten.
</p>
<h2 className="text-xl font-semibold mt-6 mb-2">9. IP- und Geo-Datenanalyse</h2>
<p className="mb-4">
Beim Aufruf unserer Website wird die IP-Adresse deines Geräts automatisch durch unseren Server verarbeitet. Zusätzlich wird das Herkunftsland ermittelt (basierend auf öffentlichen Geo-IP-Datenbanken), um potenzielle Angriffe zu erkennen und statistische Auswertungen durchzuführen. Die Daten werden dabei nicht mit anderen personenbezogenen Informationen verknüpft und nach spätestens 7 Tagen automatisch gelöscht.
</p>
</section>
);
};

View File

@@ -1,9 +1,19 @@
import { Calendar, dateFnsLocalizer } from "react-big-calendar";
import { useState } from "react";
import {
Calendar,
dateFnsLocalizer,
Event as CalendarEvent,
} from "react-big-calendar";
import "react-big-calendar/lib/css/react-big-calendar.css";
import { parse, startOfWeek, format, getDay } from "date-fns";
import { de } from "date-fns/locale";
import { useMemo } from "react";
import { Dialog } from "@headlessui/react";
// Locale-Konfiguration
const locales = {
de: de,
};
@@ -16,40 +26,54 @@ const localizer = dateFnsLocalizer({
locales,
});
// Event-Daten
const events = [
{
title: "Heimspiel Herren 1",
start: new Date("2025-06-08T15:00:00"),
end: new Date("2025-06-08T17:00:00"),
allDay: false,
location: "Sporthalle TG Laudenbach",
description: "Heimspiel gegen TSV XY.",
bgColor: "#000000", // Rot
},
{
title: "Sommerfest",
start: new Date("2025-06-15"),
end: new Date("2025-06-15"),
allDay: true,
description: "Vereinsfest mit BBQ.",
bgColor: "#10b981", // Grün
},
{
title: "Training Jugend U16",
start: new Date("2025-06-17T18:00:00"),
end: new Date("2025-06-17T19:30:00"),
allDay: false,
location: "Halle 2",
description: "Wöchentliches Training.",
bgColor: "#2563eb", // Blau
},
];
const EventsPage = () => {
const [selectedEvent, setSelectedEvent] = useState<any | null>(null);
const handleSelectEvent = (event: CalendarEvent) => {
setSelectedEvent(event);
};
return (
<div className="min-h-screen bg-white py-12 px-4 md:px-12">
<h1 className="text-3xl font-bold mb-6 text-center">Eventkalender</h1>
<div className="bg-white rounded-xl shadow-md p-4">
<Calendar
localizer={localizer}
events={events}
startAccessor="start"
endAccessor="end"
style={{ height: 600 }}
views={["month", "week", "agenda"]}
messages={{
localizer={localizer}
events={events}
startAccessor="start"
endAccessor="end"
style={{ height: 600 }}
views={["month", "week", "agenda"]}
messages={{
today: "Heute",
previous: "Zurück",
next: "Weiter",
@@ -61,9 +85,69 @@ const EventsPage = () => {
time: "Uhrzeit",
event: "Event",
noEventsInRange: "Keine Events im gewählten Zeitraum",
}}
}}
onSelectEvent={handleSelectEvent}
eventPropGetter={(event) => {
const backgroundColor = event.bgColor || "#3b82f6"; // fallback: blau
return {
style: {
backgroundColor,
color: "white",
borderRadius: "0.5rem",
border: "none",
padding: "4px 8px",
},
};
}}
/>
</div>
{/* Modal bei Event-Auswahl */}
<Dialog
open={!!selectedEvent}
onClose={() => setSelectedEvent(null)}
className="fixed inset-0 z-50 flex items-center justify-center p-4"
>
{/* Hintergrund Overlay */}
<div className="fixed inset-0 bg-black bg-opacity-30" aria-hidden="true" />
{/* Modal-Fenster */}
<Dialog.Panel className="bg-white rounded-xl p-6 max-w-md w-full z-10 shadow-lg">
<Dialog.Title className="text-xl font-bold mb-2">
{selectedEvent?.title}
</Dialog.Title>
<p className="text-sm text-gray-500 mb-1">
📅{" "}
{selectedEvent?.start &&
new Date(selectedEvent.start).toLocaleString("de-DE", {
weekday: "long",
day: "2-digit",
month: "long",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
})}
</p>
{selectedEvent?.location && (
<p className="text-sm mb-2">📍 {selectedEvent.location}</p>
)}
{selectedEvent?.description && (
<p className="text-sm text-gray-700">{selectedEvent.description}</p>
)}
<button
onClick={() => setSelectedEvent(null)}
className="mt-4 bg-primary text-white px-4 py-2 rounded hover:bg-primary/90 transition"
>
Schließen
</button>
</Dialog.Panel>
</Dialog>
</div>
);
};