import { prisma } from "@/lib/prisma"
export const dynamic = "force-dynamic";
import Navigation from "@/components/Navigation"
import Link from "next/link"
import { notFound } from "next/navigation"
interface PageProps {
params: {
id: string
}
}
export default async function PlayerProfilePage({ params }: PageProps) {
// Next.js 16 requires awaiting params
const { id } = await params
const playerId = parseInt(id, 10)
if (isNaN(playerId)) {
notFound()
}
const player = await prisma.player.findUnique({
where: { id: playerId },
include: {
eloRating: true,
openSkillRating: true,
glicko2Rating: true,
},
})
if (!player) {
notFound()
}
// Get partnership stats separately
const partnershipStats = await prisma.partnershipStat.findMany({
where: {
OR: [
{ player1Id: playerId },
{ player2Id: playerId },
],
},
include: {
player1: true,
player2: true,
},
orderBy: { gamesPlayed: "desc" },
})
// Get tournaments participated in
const tournaments = await prisma.event.findMany({
where: {
participants: {
some: {
playerId: playerId,
},
},
},
orderBy: { eventDate: "desc" },
take: 10,
})
// Get recent matches (last 10 games played)
const recentMatches = await prisma.match.findMany({
where: {
OR: [
{ team1P1Id: playerId },
{ team1P2Id: playerId },
{ team2P1Id: playerId },
{ team2P2Id: playerId },
],
},
include: {
team1P1: true,
team1P2: true,
team2P1: true,
team2P2: true,
event: true,
},
orderBy: { playedAt: "desc" },
take: 10,
})
// Use direct player stats for overall statistics (more accurate and consistent with rankings page)
const totalGames = player.gamesPlayed
const totalWins = player.wins
const winRate = totalGames > 0 ? ((totalWins / totalGames) * 100).toFixed(1) : "0.0"
// Get best partnership based on ELO contribution
// Best partner is the one who contributed most to your rating (highest totalEloChange)
// Must have played at least 2 games together to be considered
const bestPartnership = partnershipStats.reduce((best, stat) => {
if (stat.gamesPlayed < 2) return best // Need at least 2 games for partnership to be meaningful
const currentEloChange = stat.totalEloChange
const bestEloChange = best ? best.totalEloChange : -Infinity
return currentEloChange > bestEloChange ? stat : best
}, null as (typeof partnershipStats[0] | null))
return (
{/* Player Header */}
{player.name.charAt(0).toUpperCase()}
{player.name}
Member since {new Date(player.createdAt).toLocaleDateString()}
{/* Stats Grid */}
Current Elo
{player.currentElo}
OpenSkill Rating
{player.openSkillRating?.rating?.toFixed(1) || 'N/A'}
Glicko2 Rating
{player.glicko2Rating?.rating?.toFixed(1) || 'N/A'}
Best Partner
{bestPartnership
? (bestPartnership.player1Id === player.id
? bestPartnership.player2.name
: bestPartnership.player1.name)
: "N/A"}
{/* Tournaments Participated */}
Tournaments Participated
{tournaments.length === 0 ? (
No tournament data available yet.
) : (
|
Tournament
|
Date
|
Format
|
Status
|
{tournaments.map((tournament) => (
|
{tournament.name}
|
{tournament.eventDate
? new Date(tournament.eventDate).toLocaleDateString()
: "N/A"}
|
{tournament.format}
|
{tournament.status}
|
))}
)}
{/* Recent Games */}
Recent Games
{recentMatches.length === 0 ? (
No game data available yet.
) : (
|
Date
|
Tournament
|
Team
|
Opponents
|
Score
|
Result
|
{recentMatches.map((match) => {
const isTeam1 = match.team1P1Id === playerId || match.team1P2Id === playerId;
const teamWon = isTeam1 ? match.team1Score > match.team2Score : match.team2Score > match.team1Score;
const teamScore = isTeam1 ? match.team1Score : match.team2Score;
const opponentScore = isTeam1 ? match.team2Score : match.team1Score;
const teammate = isTeam1
? (match.team1P1Id === playerId ? match.team1P2 : match.team1P1)
: (match.team2P1Id === playerId ? match.team2P2 : match.team2P1);
const opponents = isTeam1
? [match.team2P1, match.team2P2]
: [match.team1P1, match.team1P2];
return (
|
{match.playedAt
? new Date(match.playedAt).toLocaleDateString()
: "N/A"}
|
{match.event?.name || "N/A"}
|
{teammate.name}
|
{opponents.map((opponent, index) => (
{opponent.name}
{index < opponents.length - 1 ? ", " : ""}
))}
|
{teamScore} - {opponentScore}
|
{teamWon ? 'Win' : 'Loss'}
|
)
})}
)}
{/* Partnership Performance */}
Partnership Performance
{partnershipStats.length === 0 ? (
No partnership data available yet.
) : (
|
Partner
|
Games
|
Win Rate
|
ELO Change
|
Last Played
|
{partnershipStats.map((stat) => {
const partner =
stat.player1Id === player.id ? stat.player2 : stat.player1
const winRate = stat.gamesPlayed > 0
? ((stat.wins / stat.gamesPlayed) * 100).toFixed(1)
: "0.0"
return (
|
{partner.name}
|
{stat.gamesPlayed}
|
{winRate}%
|
= 0 ? 'text-green-600' : 'text-red-600'
}`}>
{stat.totalEloChange >= 0 ? '+' : ''}{stat.totalEloChange}
|
{stat.lastPlayed
? new Date(stat.lastPlayed).toLocaleDateString()
: "N/A"}
|
)
})}
)}
)
}