42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
import { ViewModel } from "../contracts/view-models/ViewModel";
|
|
import type { UserProfileViewData } from "../view-data/UserProfileViewData";
|
|
|
|
export class UserProfileViewModel extends ViewModel {
|
|
private readonly data: UserProfileViewData;
|
|
|
|
constructor(data: UserProfileViewData) {
|
|
super();
|
|
this.data = data;
|
|
}
|
|
|
|
get id(): string { return this.data.id; }
|
|
get name(): string { return this.data.name; }
|
|
get avatarUrl(): string | undefined { return this.data.avatarUrl; }
|
|
get iracingId(): string | undefined { return this.data.iracingId; }
|
|
get rating(): number | undefined { return this.data.rating; }
|
|
|
|
/** UI-specific: Formatted rating */
|
|
get formattedRating(): string {
|
|
return this.rating ? this.rating.toFixed(0) : 'Unrated';
|
|
}
|
|
|
|
/** UI-specific: Whether has iRacing ID */
|
|
get hasIracingId(): boolean {
|
|
return !!this.iracingId;
|
|
}
|
|
|
|
/** UI-specific: Profile completeness percentage */
|
|
get profileCompleteness(): number {
|
|
let complete = 1; // id always there
|
|
if (this.avatarUrl) complete++;
|
|
if (this.iracingId) complete++;
|
|
if (this.rating) complete++;
|
|
return Math.round((complete / 4) * 100);
|
|
}
|
|
|
|
/** UI-specific: Avatar initials */
|
|
get avatarInitials(): string {
|
|
return this.name.split(' ').map(n => n[0]).join('').toUpperCase();
|
|
}
|
|
}
|