diff --git a/src/app/rankings/RankingsClient.tsx b/src/app/rankings/RankingsClient.tsx
new file mode 100644
index 0000000..1e6c304
--- /dev/null
+++ b/src/app/rankings/RankingsClient.tsx
@@ -0,0 +1,241 @@
+"use client"
+
+import { useState } from "react"
+import Link from "next/link"
+
+// Define the Player type with all rating relationships
+interface PlayerWithRatings {
+ id: number
+ name: string
+ currentElo: number
+ gamesPlayed: number
+ wins: number
+ losses: number
+ eloRating: { rating: number; gamesPlayed: number; wins: number; losses: number } | null
+ glicko2Rating: { rating: number; gamesPlayed: number; wins: number; losses: number } | null
+ openSkillRating: { rating: number; gamesPlayed: number; wins: number; losses: number } | null
+}
+
+export default function RankingsClient({ players }: { players: PlayerWithRatings[] }) {
+ const [activeTab, setActiveTab] = useState<"elo" | "openskill" | "glicko2">("elo")
+
+ return (
+ <>
+ {/* Tab Navigation */}
+
+
+
+
+ {/* Elo Rating Tab */}
+ {activeTab === "elo" && (
+
+
+ Elo Rating Rankings
+
+
+
+
+ |
+ Rank
+ |
+
+ Player
+ |
+
+ Elo Rating
+ |
+
+ Games Played
+ |
+
+ Win Rate
+ |
+
+
+
+ {players.map((player, index) => (
+
+ |
+ {index + 1}
+ |
+
+
+ {player.name}
+
+ |
+
+ {player.eloRating?.rating ?? player.currentElo}
+ |
+
+ {player.gamesPlayed}
+ |
+
+ {player.gamesPlayed > 0
+ ? `${((player.wins / player.gamesPlayed) * 100).toFixed(1)}%`
+ : "N/A"}
+ |
+
+ ))}
+
+
+
+ )}
+
+ {/* OpenSkill Rating Tab */}
+ {activeTab === "openskill" && (
+
+
+ OpenSkill Rating Rankings
+
+
+
+
+ |
+ Rank
+ |
+
+ Player
+ |
+
+ OpenSkill Rating
+ |
+
+ Games Played
+ |
+
+ Win Rate
+ |
+
+
+
+ {players
+ .filter(p => p.openSkillRating)
+ .sort((a, b) => (b.openSkillRating?.rating ?? 0) - (a.openSkillRating?.rating ?? 0))
+ .map((player, index) => (
+
+ |
+ {index + 1}
+ |
+
+
+ {player.name}
+
+ |
+
+ {player.openSkillRating?.rating?.toFixed(1) ?? 'N/A'}
+ |
+
+ {player.openSkillRating?.gamesPlayed ?? 0}
+ |
+
+ {player.openSkillRating && player.openSkillRating.gamesPlayed > 0
+ ? `${((player.openSkillRating.wins / player.openSkillRating.gamesPlayed) * 100).toFixed(1)}%`
+ : "N/A"}
+ |
+
+ ))}
+
+
+
+ )}
+
+ {/* Glicko2 Rating Tab */}
+ {activeTab === "glicko2" && (
+
+
+ Glicko2 Rating Rankings
+
+
+
+
+ |
+ Rank
+ |
+
+ Player
+ |
+
+ Glicko2 Rating
+ |
+
+ Games Played
+ |
+
+ Win Rate
+ |
+
+
+
+ {players
+ .filter(p => p.glicko2Rating)
+ .sort((a, b) => (b.glicko2Rating?.rating ?? 0) - (a.glicko2Rating?.rating ?? 0))
+ .map((player, index) => (
+
+ |
+ {index + 1}
+ |
+
+
+ {player.name}
+
+ |
+
+ {player.glicko2Rating?.rating?.toFixed(1) ?? 'N/A'}
+ |
+
+ {player.glicko2Rating?.gamesPlayed ?? 0}
+ |
+
+ {player.glicko2Rating && player.glicko2Rating.gamesPlayed > 0
+ ? `${((player.glicko2Rating.wins / player.glicko2Rating.gamesPlayed) * 100).toFixed(1)}%`
+ : "N/A"}
+ |
+
+ ))}
+
+
+
+ )}
+ >
+ )
+}
diff --git a/src/app/rankings/page.tsx b/src/app/rankings/page.tsx
index 39151a6..8288561 100644
--- a/src/app/rankings/page.tsx
+++ b/src/app/rankings/page.tsx
@@ -1,15 +1,18 @@
import { prisma } from "@/lib/prisma"
import Navigation from "@/components/Navigation"
-import Link from "next/link"
+import RankingsClient from "./RankingsClient"
export default async function RankingsPage() {
- // Fetch players ordered by Elo rating
+ // Fetch players with all rating systems
const players = await prisma.player.findMany({
orderBy: { currentElo: "desc" },
take: 50,
include: {
partnershipStats: true,
partnershipStats2: true,
+ eloRating: true,
+ glicko2Rating: true,
+ openSkillRating: true,
},
})
@@ -23,57 +26,7 @@ export default async function RankingsPage() {
Player Rankings
-
-
-
-
- |
- Rank
- |
-
- Player
- |
-
- Elo Rating
- |
-
- Games Played
- |
-
- Win Rate
- |
-
-
-
- {players.map((player, index) => (
-
- |
- {index + 1}
- |
-
-
- {player.name}
-
- |
-
- {player.currentElo}
- |
-
- {player.gamesPlayed}
- |
-
- {player.gamesPlayed > 0
- ? `${((player.wins / player.gamesPlayed) * 100).toFixed(1)}%`
- : "N/A"}
- |
-
- ))}
-
-
-
+