refactor(ui): update components to use new player field names

This commit is contained in:
2026-04-03 21:03:57 -07:00
parent c00f26919b
commit 52da77d57b
9 changed files with 193 additions and 212 deletions
+15 -50
View File
@@ -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>
)} )}
+44 -36
View File
@@ -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"}>
{eloChanges[match.player1P1.id] >= 0 ? "+" : ""}{eloChanges[match.player1P1.id]}
</span> </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"}>
{eloChanges[match.player1P2.id] >= 0 ? "+" : ""}{eloChanges[match.player1P2.id]}
</span> </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"}>
{eloChanges[match.player2P1.id] >= 0 ? "+" : ""}{eloChanges[match.player2P1.id]}
</span> </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"}>
{eloChanges[match.player2P2.id] >= 0 ? "+" : ""}{eloChanges[match.player2P2.id]}
</span> </span>
)}
</div> </div>
</div> </div>
</div> </div>
+6 -6
View File
@@ -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
View File
@@ -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}
+19 -17
View File
@@ -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">
{teammate && (
<Link <Link
href={`/players/${teammate.id}/profile`} href={`/players/${teammate.id}/profile`}
className="text-green-600 hover:text-green-900" className="text-green-600 hover:text-green-900"
> >
{teammate.name} {teammate.name}
</Link> </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 -33
View File
@@ -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>
+49 -29
View File
@@ -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>