refactor(ui): update components to use new player field names
This commit is contained in:
@@ -40,28 +40,14 @@ export default async function TournamentDetailPage({ params }: PageProps) {
|
|||||||
player: true,
|
player: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
teams: {
|
|
||||||
include: {
|
|
||||||
player1: true,
|
|
||||||
player2: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rounds: {
|
rounds: {
|
||||||
include: {
|
include: {
|
||||||
bracketMatchups: {
|
bracketMatchups: {
|
||||||
include: {
|
include: {
|
||||||
team1: {
|
player1P1: true,
|
||||||
include: {
|
player1P2: true,
|
||||||
player1: true,
|
player2P1: true,
|
||||||
player2: true,
|
player2P2: true,
|
||||||
},
|
|
||||||
},
|
|
||||||
team2: {
|
|
||||||
include: {
|
|
||||||
player1: true,
|
|
||||||
player2: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
match: true,
|
match: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -86,28 +72,14 @@ export default async function TournamentDetailPage({ params }: PageProps) {
|
|||||||
player: true,
|
player: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
teams: {
|
|
||||||
include: {
|
|
||||||
player1: true,
|
|
||||||
player2: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rounds: {
|
rounds: {
|
||||||
include: {
|
include: {
|
||||||
bracketMatchups: {
|
bracketMatchups: {
|
||||||
include: {
|
include: {
|
||||||
team1: {
|
player1P1: true,
|
||||||
include: {
|
player1P2: true,
|
||||||
player1: true,
|
player2P1: true,
|
||||||
player2: true,
|
player2P2: true,
|
||||||
},
|
|
||||||
},
|
|
||||||
team2: {
|
|
||||||
include: {
|
|
||||||
player1: true,
|
|
||||||
player2: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
match: true,
|
match: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -120,10 +92,10 @@ export default async function TournamentDetailPage({ params }: PageProps) {
|
|||||||
const matches = await prisma.match.findMany({
|
const matches = await prisma.match.findMany({
|
||||||
where: { eventId: tournamentId },
|
where: { eventId: tournamentId },
|
||||||
include: {
|
include: {
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "desc" },
|
orderBy: { playedAt: "desc" },
|
||||||
})
|
})
|
||||||
@@ -204,12 +176,6 @@ export default async function TournamentDetailPage({ params }: PageProps) {
|
|||||||
{tournament.participants.length}
|
{tournament.participants.length}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-gray-50 rounded-lg p-4 text-center">
|
|
||||||
<p className="text-sm text-gray-500">Teams</p>
|
|
||||||
<p className="text-2xl font-bold text-gray-900">
|
|
||||||
{tournament.teams.length}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="bg-gray-50 rounded-lg p-4 text-center">
|
<div className="bg-gray-50 rounded-lg p-4 text-center">
|
||||||
<p className="text-sm text-gray-500">Rounds</p>
|
<p className="text-sm text-gray-500">Rounds</p>
|
||||||
<p className="text-2xl font-bold text-gray-900">
|
<p className="text-2xl font-bold text-gray-900">
|
||||||
@@ -217,7 +183,7 @@ export default async function TournamentDetailPage({ params }: PageProps) {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-gray-50 rounded-lg p-4 text-center">
|
<div className="bg-gray-50 rounded-lg p-4 text-center">
|
||||||
<p className="text-sm text-gray-500">Matches</p>
|
<p className="text-sm text-gray-500">Matchups</p>
|
||||||
<p className="text-2xl font-bold text-gray-900">
|
<p className="text-2xl font-bold text-gray-900">
|
||||||
{matches.length}
|
{matches.length}
|
||||||
</p>
|
</p>
|
||||||
@@ -287,7 +253,6 @@ export default async function TournamentDetailPage({ params }: PageProps) {
|
|||||||
{/* Teams Section */}
|
{/* Teams Section */}
|
||||||
<TeamsSection
|
<TeamsSection
|
||||||
tournamentId={tournament.id}
|
tournamentId={tournament.id}
|
||||||
teams={tournament.teams}
|
|
||||||
participants={tournament.participants.map(p => ({
|
participants={tournament.participants.map(p => ({
|
||||||
id: p.player.id,
|
id: p.player.id,
|
||||||
name: p.player.name,
|
name: p.player.name,
|
||||||
@@ -317,8 +282,8 @@ export default async function TournamentDetailPage({ params }: PageProps) {
|
|||||||
{match.playedAt?.toLocaleDateString()}
|
{match.playedAt?.toLocaleDateString()}
|
||||||
</p>
|
</p>
|
||||||
<p className="font-medium">
|
<p className="font-medium">
|
||||||
{match.team1P1.name} + {match.team1P2.name} vs{" "}
|
{match.player1P1?.name} + {match.player1P2?.name} vs{" "}
|
||||||
{match.team2P1.name} + {match.team2P2.name}
|
{match.player2P1?.name} + {match.player2P2?.name}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
|
|||||||
@@ -38,10 +38,10 @@ export default async function TournamentResultsPage({ params }: PageProps) {
|
|||||||
const matches = await prisma.match.findMany({
|
const matches = await prisma.match.findMany({
|
||||||
where: { eventId: tournamentId },
|
where: { eventId: tournamentId },
|
||||||
include: {
|
include: {
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "desc" },
|
orderBy: { playedAt: "desc" },
|
||||||
})
|
})
|
||||||
@@ -114,8 +114,8 @@ export default async function TournamentResultsPage({ params }: PageProps) {
|
|||||||
{match.playedAt?.toLocaleDateString()}
|
{match.playedAt?.toLocaleDateString()}
|
||||||
</p>
|
</p>
|
||||||
<p className="font-medium">
|
<p className="font-medium">
|
||||||
{match.team1P1.name} + {match.team1P2.name} vs{" "}
|
{match.player1P1?.name} + {match.player1P2?.name} vs{" "}
|
||||||
{match.team2P1.name} + {match.team2P2.name}
|
{match.player2P1?.name} + {match.player2P2?.name}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right flex items-center">
|
<div className="text-right flex items-center">
|
||||||
|
|||||||
@@ -34,23 +34,15 @@ export default async function TournamentSchedulePage({ params }: PageProps) {
|
|||||||
const tournament = await prisma.event.findUnique({
|
const tournament = await prisma.event.findUnique({
|
||||||
where: { id: tournamentId },
|
where: { id: tournamentId },
|
||||||
include: {
|
include: {
|
||||||
teams: {
|
|
||||||
include: {
|
|
||||||
player1: true,
|
|
||||||
player2: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
rounds: {
|
rounds: {
|
||||||
orderBy: { roundNumber: "asc" },
|
orderBy: { roundNumber: "asc" },
|
||||||
include: {
|
include: {
|
||||||
bracketMatchups: {
|
bracketMatchups: {
|
||||||
include: {
|
include: {
|
||||||
team1: {
|
player1P1: true,
|
||||||
include: { player1: true, player2: true },
|
player1P2: true,
|
||||||
},
|
player2P1: true,
|
||||||
team2: {
|
player2P2: true,
|
||||||
include: { player1: true, player2: true },
|
|
||||||
},
|
|
||||||
match: true,
|
match: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -94,7 +86,7 @@ export default async function TournamentSchedulePage({ params }: PageProps) {
|
|||||||
<div className="bg-white shadow rounded-lg p-6 mb-6">
|
<div className="bg-white shadow rounded-lg p-6 mb-6">
|
||||||
<h1 className="text-2xl font-bold text-gray-900">Tournament Schedule</h1>
|
<h1 className="text-2xl font-bold text-gray-900">Tournament Schedule</h1>
|
||||||
<p className="text-gray-500 mt-1">
|
<p className="text-gray-500 mt-1">
|
||||||
{tournament.name} — {tournament.teams.length} teams
|
{tournament.name}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -106,7 +98,7 @@ export default async function TournamentSchedulePage({ params }: PageProps) {
|
|||||||
</h2>
|
</h2>
|
||||||
<ScheduleGenerator
|
<ScheduleGenerator
|
||||||
tournamentId={tournamentId}
|
tournamentId={tournamentId}
|
||||||
teamCount={tournament.teams.length}
|
teamCount={0}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -128,11 +120,11 @@ export default async function TournamentSchedulePage({ params }: PageProps) {
|
|||||||
) : (
|
) : (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
{round.bracketMatchups.map((matchup) => {
|
{round.bracketMatchups.map((matchup) => {
|
||||||
const team1Name = matchup.team1
|
const team1Name = matchup.player1P1 && matchup.player1P2
|
||||||
? `${matchup.team1.player1.name} + ${matchup.team1.player2.name}`
|
? `${matchup.player1P1.name} + ${matchup.player1P2.name}`
|
||||||
: "TBD"
|
: "TBD"
|
||||||
const team2Name = matchup.team2
|
const team2Name = matchup.player2P1 && matchup.player2P2
|
||||||
? `${matchup.team2.player1.name} + ${matchup.team2.player2.name}`
|
? `${matchup.player2P1.name} + ${matchup.player2P2.name}`
|
||||||
: "TBD"
|
: "TBD"
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -208,7 +200,7 @@ export default async function TournamentSchedulePage({ params }: PageProps) {
|
|||||||
</h2>
|
</h2>
|
||||||
<ScheduleGenerator
|
<ScheduleGenerator
|
||||||
tournamentId={tournamentId}
|
tournamentId={tournamentId}
|
||||||
teamCount={tournament.teams.length}
|
teamCount={0}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ export default async function MatchDetailPage({ params }: PageProps) {
|
|||||||
const match = await prisma.match.findUnique({
|
const match = await prisma.match.findUnique({
|
||||||
where: { id: matchId },
|
where: { id: matchId },
|
||||||
include: {
|
include: {
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
event: true,
|
event: true,
|
||||||
eloSnapshots: {
|
eloSnapshots: {
|
||||||
include: {
|
include: {
|
||||||
@@ -93,13 +93,13 @@ export default async function MatchDetailPage({ params }: PageProps) {
|
|||||||
<div className="absolute top-0 left-0 right-0 h-1/2 flex flex-col justify-end items-center pb-8">
|
<div className="absolute top-0 left-0 right-0 h-1/2 flex flex-col justify-end items-center pb-8">
|
||||||
<div className="text-center bg-white/80 rounded-lg px-3 py-2 shadow-sm -mt-[20px]">
|
<div className="text-center bg-white/80 rounded-lg px-3 py-2 shadow-sm -mt-[20px]">
|
||||||
<p className="text-base font-semibold text-amber-900">
|
<p className="text-base font-semibold text-amber-900">
|
||||||
{match.team1P1.name}
|
{match.player1P1?.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-amber-700">
|
<p className="text-xs text-amber-700">
|
||||||
Elo: {match.team1P1.currentElo}
|
Elo: {match.player1P1?.currentElo}
|
||||||
{eloChanges[match.team1P1.id] !== undefined && (
|
{match.player1P1 && eloChanges[match.player1P1.id] !== undefined && (
|
||||||
<span className={eloChanges[match.team1P1.id] >= 0 ? "text-green-600 ml-1" : "text-red-600 ml-1"}>
|
<span className={eloChanges[match.player1P1.id] >= 0 ? "text-green-600 ml-1" : "text-red-600 ml-1"}>
|
||||||
({eloChanges[match.team1P1.id] >= 0 ? "+" : ""}{eloChanges[match.team1P1.id]})
|
({eloChanges[match.player1P1.id] >= 0 ? "+" : ""}{eloChanges[match.player1P1.id]})
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
@@ -112,13 +112,13 @@ export default async function MatchDetailPage({ params }: PageProps) {
|
|||||||
<div className="text-xs text-amber-600 mb-2 font-medium">Team 1</div>
|
<div className="text-xs text-amber-600 mb-2 font-medium">Team 1</div>
|
||||||
<div className="text-center bg-white/80 rounded-lg px-3 py-2 shadow-sm mt-[10px]">
|
<div className="text-center bg-white/80 rounded-lg px-3 py-2 shadow-sm mt-[10px]">
|
||||||
<p className="text-base font-semibold text-amber-900">
|
<p className="text-base font-semibold text-amber-900">
|
||||||
{match.team1P2.name}
|
{match.player1P2?.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-amber-700">
|
<p className="text-xs text-amber-700">
|
||||||
Elo: {match.team1P2.currentElo}
|
Elo: {match.player1P2?.currentElo}
|
||||||
{eloChanges[match.team1P2.id] !== undefined && (
|
{match.player1P2 && eloChanges[match.player1P2.id] !== undefined && (
|
||||||
<span className={eloChanges[match.team1P2.id] >= 0 ? "text-green-600 ml-1" : "text-red-600 ml-1"}>
|
<span className={eloChanges[match.player1P2.id] >= 0 ? "text-green-600 ml-1" : "text-red-600 ml-1"}>
|
||||||
({eloChanges[match.team1P2.id] >= 0 ? "+" : ""}{eloChanges[match.team1P2.id]})
|
({eloChanges[match.player1P2.id] >= 0 ? "+" : ""}{eloChanges[match.player1P2.id]})
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
@@ -129,13 +129,13 @@ export default async function MatchDetailPage({ params }: PageProps) {
|
|||||||
<div className="absolute left-0 top-0 bottom-0 w-1/2 flex flex-col justify-center items-center pl-8">
|
<div className="absolute left-0 top-0 bottom-0 w-1/2 flex flex-col justify-center items-center pl-8">
|
||||||
<div className="text-center bg-white/80 rounded-lg px-3 py-2 shadow-sm rotate-[-90deg] -ml-[20px]">
|
<div className="text-center bg-white/80 rounded-lg px-3 py-2 shadow-sm rotate-[-90deg] -ml-[20px]">
|
||||||
<p className="text-sm font-semibold text-red-900">
|
<p className="text-sm font-semibold text-red-900">
|
||||||
{match.team2P1.name}
|
{match.player2P1?.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-[11px] text-red-700">
|
<p className="text-[11px] text-red-700">
|
||||||
Elo: {match.team2P1.currentElo}
|
Elo: {match.player2P1?.currentElo}
|
||||||
{eloChanges[match.team2P1.id] !== undefined && (
|
{match.player2P1 && eloChanges[match.player2P1.id] !== undefined && (
|
||||||
<span className={eloChanges[match.team2P1.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
<span className={eloChanges[match.player2P1.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
||||||
({eloChanges[match.team2P1.id] >= 0 ? "+" : ""}{eloChanges[match.team2P1.id]})
|
({eloChanges[match.player2P1.id] >= 0 ? "+" : ""}{eloChanges[match.player2P1.id]})
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
@@ -146,13 +146,13 @@ export default async function MatchDetailPage({ params }: PageProps) {
|
|||||||
<div className="absolute right-0 top-0 bottom-0 w-1/2 flex flex-col justify-center items-center pr-8">
|
<div className="absolute right-0 top-0 bottom-0 w-1/2 flex flex-col justify-center items-center pr-8">
|
||||||
<div className="text-center bg-white/80 rounded-lg px-3 py-2 shadow-sm rotate-[90deg] -mr-[20px]">
|
<div className="text-center bg-white/80 rounded-lg px-3 py-2 shadow-sm rotate-[90deg] -mr-[20px]">
|
||||||
<p className="text-sm font-semibold text-red-900">
|
<p className="text-sm font-semibold text-red-900">
|
||||||
{match.team2P2.name}
|
{match.player2P2?.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-[11px] text-red-700">
|
<p className="text-[11px] text-red-700">
|
||||||
Elo: {match.team2P2.currentElo}
|
Elo: {match.player2P2?.currentElo}
|
||||||
{eloChanges[match.team2P2.id] !== undefined && (
|
{match.player2P2 && eloChanges[match.player2P2.id] !== undefined && (
|
||||||
<span className={eloChanges[match.team2P2.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
<span className={eloChanges[match.player2P2.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
||||||
({eloChanges[match.team2P2.id] >= 0 ? "+" : ""}{eloChanges[match.team2P2.id]})
|
({eloChanges[match.player2P2.id] >= 0 ? "+" : ""}{eloChanges[match.player2P2.id]})
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
@@ -246,16 +246,20 @@ export default async function MatchDetailPage({ params }: PageProps) {
|
|||||||
<h3 className="font-medium text-amber-900 mb-3">Team 1</h3>
|
<h3 className="font-medium text-amber-900 mb-3">Team 1</h3>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span>{match.team1P1.name}</span>
|
<span>{match.player1P1?.name}</span>
|
||||||
<span className={eloChanges[match.team1P1.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
{match.player1P1 && (
|
||||||
{eloChanges[match.team1P1.id] >= 0 ? "+" : ""}{eloChanges[match.team1P1.id]}
|
<span className={eloChanges[match.player1P1.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
||||||
</span>
|
{eloChanges[match.player1P1.id] >= 0 ? "+" : ""}{eloChanges[match.player1P1.id]}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span>{match.team1P2.name}</span>
|
<span>{match.player1P2?.name}</span>
|
||||||
<span className={eloChanges[match.team1P2.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
{match.player1P2 && (
|
||||||
{eloChanges[match.team1P2.id] >= 0 ? "+" : ""}{eloChanges[match.team1P2.id]}
|
<span className={eloChanges[match.player1P2.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
||||||
</span>
|
{eloChanges[match.player1P2.id] >= 0 ? "+" : ""}{eloChanges[match.player1P2.id]}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -265,16 +269,20 @@ export default async function MatchDetailPage({ params }: PageProps) {
|
|||||||
<h3 className="font-medium text-red-900 mb-3">Team 2</h3>
|
<h3 className="font-medium text-red-900 mb-3">Team 2</h3>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span>{match.team2P1.name}</span>
|
<span>{match.player2P1?.name}</span>
|
||||||
<span className={eloChanges[match.team2P1.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
{match.player2P1 && (
|
||||||
{eloChanges[match.team2P1.id] >= 0 ? "+" : ""}{eloChanges[match.team2P1.id]}
|
<span className={eloChanges[match.player2P1.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
||||||
</span>
|
{eloChanges[match.player2P1.id] >= 0 ? "+" : ""}{eloChanges[match.player2P1.id]}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<span>{match.team2P2.name}</span>
|
<span>{match.player2P2?.name}</span>
|
||||||
<span className={eloChanges[match.team2P2.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
{match.player2P2 && (
|
||||||
{eloChanges[match.team2P2.id] >= 0 ? "+" : ""}{eloChanges[match.team2P2.id]}
|
<span className={eloChanges[match.player2P2.id] >= 0 ? "text-green-600" : "text-red-600"}>
|
||||||
</span>
|
{eloChanges[match.player2P2.id] >= 0 ? "+" : ""}{eloChanges[match.player2P2.id]}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ export default async function MatchesListPage() {
|
|||||||
orderBy: { createdAt: "desc" },
|
orderBy: { createdAt: "desc" },
|
||||||
take: 50,
|
take: 50,
|
||||||
include: {
|
include: {
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
event: true,
|
event: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -84,10 +84,10 @@ export default async function MatchesListPage() {
|
|||||||
#{match.id}
|
#{match.id}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{match.team1P1.name} & {match.team1P2.name}
|
{match.player1P1?.name} & {match.player1P2?.name}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{match.team2P1.name} & {match.team2P2.name}
|
{match.player2P1?.name} & {match.player2P2?.name}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
<span className="font-medium">{match.team1Score}</span>
|
<span className="font-medium">{match.team1Score}</span>
|
||||||
|
|||||||
+6
-6
@@ -24,10 +24,10 @@ export default async function Home() {
|
|||||||
include: {
|
include: {
|
||||||
matches: {
|
matches: {
|
||||||
include: {
|
include: {
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "desc" },
|
orderBy: { playedAt: "desc" },
|
||||||
},
|
},
|
||||||
@@ -178,7 +178,7 @@ export default async function Home() {
|
|||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex-1 text-center">
|
<div className="flex-1 text-center">
|
||||||
<div className="text-sm font-medium text-gray-900">
|
<div className="text-sm font-medium text-gray-900">
|
||||||
{match.team1P1.name} & {match.team1P2.name}
|
{match.player1P1?.name} & {match.player1P2?.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-lg font-bold text-gray-800">
|
<div className="text-lg font-bold text-gray-800">
|
||||||
{match.team1Score}
|
{match.team1Score}
|
||||||
@@ -187,7 +187,7 @@ export default async function Home() {
|
|||||||
<div className="px-3 text-gray-500">vs</div>
|
<div className="px-3 text-gray-500">vs</div>
|
||||||
<div className="flex-1 text-center">
|
<div className="flex-1 text-center">
|
||||||
<div className="text-sm font-medium text-gray-900">
|
<div className="text-sm font-medium text-gray-900">
|
||||||
{match.team2P1.name} & {match.team2P2.name}
|
{match.player2P1?.name} & {match.player2P2?.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-lg font-bold text-gray-800">
|
<div className="text-lg font-bold text-gray-800">
|
||||||
{match.team2Score}
|
{match.team2Score}
|
||||||
|
|||||||
@@ -64,17 +64,17 @@ export default async function PlayerProfilePage({ params }: PageProps) {
|
|||||||
const recentMatches = await prisma.match.findMany({
|
const recentMatches = await prisma.match.findMany({
|
||||||
where: {
|
where: {
|
||||||
OR: [
|
OR: [
|
||||||
{ team1P1Id: playerId },
|
{ player1P1Id: playerId },
|
||||||
{ team1P2Id: playerId },
|
{ player1P2Id: playerId },
|
||||||
{ team2P1Id: playerId },
|
{ player2P1Id: playerId },
|
||||||
{ team2P2Id: playerId },
|
{ player2P2Id: playerId },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
event: true,
|
event: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "desc" },
|
orderBy: { playedAt: "desc" },
|
||||||
@@ -247,18 +247,18 @@ export default async function PlayerProfilePage({ params }: PageProps) {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody className="bg-white divide-y divide-gray-200">
|
<tbody className="bg-white divide-y divide-gray-200">
|
||||||
{recentMatches.map((match) => {
|
{recentMatches.map((match) => {
|
||||||
const isTeam1 = match.team1P1Id === playerId || match.team1P2Id === playerId;
|
const isTeam1 = match.player1P1Id === playerId || match.player1P2Id === playerId;
|
||||||
const teamWon = isTeam1 ? match.team1Score > match.team2Score : match.team2Score > match.team1Score;
|
const teamWon = isTeam1 ? match.team1Score > match.team2Score : match.team2Score > match.team1Score;
|
||||||
const teamScore = isTeam1 ? match.team1Score : match.team2Score;
|
const teamScore = isTeam1 ? match.team1Score : match.team2Score;
|
||||||
const opponentScore = isTeam1 ? match.team2Score : match.team1Score;
|
const opponentScore = isTeam1 ? match.team2Score : match.team1Score;
|
||||||
|
|
||||||
const teammate = isTeam1
|
const teammate = isTeam1
|
||||||
? (match.team1P1Id === playerId ? match.team1P2 : match.team1P1)
|
? (match.player1P1Id === playerId ? match.player1P2 : match.player1P1)
|
||||||
: (match.team2P1Id === playerId ? match.team2P2 : match.team2P1);
|
: (match.player2P1Id === playerId ? match.player2P2 : match.player2P1);
|
||||||
|
|
||||||
const opponents = isTeam1
|
const opponents = isTeam1
|
||||||
? [match.team2P1, match.team2P2]
|
? [match.player2P1, match.player2P2]
|
||||||
: [match.team1P1, match.team1P2];
|
: [match.player1P1, match.player1P2];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={match.id} className="hover:bg-gray-50">
|
<tr key={match.id} className="hover:bg-gray-50">
|
||||||
@@ -276,21 +276,23 @@ export default async function PlayerProfilePage({ params }: PageProps) {
|
|||||||
{match.event?.name || "N/A"}
|
{match.event?.name || "N/A"}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
|
||||||
<Link
|
{teammate && (
|
||||||
href={`/players/${teammate.id}/profile`}
|
<Link
|
||||||
className="text-green-600 hover:text-green-900"
|
href={`/players/${teammate.id}/profile`}
|
||||||
>
|
className="text-green-600 hover:text-green-900"
|
||||||
{teammate.name}
|
>
|
||||||
</Link>
|
{teammate.name}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{opponents.map((opponent, index) => (
|
{opponents.filter(o => o !== null).map((opponent, index) => (
|
||||||
<span key={opponent.id}>
|
<span key={opponent?.id}>
|
||||||
<Link
|
<Link
|
||||||
href={`/players/${opponent.id}/profile`}
|
href={`/players/${opponent?.id}/profile`}
|
||||||
className="text-green-600 hover:text-green-900"
|
className="text-green-600 hover:text-green-900"
|
||||||
>
|
>
|
||||||
{opponent.name}
|
{opponent?.name}
|
||||||
</Link>
|
</Link>
|
||||||
{index < opponents.length - 1 ? ", " : ""}
|
{index < opponents.length - 1 ? ", " : ""}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ export default async function PlayerSchedulePage({ params }: PageProps) {
|
|||||||
where: { playedAt: { gte: new Date() } },
|
where: { playedAt: { gte: new Date() } },
|
||||||
include: {
|
include: {
|
||||||
event: true,
|
event: true,
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "asc" },
|
orderBy: { playedAt: "asc" },
|
||||||
},
|
},
|
||||||
@@ -38,10 +38,10 @@ export default async function PlayerSchedulePage({ params }: PageProps) {
|
|||||||
where: { playedAt: { gte: new Date() } },
|
where: { playedAt: { gte: new Date() } },
|
||||||
include: {
|
include: {
|
||||||
event: true,
|
event: true,
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "asc" },
|
orderBy: { playedAt: "asc" },
|
||||||
},
|
},
|
||||||
@@ -49,10 +49,10 @@ export default async function PlayerSchedulePage({ params }: PageProps) {
|
|||||||
where: { playedAt: { gte: new Date() } },
|
where: { playedAt: { gte: new Date() } },
|
||||||
include: {
|
include: {
|
||||||
event: true,
|
event: true,
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "asc" },
|
orderBy: { playedAt: "asc" },
|
||||||
},
|
},
|
||||||
@@ -60,10 +60,10 @@ export default async function PlayerSchedulePage({ params }: PageProps) {
|
|||||||
where: { playedAt: { gte: new Date() } },
|
where: { playedAt: { gte: new Date() } },
|
||||||
include: {
|
include: {
|
||||||
event: true,
|
event: true,
|
||||||
team1P1: true,
|
player1P1: true,
|
||||||
team1P2: true,
|
player1P2: true,
|
||||||
team2P1: true,
|
player2P1: true,
|
||||||
team2P2: true,
|
player2P2: true,
|
||||||
},
|
},
|
||||||
orderBy: { playedAt: "asc" },
|
orderBy: { playedAt: "asc" },
|
||||||
},
|
},
|
||||||
@@ -94,12 +94,6 @@ export default async function PlayerSchedulePage({ params }: PageProps) {
|
|||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
participants: true,
|
participants: true,
|
||||||
teams: {
|
|
||||||
include: {
|
|
||||||
player1: true,
|
|
||||||
player2: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -125,13 +119,13 @@ export default async function PlayerSchedulePage({ params }: PageProps) {
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{upcomingMatches.map((match) => {
|
{upcomingMatches.map((match) => {
|
||||||
const team1Players = [
|
const team1Players = [
|
||||||
match.team1P1.name,
|
match.player1P1?.name,
|
||||||
match.team1P2.name,
|
match.player1P2?.name,
|
||||||
].join(" + ")
|
].filter(Boolean).join(" + ")
|
||||||
const team2Players = [
|
const team2Players = [
|
||||||
match.team2P1.name,
|
match.player2P1?.name,
|
||||||
match.team2P2.name,
|
match.player2P2?.name,
|
||||||
].join(" + ")
|
].filter(Boolean).join(" + ")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -171,9 +165,9 @@ export default async function PlayerSchedulePage({ params }: PageProps) {
|
|||||||
) : (
|
) : (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{activeTournaments.map((tournament) => {
|
{activeTournaments.map((tournament) => {
|
||||||
const playerTeam = tournament.teams.find(
|
// Since teams are now ephemeral, just check if player is a participant
|
||||||
(team) =>
|
const isParticipant = tournament.participants.some(
|
||||||
team.player1Id === playerId || team.player2Id === playerId
|
(p) => p.playerId === playerId
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -192,9 +186,9 @@ export default async function PlayerSchedulePage({ params }: PageProps) {
|
|||||||
<p className="text-sm text-gray-500">
|
<p className="text-sm text-gray-500">
|
||||||
{tournament.format} - {tournament.status}
|
{tournament.format} - {tournament.status}
|
||||||
</p>
|
</p>
|
||||||
{playerTeam && (
|
{isParticipant && (
|
||||||
<p className="text-sm text-gray-600">
|
<p className="text-sm text-gray-600">
|
||||||
Team: {playerTeam.player1.name} + {playerTeam.player2.name}
|
Participant in tournament
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ interface Team {
|
|||||||
|
|
||||||
interface TeamsSectionProps {
|
interface TeamsSectionProps {
|
||||||
tournamentId: number
|
tournamentId: number
|
||||||
teams: Team[]
|
|
||||||
participants: Player[]
|
participants: Player[]
|
||||||
teamDurability: string
|
teamDurability: string
|
||||||
partnerRotation: string
|
partnerRotation: string
|
||||||
@@ -30,14 +29,13 @@ type PartnerRotationOption = 'none' | 'minimize_repeat' | 'maximize_even' | 'elo
|
|||||||
|
|
||||||
export default function TeamsSection({
|
export default function TeamsSection({
|
||||||
tournamentId,
|
tournamentId,
|
||||||
teams: initialTeams,
|
|
||||||
participants,
|
participants,
|
||||||
teamDurability: initialTeamDurability,
|
teamDurability: initialTeamDurability,
|
||||||
partnerRotation: initialPartnerRotation,
|
partnerRotation: initialPartnerRotation,
|
||||||
allowByes: initialAllowByes,
|
allowByes: initialAllowByes,
|
||||||
}: TeamsSectionProps) {
|
}: TeamsSectionProps) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const [teams, setTeams] = useState<Team[]>(initialTeams)
|
const [teams, setTeams] = useState<Team[]>([])
|
||||||
const [teamDurability, setTeamDurability] = useState<TeamDurabilityOption>(initialTeamDurability as TeamDurabilityOption)
|
const [teamDurability, setTeamDurability] = useState<TeamDurabilityOption>(initialTeamDurability as TeamDurabilityOption)
|
||||||
const [partnerRotation, setPartnerRotation] = useState<PartnerRotationOption>(initialPartnerRotation as PartnerRotationOption)
|
const [partnerRotation, setPartnerRotation] = useState<PartnerRotationOption>(initialPartnerRotation as PartnerRotationOption)
|
||||||
const [allowByes, setAllowByes] = useState(initialAllowByes)
|
const [allowByes, setAllowByes] = useState(initialAllowByes)
|
||||||
@@ -85,9 +83,9 @@ export default function TeamsSection({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleGenerateTeams = async () => {
|
const handleGenerateSchedule = async () => {
|
||||||
if (participants.length < 2) {
|
if (participants.length < 2) {
|
||||||
setError("At least 2 participants are required to generate teams")
|
setError("At least 2 participants are required to generate a schedule")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,31 +99,58 @@ export default function TeamsSection({
|
|||||||
setIsGenerating(true)
|
setIsGenerating(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/tournaments/${tournamentId}/teams/generate`, {
|
const response = await fetch(`/api/tournaments/${tournamentId}/schedule`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
|
||||||
teamDurability,
|
|
||||||
partnerRotation,
|
|
||||||
allowByes,
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
try {
|
try {
|
||||||
const errorData = await response.json()
|
const errorData = await response.json()
|
||||||
setError(errorData.error || "Failed to generate teams")
|
setError(errorData.error || "Failed to generate schedule")
|
||||||
} catch {
|
} catch {
|
||||||
setError(`Failed to generate teams: ${response.status} ${response.statusText}`)
|
setError(`Failed to generate schedule: ${response.status} ${response.statusText}`)
|
||||||
}
|
}
|
||||||
|
setIsGenerating(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
setTeams(data.teams)
|
// Update teams from the generated schedule
|
||||||
setSuccess(`Successfully generated ${data.teams.length} teams!`)
|
// Extract teams from round matchups
|
||||||
|
const generatedTeams: Team[] = []
|
||||||
|
for (const round of data.rounds) {
|
||||||
|
for (const matchup of round.bracketMatchups) {
|
||||||
|
// Add unique teams
|
||||||
|
const team1 = {
|
||||||
|
id: 0,
|
||||||
|
teamName: `${matchup.player1P1.name} & ${matchup.player1P2.name}`,
|
||||||
|
player1: matchup.player1P1,
|
||||||
|
player2: matchup.player1P2,
|
||||||
|
}
|
||||||
|
const team2 = {
|
||||||
|
id: 0,
|
||||||
|
teamName: `${matchup.player2P1.name} & ${matchup.player2P2.name}`,
|
||||||
|
player1: matchup.player2P1,
|
||||||
|
player2: matchup.player2P2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if team already exists
|
||||||
|
const existingTeam1 = generatedTeams.find(
|
||||||
|
t => t.player1.id === team1.player1.id && t.player2.id === team1.player2.id
|
||||||
|
)
|
||||||
|
if (!existingTeam1) generatedTeams.push(team1)
|
||||||
|
|
||||||
|
const existingTeam2 = generatedTeams.find(
|
||||||
|
t => t.player1.id === team2.player1.id && t.player2.id === team2.player2.id
|
||||||
|
)
|
||||||
|
if (!existingTeam2) generatedTeams.push(team2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTeams(generatedTeams)
|
||||||
|
setSuccess(`Successfully generated ${data.roundsCreated} rounds with ${data.matchupsCreated} matchups!`)
|
||||||
router.refresh()
|
router.refresh()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
@@ -139,7 +164,7 @@ export default function TeamsSection({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleDeleteTeams = async () => {
|
const handleDeleteTeams = async () => {
|
||||||
if (!confirm("Are you sure you want to delete all teams? This will also delete the schedule.")) {
|
if (!confirm("Are you sure you want to delete the schedule? This will remove all rounds and matchups.")) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,28 +173,23 @@ export default function TeamsSection({
|
|||||||
setIsGenerating(true)
|
setIsGenerating(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// First delete schedule if exists
|
// Delete schedule (which includes matchups/rounds)
|
||||||
await fetch(`/api/tournaments/${tournamentId}/schedule`, {
|
const response = await fetch(`/api/tournaments/${tournamentId}/schedule`, {
|
||||||
method: "DELETE",
|
|
||||||
})
|
|
||||||
|
|
||||||
// Then delete teams
|
|
||||||
const response = await fetch(`/api/tournaments/${tournamentId}/teams`, {
|
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
try {
|
try {
|
||||||
const errorData = await response.json()
|
const errorData = await response.json()
|
||||||
setError(errorData.error || "Failed to delete teams")
|
setError(errorData.error || "Failed to delete schedule")
|
||||||
} catch {
|
} catch {
|
||||||
setError(`Failed to delete teams: ${response.status} ${response.statusText}`)
|
setError(`Failed to delete schedule: ${response.status} ${response.statusText}`)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setTeams([])
|
setTeams([])
|
||||||
setSuccess("Teams deleted successfully!")
|
setSuccess("Schedule deleted successfully!")
|
||||||
router.refresh()
|
router.refresh()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
@@ -349,11 +369,11 @@ export default function TeamsSection({
|
|||||||
{/* Team Generation Controls */}
|
{/* Team Generation Controls */}
|
||||||
<div className="flex gap-3 mb-4">
|
<div className="flex gap-3 mb-4">
|
||||||
<button
|
<button
|
||||||
onClick={handleGenerateTeams}
|
onClick={handleGenerateSchedule}
|
||||||
disabled={isGenerating || participants.length < 2}
|
disabled={isGenerating || participants.length < 2}
|
||||||
className="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 disabled:opacity-50 text-sm"
|
className="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 disabled:opacity-50 text-sm"
|
||||||
>
|
>
|
||||||
{isGenerating ? "Generating..." : `Generate Teams (${participants.length} participants)`}
|
{isGenerating ? "Generating..." : `Generate Schedule (${participants.length} participants)`}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{teams.length > 0 && (
|
{teams.length > 0 && (
|
||||||
@@ -362,7 +382,7 @@ export default function TeamsSection({
|
|||||||
disabled={isGenerating}
|
disabled={isGenerating}
|
||||||
className="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 disabled:opacity-50 text-sm"
|
className="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 disabled:opacity-50 text-sm"
|
||||||
>
|
>
|
||||||
Delete All Teams
|
Delete Schedule
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user