117 lines
3.2 KiB
TypeScript
117 lines
3.2 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';
|
|
|
|
// TODO: Move these types to apps/website/lib/types/generated when available
|
|
type RacesPageDataRaceDTO = {
|
|
id: string;
|
|
track: string;
|
|
car: string;
|
|
scheduledAt: string;
|
|
status: string;
|
|
leagueId: string;
|
|
leagueName: string;
|
|
};
|
|
type RacesPageDataDto = { races: RacesPageDataRaceDTO[] };
|
|
type RaceStatsDTO = { totalRaces: number };
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* Get races page data with view model transformation
|
|
*/
|
|
async getRacesPageData(): Promise<RacesPageViewModel> {
|
|
const dto = await this.apiClient.getPageData();
|
|
return new RacesPageViewModel(this.transformRacesPageData(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, { leagueId, driverId });
|
|
}
|
|
|
|
/**
|
|
* Withdraw from a race
|
|
*/
|
|
async withdrawFromRace(raceId: string, driverId: string): Promise<void> {
|
|
await this.apiClient.withdraw(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);
|
|
}
|
|
|
|
/**
|
|
* Transform API races page data to view model format
|
|
*/
|
|
private transformRacesPageData(dto: RacesPageDataDto): {
|
|
upcomingRaces: Array<{ id: string; title: string; scheduledTime: string; status: string }>;
|
|
completedRaces: Array<{ id: string; title: string; scheduledTime: string; status: string }>;
|
|
totalCount: number;
|
|
} {
|
|
const upcomingRaces = dto.races
|
|
.filter(race => race.status !== 'completed')
|
|
.map(race => ({
|
|
id: race.id,
|
|
title: `${race.track} - ${race.car}`,
|
|
scheduledTime: race.scheduledAt,
|
|
status: race.status,
|
|
}));
|
|
|
|
const completedRaces = dto.races
|
|
.filter(race => race.status === 'completed')
|
|
.map(race => ({
|
|
id: race.id,
|
|
title: `${race.track} - ${race.car}`,
|
|
scheduledTime: race.scheduledAt,
|
|
status: race.status,
|
|
}));
|
|
|
|
return {
|
|
upcomingRaces,
|
|
completedRaces,
|
|
totalCount: dto.races.length,
|
|
};
|
|
}
|
|
} |