fix issues
This commit is contained in:
@@ -57,11 +57,11 @@ export class DashboardRaceSummaryViewModel {
|
||||
}
|
||||
|
||||
get leagueId(): string {
|
||||
return this.dto.leagueId;
|
||||
return (this.dto as any).leagueId ?? '';
|
||||
}
|
||||
|
||||
get leagueName(): string {
|
||||
return this.dto.leagueName;
|
||||
return (this.dto as any).leagueName ?? '';
|
||||
}
|
||||
|
||||
get track(): string {
|
||||
@@ -166,38 +166,52 @@ export class DashboardOverviewViewModel {
|
||||
|
||||
get currentDriver(): DashboardDriverSummaryViewModel {
|
||||
// DTO uses optional property; enforce a consistent object for the UI
|
||||
return new DashboardDriverSummaryViewModel(this.dto.currentDriver ?? {
|
||||
id: '',
|
||||
name: '',
|
||||
country: '',
|
||||
avatarUrl: '',
|
||||
totalRaces: 0,
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
});
|
||||
return new DashboardDriverSummaryViewModel(
|
||||
(this.dto as any).currentDriver ?? {
|
||||
id: '',
|
||||
name: '',
|
||||
country: '',
|
||||
avatarUrl: '',
|
||||
totalRaces: 0,
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
get nextRace(): DashboardRaceSummaryViewModel | null {
|
||||
return this.dto.nextRace ? new DashboardRaceSummaryViewModel(this.dto.nextRace) : null;
|
||||
const nextRace = (this.dto as any).nextRace;
|
||||
return nextRace ? new DashboardRaceSummaryViewModel(nextRace) : null;
|
||||
}
|
||||
|
||||
get upcomingRaces(): DashboardRaceSummaryViewModel[] {
|
||||
return this.dto.upcomingRaces.map((r) => new DashboardRaceSummaryViewModel(r));
|
||||
const upcomingRaces = (this.dto as any).upcomingRaces ?? [];
|
||||
return upcomingRaces.map((r: any) => new DashboardRaceSummaryViewModel(r));
|
||||
}
|
||||
|
||||
get leagueStandings(): DashboardLeagueStandingSummaryViewModel[] {
|
||||
return this.dto.leagueStandingsSummaries.map((s) => new DashboardLeagueStandingSummaryViewModel(s));
|
||||
const leagueStandings = (this.dto as any).leagueStandingsSummaries ?? (this.dto as any).leagueStandings ?? [];
|
||||
return leagueStandings.map((s: any) => new DashboardLeagueStandingSummaryViewModel(s));
|
||||
}
|
||||
|
||||
get feedItems(): DashboardFeedItemSummaryViewModel[] {
|
||||
return this.dto.feedSummary.items.map((i) => new DashboardFeedItemSummaryViewModel(i));
|
||||
const feedItems = (this.dto as any).feedSummary?.items ?? (this.dto as any).feedItems ?? [];
|
||||
return feedItems.map((i: any) => new DashboardFeedItemSummaryViewModel(i));
|
||||
}
|
||||
|
||||
get friends(): DashboardFriendSummaryViewModel[] {
|
||||
return this.dto.friends.map((f) => new DashboardFriendSummaryViewModel(f));
|
||||
const friends = (this.dto as any).friends ?? [];
|
||||
return friends.map((f: any) => new DashboardFriendSummaryViewModel(f));
|
||||
}
|
||||
|
||||
get activeLeaguesCount(): number {
|
||||
return this.dto.activeLeaguesCount;
|
||||
return (this.dto as any).activeLeaguesCount ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
DashboardDriverSummaryViewModel as DriverViewModel,
|
||||
DashboardRaceSummaryViewModel as RaceViewModel,
|
||||
DashboardLeagueStandingSummaryViewModel as LeagueStandingViewModel,
|
||||
DashboardFriendSummaryViewModel as FriendViewModel,
|
||||
};
|
||||
|
||||
@@ -108,30 +108,40 @@ export class LeagueDetailPageViewModel {
|
||||
this.ownerId = league.ownerId;
|
||||
this.createdAt = league.createdAt;
|
||||
this.settings = {
|
||||
maxDrivers: league.settings?.maxDrivers,
|
||||
maxDrivers: league.settings?.maxDrivers ?? (league as any).maxDrivers,
|
||||
};
|
||||
this.socialLinks = {
|
||||
discordUrl: league.discordUrl,
|
||||
youtubeUrl: league.youtubeUrl,
|
||||
websiteUrl: league.websiteUrl,
|
||||
discordUrl: league.discordUrl ?? (league as any).socialLinks?.discordUrl,
|
||||
youtubeUrl: league.youtubeUrl ?? (league as any).socialLinks?.youtubeUrl,
|
||||
websiteUrl: league.websiteUrl ?? (league as any).socialLinks?.websiteUrl,
|
||||
};
|
||||
|
||||
this.owner = owner;
|
||||
this.scoringConfig = scoringConfig;
|
||||
this.drivers = drivers;
|
||||
this.memberships = memberships.members.map(m => ({
|
||||
|
||||
const membershipDtos = ((memberships as any).members ?? (memberships as any).memberships ?? []) as Array<{
|
||||
driverId: string;
|
||||
role: string;
|
||||
status?: 'active' | 'inactive';
|
||||
joinedAt: string;
|
||||
}>;
|
||||
|
||||
this.memberships = membershipDtos.map((m) => ({
|
||||
driverId: m.driverId,
|
||||
role: m.role as 'owner' | 'admin' | 'steward' | 'member',
|
||||
status: 'active',
|
||||
status: m.status ?? 'active',
|
||||
joinedAt: m.joinedAt,
|
||||
}));
|
||||
|
||||
this.allRaces = allRaces;
|
||||
this.runningRaces = allRaces.filter(r => r.status === 'running');
|
||||
|
||||
const leagueStatsAny = leagueStats as any;
|
||||
|
||||
// Calculate SOF from available data
|
||||
this.averageSOF = leagueStats.averageRating ?? null;
|
||||
this.completedRacesCount = leagueStats.totalRaces ?? 0;
|
||||
this.averageSOF = leagueStatsAny.averageSOF ?? leagueStats.averageRating ?? null;
|
||||
this.completedRacesCount = leagueStatsAny.completedRaces ?? leagueStats.totalRaces ?? 0;
|
||||
|
||||
this.sponsors = sponsors;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { DriverViewModel } from './DriverViewModel';
|
||||
export class LeagueMemberViewModel {
|
||||
driverId: string;
|
||||
|
||||
private currentUserId: string;
|
||||
currentUserId: string;
|
||||
|
||||
constructor(dto: LeagueMemberDTO, currentUserId: string) {
|
||||
this.driverId = dto.driverId;
|
||||
|
||||
@@ -9,8 +9,9 @@ import type { LeagueMemberDTO } from '../types/generated/LeagueMemberDTO';
|
||||
export class LeagueMembershipsViewModel {
|
||||
memberships: LeagueMemberViewModel[];
|
||||
|
||||
constructor(dto: { members: LeagueMemberDTO[] }, currentUserId: string) {
|
||||
this.memberships = dto.members.map(membership => new LeagueMemberViewModel(membership, currentUserId));
|
||||
constructor(dto: { members?: LeagueMemberDTO[]; memberships?: LeagueMemberDTO[] }, currentUserId: string) {
|
||||
const memberships = dto.members ?? dto.memberships ?? [];
|
||||
this.memberships = memberships.map((membership) => new LeagueMemberViewModel(membership, currentUserId));
|
||||
}
|
||||
|
||||
/** UI-specific: Number of members */
|
||||
|
||||
@@ -26,7 +26,9 @@ export class MediaViewModel {
|
||||
get formattedSize(): string {
|
||||
if (!this.size) return 'Unknown';
|
||||
const kb = this.size / 1024;
|
||||
|
||||
if (kb < 1024) return `${kb.toFixed(2)} KB`;
|
||||
|
||||
const mb = kb / 1024;
|
||||
return `${mb.toFixed(2)} MB`;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export class RaceDetailViewModel {
|
||||
|
||||
/** UI-specific: Whether user is registered */
|
||||
get isRegistered(): boolean {
|
||||
return this.registration.isUserRegistered;
|
||||
return (this.registration as any).isUserRegistered ?? (this.registration as any).isRegistered ?? false;
|
||||
}
|
||||
|
||||
/** UI-specific: Whether user can register */
|
||||
|
||||
@@ -40,6 +40,10 @@ export class RaceListItemViewModel {
|
||||
this.isPast = dto.isPast;
|
||||
}
|
||||
|
||||
get title(): string {
|
||||
return `${this.track} - ${this.car}`;
|
||||
}
|
||||
|
||||
/** UI-specific: Formatted scheduled time */
|
||||
get formattedScheduledTime(): string {
|
||||
return new Date(this.scheduledAt).toLocaleString();
|
||||
|
||||
@@ -16,12 +16,26 @@ export class RacesPageViewModel {
|
||||
|
||||
constructor(dto: RacesPageDTO) {
|
||||
this.races = dto.races.map((r) => {
|
||||
const status = (r as any).status as string | undefined;
|
||||
|
||||
const isUpcoming =
|
||||
(r as any).isUpcoming ??
|
||||
(status === 'upcoming' || status === 'scheduled');
|
||||
|
||||
const isLive =
|
||||
(r as any).isLive ??
|
||||
(status === 'live' || status === 'running');
|
||||
|
||||
const isPast =
|
||||
(r as any).isPast ??
|
||||
(status === 'completed' || status === 'finished' || status === 'cancelled');
|
||||
|
||||
const normalized: RaceListItemDTO = {
|
||||
...r,
|
||||
...(r as any),
|
||||
strengthOfField: (r as any).strengthOfField ?? null,
|
||||
isUpcoming: r.isUpcoming,
|
||||
isLive: r.isLive,
|
||||
isPast: r.isPast,
|
||||
isUpcoming: Boolean(isUpcoming),
|
||||
isLive: Boolean(isLive),
|
||||
isPast: Boolean(isPast),
|
||||
};
|
||||
|
||||
return new RaceListItemViewModel(normalized);
|
||||
|
||||
@@ -11,11 +11,33 @@ export class RequestAvatarGenerationViewModel {
|
||||
avatarUrls?: string[];
|
||||
errorMessage?: string;
|
||||
|
||||
constructor(dto: RequestAvatarGenerationOutputDTO) {
|
||||
constructor(
|
||||
dto:
|
||||
| RequestAvatarGenerationOutputDTO
|
||||
| {
|
||||
success: boolean;
|
||||
requestId?: string;
|
||||
avatarUrls?: string[];
|
||||
errorMessage?: string;
|
||||
avatarUrl?: string;
|
||||
error?: string;
|
||||
},
|
||||
) {
|
||||
this.success = dto.success;
|
||||
if (dto.requestId !== undefined) this.requestId = dto.requestId;
|
||||
if (dto.avatarUrls !== undefined) this.avatarUrls = dto.avatarUrls;
|
||||
if (dto.errorMessage !== undefined) this.errorMessage = dto.errorMessage;
|
||||
|
||||
if ('requestId' in dto && dto.requestId !== undefined) this.requestId = dto.requestId;
|
||||
|
||||
if ('avatarUrls' in dto && dto.avatarUrls !== undefined) {
|
||||
this.avatarUrls = dto.avatarUrls;
|
||||
} else if ('avatarUrl' in dto && dto.avatarUrl !== undefined) {
|
||||
this.avatarUrls = [dto.avatarUrl];
|
||||
}
|
||||
|
||||
if ('errorMessage' in dto && dto.errorMessage !== undefined) {
|
||||
this.errorMessage = dto.errorMessage;
|
||||
} else if ('error' in dto && dto.error !== undefined) {
|
||||
this.errorMessage = dto.error;
|
||||
}
|
||||
}
|
||||
|
||||
/** UI-specific: Whether generation was successful */
|
||||
|
||||
@@ -9,8 +9,8 @@ interface SponsorDTO {
|
||||
export class SponsorViewModel {
|
||||
id: string;
|
||||
name: string;
|
||||
logoUrl?: string;
|
||||
websiteUrl?: string;
|
||||
declare logoUrl?: string;
|
||||
declare websiteUrl?: string;
|
||||
|
||||
constructor(dto: SponsorDTO) {
|
||||
this.id = dto.id;
|
||||
|
||||
@@ -23,10 +23,16 @@ export class TeamDetailsViewModel {
|
||||
this.ownerId = dto.team.ownerId;
|
||||
this.leagues = dto.team.leagues;
|
||||
this.createdAt = dto.team.createdAt;
|
||||
// These properties don't exist in the current TeamDTO but may be added later
|
||||
this.specialization = undefined;
|
||||
this.region = undefined;
|
||||
this.languages = undefined;
|
||||
|
||||
const teamExtras = dto.team as typeof dto.team & {
|
||||
specialization?: string;
|
||||
region?: string;
|
||||
languages?: string[];
|
||||
};
|
||||
|
||||
this.specialization = teamExtras.specialization ?? undefined;
|
||||
this.region = teamExtras.region ?? undefined;
|
||||
this.languages = teamExtras.languages ?? undefined;
|
||||
this.membership = dto.membership ? {
|
||||
role: dto.membership.role,
|
||||
joinedAt: dto.membership.joinedAt,
|
||||
|
||||
95
apps/website/lib/view-models/index.ts
Normal file
95
apps/website/lib/view-models/index.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
export * from './ActivityItemViewModel';
|
||||
export * from './AnalyticsDashboardViewModel';
|
||||
export * from './AnalyticsMetricsViewModel';
|
||||
export * from './AvailableLeaguesViewModel';
|
||||
export * from './AvatarGenerationViewModel';
|
||||
export * from './AvatarViewModel';
|
||||
export * from './BillingViewModel';
|
||||
export * from './CompleteOnboardingViewModel';
|
||||
export * from './CreateLeagueViewModel';
|
||||
export * from './CreateTeamViewModel';
|
||||
export {
|
||||
DashboardOverviewViewModel,
|
||||
DashboardDriverSummaryViewModel,
|
||||
DashboardRaceSummaryViewModel,
|
||||
DashboardLeagueStandingSummaryViewModel,
|
||||
DashboardFeedItemSummaryViewModel,
|
||||
DashboardFriendSummaryViewModel,
|
||||
} from './DashboardOverviewViewModel';
|
||||
export * from './DeleteMediaViewModel';
|
||||
export * from './DriverLeaderboardItemViewModel';
|
||||
export * from './DriverLeaderboardViewModel';
|
||||
export * from './DriverProfileViewModel';
|
||||
export * from './DriverRegistrationStatusViewModel';
|
||||
export * from './DriverSummaryViewModel';
|
||||
export * from './DriverTeamViewModel';
|
||||
export * from './DriverViewModel';
|
||||
export * from './EmailSignupViewModel';
|
||||
export * from './HomeDiscoveryViewModel';
|
||||
export * from './ImportRaceResultsSummaryViewModel';
|
||||
export * from './LeagueAdminViewModel';
|
||||
export * from './LeagueCardViewModel';
|
||||
export * from './LeagueDetailPageViewModel';
|
||||
export { LeagueDetailViewModel, LeagueViewModel } from './LeagueDetailViewModel';
|
||||
export * from './LeagueJoinRequestViewModel';
|
||||
export * from './LeagueMembershipsViewModel';
|
||||
export * from './LeagueMemberViewModel';
|
||||
export * from './LeaguePageDetailViewModel';
|
||||
export * from './LeagueScheduleViewModel';
|
||||
export * from './LeagueScoringChampionshipViewModel';
|
||||
export * from './LeagueScoringConfigViewModel';
|
||||
export * from './LeagueScoringPresetsViewModel';
|
||||
export * from './LeagueScoringPresetViewModel';
|
||||
export * from './LeagueSettingsViewModel';
|
||||
export * from './LeagueStandingsViewModel';
|
||||
export * from './LeagueStatsViewModel';
|
||||
export * from './LeagueStewardingViewModel';
|
||||
export * from './LeagueSummaryViewModel';
|
||||
export * from './LeagueWalletViewModel';
|
||||
export * from './MediaViewModel';
|
||||
export * from './MembershipFeeViewModel';
|
||||
export * from './PaymentViewModel';
|
||||
export * from './PrizeViewModel';
|
||||
export * from './ProfileOverviewViewModel';
|
||||
export * from './ProtestDriverViewModel';
|
||||
export * from './ProtestViewModel';
|
||||
export * from './RaceDetailEntryViewModel';
|
||||
export * from './RaceDetailUserResultViewModel';
|
||||
export * from './RaceDetailViewModel';
|
||||
export * from './RaceListItemViewModel';
|
||||
export * from './RaceResultsDetailViewModel';
|
||||
export * from './RaceResultViewModel';
|
||||
export * from './RacesPageViewModel';
|
||||
export * from './RaceStatsViewModel';
|
||||
export * from './RaceStewardingViewModel';
|
||||
export * from './RaceViewModel';
|
||||
export * from './RaceWithSOFViewModel';
|
||||
export * from './RecordEngagementInputViewModel';
|
||||
export * from './RecordEngagementOutputViewModel';
|
||||
export * from './RecordPageViewInputViewModel';
|
||||
export * from './RecordPageViewOutputViewModel';
|
||||
export * from './RemoveMemberViewModel';
|
||||
export * from './RenewalAlertViewModel';
|
||||
export * from './RequestAvatarGenerationViewModel';
|
||||
export * from './SessionViewModel';
|
||||
export * from './SponsorDashboardViewModel';
|
||||
export * from './SponsorSettingsViewModel';
|
||||
export * from './SponsorshipDetailViewModel';
|
||||
export * from './SponsorshipPricingViewModel';
|
||||
export * from './SponsorshipRequestViewModel';
|
||||
export * from './SponsorshipViewModel';
|
||||
export * from './SponsorSponsorshipsViewModel';
|
||||
export * from './SponsorViewModel';
|
||||
export * from './StandingEntryViewModel';
|
||||
export * from './TeamCardViewModel';
|
||||
export * from './TeamDetailsViewModel';
|
||||
export * from './TeamJoinRequestViewModel';
|
||||
export * from './TeamMemberViewModel';
|
||||
export * from './TeamSummaryViewModel';
|
||||
export * from './UpcomingRaceCardViewModel';
|
||||
export * from './UpdateAvatarViewModel';
|
||||
export * from './UpdateTeamViewModel';
|
||||
export * from './UploadMediaViewModel';
|
||||
export * from './UserProfileViewModel';
|
||||
export * from './WalletTransactionViewModel';
|
||||
export * from './WalletViewModel';
|
||||
Reference in New Issue
Block a user