Files
gridpilot.gg/apps/website/lib/services/races/RaceService.ts
2025-12-24 21:44:58 +01:00

116 lines
3.3 KiB
TypeScript

import { RacesApiClient } from '../../api/races/RacesApiClient';
import { RaceDetailViewModel } from '../../view-models/RaceDetailViewModel';
import { RacesPageViewModel } from '../../view-models/RacesPageViewModel';
import { RaceStatsViewModel } from '../../view-models/RaceStatsViewModel';
import type { FileProtestCommandDTO } from '../../types/generated/FileProtestCommandDTO';
import type { RaceStatsDTO } from '../../types/generated/RaceStatsDTO';
/**
* Race Service
*
* Orchestrates race operations by coordinating API calls and view model creation.
* All dependencies are injected via constructor.
*/
export class RaceService {
constructor(
private readonly apiClient: RacesApiClient
) {}
/**
* Get race detail with view model transformation
*/
async getRaceDetail(
raceId: string,
driverId: string
): Promise<RaceDetailViewModel> {
const dto = await this.apiClient.getDetail(raceId, driverId);
return new RaceDetailViewModel(dto, driverId);
}
/**
* Get races page data with view model transformation
*/
async getRacesPageData(): Promise<RacesPageViewModel> {
const dto = await this.apiClient.getPageData();
return new RacesPageViewModel(dto);
}
/**
* Get races page data filtered by league
*/
async getLeagueRacesPageData(leagueId: string): Promise<RacesPageViewModel> {
const dto = await this.apiClient.getPageData(leagueId);
return new RacesPageViewModel(dto);
}
/**
* Get all races page data with view model transformation
* Currently same as getRacesPageData, but can be extended for different filtering
*/
async getAllRacesPageData(): Promise<RacesPageViewModel> {
const dto = await this.apiClient.getPageData();
return new RacesPageViewModel(dto);
}
/**
* Get total races statistics with view model transformation
*/
async getRacesTotal(): Promise<RaceStatsViewModel> {
const dto: RaceStatsDTO = await this.apiClient.getTotal();
return new RaceStatsViewModel(dto);
}
/**
* Register for a race
*/
async registerForRace(raceId: string, leagueId: string, driverId: string): Promise<void> {
await this.apiClient.register(raceId, { raceId, leagueId, driverId });
}
/**
* Withdraw from a race
*/
async withdrawFromRace(raceId: string, driverId: string): Promise<void> {
await this.apiClient.withdraw(raceId, { raceId, driverId });
}
/**
* Cancel a race
*/
async cancelRace(raceId: string): Promise<void> {
await this.apiClient.cancel(raceId);
}
/**
* Complete a race
*/
async completeRace(raceId: string): Promise<void> {
await this.apiClient.complete(raceId);
}
/**
* Re-open a race
*/
async reopenRace(raceId: string): Promise<void> {
await this.apiClient.reopen(raceId);
}
/**
* File a protest
*/
async fileProtest(input: FileProtestCommandDTO): Promise<void> {
await this.apiClient.fileProtest(input);
}
/**
* Find races by league ID
*
* The races API does not currently expose a league-filtered listing endpoint in this build,
* so this method deliberately signals that the operation is unavailable instead of making
* assumptions about URL structure.
*/
async findByLeagueId(leagueId: string): Promise<RacesPageViewModel['races']> {
const page = await this.getLeagueRacesPageData(leagueId);
return page.races;
}
}