Files
gridpilot.gg/apps/website/lib/view-models/AvailableLeaguesViewModel.ts
2026-01-24 01:07:43 +01:00

75 lines
2.7 KiB
TypeScript

/**
* Available Leagues View Model
*
* View model for leagues available for sponsorship.
*
* Accepts AvailableLeaguesViewData as input and produces UI-ready data.
*/
import { ViewModel } from "../contracts/view-models/ViewModel";
import { CurrencyFormatter } from "../formatters/CurrencyFormatter";
import { LeagueTierFormatter } from "../formatters/LeagueTierFormatter";
import { NumberFormatter } from "../formatters/NumberFormatter";
import { SeasonStatusFormatter } from "../formatters/SeasonStatusFormatter";
import { AvailableLeaguesViewData, AvailableLeagueViewData } from "../view-data/AvailableLeaguesViewData";
export class AvailableLeaguesViewModel extends ViewModel {
readonly leagues: AvailableLeagueViewModel[];
constructor(data: AvailableLeaguesViewData) {
super();
this.leagues = data.leagues.map(league => new AvailableLeagueViewModel(league));
}
}
export class AvailableLeagueViewModel extends ViewModel {
private readonly data: AvailableLeagueViewData;
constructor(data: AvailableLeagueViewData) {
super();
this.data = data;
}
get id(): string { return this.data.id; }
get name(): string { return this.data.name; }
get game(): string { return this.data.game; }
get drivers(): number { return this.data.drivers; }
get avgViewsPerRace(): number { return this.data.avgViewsPerRace; }
get mainSponsorSlot() { return this.data.mainSponsorSlot; }
get secondarySlots() { return this.data.secondarySlots; }
get rating(): number { return this.data.rating; }
get tier(): 'premium' | 'standard' | 'starter' { return this.data.tier; }
get nextRace(): string | undefined { return this.data.nextRace; }
get seasonStatus(): 'active' | 'upcoming' | 'completed' { return this.data.seasonStatus; }
get description(): string { return this.data.description; }
/** UI-specific: Formatted average views */
get formattedAvgViews(): string {
return NumberFormatter.formatCompact(this.avgViewsPerRace);
}
/** UI-specific: CPM calculation */
get cpm(): number {
return Math.round((this.mainSponsorSlot.price / this.avgViewsPerRace) * 1000);
}
/** UI-specific: Formatted CPM */
get formattedCpm(): string {
return CurrencyFormatter.formatCompact(this.cpm);
}
/** UI-specific: Check if any sponsor slots are available */
get hasAvailableSlots(): boolean {
return this.mainSponsorSlot.available || this.secondarySlots.available > 0;
}
/** UI-specific: Tier configuration for badge styling */
get tierConfig() {
return LeagueTierFormatter.getDisplay(this.tier);
}
/** UI-specific: Status configuration for season state */
get statusConfig() {
return SeasonStatusFormatter.getDisplay(this.seasonStatus);
}
}