/** * 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); } }