/** * League Detail View Model * * View model for detailed league information for sponsors. */ export class LeagueDetailViewModel { league: LeagueViewModel; drivers: DriverViewModel[]; races: RaceViewModel[]; constructor(data: { league: any; drivers: any[]; races: any[] }) { this.league = new LeagueViewModel(data.league); this.drivers = data.drivers.map(driver => new DriverViewModel(driver)); this.races = data.races.map(race => new RaceViewModel(race)); } } export class LeagueViewModel { id: string; name: string; game: string; tier: 'premium' | 'standard' | 'starter'; season: string; description: string; drivers: number; races: number; completedRaces: number; totalImpressions: number; avgViewsPerRace: number; engagement: number; rating: number; seasonStatus: 'active' | 'upcoming' | 'completed'; seasonDates: { start: string; end: string }; nextRace?: { name: string; date: string }; sponsorSlots: { main: { available: boolean; price: number; benefits: string[] }; secondary: { available: number; total: number; price: number; benefits: string[] }; }; constructor(data: any) { this.id = data.id; this.name = data.name; this.game = data.game; this.tier = data.tier; this.season = data.season; this.description = data.description; this.drivers = data.drivers; this.races = data.races; this.completedRaces = data.completedRaces; this.totalImpressions = data.totalImpressions; this.avgViewsPerRace = data.avgViewsPerRace; this.engagement = data.engagement; this.rating = data.rating; this.seasonStatus = data.seasonStatus; this.seasonDates = data.seasonDates; this.nextRace = data.nextRace; this.sponsorSlots = data.sponsorSlots; } get formattedTotalImpressions(): string { return this.totalImpressions.toLocaleString(); } get formattedAvgViewsPerRace(): string { return this.avgViewsPerRace.toLocaleString(); } get projectedTotalViews(): number { return Math.round(this.avgViewsPerRace * this.races); } get formattedProjectedTotal(): string { return this.projectedTotalViews.toLocaleString(); } get mainSponsorCpm(): number { return Math.round((this.sponsorSlots.main.price / this.projectedTotalViews) * 1000); } get formattedMainSponsorCpm(): string { return `$${this.mainSponsorCpm.toFixed(2)}`; } get racesLeft(): number { return this.races - this.completedRaces; } get tierConfig() { const configs = { premium: { color: 'text-yellow-400', bgColor: 'bg-yellow-500/10', border: 'border-yellow-500/30' }, standard: { color: 'text-primary-blue', bgColor: 'bg-primary-blue/10', border: 'border-primary-blue/30' }, starter: { color: 'text-gray-400', bgColor: 'bg-gray-500/10', border: 'border-gray-500/30' }, }; return configs[this.tier]; } } export class DriverViewModel { id: string; name: string; country: string; position: number; races: number; impressions: number; team: string; constructor(data: any) { this.id = data.id; this.name = data.name; this.country = data.country; this.position = data.position; this.races = data.races; this.impressions = data.impressions; this.team = data.team; } get formattedImpressions(): string { return this.impressions.toLocaleString(); } } export class RaceViewModel { id: string; name: string; date: Date; views: number; status: 'upcoming' | 'completed'; constructor(data: any) { this.id = data.id; this.name = data.name; this.date = new Date(data.date); this.views = data.views; this.status = data.status; } get formattedDate(): string { return this.date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); } get formattedViews(): string { return this.views.toLocaleString(); } }