refactor page to use services
This commit is contained in:
@@ -11,11 +11,12 @@ export class DriverLeaderboardItemViewModel {
|
||||
podiums: number;
|
||||
isActive: boolean;
|
||||
rank: number;
|
||||
avatarUrl: string;
|
||||
|
||||
position: number;
|
||||
private previousRating?: number;
|
||||
|
||||
constructor(dto: DriverLeaderboardItemDTO, position: number, previousRating?: number) {
|
||||
constructor(dto: DriverLeaderboardItemDTO & { avatarUrl: string }, position: number, previousRating?: number) {
|
||||
this.id = dto.id;
|
||||
this.name = dto.name;
|
||||
this.rating = dto.rating;
|
||||
@@ -26,6 +27,7 @@ export class DriverLeaderboardItemViewModel {
|
||||
this.podiums = dto.podiums;
|
||||
this.isActive = dto.isActive;
|
||||
this.rank = dto.rank;
|
||||
this.avatarUrl = dto.avatarUrl;
|
||||
this.position = position;
|
||||
this.previousRating = previousRating;
|
||||
}
|
||||
|
||||
@@ -1,67 +1,23 @@
|
||||
import { LeagueSummaryDTO } from '../types/generated/LeagueSummaryDTO';
|
||||
|
||||
export class LeagueSummaryViewModel {
|
||||
export interface LeagueSummaryViewModel {
|
||||
id: string;
|
||||
name: string;
|
||||
|
||||
constructor(dto: LeagueSummaryDTO) {
|
||||
this.id = dto.id;
|
||||
this.name = dto.name;
|
||||
}
|
||||
|
||||
// Note: The generated DTO only has id and name
|
||||
// These fields will need to be added when the OpenAPI spec is updated
|
||||
description?: string;
|
||||
logoUrl?: string;
|
||||
coverImage?: string;
|
||||
memberCount: number = 0;
|
||||
maxMembers: number = 0;
|
||||
isPublic: boolean = false;
|
||||
ownerId: string = '';
|
||||
ownerName?: string;
|
||||
scoringType?: string;
|
||||
status?: string;
|
||||
|
||||
/** UI-specific: Formatted capacity display */
|
||||
get formattedCapacity(): string {
|
||||
return `${this.memberCount}/${this.maxMembers}`;
|
||||
}
|
||||
|
||||
/** UI-specific: Capacity bar percentage */
|
||||
get capacityBarPercent(): number {
|
||||
return (this.memberCount / this.maxMembers) * 100;
|
||||
}
|
||||
|
||||
/** UI-specific: Label for join button */
|
||||
get joinButtonLabel(): string {
|
||||
if (this.isFull) return 'Full';
|
||||
return this.isJoinable ? 'Join League' : 'Request to Join';
|
||||
}
|
||||
|
||||
/** UI-specific: Whether the league is full */
|
||||
get isFull(): boolean {
|
||||
return this.memberCount >= this.maxMembers;
|
||||
}
|
||||
|
||||
/** UI-specific: Whether the league is joinable */
|
||||
get isJoinable(): boolean {
|
||||
return this.isPublic && !this.isFull;
|
||||
}
|
||||
|
||||
/** UI-specific: Color for member progress */
|
||||
get memberProgressColor(): string {
|
||||
const percent = this.capacityBarPercent;
|
||||
if (percent < 50) return 'green';
|
||||
if (percent < 80) return 'yellow';
|
||||
return 'red';
|
||||
}
|
||||
|
||||
/** UI-specific: Badge variant for status */
|
||||
get statusBadgeVariant(): string {
|
||||
switch (this.status) {
|
||||
case 'active': return 'success';
|
||||
case 'inactive': return 'secondary';
|
||||
default: return 'default';
|
||||
}
|
||||
}
|
||||
description: string;
|
||||
ownerId: string;
|
||||
createdAt: string;
|
||||
maxDrivers: number;
|
||||
usedDriverSlots: number;
|
||||
maxTeams?: number;
|
||||
usedTeamSlots?: number;
|
||||
structureSummary: string;
|
||||
scoringPatternSummary?: string;
|
||||
timingSummary: string;
|
||||
scoring?: {
|
||||
gameId: string;
|
||||
gameName: string;
|
||||
primaryChampionshipType: 'driver' | 'team' | 'nations' | 'trophy';
|
||||
scoringPresetId: string;
|
||||
scoringPresetName: string;
|
||||
dropPolicySummary: string;
|
||||
scoringPatternSummary: string;
|
||||
};
|
||||
}
|
||||
100
apps/website/lib/view-models/ProfileOverviewViewModel.ts
Normal file
100
apps/website/lib/view-models/ProfileOverviewViewModel.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
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;
|
||||
totalDrivers: number | 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;
|
||||
rating: number | null;
|
||||
consistency: number | null;
|
||||
overallRank: 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;
|
||||
}
|
||||
@@ -13,15 +13,31 @@ export class TeamSummaryViewModel {
|
||||
logoUrl?: string;
|
||||
memberCount: number;
|
||||
rating: number;
|
||||
description?: string;
|
||||
totalWins: number = 0;
|
||||
totalRaces: number = 0;
|
||||
performanceLevel: string = '';
|
||||
isRecruiting: boolean = false;
|
||||
specialization?: string;
|
||||
region?: string;
|
||||
languages: string[] = [];
|
||||
|
||||
private maxMembers = 10; // Assuming max members
|
||||
|
||||
constructor(dto: TeamSummaryDTO) {
|
||||
constructor(dto: TeamSummaryDTO & { description?: string; totalWins?: number; totalRaces?: number; performanceLevel?: string; isRecruiting?: boolean; specialization?: string; region?: string; languages?: string[] }) {
|
||||
this.id = dto.id;
|
||||
this.name = dto.name;
|
||||
if (dto.logoUrl !== undefined) this.logoUrl = dto.logoUrl;
|
||||
this.memberCount = dto.memberCount;
|
||||
this.rating = dto.rating;
|
||||
this.description = dto.description;
|
||||
this.totalWins = dto.totalWins ?? 0;
|
||||
this.totalRaces = dto.totalRaces ?? 0;
|
||||
this.performanceLevel = dto.performanceLevel ?? '';
|
||||
this.isRecruiting = dto.isRecruiting ?? false;
|
||||
this.specialization = dto.specialization;
|
||||
this.region = dto.region;
|
||||
this.languages = dto.languages ?? [];
|
||||
}
|
||||
|
||||
/** UI-specific: Whether team is full */
|
||||
|
||||
Reference in New Issue
Block a user