refactor api modules
This commit is contained in:
@@ -24,7 +24,7 @@ import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
|
||||
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
|
||||
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
|
||||
import type { AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter';
|
||||
import type { RejectSponsorshipRequestResultDTO } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
import type { RejectSponsorshipRequestResult } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
|
||||
@ApiTags('sponsors')
|
||||
@Controller('sponsors')
|
||||
@@ -39,8 +39,7 @@ export class SponsorController {
|
||||
type: GetEntitySponsorshipPricingResultDTO,
|
||||
})
|
||||
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDTO> {
|
||||
const presenter = await this.sponsorService.getEntitySponsorshipPricing();
|
||||
return presenter.viewModel;
|
||||
return await this.sponsorService.getEntitySponsorshipPricing();
|
||||
}
|
||||
|
||||
@Get()
|
||||
@@ -51,8 +50,7 @@ export class SponsorController {
|
||||
type: GetSponsorsOutputDTO,
|
||||
})
|
||||
async getSponsors(): Promise<GetSponsorsOutputDTO> {
|
||||
const presenter = await this.sponsorService.getSponsors();
|
||||
return presenter.viewModel;
|
||||
return await this.sponsorService.getSponsors();
|
||||
}
|
||||
|
||||
@Post()
|
||||
@@ -64,8 +62,7 @@ export class SponsorController {
|
||||
type: CreateSponsorOutputDTO,
|
||||
})
|
||||
async createSponsor(@Body() input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDTO> {
|
||||
const presenter = await this.sponsorService.createSponsor(input);
|
||||
return presenter.viewModel;
|
||||
return await this.sponsorService.createSponsor(input);
|
||||
}
|
||||
|
||||
@Get('dashboard/:sponsorId')
|
||||
@@ -78,11 +75,10 @@ export class SponsorController {
|
||||
@ApiResponse({ status: 404, description: 'Sponsor not found' })
|
||||
async getSponsorDashboard(
|
||||
@Param('sponsorId') sponsorId: string,
|
||||
): Promise<SponsorDashboardDTO | null> {
|
||||
const presenter = await this.sponsorService.getSponsorDashboard({
|
||||
): Promise<SponsorDashboardDTO> {
|
||||
return await this.sponsorService.getSponsorDashboard({
|
||||
sponsorId,
|
||||
} as GetSponsorDashboardQueryParamsDTO);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get(':sponsorId/sponsorships')
|
||||
@@ -97,11 +93,10 @@ export class SponsorController {
|
||||
@ApiResponse({ status: 404, description: 'Sponsor not found' })
|
||||
async getSponsorSponsorships(
|
||||
@Param('sponsorId') sponsorId: string,
|
||||
): Promise<SponsorSponsorshipsDTO | null> {
|
||||
const presenter = await this.sponsorService.getSponsorSponsorships({
|
||||
): Promise<SponsorSponsorshipsDTO> {
|
||||
return await this.sponsorService.getSponsorSponsorships({
|
||||
sponsorId,
|
||||
} as GetSponsorSponsorshipsQueryParamsDTO);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get(':sponsorId')
|
||||
@@ -112,9 +107,8 @@ export class SponsorController {
|
||||
type: GetSponsorOutputDTO,
|
||||
})
|
||||
@ApiResponse({ status: 404, description: 'Sponsor not found' })
|
||||
async getSponsor(@Param('sponsorId') sponsorId: string): Promise<GetSponsorOutputDTO | null> {
|
||||
const presenter = await this.sponsorService.getSponsor(sponsorId);
|
||||
return presenter.viewModel;
|
||||
async getSponsor(@Param('sponsorId') sponsorId: string): Promise<GetSponsorOutputDTO> {
|
||||
return await this.sponsorService.getSponsor(sponsorId);
|
||||
}
|
||||
|
||||
@Get('requests')
|
||||
@@ -126,14 +120,13 @@ export class SponsorController {
|
||||
})
|
||||
async getPendingSponsorshipRequests(
|
||||
@Query() query: { entityType: string; entityId: string },
|
||||
): Promise<GetPendingSponsorshipRequestsOutputDTO | null> {
|
||||
const presenter = await this.sponsorService.getPendingSponsorshipRequests(
|
||||
): Promise<GetPendingSponsorshipRequestsOutputDTO> {
|
||||
return await this.sponsorService.getPendingSponsorshipRequests(
|
||||
query as {
|
||||
entityType: import('@core/racing/domain/entities/SponsorshipRequest').SponsorableEntityType;
|
||||
entityId: string;
|
||||
},
|
||||
);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Post('requests/:requestId/accept')
|
||||
@@ -146,11 +139,10 @@ export class SponsorController {
|
||||
@Param('requestId') requestId: string,
|
||||
@Body() input: AcceptSponsorshipRequestInputDTO,
|
||||
): Promise<AcceptSponsorshipRequestResultViewModel | null> {
|
||||
const presenter = await this.sponsorService.acceptSponsorshipRequest(
|
||||
return await this.sponsorService.acceptSponsorshipRequest(
|
||||
requestId,
|
||||
input.respondedBy,
|
||||
);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Post('requests/:requestId/reject')
|
||||
@@ -162,13 +154,12 @@ export class SponsorController {
|
||||
async rejectSponsorshipRequest(
|
||||
@Param('requestId') requestId: string,
|
||||
@Body() input: RejectSponsorshipRequestInputDTO,
|
||||
): Promise<RejectSponsorshipRequestResultDTO | null> {
|
||||
const presenter = await this.sponsorService.rejectSponsorshipRequest(
|
||||
): Promise<RejectSponsorshipRequestResult | null> {
|
||||
return await this.sponsorService.rejectSponsorshipRequest(
|
||||
requestId,
|
||||
input.respondedBy,
|
||||
input.reason,
|
||||
);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get('billing/:sponsorId')
|
||||
@@ -181,8 +172,7 @@ export class SponsorController {
|
||||
invoices: InvoiceDTO[];
|
||||
stats: BillingStatsDTO;
|
||||
}> {
|
||||
const presenter = await this.sponsorService.getSponsorBilling(sponsorId);
|
||||
return presenter.viewModel;
|
||||
return await this.sponsorService.getSponsorBilling(sponsorId);
|
||||
}
|
||||
|
||||
@Get('leagues/available')
|
||||
|
||||
@@ -5,7 +5,8 @@ import { SponsorService } from './SponsorService';
|
||||
import { NotificationService } from '@core/notifications/application/ports/NotificationService';
|
||||
import type { IPaymentRepository } from '@core/payments/domain/repositories/IPaymentRepository';
|
||||
import { IWalletRepository } from '@core/payments/domain/repositories/IWalletRepository';
|
||||
import { IPaymentGateway } from '@core/payments/domain/ports/IPaymentGateway';
|
||||
// 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';
|
||||
@@ -15,7 +16,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 } from '@core/shared/application';
|
||||
import type { Logger, UseCaseOutputPort } from '@core/shared/application';
|
||||
|
||||
import { GetSponsorBillingUseCase } from '@core/payments/application/use-cases/GetSponsorBillingUseCase';
|
||||
import { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
|
||||
@@ -40,6 +41,18 @@ import { InMemorySponsorRepository } from '@adapters/racing/persistence/inmemory
|
||||
import { InMemorySponsorshipPricingRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorshipPricingRepository';
|
||||
import { InMemorySponsorshipRequestRepository } from '@adapters/racing/persistence/inmemory/InMemorySponsorshipRequestRepository';
|
||||
|
||||
// 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';
|
||||
@@ -51,6 +64,18 @@ export const SPONSORSHIP_PRICING_REPOSITORY_TOKEN = 'ISponsorshipPricingReposito
|
||||
export const SPONSORSHIP_REQUEST_REPOSITORY_TOKEN = 'ISponsorshipRequestRepository';
|
||||
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';
|
||||
@@ -64,6 +89,19 @@ 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
|
||||
@@ -111,27 +149,94 @@ export const SponsorProviders: Provider[] = [
|
||||
provide: LOGGER_TOKEN,
|
||||
useClass: ConsoleLogger,
|
||||
},
|
||||
// Presenters
|
||||
GetEntitySponsorshipPricingPresenter,
|
||||
GetSponsorsPresenter,
|
||||
CreateSponsorPresenter,
|
||||
GetSponsorDashboardPresenter,
|
||||
GetSponsorSponsorshipsPresenter,
|
||||
GetSponsorPresenter,
|
||||
GetPendingSponsorshipRequestsPresenter,
|
||||
AcceptSponsorshipRequestPresenter,
|
||||
RejectSponsorshipRequestPresenter,
|
||||
SponsorBillingPresenter,
|
||||
// Output ports
|
||||
{
|
||||
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: () => new GetSponsorshipPricingUseCase(),
|
||||
inject: [],
|
||||
useFactory: (output: UseCaseOutputPort<any>) => new GetSponsorshipPricingUseCase(output),
|
||||
inject: [GET_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GET_SPONSORS_USE_CASE_TOKEN,
|
||||
useFactory: (sponsorRepo: ISponsorRepository) => new GetSponsorsUseCase(sponsorRepo),
|
||||
inject: [SPONSOR_REPOSITORY_TOKEN],
|
||||
useFactory: (sponsorRepo: ISponsorRepository, output: UseCaseOutputPort<any>) => new GetSponsorsUseCase(sponsorRepo, output),
|
||||
inject: [SPONSOR_REPOSITORY_TOKEN, GET_SPONSORS_OUTPUT_PORT_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: CREATE_SPONSOR_USE_CASE_TOKEN,
|
||||
useFactory: (sponsorRepo: ISponsorRepository) => new CreateSponsorUseCase(sponsorRepo),
|
||||
inject: [SPONSOR_REPOSITORY_TOKEN],
|
||||
useFactory: (sponsorRepo: ISponsorRepository, logger: Logger, output: UseCaseOutputPort<any>) => new CreateSponsorUseCase(sponsorRepo, logger, output),
|
||||
inject: [SPONSOR_REPOSITORY_TOKEN, LOGGER_TOKEN, CREATE_SPONSOR_OUTPUT_PORT_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN,
|
||||
useFactory: (sponsorRepo: ISponsorRepository, seasonSponsorshipRepo: ISeasonSponsorshipRepository, seasonRepo: ISeasonRepository, leagueRepo: ILeagueRepository, leagueMembershipRepo: ILeagueMembershipRepository, raceRepo: IRaceRepository) =>
|
||||
new GetSponsorDashboardUseCase(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],
|
||||
useFactory: (
|
||||
sponsorRepo: ISponsorRepository,
|
||||
seasonSponsorshipRepo: ISeasonSponsorshipRepository,
|
||||
seasonRepo: ISeasonRepository,
|
||||
leagueRepo: ILeagueRepository,
|
||||
leagueMembershipRepo: ILeagueMembershipRepository,
|
||||
raceRepo: IRaceRepository,
|
||||
output: UseCaseOutputPort<any>,
|
||||
) => new GetSponsorDashboardUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo, output),
|
||||
inject: [
|
||||
SPONSOR_REPOSITORY_TOKEN,
|
||||
SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
|
||||
SEASON_REPOSITORY_TOKEN,
|
||||
LEAGUE_REPOSITORY_TOKEN,
|
||||
LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
|
||||
RACE_REPOSITORY_TOKEN,
|
||||
GET_SPONSOR_DASHBOARD_OUTPUT_PORT_TOKEN,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN,
|
||||
@@ -142,7 +247,8 @@ export const SponsorProviders: Provider[] = [
|
||||
leagueRepo: ILeagueRepository,
|
||||
leagueMembershipRepo: ILeagueMembershipRepository,
|
||||
raceRepo: IRaceRepository,
|
||||
) => new GetSponsorSponsorshipsUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo),
|
||||
output: UseCaseOutputPort<any>,
|
||||
) => new GetSponsorSponsorshipsUseCase(sponsorRepo, seasonSponsorshipRepo, seasonRepo, leagueRepo, leagueMembershipRepo, raceRepo, output),
|
||||
inject: [
|
||||
SPONSOR_REPOSITORY_TOKEN,
|
||||
SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
|
||||
@@ -150,41 +256,97 @@ export const SponsorProviders: Provider[] = [
|
||||
LEAGUE_REPOSITORY_TOKEN,
|
||||
LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
|
||||
RACE_REPOSITORY_TOKEN,
|
||||
GET_SPONSOR_SPONSORSHIPS_OUTPUT_PORT_TOKEN,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: GET_SPONSOR_BILLING_USE_CASE_TOKEN,
|
||||
useFactory: (paymentRepo: IPaymentRepository, seasonSponsorshipRepo: ISeasonSponsorshipRepository) =>
|
||||
new GetSponsorBillingUseCase(paymentRepo, seasonSponsorshipRepo),
|
||||
useFactory: (
|
||||
paymentRepo: IPaymentRepository,
|
||||
seasonSponsorshipRepo: ISeasonSponsorshipRepository,
|
||||
) => {
|
||||
return new GetSponsorBillingUseCase(paymentRepo, seasonSponsorshipRepo);
|
||||
},
|
||||
inject: ['IPaymentRepository', SEASON_SPONSORSHIP_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GET_ENTITY_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
|
||||
useFactory: (sponsorshipPricingRepo: ISponsorshipPricingRepository, sponsorshipRequestRepo: ISponsorshipRequestRepository, seasonSponsorshipRepo: ISeasonSponsorshipRepository, logger: Logger) =>
|
||||
new GetEntitySponsorshipPricingUseCase(sponsorshipPricingRepo, sponsorshipRequestRepo, seasonSponsorshipRepo, logger),
|
||||
inject: [SPONSORSHIP_PRICING_REPOSITORY_TOKEN, SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, SEASON_SPONSORSHIP_REPOSITORY_TOKEN, LOGGER_TOKEN],
|
||||
useFactory: (
|
||||
sponsorshipPricingRepo: ISponsorshipPricingRepository,
|
||||
sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
seasonSponsorshipRepo: ISeasonSponsorshipRepository,
|
||||
logger: Logger,
|
||||
output: UseCaseOutputPort<any>,
|
||||
) => new GetEntitySponsorshipPricingUseCase(sponsorshipPricingRepo, sponsorshipRequestRepo, seasonSponsorshipRepo, logger, output),
|
||||
inject: [
|
||||
SPONSORSHIP_PRICING_REPOSITORY_TOKEN,
|
||||
SPONSORSHIP_REQUEST_REPOSITORY_TOKEN,
|
||||
SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
|
||||
LOGGER_TOKEN,
|
||||
GET_ENTITY_SPONSORSHIP_PRICING_OUTPUT_PORT_TOKEN,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: GET_SPONSOR_USE_CASE_TOKEN,
|
||||
useFactory: (sponsorRepo: ISponsorRepository) => new GetSponsorUseCase(sponsorRepo),
|
||||
inject: [SPONSOR_REPOSITORY_TOKEN],
|
||||
useFactory: (sponsorRepo: ISponsorRepository, output: UseCaseOutputPort<any>) => new GetSponsorUseCase(sponsorRepo, output),
|
||||
inject: [SPONSOR_REPOSITORY_TOKEN, GET_SPONSOR_OUTPUT_PORT_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN,
|
||||
useFactory: (sponsorshipRequestRepo: ISponsorshipRequestRepository, sponsorRepo: ISponsorRepository) =>
|
||||
new GetPendingSponsorshipRequestsUseCase(sponsorshipRequestRepo, sponsorRepo),
|
||||
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, SPONSOR_REPOSITORY_TOKEN],
|
||||
useFactory: (
|
||||
sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
sponsorRepo: ISponsorRepository,
|
||||
output: UseCaseOutputPort<any>,
|
||||
) => new GetPendingSponsorshipRequestsUseCase(sponsorshipRequestRepo, sponsorRepo, output),
|
||||
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, SPONSOR_REPOSITORY_TOKEN, GET_PENDING_SPONSORSHIP_REQUESTS_OUTPUT_PORT_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
|
||||
useFactory: (sponsorshipRequestRepo: ISponsorshipRequestRepository, seasonSponsorshipRepo: ISeasonSponsorshipRepository, seasonRepo: ISeasonRepository, notificationService: NotificationService, paymentGateway: IPaymentGateway, walletRepository: IWalletRepository, leagueWalletRepository: ILeagueWalletRepository, logger: Logger) =>
|
||||
new AcceptSponsorshipRequestUseCase(sponsorshipRequestRepo, seasonSponsorshipRepo, seasonRepo, notificationService, paymentGateway, walletRepository, leagueWalletRepository, logger),
|
||||
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, SEASON_SPONSORSHIP_REPOSITORY_TOKEN, SEASON_REPOSITORY_TOKEN, 'INotificationService', 'IPaymentGateway', 'IWalletRepository', 'ILeagueWalletRepository', LOGGER_TOKEN],
|
||||
useFactory: (
|
||||
sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
seasonSponsorshipRepo: ISeasonSponsorshipRepository,
|
||||
seasonRepo: ISeasonRepository,
|
||||
notificationService: NotificationService,
|
||||
walletRepository: IWalletRepository,
|
||||
leagueWalletRepository: ILeagueWalletRepository,
|
||||
logger: Logger,
|
||||
output: UseCaseOutputPort<any>,
|
||||
) => {
|
||||
// Create a mock payment processor function
|
||||
const paymentProcessor = async (_input: any) => {
|
||||
return { success: true, transactionId: `txn_${Date.now()}` };
|
||||
};
|
||||
|
||||
return new AcceptSponsorshipRequestUseCase(
|
||||
sponsorshipRequestRepo,
|
||||
seasonSponsorshipRepo,
|
||||
seasonRepo,
|
||||
notificationService,
|
||||
paymentProcessor,
|
||||
walletRepository,
|
||||
leagueWalletRepository,
|
||||
logger,
|
||||
output
|
||||
);
|
||||
},
|
||||
inject: [
|
||||
SPONSORSHIP_REQUEST_REPOSITORY_TOKEN,
|
||||
SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
|
||||
SEASON_REPOSITORY_TOKEN,
|
||||
'INotificationService',
|
||||
'IWalletRepository',
|
||||
'ILeagueWalletRepository',
|
||||
LOGGER_TOKEN,
|
||||
ACCEPT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
|
||||
useFactory: (sponsorshipRequestRepo: ISponsorshipRequestRepository, logger: Logger) =>
|
||||
new RejectSponsorshipRequestUseCase(sponsorshipRequestRepo, logger),
|
||||
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, LOGGER_TOKEN],
|
||||
useFactory: (
|
||||
sponsorshipRequestRepo: ISponsorshipRequestRepository,
|
||||
logger: Logger,
|
||||
output: UseCaseOutputPort<any>,
|
||||
) => new RejectSponsorshipRequestUseCase(sponsorshipRequestRepo, logger, output),
|
||||
inject: [SPONSORSHIP_REQUEST_REPOSITORY_TOKEN, LOGGER_TOKEN, REJECT_SPONSORSHIP_REQUEST_OUTPUT_PORT_TOKEN],
|
||||
},
|
||||
];
|
||||
];
|
||||
@@ -1,15 +1,27 @@
|
||||
import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import type { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
|
||||
import type { GetSponsorsUseCase } from '@core/racing/application/use-cases/GetSponsorsUseCase';
|
||||
import type { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateSponsorUseCase';
|
||||
import type { GetSponsorDashboardUseCase } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
|
||||
import type { GetSponsorSponsorshipsUseCase } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
|
||||
import type { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsorUseCase';
|
||||
import type { GetPendingSponsorshipRequestsUseCase } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
|
||||
import type { GetSponsorBillingUseCase } from '@core/payments/application/use-cases/GetSponsorBillingUseCase';
|
||||
import type { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
|
||||
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 { 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';
|
||||
import type { RejectSponsorshipRequestUseCase } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import { beforeEach, describe, expect, it, Mock, vi } from 'vitest';
|
||||
import type { CreateSponsorInputDTO } from './dtos/CreateSponsorInputDTO';
|
||||
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', () => {
|
||||
@@ -23,8 +35,21 @@ describe('SponsorService', () => {
|
||||
let getPendingSponsorshipRequestsUseCase: { execute: Mock };
|
||||
let acceptSponsorshipRequestUseCase: { execute: Mock };
|
||||
let rejectSponsorshipRequestUseCase: { execute: Mock };
|
||||
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() };
|
||||
getSponsorsUseCase = { execute: vi.fn() };
|
||||
@@ -35,6 +60,7 @@ describe('SponsorService', () => {
|
||||
getPendingSponsorshipRequestsUseCase = { execute: vi.fn() };
|
||||
acceptSponsorshipRequestUseCase = { execute: vi.fn() };
|
||||
rejectSponsorshipRequestUseCase = { execute: vi.fn() };
|
||||
getSponsorBillingUseCase = { execute: vi.fn() };
|
||||
logger = {
|
||||
debug: vi.fn(),
|
||||
info: vi.fn(),
|
||||
@@ -42,6 +68,18 @@ 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,
|
||||
getSponsorsUseCase as unknown as GetSponsorsUseCase,
|
||||
@@ -52,28 +90,39 @@ describe('SponsorService', () => {
|
||||
getPendingSponsorshipRequestsUseCase as unknown as GetPendingSponsorshipRequestsUseCase,
|
||||
acceptSponsorshipRequestUseCase as unknown as AcceptSponsorshipRequestUseCase,
|
||||
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 presenter with pricing data on success', async () => {
|
||||
it('returns pricing data on success', async () => {
|
||||
const outputPort = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: [
|
||||
{ id: 'tier-gold', level: 'Gold', price: 500, currency: 'USD' },
|
||||
tiers: [
|
||||
{ name: 'Gold', price: 500, benefits: ['Main slot'] },
|
||||
],
|
||||
};
|
||||
getSponsorshipPricingUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const presenter = await service.getEntitySponsorshipPricing();
|
||||
const result = await service.getEntitySponsorshipPricing();
|
||||
|
||||
expect(presenter.viewModel).toEqual({
|
||||
expect(result).toEqual({
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: [
|
||||
{ id: 'tier-gold', level: 'Gold', price: 500, currency: 'USD' },
|
||||
{ id: 'Gold', level: 'Gold', price: 500, currency: 'USD' },
|
||||
],
|
||||
});
|
||||
});
|
||||
@@ -81,9 +130,9 @@ describe('SponsorService', () => {
|
||||
it('returns empty pricing on error', async () => {
|
||||
getSponsorshipPricingUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
|
||||
|
||||
const presenter = await service.getEntitySponsorshipPricing();
|
||||
const result = await service.getEntitySponsorshipPricing();
|
||||
|
||||
expect(presenter.viewModel).toEqual({
|
||||
expect(result).toEqual({
|
||||
entityType: 'season',
|
||||
entityId: '',
|
||||
pricing: [],
|
||||
@@ -92,82 +141,93 @@ describe('SponsorService', () => {
|
||||
});
|
||||
|
||||
describe('getSponsors', () => {
|
||||
it('returns sponsors in presenter on success', async () => {
|
||||
const outputPort = { sponsors: [{ id: 's1', name: 'S1', contactEmail: 's1@test', createdAt: new Date() }] };
|
||||
it('returns sponsors on success', async () => {
|
||||
const sponsors = [{ id: 's1', name: 'S1', contactEmail: 's1@test', createdAt: new Date() }];
|
||||
const outputPort = { sponsors };
|
||||
getSponsorsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const presenter = await service.getSponsors();
|
||||
const result = await service.getSponsors();
|
||||
|
||||
expect(presenter.viewModel).toEqual({ sponsors: outputPort.sponsors });
|
||||
expect(result).toEqual({ sponsors });
|
||||
});
|
||||
|
||||
it('returns empty list on error', async () => {
|
||||
getSponsorsUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
|
||||
|
||||
const presenter = await service.getSponsors();
|
||||
const result = await service.getSponsors();
|
||||
|
||||
expect(presenter.viewModel).toEqual({ sponsors: [] });
|
||||
expect(result).toEqual({ sponsors: [] });
|
||||
});
|
||||
});
|
||||
|
||||
describe('createSponsor', () => {
|
||||
it('returns created sponsor in presenter on success', async () => {
|
||||
const input = { name: 'Test', contactEmail: 'test@example.com' };
|
||||
const outputPort = {
|
||||
sponsor: {
|
||||
id: 's1',
|
||||
name: 'Test',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date(),
|
||||
},
|
||||
it('returns created sponsor on success', async () => {
|
||||
const input: CreateSponsorInputDTO = { name: 'Test', contactEmail: 'test@example.com' };
|
||||
const sponsor = {
|
||||
id: 's1',
|
||||
name: 'Test',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date(),
|
||||
};
|
||||
const outputPort = { sponsor };
|
||||
createSponsorUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const presenter = await service.createSponsor(input as any);
|
||||
const result = await service.createSponsor(input);
|
||||
|
||||
expect(presenter.viewModel).toEqual({ sponsor: outputPort.sponsor });
|
||||
expect(result).toEqual({ sponsor });
|
||||
});
|
||||
|
||||
it('throws on error', async () => {
|
||||
const input = { name: 'Test', contactEmail: 'test@example.com' };
|
||||
const input: CreateSponsorInputDTO = { name: 'Test', contactEmail: 'test@example.com' };
|
||||
createSponsorUseCase.execute.mockResolvedValue(
|
||||
Result.err({ code: 'VALIDATION_ERROR', details: { message: 'Invalid' } }),
|
||||
);
|
||||
|
||||
await expect(service.createSponsor(input as any)).rejects.toThrow('Invalid');
|
||||
await expect(service.createSponsor(input)).rejects.toThrow('Invalid');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorDashboard', () => {
|
||||
it('returns dashboard in presenter on success', async () => {
|
||||
const params = { sponsorId: 's1' };
|
||||
it('returns dashboard on success', async () => {
|
||||
const params: GetSponsorDashboardInput = { sponsorId: 's1' };
|
||||
const outputPort = {
|
||||
sponsorId: 's1',
|
||||
sponsorName: 'S1',
|
||||
metrics: {} as any,
|
||||
metrics: {
|
||||
impressions: 0,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 0,
|
||||
viewersChange: 0,
|
||||
races: 0,
|
||||
drivers: 0,
|
||||
exposure: 0,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {} as any,
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
};
|
||||
getSponsorDashboardUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const presenter = await service.getSponsorDashboard(params as any);
|
||||
const result = await service.getSponsorDashboard(params);
|
||||
|
||||
expect(presenter.viewModel).toEqual(outputPort);
|
||||
expect(result).toEqual(outputPort);
|
||||
});
|
||||
|
||||
it('returns null in presenter on error', async () => {
|
||||
const params = { sponsorId: 's1' };
|
||||
it('throws on error', async () => {
|
||||
const params: GetSponsorDashboardInput = { sponsorId: 's1' };
|
||||
getSponsorDashboardUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
|
||||
|
||||
const presenter = await service.getSponsorDashboard(params as any);
|
||||
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
await expect(service.getSponsorDashboard(params)).rejects.toThrow('Sponsor dashboard not found');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorSponsorships', () => {
|
||||
it('returns sponsorships in presenter on success', async () => {
|
||||
const params = { sponsorId: 's1' };
|
||||
it('returns sponsorships on success', async () => {
|
||||
const params: GetSponsorSponsorshipsInput = { sponsorId: 's1' };
|
||||
const outputPort = {
|
||||
sponsorId: 's1',
|
||||
sponsorName: 'S1',
|
||||
@@ -182,46 +242,43 @@ describe('SponsorService', () => {
|
||||
};
|
||||
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const presenter = await service.getSponsorSponsorships(params as any);
|
||||
const result = await service.getSponsorSponsorships(params);
|
||||
|
||||
expect(presenter.viewModel).toEqual(outputPort);
|
||||
expect(result).toEqual(outputPort);
|
||||
});
|
||||
|
||||
it('returns null in presenter on error', async () => {
|
||||
const params = { sponsorId: 's1' };
|
||||
it('throws on error', async () => {
|
||||
const params: GetSponsorSponsorshipsInput = { sponsorId: 's1' };
|
||||
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(
|
||||
Result.err({ code: 'REPOSITORY_ERROR' }),
|
||||
);
|
||||
|
||||
const presenter = await service.getSponsorSponsorships(params as any);
|
||||
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
await expect(service.getSponsorSponsorships(params)).rejects.toThrow('Sponsor sponsorships not found');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsor', () => {
|
||||
it('returns sponsor in presenter when found', async () => {
|
||||
it('returns sponsor when found', async () => {
|
||||
const sponsorId = 's1';
|
||||
const output = { sponsor: { id: sponsorId, name: 'S1' } };
|
||||
const sponsor = { id: sponsorId, name: 'S1' };
|
||||
const output = { sponsor };
|
||||
getSponsorUseCase.execute.mockResolvedValue(Result.ok(output));
|
||||
|
||||
const presenter = await service.getSponsor(sponsorId);
|
||||
const result = await service.getSponsor(sponsorId);
|
||||
|
||||
expect(presenter.viewModel).toEqual({ sponsor: output.sponsor });
|
||||
expect(result).toEqual({ sponsor });
|
||||
});
|
||||
|
||||
it('returns null in presenter when not found', async () => {
|
||||
it('throws when not found', async () => {
|
||||
const sponsorId = 's1';
|
||||
getSponsorUseCase.execute.mockResolvedValue(Result.ok(null));
|
||||
|
||||
const presenter = await service.getSponsor(sponsorId);
|
||||
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
await expect(service.getSponsor(sponsorId)).rejects.toThrow('Sponsor not found');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPendingSponsorshipRequests', () => {
|
||||
it('returns requests in presenter on success', async () => {
|
||||
it('returns requests on success', async () => {
|
||||
const params = { entityType: 'season' as const, entityId: 'season-1' };
|
||||
const outputPort = {
|
||||
entityType: 'season',
|
||||
@@ -231,9 +288,9 @@ describe('SponsorService', () => {
|
||||
};
|
||||
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const presenter = await service.getPendingSponsorshipRequests(params);
|
||||
const result = await service.getPendingSponsorshipRequests(params);
|
||||
|
||||
expect(presenter.viewModel).toEqual(outputPort);
|
||||
expect(result).toEqual(outputPort);
|
||||
});
|
||||
|
||||
it('returns empty result on error', async () => {
|
||||
@@ -242,9 +299,9 @@ describe('SponsorService', () => {
|
||||
Result.err({ code: 'REPOSITORY_ERROR' }),
|
||||
);
|
||||
|
||||
const presenter = await service.getPendingSponsorshipRequests(params);
|
||||
const result = await service.getPendingSponsorshipRequests(params);
|
||||
|
||||
expect(presenter.viewModel).toEqual({
|
||||
expect(result).toEqual({
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
requests: [],
|
||||
@@ -253,8 +310,8 @@ describe('SponsorService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('acceptSponsorshipRequest', () => {
|
||||
it('returns accept result in presenter on success', async () => {
|
||||
describe('SponsorshipRequest', () => {
|
||||
it('returns accept result on success', async () => {
|
||||
const requestId = 'r1';
|
||||
const respondedBy = 'u1';
|
||||
const outputPort = {
|
||||
@@ -267,100 +324,114 @@ describe('SponsorService', () => {
|
||||
};
|
||||
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const presenter = await service.acceptSponsorshipRequest(requestId, respondedBy);
|
||||
const result = await service.acceptSponsorshipRequest(requestId, respondedBy);
|
||||
|
||||
expect(presenter.viewModel).toEqual(outputPort);
|
||||
expect(result).toEqual(outputPort);
|
||||
});
|
||||
|
||||
it('returns null in presenter on error', async () => {
|
||||
it('throws on error', async () => {
|
||||
const requestId = 'r1';
|
||||
const respondedBy = 'u1';
|
||||
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(
|
||||
Result.err({ code: 'SPONSORSHIP_REQUEST_NOT_FOUND' }),
|
||||
);
|
||||
|
||||
const presenter = await service.acceptSponsorshipRequest(requestId, respondedBy);
|
||||
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
await expect(service.acceptSponsorshipRequest(requestId, respondedBy)).rejects.toThrow('Accept sponsorship request failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('rejectSponsorshipRequest', () => {
|
||||
it('returns reject result in presenter on success', async () => {
|
||||
it('returns reject result on success', async () => {
|
||||
const requestId = 'r1';
|
||||
const respondedBy = 'u1';
|
||||
const reason = 'Not interested';
|
||||
const output = {
|
||||
requestId,
|
||||
status: 'rejected' as const,
|
||||
rejectedAt: new Date(),
|
||||
reason,
|
||||
respondedAt: new Date(),
|
||||
rejectionReason: reason,
|
||||
};
|
||||
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(output));
|
||||
|
||||
const presenter = await service.rejectSponsorshipRequest(requestId, respondedBy, reason);
|
||||
const result = await service.rejectSponsorshipRequest(requestId, respondedBy, reason);
|
||||
|
||||
expect(presenter.viewModel).toEqual(output);
|
||||
expect(result).toEqual(output);
|
||||
});
|
||||
|
||||
it('returns null in presenter on error', async () => {
|
||||
it('throws on error', async () => {
|
||||
const requestId = 'r1';
|
||||
const respondedBy = 'u1';
|
||||
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(
|
||||
Result.err({ code: 'SPONSORSHIP_REQUEST_NOT_FOUND' }),
|
||||
);
|
||||
|
||||
const presenter = await service.rejectSponsorshipRequest(requestId, respondedBy);
|
||||
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
await expect(service.rejectSponsorshipRequest(requestId, respondedBy)).rejects.toThrow('Reject sponsorship request failed');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorBilling', () => {
|
||||
it('returns mock billing data in presenter', async () => {
|
||||
const presenter = await service.getSponsorBilling('s1');
|
||||
it('returns billing data', async () => {
|
||||
// Mock the use case to set up the presenter
|
||||
getSponsorBillingUseCase.execute.mockImplementation(async () => {
|
||||
sponsorBillingPresenter.present({
|
||||
paymentMethods: [],
|
||||
invoices: [],
|
||||
stats: {
|
||||
totalSpent: 0,
|
||||
pendingAmount: 0,
|
||||
nextPaymentDate: '',
|
||||
nextPaymentAmount: 0,
|
||||
activeSponsorships: 0,
|
||||
averageMonthlySpend: 0,
|
||||
},
|
||||
});
|
||||
return Result.ok(undefined);
|
||||
});
|
||||
|
||||
expect(presenter.viewModel).not.toBeNull();
|
||||
expect(presenter.viewModel?.paymentMethods).toBeInstanceOf(Array);
|
||||
expect(presenter.viewModel?.invoices).toBeInstanceOf(Array);
|
||||
expect(presenter.viewModel?.stats).toBeDefined();
|
||||
const result = await service.getSponsorBilling('s1');
|
||||
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.paymentMethods).toBeInstanceOf(Array);
|
||||
expect(result.invoices).toBeInstanceOf(Array);
|
||||
expect(result.stats).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAvailableLeagues', () => {
|
||||
it('returns mock leagues in presenter', async () => {
|
||||
const presenter = await service.getAvailableLeagues();
|
||||
it('returns mock leagues', async () => {
|
||||
const result = await service.getAvailableLeagues();
|
||||
|
||||
expect(presenter.viewModel).not.toBeNull();
|
||||
expect(presenter.viewModel?.length).toBeGreaterThan(0);
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.viewModel).not.toBeNull();
|
||||
expect(result.viewModel?.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLeagueDetail', () => {
|
||||
it('returns league detail in presenter', async () => {
|
||||
const presenter = await service.getLeagueDetail('league-1');
|
||||
it('returns league detail', async () => {
|
||||
const result = await service.getLeagueDetail('league-1');
|
||||
|
||||
expect(presenter.viewModel).not.toBeNull();
|
||||
expect(presenter.viewModel?.league.id).toBe('league-1');
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.viewModel?.league.id).toBe('league-1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorSettings', () => {
|
||||
it('returns settings in presenter', async () => {
|
||||
const presenter = await service.getSponsorSettings('s1');
|
||||
it('returns settings', async () => {
|
||||
const result = await service.getSponsorSettings('s1');
|
||||
|
||||
expect(presenter.viewModel).not.toBeNull();
|
||||
expect(presenter.viewModel?.profile).toBeDefined();
|
||||
expect(presenter.viewModel?.notifications).toBeDefined();
|
||||
expect(presenter.viewModel?.privacy).toBeDefined();
|
||||
expect(result).not.toBeNull();
|
||||
expect(result.viewModel?.profile).toBeDefined();
|
||||
expect(result.viewModel?.notifications).toBeDefined();
|
||||
expect(result.viewModel?.privacy).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateSponsorSettings', () => {
|
||||
it('returns success result in presenter', async () => {
|
||||
const presenter = await service.updateSponsorSettings('s1', {});
|
||||
it('returns success result', async () => {
|
||||
const result = await service.updateSponsorSettings('s1', {});
|
||||
|
||||
expect(presenter.viewModel).toEqual({ success: true });
|
||||
expect(result.viewModel).toEqual({ success: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,12 +1,14 @@
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import { CreateSponsorInputDTO } from './dtos/CreateSponsorInputDTO';
|
||||
import { CreateSponsorOutputDTO } from './dtos/CreateSponsorOutputDTO';
|
||||
import { GetSponsorDashboardQueryParamsDTO } from './dtos/GetSponsorDashboardQueryParamsDTO';
|
||||
import { SponsorDashboardDTO } from './dtos/SponsorDashboardDTO';
|
||||
import { GetSponsorSponsorshipsQueryParamsDTO } from './dtos/GetSponsorSponsorshipsQueryParamsDTO';
|
||||
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 { SponsorSponsorshipsDTO } from './dtos/SponsorSponsorshipsDTO';
|
||||
import { GetSponsorOutputDTO } from './dtos/GetSponsorOutputDTO';
|
||||
import { GetPendingSponsorshipRequestsOutputDTO } from './dtos/GetPendingSponsorshipRequestsOutputDTO';
|
||||
import { GetEntitySponsorshipPricingResultDTO } from './dtos/GetEntitySponsorshipPricingResultDTO';
|
||||
import { GetSponsorsOutputDTO } from './dtos/GetSponsorsOutputDTO';
|
||||
import { AvailableLeagueDTO } from './dtos/AvailableLeagueDTO';
|
||||
import { LeagueDetailDTO } from './dtos/LeagueDetailDTO';
|
||||
import { DriverDTO } from './dtos/DriverDTO';
|
||||
@@ -14,6 +16,9 @@ import { RaceDTO } from './dtos/RaceDTO';
|
||||
import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
|
||||
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
|
||||
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
|
||||
import { PaymentMethodDTO } from './dtos/PaymentMethodDTO';
|
||||
import { InvoiceDTO } from './dtos/InvoiceDTO';
|
||||
import { BillingStatsDTO } from './dtos/BillingStatsDTO';
|
||||
|
||||
// Use cases
|
||||
import { GetSponsorshipPricingUseCase } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
|
||||
@@ -24,7 +29,7 @@ import { GetSponsorSponsorshipsUseCase } from '@core/racing/application/use-case
|
||||
import { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsorUseCase';
|
||||
import {
|
||||
GetPendingSponsorshipRequestsUseCase,
|
||||
GetPendingSponsorshipRequestsDTO,
|
||||
GetPendingSponsorshipRequestsInput,
|
||||
} 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';
|
||||
@@ -48,6 +53,8 @@ import { AvailableLeaguesPresenter } from './presenters/AvailableLeaguesPresente
|
||||
import { LeagueDetailPresenter } from './presenters/LeagueDetailPresenter';
|
||||
import { SponsorSettingsPresenter } from './presenters/SponsorSettingsPresenter';
|
||||
import { SponsorSettingsUpdatePresenter } from './presenters/SponsorSettingsUpdatePresenter';
|
||||
import { AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter';
|
||||
import type { RejectSponsorshipRequestResult } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
|
||||
// Tokens
|
||||
import {
|
||||
@@ -61,6 +68,16 @@ import {
|
||||
ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
|
||||
REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
|
||||
LOGGER_TOKEN,
|
||||
GET_ENTITY_SPONSORSHIP_PRICING_PRESENTER_TOKEN,
|
||||
GET_SPONSORS_PRESENTER_TOKEN,
|
||||
CREATE_SPONSOR_PRESENTER_TOKEN,
|
||||
GET_SPONSOR_DASHBOARD_PRESENTER_TOKEN,
|
||||
GET_SPONSOR_SPONSORSHIPS_PRESENTER_TOKEN,
|
||||
GET_SPONSOR_PRESENTER_TOKEN,
|
||||
GET_PENDING_SPONSORSHIP_REQUESTS_PRESENTER_TOKEN,
|
||||
ACCEPT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN,
|
||||
REJECT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN,
|
||||
GET_SPONSOR_BILLING_PRESENTER_TOKEN,
|
||||
} from './SponsorProviders';
|
||||
|
||||
@Injectable()
|
||||
@@ -88,194 +105,152 @@ export class SponsorService {
|
||||
private readonly getSponsorBillingUseCase: GetSponsorBillingUseCase,
|
||||
@Inject(LOGGER_TOKEN)
|
||||
private readonly logger: Logger,
|
||||
// Injected presenters
|
||||
@Inject(GET_ENTITY_SPONSORSHIP_PRICING_PRESENTER_TOKEN)
|
||||
private readonly getEntitySponsorshipPricingPresenter: GetEntitySponsorshipPricingPresenter,
|
||||
@Inject(GET_SPONSORS_PRESENTER_TOKEN)
|
||||
private readonly getSponsorsPresenter: GetSponsorsPresenter,
|
||||
@Inject(CREATE_SPONSOR_PRESENTER_TOKEN)
|
||||
private readonly createSponsorPresenter: CreateSponsorPresenter,
|
||||
@Inject(GET_SPONSOR_DASHBOARD_PRESENTER_TOKEN)
|
||||
private readonly getSponsorDashboardPresenter: GetSponsorDashboardPresenter,
|
||||
@Inject(GET_SPONSOR_SPONSORSHIPS_PRESENTER_TOKEN)
|
||||
private readonly getSponsorSponsorshipsPresenter: GetSponsorSponsorshipsPresenter,
|
||||
@Inject(GET_SPONSOR_PRESENTER_TOKEN)
|
||||
private readonly getSponsorPresenter: GetSponsorPresenter,
|
||||
@Inject(GET_PENDING_SPONSORSHIP_REQUESTS_PRESENTER_TOKEN)
|
||||
private readonly getPendingSponsorshipRequestsPresenter: GetPendingSponsorshipRequestsPresenter,
|
||||
@Inject(ACCEPT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN)
|
||||
private readonly acceptSponsorshipRequestPresenter: AcceptSponsorshipRequestPresenter,
|
||||
@Inject(REJECT_SPONSORSHIP_REQUEST_PRESENTER_TOKEN)
|
||||
private readonly rejectSponsorshipRequestPresenter: RejectSponsorshipRequestPresenter,
|
||||
@Inject(GET_SPONSOR_BILLING_PRESENTER_TOKEN)
|
||||
private readonly sponsorBillingPresenter: SponsorBillingPresenter,
|
||||
) {}
|
||||
|
||||
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingPresenter> {
|
||||
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDTO> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsorship pricing.');
|
||||
|
||||
const presenter = new GetEntitySponsorshipPricingPresenter();
|
||||
const result = await this.getSponsorshipPricingUseCase.execute();
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to fetch sponsorship pricing.', result.error);
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
await this.getSponsorshipPricingUseCase.execute({});
|
||||
return this.getEntitySponsorshipPricingPresenter.viewModel;
|
||||
}
|
||||
|
||||
async getSponsors(): Promise<GetSponsorsOutputDTO> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsors.');
|
||||
|
||||
const presenter = new GetSponsorsPresenter();
|
||||
const result = await this.getSponsorsUseCase.execute();
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
return presenter.responseModel;
|
||||
await this.getSponsorsUseCase.execute();
|
||||
return this.getSponsorsPresenter.responseModel;
|
||||
}
|
||||
|
||||
async createSponsor(input: CreateSponsorInputDTO): Promise<CreateSponsorPresenter> {
|
||||
async createSponsor(input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDTO> {
|
||||
this.logger.debug('[SponsorService] Creating sponsor.', { input });
|
||||
|
||||
const presenter = new CreateSponsorPresenter();
|
||||
const result = await this.createSponsorUseCase.execute(input);
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to create sponsor.', result.error);
|
||||
throw new Error(result.error.details?.message || 'Failed to create sponsor');
|
||||
}
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
await this.createSponsorUseCase.execute(input);
|
||||
return this.createSponsorPresenter.viewModel;
|
||||
}
|
||||
|
||||
async getSponsorDashboard(
|
||||
params: GetSponsorDashboardQueryParamsDTO,
|
||||
): Promise<GetSponsorDashboardPresenter> {
|
||||
): Promise<SponsorDashboardDTO> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsor dashboard.', { params });
|
||||
|
||||
const presenter = new GetSponsorDashboardPresenter();
|
||||
const result = await this.getSponsorDashboardUseCase.execute(params);
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to fetch sponsor dashboard.', result.error);
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
await this.getSponsorDashboardUseCase.execute(params);
|
||||
const result = this.getSponsorDashboardPresenter.viewModel;
|
||||
if (!result) {
|
||||
throw new Error('Sponsor dashboard not found');
|
||||
}
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
return result;
|
||||
}
|
||||
|
||||
async getSponsorSponsorships(
|
||||
params: GetSponsorSponsorshipsQueryParamsDTO,
|
||||
): Promise<GetSponsorSponsorshipsPresenter> {
|
||||
): Promise<SponsorSponsorshipsDTO> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsor sponsorships.', { params });
|
||||
|
||||
const presenter = new GetSponsorSponsorshipsPresenter();
|
||||
const result = await this.getSponsorSponsorshipsUseCase.execute(params);
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to fetch sponsor sponsorships.', result.error);
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
await this.getSponsorSponsorshipsUseCase.execute(params);
|
||||
const result = this.getSponsorSponsorshipsPresenter.viewModel;
|
||||
if (!result) {
|
||||
throw new Error('Sponsor sponsorships not found');
|
||||
}
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
return result;
|
||||
}
|
||||
|
||||
async getSponsor(sponsorId: string): Promise<GetSponsorPresenter> {
|
||||
async getSponsor(sponsorId: string): Promise<GetSponsorOutputDTO> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsor.', { sponsorId });
|
||||
|
||||
const presenter = new GetSponsorPresenter();
|
||||
const result = await this.getSponsorUseCase.execute({ sponsorId });
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to fetch sponsor.', result.error);
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
await this.getSponsorUseCase.execute({ sponsorId });
|
||||
const result = this.getSponsorPresenter.viewModel;
|
||||
if (!result) {
|
||||
throw new Error('Sponsor not found');
|
||||
}
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
return result;
|
||||
}
|
||||
|
||||
async getPendingSponsorshipRequests(params: {
|
||||
entityType: SponsorableEntityType;
|
||||
entityId: string;
|
||||
}): Promise<GetPendingSponsorshipRequestsPresenter> {
|
||||
}): Promise<GetPendingSponsorshipRequestsOutputDTO> {
|
||||
this.logger.debug('[SponsorService] Fetching pending sponsorship requests.', { params });
|
||||
|
||||
const presenter = new GetPendingSponsorshipRequestsPresenter();
|
||||
const result = await this.getPendingSponsorshipRequestsUseCase.execute(
|
||||
params as GetPendingSponsorshipRequestsDTO,
|
||||
await this.getPendingSponsorshipRequestsUseCase.execute(
|
||||
params as GetPendingSponsorshipRequestsInput,
|
||||
);
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to fetch pending sponsorship requests.', result.error);
|
||||
presenter.present({
|
||||
entityType: params.entityType,
|
||||
entityId: params.entityId,
|
||||
requests: [],
|
||||
totalCount: 0,
|
||||
});
|
||||
return presenter;
|
||||
const result = this.getPendingSponsorshipRequestsPresenter.viewModel;
|
||||
if (!result) {
|
||||
throw new Error('Pending sponsorship requests not found');
|
||||
}
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
return result;
|
||||
}
|
||||
|
||||
async acceptSponsorshipRequest(
|
||||
requestId: string,
|
||||
respondedBy: string,
|
||||
): Promise<AcceptSponsorshipRequestPresenter> {
|
||||
): Promise<AcceptSponsorshipRequestResultViewModel> {
|
||||
this.logger.debug('[SponsorService] Accepting sponsorship request.', {
|
||||
requestId,
|
||||
respondedBy,
|
||||
});
|
||||
|
||||
const presenter = new AcceptSponsorshipRequestPresenter();
|
||||
const result = await this.acceptSponsorshipRequestUseCase.execute({
|
||||
await this.acceptSponsorshipRequestUseCase.execute({
|
||||
requestId,
|
||||
respondedBy,
|
||||
} as AcceptSponsorshipRequestInputDTO);
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to accept sponsorship request.', result.error);
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
});
|
||||
const result = this.acceptSponsorshipRequestPresenter.viewModel;
|
||||
if (!result) {
|
||||
throw new Error('Accept sponsorship request failed');
|
||||
}
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
return result;
|
||||
}
|
||||
|
||||
async rejectSponsorshipRequest(
|
||||
requestId: string,
|
||||
respondedBy: string,
|
||||
reason?: string,
|
||||
): Promise<RejectSponsorshipRequestPresenter> {
|
||||
): Promise<RejectSponsorshipRequestResult> {
|
||||
this.logger.debug('[SponsorService] Rejecting sponsorship request.', {
|
||||
requestId,
|
||||
respondedBy,
|
||||
reason,
|
||||
});
|
||||
|
||||
const presenter = new RejectSponsorshipRequestPresenter();
|
||||
const result = await this.rejectSponsorshipRequestUseCase.execute({
|
||||
const input: { requestId: string; respondedBy: string; reason?: string } = {
|
||||
requestId,
|
||||
respondedBy,
|
||||
reason,
|
||||
} as RejectSponsorshipRequestInputDTO);
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to reject sponsorship request.', result.error);
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
};
|
||||
if (reason !== undefined) {
|
||||
input.reason = reason;
|
||||
}
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
await this.rejectSponsorshipRequestUseCase.execute(input);
|
||||
const result = this.rejectSponsorshipRequestPresenter.viewModel;
|
||||
if (!result) {
|
||||
throw new Error('Reject sponsorship request failed');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async getSponsorBilling(sponsorId: string): Promise<GetSponsorBillingPresenter> {
|
||||
async getSponsorBilling(sponsorId: string): Promise<{
|
||||
paymentMethods: PaymentMethodDTO[];
|
||||
invoices: InvoiceDTO[];
|
||||
stats: BillingStatsDTO;
|
||||
}> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsor billing.', { sponsorId });
|
||||
|
||||
const result = await this.getSponsorBillingUseCase.execute({ sponsorId });
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to fetch sponsor billing.', result.error);
|
||||
throw new Error(result.error.details?.message || 'Failed to fetch sponsor billing');
|
||||
await this.getSponsorBillingUseCase.execute({ sponsorId });
|
||||
const result = this.sponsorBillingPresenter.viewModel;
|
||||
if (!result) {
|
||||
throw new Error('Sponsor billing not found');
|
||||
}
|
||||
|
||||
const presenter = new GetSponsorBillingPresenter();
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
return result;
|
||||
}
|
||||
|
||||
async getAvailableLeagues(): Promise<AvailableLeaguesPresenter> {
|
||||
@@ -426,7 +401,7 @@ export class SponsorService {
|
||||
website: 'https://acme-racing.com',
|
||||
description:
|
||||
'Premium sim racing equipment and accessories for competitive drivers.',
|
||||
logoUrl: null,
|
||||
logoUrl: '',
|
||||
industry: 'Racing Equipment',
|
||||
address: {
|
||||
street: '123 Racing Boulevard',
|
||||
@@ -479,4 +454,4 @@ export class SponsorService {
|
||||
presenter.present({ success: true });
|
||||
return presenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,19 +4,19 @@ import { IsString, IsEnum, IsOptional, IsNumber } from 'class-validator';
|
||||
export class ActivityItemDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty({ enum: ['race', 'league', 'team', 'driver', 'platform'] })
|
||||
@IsEnum(['race', 'league', 'team', 'driver', 'platform'])
|
||||
type: 'race' | 'league' | 'team' | 'driver' | 'platform';
|
||||
type: 'race' | 'league' | 'team' | 'driver' | 'platform' = 'race';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
message: string;
|
||||
message: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
time: string;
|
||||
time: string = '';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsEnum, IsNumber, IsBoolean, IsOptional, IsDateString } from 'class-validator';
|
||||
import { IsString, IsEnum, IsNumber, IsOptional, IsDateString } from 'class-validator';
|
||||
|
||||
export class AvailableLeagueDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
name: string;
|
||||
name: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
game: string;
|
||||
game: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
drivers: number;
|
||||
drivers: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
avgViewsPerRace: number;
|
||||
avgViewsPerRace: number = 0;
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
mainSponsorSlot: {
|
||||
available: boolean;
|
||||
price: number;
|
||||
};
|
||||
} = { available: false, price: 0 };
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
secondarySlots: {
|
||||
available: number;
|
||||
total: number;
|
||||
price: number;
|
||||
};
|
||||
} = { available: 0, total: 0, price: 0 };
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
rating: number;
|
||||
rating: number = 0;
|
||||
|
||||
@ApiProperty({ enum: ['premium', 'standard', 'starter'] })
|
||||
@IsEnum(['premium', 'standard', 'starter'])
|
||||
tier: 'premium' | 'standard' | 'starter';
|
||||
tier: 'premium' | 'standard' | 'starter' = 'standard';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@@ -50,9 +50,9 @@ export class AvailableLeagueDTO {
|
||||
|
||||
@ApiProperty({ enum: ['active', 'upcoming', 'completed'] })
|
||||
@IsEnum(['active', 'upcoming', 'completed'])
|
||||
seasonStatus: 'active' | 'upcoming' | 'completed';
|
||||
seasonStatus: 'active' | 'upcoming' | 'completed' = 'active';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
description: string;
|
||||
description: string = '';
|
||||
}
|
||||
@@ -4,25 +4,25 @@ import { IsNumber, IsDateString } from 'class-validator';
|
||||
export class BillingStatsDTO {
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
totalSpent: number;
|
||||
totalSpent: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
pendingAmount: number;
|
||||
pendingAmount: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsDateString()
|
||||
nextPaymentDate: string;
|
||||
nextPaymentDate: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
nextPaymentAmount: number;
|
||||
nextPaymentAmount: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
activeSponsorships: number;
|
||||
activeSponsorships: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
averageMonthlySpend: number;
|
||||
averageMonthlySpend: number = 0;
|
||||
}
|
||||
@@ -3,5 +3,5 @@ import { SponsorDTO } from './SponsorDTO';
|
||||
|
||||
export class CreateSponsorOutputDTO {
|
||||
@ApiProperty({ type: SponsorDTO })
|
||||
sponsor: SponsorDTO;
|
||||
sponsor: SponsorDTO = new SponsorDTO();
|
||||
}
|
||||
@@ -4,29 +4,29 @@ import { IsString, IsNumber } from 'class-validator';
|
||||
export class DriverDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
name: string;
|
||||
name: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
country: string;
|
||||
country: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
position: number;
|
||||
position: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
races: number;
|
||||
races: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
impressions: number;
|
||||
impressions: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
team: string;
|
||||
team: string = '';
|
||||
}
|
||||
@@ -3,11 +3,11 @@ import { SponsorshipPricingItemDTO } from './SponsorshipPricingItemDTO';
|
||||
|
||||
export class GetEntitySponsorshipPricingResultDTO {
|
||||
@ApiProperty()
|
||||
entityType: string;
|
||||
entityType: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
entityId: string;
|
||||
entityId: string = '';
|
||||
|
||||
@ApiProperty({ type: [SponsorshipPricingItemDTO] })
|
||||
pricing: SponsorshipPricingItemDTO[];
|
||||
pricing: SponsorshipPricingItemDTO[] = [];
|
||||
}
|
||||
@@ -3,14 +3,14 @@ import { SponsorshipRequestDTO } from './SponsorshipRequestDTO';
|
||||
|
||||
export class GetPendingSponsorshipRequestsOutputDTO {
|
||||
@ApiProperty()
|
||||
entityType: string;
|
||||
entityType: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
entityId: string;
|
||||
entityId: string = '';
|
||||
|
||||
@ApiProperty({ type: [SponsorshipRequestDTO] })
|
||||
requests: SponsorshipRequestDTO[];
|
||||
requests: SponsorshipRequestDTO[] = [];
|
||||
|
||||
@ApiProperty()
|
||||
totalCount: number;
|
||||
totalCount: number = 0;
|
||||
}
|
||||
@@ -4,5 +4,5 @@ import { IsString } from 'class-validator';
|
||||
export class GetSponsorDashboardQueryParamsDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
sponsorId: string;
|
||||
sponsorId: string = '';
|
||||
}
|
||||
@@ -3,5 +3,5 @@ import { SponsorDTO } from './SponsorDTO';
|
||||
|
||||
export class GetSponsorOutputDTO {
|
||||
@ApiProperty({ type: SponsorDTO })
|
||||
sponsor: SponsorDTO;
|
||||
sponsor: SponsorDTO = new SponsorDTO();
|
||||
}
|
||||
@@ -4,5 +4,5 @@ import { IsString } from 'class-validator';
|
||||
export class GetSponsorSponsorshipsQueryParamsDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
sponsorId: string;
|
||||
sponsorId: string = '';
|
||||
}
|
||||
@@ -3,5 +3,5 @@ import { SponsorDTO } from './SponsorDTO';
|
||||
|
||||
export class GetSponsorsOutputDTO {
|
||||
@ApiProperty({ type: [SponsorDTO] })
|
||||
sponsors: SponsorDTO[];
|
||||
sponsors: SponsorDTO[] = [];
|
||||
}
|
||||
@@ -4,45 +4,45 @@ import { IsString, IsEnum, IsNumber, IsDateString } from 'class-validator';
|
||||
export class InvoiceDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
invoiceNumber: string;
|
||||
invoiceNumber: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsDateString()
|
||||
date: string;
|
||||
date: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsDateString()
|
||||
dueDate: string;
|
||||
dueDate: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
amount: number;
|
||||
amount: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
vatAmount: number;
|
||||
vatAmount: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
totalAmount: number;
|
||||
totalAmount: number = 0;
|
||||
|
||||
@ApiProperty({ enum: ['paid', 'pending', 'overdue', 'failed'] })
|
||||
@IsEnum(['paid', 'pending', 'overdue', 'failed'])
|
||||
status: 'paid' | 'pending' | 'overdue' | 'failed';
|
||||
status: 'paid' | 'pending' | 'overdue' | 'failed' = 'pending';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
description: string;
|
||||
description: string = '';
|
||||
|
||||
@ApiProperty({ enum: ['league', 'team', 'driver', 'race', 'platform'] })
|
||||
@IsEnum(['league', 'team', 'driver', 'race', 'platform'])
|
||||
sponsorshipType: 'league' | 'team' | 'driver' | 'race' | 'platform';
|
||||
sponsorshipType: 'league' | 'team' | 'driver' | 'race' | 'platform' = 'league';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
pdfUrl: string;
|
||||
pdfUrl: string = '';
|
||||
}
|
||||
@@ -1,68 +1,68 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsEnum, IsNumber, IsDateString, IsOptional } from 'class-validator';
|
||||
import { IsString, IsEnum, IsNumber, IsOptional } from 'class-validator';
|
||||
|
||||
export class LeagueDetailDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
name: string;
|
||||
name: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
game: string;
|
||||
game: string = '';
|
||||
|
||||
@ApiProperty({ enum: ['premium', 'standard', 'starter'] })
|
||||
@IsEnum(['premium', 'standard', 'starter'])
|
||||
tier: 'premium' | 'standard' | 'starter';
|
||||
tier: 'premium' | 'standard' | 'starter' = 'standard';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
season: string;
|
||||
season: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
description: string;
|
||||
description: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
drivers: number;
|
||||
drivers: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
races: number;
|
||||
races: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
completedRaces: number;
|
||||
completedRaces: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
totalImpressions: number;
|
||||
totalImpressions: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
avgViewsPerRace: number;
|
||||
avgViewsPerRace: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
engagement: number;
|
||||
engagement: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
rating: number;
|
||||
rating: number = 0;
|
||||
|
||||
@ApiProperty({ enum: ['active', 'upcoming', 'completed'] })
|
||||
@IsEnum(['active', 'upcoming', 'completed'])
|
||||
seasonStatus: 'active' | 'upcoming' | 'completed';
|
||||
seasonStatus: 'active' | 'upcoming' | 'completed' = 'active';
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
seasonDates: {
|
||||
start: string;
|
||||
end: string;
|
||||
};
|
||||
} = { start: '', end: '' };
|
||||
|
||||
@ApiProperty({ type: Object, required: false })
|
||||
@IsOptional()
|
||||
@@ -84,5 +84,8 @@ export class LeagueDetailDTO {
|
||||
price: number;
|
||||
benefits: string[];
|
||||
};
|
||||
} = {
|
||||
main: { available: false, price: 0, benefits: [] },
|
||||
secondary: { available: 0, total: 0, price: 0, benefits: [] }
|
||||
};
|
||||
}
|
||||
@@ -4,25 +4,25 @@ import { IsBoolean } from 'class-validator';
|
||||
export class NotificationSettingsDTO {
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
emailNewSponsorships: boolean;
|
||||
emailNewSponsorships: boolean = false;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
emailWeeklyReport: boolean;
|
||||
emailWeeklyReport: boolean = false;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
emailRaceAlerts: boolean;
|
||||
emailRaceAlerts: boolean = false;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
emailPaymentAlerts: boolean;
|
||||
emailPaymentAlerts: boolean = false;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
emailNewOpportunities: boolean;
|
||||
emailNewOpportunities: boolean = false;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
emailContractExpiry: boolean;
|
||||
emailContractExpiry: boolean = false;
|
||||
}
|
||||
@@ -4,15 +4,15 @@ import { IsString, IsEnum, IsBoolean, IsOptional, IsNumber } from 'class-validat
|
||||
export class PaymentMethodDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty({ enum: ['card', 'bank', 'sepa'] })
|
||||
@IsEnum(['card', 'bank', 'sepa'])
|
||||
type: 'card' | 'bank' | 'sepa';
|
||||
type: 'card' | 'bank' | 'sepa' = 'card';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
last4: string;
|
||||
last4: string = '';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@@ -21,7 +21,7 @@ export class PaymentMethodDTO {
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
isDefault: boolean;
|
||||
isDefault: boolean = false;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
|
||||
@@ -4,17 +4,17 @@ import { IsBoolean } from 'class-validator';
|
||||
export class PrivacySettingsDTO {
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
publicProfile: boolean;
|
||||
publicProfile: boolean = false;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
showStats: boolean;
|
||||
showStats: boolean = false;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
showActiveSponsorships: boolean;
|
||||
showActiveSponsorships: boolean = false;
|
||||
|
||||
@ApiProperty()
|
||||
@IsBoolean()
|
||||
allowDirectContact: boolean;
|
||||
allowDirectContact: boolean = false;
|
||||
}
|
||||
@@ -4,21 +4,21 @@ import { IsString, IsEnum, IsNumber, IsDateString } from 'class-validator';
|
||||
export class RaceDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
name: string;
|
||||
name: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsDateString()
|
||||
date: string;
|
||||
date: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
views: number;
|
||||
views: number = 0;
|
||||
|
||||
@ApiProperty({ enum: ['upcoming', 'completed'] })
|
||||
@IsEnum(['upcoming', 'completed'])
|
||||
status: 'upcoming' | 'completed';
|
||||
status: 'upcoming' | 'completed' = 'upcoming';
|
||||
}
|
||||
@@ -5,7 +5,7 @@ export class RejectSponsorshipRequestInputDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
respondedBy: string;
|
||||
respondedBy: string = '';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
|
||||
@@ -4,21 +4,21 @@ import { IsString, IsEnum, IsNumber, IsDateString } from 'class-validator';
|
||||
export class RenewalAlertDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
name: string;
|
||||
name: string = '';
|
||||
|
||||
@ApiProperty({ enum: ['league', 'team', 'driver', 'race', 'platform'] })
|
||||
@IsEnum(['league', 'team', 'driver', 'race', 'platform'])
|
||||
type: 'league' | 'team' | 'driver' | 'race' | 'platform';
|
||||
type: 'league' | 'team' | 'driver' | 'race' | 'platform' = 'league';
|
||||
|
||||
@ApiProperty()
|
||||
@IsDateString()
|
||||
renewDate: string;
|
||||
renewDate: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
price: number;
|
||||
price: number = 0;
|
||||
}
|
||||
@@ -2,10 +2,10 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class SponsorDTO {
|
||||
@ApiProperty()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
name: string;
|
||||
name: string = '';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
contactEmail?: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsArray, IsObject } from 'class-validator';
|
||||
import { IsString } from 'class-validator';
|
||||
import { SponsorDashboardMetricsDTO } from './SponsorDashboardMetricsDTO';
|
||||
import { SponsoredLeagueDTO } from './SponsoredLeagueDTO';
|
||||
import { SponsorDashboardInvestmentDTO } from './SponsorDashboardInvestmentDTO';
|
||||
@@ -10,20 +10,20 @@ import { RenewalAlertDTO } from './RenewalAlertDTO';
|
||||
export class SponsorDashboardDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
sponsorId: string;
|
||||
sponsorId: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
sponsorName: string;
|
||||
sponsorName: string = '';
|
||||
|
||||
@ApiProperty({ type: SponsorDashboardMetricsDTO })
|
||||
metrics: SponsorDashboardMetricsDTO;
|
||||
metrics: SponsorDashboardMetricsDTO = new SponsorDashboardMetricsDTO();
|
||||
|
||||
@ApiProperty({ type: [SponsoredLeagueDTO] })
|
||||
sponsoredLeagues: SponsoredLeagueDTO[];
|
||||
sponsoredLeagues: SponsoredLeagueDTO[] = [];
|
||||
|
||||
@ApiProperty({ type: SponsorDashboardInvestmentDTO })
|
||||
investment: SponsorDashboardInvestmentDTO;
|
||||
investment: SponsorDashboardInvestmentDTO = new SponsorDashboardInvestmentDTO();
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
sponsorships: {
|
||||
@@ -32,11 +32,17 @@ export class SponsorDashboardDTO {
|
||||
drivers: SponsorshipDTO[];
|
||||
races: SponsorshipDTO[];
|
||||
platform: SponsorshipDTO[];
|
||||
} = {
|
||||
leagues: [],
|
||||
teams: [],
|
||||
drivers: [],
|
||||
races: [],
|
||||
platform: []
|
||||
};
|
||||
|
||||
@ApiProperty({ type: [ActivityItemDTO] })
|
||||
recentActivity: ActivityItemDTO[];
|
||||
recentActivity: ActivityItemDTO[] = [];
|
||||
|
||||
@ApiProperty({ type: [RenewalAlertDTO] })
|
||||
upcomingRenewals: RenewalAlertDTO[];
|
||||
upcomingRenewals: RenewalAlertDTO[] = [];
|
||||
}
|
||||
@@ -4,13 +4,13 @@ import { IsNumber } from 'class-validator';
|
||||
export class SponsorDashboardInvestmentDTO {
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
activeSponsorships: number;
|
||||
activeSponsorships: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
totalInvestment: number;
|
||||
totalInvestment: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
costPerThousandViews: number;
|
||||
costPerThousandViews: number = 0;
|
||||
}
|
||||
@@ -4,33 +4,33 @@ import { IsNumber } from 'class-validator';
|
||||
export class SponsorDashboardMetricsDTO {
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
impressions: number;
|
||||
impressions: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
impressionsChange: number;
|
||||
impressionsChange: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
uniqueViewers: number;
|
||||
uniqueViewers: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
viewersChange: number;
|
||||
viewersChange: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
races: number;
|
||||
races: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
drivers: number;
|
||||
drivers: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
exposure: number;
|
||||
exposure: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
exposureChange: number;
|
||||
exposureChange: number = 0;
|
||||
}
|
||||
@@ -1,30 +1,30 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsOptional, IsObject } from 'class-validator';
|
||||
import { IsString, IsOptional } from 'class-validator';
|
||||
|
||||
export class SponsorProfileDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
companyName: string;
|
||||
companyName: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
contactName: string;
|
||||
contactName: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
contactEmail: string;
|
||||
contactEmail: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
contactPhone: string;
|
||||
contactPhone: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
website: string;
|
||||
website: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
description: string;
|
||||
description: string = '';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@@ -33,7 +33,7 @@ export class SponsorProfileDTO {
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
industry: string;
|
||||
industry: string = '';
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
address: {
|
||||
@@ -41,16 +41,16 @@ export class SponsorProfileDTO {
|
||||
city: string;
|
||||
country: string;
|
||||
postalCode: string;
|
||||
};
|
||||
} = { street: '', city: '', country: '', postalCode: '' };
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
taxId: string;
|
||||
taxId: string = '';
|
||||
|
||||
@ApiProperty({ type: Object })
|
||||
socialLinks: {
|
||||
twitter: string;
|
||||
linkedin: string;
|
||||
instagram: string;
|
||||
};
|
||||
} = { twitter: '', linkedin: '', instagram: '' };
|
||||
}
|
||||
@@ -5,14 +5,14 @@ import { SponsorshipDetailDTO } from './SponsorshipDetailDTO';
|
||||
export class SponsorSponsorshipsDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
sponsorId: string;
|
||||
sponsorId: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
sponsorName: string;
|
||||
sponsorName: string = '';
|
||||
|
||||
@ApiProperty({ type: [SponsorshipDetailDTO] })
|
||||
sponsorships: SponsorshipDetailDTO[];
|
||||
sponsorships: SponsorshipDetailDTO[] = [];
|
||||
|
||||
@ApiProperty()
|
||||
summary: {
|
||||
@@ -21,5 +21,11 @@ export class SponsorSponsorshipsDTO {
|
||||
totalInvestment: number;
|
||||
totalPlatformFees: number;
|
||||
currency: string;
|
||||
} = {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
totalPlatformFees: 0,
|
||||
currency: ''
|
||||
};
|
||||
}
|
||||
@@ -4,29 +4,29 @@ import { IsString, IsEnum, IsNumber } from 'class-validator';
|
||||
export class SponsoredLeagueDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
name: string;
|
||||
name: string = '';
|
||||
|
||||
@ApiProperty({ enum: ['main', 'secondary'] })
|
||||
@IsEnum(['main', 'secondary'])
|
||||
tier: 'main' | 'secondary';
|
||||
tier: 'main' | 'secondary' = 'main';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
drivers: number;
|
||||
drivers: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
races: number;
|
||||
races: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
impressions: number;
|
||||
impressions: number = 0;
|
||||
|
||||
@ApiProperty({ enum: ['active', 'upcoming', 'completed'] })
|
||||
@IsEnum(['active', 'upcoming', 'completed'])
|
||||
status: 'active' | 'upcoming' | 'completed';
|
||||
status: 'active' | 'upcoming' | 'completed' = 'active';
|
||||
}
|
||||
@@ -4,19 +4,19 @@ import { IsString, IsEnum, IsNumber, IsOptional, IsDateString } from 'class-vali
|
||||
export class SponsorshipDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty({ enum: ['leagues', 'teams', 'drivers', 'races', 'platform'] })
|
||||
@IsEnum(['leagues', 'teams', 'drivers', 'races', 'platform'])
|
||||
type: 'leagues' | 'teams' | 'drivers' | 'races' | 'platform';
|
||||
type: 'leagues' | 'teams' | 'drivers' | 'races' | 'platform' = 'leagues';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
entityId: string;
|
||||
entityId: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
entityName: string;
|
||||
entityName: string = '';
|
||||
|
||||
@ApiProperty({ enum: ['main', 'secondary'], required: false })
|
||||
@IsOptional()
|
||||
@@ -25,7 +25,7 @@ export class SponsorshipDTO {
|
||||
|
||||
@ApiProperty({ enum: ['active', 'pending_approval', 'approved', 'rejected', 'expired'] })
|
||||
@IsEnum(['active', 'pending_approval', 'approved', 'rejected', 'expired'])
|
||||
status: 'active' | 'pending_approval' | 'approved' | 'rejected' | 'expired';
|
||||
status: 'active' | 'pending_approval' | 'approved' | 'rejected' | 'expired' = 'pending_approval';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@@ -44,19 +44,19 @@ export class SponsorshipDTO {
|
||||
|
||||
@ApiProperty()
|
||||
@IsDateString()
|
||||
startDate: string;
|
||||
startDate: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsDateString()
|
||||
endDate: string;
|
||||
endDate: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
price: number;
|
||||
price: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
impressions: number;
|
||||
impressions: number = 0;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
|
||||
@@ -4,23 +4,23 @@ import { IsString, IsEnum, IsOptional, IsDate } from 'class-validator';
|
||||
export class SponsorshipDetailDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
leagueId: string;
|
||||
leagueId: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
leagueName: string;
|
||||
leagueName: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
seasonId: string;
|
||||
seasonId: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
seasonName: string;
|
||||
seasonName: string = '';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@@ -34,29 +34,29 @@ export class SponsorshipDetailDTO {
|
||||
|
||||
@ApiProperty({ enum: ['main', 'secondary'] })
|
||||
@IsEnum(['main', 'secondary'])
|
||||
tier: 'main' | 'secondary';
|
||||
tier: 'main' | 'secondary' = 'main';
|
||||
|
||||
@ApiProperty({ enum: ['pending', 'active', 'expired', 'cancelled'] })
|
||||
@IsEnum(['pending', 'active', 'expired', 'cancelled'])
|
||||
status: 'pending' | 'active' | 'expired' | 'cancelled';
|
||||
status: 'pending' | 'active' | 'expired' | 'cancelled' = 'pending';
|
||||
|
||||
@ApiProperty()
|
||||
pricing: {
|
||||
amount: number;
|
||||
currency: string;
|
||||
};
|
||||
} = { amount: 0, currency: '' };
|
||||
|
||||
@ApiProperty()
|
||||
platformFee: {
|
||||
amount: number;
|
||||
currency: string;
|
||||
};
|
||||
} = { amount: 0, currency: '' };
|
||||
|
||||
@ApiProperty()
|
||||
netAmount: {
|
||||
amount: number;
|
||||
currency: string;
|
||||
};
|
||||
} = { amount: 0, currency: '' };
|
||||
|
||||
@ApiProperty()
|
||||
metrics: {
|
||||
@@ -64,10 +64,10 @@ export class SponsorshipDetailDTO {
|
||||
races: number;
|
||||
completedRaces: number;
|
||||
impressions: number;
|
||||
};
|
||||
} = { drivers: 0, races: 0, completedRaces: 0, impressions: 0 };
|
||||
|
||||
@ApiProperty()
|
||||
createdAt: Date;
|
||||
createdAt: Date = new Date();
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
|
||||
@@ -4,17 +4,17 @@ import { IsString, IsNumber } from 'class-validator';
|
||||
export class SponsorshipPricingItemDTO {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
level: string;
|
||||
level: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
price: number;
|
||||
price: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
currency: string;
|
||||
currency: string = '';
|
||||
}
|
||||
@@ -2,38 +2,38 @@ import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class SponsorshipRequestDTO {
|
||||
@ApiProperty()
|
||||
id: string;
|
||||
id: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
sponsorId: string;
|
||||
sponsorId: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
sponsorName: string;
|
||||
sponsorName: string = '';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
sponsorLogo?: string;
|
||||
|
||||
@ApiProperty()
|
||||
tier: string;
|
||||
tier: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
offeredAmount: number;
|
||||
offeredAmount: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
currency: string;
|
||||
currency: string = '';
|
||||
|
||||
@ApiProperty()
|
||||
formattedAmount: string;
|
||||
formattedAmount: string = '';
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
message?: string;
|
||||
|
||||
@ApiProperty()
|
||||
createdAt: Date;
|
||||
createdAt: Date = new Date();
|
||||
|
||||
@ApiProperty()
|
||||
platformFee: number;
|
||||
platformFee: number = 0;
|
||||
|
||||
@ApiProperty()
|
||||
netAmount: number;
|
||||
netAmount: number = 0;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AcceptSponsorshipOutputPort } from '@core/racing/application/ports/output/AcceptSponsorshipOutputPort';
|
||||
import type { AcceptSponsorshipResult } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
|
||||
|
||||
export interface AcceptSponsorshipRequestResultViewModel {
|
||||
requestId: string;
|
||||
@@ -16,7 +16,7 @@ export class AcceptSponsorshipRequestPresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: AcceptSponsorshipOutputPort | null) {
|
||||
present(output: AcceptSponsorshipResult | null) {
|
||||
if (!output) {
|
||||
this.result = null;
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { CreateSponsorPresenter } from './CreateSponsorPresenter';
|
||||
import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
|
||||
|
||||
describe('CreateSponsorPresenter', () => {
|
||||
let presenter: CreateSponsorPresenter;
|
||||
@@ -10,9 +11,23 @@ describe('CreateSponsorPresenter', () => {
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the result to null', () => {
|
||||
const mockPort = { sponsor: { id: 'sponsor-1', name: 'Test Sponsor', contactEmail: 'test@example.com', createdAt: new Date() } };
|
||||
presenter.present(mockPort);
|
||||
expect(presenter.viewModel).toEqual({ sponsor: mockPort.sponsor });
|
||||
const mockSponsor = Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date()
|
||||
});
|
||||
presenter.present(mockSponsor);
|
||||
|
||||
const expectedViewModel = {
|
||||
sponsor: {
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: mockSponsor.createdAt.toDate()
|
||||
}
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.viewModel).toThrow('Presenter not presented');
|
||||
@@ -21,11 +36,24 @@ describe('CreateSponsorPresenter', () => {
|
||||
|
||||
describe('present', () => {
|
||||
it('should store the result', () => {
|
||||
const mockPort = { sponsor: { id: 'sponsor-1', name: 'Test Sponsor', contactEmail: 'test@example.com', createdAt: new Date() } };
|
||||
const mockSponsor = Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date()
|
||||
});
|
||||
|
||||
presenter.present(mockPort);
|
||||
presenter.present(mockSponsor);
|
||||
|
||||
expect(presenter.viewModel).toEqual({ sponsor: mockPort.sponsor });
|
||||
const expectedViewModel = {
|
||||
sponsor: {
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: mockSponsor.createdAt.toDate()
|
||||
}
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,10 +63,23 @@ describe('CreateSponsorPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockPort = { sponsor: { id: 'sponsor-1', name: 'Test Sponsor', contactEmail: 'test@example.com', createdAt: new Date() } };
|
||||
presenter.present(mockPort);
|
||||
const mockSponsor = Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date()
|
||||
});
|
||||
presenter.present(mockSponsor);
|
||||
|
||||
expect(presenter.getViewModel()).toEqual({ sponsor: mockPort.sponsor });
|
||||
const expectedViewModel = {
|
||||
sponsor: {
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: mockSponsor.createdAt.toDate()
|
||||
}
|
||||
};
|
||||
expect(presenter.getViewModel()).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,10 +89,23 @@ describe('CreateSponsorPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockPort = { sponsor: { id: 'sponsor-1', name: 'Test Sponsor', contactEmail: 'test@example.com', createdAt: new Date() } };
|
||||
presenter.present(mockPort);
|
||||
const mockSponsor = Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date()
|
||||
});
|
||||
presenter.present(mockSponsor);
|
||||
|
||||
expect(presenter.viewModel).toEqual({ sponsor: mockPort.sponsor });
|
||||
const expectedViewModel = {
|
||||
sponsor: {
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: mockSponsor.createdAt.toDate()
|
||||
}
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CreateSponsorOutputPort } from '@core/racing/application/ports/output/CreateSponsorOutputPort';
|
||||
import type { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
|
||||
import type { CreateSponsorOutputDTO } from '../dtos/CreateSponsorOutputDTO';
|
||||
|
||||
export class CreateSponsorPresenter {
|
||||
@@ -8,16 +8,24 @@ export class CreateSponsorPresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(port: CreateSponsorOutputPort) {
|
||||
present(sponsor: Sponsor) {
|
||||
const sponsorData: any = {
|
||||
id: sponsor.id.toString(),
|
||||
name: sponsor.name.toString(),
|
||||
contactEmail: sponsor.contactEmail.toString(),
|
||||
createdAt: sponsor.createdAt.toDate(),
|
||||
};
|
||||
|
||||
if (sponsor.logoUrl) {
|
||||
sponsorData.logoUrl = sponsor.logoUrl.toString();
|
||||
}
|
||||
|
||||
if (sponsor.websiteUrl) {
|
||||
sponsorData.websiteUrl = sponsor.websiteUrl.toString();
|
||||
}
|
||||
|
||||
this.result = {
|
||||
sponsor: {
|
||||
id: port.sponsor.id,
|
||||
name: port.sponsor.name,
|
||||
contactEmail: port.sponsor.contactEmail,
|
||||
logoUrl: port.sponsor.logoUrl,
|
||||
websiteUrl: port.sponsor.websiteUrl,
|
||||
createdAt: port.sponsor.createdAt,
|
||||
},
|
||||
sponsor: sponsorData,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { GetEntitySponsorshipPricingPresenter } from './GetEntitySponsorshipPricingPresenter';
|
||||
import type { GetEntitySponsorshipPricingResult } from '@core/racing/application/use-cases/GetEntitySponsorshipPricingUseCase';
|
||||
|
||||
describe('GetEntitySponsorshipPricingPresenter', () => {
|
||||
let presenter: GetEntitySponsorshipPricingPresenter;
|
||||
@@ -10,9 +11,20 @@ describe('GetEntitySponsorshipPricingPresenter', () => {
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the result to null', () => {
|
||||
const mockResult = { entityType: 'season', entityId: 'season-1', pricing: [] };
|
||||
const mockResult: GetEntitySponsorshipPricingResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
acceptingApplications: true,
|
||||
tiers: []
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
|
||||
const expectedViewModel = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.viewModel).toThrow('Presenter not presented');
|
||||
@@ -21,11 +33,21 @@ describe('GetEntitySponsorshipPricingPresenter', () => {
|
||||
|
||||
describe('present', () => {
|
||||
it('should store the result', () => {
|
||||
const mockResult = { entityType: 'season', entityId: 'season-1', pricing: [] };
|
||||
const mockResult: GetEntitySponsorshipPricingResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
acceptingApplications: true,
|
||||
tiers: []
|
||||
};
|
||||
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,10 +57,20 @@ describe('GetEntitySponsorshipPricingPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockResult = { entityType: 'season', entityId: 'season-1', pricing: [] };
|
||||
const mockResult: GetEntitySponsorshipPricingResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
acceptingApplications: true,
|
||||
tiers: []
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.getViewModel()).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
expect(presenter.getViewModel()).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,10 +80,20 @@ describe('GetEntitySponsorshipPricingPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockResult = { entityType: 'season', entityId: 'season-1', pricing: [] };
|
||||
const mockResult: GetEntitySponsorshipPricingResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
acceptingApplications: true,
|
||||
tiers: []
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GetSponsorshipPricingOutputPort } from '@core/racing/application/ports/output/GetSponsorshipPricingOutputPort';
|
||||
import type { GetEntitySponsorshipPricingResult } from '@core/racing/application/use-cases/GetEntitySponsorshipPricingUseCase';
|
||||
import { GetEntitySponsorshipPricingResultDTO } from '../dtos/GetEntitySponsorshipPricingResultDTO';
|
||||
|
||||
export class GetEntitySponsorshipPricingPresenter {
|
||||
@@ -8,7 +8,7 @@ export class GetEntitySponsorshipPricingPresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetSponsorshipPricingOutputPort | null) {
|
||||
present(output: GetEntitySponsorshipPricingResult | null) {
|
||||
if (!output) {
|
||||
this.result = {
|
||||
entityType: 'season',
|
||||
@@ -21,11 +21,11 @@ export class GetEntitySponsorshipPricingPresenter {
|
||||
this.result = {
|
||||
entityType: output.entityType,
|
||||
entityId: output.entityId,
|
||||
pricing: output.pricing.map(item => ({
|
||||
id: item.id,
|
||||
level: item.level,
|
||||
pricing: output.tiers.map(item => ({
|
||||
id: item.name,
|
||||
level: item.name,
|
||||
price: item.price,
|
||||
currency: item.currency,
|
||||
currency: 'USD',
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PendingSponsorshipRequestsOutputPort } from '@core/racing/application/ports/output/PendingSponsorshipRequestsOutputPort';
|
||||
import type { GetPendingSponsorshipRequestsResult } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
|
||||
import { GetPendingSponsorshipRequestsOutputDTO } from '../dtos/GetPendingSponsorshipRequestsOutputDTO';
|
||||
|
||||
export class GetPendingSponsorshipRequestsPresenter {
|
||||
@@ -8,7 +8,7 @@ export class GetPendingSponsorshipRequestsPresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(outputPort: PendingSponsorshipRequestsOutputPort | null) {
|
||||
present(outputPort: GetPendingSponsorshipRequestsResult | null) {
|
||||
if (!outputPort) {
|
||||
this.result = null;
|
||||
return;
|
||||
@@ -17,7 +17,30 @@ export class GetPendingSponsorshipRequestsPresenter {
|
||||
this.result = {
|
||||
entityType: outputPort.entityType,
|
||||
entityId: outputPort.entityId,
|
||||
requests: outputPort.requests,
|
||||
requests: outputPort.requests.map(r => {
|
||||
const request: any = {
|
||||
id: r.request.id,
|
||||
sponsorId: r.request.sponsorId,
|
||||
sponsorName: r.sponsor?.name?.toString() || 'Unknown Sponsor',
|
||||
tier: r.request.tier,
|
||||
offeredAmount: r.financials.offeredAmount.amount,
|
||||
currency: r.financials.offeredAmount.currency,
|
||||
formattedAmount: `${r.financials.offeredAmount.amount} ${r.financials.offeredAmount.currency}`,
|
||||
createdAt: r.request.createdAt,
|
||||
platformFee: r.financials.platformFee.amount,
|
||||
netAmount: r.financials.netAmount.amount,
|
||||
};
|
||||
|
||||
if (r.sponsor?.logoUrl) {
|
||||
request.sponsorLogo = r.sponsor.logoUrl.toString();
|
||||
}
|
||||
|
||||
if (r.request.message) {
|
||||
request.message = r.request.message;
|
||||
}
|
||||
|
||||
return request;
|
||||
}),
|
||||
totalCount: outputPort.totalCount,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { GetSponsorDashboardPresenter } from './GetSponsorDashboardPresenter';
|
||||
import type { GetSponsorDashboardResult } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
|
||||
import { Money } from '@core/racing/domain/value-objects/Money';
|
||||
|
||||
describe('GetSponsorDashboardPresenter', () => {
|
||||
let presenter: GetSponsorDashboardPresenter;
|
||||
@@ -10,9 +12,58 @@ describe('GetSponsorDashboardPresenter', () => {
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the result to null', () => {
|
||||
const mockResult = { sponsorId: 'sponsor-1', metrics: {}, sponsoredLeagues: [] };
|
||||
const mockResult: GetSponsorDashboardResult = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
metrics: {
|
||||
impressions: 1000,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 700,
|
||||
viewersChange: 0,
|
||||
races: 5,
|
||||
drivers: 10,
|
||||
exposure: 50,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: Money.create(0, 'USD'),
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
|
||||
const expectedViewModel = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
metrics: {
|
||||
impressions: 1000,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 700,
|
||||
viewersChange: 0,
|
||||
races: 5,
|
||||
drivers: 10,
|
||||
exposure: 50,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
sponsorships: {
|
||||
leagues: [],
|
||||
teams: [],
|
||||
drivers: [],
|
||||
races: [],
|
||||
platform: [],
|
||||
},
|
||||
recentActivity: [],
|
||||
upcomingRenewals: [],
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.viewModel).toThrow('Presenter not presented');
|
||||
@@ -21,11 +72,59 @@ describe('GetSponsorDashboardPresenter', () => {
|
||||
|
||||
describe('present', () => {
|
||||
it('should store the result', () => {
|
||||
const mockResult = { sponsorId: 'sponsor-1', metrics: {}, sponsoredLeagues: [] };
|
||||
const mockResult: GetSponsorDashboardResult = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
metrics: {
|
||||
impressions: 1000,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 700,
|
||||
viewersChange: 0,
|
||||
races: 5,
|
||||
drivers: 10,
|
||||
exposure: 50,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: Money.create(0, 'USD'),
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
};
|
||||
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
metrics: {
|
||||
impressions: 1000,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 700,
|
||||
viewersChange: 0,
|
||||
races: 5,
|
||||
drivers: 10,
|
||||
exposure: 50,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
sponsorships: {
|
||||
leagues: [],
|
||||
teams: [],
|
||||
drivers: [],
|
||||
races: [],
|
||||
platform: [],
|
||||
},
|
||||
recentActivity: [],
|
||||
upcomingRenewals: [],
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,10 +134,58 @@ describe('GetSponsorDashboardPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockResult = { sponsorId: 'sponsor-1', metrics: {}, sponsoredLeagues: [] };
|
||||
const mockResult: GetSponsorDashboardResult = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
metrics: {
|
||||
impressions: 1000,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 700,
|
||||
viewersChange: 0,
|
||||
races: 5,
|
||||
drivers: 10,
|
||||
exposure: 50,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: Money.create(0, 'USD'),
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.getViewModel()).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
metrics: {
|
||||
impressions: 1000,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 700,
|
||||
viewersChange: 0,
|
||||
races: 5,
|
||||
drivers: 10,
|
||||
exposure: 50,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
sponsorships: {
|
||||
leagues: [],
|
||||
teams: [],
|
||||
drivers: [],
|
||||
races: [],
|
||||
platform: [],
|
||||
},
|
||||
recentActivity: [],
|
||||
upcomingRenewals: [],
|
||||
};
|
||||
expect(presenter.getViewModel()).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,10 +195,58 @@ describe('GetSponsorDashboardPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockResult = { sponsorId: 'sponsor-1', metrics: {}, sponsoredLeagues: [] };
|
||||
const mockResult: GetSponsorDashboardResult = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
metrics: {
|
||||
impressions: 1000,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 700,
|
||||
viewersChange: 0,
|
||||
races: 5,
|
||||
drivers: 10,
|
||||
exposure: 50,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: Money.create(0, 'USD'),
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
metrics: {
|
||||
impressions: 1000,
|
||||
impressionsChange: 0,
|
||||
uniqueViewers: 700,
|
||||
viewersChange: 0,
|
||||
races: 5,
|
||||
drivers: 10,
|
||||
exposure: 50,
|
||||
exposureChange: 0,
|
||||
},
|
||||
sponsoredLeagues: [],
|
||||
investment: {
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
costPerThousandViews: 0,
|
||||
},
|
||||
sponsorships: {
|
||||
leagues: [],
|
||||
teams: [],
|
||||
drivers: [],
|
||||
races: [],
|
||||
platform: [],
|
||||
},
|
||||
recentActivity: [],
|
||||
upcomingRenewals: [],
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { SponsorDashboardOutputPort } from '@core/racing/application/ports/output/SponsorDashboardOutputPort';
|
||||
import type { GetSponsorDashboardResult } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
|
||||
import { SponsorDashboardDTO } from '../dtos/SponsorDashboardDTO';
|
||||
|
||||
export class GetSponsorDashboardPresenter {
|
||||
@@ -8,8 +8,40 @@ export class GetSponsorDashboardPresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(outputPort: SponsorDashboardOutputPort | null) {
|
||||
this.result = outputPort ?? null;
|
||||
present(outputPort: GetSponsorDashboardResult | null) {
|
||||
if (!outputPort) {
|
||||
this.result = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.result = {
|
||||
sponsorId: outputPort.sponsorId,
|
||||
sponsorName: outputPort.sponsorName,
|
||||
metrics: outputPort.metrics,
|
||||
sponsoredLeagues: outputPort.sponsoredLeagues.map(league => ({
|
||||
id: league.leagueId,
|
||||
name: league.leagueName,
|
||||
tier: league.tier,
|
||||
drivers: league.metrics.drivers,
|
||||
races: league.metrics.races,
|
||||
impressions: league.metrics.impressions,
|
||||
status: league.status,
|
||||
})),
|
||||
investment: {
|
||||
activeSponsorships: outputPort.investment.activeSponsorships,
|
||||
totalInvestment: outputPort.investment.totalInvestment.amount,
|
||||
costPerThousandViews: outputPort.investment.costPerThousandViews,
|
||||
},
|
||||
sponsorships: {
|
||||
leagues: [],
|
||||
teams: [],
|
||||
drivers: [],
|
||||
races: [],
|
||||
platform: [],
|
||||
},
|
||||
recentActivity: [],
|
||||
upcomingRenewals: [],
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): SponsorDashboardDTO | null {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { GetSponsorSponsorshipsPresenter } from './GetSponsorSponsorshipsPresenter';
|
||||
import type { GetSponsorSponsorshipsResult } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
|
||||
import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
|
||||
import { Money } from '@core/racing/domain/value-objects/Money';
|
||||
|
||||
describe('GetSponsorSponsorshipsPresenter', () => {
|
||||
let presenter: GetSponsorSponsorshipsPresenter;
|
||||
@@ -10,9 +13,38 @@ describe('GetSponsorSponsorshipsPresenter', () => {
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the result to null', () => {
|
||||
const mockResult = { sponsorId: 'sponsor-1', sponsorName: 'Test Sponsor', sponsorships: [] };
|
||||
const mockSponsor = Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date()
|
||||
});
|
||||
|
||||
const mockResult: GetSponsorSponsorshipsResult = {
|
||||
sponsor: mockSponsor,
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: Money.create(0, 'USD'),
|
||||
totalPlatformFees: Money.create(0, 'USD'),
|
||||
},
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
|
||||
const expectedViewModel = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
totalPlatformFees: 0,
|
||||
currency: 'USD',
|
||||
},
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.viewModel).toThrow('Presenter not presented');
|
||||
@@ -21,11 +53,39 @@ describe('GetSponsorSponsorshipsPresenter', () => {
|
||||
|
||||
describe('present', () => {
|
||||
it('should store the result', () => {
|
||||
const mockResult = { sponsorId: 'sponsor-1', sponsorName: 'Test Sponsor', sponsorships: [] };
|
||||
const mockSponsor = Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date()
|
||||
});
|
||||
|
||||
const mockResult: GetSponsorSponsorshipsResult = {
|
||||
sponsor: mockSponsor,
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: Money.create(0, 'USD'),
|
||||
totalPlatformFees: Money.create(0, 'USD'),
|
||||
},
|
||||
};
|
||||
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
totalPlatformFees: 0,
|
||||
currency: 'USD',
|
||||
},
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,10 +95,38 @@ describe('GetSponsorSponsorshipsPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockResult = { sponsorId: 'sponsor-1', sponsorName: 'Test Sponsor', sponsorships: [] };
|
||||
const mockSponsor = Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date()
|
||||
});
|
||||
|
||||
const mockResult: GetSponsorSponsorshipsResult = {
|
||||
sponsor: mockSponsor,
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: Money.create(0, 'USD'),
|
||||
totalPlatformFees: Money.create(0, 'USD'),
|
||||
},
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.getViewModel()).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
totalPlatformFees: 0,
|
||||
currency: 'USD',
|
||||
},
|
||||
};
|
||||
expect(presenter.getViewModel()).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,10 +136,38 @@ describe('GetSponsorSponsorshipsPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockResult = { sponsorId: 'sponsor-1', sponsorName: 'Test Sponsor', sponsorships: [] };
|
||||
const mockSponsor = Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Test Sponsor',
|
||||
contactEmail: 'test@example.com',
|
||||
createdAt: new Date()
|
||||
});
|
||||
|
||||
const mockResult: GetSponsorSponsorshipsResult = {
|
||||
sponsor: mockSponsor,
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: Money.create(0, 'USD'),
|
||||
totalPlatformFees: Money.create(0, 'USD'),
|
||||
},
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
sponsorId: 'sponsor-1',
|
||||
sponsorName: 'Test Sponsor',
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
totalPlatformFees: 0,
|
||||
currency: 'USD',
|
||||
},
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { SponsorSponsorshipsOutputPort } from '@core/racing/application/ports/output/SponsorSponsorshipsOutputPort';
|
||||
import type { GetSponsorSponsorshipsResult } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
|
||||
import { SponsorSponsorshipsDTO } from '../dtos/SponsorSponsorshipsDTO';
|
||||
|
||||
export class GetSponsorSponsorshipsPresenter {
|
||||
@@ -8,8 +8,58 @@ export class GetSponsorSponsorshipsPresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(outputPort: SponsorSponsorshipsOutputPort | null) {
|
||||
this.result = outputPort ?? null;
|
||||
present(outputPort: GetSponsorSponsorshipsResult | null) {
|
||||
if (!outputPort) {
|
||||
this.result = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.result = {
|
||||
sponsorId: outputPort.sponsor.id.toString(),
|
||||
sponsorName: outputPort.sponsor.name.toString(),
|
||||
sponsorships: outputPort.sponsorships.map(s => {
|
||||
// Map status to DTO expected values
|
||||
let status: 'pending' | 'active' | 'expired' | 'cancelled';
|
||||
if (s.sponsorship.status === 'ended') {
|
||||
status = 'expired';
|
||||
} else if (s.sponsorship.status === 'pending' || s.sponsorship.status === 'active' || s.sponsorship.status === 'cancelled') {
|
||||
status = s.sponsorship.status;
|
||||
} else {
|
||||
status = 'pending';
|
||||
}
|
||||
|
||||
return {
|
||||
id: s.sponsorship.id.toString(),
|
||||
leagueId: s.league.id.toString(),
|
||||
leagueName: s.league.name.toString(),
|
||||
seasonId: s.season.id.toString(),
|
||||
seasonName: s.season.name.toString(),
|
||||
tier: s.sponsorship.tier,
|
||||
status,
|
||||
pricing: {
|
||||
amount: s.financials.pricing.amount,
|
||||
currency: s.financials.pricing.currency,
|
||||
},
|
||||
platformFee: {
|
||||
amount: s.financials.platformFee.amount,
|
||||
currency: s.financials.platformFee.currency,
|
||||
},
|
||||
netAmount: {
|
||||
amount: s.financials.netAmount.amount,
|
||||
currency: s.financials.netAmount.currency,
|
||||
},
|
||||
metrics: s.metrics,
|
||||
createdAt: s.sponsorship.createdAt,
|
||||
};
|
||||
}),
|
||||
summary: {
|
||||
totalSponsorships: outputPort.summary.totalSponsorships,
|
||||
activeSponsorships: outputPort.summary.activeSponsorships,
|
||||
totalInvestment: outputPort.summary.totalInvestment.amount,
|
||||
totalPlatformFees: outputPort.summary.totalPlatformFees.amount,
|
||||
currency: outputPort.summary.totalInvestment.currency,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): SponsorSponsorshipsDTO | null {
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import type {
|
||||
GetSponsorsResult,
|
||||
GetSponsorsErrorCode,
|
||||
} from '@core/racing/application/use-cases/GetSponsorsUseCase';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
import { GetSponsorsPresenter } from './GetSponsorsPresenter';
|
||||
import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
|
||||
|
||||
describe('GetSponsorsPresenter', () => {
|
||||
let presenter: GetSponsorsPresenter;
|
||||
@@ -16,8 +11,8 @@ describe('GetSponsorsPresenter', () => {
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the model to null and cause responseModel to throw', () => {
|
||||
const result = Result.ok<GetSponsorsResult, never>({ sponsors: [] });
|
||||
presenter.present(result);
|
||||
const sponsors: Sponsor[] = [];
|
||||
presenter.present(sponsors);
|
||||
expect(presenter.responseModel).toEqual({ sponsors: [] });
|
||||
|
||||
presenter.reset();
|
||||
@@ -26,29 +21,24 @@ describe('GetSponsorsPresenter', () => {
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should map Result.ok sponsors to DTO responseModel', () => {
|
||||
const result = Result.ok<GetSponsorsResult, never>({
|
||||
sponsors: [
|
||||
{
|
||||
id: 'sponsor-1',
|
||||
name: 'Sponsor One',
|
||||
contactEmail: 's1@example.com',
|
||||
logoUrl: 'logo1.png',
|
||||
websiteUrl: 'https://one.example.com',
|
||||
createdAt: new Date('2024-01-01T00:00:00Z'),
|
||||
},
|
||||
{
|
||||
id: 'sponsor-2',
|
||||
name: 'Sponsor Two',
|
||||
contactEmail: 's2@example.com',
|
||||
logoUrl: undefined,
|
||||
websiteUrl: undefined,
|
||||
createdAt: undefined,
|
||||
},
|
||||
],
|
||||
});
|
||||
it('should map sponsors to DTO responseModel', () => {
|
||||
const sponsors: Sponsor[] = [
|
||||
Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Sponsor One',
|
||||
contactEmail: 's1@example.com',
|
||||
logoUrl: 'logo1.png',
|
||||
websiteUrl: 'https://one.example.com',
|
||||
createdAt: new Date('2024-01-01T00:00:00Z'),
|
||||
}),
|
||||
Sponsor.create({
|
||||
id: 'sponsor-2',
|
||||
name: 'Sponsor Two',
|
||||
contactEmail: 's2@example.com',
|
||||
}),
|
||||
];
|
||||
|
||||
presenter.present(result);
|
||||
presenter.present(sponsors);
|
||||
|
||||
expect(presenter.responseModel).toEqual({
|
||||
sponsors: [
|
||||
@@ -64,9 +54,7 @@ describe('GetSponsorsPresenter', () => {
|
||||
id: 'sponsor-2',
|
||||
name: 'Sponsor Two',
|
||||
contactEmail: 's2@example.com',
|
||||
logoUrl: undefined,
|
||||
websiteUrl: undefined,
|
||||
createdAt: undefined,
|
||||
createdAt: expect.any(Date),
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -79,8 +67,8 @@ describe('GetSponsorsPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the model when presented', () => {
|
||||
const result = Result.ok<GetSponsorsResult, never>({ sponsors: [] });
|
||||
presenter.present(result);
|
||||
const sponsors: Sponsor[] = [];
|
||||
presenter.present(sponsors);
|
||||
|
||||
expect(presenter.getResponseModel()).toEqual({ sponsors: [] });
|
||||
});
|
||||
@@ -91,16 +79,26 @@ describe('GetSponsorsPresenter', () => {
|
||||
expect(() => presenter.responseModel).toThrow('Presenter not presented');
|
||||
});
|
||||
|
||||
it('should fallback to empty sponsors list on error', () => {
|
||||
const error = {
|
||||
code: 'REPOSITORY_ERROR' as GetSponsorsErrorCode,
|
||||
details: { message: 'DB error' },
|
||||
} satisfies ApplicationErrorCode<GetSponsorsErrorCode, { message: string }>;
|
||||
const result = Result.err<GetSponsorsResult, typeof error>(error);
|
||||
it('should return the model when presented', () => {
|
||||
const sponsors: Sponsor[] = [
|
||||
Sponsor.create({
|
||||
id: 'sponsor-1',
|
||||
name: 'Sponsor One',
|
||||
contactEmail: 's1@example.com',
|
||||
}),
|
||||
];
|
||||
presenter.present(sponsors);
|
||||
|
||||
presenter.present(result);
|
||||
|
||||
expect(presenter.responseModel).toEqual({ sponsors: [] });
|
||||
expect(presenter.responseModel).toEqual({
|
||||
sponsors: [
|
||||
{
|
||||
id: 'sponsor-1',
|
||||
name: 'Sponsor One',
|
||||
contactEmail: 's1@example.com',
|
||||
createdAt: expect.any(Date),
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,9 +1,4 @@
|
||||
import type { Result } from '@core/shared/application/Result';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
import type {
|
||||
GetSponsorsResult,
|
||||
GetSponsorsErrorCode,
|
||||
} from '@core/racing/application/use-cases/GetSponsorsUseCase';
|
||||
import type { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
|
||||
import { GetSponsorsOutputDTO } from '../dtos/GetSponsorsOutputDTO';
|
||||
import type { SponsorDTO } from '../dtos/SponsorDTO';
|
||||
|
||||
@@ -14,29 +9,26 @@ export class GetSponsorsPresenter {
|
||||
this.model = null;
|
||||
}
|
||||
|
||||
present(
|
||||
result: Result<
|
||||
GetSponsorsResult,
|
||||
ApplicationErrorCode<GetSponsorsErrorCode, { message: string }>
|
||||
>,
|
||||
): void {
|
||||
if (result.isErr()) {
|
||||
// For sponsor listing, fall back to empty list on error
|
||||
this.model = { sponsors: [] };
|
||||
return;
|
||||
}
|
||||
|
||||
const output = result.unwrap();
|
||||
|
||||
present(sponsors: Sponsor[]): void {
|
||||
this.model = {
|
||||
sponsors: output.sponsors.map<SponsorDTO>((sponsor) => ({
|
||||
id: sponsor.id,
|
||||
name: sponsor.name,
|
||||
contactEmail: sponsor.contactEmail,
|
||||
logoUrl: sponsor.logoUrl,
|
||||
websiteUrl: sponsor.websiteUrl,
|
||||
createdAt: sponsor.createdAt,
|
||||
})),
|
||||
sponsors: sponsors.map<SponsorDTO>((sponsor) => {
|
||||
const sponsorData: any = {
|
||||
id: sponsor.id.toString(),
|
||||
name: sponsor.name.toString(),
|
||||
contactEmail: sponsor.contactEmail.toString(),
|
||||
createdAt: sponsor.createdAt.toDate(),
|
||||
};
|
||||
|
||||
if (sponsor.logoUrl) {
|
||||
sponsorData.logoUrl = sponsor.logoUrl.toString();
|
||||
}
|
||||
|
||||
if (sponsor.websiteUrl) {
|
||||
sponsorData.websiteUrl = sponsor.websiteUrl.toString();
|
||||
}
|
||||
|
||||
return sponsorData;
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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;
|
||||
@@ -10,9 +11,19 @@ describe('GetSponsorshipPricingPresenter', () => {
|
||||
|
||||
describe('reset', () => {
|
||||
it('should reset the result to null', () => {
|
||||
const mockResult = { tiers: [] };
|
||||
const mockResult: GetSponsorshipPricingResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
|
||||
const expectedViewModel = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
|
||||
presenter.reset();
|
||||
expect(() => presenter.viewModel).toThrow('Presenter not presented');
|
||||
@@ -21,11 +32,20 @@ describe('GetSponsorshipPricingPresenter', () => {
|
||||
|
||||
describe('present', () => {
|
||||
it('should store the result', () => {
|
||||
const mockResult = { tiers: [] };
|
||||
const mockResult: GetSponsorshipPricingResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,10 +55,19 @@ describe('GetSponsorshipPricingPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockResult = { tiers: [] };
|
||||
const mockResult: GetSponsorshipPricingResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.getViewModel()).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
expect(presenter.getViewModel()).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -48,10 +77,19 @@ describe('GetSponsorshipPricingPresenter', () => {
|
||||
});
|
||||
|
||||
it('should return the result when presented', () => {
|
||||
const mockResult = { tiers: [] };
|
||||
const mockResult: GetSponsorshipPricingResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
presenter.present(mockResult);
|
||||
|
||||
expect(presenter.viewModel).toEqual(mockResult);
|
||||
const expectedViewModel = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: []
|
||||
};
|
||||
expect(presenter.viewModel).toEqual(expectedViewModel);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,12 +1,32 @@
|
||||
import type { GetSponsorshipPricingOutputPort } from '@core/racing/application/ports/output/GetSponsorshipPricingOutputPort';
|
||||
import type { GetSponsorshipPricingResult } from '@core/racing/application/use-cases/GetSponsorshipPricingUseCase';
|
||||
import { GetEntitySponsorshipPricingResultDTO } from '../dtos/GetEntitySponsorshipPricingResultDTO';
|
||||
|
||||
export class GetSponsorshipPricingPresenter {
|
||||
present(outputPort: GetSponsorshipPricingOutputPort): GetEntitySponsorshipPricingResultDTO {
|
||||
return {
|
||||
private result: GetEntitySponsorshipPricingResultDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(outputPort: GetSponsorshipPricingResult): void {
|
||||
this.result = {
|
||||
entityType: outputPort.entityType,
|
||||
entityId: outputPort.entityId,
|
||||
pricing: outputPort.pricing,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
import type { RejectSponsorshipRequestResultDTO } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
import type { RejectSponsorshipRequestResult } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
|
||||
export class RejectSponsorshipRequestPresenter {
|
||||
private result: RejectSponsorshipRequestResultDTO | null = null;
|
||||
private result: RejectSponsorshipRequestResult | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: RejectSponsorshipRequestResultDTO | null) {
|
||||
present(output: RejectSponsorshipRequestResult | null) {
|
||||
this.result = output ?? null;
|
||||
}
|
||||
|
||||
getViewModel(): RejectSponsorshipRequestResultDTO | null {
|
||||
getViewModel(): RejectSponsorshipRequestResult | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): RejectSponsorshipRequestResultDTO | null {
|
||||
get viewModel(): RejectSponsorshipRequestResult | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user