81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
import { RaceDetailLeagueDTO } from '../types/generated/RaceDetailLeagueDTO';
|
|
import { RaceDetailRaceDTO } from '../types/generated/RaceDetailRaceDTO';
|
|
import { RaceDetailRegistrationDTO } from '../types/generated/RaceDetailRegistrationDTO';
|
|
import { RaceDetailUserResultDTO } from '../types/generated/RaceDetailUserResultDTO';
|
|
import { RaceDetailEntryDTO } from '../types/generated/RaceDetailEntryDTO';
|
|
import { RaceDetailEntryViewModel } from './RaceDetailEntryViewModel';
|
|
import { RaceDetailUserResultViewModel } from './RaceDetailUserResultViewModel';
|
|
|
|
export class RaceDetailViewModel {
|
|
race: RaceDetailRaceDTO | null;
|
|
league: RaceDetailLeagueDTO | null;
|
|
entryList: RaceDetailEntryViewModel[];
|
|
registration: RaceDetailRegistrationDTO;
|
|
userResult: RaceDetailUserResultViewModel | null;
|
|
error?: string;
|
|
|
|
constructor(dto: {
|
|
race: RaceDetailRaceDTO | null;
|
|
league: RaceDetailLeagueDTO | null;
|
|
entryList: RaceDetailEntryDTO[];
|
|
registration: RaceDetailRegistrationDTO;
|
|
userResult: RaceDetailUserResultDTO | null;
|
|
error?: string;
|
|
}, currentDriverId: string) {
|
|
this.race = dto.race;
|
|
this.league = dto.league;
|
|
this.entryList = dto.entryList.map(entry => new RaceDetailEntryViewModel(entry, currentDriverId));
|
|
this.registration = dto.registration;
|
|
this.userResult = dto.userResult ? new RaceDetailUserResultViewModel(dto.userResult) : null;
|
|
this.error = dto.error;
|
|
}
|
|
|
|
/** UI-specific: Whether user is registered */
|
|
get isRegistered(): boolean {
|
|
return this.registration.isUserRegistered;
|
|
}
|
|
|
|
/** UI-specific: Whether user can register */
|
|
get canRegister(): boolean {
|
|
return this.registration.canRegister;
|
|
}
|
|
|
|
/** UI-specific: Race status display */
|
|
get raceStatusDisplay(): string {
|
|
if (!this.race) return 'Unknown';
|
|
switch (this.race.status) {
|
|
case 'upcoming': return 'Upcoming';
|
|
case 'live': return 'Live';
|
|
case 'finished': return 'Finished';
|
|
default: return this.race.status;
|
|
}
|
|
}
|
|
|
|
/** UI-specific: Formatted scheduled time */
|
|
get formattedScheduledTime(): string {
|
|
return this.race ? new Date(this.race.scheduledAt).toLocaleString() : '';
|
|
}
|
|
|
|
/** UI-specific: Entry list count */
|
|
get entryCount(): number {
|
|
return this.entryList.length;
|
|
}
|
|
|
|
/** UI-specific: Whether race has results */
|
|
get hasResults(): boolean {
|
|
return this.userResult !== null;
|
|
}
|
|
|
|
/** UI-specific: Registration status message */
|
|
get registrationStatusMessage(): string {
|
|
if (this.isRegistered) return 'You are registered for this race';
|
|
if (this.canRegister) return 'You can register for this race';
|
|
return 'Registration not available';
|
|
}
|
|
|
|
/** UI-specific: Whether race can be re-opened */
|
|
get canReopenRace(): boolean {
|
|
if (!this.race) return false;
|
|
return this.race.status === 'completed' || this.race.status === 'cancelled';
|
|
}
|
|
} |