This commit is contained in:
2025-12-11 00:57:32 +01:00
parent 1303a14493
commit 6a427eab57
112 changed files with 6148 additions and 2272 deletions

View File

@@ -0,0 +1,27 @@
export type AllRacesStatus = 'scheduled' | 'running' | 'completed' | 'cancelled' | 'all';
export interface AllRacesListItemViewModel {
id: string;
track: string;
car: string;
scheduledAt: string;
status: 'scheduled' | 'running' | 'completed' | 'cancelled';
leagueId: string;
leagueName: string;
strengthOfField: number | null;
}
export interface AllRacesFilterOptionsViewModel {
statuses: { value: AllRacesStatus; label: string }[];
leagues: { id: string; name: string }[];
}
export interface AllRacesPageViewModel {
races: AllRacesListItemViewModel[];
filters: AllRacesFilterOptionsViewModel;
}
export interface IAllRacesPagePresenter {
present(viewModel: AllRacesPageViewModel): void;
getViewModel(): AllRacesPageViewModel | null;
}

View File

@@ -0,0 +1,88 @@
export interface DashboardDriverSummaryViewModel {
id: string;
name: string;
country: string;
avatarUrl: string;
rating: number | null;
globalRank: number | null;
totalRaces: number;
wins: number;
podiums: number;
consistency: number | null;
}
export interface DashboardRaceSummaryViewModel {
id: string;
leagueId: string;
leagueName: string;
track: string;
car: string;
scheduledAt: string;
status: 'scheduled' | 'running' | 'completed' | 'cancelled';
isMyLeague: boolean;
}
export interface DashboardRecentResultViewModel {
raceId: string;
raceName: string;
leagueId: string;
leagueName: string;
finishedAt: string;
position: number;
incidents: number;
}
export interface DashboardLeagueStandingSummaryViewModel {
leagueId: string;
leagueName: string;
position: number;
totalDrivers: number;
points: number;
}
export interface DashboardFeedItemSummaryViewModel {
id: string;
type: string;
headline: string;
body?: string;
timestamp: string;
ctaLabel?: string;
ctaHref?: string;
}
export interface DashboardFeedSummaryViewModel {
notificationCount: number;
items: DashboardFeedItemSummaryViewModel[];
}
export interface DashboardFriendSummaryViewModel {
id: string;
name: string;
country: string;
avatarUrl: string;
}
export interface DashboardOverviewViewModel {
currentDriver: DashboardDriverSummaryViewModel | null;
myUpcomingRaces: DashboardRaceSummaryViewModel[];
otherUpcomingRaces: DashboardRaceSummaryViewModel[];
/**
* All upcoming races for the driver, already sorted by scheduledAt ascending.
*/
upcomingRaces: DashboardRaceSummaryViewModel[];
/**
* Count of distinct leagues that are currently "active" for the driver,
* based on upcoming races and league standings.
*/
activeLeaguesCount: number;
nextRace: DashboardRaceSummaryViewModel | null;
recentResults: DashboardRecentResultViewModel[];
leagueStandingsSummaries: DashboardLeagueStandingSummaryViewModel[];
feedSummary: DashboardFeedSummaryViewModel;
friends: DashboardFriendSummaryViewModel[];
}
export interface IDashboardOverviewPresenter {
present(viewModel: DashboardOverviewViewModel): void;
getViewModel(): DashboardOverviewViewModel | null;
}

View File

@@ -1,4 +1,4 @@
import type { GetEntitySponsorshipPricingResultDTO } from '../use-cases/GetEntitySponsorshipPricingQuery';
import type { GetEntitySponsorshipPricingResultDTO } from '../use-cases/GetEntitySponsorshipPricingUseCase';
export interface IEntitySponsorshipPricingPresenter {
present(data: GetEntitySponsorshipPricingResultDTO | null): void;

View File

@@ -0,0 +1,9 @@
export interface ImportRaceResultsSummaryViewModel {
importedCount: number;
standingsRecalculated: boolean;
}
export interface IImportRaceResultsPresenter {
present(viewModel: ImportRaceResultsSummaryViewModel): ImportRaceResultsSummaryViewModel;
getViewModel(): ImportRaceResultsSummaryViewModel | null;
}

View File

@@ -1,4 +1,4 @@
import type { GetPendingSponsorshipRequestsResultDTO } from '../use-cases/GetPendingSponsorshipRequestsQuery';
import type { GetPendingSponsorshipRequestsResultDTO } from '../use-cases/GetPendingSponsorshipRequestsUseCase';
export interface IPendingSponsorshipRequestsPresenter {
present(data: GetPendingSponsorshipRequestsResultDTO): void;

View File

@@ -0,0 +1,101 @@
export interface ProfileOverviewDriverSummaryViewModel {
id: string;
name: string;
country: string;
avatarUrl: string;
iracingId: string | null;
joinedAt: string;
rating: number | null;
globalRank: number | null;
consistency: number | null;
bio: string | null;
}
export interface ProfileOverviewStatsViewModel {
totalRaces: number;
wins: number;
podiums: number;
dnfs: number;
avgFinish: number | null;
bestFinish: number | null;
worstFinish: number | null;
finishRate: number | null;
winRate: number | null;
podiumRate: number | null;
percentile: number | null;
}
export interface ProfileOverviewFinishDistributionViewModel {
totalRaces: number;
wins: number;
podiums: number;
topTen: number;
dnfs: number;
other: number;
}
export interface ProfileOverviewTeamMembershipViewModel {
teamId: string;
teamName: string;
teamTag: string | null;
role: string;
joinedAt: string;
isCurrent: boolean;
}
export interface ProfileOverviewSocialFriendSummaryViewModel {
id: string;
name: string;
country: string;
avatarUrl: string;
}
export interface ProfileOverviewSocialSummaryViewModel {
friendsCount: number;
friends: ProfileOverviewSocialFriendSummaryViewModel[];
}
export type ProfileOverviewSocialPlatform = 'twitter' | 'youtube' | 'twitch' | 'discord';
export type ProfileOverviewAchievementRarity = 'common' | 'rare' | 'epic' | 'legendary';
export interface ProfileOverviewAchievementViewModel {
id: string;
title: string;
description: string;
icon: 'trophy' | 'medal' | 'star' | 'crown' | 'target' | 'zap';
rarity: ProfileOverviewAchievementRarity;
earnedAt: string;
}
export interface ProfileOverviewSocialHandleViewModel {
platform: ProfileOverviewSocialPlatform;
handle: string;
url: string;
}
export interface ProfileOverviewExtendedProfileViewModel {
socialHandles: ProfileOverviewSocialHandleViewModel[];
achievements: ProfileOverviewAchievementViewModel[];
racingStyle: string;
favoriteTrack: string;
favoriteCar: string;
timezone: string;
availableHours: string;
lookingForTeam: boolean;
openToRequests: boolean;
}
export interface ProfileOverviewViewModel {
currentDriver: ProfileOverviewDriverSummaryViewModel | null;
stats: ProfileOverviewStatsViewModel | null;
finishDistribution: ProfileOverviewFinishDistributionViewModel | null;
teamMemberships: ProfileOverviewTeamMembershipViewModel[];
socialSummary: ProfileOverviewSocialSummaryViewModel;
extendedProfile: ProfileOverviewExtendedProfileViewModel | null;
}
export interface IProfileOverviewPresenter {
present(viewModel: ProfileOverviewViewModel): void;
getViewModel(): ProfileOverviewViewModel | null;
}

View File

@@ -0,0 +1,61 @@
import type { SessionType, RaceStatus } from '../../domain/entities/Race';
export interface RaceDetailEntryViewModel {
id: string;
name: string;
country: string;
avatarUrl: string;
rating: number | null;
isCurrentUser: boolean;
}
export interface RaceDetailUserResultViewModel {
position: number;
startPosition: number;
incidents: number;
fastestLap: number;
positionChange: number;
isPodium: boolean;
isClean: boolean;
ratingChange: number | null;
}
export interface RaceDetailRaceViewModel {
id: string;
leagueId: string;
track: string;
car: string;
scheduledAt: string;
sessionType: SessionType;
status: RaceStatus;
strengthOfField: number | null;
registeredCount?: number;
maxParticipants?: number;
}
export interface RaceDetailLeagueViewModel {
id: string;
name: string;
description: string;
settings: {
maxDrivers?: number;
qualifyingFormat?: string;
};
}
export interface RaceDetailViewModel {
race: RaceDetailRaceViewModel | null;
league: RaceDetailLeagueViewModel | null;
entryList: RaceDetailEntryViewModel[];
registration: {
isUserRegistered: boolean;
canRegister: boolean;
};
userResult: RaceDetailUserResultViewModel | null;
error?: string;
}
export interface IRaceDetailPresenter {
present(viewModel: RaceDetailViewModel): RaceDetailViewModel;
getViewModel(): RaceDetailViewModel | null;
}

View File

@@ -0,0 +1,40 @@
import type { RaceStatus } from '../../domain/entities/Race';
import type { Result } from '../../domain/entities/Result';
import type { Driver } from '../../domain/entities/Driver';
import type { PenaltyType } from '../../domain/entities/Penalty';
export interface RaceResultsHeaderViewModel {
id: string;
leagueId: string;
track: string;
scheduledAt: Date;
status: RaceStatus;
}
export interface RaceResultsLeagueViewModel {
id: string;
name: string;
}
export interface RaceResultsPenaltySummaryViewModel {
driverId: string;
type: PenaltyType;
value?: number;
}
export interface RaceResultsDetailViewModel {
race: RaceResultsHeaderViewModel | null;
league: RaceResultsLeagueViewModel | null;
results: Result[];
drivers: Driver[];
penalties: RaceResultsPenaltySummaryViewModel[];
pointsSystem: Record<number, number>;
fastestLapTime?: number;
currentDriverId?: string;
error?: string;
}
export interface IRaceResultsDetailPresenter {
present(viewModel: RaceResultsDetailViewModel): RaceResultsDetailViewModel;
getViewModel(): RaceResultsDetailViewModel | null;
}

View File

@@ -1,4 +1,4 @@
import type { SponsoredLeagueDTO, SponsorDashboardDTO } from '../use-cases/GetSponsorDashboardQuery';
import type { SponsoredLeagueDTO, SponsorDashboardDTO } from '../use-cases/GetSponsorDashboardUseCase';
export interface ISponsorDashboardPresenter {
present(data: SponsorDashboardDTO | null): void;

View File

@@ -1,4 +1,4 @@
import type { SponsorSponsorshipsDTO } from '../use-cases/GetSponsorSponsorshipsQuery';
import type { SponsorSponsorshipsDTO } from '../use-cases/GetSponsorSponsorshipsUseCase';
export interface ISponsorSponsorshipsPresenter {
present(data: SponsorSponsorshipsDTO | null): void;

View File

@@ -19,6 +19,14 @@ export interface TeamLeaderboardItemViewModel {
export interface TeamsLeaderboardViewModel {
teams: TeamLeaderboardItemViewModel[];
recruitingCount: number;
/**
* Teams grouped by their skill level for UI display.
*/
groupsBySkillLevel: Record<SkillLevel, TeamLeaderboardItemViewModel[]>;
/**
* Precomputed top teams ordered for leaderboard preview.
*/
topTeams: TeamLeaderboardItemViewModel[];
}
export interface ITeamsLeaderboardPresenter {