fix data flow issues

This commit is contained in:
2025-12-19 23:18:53 +01:00
parent ec177a75ce
commit 5c74837d73
45 changed files with 2726 additions and 746 deletions

View File

@@ -1,4 +1,4 @@
import { Controller, Get, Post, Body, HttpCode, HttpStatus, Param, Query } from '@nestjs/common';
import { Controller, Get, Post, Put, Body, HttpCode, HttpStatus, Param, Query } from '@nestjs/common';
import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
import { SponsorService } from './SponsorService';
import { GetEntitySponsorshipPricingResultDTO } from './dtos/GetEntitySponsorshipPricingResultDTO';
@@ -13,6 +13,16 @@ import { GetSponsorOutputDTO } from './dtos/GetSponsorOutputDTO';
import { GetPendingSponsorshipRequestsOutputDTO } from './dtos/GetPendingSponsorshipRequestsOutputDTO';
import { AcceptSponsorshipRequestInputDTO } from './dtos/AcceptSponsorshipRequestInputDTO';
import { RejectSponsorshipRequestInputDTO } from './dtos/RejectSponsorshipRequestInputDTO';
import { PaymentMethodDTO } from './dtos/PaymentMethodDTO';
import { InvoiceDTO } from './dtos/InvoiceDTO';
import { BillingStatsDTO } from './dtos/BillingStatsDTO';
import { AvailableLeagueDTO } from './dtos/AvailableLeagueDTO';
import { LeagueDetailDTO } from './dtos/LeagueDetailDTO';
import { DriverDTO } from './dtos/DriverDTO';
import { RaceDTO } from './dtos/RaceDTO';
import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
import type { AcceptSponsorshipRequestResultPort } from '@core/racing/application/ports/output/AcceptSponsorshipRequestResultPort';
import type { RejectSponsorshipRequestResultDTO } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
@@ -93,4 +103,59 @@ export class SponsorController {
async rejectSponsorshipRequest(@Param('requestId') requestId: string, @Body() input: RejectSponsorshipRequestInputDTO): Promise<RejectSponsorshipRequestResultDTO | null> {
return this.sponsorService.rejectSponsorshipRequest(requestId, input.respondedBy, input.reason);
}
@Get('billing/:sponsorId')
@ApiOperation({ summary: 'Get sponsor billing information' })
@ApiResponse({ status: 200, description: 'Sponsor billing data', type: Object })
async getSponsorBilling(@Param('sponsorId') sponsorId: string): Promise<{
paymentMethods: PaymentMethodDTO[];
invoices: InvoiceDTO[];
stats: BillingStatsDTO;
}> {
return this.sponsorService.getSponsorBilling(sponsorId);
}
@Get('leagues/available')
@ApiOperation({ summary: 'Get available leagues for sponsorship' })
@ApiResponse({ status: 200, description: 'Available leagues', type: [AvailableLeagueDTO] })
async getAvailableLeagues(): Promise<AvailableLeagueDTO[]> {
return this.sponsorService.getAvailableLeagues();
}
@Get('leagues/:leagueId/detail')
@ApiOperation({ summary: 'Get detailed league information for sponsors' })
@ApiResponse({ status: 200, description: 'League detail data', type: Object })
async getLeagueDetail(@Param('leagueId') leagueId: string): Promise<{
league: LeagueDetailDTO;
drivers: DriverDTO[];
races: RaceDTO[];
}> {
return this.sponsorService.getLeagueDetail(leagueId);
}
@Get('settings/:sponsorId')
@ApiOperation({ summary: 'Get sponsor settings' })
@ApiResponse({ status: 200, description: 'Sponsor settings', type: Object })
async getSponsorSettings(@Param('sponsorId') sponsorId: string): Promise<{
profile: SponsorProfileDTO;
notifications: NotificationSettingsDTO;
privacy: PrivacySettingsDTO;
}> {
return this.sponsorService.getSponsorSettings(sponsorId);
}
@Put('settings/:sponsorId')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Update sponsor settings' })
@ApiResponse({ status: 200, description: 'Settings updated successfully' })
async updateSponsorSettings(
@Param('sponsorId') sponsorId: string,
@Body() input: {
profile?: Partial<SponsorProfileDTO>;
notifications?: Partial<NotificationSettingsDTO>;
privacy?: Partial<PrivacySettingsDTO>;
}
): Promise<void> {
return this.sponsorService.updateSponsorSettings(sponsorId, input);
}
}

View File

@@ -13,10 +13,11 @@ import { ISponsorshipRequestRepository } from '@core/racing/domain/repositories/
import { INotificationService } from '@core/notifications/application/ports/INotificationService';
import { IPaymentGateway } from '@core/racing/application/ports/IPaymentGateway';
import { IWalletRepository } from '@core/payments/domain/repositories/IWalletRepository';
import type { IPaymentRepository } from '@core/payments/domain/repositories/IPaymentRepository';
import { ILeagueWalletRepository } from '@core/racing/domain/repositories/ILeagueWalletRepository';
import type { Logger } from '@core/shared/application';
// Import use cases
// Import use cases / application services
import { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
import { GetSponsorsUseCase } from '@core/racing/application/use-cases/GetSponsorsUseCase';
import { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateSponsorUseCase';
@@ -27,6 +28,7 @@ import { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsor
import { GetPendingSponsorshipRequestsUseCase } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
import { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
import { RejectSponsorshipRequestUseCase } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
import { SponsorBillingService } from '@core/payments/application/services/SponsorBillingService';
// Import concrete in-memory implementations
import { InMemorySponsorRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorRepository';
@@ -37,6 +39,7 @@ import { InMemoryLeagueMembershipRepository } from '@adapters/racing/persistence
import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/InMemoryRaceRepository';
import { InMemorySponsorshipPricingRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorshipPricingRepository';
import { InMemorySponsorshipRequestRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorshipRequestRepository';
import { InMemoryPaymentRepository } from '@adapters/payments/persistence/inmemory/InMemoryPaymentRepository';
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
// Define injection tokens
@@ -50,7 +53,7 @@ export const SPONSORSHIP_PRICING_REPOSITORY_TOKEN = 'ISponsorshipPricingReposito
export const SPONSORSHIP_REQUEST_REPOSITORY_TOKEN = 'ISponsorshipRequestRepository';
export const LOGGER_TOKEN = 'Logger';
// Use case tokens
// Use case / application service tokens
export const GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN = 'GetSponsorshipPricingUseCase';
export const GET_SPONSORS_USE_CASE_TOKEN = 'GetSponsorsUseCase';
export const CREATE_SPONSOR_USE_CASE_TOKEN = 'CreateSponsorUseCase';
@@ -61,6 +64,7 @@ export const GET_SPONSOR_USE_CASE_TOKEN = 'GetSponsorUseCase';
export const GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN = 'GetPendingSponsorshipRequestsUseCase';
export const ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN = 'AcceptSponsorshipRequestUseCase';
export const REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN = 'RejectSponsorshipRequestUseCase';
export const SPONSOR_BILLING_SERVICE_TOKEN = 'SponsorBillingService';
export const SponsorProviders: Provider[] = [
SponsorService,
@@ -133,9 +137,28 @@ export const SponsorProviders: Provider[] = [
},
{
provide: GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN,
useFactory: (sponsorRepo: ISponsorRepository, seasonSponsorshipRepo: ISeasonSponsorshipRepository, seasonRepo: ISeasonRepository, raceRepo: IRaceRepository) =>
new GetSponsorSponsorshipsUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, raceRepo),
inject: [SPONSOR_REPOSITORY_TOKEN, SEASON_SPONSORSHIP_REPOSITORY_TOKEN, SEASON_REPOSITORY_TOKEN, RACE_REPOSITORY_TOKEN],
useFactory: (
sponsorRepo: ISponsorRepository,
seasonSponsorshipRepo: ISeasonSponsorshipRepository,
seasonRepo: ISeasonRepository,
leagueRepo: ILeagueRepository,
leagueMembershipRepo: ILeagueMembershipRepository,
raceRepo: IRaceRepository,
) => new GetSponsorSponsorshipsUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo),
inject: [
SPONSOR_REPOSITORY_TOKEN,
SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
SEASON_REPOSITORY_TOKEN,
LEAGUE_REPOSITORY_TOKEN,
LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
RACE_REPOSITORY_TOKEN,
],
},
{
provide: SPONSOR_BILLING_SERVICE_TOKEN,
useFactory: (paymentRepo: IPaymentRepository, seasonSponsorshipRepo: ISeasonSponsorshipRepository) =>
new SponsorBillingService(paymentRepo, seasonSponsorshipRepo),
inject: ['IPaymentRepository', SEASON_SPONSORSHIP_REPOSITORY_TOKEN],
},
{
provide: GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN,

View File

@@ -11,6 +11,16 @@ import { GetSponsorOutputDTO } from './dtos/GetSponsorOutputDTO';
import { GetPendingSponsorshipRequestsOutputDTO } from './dtos/GetPendingSponsorshipRequestsOutputDTO';
import { AcceptSponsorshipRequestInputDTO } from './dtos/AcceptSponsorshipRequestInputDTO';
import { RejectSponsorshipRequestInputDTO } from './dtos/RejectSponsorshipRequestInputDTO';
import { PaymentMethodDTO } from './dtos/PaymentMethodDTO';
import { InvoiceDTO } from './dtos/InvoiceDTO';
import { BillingStatsDTO } from './dtos/BillingStatsDTO';
import { AvailableLeagueDTO } from './dtos/AvailableLeagueDTO';
import { LeagueDetailDTO } from './dtos/LeagueDetailDTO';
import { DriverDTO } from './dtos/DriverDTO';
import { RaceDTO } from './dtos/RaceDTO';
import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
// Use cases
import { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
@@ -144,4 +154,259 @@ export class SponsorService {
}
return result.value;
}
async getSponsorBilling(sponsorId: string): Promise<{
paymentMethods: PaymentMethodDTO[];
invoices: InvoiceDTO[];
stats: BillingStatsDTO;
}> {
this.logger.debug('[SponsorService] Fetching sponsor billing.', { sponsorId });
// Mock data - in real implementation, this would come from repositories
const paymentMethods: PaymentMethodDTO[] = [
{
id: 'pm-1',
type: 'card',
last4: '4242',
brand: 'Visa',
isDefault: true,
expiryMonth: 12,
expiryYear: 2027,
},
{
id: 'pm-2',
type: 'card',
last4: '5555',
brand: 'Mastercard',
isDefault: false,
expiryMonth: 6,
expiryYear: 2026,
},
{
id: 'pm-3',
type: 'sepa',
last4: '8901',
bankName: 'Deutsche Bank',
isDefault: false,
},
];
const invoices: InvoiceDTO[] = [
{
id: 'inv-1',
invoiceNumber: 'GP-2025-001234',
date: '2025-11-01',
dueDate: '2025-11-15',
amount: 1090.91,
vatAmount: 207.27,
totalAmount: 1298.18,
status: 'paid',
description: 'GT3 Pro Championship - Primary Sponsor (Q4 2025)',
sponsorshipType: 'league',
pdfUrl: '#',
},
{
id: 'inv-2',
invoiceNumber: 'GP-2025-001235',
date: '2025-10-01',
dueDate: '2025-10-15',
amount: 363.64,
vatAmount: 69.09,
totalAmount: 432.73,
status: 'paid',
description: 'Team Velocity - Gear Sponsor (Q4 2025)',
sponsorshipType: 'team',
pdfUrl: '#',
},
{
id: 'inv-3',
invoiceNumber: 'GP-2025-001236',
date: '2025-12-01',
dueDate: '2025-12-15',
amount: 318.18,
vatAmount: 60.45,
totalAmount: 378.63,
status: 'pending',
description: 'Alex Thompson - Driver Sponsorship (Dec 2025)',
sponsorshipType: 'driver',
pdfUrl: '#',
},
];
const stats: BillingStatsDTO = {
totalSpent: 12450,
pendingAmount: 919.54,
nextPaymentDate: '2025-12-15',
nextPaymentAmount: 378.63,
activeSponsorships: 6,
averageMonthlySpend: 2075,
};
return { paymentMethods, invoices, stats };
}
async getAvailableLeagues(): Promise<AvailableLeagueDTO[]> {
this.logger.debug('[SponsorService] Fetching available leagues.');
// Mock data
return [
{
id: 'league-1',
name: 'GT3 Masters Championship',
game: 'iRacing',
drivers: 48,
avgViewsPerRace: 8200,
mainSponsorSlot: { available: true, price: 1200 },
secondarySlots: { available: 1, total: 2, price: 400 },
rating: 4.8,
tier: 'premium',
nextRace: '2025-12-20',
seasonStatus: 'active',
description: 'Premier GT3 racing with top-tier drivers. Weekly broadcasts and active community.',
},
{
id: 'league-2',
name: 'Endurance Pro Series',
game: 'ACC',
drivers: 72,
avgViewsPerRace: 12500,
mainSponsorSlot: { available: false, price: 1500 },
secondarySlots: { available: 2, total: 2, price: 500 },
rating: 4.9,
tier: 'premium',
nextRace: '2026-01-05',
seasonStatus: 'active',
description: 'Multi-class endurance racing. High engagement from dedicated endurance fans.',
},
];
}
async getLeagueDetail(leagueId: string): Promise<{
league: LeagueDetailDTO;
drivers: DriverDTO[];
races: RaceDTO[];
}> {
this.logger.debug('[SponsorService] Fetching league detail.', { leagueId });
// Mock data
const league: LeagueDetailDTO = {
id: leagueId,
name: 'GT3 Masters Championship',
game: 'iRacing',
tier: 'premium',
season: 'Season 3',
description: 'Premier GT3 racing with top-tier drivers competing across the world\'s most iconic circuits.',
drivers: 48,
races: 12,
completedRaces: 8,
totalImpressions: 45200,
avgViewsPerRace: 5650,
engagement: 4.2,
rating: 4.8,
seasonStatus: 'active',
seasonDates: { start: '2025-10-01', end: '2026-02-28' },
nextRace: { name: 'Spa-Francorchamps', date: '2025-12-20' },
sponsorSlots: {
main: {
available: true,
price: 1200,
benefits: [
'Primary logo placement on all liveries',
'League page header banner',
'Race results page branding',
'Social media feature posts',
'Newsletter sponsor spot',
]
},
secondary: {
available: 1,
total: 2,
price: 400,
benefits: [
'Secondary logo on liveries',
'League page sidebar placement',
'Race results mention',
'Social media mentions',
]
},
},
};
const drivers: DriverDTO[] = [
{ id: 'd1', name: 'Max Verstappen', country: 'NL', position: 1, races: 8, impressions: 4200, team: 'Red Bull Racing' },
{ id: 'd2', name: 'Lewis Hamilton', country: 'GB', position: 2, races: 8, impressions: 3980, team: 'Mercedes AMG' },
];
const races: RaceDTO[] = [
{ id: 'r1', name: 'Spa-Francorchamps', date: '2025-12-20', views: 0, status: 'upcoming' },
{ id: 'r2', name: 'Monza', date: '2025-12-08', views: 5800, status: 'completed' },
];
return { league, drivers, races };
}
async getSponsorSettings(sponsorId: string): Promise<{
profile: SponsorProfileDTO;
notifications: NotificationSettingsDTO;
privacy: PrivacySettingsDTO;
}> {
this.logger.debug('[SponsorService] Fetching sponsor settings.', { sponsorId });
// Mock data
const profile: SponsorProfileDTO = {
companyName: 'Acme Racing Co.',
contactName: 'John Smith',
contactEmail: 'sponsor@acme-racing.com',
contactPhone: '+1 (555) 123-4567',
website: 'https://acme-racing.com',
description: 'Premium sim racing equipment and accessories for competitive drivers.',
logoUrl: null,
industry: 'Racing Equipment',
address: {
street: '123 Racing Boulevard',
city: 'Indianapolis',
country: 'United States',
postalCode: '46222',
},
taxId: 'US12-3456789',
socialLinks: {
twitter: '@acmeracing',
linkedin: 'acme-racing-co',
instagram: '@acmeracing',
},
};
const notifications: NotificationSettingsDTO = {
emailNewSponsorships: true,
emailWeeklyReport: true,
emailRaceAlerts: false,
emailPaymentAlerts: true,
emailNewOpportunities: true,
emailContractExpiry: true,
};
const privacy: PrivacySettingsDTO = {
publicProfile: true,
showStats: false,
showActiveSponsorships: true,
allowDirectContact: true,
};
return { profile, notifications, privacy };
}
async updateSponsorSettings(
sponsorId: string,
input: {
profile?: Partial<SponsorProfileDTO>;
notifications?: Partial<NotificationSettingsDTO>;
privacy?: Partial<PrivacySettingsDTO>;
}
): Promise<void> {
this.logger.debug('[SponsorService] Updating sponsor settings.', { sponsorId, input });
// Mock implementation - in real app, this would persist to database
// For now, just log the update
this.logger.info('[SponsorService] Settings updated successfully.', { sponsorId });
}
}

View File

@@ -0,0 +1,25 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsOptional, IsNumber } from 'class-validator';
export class ActivityItemDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty({ enum: ['race', 'league', 'team', 'driver', 'platform'] })
@IsEnum(['race', 'league', 'team', 'driver', 'platform'])
type: 'race' | 'league' | 'team' | 'driver' | 'platform';
@ApiProperty()
@IsString()
message: string;
@ApiProperty()
@IsString()
time: string;
@ApiProperty({ required: false })
@IsOptional()
@IsNumber()
impressions?: number;
}

View File

@@ -0,0 +1,58 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsNumber, IsBoolean, IsOptional, IsDateString } from 'class-validator';
export class AvailableLeagueDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
name: string;
@ApiProperty()
@IsString()
game: string;
@ApiProperty()
@IsNumber()
drivers: number;
@ApiProperty()
@IsNumber()
avgViewsPerRace: number;
@ApiProperty({ type: Object })
mainSponsorSlot: {
available: boolean;
price: number;
};
@ApiProperty({ type: Object })
secondarySlots: {
available: number;
total: number;
price: number;
};
@ApiProperty()
@IsNumber()
rating: number;
@ApiProperty({ enum: ['premium', 'standard', 'starter'] })
@IsEnum(['premium', 'standard', 'starter'])
tier: 'premium' | 'standard' | 'starter';
@ApiProperty({ required: false })
@IsOptional()
@IsDateString()
nextRace?: string;
@ApiProperty({ enum: ['active', 'upcoming', 'completed'] })
@IsEnum(['active', 'upcoming', 'completed'])
seasonStatus: 'active' | 'upcoming' | 'completed';
@ApiProperty()
@IsString()
description: string;
}

View File

@@ -0,0 +1,28 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber, IsDateString } from 'class-validator';
export class BillingStatsDTO {
@ApiProperty()
@IsNumber()
totalSpent: number;
@ApiProperty()
@IsNumber()
pendingAmount: number;
@ApiProperty()
@IsDateString()
nextPaymentDate: string;
@ApiProperty()
@IsNumber()
nextPaymentAmount: number;
@ApiProperty()
@IsNumber()
activeSponsorships: number;
@ApiProperty()
@IsNumber()
averageMonthlySpend: number;
}

View File

@@ -0,0 +1,32 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsNumber } from 'class-validator';
export class DriverDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
name: string;
@ApiProperty()
@IsString()
country: string;
@ApiProperty()
@IsNumber()
position: number;
@ApiProperty()
@IsNumber()
races: number;
@ApiProperty()
@IsNumber()
impressions: number;
@ApiProperty()
@IsString()
team: string;
}

View File

@@ -0,0 +1,48 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsNumber, IsDateString } from 'class-validator';
export class InvoiceDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
invoiceNumber: string;
@ApiProperty()
@IsDateString()
date: string;
@ApiProperty()
@IsDateString()
dueDate: string;
@ApiProperty()
@IsNumber()
amount: number;
@ApiProperty()
@IsNumber()
vatAmount: number;
@ApiProperty()
@IsNumber()
totalAmount: number;
@ApiProperty({ enum: ['paid', 'pending', 'overdue', 'failed'] })
@IsEnum(['paid', 'pending', 'overdue', 'failed'])
status: 'paid' | 'pending' | 'overdue' | 'failed';
@ApiProperty()
@IsString()
description: string;
@ApiProperty({ enum: ['league', 'team', 'driver', 'race', 'platform'] })
@IsEnum(['league', 'team', 'driver', 'race', 'platform'])
sponsorshipType: 'league' | 'team' | 'driver' | 'race' | 'platform';
@ApiProperty()
@IsString()
pdfUrl: string;
}

View File

@@ -0,0 +1,88 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsNumber, IsDateString, IsOptional } from 'class-validator';
export class LeagueDetailDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
name: string;
@ApiProperty()
@IsString()
game: string;
@ApiProperty({ enum: ['premium', 'standard', 'starter'] })
@IsEnum(['premium', 'standard', 'starter'])
tier: 'premium' | 'standard' | 'starter';
@ApiProperty()
@IsString()
season: string;
@ApiProperty()
@IsString()
description: string;
@ApiProperty()
@IsNumber()
drivers: number;
@ApiProperty()
@IsNumber()
races: number;
@ApiProperty()
@IsNumber()
completedRaces: number;
@ApiProperty()
@IsNumber()
totalImpressions: number;
@ApiProperty()
@IsNumber()
avgViewsPerRace: number;
@ApiProperty()
@IsNumber()
engagement: number;
@ApiProperty()
@IsNumber()
rating: number;
@ApiProperty({ enum: ['active', 'upcoming', 'completed'] })
@IsEnum(['active', 'upcoming', 'completed'])
seasonStatus: 'active' | 'upcoming' | 'completed';
@ApiProperty({ type: Object })
seasonDates: {
start: string;
end: string;
};
@ApiProperty({ type: Object, required: false })
@IsOptional()
nextRace?: {
name: string;
date: string;
};
@ApiProperty({ type: Object })
sponsorSlots: {
main: {
available: boolean;
price: number;
benefits: string[];
};
secondary: {
available: number;
total: number;
price: number;
benefits: string[];
};
};
}

View File

@@ -0,0 +1,28 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsBoolean } from 'class-validator';
export class NotificationSettingsDTO {
@ApiProperty()
@IsBoolean()
emailNewSponsorships: boolean;
@ApiProperty()
@IsBoolean()
emailWeeklyReport: boolean;
@ApiProperty()
@IsBoolean()
emailRaceAlerts: boolean;
@ApiProperty()
@IsBoolean()
emailPaymentAlerts: boolean;
@ApiProperty()
@IsBoolean()
emailNewOpportunities: boolean;
@ApiProperty()
@IsBoolean()
emailContractExpiry: boolean;
}

View File

@@ -0,0 +1,40 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsBoolean, IsOptional, IsNumber } from 'class-validator';
export class PaymentMethodDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty({ enum: ['card', 'bank', 'sepa'] })
@IsEnum(['card', 'bank', 'sepa'])
type: 'card' | 'bank' | 'sepa';
@ApiProperty()
@IsString()
last4: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
brand?: string;
@ApiProperty()
@IsBoolean()
isDefault: boolean;
@ApiProperty({ required: false })
@IsOptional()
@IsNumber()
expiryMonth?: number;
@ApiProperty({ required: false })
@IsOptional()
@IsNumber()
expiryYear?: number;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
bankName?: string;
}

View File

@@ -0,0 +1,20 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsBoolean } from 'class-validator';
export class PrivacySettingsDTO {
@ApiProperty()
@IsBoolean()
publicProfile: boolean;
@ApiProperty()
@IsBoolean()
showStats: boolean;
@ApiProperty()
@IsBoolean()
showActiveSponsorships: boolean;
@ApiProperty()
@IsBoolean()
allowDirectContact: boolean;
}

View File

@@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsNumber, IsDateString } from 'class-validator';
export class RaceDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
name: string;
@ApiProperty()
@IsDateString()
date: string;
@ApiProperty()
@IsNumber()
views: number;
@ApiProperty({ enum: ['upcoming', 'completed'] })
@IsEnum(['upcoming', 'completed'])
status: 'upcoming' | 'completed';
}

View File

@@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsNumber, IsDateString } from 'class-validator';
export class RenewalAlertDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty()
@IsString()
name: string;
@ApiProperty({ enum: ['league', 'team', 'driver', 'race', 'platform'] })
@IsEnum(['league', 'team', 'driver', 'race', 'platform'])
type: 'league' | 'team' | 'driver' | 'race' | 'platform';
@ApiProperty()
@IsDateString()
renewDate: string;
@ApiProperty()
@IsNumber()
price: number;
}

View File

@@ -1,8 +1,11 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString } from 'class-validator';
import { IsString, IsArray, IsObject } from 'class-validator';
import { SponsorDashboardMetricsDTO } from './SponsorDashboardMetricsDTO';
import { SponsoredLeagueDTO } from './SponsoredLeagueDTO';
import { SponsorDashboardInvestmentDTO } from './SponsorDashboardInvestmentDTO';
import { SponsorshipDTO } from './SponsorshipDTO';
import { ActivityItemDTO } from './ActivityItemDTO';
import { RenewalAlertDTO } from './RenewalAlertDTO';
export class SponsorDashboardDTO {
@ApiProperty()
@@ -21,4 +24,19 @@ export class SponsorDashboardDTO {
@ApiProperty({ type: SponsorDashboardInvestmentDTO })
investment: SponsorDashboardInvestmentDTO;
@ApiProperty({ type: Object })
sponsorships: {
leagues: SponsorshipDTO[];
teams: SponsorshipDTO[];
drivers: SponsorshipDTO[];
races: SponsorshipDTO[];
platform: SponsorshipDTO[];
};
@ApiProperty({ type: [ActivityItemDTO] })
recentActivity: ActivityItemDTO[];
@ApiProperty({ type: [RenewalAlertDTO] })
upcomingRenewals: RenewalAlertDTO[];
}

View File

@@ -0,0 +1,56 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsOptional, IsObject } from 'class-validator';
export class SponsorProfileDTO {
@ApiProperty()
@IsString()
companyName: string;
@ApiProperty()
@IsString()
contactName: string;
@ApiProperty()
@IsString()
contactEmail: string;
@ApiProperty()
@IsString()
contactPhone: string;
@ApiProperty()
@IsString()
website: string;
@ApiProperty()
@IsString()
description: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
logoUrl?: string;
@ApiProperty()
@IsString()
industry: string;
@ApiProperty({ type: Object })
address: {
street: string;
city: string;
country: string;
postalCode: string;
};
@ApiProperty()
@IsString()
taxId: string;
@ApiProperty({ type: Object })
socialLinks: {
twitter: string;
linkedin: string;
instagram: string;
};
}

View File

@@ -0,0 +1,85 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsEnum, IsNumber, IsOptional, IsDateString } from 'class-validator';
export class SponsorshipDTO {
@ApiProperty()
@IsString()
id: string;
@ApiProperty({ enum: ['leagues', 'teams', 'drivers', 'races', 'platform'] })
@IsEnum(['leagues', 'teams', 'drivers', 'races', 'platform'])
type: 'leagues' | 'teams' | 'drivers' | 'races' | 'platform';
@ApiProperty()
@IsString()
entityId: string;
@ApiProperty()
@IsString()
entityName: string;
@ApiProperty({ enum: ['main', 'secondary'], required: false })
@IsOptional()
@IsEnum(['main', 'secondary'])
tier?: 'main' | 'secondary';
@ApiProperty({ enum: ['active', 'pending_approval', 'approved', 'rejected', 'expired'] })
@IsEnum(['active', 'pending_approval', 'approved', 'rejected', 'expired'])
status: 'active' | 'pending_approval' | 'approved' | 'rejected' | 'expired';
@ApiProperty({ required: false })
@IsOptional()
@IsDateString()
applicationDate?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsDateString()
approvalDate?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
rejectionReason?: string;
@ApiProperty()
@IsDateString()
startDate: string;
@ApiProperty()
@IsDateString()
endDate: string;
@ApiProperty()
@IsNumber()
price: number;
@ApiProperty()
@IsNumber()
impressions: number;
@ApiProperty({ required: false })
@IsOptional()
@IsNumber()
impressionsChange?: number;
@ApiProperty({ required: false })
@IsOptional()
@IsNumber()
engagement?: number;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
details?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
entityOwner?: string;
@ApiProperty({ required: false })
@IsOptional()
@IsString()
applicationMessage?: string;
}