87 lines
2.4 KiB
TypeScript
87 lines
2.4 KiB
TypeScript
import { DriverLeaderboardItemDTO } from '../types/generated/DriverLeaderboardItemDTO';
|
|
|
|
export class DriverLeaderboardItemViewModel {
|
|
id: string;
|
|
name: string;
|
|
rating: number;
|
|
skillLevel: string;
|
|
nationality: string;
|
|
racesCompleted: number;
|
|
wins: number;
|
|
podiums: number;
|
|
isActive: boolean;
|
|
rank: number;
|
|
avatarUrl: string;
|
|
|
|
position: number;
|
|
private previousRating?: number;
|
|
|
|
constructor(dto: DriverLeaderboardItemDTO & { avatarUrl: string }, position: number, previousRating?: number) {
|
|
this.id = dto.id;
|
|
this.name = dto.name;
|
|
this.rating = dto.rating;
|
|
this.skillLevel = dto.skillLevel;
|
|
this.nationality = dto.nationality;
|
|
this.racesCompleted = dto.racesCompleted;
|
|
this.wins = dto.wins;
|
|
this.podiums = dto.podiums;
|
|
this.isActive = dto.isActive;
|
|
this.rank = dto.rank;
|
|
this.avatarUrl = dto.avatarUrl;
|
|
this.position = position;
|
|
this.previousRating = previousRating;
|
|
}
|
|
|
|
/** UI-specific: Skill level color */
|
|
get skillLevelColor(): string {
|
|
switch (this.skillLevel) {
|
|
case 'beginner': return 'green';
|
|
case 'intermediate': return 'yellow';
|
|
case 'advanced': return 'orange';
|
|
case 'expert': return 'red';
|
|
default: return 'gray';
|
|
}
|
|
}
|
|
|
|
/** UI-specific: Skill level icon */
|
|
get skillLevelIcon(): string {
|
|
switch (this.skillLevel) {
|
|
case 'beginner': return '🥉';
|
|
case 'intermediate': return '🥈';
|
|
case 'advanced': return '🥇';
|
|
case 'expert': return '👑';
|
|
default: return '🏁';
|
|
}
|
|
}
|
|
|
|
/** UI-specific: Win rate */
|
|
get winRate(): number {
|
|
return this.racesCompleted > 0 ? (this.wins / this.racesCompleted) * 100 : 0;
|
|
}
|
|
|
|
/** UI-specific: Formatted win rate */
|
|
get winRateFormatted(): string {
|
|
return `${this.winRate.toFixed(1)}%`;
|
|
}
|
|
|
|
/** UI-specific: Rating trend */
|
|
get ratingTrend(): 'up' | 'down' | 'same' {
|
|
if (!this.previousRating) return 'same';
|
|
if (this.rating > this.previousRating) return 'up';
|
|
if (this.rating < this.previousRating) return 'down';
|
|
return 'same';
|
|
}
|
|
|
|
/** UI-specific: Rating change indicator */
|
|
get ratingChangeIndicator(): string {
|
|
const change = this.previousRating ? this.rating - this.previousRating : 0;
|
|
if (change > 0) return `+${change}`;
|
|
if (change < 0) return `${change}`;
|
|
return '0';
|
|
}
|
|
|
|
/** UI-specific: Position badge */
|
|
get positionBadge(): string {
|
|
return this.position.toString();
|
|
}
|
|
} |