view data fixes

This commit is contained in:
2026-01-24 00:52:27 +01:00
parent 62e8b768ce
commit ae59df61eb
321 changed files with 1157 additions and 2234 deletions

View File

@@ -1,145 +1,25 @@
import type { GetDriverProfileOutputDTO } from '@/lib/types/generated/GetDriverProfileOutputDTO';
import type { DriverProfileDriverSummaryDTO } from '@/lib/types/generated/DriverProfileDriverSummaryDTO';
import type { DriverProfileStatsDTO } from '@/lib/types/generated/DriverProfileStatsDTO';
import type { DriverProfileFinishDistributionDTO } from '@/lib/types/generated/DriverProfileFinishDistributionDTO';
import type { DriverProfileTeamMembershipDTO } from '@/lib/types/generated/DriverProfileTeamMembershipDTO';
import type { DriverProfileSocialSummaryDTO } from '@/lib/types/generated/DriverProfileSocialSummaryDTO';
import type { DriverProfileExtendedProfileDTO } from '@/lib/types/generated/DriverProfileExtendedProfileDTO';
import { DriverProfileViewModel } from '@/lib/view-models/DriverProfileViewModel';
import type {
DriverProfileDriverSummaryViewModel,
DriverProfileStatsViewModel,
DriverProfileFinishDistributionViewModel,
DriverProfileTeamMembershipViewModel,
DriverProfileSocialSummaryViewModel,
DriverProfileExtendedProfileViewModel,
} from '@/lib/view-models/DriverProfileViewModel';
import { ProfileViewData } from '@/lib/view-data/ProfileViewData';
import { ViewModelBuilder } from "../../contracts/builders/ViewModelBuilder";
/**
* DriverProfileViewModelBuilder
*
* Transforms GetDriverProfileOutputDTO into DriverProfileViewModel.
* Transforms ProfileViewData into DriverProfileViewModel.
* Deterministic, side-effect free, no HTTP calls.
*/
import { ViewModelBuilder } from "../../contracts/builders/ViewModelBuilder";
export class DriverProfileViewModelBuilder implements ViewModelBuilder<any, any> {
build(input: any): any {
return DriverProfileViewModelBuilder.build(input);
}
static build(
/**
* Build ViewModel from API DTO
*
* @param apiDto - The API transport DTO
* @returns ViewModel ready for template
* Build ViewModel from ViewData
*
* @param viewData - The template-ready ViewData
* @returns ViewModel ready for client-side state
*/
static build(apiDto: GetDriverProfileOutputDTO): DriverProfileViewModel {
return new DriverProfileViewModel({
currentDriver: apiDto.currentDriver ? this.transformCurrentDriver(apiDto.currentDriver) : null,
stats: apiDto.stats ? this.transformStats(apiDto.stats) : null,
finishDistribution: apiDto.finishDistribution ? this.transformFinishDistribution(apiDto.finishDistribution) : null,
teamMemberships: apiDto.teamMemberships.map(m => this.transformTeamMembership(m)),
socialSummary: this.transformSocialSummary(apiDto.socialSummary),
extendedProfile: apiDto.extendedProfile ? this.transformExtendedProfile(apiDto.extendedProfile) : null,
});
}
private static transformCurrentDriver(dto: DriverProfileDriverSummaryDTO): DriverProfileDriverSummaryViewModel {
return {
id: dto.id,
name: dto.name,
country: dto.country,
avatarUrl: dto.avatarUrl || '', // Handle undefined
iracingId: dto.iracingId || null,
joinedAt: dto.joinedAt,
rating: dto.rating ?? null,
globalRank: dto.globalRank ?? null,
consistency: dto.consistency ?? null,
bio: dto.bio || null,
totalDrivers: dto.totalDrivers ?? null,
};
}
private static transformStats(dto: DriverProfileStatsDTO): DriverProfileStatsViewModel {
return {
totalRaces: dto.totalRaces,
wins: dto.wins,
podiums: dto.podiums,
dnfs: dto.dnfs,
avgFinish: dto.avgFinish ?? null,
bestFinish: dto.bestFinish ?? null,
worstFinish: dto.worstFinish ?? null,
finishRate: dto.finishRate ?? null,
winRate: dto.winRate ?? null,
podiumRate: dto.podiumRate ?? null,
percentile: dto.percentile ?? null,
rating: dto.rating ?? null,
consistency: dto.consistency ?? null,
overallRank: dto.overallRank ?? null,
};
}
private static transformFinishDistribution(dto: DriverProfileFinishDistributionDTO): DriverProfileFinishDistributionViewModel {
return {
totalRaces: dto.totalRaces,
wins: dto.wins,
podiums: dto.podiums,
topTen: dto.topTen,
dnfs: dto.dnfs,
other: dto.other,
};
}
private static transformTeamMembership(dto: DriverProfileTeamMembershipDTO): DriverProfileTeamMembershipViewModel {
return {
teamId: dto.teamId,
teamName: dto.teamName,
teamTag: dto.teamTag || null,
role: dto.role,
joinedAt: dto.joinedAt,
isCurrent: dto.isCurrent,
};
}
private static transformSocialSummary(dto: DriverProfileSocialSummaryDTO): DriverProfileSocialSummaryViewModel {
return {
friendsCount: dto.friendsCount,
friends: dto.friends.map(f => ({
id: f.id,
name: f.name,
country: f.country,
avatarUrl: f.avatarUrl || '', // Handle undefined
})),
};
}
private static transformExtendedProfile(dto: DriverProfileExtendedProfileDTO): DriverProfileExtendedProfileViewModel {
return {
socialHandles: dto.socialHandles.map(h => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
platform: h.platform as any, // Type assertion - assuming valid platform
handle: h.handle,
url: h.url,
})),
achievements: dto.achievements.map(a => ({
id: a.id,
title: a.title,
description: a.description,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
icon: a.icon as any, // Type assertion - assuming valid icon
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rarity: a.rarity as any, // Type assertion - assuming valid rarity
earnedAt: a.earnedAt,
})),
racingStyle: dto.racingStyle,
favoriteTrack: dto.favoriteTrack,
favoriteCar: dto.favoriteCar,
timezone: dto.timezone,
availableHours: dto.availableHours,
lookingForTeam: dto.lookingForTeam,
openToRequests: dto.openToRequests,
};
static build(viewData: ProfileViewData): DriverProfileViewModel {
return new DriverProfileViewModel(viewData);
}
}

View File

@@ -1,5 +1,5 @@
import type { DriversLeaderboardDTO } from '@/lib/types/generated/DriversLeaderboardDTO';
import { DriverLeaderboardViewModel } from '@/lib/view-models/DriverLeaderboardViewModel';
import { LeaderboardsViewData } from '@/lib/view-data/LeaderboardsViewData';
/**
* DriversViewModelBuilder
@@ -14,10 +14,7 @@ export class DriversViewModelBuilder implements ViewModelBuilder<any, any> {
return DriversViewModelBuilder.build(input);
}
static build(
static build(apiDto: DriversLeaderboardDTO): DriverLeaderboardViewModel {
return new DriverLeaderboardViewModel({
drivers: apiDto.drivers,
});
static build(viewData: LeaderboardsViewData): DriverLeaderboardViewModel {
return new DriverLeaderboardViewModel(viewData);
}
}

View File

@@ -9,24 +9,6 @@ export class LeagueSummaryViewModelBuilder implements ViewModelBuilder<any, any>
}
static build(league: LeaguesViewData['leagues'][number]): LeagueSummaryViewModel {
return {
id: league.id,
name: league.name,
description: league.description ?? '',
logoUrl: league.logoUrl,
ownerId: league.ownerId,
createdAt: league.createdAt,
maxDrivers: league.maxDrivers,
usedDriverSlots: league.usedDriverSlots,
maxTeams: league.maxTeams ?? 0,
usedTeamSlots: league.usedTeamSlots ?? 0,
structureSummary: league.structureSummary,
timingSummary: league.timingSummary,
category: league.category ?? undefined,
scoring: league.scoring ? {
...league.scoring,
primaryChampionshipType: league.scoring.primaryChampionshipType as 'driver' | 'team' | 'nations' | 'trophy',
} : undefined,
};
return new LeagueSummaryViewModel(league as any);
}
}

View File

@@ -16,12 +16,11 @@ export class OnboardingViewModelBuilder implements ViewModelBuilder<any, any> {
return OnboardingViewModelBuilder.build(input);
}
static build(
static build(apiDto: { isAlreadyOnboarded: boolean }): Result<OnboardingViewModel, DomainError> {
try {
return Result.ok({
return Result.ok(new OnboardingViewModel({
isAlreadyOnboarded: apiDto.isAlreadyOnboarded || false,
});
}));
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Failed to build ViewModel';
return Result.err({ type: 'unknown', message: errorMessage });