wip
This commit is contained in:
@@ -20,36 +20,18 @@ import {
|
||||
} from 'lucide-react';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Heading from '@/components/ui/Heading';
|
||||
import { getDriverRepository, getDriverStats, getAllDriverRankings, getImageService, getGetAllTeamsQuery, getGetTeamMembersQuery } from '@/lib/di-container';
|
||||
import { getGetDriversLeaderboardUseCase, getGetTeamsLeaderboardUseCase } from '@/lib/di-container';
|
||||
import type { DriverLeaderboardItemViewModel, SkillLevel } from '@gridpilot/racing/application/presenters/IDriversLeaderboardPresenter';
|
||||
import type { TeamLeaderboardItemViewModel } from '@gridpilot/racing/application/presenters/ITeamsLeaderboardPresenter';
|
||||
import Image from 'next/image';
|
||||
import type { Team } from '@gridpilot/racing';
|
||||
|
||||
// ============================================================================
|
||||
// TYPES
|
||||
// ============================================================================
|
||||
|
||||
type SkillLevel = 'beginner' | 'intermediate' | 'advanced' | 'pro';
|
||||
type DriverListItem = DriverLeaderboardItemViewModel;
|
||||
|
||||
interface DriverListItem {
|
||||
id: string;
|
||||
name: string;
|
||||
rating: number;
|
||||
skillLevel: SkillLevel;
|
||||
nationality: string;
|
||||
wins: number;
|
||||
podiums: number;
|
||||
rank: number;
|
||||
}
|
||||
|
||||
interface TeamDisplayData {
|
||||
id: string;
|
||||
name: string;
|
||||
memberCount: number;
|
||||
rating: number | null;
|
||||
totalWins: number;
|
||||
totalRaces: number;
|
||||
performanceLevel: SkillLevel;
|
||||
}
|
||||
type TeamDisplayData = TeamLeaderboardItemViewModel;
|
||||
|
||||
// ============================================================================
|
||||
// SKILL LEVEL CONFIG
|
||||
@@ -80,7 +62,6 @@ interface DriverLeaderboardPreviewProps {
|
||||
|
||||
function DriverLeaderboardPreview({ drivers, onDriverClick }: DriverLeaderboardPreviewProps) {
|
||||
const router = useRouter();
|
||||
const imageService = getImageService();
|
||||
const top10 = drivers.slice(0, 10);
|
||||
|
||||
const getMedalColor = (position: number) => {
|
||||
@@ -144,7 +125,7 @@ function DriverLeaderboardPreview({ drivers, onDriverClick }: DriverLeaderboardP
|
||||
|
||||
{/* Avatar */}
|
||||
<div className="relative w-9 h-9 rounded-full overflow-hidden border-2 border-charcoal-outline">
|
||||
<Image src={imageService.getDriverAvatar(driver.id)} alt={driver.name} fill className="object-cover" />
|
||||
<Image src={driver.avatarUrl} alt={driver.name} fill className="object-cover" />
|
||||
</div>
|
||||
|
||||
{/* Info */}
|
||||
@@ -189,7 +170,6 @@ interface TeamLeaderboardPreviewProps {
|
||||
|
||||
function TeamLeaderboardPreview({ teams, onTeamClick }: TeamLeaderboardPreviewProps) {
|
||||
const router = useRouter();
|
||||
const imageService = getImageService();
|
||||
const top5 = [...teams]
|
||||
.filter((t) => t.rating !== null)
|
||||
.sort((a, b) => (b.rating ?? 0) - (a.rating ?? 0))
|
||||
@@ -304,99 +284,16 @@ export default function LeaderboardsPage() {
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
try {
|
||||
// Load drivers
|
||||
const driverRepo = getDriverRepository();
|
||||
const allDrivers = await driverRepo.findAll();
|
||||
const rankings = getAllDriverRankings();
|
||||
const driversUseCase = getGetDriversLeaderboardUseCase();
|
||||
const teamsUseCase = getGetTeamsLeaderboardUseCase();
|
||||
await driversUseCase.execute();
|
||||
await teamsUseCase.execute();
|
||||
|
||||
const driverItems: DriverListItem[] = allDrivers.map((driver) => {
|
||||
const stats = getDriverStats(driver.id);
|
||||
const rating = stats?.rating ?? 0;
|
||||
const wins = stats?.wins ?? 0;
|
||||
const podiums = stats?.podiums ?? 0;
|
||||
const driversViewModel = driversUseCase.presenter.getViewModel();
|
||||
const teamsViewModel = teamsUseCase.presenter.getViewModel();
|
||||
|
||||
let effectiveRank = Number.POSITIVE_INFINITY;
|
||||
if (typeof stats?.overallRank === 'number' && stats.overallRank > 0) {
|
||||
effectiveRank = stats.overallRank;
|
||||
} else {
|
||||
const indexInGlobal = rankings.findIndex((entry) => entry.driverId === driver.id);
|
||||
if (indexInGlobal !== -1) {
|
||||
effectiveRank = indexInGlobal + 1;
|
||||
}
|
||||
}
|
||||
|
||||
const skillLevel: SkillLevel =
|
||||
rating >= 3000 ? 'pro' : rating >= 2500 ? 'advanced' : rating >= 1800 ? 'intermediate' : 'beginner';
|
||||
|
||||
return {
|
||||
id: driver.id,
|
||||
name: driver.name,
|
||||
rating,
|
||||
skillLevel,
|
||||
nationality: driver.country,
|
||||
wins,
|
||||
podiums,
|
||||
rank: effectiveRank,
|
||||
};
|
||||
});
|
||||
|
||||
// Sort by rank
|
||||
driverItems.sort((a, b) => {
|
||||
const rankA = Number.isFinite(a.rank) && a.rank > 0 ? a.rank : Number.POSITIVE_INFINITY;
|
||||
const rankB = Number.isFinite(b.rank) && b.rank > 0 ? b.rank : Number.POSITIVE_INFINITY;
|
||||
return rankA - rankB || b.rating - a.rating;
|
||||
});
|
||||
|
||||
// Load teams
|
||||
const allTeamsQuery = getGetAllTeamsQuery();
|
||||
const teamMembersQuery = getGetTeamMembersQuery();
|
||||
const allTeams = await allTeamsQuery.execute();
|
||||
const teamData: TeamDisplayData[] = [];
|
||||
|
||||
await Promise.all(
|
||||
allTeams.map(async (team: Team) => {
|
||||
const memberships = await teamMembersQuery.execute({ teamId: team.id });
|
||||
const memberCount = memberships.length;
|
||||
|
||||
let ratingSum = 0;
|
||||
let ratingCount = 0;
|
||||
let totalWins = 0;
|
||||
let totalRaces = 0;
|
||||
|
||||
for (const membership of memberships) {
|
||||
const stats = getDriverStats(membership.driverId);
|
||||
if (!stats) continue;
|
||||
if (typeof stats.rating === 'number') {
|
||||
ratingSum += stats.rating;
|
||||
ratingCount += 1;
|
||||
}
|
||||
totalWins += stats.wins ?? 0;
|
||||
totalRaces += stats.totalRaces ?? 0;
|
||||
}
|
||||
|
||||
const averageRating = ratingCount > 0 ? ratingSum / ratingCount : null;
|
||||
|
||||
let performanceLevel: SkillLevel = 'beginner';
|
||||
if (averageRating !== null) {
|
||||
if (averageRating >= 4500) performanceLevel = 'pro';
|
||||
else if (averageRating >= 3000) performanceLevel = 'advanced';
|
||||
else if (averageRating >= 2000) performanceLevel = 'intermediate';
|
||||
}
|
||||
|
||||
teamData.push({
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
memberCount,
|
||||
rating: averageRating,
|
||||
totalWins,
|
||||
totalRaces,
|
||||
performanceLevel,
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
setDrivers(driverItems);
|
||||
setTeams(teamData);
|
||||
setDrivers(driversViewModel.drivers);
|
||||
setTeams(teamsViewModel.teams);
|
||||
} catch (error) {
|
||||
console.error('Failed to load leaderboard data:', error);
|
||||
setDrivers([]);
|
||||
|
||||
Reference in New Issue
Block a user