docs
This commit is contained in:
@@ -1,217 +1,198 @@
|
||||
import type { DashboardOverviewDTO } from '@/lib/types/generated/DashboardOverviewDTO';
|
||||
import type { DashboardDriverSummaryDTO } from '@/lib/types/generated/DashboardDriverSummaryDTO';
|
||||
import type { DashboardRaceSummaryDTO } from '@/lib/types/generated/DashboardRaceSummaryDTO';
|
||||
import type { DashboardLeagueStandingSummaryDTO } from '@/lib/types/generated/DashboardLeagueStandingSummaryDTO';
|
||||
import type { DashboardFeedItemSummaryDTO } from '@/lib/types/generated/DashboardFeedItemSummaryDTO';
|
||||
import type { DashboardFriendSummaryDTO } from '@/lib/types/generated/DashboardFriendSummaryDTO';
|
||||
|
||||
export class DashboardDriverSummaryViewModel {
|
||||
constructor(private readonly dto: DashboardDriverSummaryDTO) {}
|
||||
|
||||
get id(): string {
|
||||
return this.dto.id;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this.dto.name;
|
||||
}
|
||||
|
||||
get avatarUrl(): string {
|
||||
return this.dto.avatarUrl || '';
|
||||
}
|
||||
|
||||
get country(): string {
|
||||
return this.dto.country;
|
||||
}
|
||||
|
||||
get totalRaces(): number {
|
||||
return this.dto.totalRaces;
|
||||
}
|
||||
|
||||
get wins(): number {
|
||||
return this.dto.wins;
|
||||
}
|
||||
|
||||
get podiums(): number {
|
||||
return this.dto.podiums;
|
||||
}
|
||||
|
||||
get rating(): number {
|
||||
return this.dto.rating ?? 0;
|
||||
}
|
||||
|
||||
get globalRank(): number {
|
||||
return this.dto.globalRank ?? 0;
|
||||
}
|
||||
|
||||
get consistency(): number {
|
||||
return this.dto.consistency ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class DashboardRaceSummaryViewModel {
|
||||
constructor(private readonly dto: DashboardRaceSummaryDTO) {}
|
||||
|
||||
get id(): string {
|
||||
return this.dto.id;
|
||||
}
|
||||
|
||||
get leagueId(): string {
|
||||
return (this.dto as any).leagueId ?? '';
|
||||
}
|
||||
|
||||
get leagueName(): string {
|
||||
return (this.dto as any).leagueName ?? '';
|
||||
}
|
||||
|
||||
get track(): string {
|
||||
return this.dto.track;
|
||||
}
|
||||
|
||||
get car(): string {
|
||||
return this.dto.car;
|
||||
}
|
||||
|
||||
get scheduledAt(): Date {
|
||||
return new Date(this.dto.scheduledAt);
|
||||
}
|
||||
|
||||
get status(): string {
|
||||
return this.dto.status;
|
||||
}
|
||||
|
||||
get isMyLeague(): boolean {
|
||||
return this.dto.isMyLeague;
|
||||
}
|
||||
}
|
||||
|
||||
export class DashboardLeagueStandingSummaryViewModel {
|
||||
constructor(private readonly dto: DashboardLeagueStandingSummaryDTO) {}
|
||||
|
||||
get leagueId(): string {
|
||||
return this.dto.leagueId;
|
||||
}
|
||||
|
||||
get leagueName(): string {
|
||||
return this.dto.leagueName;
|
||||
}
|
||||
|
||||
get position(): number {
|
||||
return this.dto.position;
|
||||
}
|
||||
|
||||
get points(): number {
|
||||
return this.dto.points;
|
||||
}
|
||||
|
||||
get totalDrivers(): number {
|
||||
return this.dto.totalDrivers;
|
||||
}
|
||||
}
|
||||
|
||||
export class DashboardFeedItemSummaryViewModel {
|
||||
constructor(private readonly dto: DashboardFeedItemSummaryDTO) {}
|
||||
|
||||
get id(): string {
|
||||
return this.dto.id;
|
||||
}
|
||||
|
||||
get type(): string {
|
||||
return this.dto.type;
|
||||
}
|
||||
|
||||
get headline(): string {
|
||||
return this.dto.headline;
|
||||
}
|
||||
|
||||
get body(): string | undefined {
|
||||
return this.dto.body;
|
||||
}
|
||||
|
||||
get timestamp(): Date {
|
||||
return new Date(this.dto.timestamp);
|
||||
}
|
||||
|
||||
get ctaHref(): string | undefined {
|
||||
return this.dto.ctaHref;
|
||||
}
|
||||
|
||||
get ctaLabel(): string | undefined {
|
||||
return this.dto.ctaLabel;
|
||||
}
|
||||
}
|
||||
|
||||
export class DashboardFriendSummaryViewModel {
|
||||
constructor(private readonly dto: DashboardFriendSummaryDTO) {}
|
||||
|
||||
get id(): string {
|
||||
return this.dto.id;
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return this.dto.name;
|
||||
}
|
||||
|
||||
get avatarUrl(): string {
|
||||
return this.dto.avatarUrl || '';
|
||||
}
|
||||
|
||||
get country(): string {
|
||||
return this.dto.country;
|
||||
}
|
||||
}
|
||||
import type { DashboardOverviewViewModelData } from './DashboardOverviewViewModelData';
|
||||
import {
|
||||
dashboardStatDisplay,
|
||||
formatDashboardDate,
|
||||
formatRating,
|
||||
formatRank,
|
||||
formatConsistency,
|
||||
formatRaceCount,
|
||||
formatFriendCount,
|
||||
formatLeaguePosition,
|
||||
formatPoints,
|
||||
formatTotalDrivers,
|
||||
} from '@/lib/display-objects/DashboardDisplay';
|
||||
|
||||
/**
|
||||
* Dashboard Overview ViewModel
|
||||
*
|
||||
* Clean class that accepts DTO only and exposes derived values.
|
||||
* This is client-only and instantiated after hydration.
|
||||
*/
|
||||
export class DashboardOverviewViewModel {
|
||||
constructor(private readonly dto: DashboardOverviewDTO) {}
|
||||
constructor(private readonly dto: DashboardOverviewViewModelData) {}
|
||||
|
||||
get currentDriver(): DashboardDriverSummaryViewModel {
|
||||
// DTO uses optional property; enforce a consistent object for the UI
|
||||
return new DashboardDriverSummaryViewModel(
|
||||
(this.dto as any).currentDriver ?? {
|
||||
id: '',
|
||||
name: '',
|
||||
country: '',
|
||||
avatarUrl: '',
|
||||
totalRaces: 0,
|
||||
wins: 0,
|
||||
podiums: 0,
|
||||
},
|
||||
);
|
||||
// Current Driver - Derived Values
|
||||
get currentDriverName(): string {
|
||||
return this.dto.currentDriver?.name || '';
|
||||
}
|
||||
|
||||
get nextRace(): DashboardRaceSummaryViewModel | null {
|
||||
const nextRace = (this.dto as any).nextRace;
|
||||
return nextRace ? new DashboardRaceSummaryViewModel(nextRace) : null;
|
||||
get currentDriverAvatarUrl(): string {
|
||||
return this.dto.currentDriver?.avatarUrl || '';
|
||||
}
|
||||
|
||||
get upcomingRaces(): DashboardRaceSummaryViewModel[] {
|
||||
const upcomingRaces = (this.dto as any).upcomingRaces ?? [];
|
||||
return upcomingRaces.map((r: any) => new DashboardRaceSummaryViewModel(r));
|
||||
get currentDriverCountry(): string {
|
||||
return this.dto.currentDriver?.country || '';
|
||||
}
|
||||
|
||||
get leagueStandings(): DashboardLeagueStandingSummaryViewModel[] {
|
||||
const leagueStandings = (this.dto as any).leagueStandingsSummaries ?? (this.dto as any).leagueStandings ?? [];
|
||||
return leagueStandings.map((s: any) => new DashboardLeagueStandingSummaryViewModel(s));
|
||||
get currentDriverRating(): string {
|
||||
return this.dto.currentDriver ? formatRating(this.dto.currentDriver.rating) : '0.0';
|
||||
}
|
||||
|
||||
get feedItems(): DashboardFeedItemSummaryViewModel[] {
|
||||
const feedItems = (this.dto as any).feedSummary?.items ?? (this.dto as any).feedItems ?? [];
|
||||
return feedItems.map((i: any) => new DashboardFeedItemSummaryViewModel(i));
|
||||
get currentDriverRank(): string {
|
||||
return this.dto.currentDriver ? formatRank(this.dto.currentDriver.globalRank) : '0';
|
||||
}
|
||||
|
||||
get friends(): DashboardFriendSummaryViewModel[] {
|
||||
const friends = (this.dto as any).friends ?? [];
|
||||
return friends.map((f: any) => new DashboardFriendSummaryViewModel(f));
|
||||
get currentDriverTotalRaces(): string {
|
||||
return this.dto.currentDriver ? formatRaceCount(this.dto.currentDriver.totalRaces) : '0';
|
||||
}
|
||||
|
||||
get activeLeaguesCount(): number {
|
||||
return (this.dto as any).activeLeaguesCount ?? 0;
|
||||
get currentDriverWins(): string {
|
||||
return this.dto.currentDriver ? formatRaceCount(this.dto.currentDriver.wins) : '0';
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
DashboardDriverSummaryViewModel as DriverViewModel,
|
||||
DashboardRaceSummaryViewModel as RaceViewModel,
|
||||
DashboardLeagueStandingSummaryViewModel as LeagueStandingViewModel,
|
||||
DashboardFriendSummaryViewModel as FriendViewModel,
|
||||
};
|
||||
get currentDriverPodiums(): string {
|
||||
return this.dto.currentDriver ? formatRaceCount(this.dto.currentDriver.podiums) : '0';
|
||||
}
|
||||
|
||||
get currentDriverConsistency(): string {
|
||||
return this.dto.currentDriver ? formatConsistency(this.dto.currentDriver.consistency) : '0%';
|
||||
}
|
||||
|
||||
// Next Race - Derived Values
|
||||
get nextRace(): {
|
||||
id: string;
|
||||
track: string;
|
||||
car: string;
|
||||
scheduledAt: string;
|
||||
status: string;
|
||||
isMyLeague: boolean;
|
||||
formattedDate: string;
|
||||
formattedTime: string;
|
||||
timeUntil: string;
|
||||
} | null {
|
||||
if (!this.dto.nextRace) return null;
|
||||
|
||||
const dateInfo = formatDashboardDate(new Date(this.dto.nextRace.scheduledAt));
|
||||
|
||||
return {
|
||||
id: this.dto.nextRace.id,
|
||||
track: this.dto.nextRace.track,
|
||||
car: this.dto.nextRace.car,
|
||||
scheduledAt: this.dto.nextRace.scheduledAt,
|
||||
status: this.dto.nextRace.status,
|
||||
isMyLeague: this.dto.nextRace.isMyLeague,
|
||||
formattedDate: dateInfo.date,
|
||||
formattedTime: dateInfo.time,
|
||||
timeUntil: dateInfo.relative,
|
||||
};
|
||||
}
|
||||
|
||||
// Upcoming Races - Derived Values
|
||||
get upcomingRaces(): Array<{
|
||||
id: string;
|
||||
track: string;
|
||||
car: string;
|
||||
scheduledAt: string;
|
||||
status: string;
|
||||
isMyLeague: boolean;
|
||||
formattedDate: string;
|
||||
formattedTime: string;
|
||||
timeUntil: string;
|
||||
}> {
|
||||
return this.dto.upcomingRaces.map((race) => {
|
||||
const dateInfo = formatDashboardDate(new Date(race.scheduledAt));
|
||||
return {
|
||||
id: race.id,
|
||||
track: race.track,
|
||||
car: race.car,
|
||||
scheduledAt: race.scheduledAt,
|
||||
status: race.status,
|
||||
isMyLeague: race.isMyLeague,
|
||||
formattedDate: dateInfo.date,
|
||||
formattedTime: dateInfo.time,
|
||||
timeUntil: dateInfo.relative,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// League Standings - Derived Values
|
||||
get leagueStandings(): Array<{
|
||||
leagueId: string;
|
||||
leagueName: string;
|
||||
position: string;
|
||||
points: string;
|
||||
totalDrivers: string;
|
||||
}> {
|
||||
return this.dto.leagueStandingsSummaries.map((standing) => ({
|
||||
leagueId: standing.leagueId,
|
||||
leagueName: standing.leagueName,
|
||||
position: formatLeaguePosition(standing.position),
|
||||
points: formatPoints(standing.points),
|
||||
totalDrivers: formatTotalDrivers(standing.totalDrivers),
|
||||
}));
|
||||
}
|
||||
|
||||
// Feed Items - Derived Values
|
||||
get feedItems(): Array<{
|
||||
id: string;
|
||||
type: string;
|
||||
headline: string;
|
||||
body?: string;
|
||||
timestamp: string;
|
||||
ctaHref?: string;
|
||||
ctaLabel?: string;
|
||||
formattedTime: string;
|
||||
}> {
|
||||
return this.dto.feedSummary.items.map((item) => ({
|
||||
id: item.id,
|
||||
type: item.type,
|
||||
headline: item.headline,
|
||||
body: item.body,
|
||||
timestamp: item.timestamp,
|
||||
ctaHref: item.ctaHref,
|
||||
ctaLabel: item.ctaLabel,
|
||||
formattedTime: formatDashboardDate(new Date(item.timestamp)).relative,
|
||||
}));
|
||||
}
|
||||
|
||||
// Friends - Derived Values
|
||||
get friends(): Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
avatarUrl: string;
|
||||
country: string;
|
||||
}> {
|
||||
// No additional formatting needed for friends
|
||||
return this.dto.friends;
|
||||
}
|
||||
|
||||
// Active Leagues Count
|
||||
get activeLeaguesCount(): string {
|
||||
return formatRaceCount(this.dto.activeLeaguesCount);
|
||||
}
|
||||
|
||||
// Convenience getters for display
|
||||
get hasNextRace(): boolean {
|
||||
return this.dto.nextRace !== undefined;
|
||||
}
|
||||
|
||||
get hasUpcomingRaces(): boolean {
|
||||
return this.dto.upcomingRaces.length > 0;
|
||||
}
|
||||
|
||||
get hasLeagueStandings(): boolean {
|
||||
return this.dto.leagueStandingsSummaries.length > 0;
|
||||
}
|
||||
|
||||
get hasFeedItems(): boolean {
|
||||
return this.dto.feedSummary.items.length > 0;
|
||||
}
|
||||
|
||||
get hasFriends(): boolean {
|
||||
return this.dto.friends.length > 0;
|
||||
}
|
||||
|
||||
get friendCount(): string {
|
||||
return formatFriendCount(this.dto.friends.length);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user