diff --git a/src/admin/AdminDashboard.tsx b/src/admin/AdminDashboard.tsx index add635f58..9d5684a8f 100644 --- a/src/admin/AdminDashboard.tsx +++ b/src/admin/AdminDashboard.tsx @@ -57,7 +57,15 @@ const AdminDashboard = () => { - {/* 🎉 Neue Galerie-Kachel */} + + + + Events verwalten + Alle Events sehen und bearbeiten + + + + diff --git a/src/admin/EventsAdmin.tsx b/src/admin/EventsAdmin.tsx new file mode 100644 index 000000000..f3e692ed8 --- /dev/null +++ b/src/admin/EventsAdmin.tsx @@ -0,0 +1,152 @@ +import { useEffect, useState } from "react"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; +import { Button } from "@/components/ui/button"; +import { Switch } from "@/components/ui/switch"; +import axios from "axios"; + +type Event = { + id?: number; + title: string; + description: string; + max_participants?: number; + fee?: number; + address?: string; + is_private: boolean; +}; + +const defaultEvent: Event = { + title: "", + description: "", + max_participants: undefined, + fee: undefined, + address: "", + is_private: false, +}; + +const EventsAdmin = () => { + const [events, setEvents] = useState([]); + const [form, setForm] = useState(defaultEvent); + const [isEditing, setIsEditing] = useState(false); + + const fetchEvents = async () => { + try { + const res = await axios.get("/api/events?showPrivate=true"); + if (Array.isArray(res.data)) { + setEvents(res.data); + } else { + console.warn("⚠️ Events-API hat kein Array geliefert:", res.data); + setEvents([]); + } + } catch (error) { + console.error("❌ Fehler beim Laden der Events:", error); + setEvents([]); + } + }; + + + useEffect(() => { + fetchEvents(); + }, []); + + const handleSubmit = async () => { + if (isEditing && form.id) { + await axios.put(`/api/events/${form.id}`, form); + } else { + await axios.post("/api/events", form); + } + setForm(defaultEvent); + setIsEditing(false); + fetchEvents(); + }; + + const handleDelete = async (id: number) => { + await axios.delete(`/api/events/${id}`); + fetchEvents(); + }; + + const handleEdit = (event: Event) => { + setForm(event); + setIsEditing(true); + }; + + return ( + + {isEditing ? "Event bearbeiten" : "Neues Event erstellen"} + + + setForm({ ...form, title: e.target.value })} + /> + setForm({ ...form, description: e.target.value })} + /> + setForm({ ...form, max_participants: parseInt(e.target.value) || undefined })} + /> + setForm({ ...form, fee: parseFloat(e.target.value) || undefined })} + /> + setForm({ ...form, address: e.target.value })} + /> + + setForm({ ...form, is_private: val })} + /> + Privat + + + + + {isEditing ? "Speichern" : "Erstellen"} + + {isEditing && ( + { setForm(defaultEvent); setIsEditing(false); }}> + Abbrechen + + )} + + + + + + Bestehende Events + {Array.isArray(events) && events.length > 0 ? ( + + {events.map((ev) => ( + + + {ev.title} + {ev.description?.slice(0, 60)}... + + + handleEdit(ev)}>Bearbeiten + handleDelete(ev.id!)}>Löschen + + + ))} + + ) : ( + Noch keine Events vorhanden. + )} + + + ); +}; + +export default EventsAdmin; diff --git a/src/main.tsx b/src/main.tsx index 7a2a43f5e..d3a7c94fd 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -27,6 +27,7 @@ import PlayerEdit from "./admin/PlayerEdit"; import PlayerManagementPage from "./admin/PlayerManagementPage"; import GalleryManager from "./admin/GalleryManager"; import GalleryPage from "./pages/GalleryPage"; +import EventsAdmin from "./admin/EventsAdmin"; @@ -75,6 +76,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render( } /> } /> } /> + } /> diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx index 5527b2ae2..3cf3e191a 100644 --- a/src/pages/LoginPage.tsx +++ b/src/pages/LoginPage.tsx @@ -22,19 +22,26 @@ const LoginPage = () => { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ username: email, password }), }); - + if (!res.ok) { - throw new Error("Login fehlgeschlagen"); + if (res.status === 429) { + throw new Error("rate_limit"); + } + throw new Error("login_failed"); } - + const data = await res.json(); localStorage.setItem("token", data.token); - navigate("/admin"); - } catch (err) { + } catch (err: any) { console.error(err); - setError("Login fehlgeschlagen. Bitte prüfe Benutzername und Passwort."); + if (err.message === "rate_limit") { + setError("Zu viele fehlgeschlagene Login-Versuche. Bitte versuch es später erneut."); + } else { + setError("Login fehlgeschlagen. Bitte prüfe Benutzername und Passwort."); + } } + }; return (
Alle Events sehen und bearbeiten
Noch keine Events vorhanden.