This commit is contained in:
2025-12-31 01:17:12 +01:00
commit b7a802a52c
34 changed files with 4567 additions and 0 deletions

131
src/pages/ScoringPage.jsx Normal file
View File

@@ -0,0 +1,131 @@
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useTeams } from '../hooks/useTeams'
import { useMatches } from '../hooks/useMatches'
import Header from '../components/Header'
export default function ScoringPage() {
const navigate = useNavigate()
const { teams } = useTeams()
const { matches: championsMatches } = useMatches(teams.championsleague, teams.fields)
const { matches: bundesligaMatches } = useMatches(teams.bundesliga, teams.fields)
const [scores, setScores] = useState({})
const [selectedGroup, setSelectedGroup] = useState('championsleague')
const allMatches = selectedGroup === 'championsleague' ? championsMatches : bundesligaMatches
const handleScoreChange = (matchId, team, value) => {
setScores(prev => ({
...prev,
[matchId]: {
...prev[matchId],
[team]: parseInt(value) || 0
}
}))
}
const handleSaveScore = (matchId) => {
// TODO: Hier könnte man die Scores speichern
console.log('Scores gespeichert:', scores[matchId])
}
return (
<div className="min-h-screen bg-gradient-to-b from-gray-900 to-gray-800">
<Header />
<div className="max-w-4xl mx-auto p-4">
<div className="flex justify-between items-center mb-6">
<h1 className="text-3xl font-bold text-white">📊 Punkte Eintragen</h1>
<button
onClick={() => navigate('/tournament')}
className="btn-primary"
>
Zurück
</button>
</div>
{/* Gruppen Toggle */}
<div className="flex gap-2 mb-6">
<button
onClick={() => setSelectedGroup('championsleague')}
className={`px-4 py-2 rounded-lg font-semibold transition-all ${
selectedGroup === 'championsleague'
? 'bg-primary text-white'
: 'bg-gray-700 text-gray-300 hover:bg-gray-600'
}`}
>
🏆 Champions League
</button>
<button
onClick={() => setSelectedGroup('bundesliga')}
className={`px-4 py-2 rounded-lg font-semibold transition-all ${
selectedGroup === 'bundesliga'
? 'bg-primary text-white'
: 'bg-gray-700 text-gray-300 hover:bg-gray-600'
}`}
>
Bundesliga
</button>
</div>
{/* Matches zum Scores eingeben */}
<div className="space-y-4">
{allMatches.length === 0 ? (
<div className="bg-gray-800 rounded-lg p-6 text-center text-gray-400">
Keine Spiele in dieser Gruppe
</div>
) : (
allMatches.map(match => (
<div key={match.id} className="bg-gray-800 rounded-lg p-4 border border-gray-700">
<div className="flex items-center justify-between">
{/* Team 1 */}
<div className="flex-1">
<p className="text-sm text-gray-400">{match.team1.clubName}</p>
<p className="font-bold text-white">{match.team1.teamName}</p>
</div>
{/* Score Input */}
<div className="flex items-center gap-3">
<input
type="number"
min="0"
max="999"
value={scores[match.id]?.team1 || ''}
onChange={(e) => handleScoreChange(match.id, 'team1', e.target.value)}
placeholder="0"
className="w-16 bg-gray-700 text-white text-center text-xl font-bold rounded px-2 py-1 border border-gray-600 focus:border-primary"
/>
<span className="text-xl font-bold text-gray-400">:</span>
<input
type="number"
min="0"
max="999"
value={scores[match.id]?.team2 || ''}
onChange={(e) => handleScoreChange(match.id, 'team2', e.target.value)}
placeholder="0"
className="w-16 bg-gray-700 text-white text-center text-xl font-bold rounded px-2 py-1 border border-gray-600 focus:border-primary"
/>
</div>
{/* Team 2 */}
<div className="flex-1 text-right">
<p className="text-sm text-gray-400">{match.team2.clubName}</p>
<p className="font-bold text-white">{match.team2.teamName}</p>
</div>
{/* Speichern Button */}
<button
onClick={() => handleSaveScore(match.id)}
className="ml-4 btn-primary btn-sm"
>
</button>
</div>
</div>
))
)}
</div>
</div>
</div>
)
}

95
src/pages/SetupPage.jsx Normal file
View File

@@ -0,0 +1,95 @@
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import Header from '../components/Header'
import FieldsSettings from '../components/FieldsSettings'
import GroupSection from '../components/GroupSection'
import Toast from '../components/Toast'
import { useTeams } from '../hooks/useTeams'
export default function SetupPage() {
const { teams, addTeam, deleteTeam, updateFields, resetAll } = useTeams()
const [toast, setToast] = useState(null)
const navigate = useNavigate()
const showToast = (message, type = 'success') => {
setToast({ message, type })
setTimeout(() => setToast(null), 3000)
}
const handleAddTeam = (group, clubName, teamName, chant) => {
if (!clubName.trim() || !teamName.trim() || !chant.trim()) {
showToast('Bitte alle Felder ausfüllen!', 'error')
return
}
addTeam(group, clubName, teamName, chant)
showToast(`${teamName} hinzugefügt! 🎉`, 'success')
}
const handleDeleteTeam = (group, teamId) => {
deleteTeam(group, teamId)
showToast('Team gelöscht', 'info')
}
const handleStartTournament = () => {
const totalTeams = teams.bundesliga.length + teams.championsleague.length
if (totalTeams < 2) {
showToast('Du brauchst mindestens 2 Teams!', 'error')
return
}
navigate('/tournament')
}
const handleResetAll = () => {
if (window.confirm('Alle Teams wirklich löschen?')) {
resetAll()
showToast('Alle Teams gelöscht', 'info')
}
}
return (
<div className="min-h-screen bg-gradient-to-br from-primary to-secondary p-4 md:p-8">
<div className="max-w-6xl mx-auto">
<Header />
<FieldsSettings
fields={teams.fields}
onUpdateFields={updateFields}
/>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 my-8">
<GroupSection
title="🏐 Volleyball Bundesliga"
group="bundesliga"
teams={teams.bundesliga}
onAddTeam={handleAddTeam}
onDeleteTeam={handleDeleteTeam}
/>
<GroupSection
title="🏆 Volleyball Champions League"
group="championsleague"
teams={teams.championsleague}
onAddTeam={handleAddTeam}
onDeleteTeam={handleDeleteTeam}
/>
</div>
<div className="flex gap-4 justify-center flex-wrap">
<button
onClick={handleStartTournament}
className="btn-primary text-lg px-8 py-3"
>
🎮 Turnier Starten
</button>
<button
onClick={handleResetAll}
className="btn-danger text-lg px-8 py-3"
>
🗑 Alle Teams löschen
</button>
</div>
</div>
{toast && <Toast message={toast.message} type={toast.type} />}
</div>
)
}

View File

@@ -0,0 +1,110 @@
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useTeams } from '../hooks/useTeams'
import { useMatches } from '../hooks/useMatches'
import FieldGroup from '../components/FieldGroup'
import Stopwatch from '../components/Stopwatch'
import ScoreboardModal from '../components/ScoreboardModal'
export default function TournamentPage() {
const navigate = useNavigate()
const { teams } = useTeams()
const [scoreboardOpen, setScoreboardOpen] = useState(false)
const [scoreboardGroup, setScoreboardGroup] = useState('championsleague')
const bundesliga = useMatches(teams, teams.fields, 'bundesliga')
const championsleague = useMatches(teams, teams.fields, 'championsleague')
const handleShowScoreboard = (group) => {
setScoreboardGroup(group)
setScoreboardOpen(true)
}
return (
<div className="flex flex-col h-screen bg-gray-900 text-white">
{/* Header */}
<div className="bg-gradient-to-r from-primary to-secondary p-4 shadow-lg">
<div className="flex justify-between items-center">
<h1 className="text-2xl md:text-3xl font-bold">🏐 Volleyball Turnier Manager</h1>
{/* Center Buttons */}
<div className="flex gap-2">
<button
onClick={() => navigate('/scoring')}
className="btn-primary"
title="Punkte eintragen"
>
📝 Punkte
</button>
<button
onClick={() => handleShowScoreboard('championsleague')}
className="btn-primary"
title="Scoreboard anzeigen"
>
📊 Ergebnisse
</button>
</div>
{/* Right Side */}
<div className="flex gap-2 items-center">
<Stopwatch />
<button
onClick={() => navigate('/')}
className="btn-primary"
title="Zurück zur Team-Verwaltung"
>
Zurück
</button>
</div>
</div>
</div>
{/* Main Content - Two Column Layout */}
<div className="flex-1 overflow-hidden grid grid-cols-1 md:grid-cols-2 gap-4 p-4">
{/* Champions League */}
<div className="bg-white text-gray-800 rounded-lg shadow-xl overflow-hidden flex flex-col">
<FieldGroup
groupName="🏆 Champions League"
fields={teams.fields}
matches={championsleague.matches}
waitingList={championsleague.waitingList}
/>
</div>
{/* Bundesliga */}
<div className="bg-white text-gray-800 rounded-lg shadow-xl overflow-hidden flex flex-col">
<FieldGroup
groupName="🏐 Bundesliga"
fields={teams.fields}
matches={bundesliga.matches}
waitingList={bundesliga.waitingList}
/>
</div>
</div>
{/* Footer Stats */}
<div className="bg-gray-800 border-t border-gray-700 p-4 flex justify-around text-sm">
<div>
<p className="text-gray-400">Champions League</p>
<p className="text-lg font-bold">{championsleague.matches.length} aktiv | {championsleague.waitingList.length} warten</p>
</div>
<div className="border-l border-gray-700 pl-4">
<p className="text-gray-400">Bundesliga</p>
<p className="text-lg font-bold">{bundesliga.matches.length} aktiv | {bundesliga.waitingList.length} warten</p>
</div>
<div className="border-l border-gray-700 pl-4">
<p className="text-gray-400">Verfügbare Felder</p>
<p className="text-lg font-bold">{teams.fields}</p>
</div>
</div>
{/* Scoreboard Modal */}
<ScoreboardModal
isOpen={scoreboardOpen}
onClose={() => setScoreboardOpen(false)}
matches={scoreboardGroup === 'championsleague' ? championsleague.matches : bundesliga.matches}
groupName={scoreboardGroup === 'championsleague' ? '🏆 Champions League' : '🏐 Bundesliga'}
/>
</div>
)
}