This commit is contained in:
parent
6f5d0a0fd0
commit
1d5dea8ff1
@ -18,8 +18,8 @@ const AdminDashboard = () => {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{/* Jeder eingeloggt Benutzer darf News verwalten */}
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{/* Jeder Benutzer darf News verwalten */}
|
||||
<Link to="/admin/news">
|
||||
<Card className="hover:shadow-lg transition-shadow cursor-pointer">
|
||||
<CardContent className="p-6 text-center">
|
||||
@ -49,6 +49,15 @@ const AdminDashboard = () => {
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
|
||||
<Link to="/admin/players">
|
||||
<Card className="hover:shadow-lg transition-shadow cursor-pointer">
|
||||
<CardContent className="p-6 text-center">
|
||||
<CardTitle className="text-frog-600">Spieler verwalten</CardTitle>
|
||||
<p className="text-gray-600 mt-2 text-sm">Alle Spieler sehen und bearbeiten</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -2,14 +2,21 @@ import { useEffect, useState } from "react";
|
||||
import { useParams, useNavigate, Link } from "react-router-dom";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useToast } from "@/components/ui//use-toast";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
|
||||
const apiBase = import.meta.env.VITE_API_URL;
|
||||
|
||||
type Team = {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
|
||||
const PlayerEdit = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
const {toast} = useToast();
|
||||
const { toast } = useToast();
|
||||
|
||||
const [name, setName] = useState("");
|
||||
const [nickname, setNickname] = useState("");
|
||||
@ -21,8 +28,12 @@ const PlayerEdit = () => {
|
||||
const [imageUrl, setImageUrl] = useState<string | null>(null);
|
||||
const [uploading, setUploading] = useState(false);
|
||||
|
||||
const [teams, setTeams] = useState<Team[]>([]);
|
||||
const [selectedTeamId, setSelectedTeamId] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetchPlayer();
|
||||
fetchTeams();
|
||||
}, [id]);
|
||||
|
||||
const fetchPlayer = async () => {
|
||||
@ -38,11 +49,24 @@ const PlayerEdit = () => {
|
||||
setFavoriteFood(data.favorite_food || "");
|
||||
setStatus(data.status || "aktiv");
|
||||
setImageUrl(data.image_url ? `${apiBase}${data.image_url}` : null);
|
||||
if (data.team_ids && data.team_ids.length > 0) {
|
||||
setSelectedTeamId(data.team_ids[0]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Fehler beim Laden des Spielers:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchTeams = async () => {
|
||||
try {
|
||||
const res = await fetch(`${apiBase}/api/teams`);
|
||||
const data = await res.json();
|
||||
setTeams(data);
|
||||
} catch (err) {
|
||||
console.error("Fehler beim Laden der Teams:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleImageUpload = async (file: File) => {
|
||||
const formData = new FormData();
|
||||
formData.append("image", file);
|
||||
@ -67,6 +91,7 @@ const PlayerEdit = () => {
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
// Spieler speichern
|
||||
const res = await fetch(`${apiBase}/api/players/${id}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@ -78,26 +103,33 @@ const PlayerEdit = () => {
|
||||
birthdate,
|
||||
favorite_food: favoriteFood,
|
||||
status,
|
||||
image_url: imageUrl?.replace(apiBase, ""), // Nur Pfad speichern
|
||||
image_url: imageUrl?.replace(apiBase, ""),
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
toast({
|
||||
title: "Spieler gespeichert",
|
||||
description: "Die Änderungen wurden erfolgreich übernommen.",
|
||||
|
||||
if (!res.ok) throw new Error("Fehler beim Speichern");
|
||||
|
||||
// Teamzuordnung aktualisieren
|
||||
if (selectedTeamId) {
|
||||
await fetch(`${apiBase}/api/players/${id}/assign-team`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ team_id: selectedTeamId }),
|
||||
});
|
||||
setTimeout(() => {
|
||||
navigate(-1);
|
||||
}, 500); // Warte kurz, damit der Toast sichtbar bleibt
|
||||
} else {
|
||||
console.error("Fehler beim Speichern");
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "Spieler gespeichert",
|
||||
description: "Die Änderungen wurden erfolgreich übernommen.",
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
navigate(-1);
|
||||
}, 500);
|
||||
} catch (err) {
|
||||
console.error("Fehler beim Speichern:", err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto py-12 px-4">
|
||||
@ -130,6 +162,26 @@ const PlayerEdit = () => {
|
||||
onChange={(e) => setStatus(e.target.value)}
|
||||
/>
|
||||
|
||||
{/* Team Auswahl */}
|
||||
<div>
|
||||
<Label>Teamzugehörigkeit</Label>
|
||||
<Select
|
||||
value={selectedTeamId?.toString()}
|
||||
onValueChange={(value) => setSelectedTeamId(Number(value))}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Team auswählen" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{teams.map((team) => (
|
||||
<SelectItem key={team.id} value={team.id.toString()}>
|
||||
{team.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* Bild-Upload */}
|
||||
<Input
|
||||
type="file"
|
||||
@ -151,7 +203,7 @@ const PlayerEdit = () => {
|
||||
{/* Buttons */}
|
||||
<div className="flex justify-end gap-4 mt-6">
|
||||
<Button variant="outline" asChild>
|
||||
<Link to="/admin/teams">Abbrechen</Link>
|
||||
<Link to="/admin/players">Abbrechen</Link>
|
||||
</Button>
|
||||
<Button onClick={handleSave} className="bg-frog-500 hover:bg-frog-600 text-white">
|
||||
Speichern
|
||||
|
||||
101
src/admin/PlayerManagementPage.tsx
Normal file
101
src/admin/PlayerManagementPage.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Card, CardContent, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { toast } from "sonner";
|
||||
|
||||
const apiBase = import.meta.env.VITE_API_URL;
|
||||
|
||||
type Player = {
|
||||
id: number;
|
||||
name: string;
|
||||
nickname?: string;
|
||||
position: string;
|
||||
jersey_number?: number;
|
||||
image_url?: string;
|
||||
};
|
||||
|
||||
const PlayerManagementPage = () => {
|
||||
const [players, setPlayers] = useState<Player[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const fetchPlayers = async () => {
|
||||
try {
|
||||
const res = await fetch(`${apiBase}/api/players`);
|
||||
const data = await res.json();
|
||||
setPlayers(data);
|
||||
} catch (err) {
|
||||
console.error("Fehler beim Laden der Spieler:", err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchPlayers();
|
||||
}, []);
|
||||
|
||||
const handleDelete = async (id: number) => {
|
||||
if (!confirm("Willst du diesen Spieler wirklich löschen?")) return;
|
||||
|
||||
try {
|
||||
const res = await fetch(`${apiBase}/api/players/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
setPlayers((prev) => prev.filter((p) => p.id !== id));
|
||||
toast.success("Spieler erfolgreich gelöscht!");
|
||||
} else {
|
||||
toast.error("Fehler beim Löschen des Spielers");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Fehler beim Löschen:", err);
|
||||
toast.error("Serverfehler");
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) return <p className="text-center py-12">Lade Spieler...</p>;
|
||||
|
||||
return (
|
||||
<div className="max-w-6xl mx-auto py-12 px-4">
|
||||
<h1 className="text-3xl font-bold text-frog-600 mb-8">Spieler verwalten</h1>
|
||||
|
||||
{players.length === 0 ? (
|
||||
<p className="text-gray-600 text-center">Noch keine Spieler vorhanden.</p>
|
||||
) : (
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{players.map((player) => (
|
||||
<Card key={player.id} className="hover:shadow-md transition-shadow">
|
||||
<CardContent className="flex flex-col items-center p-6">
|
||||
<img
|
||||
src={player.image_url ? `${apiBase}${player.image_url}` : "/images/default-player.png"}
|
||||
alt={player.name}
|
||||
className="w-24 h-24 rounded-full object-cover border-2 border-frog-500 shadow-md mb-4"
|
||||
/>
|
||||
<CardTitle className="text-center">
|
||||
{player.name} {player.nickname && `(${player.nickname})`}
|
||||
</CardTitle>
|
||||
<p className="text-gray-500 text-sm mt-2">{player.position}</p>
|
||||
{player.jersey_number && (
|
||||
<p className="text-gray-500 text-sm"># {player.jersey_number}</p>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2 mt-4">
|
||||
<Button asChild variant="outline" className="text-frog-600 border-frog-500 hover:bg-frog-50">
|
||||
<Link to={`/admin/players/${player.id}/edit`}>Bearbeiten</Link>
|
||||
</Button>
|
||||
<Button variant="destructive" onClick={() => handleDelete(player.id)}>
|
||||
Löschen
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlayerManagementPage;
|
||||
@ -2,11 +2,26 @@ import { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
|
||||
const apiBase = import.meta.env.VITE_API_URL;
|
||||
|
||||
const TeamCreate = () => {
|
||||
const [teamName, setTeamName] = useState("");
|
||||
const [liga, setLiga] = useState("");
|
||||
const [suchtSpieler, setSuchtSpieler] = useState(false);
|
||||
const [socialMedia, setSocialMedia] = useState("");
|
||||
const [trainerName, setTrainerName] = useState("");
|
||||
const [carouselImages, setCarouselImages] = useState<string>("");
|
||||
const [trainingszeiten, setTrainingszeiten] = useState("");
|
||||
const [trainingsort, setTrainingsort] = useState("");
|
||||
const [kontaktName, setKontaktName] = useState("");
|
||||
const [kontaktEmail, setKontaktEmail] = useState("");
|
||||
const [teamfarben, setTeamfarben] = useState("");
|
||||
const [beschreibung, setBeschreibung] = useState("");
|
||||
const [tabellenlink, setTabellenlink] = useState("");
|
||||
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [errorMsg, setErrorMsg] = useState("");
|
||||
|
||||
@ -14,23 +29,37 @@ const TeamCreate = () => {
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!teamName.trim()) return;
|
||||
|
||||
|
||||
setSaving(true);
|
||||
setErrorMsg("");
|
||||
|
||||
|
||||
try {
|
||||
const res = await fetch(`${apiBase}/api/teams`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ name: teamName }),
|
||||
body: JSON.stringify({
|
||||
name: teamName,
|
||||
liga,
|
||||
sucht_spieler: suchtSpieler,
|
||||
social_media: socialMedia,
|
||||
karussell_bilder: carouselImages.trim() ? JSON.parse(carouselImages) : [],
|
||||
trainer_name: trainerName,
|
||||
trainingszeiten,
|
||||
trainingsort,
|
||||
kontakt_name: kontaktName,
|
||||
kontakt_email: kontaktEmail,
|
||||
teamfarben,
|
||||
beschreibung,
|
||||
tabellenlink,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
if (!res.ok) {
|
||||
const msg = await res.text();
|
||||
setErrorMsg(msg);
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
|
||||
navigate("/admin/teams");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@ -38,22 +67,50 @@ const TeamCreate = () => {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl mx-auto py-12 px-4">
|
||||
<h1 className="text-3xl font-bold text-frog-600 mb-6">Neues Team anlegen</h1>
|
||||
|
||||
<div className="space-y-4">
|
||||
<Input
|
||||
placeholder="Teamname"
|
||||
value={teamName}
|
||||
onChange={(e) => setTeamName(e.target.value)}
|
||||
/>
|
||||
<Input placeholder="Teamname" value={teamName} onChange={(e) => setTeamName(e.target.value)} />
|
||||
<Input placeholder="Liga" value={liga} onChange={(e) => setLiga(e.target.value)} />
|
||||
<Input placeholder="Trainer/in" value={trainerName} onChange={(e) => setTrainerName(e.target.value)} />
|
||||
<Input placeholder="Trainingszeiten" value={trainingszeiten} onChange={(e) => setTrainingszeiten(e.target.value)} />
|
||||
<Input placeholder="Trainingsort" value={trainingsort} onChange={(e) => setTrainingsort(e.target.value)} />
|
||||
<Input placeholder="Kontaktname" value={kontaktName} onChange={(e) => setKontaktName(e.target.value)} />
|
||||
<Input placeholder="Kontakt E-Mail" value={kontaktEmail} onChange={(e) => setKontaktEmail(e.target.value)} />
|
||||
<Input placeholder="Teamfarben" value={teamfarben} onChange={(e) => setTeamfarben(e.target.value)} />
|
||||
<Textarea placeholder="Beschreibung" value={beschreibung} onChange={(e) => setBeschreibung(e.target.value)} />
|
||||
<Input placeholder="Link zur Tabelle" value={tabellenlink} onChange={(e) => setTabellenlink(e.target.value)} />
|
||||
<Input placeholder="Social Media" value={socialMedia} onChange={(e) => setSocialMedia(e.target.value)} />
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
id="suchtSpieler"
|
||||
type="checkbox"
|
||||
checked={suchtSpieler}
|
||||
onChange={(e) => setSuchtSpieler(e.target.checked)}
|
||||
/>
|
||||
<Label htmlFor="suchtSpieler">Spieler/in gesucht?</Label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="carouselImages">Karussell-Bilder (als JSON-Array)</Label>
|
||||
<Textarea
|
||||
id="carouselImages"
|
||||
placeholder='z. B. ["/uploads/x.jpg", "/uploads/y.jpg"]'
|
||||
value={carouselImages}
|
||||
onChange={(e) => setCarouselImages(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{errorMsg && (
|
||||
<p className="text-sm text-red-600 bg-red-50 border border-red-200 px-3 py-2 rounded-md">
|
||||
<p className="text-sm text-red-600 bg-red-50 border border-red-200 px-3 py-2 rounded-md">
|
||||
{errorMsg}
|
||||
</p>
|
||||
</p>
|
||||
)}
|
||||
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
disabled={saving}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams, useNavigate } from "react-router-dom";
|
||||
import { useParams, useNavigate, Link } 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";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { toast } from "sonner";
|
||||
|
||||
const apiBase = import.meta.env.VITE_API_URL;
|
||||
|
||||
@ -19,8 +20,20 @@ type Player = {
|
||||
const TeamDetail = () => {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
const [teamName, setTeamName] = useState("");
|
||||
const [liga, setLiga] = useState("");
|
||||
const [trainerName, setTrainerName] = useState("");
|
||||
const [socialMedia, setSocialMedia] = useState("");
|
||||
const [spielerGesucht, setSpielerGesucht] = useState(false);
|
||||
const [carouselImages, setCarouselImages] = useState("");
|
||||
const [trainingszeiten, setTrainingszeiten] = useState("");
|
||||
const [trainingsort, setTrainingsort] = useState("");
|
||||
const [kontaktName, setKontaktName] = useState("");
|
||||
const [kontaktEmail, setKontaktEmail] = useState("");
|
||||
const [teamfarben, setTeamfarben] = useState("");
|
||||
const [beschreibung, setBeschreibung] = useState("");
|
||||
const [tabellenlink, setTabellenlink] = useState("");
|
||||
const [players, setPlayers] = useState<Player[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
@ -28,7 +41,20 @@ const TeamDetail = () => {
|
||||
try {
|
||||
const res = await fetch(`${apiBase}/api/teams/${id}`);
|
||||
const data = await res.json();
|
||||
|
||||
setTeamName(data.name ?? "");
|
||||
setLiga(data.liga ?? "");
|
||||
setTrainerName(data.trainer_name ?? "");
|
||||
setSocialMedia(data.social_media ?? "");
|
||||
setSpielerGesucht(data.sucht_spieler ?? false);
|
||||
setCarouselImages(data.karussell_bilder ? JSON.stringify(data.karussell_bilder) : "");
|
||||
setTrainingszeiten(data.trainingszeiten ?? "");
|
||||
setTrainingsort(data.trainingsort ?? "");
|
||||
setKontaktName(data.kontakt_name ?? "");
|
||||
setKontaktEmail(data.kontakt_email ?? "");
|
||||
setTeamfarben(data.teamfarben ?? "");
|
||||
setBeschreibung(data.beschreibung ?? "");
|
||||
setTabellenlink(data.tabellenlink ?? "");
|
||||
setPlayers(data.players ?? []);
|
||||
} catch (err) {
|
||||
console.error("Fehler beim Laden des Teams:", err);
|
||||
@ -41,19 +67,35 @@ const TeamDetail = () => {
|
||||
fetchTeam();
|
||||
}, [id]);
|
||||
|
||||
const handleUpdateName = async () => {
|
||||
const handleUpdateTeam = async () => {
|
||||
try {
|
||||
const res = await fetch(`${apiBase}/api/teams/${id}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ name: teamName }),
|
||||
body: JSON.stringify({
|
||||
name: teamName,
|
||||
liga,
|
||||
sucht_spieler: spielerGesucht,
|
||||
social_media: socialMedia,
|
||||
karussell_bilder: carouselImages ? JSON.parse(carouselImages) : [],
|
||||
trainer_name: trainerName,
|
||||
trainingszeiten,
|
||||
trainingsort,
|
||||
kontakt_name: kontaktName,
|
||||
kontakt_email: kontaktEmail,
|
||||
teamfarben,
|
||||
beschreibung,
|
||||
tabellenlink,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error("Fehler beim Aktualisieren des Teamnamens");
|
||||
if (!res.ok) throw new Error("Fehler beim Aktualisieren des Teams");
|
||||
|
||||
alert("Teamname aktualisiert!");
|
||||
toast.success("Team erfolgreich aktualisiert!");
|
||||
fetchTeam(); // Aktuelle Daten neu laden
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toast.error("Fehler beim Aktualisieren des Teams.");
|
||||
}
|
||||
};
|
||||
|
||||
@ -76,26 +118,46 @@ const TeamDetail = () => {
|
||||
if (loading) return <p className="text-center py-12">Lade Team...</p>;
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto py-12 px-4">
|
||||
<div className="max-w-5xl mx-auto py-12 px-4">
|
||||
<h1 className="text-3xl font-bold text-frog-600 mb-6">Team bearbeiten</h1>
|
||||
|
||||
|
||||
<div className="space-y-4 mb-8">
|
||||
<Input
|
||||
value={teamName}
|
||||
onChange={(e) => setTeamName(e.target.value)}
|
||||
placeholder="Teamname"
|
||||
<Input value={teamName} onChange={(e) => setTeamName(e.target.value)} placeholder="Teamname" />
|
||||
<Input value={liga} onChange={(e) => setLiga(e.target.value)} placeholder="Liga" />
|
||||
<Input value={trainerName} onChange={(e) => setTrainerName(e.target.value)} placeholder="Trainer/in" />
|
||||
<Input value={trainingszeiten} onChange={(e) => setTrainingszeiten(e.target.value)} placeholder="Trainingszeiten" />
|
||||
<Input value={trainingsort} onChange={(e) => setTrainingsort(e.target.value)} placeholder="Trainingsort" />
|
||||
<Input value={kontaktName} onChange={(e) => setKontaktName(e.target.value)} placeholder="Kontaktname" />
|
||||
<Input value={kontaktEmail} onChange={(e) => setKontaktEmail(e.target.value)} placeholder="Kontakt E-Mail" />
|
||||
<Input value={teamfarben} onChange={(e) => setTeamfarben(e.target.value)} placeholder="Teamfarben" />
|
||||
<Textarea value={beschreibung} onChange={(e) => setBeschreibung(e.target.value)} placeholder="Beschreibung" />
|
||||
<Input value={tabellenlink} onChange={(e) => setTabellenlink(e.target.value)} placeholder="Link zur Tabelle" />
|
||||
<Input value={socialMedia} onChange={(e) => setSocialMedia(e.target.value)} placeholder="Social Media Link" />
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={spielerGesucht}
|
||||
onChange={() => setSpielerGesucht(!spielerGesucht)}
|
||||
className="w-5 h-5 text-frog-500"
|
||||
/>
|
||||
<label className="text-gray-700">Neue Spieler gesucht?</label>
|
||||
</div>
|
||||
|
||||
<Textarea
|
||||
value={carouselImages}
|
||||
onChange={(e) => setCarouselImages(e.target.value)}
|
||||
placeholder="Karussell-Bilder (JSON-Array z.B. [\"//uploads/x.jpg\"])"
|
||||
/>
|
||||
<Button
|
||||
onClick={handleUpdateName}
|
||||
className="bg-frog-500 hover:bg-frog-600 text-white"
|
||||
>
|
||||
Teamname speichern
|
||||
|
||||
<Button onClick={handleUpdateTeam} className="bg-frog-500 hover:bg-frog-600 text-white">
|
||||
Team speichern
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="mb-8">
|
||||
<h2 className="text-2xl font-bold text-frog-500 mb-4">Spieler im Team</h2>
|
||||
|
||||
|
||||
{players.length === 0 ? (
|
||||
<p className="text-gray-600">Noch keine Spieler zugeordnet.</p>
|
||||
) : (
|
||||
@ -124,19 +186,10 @@ const TeamDetail = () => {
|
||||
<p className="text-gray-600">Nummer: {player.jersey_number}</p>
|
||||
)}
|
||||
<div className="flex gap-2 mt-4">
|
||||
<Button
|
||||
asChild
|
||||
variant="outline"
|
||||
className="text-frog-600 border-frog-500 hover:bg-frog-50"
|
||||
>
|
||||
<Link to={`/admin/players/${player.id}/edit`}>
|
||||
Bearbeiten
|
||||
</Link>
|
||||
<Button asChild variant="outline" className="text-frog-600 border-frog-500 hover:bg-frog-50">
|
||||
<Link to={`/admin/players/${player.id}/edit`}>Bearbeiten</Link>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => handleRemovePlayer(player.id)}
|
||||
variant="destructive"
|
||||
>
|
||||
<Button onClick={() => handleRemovePlayer(player.id)} variant="destructive">
|
||||
Entfernen
|
||||
</Button>
|
||||
</div>
|
||||
@ -146,8 +199,8 @@ const TeamDetail = () => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="text-center">
|
||||
|
||||
<div className="text-center mt-8">
|
||||
<Button asChild>
|
||||
<Link to={`/admin/teams/${id}/add-player`}>
|
||||
+ Spieler hinzufügen
|
||||
@ -156,8 +209,6 @@ const TeamDetail = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
};
|
||||
|
||||
export default TeamDetail;
|
||||
|
||||
@ -24,6 +24,7 @@ import TeamCreate from "./admin/TeamCreate";
|
||||
import TeamDetail from "./admin/TeamDetail";
|
||||
import TeamAddPlayer from "./admin/TeamAddPlayer";
|
||||
import PlayerEdit from "./admin/PlayerEdit";
|
||||
import PlayerManagementPage from "./admin/PlayerManagementPage";
|
||||
|
||||
|
||||
|
||||
@ -69,6 +70,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<Route path="/admin/teams/:id" element={<PrivateRoute><Layout><TeamDetail /></Layout></PrivateRoute>} />
|
||||
<Route path="/admin/teams/:id/add-player" element={<PrivateRoute><Layout><TeamAddPlayer /></Layout></PrivateRoute>} />
|
||||
<Route path="/admin/players/:id/edit" element={<PrivateRoute><Layout><PlayerEdit /></Layout></PrivateRoute>} />
|
||||
<Route path="/admin/players" element={<PrivateRoute><Layout><PlayerManagementPage /></Layout></PrivateRoute>} />
|
||||
|
||||
</Routes>
|
||||
</AuthProvider>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user