Files
gridpilot.gg/apps/website/lib/presenters/LeagueFullConfigPresenter.ts
2025-12-11 21:06:25 +01:00

117 lines
3.6 KiB
TypeScript

import type { DropScorePolicy } from '@gridpilot/racing/domain/types/DropScorePolicy';
import type {
ILeagueFullConfigPresenter,
LeagueFullConfigData,
LeagueConfigFormViewModel,
} from '@gridpilot/racing/application/presenters/ILeagueFullConfigPresenter';
export class LeagueFullConfigPresenter implements ILeagueFullConfigPresenter {
private viewModel: LeagueConfigFormViewModel | null = null;
reset(): void {
this.viewModel = null;
}
present(data: LeagueFullConfigData): void {
const { league, activeSeason, scoringConfig, game } = data;
const patternId = scoringConfig?.scoringPresetId;
const primaryChampionship =
scoringConfig && scoringConfig.championships && scoringConfig.championships.length > 0
? scoringConfig.championships[0]
: undefined;
const dropPolicy = primaryChampionship?.dropScorePolicy ?? undefined;
const dropPolicyForm = this.mapDropPolicy(dropPolicy);
const defaultQualifyingMinutes = 30;
const defaultMainRaceMinutes = 40;
const mainRaceMinutes =
typeof league.settings.sessionDuration === 'number'
? league.settings.sessionDuration
: defaultMainRaceMinutes;
const qualifyingMinutes = defaultQualifyingMinutes;
const roundsPlanned = 8;
let sessionCount = 2;
if (primaryChampionship && Array.isArray(primaryChampionship.sessionTypes)) {
sessionCount = primaryChampionship.sessionTypes.length;
}
const practiceMinutes = 20;
const sprintRaceMinutes = patternId === 'sprint-main-driver' ? 20 : undefined;
this.viewModel = {
leagueId: league.id,
basics: {
name: league.name,
description: league.description,
visibility: 'public',
gameId: game?.id ?? 'iracing',
},
structure: {
mode: 'solo',
maxDrivers: league.settings.maxDrivers ?? 32,
multiClassEnabled: false,
},
championships: {
enableDriverChampionship: true,
enableTeamChampionship: false,
enableNationsChampionship: false,
enableTrophyChampionship: false,
},
scoring: {
customScoringEnabled: !patternId,
...(patternId ? { patternId } : {}),
},
dropPolicy: dropPolicyForm,
timings: {
practiceMinutes,
qualifyingMinutes,
mainRaceMinutes,
sessionCount,
roundsPlanned,
...(typeof sprintRaceMinutes === 'number'
? { sprintRaceMinutes }
: {}),
},
stewarding: {
decisionMode: 'admin_only',
requireDefense: true,
defenseTimeLimit: 48,
voteTimeLimit: 72,
protestDeadlineHours: 72,
stewardingClosesHours: 168,
notifyAccusedOnProtest: true,
notifyOnVoteRequired: true,
},
};
}
getViewModel(): LeagueConfigFormViewModel | null {
if (!this.viewModel) {
throw new Error('Presenter has not been called yet');
}
return this.viewModel;
}
private mapDropPolicy(policy: DropScorePolicy | undefined): { strategy: string; n?: number } {
if (!policy || policy.strategy === 'none') {
return { strategy: 'none' };
}
if (policy.strategy === 'bestNResults') {
const n = typeof policy.count === 'number' ? policy.count : undefined;
return n !== undefined ? { strategy: 'bestNResults', n } : { strategy: 'none' };
}
if (policy.strategy === 'dropWorstN') {
const n = typeof policy.dropCount === 'number' ? policy.dropCount : undefined;
return n !== undefined ? { strategy: 'dropWorstN', n } : { strategy: 'none' };
}
return { strategy: 'none' };
}
}