Init
This commit is contained in:
131
src/pages/ScoringPage.jsx
Normal file
131
src/pages/ScoringPage.jsx
Normal 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
95
src/pages/SetupPage.jsx
Normal 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>
|
||||
)
|
||||
}
|
||||
110
src/pages/TournamentPage.jsx
Normal file
110
src/pages/TournamentPage.jsx
Normal 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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user