refactor use cases

This commit is contained in:
2026-01-08 15:34:51 +01:00
parent d984ab24a8
commit 52e9a2f6a7
362 changed files with 5192 additions and 8409 deletions

View File

@@ -28,7 +28,7 @@ import { SponsorRaceDTO } from './dtos/RaceDTO';
import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
import type { AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter';
import { AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter';
import type { RejectSponsorshipRequestResult } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
@ApiTags('sponsors')
@@ -166,7 +166,7 @@ export class SponsorController {
async acceptSponsorshipRequest(
@Param('requestId') requestId: string,
@Body() input: AcceptSponsorshipRequestInputDTO,
): Promise<AcceptSponsorshipRequestResultViewModel | null> {
): Promise<AcceptSponsorshipRequestResultViewModel> {
return await this.sponsorService.acceptSponsorshipRequest(
requestId,
input.respondedBy,
@@ -185,7 +185,7 @@ export class SponsorController {
async rejectSponsorshipRequest(
@Param('requestId') requestId: string,
@Body() input: RejectSponsorshipRequestInputDTO,
): Promise<RejectSponsorshipRequestResult | null> {
): Promise<RejectSponsorshipRequestResult> {
return await this.sponsorService.rejectSponsorshipRequest(
requestId,
input.respondedBy,
@@ -219,9 +219,13 @@ export class SponsorController {
description: 'Available leagues',
type: [AvailableLeagueDTO],
})
async getAvailableLeagues(): Promise<AvailableLeagueDTO[] | null> {
async getAvailableLeagues(): Promise<AvailableLeagueDTO[]> {
const presenter = await this.sponsorService.getAvailableLeagues();
return presenter.viewModel;
const viewModel = presenter.viewModel;
if (!viewModel) {
throw new Error('Available leagues not found');
}
return viewModel;
}
@Get('leagues/:leagueId/detail')
@@ -236,9 +240,13 @@ export class SponsorController {
league: LeagueDetailDTO;
drivers: SponsorDriverDTO[];
races: SponsorRaceDTO[];
} | null> {
}> {
const presenter = await this.sponsorService.getLeagueDetail(leagueId);
return presenter.viewModel;
const viewModel = presenter.viewModel;
if (!viewModel) {
throw new Error('League detail not found');
}
return viewModel;
}
@Get('settings/:sponsorId')
@@ -253,9 +261,13 @@ export class SponsorController {
profile: SponsorProfileDTO;
notifications: NotificationSettingsDTO;
privacy: PrivacySettingsDTO;
} | null> {
}> {
const presenter = await this.sponsorService.getSponsorSettings(sponsorId);
return presenter.viewModel;
const viewModel = presenter.viewModel;
if (!viewModel) {
throw new Error('Sponsor settings not found');
}
return viewModel;
}
@Put('settings/:sponsorId')
@@ -273,8 +285,12 @@ export class SponsorController {
notifications?: Partial<NotificationSettingsDTO>;
privacy?: Partial<PrivacySettingsDTO>;
},
): Promise<{ success: boolean; errorCode?: string; message?: string } | null> {
): Promise<{ success: boolean; errorCode?: string; message?: string }> {
const presenter = await this.sponsorService.updateSponsorSettings(sponsorId, input);
return presenter.viewModel;
const viewModel = presenter.viewModel;
if (!viewModel) {
throw new Error('Update failed');
}
return viewModel;
}
}
}

View File

@@ -5,8 +5,6 @@ import { SponsorService } from './SponsorService';
import type { NotificationService } from '@core/notifications/application/ports/NotificationService';
import type { IPaymentRepository } from '@core/payments/domain/repositories/IPaymentRepository';
import type { IWalletRepository } from '@core/payments/domain/repositories/IWalletRepository';
// Remove the missing import
// import { IPaymentGateway } from '@core/payments/domain/ports/IPaymentGateway';
import { ILeagueMembershipRepository } from '@core/racing/domain/repositories/ILeagueMembershipRepository';
import { ILeagueRepository } from '@core/racing/domain/repositories/ILeagueRepository';
import { ILeagueWalletRepository } from '@core/racing/domain/repositories/ILeagueWalletRepository';
@@ -16,7 +14,7 @@ import { ISeasonSponsorshipRepository } from '@core/racing/domain/repositories/I
import { ISponsorRepository } from '@core/racing/domain/repositories/ISponsorRepository';
import { ISponsorshipPricingRepository } from '@core/racing/domain/repositories/ISponsorshipPricingRepository';
import { ISponsorshipRequestRepository } from '@core/racing/domain/repositories/ISponsorshipRequestRepository';
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import type { Logger } from '@core/shared/application';
import { GetSponsorBillingUseCase } from '@core/payments/application/use-cases/GetSponsorBillingUseCase';
import { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
@@ -24,7 +22,6 @@ import { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateS
import { GetEntitySponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetEntitySponsorshipPricingUseCase';
import { GetPendingSponsorshipRequestsUseCase } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
import { GetSponsorDashboardUseCase } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
import { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
import { GetSponsorSponsorshipsUseCase } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
import { GetSponsorsUseCase } from '@core/racing/application/use-cases/GetSponsorsUseCase';
import { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsorUseCase';
@@ -35,18 +32,6 @@ import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
import { InMemoryPaymentRepository } from '@adapters/payments/persistence/inmemory/InMemoryPaymentRepository';
import { InMemoryWalletRepository } from '@adapters/payments/persistence/inmemory/InMemoryWalletRepository';
// Import presenters
import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter';
import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter';
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter';
import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter';
import { GetSponsorPresenter } from './presenters/GetSponsorPresenter';
import { GetPendingSponsorshipRequestsPresenter } from './presenters/GetPendingSponsorshipRequestsPresenter';
import { AcceptSponsorshipRequestPresenter } from './presenters/AcceptSponsorshipRequestPresenter';
import { RejectSponsorshipRequestPresenter } from './presenters/RejectSponsorshipRequestPresenter';
import { SponsorBillingPresenter } from './presenters/SponsorBillingPresenter';
// Define injection tokens
export const SPONSOR_REPOSITORY_TOKEN = 'ISponsorRepository';
export const SEASON_SPONSORSHIP_REPOSITORY_TOKEN = 'ISeasonSponsorshipRepository';
@@ -62,20 +47,7 @@ export const LEAGUE_WALLET_REPOSITORY_TOKEN = 'ILeagueWalletRepository';
export const NOTIFICATION_SERVICE_TOKEN = 'INotificationService';
export const LOGGER_TOKEN = 'Logger';
// Presenter tokens
export const GET_ENTITY_SPONSORSHIP_PRICING_PRESENTER_TOKEN = 'GetEntitySponsorshipPricingPresenter';
export const GET_SPONSORS_PRESENTER_TOKEN = 'GetSponsorsPresenter';
export const CREATE_SPONSOR_PRESENTER_TOKEN = 'CreateSponsorPresenter';
export const GET_SPONSOR_DASHBOARD_PRESENTER_TOKEN = 'GetSponsorDashboardPresenter';
export const GET_SPONSOR_SPONSORSHIPS_PRESENTER_TOKEN = 'GetSponsorSponsorshipsPresenter';
export const GET_SPONSOR_PRESENTER_TOKEN = 'GetSponsorPresenter';
export const GET_PENDING_SPONSORSHIP_REQUESTS_PRESENTER_TOKEN = 'GetPendingSponsorshipRequestsPresenter';
export const ACCEPT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN = 'AcceptSponsorshipRequestPresenter';
export const REJECT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN = 'RejectSponsorshipRequestPresenter';
export const GET_SPONSOR_BILLING_PRESENTER_TOKEN = 'SponsorBillingPresenter';
// 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';
export const GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN = 'GetSponsorDashboardUseCase';
@@ -87,19 +59,6 @@ export const ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN = 'AcceptSponsorshipReque
export const REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN = 'RejectSponsorshipRequestUseCase';
export const GET_SPONSOR_BILLING_USE_CASE_TOKEN = 'GetSponsorBillingUseCase';
// Output port tokens
export const GET_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN = 'GetSponsorshipPricingOutputPort_TOKEN';
export const GET_SPONSORS_OUTPUT_PORT_TOKEN = 'GetSponsorsOutputPort_TOKEN';
export const CREATE_SPONSOR_OUTPUT_PORT_TOKEN = 'CreateSponsorOutputPort_TOKEN';
export const GET_SPONSOR_DASHBOARD_OUTPUT_PORT_TOKEN = 'GetSponsorDashboardOutputPort_TOKEN';
export const GET_SPONSOR_SPONSORSHIPS_OUTPUT_PORT_TOKEN = 'GetSponsorSponsorshipsOutputPort_TOKEN';
export const GET_ENTITY_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN = 'GetEntitySponsorshipPricingOutputPort_TOKEN';
export const GET_SPONSOR_OUTPUT_PORT_TOKEN = 'GetSponsorOutputPort_TOKEN';
export const GET_PENDING_SPONSORSHIP_REQUESTS_OUTPUT_PORT_TOKEN = 'GetPendingSponsorshipRequestsOutputPort_TOKEN';
export const ACCEPT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN = 'AcceptSponsorshipRequestOutputPort_TOKEN';
export const REJECT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN = 'RejectSponsorshipRequestOutputPort_TOKEN';
export const GET_SPONSOR_BILLING_OUTPUT_PORT_TOKEN = 'GetSponsorBillingOutputPort_TOKEN';
export const SponsorProviders: Provider[] = [
SponsorService,
// Repositories (payments repos are local to this module; racing repos come from InMemoryRacingPersistenceModule)
@@ -126,77 +85,16 @@ export const SponsorProviders: Provider[] = [
provide: LOGGER_TOKEN,
useClass: ConsoleLogger,
},
// Presenters
GetEntitySponsorshipPricingPresenter,
GetSponsorsPresenter,
CreateSponsorPresenter,
GetSponsorDashboardPresenter,
GetSponsorSponsorshipsPresenter,
GetSponsorPresenter,
GetPendingSponsorshipRequestsPresenter,
AcceptSponsorshipRequestPresenter,
RejectSponsorshipRequestPresenter,
SponsorBillingPresenter,
// Output ports
{
provide: GET_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN,
useExisting: GetEntitySponsorshipPricingPresenter,
},
{
provide: GET_ENTITY_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN,
useExisting: GetEntitySponsorshipPricingPresenter,
},
{
provide: GET_SPONSORS_OUTPUT_PORT_TOKEN,
useExisting: GetSponsorsPresenter,
},
{
provide: CREATE_SPONSOR_OUTPUT_PORT_TOKEN,
useExisting: CreateSponsorPresenter,
},
{
provide: GET_SPONSOR_DASHBOARD_OUTPUT_PORT_TOKEN,
useExisting: GetSponsorDashboardPresenter,
},
{
provide: GET_SPONSOR_SPONSORSHIPS_OUTPUT_PORT_TOKEN,
useExisting: GetSponsorSponsorshipsPresenter,
},
{
provide: GET_SPONSOR_OUTPUT_PORT_TOKEN,
useExisting: GetSponsorPresenter,
},
{
provide: GET_PENDING_SPONSORSHIP_REQUESTS_OUTPUT_PORT_TOKEN,
useExisting: GetPendingSponsorshipRequestsPresenter,
},
{
provide: ACCEPT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN,
useExisting: AcceptSponsorshipRequestPresenter,
},
{
provide: REJECT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN,
useExisting: RejectSponsorshipRequestPresenter,
},
{
provide: GET_SPONSOR_BILLING_OUTPUT_PORT_TOKEN,
useExisting: SponsorBillingPresenter,
},
// Use cases
{
provide: GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
useFactory: (output: UseCaseOutputPort<unknown>) => new GetSponsorshipPricingUseCase(output),
inject: [GET_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN],
},
{
provide: GET_SPONSORS_USE_CASE_TOKEN,
useFactory: (sponsorRepo: ISponsorRepository, output: UseCaseOutputPort<unknown>) => new GetSponsorsUseCase(sponsorRepo, output),
inject: [SPONSOR_REPOSITORY_TOKEN, GET_SPONSORS_OUTPUT_PORT_TOKEN],
useFactory: (sponsorRepo: ISponsorRepository) => new GetSponsorsUseCase(sponsorRepo),
inject: [SPONSOR_REPOSITORY_TOKEN],
},
{
provide: CREATE_SPONSOR_USE_CASE_TOKEN,
useFactory: (sponsorRepo: ISponsorRepository, logger: Logger, output: UseCaseOutputPort<unknown>) => new CreateSponsorUseCase(sponsorRepo, logger, output),
inject: [SPONSOR_REPOSITORY_TOKEN, LOGGER_TOKEN, CREATE_SPONSOR_OUTPUT_PORT_TOKEN],
useFactory: (sponsorRepo: ISponsorRepository, logger: Logger) => new CreateSponsorUseCase(sponsorRepo, logger),
inject: [SPONSOR_REPOSITORY_TOKEN, LOGGER_TOKEN],
},
{
provide: GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN,
@@ -207,8 +105,7 @@ export const SponsorProviders: Provider[] = [
leagueRepo: ILeagueRepository,
leagueMembershipRepo: ILeagueMembershipRepository,
raceRepo: IRaceRepository,
output: UseCaseOutputPort<unknown>,
) => new GetSponsorDashboardUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo, output),
) => new GetSponsorDashboardUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo),
inject: [
SPONSOR_REPOSITORY_TOKEN,
SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
@@ -216,7 +113,6 @@ export const SponsorProviders: Provider[] = [
LEAGUE_REPOSITORY_TOKEN,
LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
RACE_REPOSITORY_TOKEN,
GET_SPONSOR_DASHBOARD_OUTPUT_PORT_TOKEN,
],
},
{
@@ -228,8 +124,7 @@ export const SponsorProviders: Provider[] = [
leagueRepo: ILeagueRepository,
leagueMembershipRepo: ILeagueMembershipRepository,
raceRepo: IRaceRepository,
output: UseCaseOutputPort<unknown>,
) => new GetSponsorSponsorshipsUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo, output),
) => new GetSponsorSponsorshipsUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo),
inject: [
SPONSOR_REPOSITORY_TOKEN,
SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
@@ -237,7 +132,6 @@ export const SponsorProviders: Provider[] = [
LEAGUE_REPOSITORY_TOKEN,
LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
RACE_REPOSITORY_TOKEN,
GET_SPONSOR_SPONSORSHIPS_OUTPUT_PORT_TOKEN,
],
},
{
@@ -255,27 +149,24 @@ export const SponsorProviders: Provider[] = [
useFactory: (
sponsorshipPricingRepo: ISponsorshipPricingRepository,
logger: Logger,
output: UseCaseOutputPort<unknown>,
) => new GetEntitySponsorshipPricingUseCase(sponsorshipPricingRepo, logger, output),
) => new GetEntitySponsorshipPricingUseCase(sponsorshipPricingRepo, logger),
inject: [
SPONSORSHIP_PRICING_REPOSITORY_TOKEN,
LOGGER_TOKEN,
GET_ENTITY_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN,
],
},
{
provide: GET_SPONSOR_USE_CASE_TOKEN,
useFactory: (sponsorRepo: ISponsorRepository, output: UseCaseOutputPort<unknown>) => new GetSponsorUseCase(sponsorRepo, output),
inject: [SPONSOR_REPOSITORY_TOKEN, GET_SPONSOR_OUTPUT_PORT_TOKEN],
useFactory: (sponsorRepo: ISponsorRepository) => new GetSponsorUseCase(sponsorRepo),
inject: [SPONSOR_REPOSITORY_TOKEN],
},
{
provide: GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN,
useFactory: (
sponsorshipRequestRepo: ISponsorshipRequestRepository,
sponsorRepo: ISponsorRepository,
output: UseCaseOutputPort<unknown>,
) => new GetPendingSponsorshipRequestsUseCase(sponsorshipRequestRepo, sponsorRepo, output),
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, SPONSOR_REPOSITORY_TOKEN, GET_PENDING_SPONSORSHIP_REQUESTS_OUTPUT_PORT_TOKEN],
) => new GetPendingSponsorshipRequestsUseCase(sponsorshipRequestRepo, sponsorRepo),
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, SPONSOR_REPOSITORY_TOKEN],
},
{
provide: ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
@@ -287,7 +178,6 @@ export const SponsorProviders: Provider[] = [
walletRepository: IWalletRepository,
leagueWalletRepository: ILeagueWalletRepository,
logger: Logger,
output: UseCaseOutputPort<unknown>,
) => {
// Create a mock payment processor function
const paymentProcessor = async (input: unknown) => {
@@ -303,8 +193,7 @@ export const SponsorProviders: Provider[] = [
paymentProcessor,
walletRepository,
leagueWalletRepository,
logger,
output
logger
);
},
inject: [
@@ -315,7 +204,6 @@ export const SponsorProviders: Provider[] = [
WALLET_REPOSITORY_TOKEN,
LEAGUE_WALLET_REPOSITORY_TOKEN,
LOGGER_TOKEN,
ACCEPT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN,
],
},
{
@@ -323,8 +211,7 @@ export const SponsorProviders: Provider[] = [
useFactory: (
sponsorshipRequestRepo: ISponsorshipRequestRepository,
logger: Logger,
output: UseCaseOutputPort<unknown>,
) => new RejectSponsorshipRequestUseCase(sponsorshipRequestRepo, logger, output),
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, LOGGER_TOKEN, REJECT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN],
) => new RejectSponsorshipRequestUseCase(sponsorshipRequestRepo, logger),
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, LOGGER_TOKEN],
},
];

View File

@@ -3,7 +3,7 @@ import type { AcceptSponsorshipRequestUseCase } from '@core/racing/application/u
import type { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateSponsorUseCase';
import type { GetPendingSponsorshipRequestsUseCase } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
import type { GetSponsorDashboardInput, GetSponsorDashboardUseCase } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
import type { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
import type { GetEntitySponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetEntitySponsorshipPricingUseCase';
import type { GetSponsorSponsorshipsInput, GetSponsorSponsorshipsUseCase } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
import type { GetSponsorsUseCase } from '@core/racing/application/use-cases/GetSponsorsUseCase';
import type { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsorUseCase';
@@ -14,21 +14,11 @@ import { beforeEach, describe, expect, it, Mock, vi } from 'vitest';
import type { CreateSponsorInputDTO } from './dtos/CreateSponsorInputDTO';
import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
import { Money } from '@core/racing/domain/value-objects/Money';
import { AcceptSponsorshipRequestPresenter } from './presenters/AcceptSponsorshipRequestPresenter';
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter';
import { GetPendingSponsorshipRequestsPresenter } from './presenters/GetPendingSponsorshipRequestsPresenter';
import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter';
import { GetSponsorPresenter } from './presenters/GetSponsorPresenter';
import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter';
import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter';
import { RejectSponsorshipRequestPresenter } from './presenters/RejectSponsorshipRequestPresenter';
import { SponsorBillingPresenter } from './presenters/SponsorBillingPresenter';
import { SponsorService } from './SponsorService';
describe('SponsorService', () => {
let service: SponsorService;
let getSponsorshipPricingUseCase: { execute: Mock };
let getEntitySponsorshipPricingUseCase: { execute: Mock };
let getSponsorsUseCase: { execute: Mock };
let createSponsorUseCase: { execute: Mock };
let getSponsorDashboardUseCase: { execute: Mock };
@@ -40,20 +30,8 @@ describe('SponsorService', () => {
let getSponsorBillingUseCase: { execute: Mock };
let logger: Logger;
// Presenters
let getEntitySponsorshipPricingPresenter: GetEntitySponsorshipPricingPresenter;
let getSponsorsPresenter: GetSponsorsPresenter;
let createSponsorPresenter: CreateSponsorPresenter;
let getSponsorDashboardPresenter: GetSponsorDashboardPresenter;
let getSponsorSponsorshipsPresenter: GetSponsorSponsorshipsPresenter;
let getSponsorPresenter: GetSponsorPresenter;
let getPendingSponsorshipRequestsPresenter: GetPendingSponsorshipRequestsPresenter;
let acceptSponsorshipRequestPresenter: AcceptSponsorshipRequestPresenter;
let rejectSponsorshipRequestPresenter: RejectSponsorshipRequestPresenter;
let sponsorBillingPresenter: SponsorBillingPresenter;
beforeEach(() => {
getSponsorshipPricingUseCase = { execute: vi.fn() };
getEntitySponsorshipPricingUseCase = { execute: vi.fn() };
getSponsorsUseCase = { execute: vi.fn() };
createSponsorUseCase = { execute: vi.fn() };
getSponsorDashboardUseCase = { execute: vi.fn() };
@@ -70,20 +48,8 @@ describe('SponsorService', () => {
error: vi.fn(),
} as unknown as Logger;
// Initialize presenters
getEntitySponsorshipPricingPresenter = new GetEntitySponsorshipPricingPresenter();
getSponsorsPresenter = new GetSponsorsPresenter();
createSponsorPresenter = new CreateSponsorPresenter();
getSponsorDashboardPresenter = new GetSponsorDashboardPresenter();
getSponsorSponsorshipsPresenter = new GetSponsorSponsorshipsPresenter();
getSponsorPresenter = new GetSponsorPresenter();
getPendingSponsorshipRequestsPresenter = new GetPendingSponsorshipRequestsPresenter();
acceptSponsorshipRequestPresenter = new AcceptSponsorshipRequestPresenter();
rejectSponsorshipRequestPresenter = new RejectSponsorshipRequestPresenter();
sponsorBillingPresenter = new SponsorBillingPresenter();
service = new SponsorService(
getSponsorshipPricingUseCase as unknown as GetSponsorshipPricingUseCase,
getEntitySponsorshipPricingUseCase as unknown as GetEntitySponsorshipPricingUseCase,
getSponsorsUseCase as unknown as GetSponsorsUseCase,
createSponsorUseCase as unknown as CreateSponsorUseCase,
getSponsorDashboardUseCase as unknown as GetSponsorDashboardUseCase,
@@ -94,31 +60,19 @@ describe('SponsorService', () => {
rejectSponsorshipRequestUseCase as unknown as RejectSponsorshipRequestUseCase,
getSponsorBillingUseCase as unknown as GetSponsorBillingUseCase,
logger,
getEntitySponsorshipPricingPresenter,
getSponsorsPresenter,
createSponsorPresenter,
getSponsorDashboardPresenter,
getSponsorSponsorshipsPresenter,
getSponsorPresenter,
getPendingSponsorshipRequestsPresenter,
acceptSponsorshipRequestPresenter,
rejectSponsorshipRequestPresenter,
sponsorBillingPresenter,
);
});
describe('getEntitySponsorshipPricing', () => {
it('returns pricing data on success', async () => {
const outputPort = {
const output = {
entityType: 'season',
entityId: 'season-1',
acceptingApplications: true,
tiers: [{ name: 'Gold', price: { amount: 500, currency: 'USD' }, benefits: ['Main slot'] }],
};
getSponsorshipPricingUseCase.execute.mockImplementation(async () => {
getEntitySponsorshipPricingPresenter.present(outputPort as any);
return Result.ok(undefined);
});
getEntitySponsorshipPricingUseCase.execute.mockResolvedValue(Result.ok(output));
const result = await service.getEntitySponsorshipPricing();
@@ -130,7 +84,7 @@ describe('SponsorService', () => {
});
it('returns empty pricing on error', async () => {
getSponsorshipPricingUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
getEntitySponsorshipPricingUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
const result = await service.getEntitySponsorshipPricing();
@@ -153,10 +107,7 @@ describe('SponsorService', () => {
}),
];
getSponsorsUseCase.execute.mockImplementation(async () => {
getSponsorsPresenter.present(sponsors);
return Result.ok(undefined);
});
getSponsorsUseCase.execute.mockResolvedValue(Result.ok({ sponsors }));
const result = await service.getSponsors();
@@ -191,10 +142,7 @@ describe('SponsorService', () => {
createdAt: new Date('2024-01-01T00:00:00Z'),
});
createSponsorUseCase.execute.mockImplementation(async () => {
createSponsorPresenter.present(sponsor);
return Result.ok(undefined);
});
createSponsorUseCase.execute.mockResolvedValue(Result.ok({ sponsor }));
const result = await service.createSponsor(input);
@@ -235,7 +183,7 @@ describe('SponsorService', () => {
describe('getSponsorDashboard', () => {
it('returns dashboard on success', async () => {
const params: GetSponsorDashboardInput = { sponsorId: 's1' };
const outputPort = {
const output = {
sponsorId: 's1',
sponsorName: 'S1',
metrics: {
@@ -254,19 +202,25 @@ describe('SponsorService', () => {
totalInvestment: Money.create(0, 'USD'),
costPerThousandViews: 0,
},
sponsorships: {
leagues: [],
teams: [],
drivers: [],
races: [],
platform: [],
},
recentActivity: [],
upcomingRenewals: [],
};
getSponsorDashboardUseCase.execute.mockImplementation(async () => {
getSponsorDashboardPresenter.present(outputPort as any);
return Result.ok(undefined);
});
getSponsorDashboardUseCase.execute.mockResolvedValue(Result.ok(output));
const result = await service.getSponsorDashboard(params);
expect(result).toEqual({
sponsorId: 's1',
sponsorName: 'S1',
metrics: outputPort.metrics,
metrics: output.metrics,
sponsoredLeagues: [],
investment: {
activeSponsorships: 0,
@@ -296,7 +250,7 @@ describe('SponsorService', () => {
describe('getSponsorSponsorships', () => {
it('returns sponsorships on success', async () => {
const params: GetSponsorSponsorshipsInput = { sponsorId: 's1' };
const outputPort = {
const output = {
sponsor: Sponsor.create({
id: 's1',
name: 'S1',
@@ -311,10 +265,7 @@ describe('SponsorService', () => {
},
};
getSponsorSponsorshipsUseCase.execute.mockImplementation(async () => {
getSponsorSponsorshipsPresenter.present(outputPort as any);
return Result.ok(undefined);
});
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(Result.ok(output));
const result = await service.getSponsorSponsorships(params);
@@ -345,16 +296,25 @@ describe('SponsorService', () => {
describe('getSponsor', () => {
it('returns sponsor when found', async () => {
const sponsorId = 's1';
const output = { sponsor: { id: sponsorId, name: 'S1' } };
getSponsorUseCase.execute.mockImplementation(async () => {
getSponsorPresenter.present(output);
return Result.ok(undefined);
const sponsor = Sponsor.create({
id: sponsorId,
name: 'S1',
contactEmail: 's1@example.com',
createdAt: new Date('2024-01-01T00:00:00Z'),
});
getSponsorUseCase.execute.mockResolvedValue(Result.ok({ sponsor }));
const result = await service.getSponsor(sponsorId);
expect(result).toEqual(output);
expect(result).toEqual({
sponsor: {
id: sponsorId,
name: 'S1',
logoUrl: undefined,
websiteUrl: undefined,
},
});
});
it('throws when not found', async () => {
@@ -375,21 +335,18 @@ describe('SponsorService', () => {
describe('getPendingSponsorshipRequests', () => {
it('returns requests on success', async () => {
const params = { entityType: 'season' as const, entityId: 'season-1' };
const outputPort = {
const output = {
entityType: 'season',
entityId: 'season-1',
requests: [],
totalCount: 0,
};
getPendingSponsorshipRequestsUseCase.execute.mockImplementation(async () => {
getPendingSponsorshipRequestsPresenter.present(outputPort as any);
return Result.ok(undefined);
});
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.ok(output));
const result = await service.getPendingSponsorshipRequests(params);
expect(result).toEqual(outputPort);
expect(result).toEqual(output);
});
it('returns empty result on error', async () => {
@@ -405,20 +362,13 @@ describe('SponsorService', () => {
totalCount: 0,
});
});
it('throws when presenter viewModel is missing on success', async () => {
const params = { entityType: 'season' as const, entityId: 'season-1' };
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.ok(undefined));
await expect(service.getPendingSponsorshipRequests(params)).rejects.toThrow('Pending sponsorship requests not found');
});
});
describe('SponsorshipRequest', () => {
it('returns accept result on success', async () => {
const requestId = 'r1';
const respondedBy = 'u1';
const outputPort = {
const output = {
requestId,
sponsorshipId: 'sp1',
status: 'accepted' as const,
@@ -427,14 +377,11 @@ describe('SponsorService', () => {
netAmount: 90,
};
acceptSponsorshipRequestUseCase.execute.mockImplementation(async () => {
acceptSponsorshipRequestPresenter.present(outputPort as any);
return Result.ok(undefined);
});
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(output));
const result = await service.acceptSponsorshipRequest(requestId, respondedBy);
expect(result).toEqual(outputPort);
expect(result).toEqual(output);
});
it('throws on error', async () => {
@@ -448,16 +395,6 @@ describe('SponsorService', () => {
'Accept sponsorship request failed',
);
});
it('throws when presenter viewModel is missing on success', async () => {
const requestId = 'r1';
const respondedBy = 'u1';
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(undefined));
await expect(service.acceptSponsorshipRequest(requestId, respondedBy)).rejects.toThrow(
'Accept sponsorship request failed',
);
});
});
describe('rejectSponsorshipRequest', () => {
@@ -472,10 +409,7 @@ describe('SponsorService', () => {
rejectionReason: reason,
};
rejectSponsorshipRequestUseCase.execute.mockImplementation(async () => {
rejectSponsorshipRequestPresenter.present(output as any);
return Result.ok(undefined);
});
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(output));
const result = await service.rejectSponsorshipRequest(requestId, respondedBy, reason);
@@ -485,19 +419,18 @@ describe('SponsorService', () => {
it('passes no reason when reason is undefined', async () => {
const requestId = 'r1';
const respondedBy = 'u1';
const output = {
requestId,
status: 'rejected' as const,
respondedAt: new Date(),
rejectionReason: '',
};
rejectSponsorshipRequestUseCase.execute.mockImplementation(async (input: any) => {
expect(input).toEqual({ requestId, respondedBy });
rejectSponsorshipRequestPresenter.present({
requestId,
status: 'rejected' as const,
respondedAt: new Date(),
rejectionReason: '',
} as any);
return Result.ok(undefined);
});
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(output));
await expect(service.rejectSponsorshipRequest(requestId, respondedBy)).resolves.toMatchObject({
const result = await service.rejectSponsorshipRequest(requestId, respondedBy);
expect(result).toMatchObject({
requestId,
status: 'rejected',
});
@@ -514,16 +447,6 @@ describe('SponsorService', () => {
'Reject sponsorship request failed',
);
});
it('throws when presenter viewModel is missing on success', async () => {
const requestId = 'r1';
const respondedBy = 'u1';
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(undefined));
await expect(service.rejectSponsorshipRequest(requestId, respondedBy)).rejects.toThrow(
'Reject sponsorship request failed',
);
});
});
describe('getSponsorBilling', () => {

View File

@@ -21,7 +21,7 @@ import { InvoiceDTO } from './dtos/InvoiceDTO';
import { BillingStatsDTO } from './dtos/BillingStatsDTO';
// Use cases
import { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
import { GetEntitySponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetEntitySponsorshipPricingUseCase';
import { GetSponsorsUseCase } from '@core/racing/application/use-cases/GetSponsorsUseCase';
import { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateSponsorUseCase';
import { GetSponsorDashboardUseCase } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
@@ -37,26 +37,8 @@ import { GetSponsorBillingUseCase } from '@core/payments/application/use-cases/G
import type { SponsorableEntityType } from '@core/racing/domain/entities/SponsorshipRequest';
import type { Logger } from '@core/shared/application';
// Presenters
import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter';
import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter';
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter';
import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter';
import { GetSponsorPresenter } from './presenters/GetSponsorPresenter';
import { GetPendingSponsorshipRequestsPresenter } from './presenters/GetPendingSponsorshipRequestsPresenter';
import { AcceptSponsorshipRequestPresenter, AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter';
import { RejectSponsorshipRequestPresenter } from './presenters/RejectSponsorshipRequestPresenter';
import { SponsorBillingPresenter } from './presenters/SponsorBillingPresenter';
import { AvailableLeaguesPresenter } from './presenters/AvailableLeaguesPresenter';
import { LeagueDetailPresenter } from './presenters/LeagueDetailPresenter';
import { SponsorSettingsPresenter } from './presenters/SponsorSettingsPresenter';
import { SponsorSettingsUpdatePresenter } from './presenters/SponsorSettingsUpdatePresenter';
import type { RejectSponsorshipRequestResult } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
// Tokens
import {
GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
GET_SPONSORS_USE_CASE_TOKEN,
CREATE_SPONSOR_USE_CASE_TOKEN,
GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN,
@@ -66,14 +48,33 @@ import {
ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
GET_SPONSOR_BILLING_USE_CASE_TOKEN,
GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
LOGGER_TOKEN,
} from './SponsorTokens';
// Presenters (for view model transformation only)
import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter';
import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter';
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter';
import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter';
import { GetSponsorPresenter } from './presenters/GetSponsorPresenter';
import { GetPendingSponsorshipRequestsPresenter } from './presenters/GetPendingSponsorshipRequestsPresenter';
import { AcceptSponsorshipRequestPresenter } from './presenters/AcceptSponsorshipRequestPresenter';
import { RejectSponsorshipRequestPresenter } from './presenters/RejectSponsorshipRequestPresenter';
import { SponsorBillingPresenter } from './presenters/SponsorBillingPresenter';
import { AvailableLeaguesPresenter } from './presenters/AvailableLeaguesPresenter';
import { LeagueDetailPresenter } from './presenters/LeagueDetailPresenter';
import { SponsorSettingsPresenter } from './presenters/SponsorSettingsPresenter';
import { SponsorSettingsUpdatePresenter } from './presenters/SponsorSettingsUpdatePresenter';
import type { RejectSponsorshipRequestResult } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
import type { AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter';
@Injectable()
export class SponsorService {
constructor(
@Inject(GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN)
private readonly getSponsorshipPricingUseCase: GetSponsorshipPricingUseCase,
@Inject(GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN)
private readonly getEntitySponsorshipPricingUseCase: GetEntitySponsorshipPricingUseCase,
@Inject(GET_SPONSORS_USE_CASE_TOKEN)
private readonly getSponsorsUseCase: GetSponsorsUseCase,
@Inject(CREATE_SPONSOR_USE_CASE_TOKEN)
@@ -94,22 +95,14 @@ export class SponsorService {
private readonly getSponsorBillingUseCase: GetSponsorBillingUseCase,
@Inject(LOGGER_TOKEN)
private readonly logger: Logger,
// Injected presenters
private readonly getEntitySponsorshipPricingPresenter: GetEntitySponsorshipPricingPresenter,
private readonly getSponsorsPresenter: GetSponsorsPresenter,
private readonly createSponsorPresenter: CreateSponsorPresenter,
private readonly getSponsorDashboardPresenter: GetSponsorDashboardPresenter,
private readonly getSponsorSponsorshipsPresenter: GetSponsorSponsorshipsPresenter,
private readonly getSponsorPresenter: GetSponsorPresenter,
private readonly getPendingSponsorshipRequestsPresenter: GetPendingSponsorshipRequestsPresenter,
private readonly acceptSponsorshipRequestPresenter: AcceptSponsorshipRequestPresenter,
private readonly rejectSponsorshipRequestPresenter: RejectSponsorshipRequestPresenter,
private readonly sponsorBillingPresenter: SponsorBillingPresenter,
) {}
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDTO> {
this.logger.debug('[SponsorService] Fetching sponsorship pricing.');
const result = await this.getSponsorshipPricingUseCase.execute({});
const result = await this.getEntitySponsorshipPricingUseCase.execute({
entityType: 'season',
entityId: 'default',
});
if (result.isErr()) {
return {
@@ -119,18 +112,22 @@ export class SponsorService {
};
}
return this.getEntitySponsorshipPricingPresenter.viewModel;
const presenter = new GetEntitySponsorshipPricingPresenter();
presenter.present(result.value);
return presenter.viewModel;
}
async getSponsors(): Promise<GetSponsorsOutputDTO> {
this.logger.debug('[SponsorService] Fetching sponsors.');
const result = await this.getSponsorsUseCase.execute();
const result = await this.getSponsorsUseCase.execute({});
if (result.isErr()) {
return { sponsors: [] };
}
return this.getSponsorsPresenter.responseModel;
const presenter = new GetSponsorsPresenter();
presenter.present(result.unwrap().sponsors);
return presenter.responseModel;
}
async createSponsor(input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDTO> {
@@ -142,7 +139,14 @@ export class SponsorService {
throw new Error(error.details?.message ?? error.message ?? 'Failed to create sponsor');
}
return this.createSponsorPresenter.viewModel;
const resultValue = result.value;
if (!resultValue) {
throw new Error('Create sponsor failed');
}
const presenter = new CreateSponsorPresenter();
presenter.present(resultValue.sponsor);
return presenter.viewModel;
}
async getSponsorDashboard(
@@ -155,7 +159,14 @@ export class SponsorService {
throw new Error('Sponsor dashboard not found');
}
return this.getSponsorDashboardPresenter.viewModel;
const resultValue = result.value;
if (!resultValue) {
throw new Error('Sponsor dashboard not found');
}
const presenter = new GetSponsorDashboardPresenter();
presenter.present(resultValue);
return presenter.viewModel;
}
async getSponsorSponsorships(
@@ -168,7 +179,14 @@ export class SponsorService {
throw new Error('Sponsor sponsorships not found');
}
return this.getSponsorSponsorshipsPresenter.viewModel;
const resultValue = result.value;
if (!resultValue) {
throw new Error('Sponsor sponsorships not found');
}
const presenter = new GetSponsorSponsorshipsPresenter();
presenter.present(resultValue);
return presenter.viewModel;
}
async getSponsor(sponsorId: string): Promise<GetSponsorOutputDTO> {
@@ -179,7 +197,14 @@ export class SponsorService {
throw new Error('Sponsor not found');
}
const viewModel = this.getSponsorPresenter.viewModel;
const resultValue = result.value;
if (!resultValue) {
throw new Error('Sponsor not found');
}
const presenter = new GetSponsorPresenter();
presenter.present(resultValue.sponsor);
const viewModel = presenter.viewModel;
if (!viewModel) {
throw new Error('Sponsor not found');
}
@@ -205,7 +230,14 @@ export class SponsorService {
};
}
const viewModel = this.getPendingSponsorshipRequestsPresenter.viewModel;
const resultValue = result.value;
if (!resultValue) {
throw new Error('Pending sponsorship requests not found');
}
const presenter = new GetPendingSponsorshipRequestsPresenter();
presenter.present(resultValue);
const viewModel = presenter.viewModel;
if (!viewModel) {
throw new Error('Pending sponsorship requests not found');
}
@@ -231,7 +263,14 @@ export class SponsorService {
throw new Error('Accept sponsorship request failed');
}
const viewModel = this.acceptSponsorshipRequestPresenter.viewModel;
const resultValue = result.value;
if (!resultValue) {
throw new Error('Accept sponsorship request failed');
}
const presenter = new AcceptSponsorshipRequestPresenter();
presenter.present(resultValue);
const viewModel = presenter.viewModel;
if (!viewModel) {
throw new Error('Accept sponsorship request failed');
}
@@ -263,7 +302,14 @@ export class SponsorService {
throw new Error('Reject sponsorship request failed');
}
const viewModel = this.rejectSponsorshipRequestPresenter.viewModel;
const resultValue = result.value;
if (!resultValue) {
throw new Error('Reject sponsorship request failed');
}
const presenter = new RejectSponsorshipRequestPresenter();
presenter.present(resultValue);
const viewModel = presenter.viewModel;
if (!viewModel) {
throw new Error('Reject sponsorship request failed');
}
@@ -284,7 +330,8 @@ export class SponsorService {
}
const billingData = result.unwrap();
this.sponsorBillingPresenter.present({
const presenter = new SponsorBillingPresenter();
presenter.present({
paymentMethods: billingData.paymentMethods,
invoices: billingData.invoices,
stats: {
@@ -294,7 +341,7 @@ export class SponsorService {
},
});
return this.sponsorBillingPresenter.viewModel;
return presenter.viewModel;
}
async getAvailableLeagues(): Promise<AvailableLeaguesPresenter> {
@@ -498,4 +545,4 @@ export class SponsorService {
presenter.present({ success: true });
return presenter;
}
}
}

View File

@@ -9,18 +9,6 @@ export const SPONSORSHIP_REQUEST_REPOSITORY_TOKEN = 'ISponsorshipRequestReposito
export const LOGGER_TOKEN = 'Logger';
export const MEDIA_RESOLVER_TOKEN = 'MediaResolverPort';
// Presenter tokens
export const GET_ENTITY_SPONSORSHIP_PRICING_PRESENTER_TOKEN = 'GetEntitySponsorshipPricingPresenter';
export const GET_SPONSORS_PRESENTER_TOKEN = 'GetSponsorsPresenter';
export const CREATE_SPONSOR_PRESENTER_TOKEN = 'CreateSponsorPresenter';
export const GET_SPONSOR_DASHBOARD_PRESENTER_TOKEN = 'GetSponsorDashboardPresenter';
export const GET_SPONSOR_SPONSORSHIPS_PRESENTER_TOKEN = 'GetSponsorSponsorshipsPresenter';
export const GET_SPONSOR_PRESENTER_TOKEN = 'GetSponsorPresenter';
export const GET_PENDING_SPONSORSHIP_REQUESTS_PRESENTER_TOKEN = 'GetPendingSponsorshipRequestsPresenter';
export const ACCEPT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN = 'AcceptSponsorshipRequestPresenter';
export const REJECT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN = 'RejectSponsorshipRequestPresenter';
export const GET_SPONSOR_BILLING_PRESENTER_TOKEN = 'SponsorBillingPresenter';
// Use case / application service tokens
export const GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN = 'GetSponsorshipPricingUseCase';
export const GET_SPONSORS_USE_CASE_TOKEN = 'GetSponsorsUseCase';
@@ -32,17 +20,4 @@ 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 GET_SPONSOR_BILLING_USE_CASE_TOKEN = 'GetSponsorBillingUseCase';
// Output port tokens
export const GET_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN = 'GetSponsorshipPricingOutputPort_TOKEN';
export const GET_SPONSORS_OUTPUT_PORT_TOKEN = 'GetSponsorsOutputPort_TOKEN';
export const CREATE_SPONSOR_OUTPUT_PORT_TOKEN = 'CreateSponsorOutputPort_TOKEN';
export const GET_SPONSOR_DASHBOARD_OUTPUT_PORT_TOKEN = 'GetSponsorDashboardOutputPort_TOKEN';
export const GET_SPONSOR_SPONSORSHIPS_OUTPUT_PORT_TOKEN = 'GetSponsorSponsorshipsOutputPort_TOKEN';
export const GET_ENTITY_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN = 'GetEntitySponsorshipPricingOutputPort_TOKEN';
export const GET_SPONSOR_OUTPUT_PORT_TOKEN = 'GetSponsorOutputPort_TOKEN';
export const GET_PENDING_SPONSORSHIP_REQUESTS_OUTPUT_PORT_TOKEN = 'GetPendingSponsorshipRequestsOutputPort_TOKEN';
export const ACCEPT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN = 'AcceptSponsorshipRequestOutputPort_TOKEN';
export const REJECT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN = 'RejectSponsorshipRequestOutputPort_TOKEN';
export const GET_SPONSOR_BILLING_OUTPUT_PORT_TOKEN = 'GetSponsorBillingOutputPort_TOKEN';
export const GET_SPONSOR_BILLING_USE_CASE_TOKEN = 'GetSponsorBillingUseCase';

View File

@@ -8,7 +8,7 @@ export class GetEntitySponsorshipPricingPresenter {
this.result = null;
}
present(output: GetEntitySponsorshipPricingResult | null) {
present(output: GetEntitySponsorshipPricingResult | null | undefined) {
if (!output) {
this.result = {
entityType: 'season',

View File

@@ -1,13 +1,5 @@
import { GetSponsorOutputDTO } from '../dtos/GetSponsorOutputDTO';
interface GetSponsorOutputPort {
sponsor: {
id: string;
name: string;
logoUrl?: string;
websiteUrl?: string;
};
}
import type { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
export class GetSponsorPresenter {
private result: GetSponsorOutputDTO | null = null;
@@ -16,18 +8,18 @@ export class GetSponsorPresenter {
this.result = null;
}
present(output: GetSponsorOutputPort | null) {
if (!output) {
present(sponsor: Sponsor) {
if (!sponsor) {
this.result = null;
return;
}
this.result = {
sponsor: {
id: output.sponsor.id,
name: output.sponsor.name,
...(output.sponsor.logoUrl !== undefined ? { logoUrl: output.sponsor.logoUrl } : {}),
...(output.sponsor.websiteUrl !== undefined ? { websiteUrl: output.sponsor.websiteUrl } : {}),
id: sponsor.id.toString(),
name: sponsor.name.toString(),
...(sponsor.logoUrl !== undefined ? { logoUrl: sponsor.logoUrl.toString() } : {}),
...(sponsor.websiteUrl !== undefined ? { websiteUrl: sponsor.websiteUrl.toString() } : {}),
},
} as GetSponsorOutputDTO;
}

View File

@@ -1,95 +0,0 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { GetSponsorshipPricingPresenter } from './GetSponsorshipPricingPresenter';
import type { GetSponsorshipPricingResult } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
describe('GetSponsorshipPricingPresenter', () => {
let presenter: GetSponsorshipPricingPresenter;
beforeEach(() => {
presenter = new GetSponsorshipPricingPresenter();
});
describe('reset', () => {
it('should reset the result to null', () => {
const mockResult: GetSponsorshipPricingResult = {
entityType: 'season',
entityId: 'season-1',
pricing: []
};
presenter.present(mockResult);
const expectedViewModel = {
entityType: 'season',
entityId: 'season-1',
pricing: []
};
expect(presenter.viewModel).toEqual(expectedViewModel);
presenter.reset();
expect(() => presenter.viewModel).toThrow('Presenter not presented');
});
});
describe('present', () => {
it('should store the result', () => {
const mockResult: GetSponsorshipPricingResult = {
entityType: 'season',
entityId: 'season-1',
pricing: []
};
presenter.present(mockResult);
const expectedViewModel = {
entityType: 'season',
entityId: 'season-1',
pricing: []
};
expect(presenter.viewModel).toEqual(expectedViewModel);
});
});
describe('getViewModel', () => {
it('should return null when not presented', () => {
expect(presenter.getViewModel()).toBeNull();
});
it('should return the result when presented', () => {
const mockResult: GetSponsorshipPricingResult = {
entityType: 'season',
entityId: 'season-1',
pricing: []
};
presenter.present(mockResult);
const expectedViewModel = {
entityType: 'season',
entityId: 'season-1',
pricing: []
};
expect(presenter.getViewModel()).toEqual(expectedViewModel);
});
});
describe('viewModel', () => {
it('should throw error when not presented', () => {
expect(() => presenter.viewModel).toThrow('Presenter not presented');
});
it('should return the result when presented', () => {
const mockResult: GetSponsorshipPricingResult = {
entityType: 'season',
entityId: 'season-1',
pricing: []
};
presenter.present(mockResult);
const expectedViewModel = {
entityType: 'season',
entityId: 'season-1',
pricing: []
};
expect(presenter.viewModel).toEqual(expectedViewModel);
});
});
});

View File

@@ -1,32 +0,0 @@
import type { GetSponsorshipPricingResult } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
import { GetEntitySponsorshipPricingResultDTO } from '../dtos/GetEntitySponsorshipPricingResultDTO';
export class GetSponsorshipPricingPresenter {
private result: GetEntitySponsorshipPricingResultDTO | null = null;
reset() {
this.result = null;
}
present(outputPort: GetSponsorshipPricingResult): void {
this.result = {
entityType: outputPort.entityType,
entityId: outputPort.entityId,
pricing: outputPort.pricing.map(item => ({
id: item.id,
level: item.level,
price: item.price,
currency: item.currency,
})),
};
}
getViewModel(): GetEntitySponsorshipPricingResultDTO | null {
return this.result;
}
get viewModel(): GetEntitySponsorshipPricingResultDTO {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
}