resolve todos in website and api

This commit is contained in:
2025-12-20 10:45:56 +01:00
parent 656ec62426
commit 7bbad511e2
62 changed files with 2036 additions and 611 deletions

View File

@@ -51,7 +51,7 @@ describe('DriversLeaderboardPresenter', () => {
id: 'driver-1',
name: 'Driver One',
rating: 2500,
skillLevel: 'Pro',
skillLevel: 'advanced',
nationality: 'US',
racesCompleted: 50,
wins: 10,
@@ -64,7 +64,7 @@ describe('DriversLeaderboardPresenter', () => {
id: 'driver-2',
name: 'Driver Two',
rating: 2400,
skillLevel: 'Pro',
skillLevel: 'intermediate',
nationality: 'DE',
racesCompleted: 40,
wins: 5,
@@ -137,6 +137,45 @@ describe('DriversLeaderboardPresenter', () => {
expect(result.drivers[0].racesCompleted).toBe(0);
expect(result.drivers[0].wins).toBe(0);
expect(result.drivers[0].podiums).toBe(0);
expect(result.drivers[0].isActive).toBe(false);
});
it('should derive skill level from rating bands', () => {
const dto: DriversLeaderboardResultDTO = {
drivers: [
{ id: 'd1', name: 'Beginner', country: 'US', iracingId: '1', joinedAt: new Date() },
{ id: 'd2', name: 'Intermediate', country: 'US', iracingId: '2', joinedAt: new Date() },
{ id: 'd3', name: 'Advanced', country: 'US', iracingId: '3', joinedAt: new Date() },
{ id: 'd4', name: 'Pro', country: 'US', iracingId: '4', joinedAt: new Date() },
],
rankings: [
{ driverId: 'd1', rating: 1700, overallRank: 4 },
{ driverId: 'd2', rating: 2000, overallRank: 3 },
{ driverId: 'd3', rating: 2600, overallRank: 2 },
{ driverId: 'd4', rating: 3100, overallRank: 1 },
],
stats: {
d1: { racesCompleted: 5, wins: 0, podiums: 0 },
d2: { racesCompleted: 5, wins: 0, podiums: 0 },
d3: { racesCompleted: 5, wins: 0, podiums: 0 },
d4: { racesCompleted: 5, wins: 0, podiums: 0 },
},
avatarUrls: {
d1: 'avatar-1',
d2: 'avatar-2',
d3: 'avatar-3',
d4: 'avatar-4',
},
};
presenter.present(dto);
const result = presenter.viewModel;
const levels = result.drivers
.sort((a, b) => a.rating - b.rating)
.map(d => d.skillLevel);
expect(levels).toEqual(['beginner', 'intermediate', 'advanced', 'pro']);
});
});

View File

@@ -1,6 +1,7 @@
import { DriversLeaderboardDTO, DriverLeaderboardItemDTO } from '../dtos/DriversLeaderboardDTO';
import { DriversLeaderboardDTO } from '../dtos/DriversLeaderboardDTO';
import { DriverLeaderboardItemDTO } from '../dtos/DriverLeaderboardItemDTO';
import type { IDriversLeaderboardPresenter, DriversLeaderboardResultDTO } from '../../../../../core/racing/application/presenters/IDriversLeaderboardPresenter';
import { SkillLevelService } from '../../../../../core/racing/domain/services/SkillLevelService';
export class DriversLeaderboardPresenter implements IDriversLeaderboardPresenter {
private result: DriversLeaderboardDTO | null = null;
@@ -15,16 +16,21 @@ export class DriversLeaderboardPresenter implements IDriversLeaderboardPresenter
const stats = dto.stats[driver.id];
const avatarUrl = dto.avatarUrls[driver.id];
const rating = ranking?.rating ?? 0;
const racesCompleted = stats?.racesCompleted ?? 0;
return {
id: driver.id,
name: driver.name,
rating: ranking?.rating ?? 0,
skillLevel: 'Pro', // TODO: map from domain
rating,
// Use core SkillLevelService to derive band from rating
skillLevel: SkillLevelService.getSkillLevel(rating),
nationality: driver.country,
racesCompleted: stats?.racesCompleted ?? 0,
racesCompleted,
wins: stats?.wins ?? 0,
podiums: stats?.podiums ?? 0,
isActive: true, // TODO: determine from domain
// Consider a driver active if they have completed at least one race
isActive: racesCompleted > 0,
rank: ranking?.overallRank ?? 0,
avatarUrl,
};