178 lines
5.6 KiB
TypeScript
178 lines
5.6 KiB
TypeScript
/**
|
|
* Application Use Case: GetSponsorSponsorshipsUseCase
|
|
*
|
|
* Returns detailed sponsorship information for a sponsor's campaigns/sponsorships page.
|
|
*/
|
|
|
|
import type { ISponsorRepository } from '../../domain/repositories/ISponsorRepository';
|
|
import type { ISeasonSponsorshipRepository } from '../../domain/repositories/ISeasonSponsorshipRepository';
|
|
import type { ISeasonRepository } from '../../domain/repositories/ISeasonRepository';
|
|
import type { ILeagueRepository } from '../../domain/repositories/ILeagueRepository';
|
|
import type { ILeagueMembershipRepository } from '../../domain/repositories/ILeagueMembershipRepository';
|
|
import type { IRaceRepository } from '../../domain/repositories/IRaceRepository';
|
|
import type { SponsorshipTier, SponsorshipStatus } from '../../domain/entities/SeasonSponsorship';
|
|
import type {
|
|
ISponsorSponsorshipsPresenter,
|
|
SponsorSponsorshipsViewModel,
|
|
} from '../presenters/ISponsorSponsorshipsPresenter';
|
|
import type { UseCase } from '@gridpilot/shared/application/UseCase';
|
|
|
|
export interface GetSponsorSponsorshipsQueryParams {
|
|
sponsorId: string;
|
|
}
|
|
|
|
export interface SponsorshipDetailDTO {
|
|
id: string;
|
|
leagueId: string;
|
|
leagueName: string;
|
|
seasonId: string;
|
|
seasonName: string;
|
|
seasonStartDate?: Date;
|
|
seasonEndDate?: Date;
|
|
tier: SponsorshipTier;
|
|
status: SponsorshipStatus;
|
|
pricing: {
|
|
amount: number;
|
|
currency: string;
|
|
};
|
|
platformFee: {
|
|
amount: number;
|
|
currency: string;
|
|
};
|
|
netAmount: {
|
|
amount: number;
|
|
currency: string;
|
|
};
|
|
metrics: {
|
|
drivers: number;
|
|
races: number;
|
|
completedRaces: number;
|
|
impressions: number;
|
|
};
|
|
createdAt: Date;
|
|
activatedAt?: Date;
|
|
}
|
|
|
|
export interface SponsorSponsorshipsDTO {
|
|
sponsorId: string;
|
|
sponsorName: string;
|
|
sponsorships: SponsorshipDetailDTO[];
|
|
summary: {
|
|
totalSponsorships: number;
|
|
activeSponsorships: number;
|
|
totalInvestment: number;
|
|
totalPlatformFees: number;
|
|
currency: string;
|
|
};
|
|
}
|
|
|
|
export class GetSponsorSponsorshipsUseCase
|
|
implements UseCase<GetSponsorSponsorshipsQueryParams, SponsorSponsorshipsDTO | null, SponsorSponsorshipsViewModel, ISponsorSponsorshipsPresenter>
|
|
{
|
|
constructor(
|
|
private readonly sponsorRepository: ISponsorRepository,
|
|
private readonly seasonSponsorshipRepository: ISeasonSponsorshipRepository,
|
|
private readonly seasonRepository: ISeasonRepository,
|
|
private readonly leagueRepository: ILeagueRepository,
|
|
private readonly leagueMembershipRepository: ILeagueMembershipRepository,
|
|
private readonly raceRepository: IRaceRepository,
|
|
) {}
|
|
|
|
async execute(
|
|
params: GetSponsorSponsorshipsQueryParams,
|
|
presenter: ISponsorSponsorshipsPresenter,
|
|
): Promise<void> {
|
|
presenter.reset();
|
|
|
|
const { sponsorId } = params;
|
|
|
|
const sponsor = await this.sponsorRepository.findById(sponsorId);
|
|
if (!sponsor) {
|
|
presenter.present(null);
|
|
return;
|
|
}
|
|
|
|
// Get all sponsorships for this sponsor
|
|
const sponsorships = await this.seasonSponsorshipRepository.findBySponsorId(sponsorId);
|
|
|
|
const sponsorshipDetails: SponsorshipDetailDTO[] = [];
|
|
let totalInvestment = 0;
|
|
let totalPlatformFees = 0;
|
|
|
|
for (const sponsorship of sponsorships) {
|
|
// Get season to find league
|
|
const season = await this.seasonRepository.findById(sponsorship.seasonId);
|
|
if (!season) continue;
|
|
|
|
const league = await this.leagueRepository.findById(season.leagueId);
|
|
if (!league) continue;
|
|
|
|
// Get membership count for this league
|
|
const memberships = await this.leagueMembershipRepository.getLeagueMembers(season.leagueId);
|
|
const driverCount = memberships.length;
|
|
|
|
// Get races for this league
|
|
const races = await this.raceRepository.findByLeagueId(season.leagueId);
|
|
const completedRaces = races.filter(r => r.status === 'completed').length;
|
|
|
|
// Calculate impressions
|
|
const impressions = completedRaces * driverCount * 100;
|
|
|
|
// Calculate platform fee (10%)
|
|
const platformFee = sponsorship.getPlatformFee();
|
|
const netAmount = sponsorship.getNetAmount();
|
|
|
|
totalInvestment += sponsorship.pricing.amount;
|
|
totalPlatformFees += platformFee.amount;
|
|
|
|
sponsorshipDetails.push({
|
|
id: sponsorship.id,
|
|
leagueId: league.id,
|
|
leagueName: league.name,
|
|
seasonId: season.id,
|
|
seasonName: season.name,
|
|
...(season.startDate !== undefined ? { seasonStartDate: season.startDate } : {}),
|
|
...(season.endDate !== undefined ? { seasonEndDate: season.endDate } : {}),
|
|
tier: sponsorship.tier,
|
|
status: sponsorship.status,
|
|
pricing: {
|
|
amount: sponsorship.pricing.amount,
|
|
currency: sponsorship.pricing.currency,
|
|
},
|
|
platformFee: {
|
|
amount: platformFee.amount,
|
|
currency: platformFee.currency,
|
|
},
|
|
netAmount: {
|
|
amount: netAmount.amount,
|
|
currency: netAmount.currency,
|
|
},
|
|
metrics: {
|
|
drivers: driverCount,
|
|
races: races.length,
|
|
completedRaces,
|
|
impressions,
|
|
},
|
|
createdAt: sponsorship.createdAt,
|
|
...(sponsorship.activatedAt !== undefined ? { activatedAt: sponsorship.activatedAt } : {}),
|
|
});
|
|
}
|
|
|
|
const activeSponsorships = sponsorships.filter(s => s.status === 'active').length;
|
|
|
|
const dto: SponsorSponsorshipsDTO = {
|
|
sponsorId,
|
|
sponsorName: sponsor.name,
|
|
sponsorships: sponsorshipDetails,
|
|
summary: {
|
|
totalSponsorships: sponsorships.length,
|
|
activeSponsorships,
|
|
totalInvestment,
|
|
totalPlatformFees,
|
|
currency: 'USD',
|
|
},
|
|
};
|
|
|
|
presenter.present(dto);
|
|
}
|
|
} |