services refactor

This commit is contained in:
2025-12-17 22:17:02 +01:00
parent 26f7a2b6aa
commit 055a7f67b5
93 changed files with 7434 additions and 659 deletions

View File

@@ -0,0 +1,10 @@
/**
* Avatar View Model
*
* Represents avatar information for the UI layer
*/
export interface AvatarViewModel {
driverId: string;
avatarUrl?: string;
hasAvatar: boolean;
}

View File

@@ -0,0 +1,8 @@
/**
* Complete onboarding view model
* UI representation of onboarding completion result
*/
export interface CompleteOnboardingViewModel {
driverId: string;
success: boolean;
}

View File

@@ -0,0 +1,9 @@
/**
* Delete Media View Model
*
* Represents the result of a media deletion operation
*/
export interface DeleteMediaViewModel {
success: boolean;
error?: string;
}

View File

@@ -0,0 +1,11 @@
/**
* Driver view model
* UI representation of a driver
*/
export interface DriverViewModel {
id: string;
name: string;
avatarUrl?: string;
iracingId?: string;
rating?: number;
}

View File

@@ -0,0 +1,13 @@
/**
* Media View Model
*
* Represents media information for the UI layer
*/
export interface MediaViewModel {
id: string;
url: string;
type: 'image' | 'video' | 'document';
category?: 'avatar' | 'team-logo' | 'league-cover' | 'race-result';
uploadedAt: Date;
size?: number;
}

View File

@@ -0,0 +1,10 @@
/**
* Request Avatar Generation View Model
*
* Represents the result of an avatar generation request
*/
export interface RequestAvatarGenerationViewModel {
success: boolean;
avatarUrl?: string;
error?: string;
}

View File

@@ -0,0 +1,41 @@
import type { SponsorDashboardDto } from '../dtos';
/**
* Sponsor Dashboard View Model
*
* View model for sponsor dashboard data with UI-specific transformations.
*/
export class SponsorDashboardViewModel implements SponsorDashboardDto {
sponsorId: string;
sponsorName: string;
totalSponsorships: number;
activeSponsorships: number;
totalInvestment: number;
constructor(dto: SponsorDashboardDto) {
Object.assign(this, dto);
}
/** UI-specific: Formatted total investment */
get formattedTotalInvestment(): string {
return `$${this.totalInvestment.toLocaleString()}`;
}
/** UI-specific: Active percentage */
get activePercentage(): number {
if (this.totalSponsorships === 0) return 0;
return Math.round((this.activeSponsorships / this.totalSponsorships) * 100);
}
/** UI-specific: Has sponsorships */
get hasSponsorships(): boolean {
return this.totalSponsorships > 0;
}
/** UI-specific: Status text */
get statusText(): string {
if (this.activeSponsorships === 0) return 'No active sponsorships';
if (this.activeSponsorships === this.totalSponsorships) return 'All sponsorships active';
return `${this.activeSponsorships} of ${this.totalSponsorships} active`;
}
}

View File

@@ -0,0 +1,50 @@
import type { SponsorSponsorshipsDto } from '../dtos';
import { SponsorshipDetailViewModel } from './SponsorshipDetailViewModel';
/**
* Sponsor Sponsorships View Model
*
* View model for sponsor sponsorships data with UI-specific transformations.
*/
export class SponsorSponsorshipsViewModel {
sponsorId: string;
sponsorName: string;
sponsorships: SponsorshipDetailViewModel[];
constructor(dto: SponsorSponsorshipsDto) {
this.sponsorId = dto.sponsorId;
this.sponsorName = dto.sponsorName;
this.sponsorships = dto.sponsorships.map(s => new SponsorshipDetailViewModel(s));
}
/** UI-specific: Total sponsorships count */
get totalCount(): number {
return this.sponsorships.length;
}
/** UI-specific: Active sponsorships */
get activeSponsorships(): SponsorshipDetailViewModel[] {
return this.sponsorships.filter(s => s.status === 'active');
}
/** UI-specific: Active count */
get activeCount(): number {
return this.activeSponsorships.length;
}
/** UI-specific: Has sponsorships */
get hasSponsorships(): boolean {
return this.sponsorships.length > 0;
}
/** UI-specific: Total investment */
get totalInvestment(): number {
return this.sponsorships.reduce((sum, s) => sum + s.amount, 0);
}
/** UI-specific: Formatted total investment */
get formattedTotalInvestment(): string {
const firstCurrency = this.sponsorships[0]?.currency || 'USD';
return `${firstCurrency} ${this.totalInvestment.toLocaleString()}`;
}
}

View File

@@ -0,0 +1,44 @@
import type { GetEntitySponsorshipPricingResultDto } from '../dtos';
/**
* Sponsorship Pricing View Model
*
* View model for sponsorship pricing data with UI-specific transformations.
*/
export class SponsorshipPricingViewModel {
mainSlotPrice: number;
secondarySlotPrice: number;
currency: string;
constructor(dto: GetEntitySponsorshipPricingResultDto) {
this.mainSlotPrice = dto.mainSlotPrice;
this.secondarySlotPrice = dto.secondarySlotPrice;
this.currency = dto.currency;
}
/** UI-specific: Formatted main slot price */
get formattedMainSlotPrice(): string {
return `${this.currency} ${this.mainSlotPrice.toLocaleString()}`;
}
/** UI-specific: Formatted secondary slot price */
get formattedSecondarySlotPrice(): string {
return `${this.currency} ${this.secondarySlotPrice.toLocaleString()}`;
}
/** UI-specific: Price difference */
get priceDifference(): number {
return this.mainSlotPrice - this.secondarySlotPrice;
}
/** UI-specific: Formatted price difference */
get formattedPriceDifference(): string {
return `${this.currency} ${this.priceDifference.toLocaleString()}`;
}
/** UI-specific: Discount percentage for secondary slot */
get secondaryDiscountPercentage(): number {
if (this.mainSlotPrice === 0) return 0;
return Math.round((1 - this.secondarySlotPrice / this.mainSlotPrice) * 100);
}
}

View File

@@ -0,0 +1,9 @@
/**
* Update Avatar View Model
*
* Represents the result of an avatar update operation
*/
export interface UpdateAvatarViewModel {
success: boolean;
error?: string;
}

View File

@@ -0,0 +1,11 @@
/**
* Upload Media View Model
*
* Represents the result of a media upload operation
*/
export interface UploadMediaViewModel {
success: boolean;
mediaId?: string;
url?: string;
error?: string;
}

View File

@@ -32,7 +32,10 @@ export { RaceResultsDetailViewModel } from './RaceResultsDetailViewModel';
// Sponsor ViewModels
export { SponsorViewModel } from './SponsorViewModel';
export { SponsorDashboardViewModel } from './SponsorDashboardViewModel';
export { SponsorSponsorshipsViewModel } from './SponsorSponsorshipsViewModel';
export { SponsorshipDetailViewModel } from './SponsorshipDetailViewModel';
export { SponsorshipPricingViewModel } from './SponsorshipPricingViewModel';
// Team ViewModels
export { TeamDetailsViewModel } from './TeamDetailsViewModel';