164 lines
6.0 KiB
TypeScript
164 lines
6.0 KiB
TypeScript
import { DriversApiClient } from '@/lib/api/drivers/DriversApiClient';
|
|
import type { CompleteOnboardingInputDTO } from '@/lib/types/generated/CompleteOnboardingInputDTO';
|
|
import type { GetDriverOutputDTO } from '@/lib/types/generated/GetDriverOutputDTO';
|
|
import { CompleteOnboardingViewModel } from "@/lib/view-models/CompleteOnboardingViewModel";
|
|
import { DriverLeaderboardViewModel } from "@/lib/view-models/DriverLeaderboardViewModel";
|
|
import { DriverViewModel } from "@/lib/view-models/DriverViewModel";
|
|
import { DriverProfileViewModel } from "@/lib/view-models/DriverProfileViewModel";
|
|
|
|
/**
|
|
* Driver Service
|
|
*
|
|
* Orchestrates driver operations by coordinating API calls and view model creation.
|
|
* All dependencies are injected via constructor.
|
|
*/
|
|
export class DriverService {
|
|
constructor(
|
|
private readonly apiClient: DriversApiClient
|
|
) {}
|
|
|
|
/**
|
|
* Get driver leaderboard with view model transformation
|
|
*/
|
|
async getDriverLeaderboard(): Promise<DriverLeaderboardViewModel> {
|
|
const dto = await this.apiClient.getLeaderboard();
|
|
return new DriverLeaderboardViewModel(dto);
|
|
}
|
|
|
|
/**
|
|
* Complete driver onboarding with view model transformation
|
|
*/
|
|
async completeDriverOnboarding(input: CompleteOnboardingInputDTO): Promise<CompleteOnboardingViewModel> {
|
|
const dto = await this.apiClient.completeOnboarding(input);
|
|
return new CompleteOnboardingViewModel(dto);
|
|
}
|
|
|
|
/**
|
|
* Get current driver with view model transformation
|
|
*/
|
|
async getCurrentDriver(): Promise<DriverViewModel | null> {
|
|
const dto = await this.apiClient.getCurrent();
|
|
if (!dto) {
|
|
return null;
|
|
}
|
|
return new DriverViewModel({ ...dto, avatarUrl: (dto as any).avatarUrl ?? null });
|
|
}
|
|
|
|
/**
|
|
* Get driver profile with full details and view model transformation
|
|
*/
|
|
async getDriverProfile(driverId: string): Promise<DriverProfileViewModel> {
|
|
const dto = await this.apiClient.getDriverProfile(driverId);
|
|
return new DriverProfileViewModel({
|
|
currentDriver: dto.currentDriver
|
|
? {
|
|
id: dto.currentDriver.id,
|
|
name: dto.currentDriver.name,
|
|
country: dto.currentDriver.country,
|
|
avatarUrl: dto.currentDriver.avatarUrl || '',
|
|
iracingId: dto.currentDriver.iracingId ?? null,
|
|
joinedAt: dto.currentDriver.joinedAt,
|
|
rating: dto.currentDriver.rating ?? null,
|
|
globalRank: dto.currentDriver.globalRank ?? null,
|
|
consistency: dto.currentDriver.consistency ?? null,
|
|
bio: dto.currentDriver.bio ?? null,
|
|
totalDrivers: dto.currentDriver.totalDrivers ?? null,
|
|
}
|
|
: null,
|
|
stats: dto.stats
|
|
? {
|
|
totalRaces: dto.stats.totalRaces,
|
|
wins: dto.stats.wins,
|
|
podiums: dto.stats.podiums,
|
|
dnfs: dto.stats.dnfs,
|
|
avgFinish: dto.stats.avgFinish ?? null,
|
|
bestFinish: dto.stats.bestFinish ?? null,
|
|
worstFinish: dto.stats.worstFinish ?? null,
|
|
finishRate: dto.stats.finishRate ?? null,
|
|
winRate: dto.stats.winRate ?? null,
|
|
podiumRate: dto.stats.podiumRate ?? null,
|
|
percentile: dto.stats.percentile ?? null,
|
|
rating: dto.stats.rating ?? null,
|
|
consistency: dto.stats.consistency ?? null,
|
|
overallRank: dto.stats.overallRank ?? null,
|
|
}
|
|
: null,
|
|
finishDistribution: dto.finishDistribution
|
|
? {
|
|
totalRaces: dto.finishDistribution.totalRaces,
|
|
wins: dto.finishDistribution.wins,
|
|
podiums: dto.finishDistribution.podiums,
|
|
topTen: dto.finishDistribution.topTen,
|
|
dnfs: dto.finishDistribution.dnfs,
|
|
other: dto.finishDistribution.other,
|
|
}
|
|
: null,
|
|
teamMemberships: dto.teamMemberships.map((m) => ({
|
|
teamId: m.teamId,
|
|
teamName: m.teamName,
|
|
teamTag: m.teamTag ?? null,
|
|
role: m.role,
|
|
joinedAt: m.joinedAt,
|
|
isCurrent: m.isCurrent,
|
|
})),
|
|
socialSummary: {
|
|
friendsCount: dto.socialSummary.friendsCount,
|
|
friends: dto.socialSummary.friends.map((f) => ({
|
|
id: f.id,
|
|
name: f.name,
|
|
country: f.country,
|
|
avatarUrl: f.avatarUrl || '',
|
|
})),
|
|
},
|
|
extendedProfile: dto.extendedProfile
|
|
? {
|
|
socialHandles: dto.extendedProfile.socialHandles.map((h) => ({
|
|
platform: h.platform as any,
|
|
handle: h.handle,
|
|
url: h.url,
|
|
})),
|
|
achievements: dto.extendedProfile.achievements.map((a) => ({
|
|
id: a.id,
|
|
title: a.title,
|
|
description: a.description,
|
|
icon: a.icon as any,
|
|
rarity: a.rarity as any,
|
|
earnedAt: a.earnedAt,
|
|
})),
|
|
racingStyle: dto.extendedProfile.racingStyle,
|
|
favoriteTrack: dto.extendedProfile.favoriteTrack,
|
|
favoriteCar: dto.extendedProfile.favoriteCar,
|
|
timezone: dto.extendedProfile.timezone,
|
|
availableHours: dto.extendedProfile.availableHours,
|
|
lookingForTeam: dto.extendedProfile.lookingForTeam,
|
|
openToRequests: dto.extendedProfile.openToRequests,
|
|
}
|
|
: null,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update current driver profile with view model transformation
|
|
*/
|
|
async updateProfile(updates: { bio?: string; country?: string }): Promise<DriverProfileViewModel> {
|
|
const dto = await this.apiClient.updateProfile(updates);
|
|
// After updating, get the full profile again to return updated view model
|
|
return this.getDriverProfile(dto.id);
|
|
}
|
|
|
|
/**
|
|
* Find driver by ID
|
|
*/
|
|
async findById(id: string): Promise<GetDriverOutputDTO | null> {
|
|
return this.apiClient.getDriver(id);
|
|
}
|
|
|
|
/**
|
|
* Find multiple drivers by IDs
|
|
*/
|
|
async findByIds(ids: string[]): Promise<GetDriverOutputDTO[]> {
|
|
const drivers = await Promise.all(ids.map(id => this.apiClient.getDriver(id)));
|
|
return drivers.filter((d): d is GetDriverOutputDTO => d !== null);
|
|
}
|
|
}
|