This commit is contained in:
2025-12-16 10:50:15 +01:00
parent 775d41e055
commit 8ed6ba1fd1
144 changed files with 5763 additions and 1985 deletions

View File

@@ -1,162 +1,72 @@
import { Injectable } from '@nestjs/common';
import { GetEntitySponsorshipPricingResultDto, SponsorDto, GetSponsorsOutput, CreateSponsorInput, CreateSponsorOutput, GetSponsorDashboardQueryParams, SponsorDashboardDTO, GetSponsorSponsorshipsQueryParams, SponsorshipDetailDTO, SponsorSponsorshipsDTO, SponsoredLeagueDTO, SponsorDashboardMetricsDTO, SponsorDashboardInvestmentDTO } from './dto/SponsorDto';
import { Injectable, Inject } from '@nestjs/common';
import { GetEntitySponsorshipPricingResultDto, GetSponsorsOutput, CreateSponsorInput, CreateSponsorOutput, GetSponsorDashboardQueryParams, SponsorDashboardDTO, GetSponsorSponsorshipsQueryParams, SponsorSponsorshipsDTO, SponsorDto, SponsorDashboardMetricsDTO, SponsoredLeagueDTO, SponsorDashboardInvestmentDTO, SponsorshipDetailDTO } from './dto/SponsorDto';
const sponsors: Map<string, SponsorDto> = new Map();
// Use cases
import { GetSponsorshipPricingUseCase } from '@gridpilot/racing/application/use-cases/GetSponsorshipPricingUseCase';
import { GetSponsorsUseCase } from '@gridpilot/racing/application/use-cases/GetSponsorsUseCase';
import { CreateSponsorUseCase } from '@gridpilot/racing/application/use-cases/CreateSponsorUseCase';
import { GetSponsorDashboardUseCase } from '@gridpilot/racing/application/use-cases/GetSponsorDashboardUseCase';
import { GetSponsorSponsorshipsUseCase } from '@gridpilot/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
// Presenters
import { GetSponsorshipPricingPresenter } from './presenters/GetSponsorshipPricingPresenter';
import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter';
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter';
import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter';
// Tokens
import { GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN, GET_SPONSORS_USE_CASE_TOKEN, CREATE_SPONSOR_USE_CASE_TOKEN, GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN, GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN, LOGGER_TOKEN } from './SponsorProviders';
import { Logger } from '@gridpilot/shared/application';
@Injectable()
export class SponsorService {
constructor(
@Inject(GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN) private readonly getSponsorshipPricingUseCase: GetSponsorshipPricingUseCase,
@Inject(GET_SPONSORS_USE_CASE_TOKEN) private readonly getSponsorsUseCase: GetSponsorsUseCase,
@Inject(CREATE_SPONSOR_USE_CASE_TOKEN) private readonly createSponsorUseCase: CreateSponsorUseCase,
@Inject(GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN) private readonly getSponsorDashboardUseCase: GetSponsorDashboardUseCase,
@Inject(GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN) private readonly getSponsorSponsorshipsUseCase: GetSponsorSponsorshipsUseCase,
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
) {}
constructor() {
// Seed some demo sponsors for dashboard if empty
if (sponsors.size === 0) {
const demoSponsor1: SponsorDto = {
id: 'sponsor-demo-1',
name: 'Demo Sponsor Co.',
contactEmail: 'contact@demosponsor.com',
websiteUrl: 'https://demosponsor.com',
logoUrl: 'https://fakeimg.pl/200x100/aaaaaa/ffffff?text=DemoCo',
createdAt: new Date(),
};
const demoSponsor2: SponsorDto = {
id: 'sponsor-demo-2',
name: 'Second Brand',
contactEmail: 'info@secondbrand.net',
websiteUrl: 'https://secondbrand.net',
logoUrl: 'https://fakeimg.pl/200x100/cccccc/ffffff?text=Brand2',
createdAt: new Date(Date.now() - 86400000 * 5),
};
sponsors.set(demoSponsor1.id, demoSponsor1);
sponsors.set(demoSponsor2.id, demoSponsor2);
}
}
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDto> {
this.logger.debug('[SponsorService] Fetching sponsorship pricing.');
getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDto> {
// This logic relies on external factors (e.g., pricing configuration, entity type)
// For now, return mock data
return Promise.resolve({
pricing: [
{ id: 'tier-bronze', level: 'Bronze', price: 100, currency: 'USD' },
{ id: 'tier-silver', level: 'Silver', price: 250, currency: 'USD' },
{ id: 'tier-gold', level: 'Gold', price: 500, currency: 'USD' },
],
});
const presenter = new GetSponsorshipPricingPresenter();
await this.getSponsorshipPricingUseCase.execute(undefined, presenter);
return presenter.viewModel;
}
async getSponsors(): Promise<GetSponsorsOutput> {
return { sponsors: Array.from(sponsors.values()) };
this.logger.debug('[SponsorService] Fetching sponsors.');
const presenter = new GetSponsorsPresenter();
await this.getSponsorsUseCase.execute(undefined, presenter);
return presenter.viewModel;
}
async createSponsor(input: CreateSponsorInput): Promise<CreateSponsorOutput> {
const id = `sponsor-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const newSponsor: SponsorDto = {
id,
name: input.name,
contactEmail: input.contactEmail,
websiteUrl: input.websiteUrl,
logoUrl: input.logoUrl,
createdAt: new Date(),
};
sponsors.set(id, newSponsor);
return { sponsor: newSponsor };
this.logger.debug('[SponsorService] Creating sponsor.', { input });
const presenter = new CreateSponsorPresenter();
await this.createSponsorUseCase.execute(input, presenter);
return presenter.viewModel;
}
async getSponsorDashboard(params: GetSponsorDashboardQueryParams): Promise<SponsorDashboardDTO | null> {
const { sponsorId } = params;
this.logger.debug('[SponsorService] Fetching sponsor dashboard.', { params });
const sponsor = sponsors.get(sponsorId);
if (!sponsor) {
return null;
}
// Simplified mock data for dashboard metrics and sponsored leagues
const metrics: SponsorDashboardMetricsDTO = {
impressions: 10000,
impressionsChange: 12.5,
uniqueViewers: 7000,
viewersChange: 8.3,
races: 50,
drivers: 100,
exposure: 75,
exposureChange: 5.2,
};
const sponsoredLeagues: SponsoredLeagueDTO[] = [
{ id: 'league-1', name: 'League 1', tier: 'main', drivers: 50, races: 10, impressions: 5000, status: 'active' },
{ id: 'league-2', name: 'League 2', tier: 'secondary', drivers: 30, races: 5, impressions: 1500, status: 'upcoming' },
];
const investment: SponsorDashboardInvestmentDTO = {
activeSponsorships: 2,
totalInvestment: 5000,
costPerThousandViews: 0.5,
};
return {
sponsorId,
sponsorName: sponsor.name,
metrics,
sponsoredLeagues,
investment,
};
const presenter = new GetSponsorDashboardPresenter();
await this.getSponsorDashboardUseCase.execute(params, presenter);
return presenter.viewModel as SponsorDashboardDTO | null;
}
async getSponsorSponsorships(params: GetSponsorSponsorshipsQueryParams): Promise<SponsorSponsorshipsDTO | null> {
const { sponsorId } = params;
this.logger.debug('[SponsorService] Fetching sponsor sponsorships.', { params });
const sponsor = sponsors.get(sponsorId);
if (!sponsor) {
return null;
};
const sponsorshipDetails: SponsorshipDetailDTO[] = [
{
id: 'sponsorship-1',
leagueId: 'league-1',
leagueName: 'League 1',
seasonId: 'season-1',
seasonName: 'Season 1',
seasonStartDate: new Date('2025-01-01'),
seasonEndDate: new Date('2025-12-31'),
tier: 'main',
status: 'active',
pricing: { amount: 1000, currency: 'USD' },
platformFee: { amount: 100, currency: 'USD' },
netAmount: { amount: 900, currency: 'USD' },
metrics: { drivers: 50, races: 10, completedRaces: 8, impressions: 5000 },
createdAt: new Date('2024-12-01'),
activatedAt: new Date('2025-01-01'),
},
{
id: 'sponsorship-2',
leagueId: 'league-2',
leagueName: 'League 2',
seasonId: 'season-2',
seasonName: 'Season 2',
tier: 'secondary',
status: 'pending',
pricing: { amount: 500, currency: 'USD' },
platformFee: { amount: 50, currency: 'USD' },
netAmount: { amount: 450, currency: 'USD' },
metrics: { drivers: 30, races: 5, completedRaces: 0, impressions: 0 },
createdAt: new Date('2025-03-15'),
},
];
const totalInvestment = sponsorshipDetails.reduce((sum, s) => sum + s.pricing.amount, 0);
const totalPlatformFees = sponsorshipDetails.reduce((sum, s) => sum + s.platformFee.amount, 0);
const activeSponsorships = sponsorshipDetails.filter(s => s.status === 'active').length;
return {
sponsorId,
sponsorName: sponsor.name,
sponsorships: sponsorshipDetails,
summary: {
totalSponsorships: sponsorshipDetails.length,
activeSponsorships,
totalInvestment,
totalPlatformFees,
currency: 'USD',
},
};
const presenter = new GetSponsorSponsorshipsPresenter();
await this.getSponsorSponsorshipsUseCase.execute(params, presenter);
return presenter.viewModel as SponsorSponsorshipsDTO | null;
}
}