Files
gridpilot.gg/apps/website/lib/view-models/DriverProfileViewModel.ts
2026-01-26 17:47:37 +01:00

167 lines
4.9 KiB
TypeScript

import { ViewModel } from "../contracts/view-models/ViewModel";
import { ProfileViewData } from "../view-data/ProfileViewData";
import { DriverProfileDriverSummaryViewModel } from "./DriverProfileDriverSummaryViewModel";
export { DriverProfileDriverSummaryViewModel };
export interface DriverProfileStatsViewModel extends ViewModel {
totalRaces: number;
wins: number;
podiums: number;
dnfs: number;
avgFinish: number | null;
bestFinish: number | null;
worstFinish: number | null;
finishRate: number | null;
winRate: number | null;
podiumRate: number | null;
percentile: number | null;
rating: number | null;
consistency: number | null;
overallRank: number | null;
}
export interface DriverProfileFinishDistributionViewModel extends ViewModel {
totalRaces: number;
wins: number;
podiums: number;
topTen: number;
dnfs: number;
other: number;
}
export interface DriverProfileTeamMembershipViewModel extends ViewModel {
teamId: string;
teamName: string;
teamTag: string | null;
role: string;
joinedAt: string;
isCurrent: boolean;
}
export interface DriverProfileSocialFriendSummaryViewModel extends ViewModel {
id: string;
name: string;
country: string;
avatarUrl: string;
}
export interface DriverProfileSocialSummaryViewModel extends ViewModel {
friendsCount: number;
friends: DriverProfileSocialFriendSummaryViewModel[];
}
export type DriverProfileSocialPlatform = 'twitter' | 'youtube' | 'twitch' | 'discord';
export type DriverProfileAchievementRarity = 'common' | 'rare' | 'epic' | 'legendary';
export interface DriverProfileAchievementViewModel extends ViewModel {
id: string;
title: string;
description: string;
icon: 'trophy' | 'medal' | 'star' | 'crown' | 'target' | 'zap';
rarity: DriverProfileAchievementRarity;
earnedAt: string;
}
export interface DriverProfileSocialHandleViewModel extends ViewModel {
platform: DriverProfileSocialPlatform;
handle: string;
url: string;
}
export interface DriverProfileExtendedProfileViewModel extends ViewModel {
socialHandles: DriverProfileSocialHandleViewModel[];
achievements: DriverProfileAchievementViewModel[];
racingStyle: string;
favoriteTrack: string;
favoriteCar: string;
timezone: string;
availableHours: string;
lookingForTeam: boolean;
openToRequests: boolean;
}
export interface DriverProfileViewModelData {
currentDriver: DriverProfileDriverSummaryViewModel | null;
stats: DriverProfileStatsViewModel | null;
finishDistribution: DriverProfileFinishDistributionViewModel | null;
teamMemberships: DriverProfileTeamMembershipViewModel[];
socialSummary: DriverProfileSocialSummaryViewModel;
extendedProfile: DriverProfileExtendedProfileViewModel | null;
}
/**
* Driver Profile View Model
*
* Represents a fully prepared UI state for driver profile display.
* Transforms ViewData into UI-ready data structures.
*/
export class DriverProfileViewModel extends ViewModel {
constructor(private readonly viewData: ProfileViewData) {
super();
}
get currentDriver(): DriverProfileDriverSummaryViewModel | null {
if (!this.viewData.driver) return null;
return new DriverProfileDriverSummaryViewModel(this.viewData);
}
get stats(): DriverProfileStatsViewModel | null {
if (!this.viewData.stats) return null;
return {
totalRaces: 0,
wins: 0,
podiums: 0,
dnfs: 0,
avgFinish: null,
bestFinish: null,
worstFinish: null,
finishRate: null,
winRate: null,
podiumRate: null,
percentile: null,
rating: null,
consistency: null,
overallRank: null,
};
}
get teamMemberships(): DriverProfileTeamMembershipViewModel[] {
return this.viewData.teamMemberships.map((m) => ({
teamId: m.teamId,
teamName: m.teamName,
teamTag: m.teamTag,
role: m.roleLabel,
joinedAt: m.joinedAtLabel,
isCurrent: true,
}));
}
get extendedProfile(): DriverProfileExtendedProfileViewModel | null {
if (!this.viewData.extendedProfile) return null;
return {
socialHandles: this.viewData.extendedProfile.socialHandles.map((h) => ({
platform: h.platformLabel.toLowerCase() as any,
handle: h.handle,
url: h.url,
})),
achievements: this.viewData.extendedProfile.achievements.map((a) => ({
id: a.id,
title: a.title,
description: a.description,
icon: a.icon,
rarity: a.rarityLabel.toLowerCase() as any,
earnedAt: a.earnedAtLabel,
})),
racingStyle: this.viewData.extendedProfile.racingStyle,
favoriteTrack: this.viewData.extendedProfile.favoriteTrack,
favoriteCar: this.viewData.extendedProfile.favoriteCar,
timezone: this.viewData.extendedProfile.timezone,
availableHours: this.viewData.extendedProfile.availableHours,
lookingForTeam: this.viewData.extendedProfile.lookingForTeamLabel === 'Yes',
openToRequests: this.viewData.extendedProfile.openToRequestsLabel === 'Yes',
};
}
}