78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
/**
|
|
* Available Leagues View Model
|
|
*
|
|
* View model for leagues available for sponsorship.
|
|
*/
|
|
export class AvailableLeaguesViewModel {
|
|
leagues: AvailableLeagueViewModel[];
|
|
|
|
constructor(leagues: unknown[]) {
|
|
this.leagues = leagues.map(league => new AvailableLeagueViewModel(league));
|
|
}
|
|
}
|
|
|
|
export class AvailableLeagueViewModel {
|
|
id: string;
|
|
name: string;
|
|
game: string;
|
|
drivers: number;
|
|
avgViewsPerRace: number;
|
|
mainSponsorSlot: { available: boolean; price: number };
|
|
secondarySlots: { available: number; total: number; price: number };
|
|
rating: number;
|
|
tier: 'premium' | 'standard' | 'starter';
|
|
nextRace?: string;
|
|
seasonStatus: 'active' | 'upcoming' | 'completed';
|
|
description: string;
|
|
|
|
constructor(data: unknown) {
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const d = data as any;
|
|
this.id = d.id;
|
|
this.name = d.name;
|
|
this.game = d.game;
|
|
this.drivers = d.drivers;
|
|
this.avgViewsPerRace = d.avgViewsPerRace;
|
|
this.mainSponsorSlot = d.mainSponsorSlot;
|
|
this.secondarySlots = d.secondarySlots;
|
|
this.rating = d.rating;
|
|
this.tier = d.tier;
|
|
this.nextRace = d.nextRace;
|
|
this.seasonStatus = d.seasonStatus;
|
|
this.description = d.description;
|
|
}
|
|
|
|
get formattedAvgViews(): string {
|
|
return `${(this.avgViewsPerRace / 1000).toFixed(1)}k`;
|
|
}
|
|
|
|
get cpm(): number {
|
|
return Math.round((this.mainSponsorSlot.price / this.avgViewsPerRace) * 1000);
|
|
}
|
|
|
|
get formattedCpm(): string {
|
|
return `$${this.cpm}`;
|
|
}
|
|
|
|
get hasAvailableSlots(): boolean {
|
|
return this.mainSponsorSlot.available || this.secondarySlots.available > 0;
|
|
}
|
|
|
|
get tierConfig() {
|
|
const configs = {
|
|
premium: { color: 'text-yellow-400', bgColor: 'bg-yellow-500/10', border: 'border-yellow-500/30', icon: '⭐' },
|
|
standard: { color: 'text-primary-blue', bgColor: 'bg-primary-blue/10', border: 'border-primary-blue/30', icon: '🏆' },
|
|
starter: { color: 'text-gray-400', bgColor: 'bg-gray-500/10', border: 'border-gray-500/30', icon: '🚀' },
|
|
};
|
|
return configs[this.tier];
|
|
}
|
|
|
|
get statusConfig() {
|
|
const configs = {
|
|
active: { color: 'text-performance-green', bg: 'bg-performance-green/10', label: 'Active Season' },
|
|
upcoming: { color: 'text-warning-amber', bg: 'bg-warning-amber/10', label: 'Starting Soon' },
|
|
completed: { color: 'text-gray-400', bg: 'bg-gray-400/10', label: 'Season Ended' },
|
|
};
|
|
return configs[this.seasonStatus];
|
|
}
|
|
} |