72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
import type {
|
|
ILeagueDriverSeasonStatsPresenter,
|
|
LeagueDriverSeasonStatsItemViewModel,
|
|
LeagueDriverSeasonStatsViewModel,
|
|
LeagueDriverSeasonStatsResultDTO,
|
|
} from '@gridpilot/racing/application/presenters/ILeagueDriverSeasonStatsPresenter';
|
|
|
|
export class LeagueDriverSeasonStatsPresenter implements ILeagueDriverSeasonStatsPresenter {
|
|
private viewModel: LeagueDriverSeasonStatsViewModel | null = null;
|
|
|
|
reset(): void {
|
|
this.viewModel = null;
|
|
}
|
|
|
|
present(dto: LeagueDriverSeasonStatsResultDTO): void {
|
|
const { leagueId, standings, penalties, driverResults, driverRatings } = dto;
|
|
|
|
const stats: LeagueDriverSeasonStatsItemViewModel[] = standings.map((standing) => {
|
|
const penalty = penalties.get(standing.driverId) ?? { baseDelta: 0, bonusDelta: 0 };
|
|
const totalPenaltyPoints = penalty.baseDelta;
|
|
const bonusPoints = penalty.bonusDelta;
|
|
|
|
const racesCompleted = standing.racesCompleted;
|
|
const pointsPerRace = racesCompleted > 0 ? standing.points / racesCompleted : 0;
|
|
|
|
const ratingInfo = driverRatings.get(standing.driverId) ?? { rating: null, ratingChange: null };
|
|
|
|
const results = driverResults.get(standing.driverId) ?? [];
|
|
let avgFinish: number | null = null;
|
|
if (results.length > 0) {
|
|
const totalPositions = results.reduce((sum, r) => sum + r.position, 0);
|
|
const avg = totalPositions / results.length;
|
|
avgFinish = Number.isFinite(avg) ? Number(avg.toFixed(2)) : null;
|
|
}
|
|
|
|
return {
|
|
leagueId,
|
|
driverId: standing.driverId,
|
|
position: standing.position,
|
|
driverName: '',
|
|
teamId: '',
|
|
teamName: '',
|
|
totalPoints: standing.points + totalPenaltyPoints + bonusPoints,
|
|
basePoints: standing.points,
|
|
penaltyPoints: Math.abs(totalPenaltyPoints),
|
|
bonusPoints,
|
|
pointsPerRace,
|
|
racesStarted: results.length,
|
|
racesFinished: results.length,
|
|
dnfs: 0,
|
|
noShows: 0,
|
|
avgFinish,
|
|
rating: ratingInfo.rating,
|
|
ratingChange: ratingInfo.ratingChange,
|
|
};
|
|
});
|
|
|
|
stats.sort((a, b) => a.position - b.position);
|
|
|
|
this.viewModel = {
|
|
leagueId,
|
|
stats,
|
|
};
|
|
}
|
|
|
|
getViewModel(): LeagueDriverSeasonStatsViewModel {
|
|
if (!this.viewModel) {
|
|
throw new Error('Presenter has not been called yet');
|
|
}
|
|
return this.viewModel;
|
|
}
|
|
} |