Login integriert
This commit is contained in:
@@ -1,54 +1,28 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Select, SelectItem } from "@/components/ui/select"; // Falls du ein Select UI-Element hast
|
||||
|
||||
const news = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Saisonstart 2023/24",
|
||||
date: "2023-09-15",
|
||||
description: "Die neue Saison beginnt mit einem Heimspiel gegen VfB Mosbach. Kommt vorbei und unterstützt unser Team!",
|
||||
image: "https://images.unsplash.com/photo-1612872087720-bb876e2e67d1?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80",
|
||||
team: "Herren I"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Beachvolleyball-Turnier",
|
||||
date: "2023-07-03",
|
||||
description: "Unser jährliches Beachvolleyball-Turnier war ein voller Erfolg! 24 Teams kämpften um den Sieg.",
|
||||
image: "https://images.unsplash.com/photo-1583514555852-6f77e7c9e081?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80",
|
||||
team: "Mixed-Team"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "Neuer Trainer für die Jugendmannschaft",
|
||||
date: "2023-05-21",
|
||||
description: "Wir freuen uns, Marc Schneider als neuen Trainer für unsere U16-Mannschaft begrüßen zu dürfen.",
|
||||
image: "https://images.unsplash.com/photo-1547347298-4074fc3086f0?ixlib=rb-4.0.3&auto=format&fit=crop&w=500&q=80",
|
||||
team: "Jugend U16"
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
type NewsItem = {
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
image_url: string;
|
||||
team: string;
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
const AlleNeuigkeitenPage = () => {
|
||||
const [selectedTeam, setSelectedTeam] = useState("Alle");
|
||||
const [news, setNews] = useState<NewsItem[]>([]);
|
||||
|
||||
// Teams dynamisch auslesen
|
||||
const teams = ["Alle", ...Array.from(new Set(news.map((item) => item.team)))];
|
||||
|
||||
// Nach Datum absteigend sortieren
|
||||
const sortedNews = [...news].sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
||||
|
||||
// Nach Team filtern
|
||||
const filteredNews = sortedNews.filter((item) =>
|
||||
selectedTeam === "Alle" ? true : item.team === selectedTeam
|
||||
);
|
||||
useEffect(() => {
|
||||
fetch("http://192.168.50.65:3000/api/news")
|
||||
.then((res) => res.json())
|
||||
.then((data) => setNews(data))
|
||||
.catch((err) => console.error("Fehler beim Laden der News:", err));
|
||||
}, []);
|
||||
|
||||
// Gruppieren nach Jahren
|
||||
const groupedNews = filteredNews.reduce((acc: any, item) => {
|
||||
const year = new Date(item.date).getFullYear();
|
||||
const groupedNews = news.reduce((acc: Record<string, NewsItem[]>, item) => {
|
||||
const year = new Date(item.created_at).getFullYear().toString();
|
||||
if (!acc[year]) acc[year] = [];
|
||||
acc[year].push(item);
|
||||
return acc;
|
||||
@@ -58,34 +32,23 @@ const AlleNeuigkeitenPage = () => {
|
||||
<div className="max-w-5xl mx-auto px-4 py-12">
|
||||
<h1 className="text-3xl font-bold text-center mb-8 text-frog-600">Alle Neuigkeiten</h1>
|
||||
|
||||
{/* Team-Filter */}
|
||||
<div className="flex justify-center mb-8">
|
||||
<select
|
||||
value={selectedTeam}
|
||||
onChange={(e) => setSelectedTeam(e.target.value)}
|
||||
className="border border-gray-300 rounded-md p-2"
|
||||
>
|
||||
{teams.map((team) => (
|
||||
<option key={team} value={team}>
|
||||
{team}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* News nach Jahren gruppiert */}
|
||||
{Object.entries(groupedNews).map(([year, items]) => (
|
||||
<div key={year} className="mb-12">
|
||||
<h2 className="text-2xl font-bold text-frog-500 mb-4">{year}</h2>
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{(items as typeof news).map((item) => (
|
||||
{items.map((item) => (
|
||||
<Card key={item.id} className="overflow-hidden">
|
||||
<div className="h-48 overflow-hidden">
|
||||
<img src={item.image} alt={item.title} className="w-full h-full object-cover" />
|
||||
<img
|
||||
src={item.image_url || "https://via.placeholder.com/400x300?text=Kein+Bild"}
|
||||
alt={item.title}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<CardHeader>
|
||||
<CardTitle>{item.title}</CardTitle>
|
||||
<CardDescription>{new Date(item.date).toLocaleDateString("de-DE")}</CardDescription>
|
||||
<CardDescription>{new Date(item.created_at).toLocaleDateString("de-DE")}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p>{item.description}</p>
|
||||
@@ -95,7 +58,6 @@ const AlleNeuigkeitenPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,40 @@
|
||||
import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
|
||||
const LoginPage = () => {
|
||||
const [email, setEmail] = useState(""); // Wird eigentlich Username sein!
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const navigate = useNavigate();
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError("");
|
||||
|
||||
try {
|
||||
const res = await fetch("http://192.168.50.65:3000/api/login", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ username: email, password }),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("Login fehlgeschlagen");
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
localStorage.setItem("token", data.token);
|
||||
|
||||
navigate("/admin");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setError("Login fehlgeschlagen. Bitte prüfe Benutzername und Passwort.");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-screen bg-gray-50">
|
||||
<Card className="w-full max-w-md">
|
||||
@@ -10,9 +42,22 @@ const LoginPage = () => {
|
||||
<CardTitle className="text-center text-frog-600">Login</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form className="space-y-4">
|
||||
<Input placeholder="E-Mail-Adresse" type="email" required />
|
||||
<Input placeholder="Passwort" type="password" required />
|
||||
<form className="space-y-4" onSubmit={handleLogin}>
|
||||
<Input
|
||||
placeholder="Benutzername"
|
||||
type="text"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
placeholder="Passwort"
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
/>
|
||||
{error && <p className="text-red-500 text-sm">{error}</p>}
|
||||
<Button type="submit" className="w-full bg-frog-500 hover:bg-frog-600 text-white">
|
||||
Einloggen
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user