presenter refactoring
This commit is contained in:
@@ -23,6 +23,11 @@ describe('SponsorController', () => {
|
||||
getPendingSponsorshipRequests: vi.fn(),
|
||||
acceptSponsorshipRequest: vi.fn(),
|
||||
rejectSponsorshipRequest: vi.fn(),
|
||||
getSponsorBilling: vi.fn(),
|
||||
getAvailableLeagues: vi.fn(),
|
||||
getLeagueDetail: vi.fn(),
|
||||
getSponsorSettings: vi.fn(),
|
||||
updateSponsorSettings: vi.fn(),
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -35,7 +40,7 @@ describe('SponsorController', () => {
|
||||
describe('getEntitySponsorshipPricing', () => {
|
||||
it('should return sponsorship pricing', async () => {
|
||||
const mockResult = { entityType: 'season', entityId: 'season-1', pricing: [] };
|
||||
sponsorService.getEntitySponsorshipPricing.mockResolvedValue(mockResult);
|
||||
sponsorService.getEntitySponsorshipPricing.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getEntitySponsorshipPricing();
|
||||
|
||||
@@ -47,7 +52,7 @@ describe('SponsorController', () => {
|
||||
describe('getSponsors', () => {
|
||||
it('should return sponsors list', async () => {
|
||||
const mockResult = { sponsors: [] };
|
||||
sponsorService.getSponsors.mockResolvedValue(mockResult);
|
||||
sponsorService.getSponsors.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getSponsors();
|
||||
|
||||
@@ -59,10 +64,10 @@ describe('SponsorController', () => {
|
||||
describe('createSponsor', () => {
|
||||
it('should create sponsor', async () => {
|
||||
const input = { name: 'Test Sponsor', contactEmail: 'test@example.com' };
|
||||
const mockResult = { id: 'sponsor-1', name: 'Test Sponsor' };
|
||||
sponsorService.createSponsor.mockResolvedValue(mockResult);
|
||||
const mockResult = { sponsor: { id: 's1', name: 'Test Sponsor' } };
|
||||
sponsorService.createSponsor.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.createSponsor(input);
|
||||
const result = await controller.createSponsor(input as any);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(sponsorService.createSponsor).toHaveBeenCalledWith(input);
|
||||
@@ -71,9 +76,9 @@ describe('SponsorController', () => {
|
||||
|
||||
describe('getSponsorDashboard', () => {
|
||||
it('should return sponsor dashboard', async () => {
|
||||
const sponsorId = 'sponsor-1';
|
||||
const mockResult = { sponsorId, metrics: {}, sponsoredLeagues: [] };
|
||||
sponsorService.getSponsorDashboard.mockResolvedValue(mockResult);
|
||||
const sponsorId = 's1';
|
||||
const mockResult = { sponsorId, metrics: {} as any, sponsoredLeagues: [], investment: {} as any };
|
||||
sponsorService.getSponsorDashboard.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getSponsorDashboard(sponsorId);
|
||||
|
||||
@@ -82,8 +87,8 @@ describe('SponsorController', () => {
|
||||
});
|
||||
|
||||
it('should return null when sponsor not found', async () => {
|
||||
const sponsorId = 'sponsor-1';
|
||||
sponsorService.getSponsorDashboard.mockResolvedValue(null);
|
||||
const sponsorId = 's1';
|
||||
sponsorService.getSponsorDashboard.mockResolvedValue({ viewModel: null } as any);
|
||||
|
||||
const result = await controller.getSponsorDashboard(sponsorId);
|
||||
|
||||
@@ -93,9 +98,20 @@ describe('SponsorController', () => {
|
||||
|
||||
describe('getSponsorSponsorships', () => {
|
||||
it('should return sponsor sponsorships', async () => {
|
||||
const sponsorId = 'sponsor-1';
|
||||
const mockResult = { sponsorId, sponsorships: [] };
|
||||
sponsorService.getSponsorSponsorships.mockResolvedValue(mockResult);
|
||||
const sponsorId = 's1';
|
||||
const mockResult = {
|
||||
sponsorId,
|
||||
sponsorName: 'S1',
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
totalPlatformFees: 0,
|
||||
currency: 'USD',
|
||||
},
|
||||
};
|
||||
sponsorService.getSponsorSponsorships.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getSponsorSponsorships(sponsorId);
|
||||
|
||||
@@ -104,8 +120,8 @@ describe('SponsorController', () => {
|
||||
});
|
||||
|
||||
it('should return null when sponsor not found', async () => {
|
||||
const sponsorId = 'sponsor-1';
|
||||
sponsorService.getSponsorSponsorships.mockResolvedValue(null);
|
||||
const sponsorId = 's1';
|
||||
sponsorService.getSponsorSponsorships.mockResolvedValue({ viewModel: null } as any);
|
||||
|
||||
const result = await controller.getSponsorSponsorships(sponsorId);
|
||||
|
||||
@@ -115,9 +131,9 @@ describe('SponsorController', () => {
|
||||
|
||||
describe('getSponsor', () => {
|
||||
it('should return sponsor', async () => {
|
||||
const sponsorId = 'sponsor-1';
|
||||
const mockResult = { id: sponsorId, name: 'Test Sponsor' };
|
||||
sponsorService.getSponsor.mockResolvedValue(mockResult);
|
||||
const sponsorId = 's1';
|
||||
const mockResult = { sponsor: { id: sponsorId, name: 'S1' } };
|
||||
sponsorService.getSponsor.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getSponsor(sponsorId);
|
||||
|
||||
@@ -126,8 +142,8 @@ describe('SponsorController', () => {
|
||||
});
|
||||
|
||||
it('should return null when sponsor not found', async () => {
|
||||
const sponsorId = 'sponsor-1';
|
||||
sponsorService.getSponsor.mockResolvedValue(null);
|
||||
const sponsorId = 's1';
|
||||
sponsorService.getSponsor.mockResolvedValue({ viewModel: null } as any);
|
||||
|
||||
const result = await controller.getSponsor(sponsorId);
|
||||
|
||||
@@ -138,8 +154,13 @@ describe('SponsorController', () => {
|
||||
describe('getPendingSponsorshipRequests', () => {
|
||||
it('should return pending sponsorship requests', async () => {
|
||||
const query = { entityType: 'season' as const, entityId: 'season-1' };
|
||||
const mockResult = { entityType: 'season', entityId: 'season-1', requests: [], totalCount: 0 };
|
||||
sponsorService.getPendingSponsorshipRequests.mockResolvedValue(mockResult);
|
||||
const mockResult = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
requests: [],
|
||||
totalCount: 0,
|
||||
};
|
||||
sponsorService.getPendingSponsorshipRequests.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getPendingSponsorshipRequests(query);
|
||||
|
||||
@@ -150,30 +171,33 @@ describe('SponsorController', () => {
|
||||
|
||||
describe('acceptSponsorshipRequest', () => {
|
||||
it('should accept sponsorship request', async () => {
|
||||
const requestId = 'request-1';
|
||||
const input = { respondedBy: 'user-1' };
|
||||
const requestId = 'r1';
|
||||
const input = { respondedBy: 'u1' };
|
||||
const mockResult = {
|
||||
requestId,
|
||||
sponsorshipId: 'sponsorship-1',
|
||||
sponsorshipId: 'sp1',
|
||||
status: 'accepted' as const,
|
||||
acceptedAt: new Date(),
|
||||
platformFee: 10,
|
||||
netAmount: 90,
|
||||
};
|
||||
sponsorService.acceptSponsorshipRequest.mockResolvedValue(mockResult);
|
||||
sponsorService.acceptSponsorshipRequest.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.acceptSponsorshipRequest(requestId, input);
|
||||
const result = await controller.acceptSponsorshipRequest(requestId, input as any);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(sponsorService.acceptSponsorshipRequest).toHaveBeenCalledWith(requestId, input.respondedBy);
|
||||
expect(sponsorService.acceptSponsorshipRequest).toHaveBeenCalledWith(
|
||||
requestId,
|
||||
input.respondedBy,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return null on error', async () => {
|
||||
const requestId = 'request-1';
|
||||
const input = { respondedBy: 'user-1' };
|
||||
sponsorService.acceptSponsorshipRequest.mockResolvedValue(null);
|
||||
const requestId = 'r1';
|
||||
const input = { respondedBy: 'u1' };
|
||||
sponsorService.acceptSponsorshipRequest.mockResolvedValue({ viewModel: null } as any);
|
||||
|
||||
const result = await controller.acceptSponsorshipRequest(requestId, input);
|
||||
const result = await controller.acceptSponsorshipRequest(requestId, input as any);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
@@ -181,30 +205,118 @@ describe('SponsorController', () => {
|
||||
|
||||
describe('rejectSponsorshipRequest', () => {
|
||||
it('should reject sponsorship request', async () => {
|
||||
const requestId = 'request-1';
|
||||
const input = { respondedBy: 'user-1', reason: 'Not interested' };
|
||||
const requestId = 'r1';
|
||||
const input = { respondedBy: 'u1', reason: 'Not interested' };
|
||||
const mockResult = {
|
||||
requestId,
|
||||
status: 'rejected' as const,
|
||||
rejectedAt: new Date(),
|
||||
reason: 'Not interested',
|
||||
};
|
||||
sponsorService.rejectSponsorshipRequest.mockResolvedValue(mockResult);
|
||||
sponsorService.rejectSponsorshipRequest.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.rejectSponsorshipRequest(requestId, input);
|
||||
const result = await controller.rejectSponsorshipRequest(requestId, input as any);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(sponsorService.rejectSponsorshipRequest).toHaveBeenCalledWith(requestId, input.respondedBy, input.reason);
|
||||
expect(sponsorService.rejectSponsorshipRequest).toHaveBeenCalledWith(
|
||||
requestId,
|
||||
input.respondedBy,
|
||||
input.reason,
|
||||
);
|
||||
});
|
||||
|
||||
it('should return null on error', async () => {
|
||||
const requestId = 'request-1';
|
||||
const input = { respondedBy: 'user-1' };
|
||||
sponsorService.rejectSponsorshipRequest.mockResolvedValue(null);
|
||||
const requestId = 'r1';
|
||||
const input = { respondedBy: 'u1' };
|
||||
sponsorService.rejectSponsorshipRequest.mockResolvedValue({ viewModel: null } as any);
|
||||
|
||||
const result = await controller.rejectSponsorshipRequest(requestId, input);
|
||||
const result = await controller.rejectSponsorshipRequest(requestId, input as any);
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorBilling', () => {
|
||||
it('should return sponsor billing', async () => {
|
||||
const sponsorId = 's1';
|
||||
const mockResult = {
|
||||
paymentMethods: [],
|
||||
invoices: [],
|
||||
stats: {
|
||||
totalSpent: 0,
|
||||
pendingAmount: 0,
|
||||
nextPaymentDate: '2025-01-01',
|
||||
nextPaymentAmount: 0,
|
||||
activeSponsorships: 0,
|
||||
averageMonthlySpend: 0,
|
||||
},
|
||||
};
|
||||
sponsorService.getSponsorBilling.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getSponsorBilling(sponsorId);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(sponsorService.getSponsorBilling).toHaveBeenCalledWith(sponsorId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAvailableLeagues', () => {
|
||||
it('should return available leagues', async () => {
|
||||
const mockResult: any[] = [];
|
||||
sponsorService.getAvailableLeagues.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getAvailableLeagues();
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(sponsorService.getAvailableLeagues).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLeagueDetail', () => {
|
||||
it('should return league detail', async () => {
|
||||
const leagueId = 'league-1';
|
||||
const mockResult = {
|
||||
league: { id: leagueId } as any,
|
||||
drivers: [],
|
||||
races: [],
|
||||
};
|
||||
sponsorService.getLeagueDetail.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getLeagueDetail(leagueId);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(sponsorService.getLeagueDetail).toHaveBeenCalledWith(leagueId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorSettings', () => {
|
||||
it('should return sponsor settings', async () => {
|
||||
const sponsorId = 's1';
|
||||
const mockResult = {
|
||||
profile: {} as any,
|
||||
notifications: {} as any,
|
||||
privacy: {} as any,
|
||||
};
|
||||
sponsorService.getSponsorSettings.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.getSponsorSettings(sponsorId);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(sponsorService.getSponsorSettings).toHaveBeenCalledWith(sponsorId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateSponsorSettings', () => {
|
||||
it('should update sponsor settings', async () => {
|
||||
const sponsorId = 's1';
|
||||
const input = {};
|
||||
const mockResult = { success: true };
|
||||
sponsorService.updateSponsorSettings.mockResolvedValue({ viewModel: mockResult } as any);
|
||||
|
||||
const result = await controller.updateSponsorSettings(sponsorId, input);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(sponsorService.updateSponsorSettings).toHaveBeenCalledWith(sponsorId, input);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,7 +23,7 @@ import { RaceDTO } from './dtos/RaceDTO';
|
||||
import { SponsorProfileDTO } from './dtos/SponsorProfileDTO';
|
||||
import { NotificationSettingsDTO } from './dtos/NotificationSettingsDTO';
|
||||
import { PrivacySettingsDTO } from './dtos/PrivacySettingsDTO';
|
||||
import type { AcceptSponsorshipRequestResultPort } from '@core/racing/application/ports/output/AcceptSponsorshipRequestResultPort';
|
||||
import type { AcceptSponsorshipRequestResultViewModel } from './presenters/AcceptSponsorshipRequestPresenter';
|
||||
import type { RejectSponsorshipRequestResultDTO } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
|
||||
@ApiTags('sponsors')
|
||||
@@ -33,129 +33,212 @@ export class SponsorController {
|
||||
|
||||
@Get('pricing')
|
||||
@ApiOperation({ summary: 'Get sponsorship pricing for an entity' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsorship pricing', type: GetEntitySponsorshipPricingResultDTO })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Sponsorship pricing',
|
||||
type: GetEntitySponsorshipPricingResultDTO,
|
||||
})
|
||||
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDTO> {
|
||||
return this.sponsorService.getEntitySponsorshipPricing();
|
||||
const presenter = await this.sponsorService.getEntitySponsorshipPricing();
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Get all sponsors' })
|
||||
@ApiResponse({ status: 200, description: 'List of sponsors', type: GetSponsorsOutputDTO })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'List of sponsors',
|
||||
type: GetSponsorsOutputDTO,
|
||||
})
|
||||
async getSponsors(): Promise<GetSponsorsOutputDTO> {
|
||||
return this.sponsorService.getSponsors();
|
||||
const presenter = await this.sponsorService.getSponsors();
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Post()
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
@ApiOperation({ summary: 'Create a new sponsor' })
|
||||
@ApiResponse({ status: 201, description: 'Sponsor created', type: CreateSponsorOutputDTO })
|
||||
@ApiResponse({
|
||||
status: 201,
|
||||
description: 'Sponsor created',
|
||||
type: CreateSponsorOutputDTO,
|
||||
})
|
||||
async createSponsor(@Body() input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDTO> {
|
||||
return this.sponsorService.createSponsor(input);
|
||||
const presenter = await this.sponsorService.createSponsor(input);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
// Add other Sponsor endpoints here based on other presenters
|
||||
@Get('dashboard/:sponsorId')
|
||||
@ApiOperation({ summary: 'Get sponsor dashboard metrics and sponsored leagues' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsor dashboard data', type: SponsorDashboardDTO })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Sponsor dashboard data',
|
||||
type: SponsorDashboardDTO,
|
||||
})
|
||||
@ApiResponse({ status: 404, description: 'Sponsor not found' })
|
||||
async getSponsorDashboard(@Param('sponsorId') sponsorId: string): Promise<SponsorDashboardDTO | null> {
|
||||
return this.sponsorService.getSponsorDashboard({ sponsorId } as GetSponsorDashboardQueryParamsDTO);
|
||||
async getSponsorDashboard(
|
||||
@Param('sponsorId') sponsorId: string,
|
||||
): Promise<SponsorDashboardDTO | null> {
|
||||
const presenter = await this.sponsorService.getSponsorDashboard({
|
||||
sponsorId,
|
||||
} as GetSponsorDashboardQueryParamsDTO);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get(':sponsorId/sponsorships')
|
||||
@ApiOperation({ summary: 'Get all sponsorships for a given sponsor' })
|
||||
@ApiResponse({ status: 200, description: 'List of sponsorships', type: SponsorSponsorshipsDTO })
|
||||
@ApiOperation({
|
||||
summary: 'Get all sponsorships for a given sponsor',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'List of sponsorships',
|
||||
type: SponsorSponsorshipsDTO,
|
||||
})
|
||||
@ApiResponse({ status: 404, description: 'Sponsor not found' })
|
||||
async getSponsorSponsorships(@Param('sponsorId') sponsorId: string): Promise<SponsorSponsorshipsDTO | null> {
|
||||
return this.sponsorService.getSponsorSponsorships({ sponsorId } as GetSponsorSponsorshipsQueryParamsDTO);
|
||||
async getSponsorSponsorships(
|
||||
@Param('sponsorId') sponsorId: string,
|
||||
): Promise<SponsorSponsorshipsDTO | null> {
|
||||
const presenter = await this.sponsorService.getSponsorSponsorships({
|
||||
sponsorId,
|
||||
} as GetSponsorSponsorshipsQueryParamsDTO);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get(':sponsorId')
|
||||
@ApiOperation({ summary: 'Get a sponsor by ID' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsor data', type: GetSponsorOutputDTO })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Sponsor data',
|
||||
type: GetSponsorOutputDTO,
|
||||
})
|
||||
@ApiResponse({ status: 404, description: 'Sponsor not found' })
|
||||
async getSponsor(@Param('sponsorId') sponsorId: string): Promise<GetSponsorOutputDTO | null> {
|
||||
return this.sponsorService.getSponsor(sponsorId);
|
||||
const presenter = await this.sponsorService.getSponsor(sponsorId);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get('requests')
|
||||
@ApiOperation({ summary: 'Get pending sponsorship requests' })
|
||||
@ApiResponse({ status: 200, description: 'List of pending sponsorship requests', type: GetPendingSponsorshipRequestsOutputDTO })
|
||||
async getPendingSponsorshipRequests(@Query() query: { entityType: string; entityId: string }): Promise<GetPendingSponsorshipRequestsOutputDTO> {
|
||||
return this.sponsorService.getPendingSponsorshipRequests(query as { entityType: import('@core/racing/domain/entities/SponsorshipRequest').SponsorableEntityType; entityId: string });
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'List of pending sponsorship requests',
|
||||
type: GetPendingSponsorshipRequestsOutputDTO,
|
||||
})
|
||||
async getPendingSponsorshipRequests(
|
||||
@Query() query: { entityType: string; entityId: string },
|
||||
): Promise<GetPendingSponsorshipRequestsOutputDTO | null> {
|
||||
const presenter = await this.sponsorService.getPendingSponsorshipRequests(
|
||||
query as {
|
||||
entityType: import('@core/racing/domain/entities/SponsorshipRequest').SponsorableEntityType;
|
||||
entityId: string;
|
||||
},
|
||||
);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Post('requests/:requestId/accept')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Accept a sponsorship request' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsorship request accepted' })
|
||||
@ApiResponse({ status: 400, description: 'Invalid request' })
|
||||
@ApiResponse({ status: 404, description: 'Request not found' })
|
||||
async acceptSponsorshipRequest(@Param('requestId') requestId: string, @Body() input: AcceptSponsorshipRequestInputDTO): Promise<AcceptSponsorshipRequestResultPort | null> {
|
||||
return this.sponsorService.acceptSponsorshipRequest(requestId, input.respondedBy);
|
||||
}
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Accept a sponsorship request' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsorship request accepted' })
|
||||
@ApiResponse({ status: 400, description: 'Invalid request' })
|
||||
@ApiResponse({ status: 404, description: 'Request not found' })
|
||||
async acceptSponsorshipRequest(
|
||||
@Param('requestId') requestId: string,
|
||||
@Body() input: AcceptSponsorshipRequestInputDTO,
|
||||
): Promise<AcceptSponsorshipRequestResultViewModel | null> {
|
||||
const presenter = await this.sponsorService.acceptSponsorshipRequest(
|
||||
requestId,
|
||||
input.respondedBy,
|
||||
);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Post('requests/:requestId/reject')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Reject a sponsorship request' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsorship request rejected' })
|
||||
@ApiResponse({ status: 400, description: 'Invalid request' })
|
||||
@ApiResponse({ status: 404, description: 'Request not found' })
|
||||
async rejectSponsorshipRequest(@Param('requestId') requestId: string, @Body() input: RejectSponsorshipRequestInputDTO): Promise<RejectSponsorshipRequestResultDTO | null> {
|
||||
return this.sponsorService.rejectSponsorshipRequest(requestId, input.respondedBy, input.reason);
|
||||
}
|
||||
@Post('requests/:requestId/reject')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Reject a sponsorship request' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsorship request rejected' })
|
||||
@ApiResponse({ status: 400, description: 'Invalid request' })
|
||||
@ApiResponse({ status: 404, description: 'Request not found' })
|
||||
async rejectSponsorshipRequest(
|
||||
@Param('requestId') requestId: string,
|
||||
@Body() input: RejectSponsorshipRequestInputDTO,
|
||||
): Promise<RejectSponsorshipRequestResultDTO | null> {
|
||||
const presenter = await this.sponsorService.rejectSponsorshipRequest(
|
||||
requestId,
|
||||
input.respondedBy,
|
||||
input.reason,
|
||||
);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get('billing/:sponsorId')
|
||||
@ApiOperation({ summary: 'Get sponsor billing information' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsor billing data', type: Object })
|
||||
async getSponsorBilling(@Param('sponsorId') sponsorId: string): Promise<{
|
||||
paymentMethods: PaymentMethodDTO[];
|
||||
invoices: InvoiceDTO[];
|
||||
stats: BillingStatsDTO;
|
||||
}> {
|
||||
return this.sponsorService.getSponsorBilling(sponsorId);
|
||||
}
|
||||
@Get('billing/:sponsorId')
|
||||
@ApiOperation({ summary: 'Get sponsor billing information' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsor billing data', type: Object })
|
||||
async getSponsorBilling(
|
||||
@Param('sponsorId') sponsorId: string,
|
||||
): Promise<{
|
||||
paymentMethods: PaymentMethodDTO[];
|
||||
invoices: InvoiceDTO[];
|
||||
stats: BillingStatsDTO;
|
||||
}> {
|
||||
const presenter = await this.sponsorService.getSponsorBilling(sponsorId);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get('leagues/available')
|
||||
@ApiOperation({ summary: 'Get available leagues for sponsorship' })
|
||||
@ApiResponse({ status: 200, description: 'Available leagues', type: [AvailableLeagueDTO] })
|
||||
async getAvailableLeagues(): Promise<AvailableLeagueDTO[]> {
|
||||
return this.sponsorService.getAvailableLeagues();
|
||||
}
|
||||
@Get('leagues/available')
|
||||
@ApiOperation({ summary: 'Get available leagues for sponsorship' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Available leagues',
|
||||
type: [AvailableLeagueDTO],
|
||||
})
|
||||
async getAvailableLeagues(): Promise<AvailableLeagueDTO[] | null> {
|
||||
const presenter = await this.sponsorService.getAvailableLeagues();
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get('leagues/:leagueId/detail')
|
||||
@ApiOperation({ summary: 'Get detailed league information for sponsors' })
|
||||
@ApiResponse({ status: 200, description: 'League detail data', type: Object })
|
||||
async getLeagueDetail(@Param('leagueId') leagueId: string): Promise<{
|
||||
league: LeagueDetailDTO;
|
||||
drivers: DriverDTO[];
|
||||
races: RaceDTO[];
|
||||
}> {
|
||||
return this.sponsorService.getLeagueDetail(leagueId);
|
||||
}
|
||||
@Get('leagues/:leagueId/detail')
|
||||
@ApiOperation({ summary: 'Get detailed league information for sponsors' })
|
||||
@ApiResponse({ status: 200, description: 'League detail data', type: Object })
|
||||
async getLeagueDetail(
|
||||
@Param('leagueId') leagueId: string,
|
||||
): Promise<{
|
||||
league: LeagueDetailDTO;
|
||||
drivers: DriverDTO[];
|
||||
races: RaceDTO[];
|
||||
} | null> {
|
||||
const presenter = await this.sponsorService.getLeagueDetail(leagueId);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Get('settings/:sponsorId')
|
||||
@ApiOperation({ summary: 'Get sponsor settings' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsor settings', type: Object })
|
||||
async getSponsorSettings(@Param('sponsorId') sponsorId: string): Promise<{
|
||||
profile: SponsorProfileDTO;
|
||||
notifications: NotificationSettingsDTO;
|
||||
privacy: PrivacySettingsDTO;
|
||||
}> {
|
||||
return this.sponsorService.getSponsorSettings(sponsorId);
|
||||
}
|
||||
@Get('settings/:sponsorId')
|
||||
@ApiOperation({ summary: 'Get sponsor settings' })
|
||||
@ApiResponse({ status: 200, description: 'Sponsor settings', type: Object })
|
||||
async getSponsorSettings(
|
||||
@Param('sponsorId') sponsorId: string,
|
||||
): Promise<{
|
||||
profile: SponsorProfileDTO;
|
||||
notifications: NotificationSettingsDTO;
|
||||
privacy: PrivacySettingsDTO;
|
||||
} | null> {
|
||||
const presenter = await this.sponsorService.getSponsorSettings(sponsorId);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
|
||||
@Put('settings/:sponsorId')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Update sponsor settings' })
|
||||
@ApiResponse({ status: 200, description: 'Settings updated successfully' })
|
||||
async updateSponsorSettings(
|
||||
@Param('sponsorId') sponsorId: string,
|
||||
@Body() input: {
|
||||
profile?: Partial<SponsorProfileDTO>;
|
||||
notifications?: Partial<NotificationSettingsDTO>;
|
||||
privacy?: Partial<PrivacySettingsDTO>;
|
||||
}
|
||||
): Promise<void> {
|
||||
return this.sponsorService.updateSponsorSettings(sponsorId, input);
|
||||
}
|
||||
@Put('settings/:sponsorId')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Update sponsor settings' })
|
||||
@ApiResponse({ status: 200, description: 'Settings updated successfully' })
|
||||
async updateSponsorSettings(
|
||||
@Param('sponsorId') sponsorId: string,
|
||||
@Body()
|
||||
input: {
|
||||
profile?: Partial<SponsorProfileDTO>;
|
||||
notifications?: Partial<NotificationSettingsDTO>;
|
||||
privacy?: Partial<PrivacySettingsDTO>;
|
||||
},
|
||||
): Promise<{ success: boolean; errorCode?: string; message?: string } | null> {
|
||||
const presenter = await this.sponsorService.updateSponsorSettings(sponsorId, input);
|
||||
return presenter.viewModel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
|
||||
import { SponsorService } from './SponsorService';
|
||||
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';
|
||||
@@ -9,8 +10,7 @@ import type { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSp
|
||||
import type { GetPendingSponsorshipRequestsUseCase } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
|
||||
import type { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
|
||||
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 { SponsorService } from './SponsorService';
|
||||
|
||||
describe('SponsorService', () => {
|
||||
let service: SponsorService;
|
||||
@@ -23,12 +23,7 @@ describe('SponsorService', () => {
|
||||
let getPendingSponsorshipRequestsUseCase: { execute: Mock };
|
||||
let acceptSponsorshipRequestUseCase: { execute: Mock };
|
||||
let rejectSponsorshipRequestUseCase: { execute: Mock };
|
||||
let logger: {
|
||||
debug: Mock;
|
||||
info: Mock;
|
||||
warn: Mock;
|
||||
error: Mock;
|
||||
};
|
||||
let logger: Logger;
|
||||
|
||||
beforeEach(() => {
|
||||
getSponsorshipPricingUseCase = { execute: vi.fn() };
|
||||
@@ -45,7 +40,7 @@ describe('SponsorService', () => {
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
error: vi.fn(),
|
||||
};
|
||||
} as unknown as Logger;
|
||||
|
||||
service = new SponsorService(
|
||||
getSponsorshipPricingUseCase as unknown as GetSponsorshipPricingUseCase,
|
||||
@@ -57,136 +52,199 @@ describe('SponsorService', () => {
|
||||
getPendingSponsorshipRequestsUseCase as unknown as GetPendingSponsorshipRequestsUseCase,
|
||||
acceptSponsorshipRequestUseCase as unknown as AcceptSponsorshipRequestUseCase,
|
||||
rejectSponsorshipRequestUseCase as unknown as RejectSponsorshipRequestUseCase,
|
||||
logger as unknown as Logger,
|
||||
logger,
|
||||
);
|
||||
});
|
||||
|
||||
describe('getEntitySponsorshipPricing', () => {
|
||||
it('should return sponsorship pricing', async () => {
|
||||
const mockPresenter = {
|
||||
viewModel: { entityType: 'season', entityId: 'season-1', pricing: [] },
|
||||
it('returns presenter with pricing data on success', async () => {
|
||||
const outputPort = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: [
|
||||
{ id: 'tier-gold', level: 'Gold', price: 500, currency: 'USD' },
|
||||
],
|
||||
};
|
||||
getSponsorshipPricingUseCase.execute.mockResolvedValue(undefined);
|
||||
getSponsorshipPricingUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
// Mock the presenter
|
||||
const originalGetSponsorshipPricingPresenter = await import('./presenters/GetSponsorshipPricingPresenter');
|
||||
const mockPresenterClass = vi.fn().mockImplementation(() => mockPresenter);
|
||||
vi.doMock('./presenters/GetSponsorshipPricingPresenter', () => ({
|
||||
GetSponsorshipPricingPresenter: mockPresenterClass,
|
||||
}));
|
||||
const presenter = await service.getEntitySponsorshipPricing();
|
||||
|
||||
const result = await service.getEntitySponsorshipPricing();
|
||||
expect(presenter.viewModel).toEqual({
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
pricing: [
|
||||
{ id: 'tier-gold', level: 'Gold', price: 500, currency: 'USD' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
expect(result).toEqual(mockPresenter.viewModel);
|
||||
expect(getSponsorshipPricingUseCase.execute).toHaveBeenCalledWith(undefined, mockPresenter);
|
||||
it('returns empty pricing on error', async () => {
|
||||
getSponsorshipPricingUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
|
||||
|
||||
const presenter = await service.getEntitySponsorshipPricing();
|
||||
|
||||
expect(presenter.viewModel).toEqual({
|
||||
entityType: 'season',
|
||||
entityId: '',
|
||||
pricing: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsors', () => {
|
||||
it('should return sponsors list', async () => {
|
||||
const mockPresenter = {
|
||||
viewModel: { sponsors: [] },
|
||||
};
|
||||
getSponsorsUseCase.execute.mockResolvedValue(undefined);
|
||||
it('returns sponsors in presenter on success', async () => {
|
||||
const outputPort = { sponsors: [{ id: 's1', name: 'S1', contactEmail: 's1@test', createdAt: new Date() }] };
|
||||
getSponsorsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const result = await service.getSponsors();
|
||||
const presenter = await service.getSponsors();
|
||||
|
||||
expect(result).toEqual(mockPresenter.viewModel);
|
||||
expect(getSponsorsUseCase.execute).toHaveBeenCalledWith(undefined, expect.any(Object));
|
||||
expect(presenter.viewModel).toEqual({ sponsors: outputPort.sponsors });
|
||||
});
|
||||
|
||||
it('returns empty list on error', async () => {
|
||||
getSponsorsUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
|
||||
|
||||
const presenter = await service.getSponsors();
|
||||
|
||||
expect(presenter.viewModel).toEqual({ sponsors: [] });
|
||||
});
|
||||
});
|
||||
|
||||
describe('createSponsor', () => {
|
||||
it('should create sponsor successfully', async () => {
|
||||
const input = { name: 'Test Sponsor', contactEmail: 'test@example.com' };
|
||||
const mockPresenter = {
|
||||
viewModel: { id: 'sponsor-1', name: 'Test Sponsor' },
|
||||
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(),
|
||||
},
|
||||
};
|
||||
createSponsorUseCase.execute.mockResolvedValue(undefined);
|
||||
createSponsorUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const result = await service.createSponsor(input);
|
||||
const presenter = await service.createSponsor(input as any);
|
||||
|
||||
expect(result).toEqual(mockPresenter.viewModel);
|
||||
expect(createSponsorUseCase.execute).toHaveBeenCalledWith(input, expect.any(Object));
|
||||
expect(presenter.viewModel).toEqual({ sponsor: outputPort.sponsor });
|
||||
});
|
||||
|
||||
it('throws on error', async () => {
|
||||
const input = { 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');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorDashboard', () => {
|
||||
it('should return sponsor dashboard', async () => {
|
||||
const params = { sponsorId: 'sponsor-1' };
|
||||
const mockPresenter = {
|
||||
viewModel: { sponsorId: 'sponsor-1', metrics: {}, sponsoredLeagues: [] },
|
||||
it('returns dashboard in presenter on success', async () => {
|
||||
const params = { sponsorId: 's1' };
|
||||
const outputPort = {
|
||||
sponsorId: 's1',
|
||||
sponsorName: 'S1',
|
||||
metrics: {} as any,
|
||||
sponsoredLeagues: [],
|
||||
investment: {} as any,
|
||||
};
|
||||
getSponsorDashboardUseCase.execute.mockResolvedValue(undefined);
|
||||
getSponsorDashboardUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const result = await service.getSponsorDashboard(params);
|
||||
const presenter = await service.getSponsorDashboard(params as any);
|
||||
|
||||
expect(result).toEqual(mockPresenter.viewModel);
|
||||
expect(getSponsorDashboardUseCase.execute).toHaveBeenCalledWith(params, expect.any(Object));
|
||||
expect(presenter.viewModel).toEqual(outputPort);
|
||||
});
|
||||
|
||||
it('returns null in presenter on error', async () => {
|
||||
const params = { sponsorId: 's1' };
|
||||
getSponsorDashboardUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
|
||||
|
||||
const presenter = await service.getSponsorDashboard(params as any);
|
||||
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorSponsorships', () => {
|
||||
it('should return sponsor sponsorships', async () => {
|
||||
const params = { sponsorId: 'sponsor-1' };
|
||||
const mockPresenter = {
|
||||
viewModel: { sponsorId: 'sponsor-1', sponsorships: [] },
|
||||
it('returns sponsorships in presenter on success', async () => {
|
||||
const params = { sponsorId: 's1' };
|
||||
const outputPort = {
|
||||
sponsorId: 's1',
|
||||
sponsorName: 'S1',
|
||||
sponsorships: [],
|
||||
summary: {
|
||||
totalSponsorships: 0,
|
||||
activeSponsorships: 0,
|
||||
totalInvestment: 0,
|
||||
totalPlatformFees: 0,
|
||||
currency: 'USD',
|
||||
},
|
||||
};
|
||||
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(undefined);
|
||||
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const result = await service.getSponsorSponsorships(params);
|
||||
const presenter = await service.getSponsorSponsorships(params as any);
|
||||
|
||||
expect(result).toEqual(mockPresenter.viewModel);
|
||||
expect(getSponsorSponsorshipsUseCase.execute).toHaveBeenCalledWith(params, expect.any(Object));
|
||||
expect(presenter.viewModel).toEqual(outputPort);
|
||||
});
|
||||
|
||||
it('returns null in presenter on error', async () => {
|
||||
const params = { sponsorId: 's1' };
|
||||
getSponsorSponsorshipsUseCase.execute.mockResolvedValue(
|
||||
Result.err({ code: 'REPOSITORY_ERROR' }),
|
||||
);
|
||||
|
||||
const presenter = await service.getSponsorSponsorships(params as any);
|
||||
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsor', () => {
|
||||
it('should return sponsor when found', async () => {
|
||||
const sponsorId = 'sponsor-1';
|
||||
const mockSponsor = { id: sponsorId, name: 'Test Sponsor' };
|
||||
getSponsorUseCase.execute.mockResolvedValue(Result.ok(mockSponsor));
|
||||
it('returns sponsor in presenter when found', async () => {
|
||||
const sponsorId = 's1';
|
||||
const output = { sponsor: { id: sponsorId, name: 'S1' } };
|
||||
getSponsorUseCase.execute.mockResolvedValue(Result.ok(output));
|
||||
|
||||
const result = await service.getSponsor(sponsorId);
|
||||
const presenter = await service.getSponsor(sponsorId);
|
||||
|
||||
expect(result).toEqual(mockSponsor);
|
||||
expect(getSponsorUseCase.execute).toHaveBeenCalledWith({ sponsorId });
|
||||
expect(presenter.viewModel).toEqual({ sponsor: output.sponsor });
|
||||
});
|
||||
|
||||
it('should return null when sponsor not found', async () => {
|
||||
const sponsorId = 'sponsor-1';
|
||||
getSponsorUseCase.execute.mockResolvedValue(Result.err({ code: 'NOT_FOUND' }));
|
||||
it('returns null in presenter when not found', async () => {
|
||||
const sponsorId = 's1';
|
||||
getSponsorUseCase.execute.mockResolvedValue(Result.ok(null));
|
||||
|
||||
const result = await service.getSponsor(sponsorId);
|
||||
const presenter = await service.getSponsor(sponsorId);
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPendingSponsorshipRequests', () => {
|
||||
it('should return pending sponsorship requests', async () => {
|
||||
it('returns requests in presenter on success', async () => {
|
||||
const params = { entityType: 'season' as const, entityId: 'season-1' };
|
||||
const mockResult = {
|
||||
const outputPort = {
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
requests: [],
|
||||
totalCount: 0,
|
||||
};
|
||||
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.ok(mockResult));
|
||||
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const result = await service.getPendingSponsorshipRequests(params);
|
||||
const presenter = await service.getPendingSponsorshipRequests(params);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(getPendingSponsorshipRequestsUseCase.execute).toHaveBeenCalledWith(params);
|
||||
expect(presenter.viewModel).toEqual(outputPort);
|
||||
});
|
||||
|
||||
it('should return empty result on error', async () => {
|
||||
it('returns empty result on error', async () => {
|
||||
const params = { entityType: 'season' as const, entityId: 'season-1' };
|
||||
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(Result.err({ code: 'REPOSITORY_ERROR' }));
|
||||
getPendingSponsorshipRequestsUseCase.execute.mockResolvedValue(
|
||||
Result.err({ code: 'REPOSITORY_ERROR' }),
|
||||
);
|
||||
|
||||
const result = await service.getPendingSponsorshipRequests(params);
|
||||
const presenter = await service.getPendingSponsorshipRequests(params);
|
||||
|
||||
expect(result).toEqual({
|
||||
expect(presenter.viewModel).toEqual({
|
||||
entityType: 'season',
|
||||
entityId: 'season-1',
|
||||
requests: [],
|
||||
@@ -196,63 +254,113 @@ describe('SponsorService', () => {
|
||||
});
|
||||
|
||||
describe('acceptSponsorshipRequest', () => {
|
||||
it('should accept sponsorship request successfully', async () => {
|
||||
const requestId = 'request-1';
|
||||
const respondedBy = 'user-1';
|
||||
const mockResult = {
|
||||
it('returns accept result in presenter on success', async () => {
|
||||
const requestId = 'r1';
|
||||
const respondedBy = 'u1';
|
||||
const outputPort = {
|
||||
requestId,
|
||||
sponsorshipId: 'sponsorship-1',
|
||||
sponsorshipId: 'sp1',
|
||||
status: 'accepted' as const,
|
||||
acceptedAt: new Date(),
|
||||
platformFee: 10,
|
||||
netAmount: 90,
|
||||
};
|
||||
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(mockResult));
|
||||
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(outputPort));
|
||||
|
||||
const result = await service.acceptSponsorshipRequest(requestId, respondedBy);
|
||||
const presenter = await service.acceptSponsorshipRequest(requestId, respondedBy);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(acceptSponsorshipRequestUseCase.execute).toHaveBeenCalledWith({ requestId, respondedBy });
|
||||
expect(presenter.viewModel).toEqual(outputPort);
|
||||
});
|
||||
|
||||
it('should return null on error', async () => {
|
||||
const requestId = 'request-1';
|
||||
const respondedBy = 'user-1';
|
||||
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(Result.err({ code: 'NOT_FOUND' }));
|
||||
it('returns null in presenter on error', async () => {
|
||||
const requestId = 'r1';
|
||||
const respondedBy = 'u1';
|
||||
acceptSponsorshipRequestUseCase.execute.mockResolvedValue(
|
||||
Result.err({ code: 'SPONSORSHIP_REQUEST_NOT_FOUND' }),
|
||||
);
|
||||
|
||||
const result = await service.acceptSponsorshipRequest(requestId, respondedBy);
|
||||
const presenter = await service.acceptSponsorshipRequest(requestId, respondedBy);
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('rejectSponsorshipRequest', () => {
|
||||
it('should reject sponsorship request successfully', async () => {
|
||||
const requestId = 'request-1';
|
||||
const respondedBy = 'user-1';
|
||||
it('returns reject result in presenter on success', async () => {
|
||||
const requestId = 'r1';
|
||||
const respondedBy = 'u1';
|
||||
const reason = 'Not interested';
|
||||
const mockResult = {
|
||||
const output = {
|
||||
requestId,
|
||||
status: 'rejected' as const,
|
||||
rejectedAt: new Date(),
|
||||
reason,
|
||||
};
|
||||
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(mockResult));
|
||||
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.ok(output));
|
||||
|
||||
const result = await service.rejectSponsorshipRequest(requestId, respondedBy, reason);
|
||||
const presenter = await service.rejectSponsorshipRequest(requestId, respondedBy, reason);
|
||||
|
||||
expect(result).toEqual(mockResult);
|
||||
expect(rejectSponsorshipRequestUseCase.execute).toHaveBeenCalledWith({ requestId, respondedBy, reason });
|
||||
expect(presenter.viewModel).toEqual(output);
|
||||
});
|
||||
|
||||
it('should return null on error', async () => {
|
||||
const requestId = 'request-1';
|
||||
const respondedBy = 'user-1';
|
||||
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(Result.err({ code: 'NOT_FOUND' }));
|
||||
it('returns null in presenter on error', async () => {
|
||||
const requestId = 'r1';
|
||||
const respondedBy = 'u1';
|
||||
rejectSponsorshipRequestUseCase.execute.mockResolvedValue(
|
||||
Result.err({ code: 'SPONSORSHIP_REQUEST_NOT_FOUND' }),
|
||||
);
|
||||
|
||||
const result = await service.rejectSponsorshipRequest(requestId, respondedBy);
|
||||
const presenter = await service.rejectSponsorshipRequest(requestId, respondedBy);
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(presenter.viewModel).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorBilling', () => {
|
||||
it('returns mock billing data in presenter', async () => {
|
||||
const presenter = await service.getSponsorBilling('s1');
|
||||
|
||||
expect(presenter.viewModel).not.toBeNull();
|
||||
expect(presenter.viewModel?.paymentMethods).toBeInstanceOf(Array);
|
||||
expect(presenter.viewModel?.invoices).toBeInstanceOf(Array);
|
||||
expect(presenter.viewModel?.stats).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAvailableLeagues', () => {
|
||||
it('returns mock leagues in presenter', async () => {
|
||||
const presenter = await service.getAvailableLeagues();
|
||||
|
||||
expect(presenter.viewModel).not.toBeNull();
|
||||
expect(presenter.viewModel?.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getLeagueDetail', () => {
|
||||
it('returns league detail in presenter', async () => {
|
||||
const presenter = await service.getLeagueDetail('league-1');
|
||||
|
||||
expect(presenter.viewModel).not.toBeNull();
|
||||
expect(presenter.viewModel?.league.id).toBe('league-1');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSponsorSettings', () => {
|
||||
it('returns settings in presenter', async () => {
|
||||
const presenter = await service.getSponsorSettings('s1');
|
||||
|
||||
expect(presenter.viewModel).not.toBeNull();
|
||||
expect(presenter.viewModel?.profile).toBeDefined();
|
||||
expect(presenter.viewModel?.notifications).toBeDefined();
|
||||
expect(presenter.viewModel?.privacy).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateSponsorSettings', () => {
|
||||
it('returns success result in presenter', async () => {
|
||||
const presenter = await service.updateSponsorSettings('s1', {});
|
||||
|
||||
expect(presenter.viewModel).toEqual({ success: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import { GetEntitySponsorshipPricingResultDTO } from './dtos/GetEntitySponsorshipPricingResultDTO';
|
||||
import { GetSponsorsOutputDTO } from './dtos/GetSponsorsOutputDTO';
|
||||
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 { SponsorSponsorshipsDTO } from './dtos/SponsorSponsorshipsDTO';
|
||||
import { GetSponsorOutputDTO } from './dtos/GetSponsorOutputDTO';
|
||||
import { GetPendingSponsorshipRequestsOutputDTO } from './dtos/GetPendingSponsorshipRequestsOutputDTO';
|
||||
import { AcceptSponsorshipRequestInputDTO } from './dtos/AcceptSponsorshipRequestInputDTO';
|
||||
import { RejectSponsorshipRequestInputDTO } from './dtos/RejectSponsorshipRequestInputDTO';
|
||||
import { PaymentMethodDTO } from './dtos/PaymentMethodDTO';
|
||||
@@ -29,139 +22,253 @@ import { CreateSponsorUseCase } from '@core/racing/application/use-cases/CreateS
|
||||
import { GetSponsorDashboardUseCase } from '@core/racing/application/use-cases/GetSponsorDashboardUseCase';
|
||||
import { GetSponsorSponsorshipsUseCase } from '@core/racing/application/use-cases/GetSponsorSponsorshipsUseCase';
|
||||
import { GetSponsorUseCase } from '@core/racing/application/use-cases/GetSponsorUseCase';
|
||||
import { GetPendingSponsorshipRequestsUseCase, GetPendingSponsorshipRequestsDTO } from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
|
||||
import {
|
||||
GetPendingSponsorshipRequestsUseCase,
|
||||
GetPendingSponsorshipRequestsDTO,
|
||||
} from '@core/racing/application/use-cases/GetPendingSponsorshipRequestsUseCase';
|
||||
import { AcceptSponsorshipRequestUseCase } from '@core/racing/application/use-cases/AcceptSponsorshipRequestUseCase';
|
||||
import { RejectSponsorshipRequestUseCase } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
import type { SponsorableEntityType } from '@core/racing/domain/entities/SponsorshipRequest';
|
||||
import type { AcceptSponsorshipRequestResultPort } from '@core/racing/application/ports/output/AcceptSponsorshipRequestResultPort';
|
||||
import type { RejectSponsorshipRequestResultDTO } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
|
||||
// Presenters
|
||||
import { GetEntitySponsorshipPricingPresenter } from './presenters/GetEntitySponsorshipPricingPresenter';
|
||||
import { GetSponsorsPresenter } from './presenters/GetSponsorsPresenter';
|
||||
import { CreateSponsorPresenter } from './presenters/CreateSponsorPresenter';
|
||||
import { GetSponsorDashboardPresenter } from './presenters/GetSponsorDashboardPresenter';
|
||||
import { GetSponsorSponsorshipsPresenter } from './presenters/GetSponsorSponsorshipsPresenter';
|
||||
import { GetSponsorPresenter } from './presenters/GetSponsorPresenter';
|
||||
import { GetPendingSponsorshipRequestsPresenter } from './presenters/GetPendingSponsorshipRequestsPresenter';
|
||||
import { AcceptSponsorshipRequestPresenter } from './presenters/AcceptSponsorshipRequestPresenter';
|
||||
import { RejectSponsorshipRequestPresenter } from './presenters/RejectSponsorshipRequestPresenter';
|
||||
import { SponsorBillingPresenter } from './presenters/SponsorBillingPresenter';
|
||||
import { AvailableLeaguesPresenter } from './presenters/AvailableLeaguesPresenter';
|
||||
import { LeagueDetailPresenter } from './presenters/LeagueDetailPresenter';
|
||||
import { SponsorSettingsPresenter } from './presenters/SponsorSettingsPresenter';
|
||||
import { SponsorSettingsUpdatePresenter } from './presenters/SponsorSettingsUpdatePresenter';
|
||||
|
||||
// Tokens
|
||||
import { GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN, GET_SPONSORS_USE_CASE_TOKEN, CREATE_SPONSOR_USE_CASE_TOKEN, GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN, GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN, GET_SPONSOR_USE_CASE_TOKEN, GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN, ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN, REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN, LOGGER_TOKEN } from './SponsorProviders';
|
||||
import type { Logger } from '@core/shared/application';
|
||||
import {
|
||||
GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN,
|
||||
GET_SPONSORS_USE_CASE_TOKEN,
|
||||
CREATE_SPONSOR_USE_CASE_TOKEN,
|
||||
GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN,
|
||||
GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN,
|
||||
GET_SPONSOR_USE_CASE_TOKEN,
|
||||
GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN,
|
||||
ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
|
||||
REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN,
|
||||
LOGGER_TOKEN,
|
||||
} from './SponsorProviders';
|
||||
|
||||
@Injectable()
|
||||
export class SponsorService {
|
||||
constructor(
|
||||
@Inject(GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN) private readonly getSponsorshipPricingUseCase: GetSponsorshipPricingUseCase,
|
||||
@Inject(GET_SPONSORS_USE_CASE_TOKEN) private readonly getSponsorsUseCase: GetSponsorsUseCase,
|
||||
@Inject(CREATE_SPONSOR_USE_CASE_TOKEN) private readonly createSponsorUseCase: CreateSponsorUseCase,
|
||||
@Inject(GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN) private readonly getSponsorDashboardUseCase: GetSponsorDashboardUseCase,
|
||||
@Inject(GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN) private readonly getSponsorSponsorshipsUseCase: GetSponsorSponsorshipsUseCase,
|
||||
@Inject(GET_SPONSOR_USE_CASE_TOKEN) private readonly getSponsorUseCase: GetSponsorUseCase,
|
||||
@Inject(GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN) private readonly getPendingSponsorshipRequestsUseCase: GetPendingSponsorshipRequestsUseCase,
|
||||
@Inject(ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN) private readonly acceptSponsorshipRequestUseCase: AcceptSponsorshipRequestUseCase,
|
||||
@Inject(REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN) private readonly rejectSponsorshipRequestUseCase: RejectSponsorshipRequestUseCase,
|
||||
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
||||
@Inject(GET_SPONSORSHIP_PRICING_USE_CASE_TOKEN)
|
||||
private readonly getSponsorshipPricingUseCase: GetSponsorshipPricingUseCase,
|
||||
@Inject(GET_SPONSORS_USE_CASE_TOKEN)
|
||||
private readonly getSponsorsUseCase: GetSponsorsUseCase,
|
||||
@Inject(CREATE_SPONSOR_USE_CASE_TOKEN)
|
||||
private readonly createSponsorUseCase: CreateSponsorUseCase,
|
||||
@Inject(GET_SPONSOR_DASHBOARD_USE_CASE_TOKEN)
|
||||
private readonly getSponsorDashboardUseCase: GetSponsorDashboardUseCase,
|
||||
@Inject(GET_SPONSOR_SPONSORSHIPS_USE_CASE_TOKEN)
|
||||
private readonly getSponsorSponsorshipsUseCase: GetSponsorSponsorshipsUseCase,
|
||||
@Inject(GET_SPONSOR_USE_CASE_TOKEN)
|
||||
private readonly getSponsorUseCase: GetSponsorUseCase,
|
||||
@Inject(GET_PENDING_SPONSORSHIP_REQUESTS_USE_CASE_TOKEN)
|
||||
private readonly getPendingSponsorshipRequestsUseCase: GetPendingSponsorshipRequestsUseCase,
|
||||
@Inject(ACCEPT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN)
|
||||
private readonly acceptSponsorshipRequestUseCase: AcceptSponsorshipRequestUseCase,
|
||||
@Inject(REJECT_SPONSORSHIP_REQUEST_USE_CASE_TOKEN)
|
||||
private readonly rejectSponsorshipRequestUseCase: RejectSponsorshipRequestUseCase,
|
||||
@Inject(LOGGER_TOKEN)
|
||||
private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingResultDTO> {
|
||||
async getEntitySponsorshipPricing(): Promise<GetEntitySponsorshipPricingPresenter> {
|
||||
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);
|
||||
return { entityType: 'season', entityId: '', pricing: [] };
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
}
|
||||
return result.value as GetEntitySponsorshipPricingResultDTO;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getSponsors(): Promise<GetSponsorsOutputDTO> {
|
||||
async getSponsors(): Promise<GetSponsorsPresenter> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsors.');
|
||||
|
||||
const presenter = new GetSponsorsPresenter();
|
||||
const result = await this.getSponsorsUseCase.execute();
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to fetch sponsors.', result.error);
|
||||
return { sponsors: [] };
|
||||
presenter.present({ sponsors: [] });
|
||||
return presenter;
|
||||
}
|
||||
return result.value as GetSponsorsOutputDTO;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async createSponsor(input: CreateSponsorInputDTO): Promise<CreateSponsorOutputDTO> {
|
||||
async createSponsor(input: CreateSponsorInputDTO): Promise<CreateSponsorPresenter> {
|
||||
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');
|
||||
}
|
||||
return result.value as CreateSponsorOutputDTO;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getSponsorDashboard(params: GetSponsorDashboardQueryParamsDTO): Promise<SponsorDashboardDTO | null> {
|
||||
async getSponsorDashboard(
|
||||
params: GetSponsorDashboardQueryParamsDTO,
|
||||
): Promise<GetSponsorDashboardPresenter> {
|
||||
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);
|
||||
return null;
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
}
|
||||
return result.value as SponsorDashboardDTO | null;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getSponsorSponsorships(params: GetSponsorSponsorshipsQueryParamsDTO): Promise<SponsorSponsorshipsDTO | null> {
|
||||
async getSponsorSponsorships(
|
||||
params: GetSponsorSponsorshipsQueryParamsDTO,
|
||||
): Promise<GetSponsorSponsorshipsPresenter> {
|
||||
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);
|
||||
return null;
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
}
|
||||
return result.value as SponsorSponsorshipsDTO | null;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getSponsor(sponsorId: string): Promise<GetSponsorOutputDTO | null> {
|
||||
async getSponsor(sponsorId: string): Promise<GetSponsorPresenter> {
|
||||
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);
|
||||
return null;
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
}
|
||||
return result.value as GetSponsorOutputDTO | null;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getPendingSponsorshipRequests(params: { entityType: SponsorableEntityType; entityId: string }): Promise<GetPendingSponsorshipRequestsOutputDTO> {
|
||||
async getPendingSponsorshipRequests(params: {
|
||||
entityType: SponsorableEntityType;
|
||||
entityId: string;
|
||||
}): Promise<GetPendingSponsorshipRequestsPresenter> {
|
||||
this.logger.debug('[SponsorService] Fetching pending sponsorship requests.', { params });
|
||||
|
||||
const result = await this.getPendingSponsorshipRequestsUseCase.execute(params as GetPendingSponsorshipRequestsDTO);
|
||||
const presenter = new GetPendingSponsorshipRequestsPresenter();
|
||||
const result = await this.getPendingSponsorshipRequestsUseCase.execute(
|
||||
params as GetPendingSponsorshipRequestsDTO,
|
||||
);
|
||||
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to fetch pending sponsorship requests.', result.error);
|
||||
return { entityType: params.entityType, entityId: params.entityId, requests: [], totalCount: 0 };
|
||||
presenter.present({
|
||||
entityType: params.entityType,
|
||||
entityId: params.entityId,
|
||||
requests: [],
|
||||
totalCount: 0,
|
||||
});
|
||||
return presenter;
|
||||
}
|
||||
return result.value as GetPendingSponsorshipRequestsOutputDTO;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async acceptSponsorshipRequest(requestId: string, respondedBy: string): Promise<AcceptSponsorshipRequestResultPort | null> {
|
||||
this.logger.debug('[SponsorService] Accepting sponsorship request.', { requestId, respondedBy });
|
||||
async acceptSponsorshipRequest(
|
||||
requestId: string,
|
||||
respondedBy: string,
|
||||
): Promise<AcceptSponsorshipRequestPresenter> {
|
||||
this.logger.debug('[SponsorService] Accepting sponsorship request.', {
|
||||
requestId,
|
||||
respondedBy,
|
||||
});
|
||||
|
||||
const presenter = new AcceptSponsorshipRequestPresenter();
|
||||
const result = await this.acceptSponsorshipRequestUseCase.execute({
|
||||
requestId,
|
||||
respondedBy,
|
||||
} as AcceptSponsorshipRequestInputDTO);
|
||||
|
||||
const result = await this.acceptSponsorshipRequestUseCase.execute({ requestId, respondedBy });
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to accept sponsorship request.', result.error);
|
||||
return null;
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
}
|
||||
return result.value;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async rejectSponsorshipRequest(requestId: string, respondedBy: string, reason?: string): Promise<RejectSponsorshipRequestResultDTO | null> {
|
||||
this.logger.debug('[SponsorService] Rejecting sponsorship request.', { requestId, respondedBy, reason });
|
||||
async rejectSponsorshipRequest(
|
||||
requestId: string,
|
||||
respondedBy: string,
|
||||
reason?: string,
|
||||
): Promise<RejectSponsorshipRequestPresenter> {
|
||||
this.logger.debug('[SponsorService] Rejecting sponsorship request.', {
|
||||
requestId,
|
||||
respondedBy,
|
||||
reason,
|
||||
});
|
||||
|
||||
const presenter = new RejectSponsorshipRequestPresenter();
|
||||
const result = await this.rejectSponsorshipRequestUseCase.execute({
|
||||
requestId,
|
||||
respondedBy,
|
||||
reason,
|
||||
} as RejectSponsorshipRequestInputDTO);
|
||||
|
||||
const result = await this.rejectSponsorshipRequestUseCase.execute({ requestId, respondedBy, reason });
|
||||
if (result.isErr()) {
|
||||
this.logger.error('[SponsorService] Failed to reject sponsorship request.', result.error);
|
||||
return null;
|
||||
presenter.present(null);
|
||||
return presenter;
|
||||
}
|
||||
return result.value;
|
||||
|
||||
presenter.present(result.value);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getSponsorBilling(sponsorId: string): Promise<{
|
||||
paymentMethods: PaymentMethodDTO[];
|
||||
invoices: InvoiceDTO[];
|
||||
stats: BillingStatsDTO;
|
||||
}> {
|
||||
async getSponsorBilling(sponsorId: string): Promise<SponsorBillingPresenter> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsor billing.', { sponsorId });
|
||||
|
||||
const presenter = new SponsorBillingPresenter();
|
||||
|
||||
// Mock data - in real implementation, this would come from repositories
|
||||
const paymentMethods: PaymentMethodDTO[] = [
|
||||
{
|
||||
@@ -242,14 +349,16 @@ export class SponsorService {
|
||||
averageMonthlySpend: 2075,
|
||||
};
|
||||
|
||||
return { paymentMethods, invoices, stats };
|
||||
presenter.present({ paymentMethods, invoices, stats });
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getAvailableLeagues(): Promise<AvailableLeagueDTO[]> {
|
||||
async getAvailableLeagues(): Promise<AvailableLeaguesPresenter> {
|
||||
this.logger.debug('[SponsorService] Fetching available leagues.');
|
||||
|
||||
// Mock data
|
||||
return [
|
||||
const presenter = new AvailableLeaguesPresenter();
|
||||
|
||||
const leagues: AvailableLeagueDTO[] = [
|
||||
{
|
||||
id: 'league-1',
|
||||
name: 'GT3 Masters Championship',
|
||||
@@ -262,7 +371,8 @@ export class SponsorService {
|
||||
tier: 'premium',
|
||||
nextRace: '2025-12-20',
|
||||
seasonStatus: 'active',
|
||||
description: 'Premier GT3 racing with top-tier drivers. Weekly broadcasts and active community.',
|
||||
description:
|
||||
'Premier GT3 racing with top-tier drivers. Weekly broadcasts and active community.',
|
||||
},
|
||||
{
|
||||
id: 'league-2',
|
||||
@@ -276,18 +386,20 @@ export class SponsorService {
|
||||
tier: 'premium',
|
||||
nextRace: '2026-01-05',
|
||||
seasonStatus: 'active',
|
||||
description: 'Multi-class endurance racing. High engagement from dedicated endurance fans.',
|
||||
description:
|
||||
'Multi-class endurance racing. High engagement from dedicated endurance fans.',
|
||||
},
|
||||
];
|
||||
|
||||
presenter.present(leagues);
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getLeagueDetail(leagueId: string): Promise<{
|
||||
league: LeagueDetailDTO;
|
||||
drivers: DriverDTO[];
|
||||
races: RaceDTO[];
|
||||
}> {
|
||||
async getLeagueDetail(leagueId: string): Promise<LeagueDetailPresenter> {
|
||||
this.logger.debug('[SponsorService] Fetching league detail.', { leagueId });
|
||||
|
||||
const presenter = new LeagueDetailPresenter();
|
||||
|
||||
// Mock data
|
||||
const league: LeagueDetailDTO = {
|
||||
id: leagueId,
|
||||
@@ -295,7 +407,8 @@ export class SponsorService {
|
||||
game: 'iRacing',
|
||||
tier: 'premium',
|
||||
season: 'Season 3',
|
||||
description: 'Premier GT3 racing with top-tier drivers competing across the world\'s most iconic circuits.',
|
||||
description:
|
||||
"Premier GT3 racing with top-tier drivers competing across the world's most iconic circuits.",
|
||||
drivers: 48,
|
||||
races: 12,
|
||||
completedRaces: 8,
|
||||
@@ -316,7 +429,7 @@ export class SponsorService {
|
||||
'Race results page branding',
|
||||
'Social media feature posts',
|
||||
'Newsletter sponsor spot',
|
||||
]
|
||||
],
|
||||
},
|
||||
secondary: {
|
||||
available: 1,
|
||||
@@ -327,31 +440,58 @@ export class SponsorService {
|
||||
'League page sidebar placement',
|
||||
'Race results mention',
|
||||
'Social media mentions',
|
||||
]
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const drivers: DriverDTO[] = [
|
||||
{ id: 'd1', name: 'Max Verstappen', country: 'NL', position: 1, races: 8, impressions: 4200, team: 'Red Bull Racing' },
|
||||
{ id: 'd2', name: 'Lewis Hamilton', country: 'GB', position: 2, races: 8, impressions: 3980, team: 'Mercedes AMG' },
|
||||
{
|
||||
id: 'd1',
|
||||
name: 'Max Verstappen',
|
||||
country: 'NL',
|
||||
position: 1,
|
||||
races: 8,
|
||||
impressions: 4200,
|
||||
team: 'Red Bull Racing',
|
||||
},
|
||||
{
|
||||
id: 'd2',
|
||||
name: 'Lewis Hamilton',
|
||||
country: 'GB',
|
||||
position: 2,
|
||||
races: 8,
|
||||
impressions: 3980,
|
||||
team: 'Mercedes AMG',
|
||||
},
|
||||
];
|
||||
|
||||
const races: RaceDTO[] = [
|
||||
{ id: 'r1', name: 'Spa-Francorchamps', date: '2025-12-20', views: 0, status: 'upcoming' },
|
||||
{ id: 'r2', name: 'Monza', date: '2025-12-08', views: 5800, status: 'completed' },
|
||||
{
|
||||
id: 'r1',
|
||||
name: 'Spa-Francorchamps',
|
||||
date: '2025-12-20',
|
||||
views: 0,
|
||||
status: 'upcoming',
|
||||
},
|
||||
{
|
||||
id: 'r2',
|
||||
name: 'Monza',
|
||||
date: '2025-12-08',
|
||||
views: 5800,
|
||||
status: 'completed',
|
||||
},
|
||||
];
|
||||
|
||||
return { league, drivers, races };
|
||||
presenter.present({ league, drivers, races });
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async getSponsorSettings(sponsorId: string): Promise<{
|
||||
profile: SponsorProfileDTO;
|
||||
notifications: NotificationSettingsDTO;
|
||||
privacy: PrivacySettingsDTO;
|
||||
}> {
|
||||
async getSponsorSettings(sponsorId: string): Promise<SponsorSettingsPresenter> {
|
||||
this.logger.debug('[SponsorService] Fetching sponsor settings.', { sponsorId });
|
||||
|
||||
const presenter = new SponsorSettingsPresenter();
|
||||
|
||||
// Mock data
|
||||
const profile: SponsorProfileDTO = {
|
||||
companyName: 'Acme Racing Co.',
|
||||
@@ -359,7 +499,8 @@ export class SponsorService {
|
||||
contactEmail: 'sponsor@acme-racing.com',
|
||||
contactPhone: '+1 (555) 123-4567',
|
||||
website: 'https://acme-racing.com',
|
||||
description: 'Premium sim racing equipment and accessories for competitive drivers.',
|
||||
description:
|
||||
'Premium sim racing equipment and accessories for competitive drivers.',
|
||||
logoUrl: null,
|
||||
industry: 'Racing Equipment',
|
||||
address: {
|
||||
@@ -392,7 +533,8 @@ export class SponsorService {
|
||||
allowDirectContact: true,
|
||||
};
|
||||
|
||||
return { profile, notifications, privacy };
|
||||
presenter.present({ profile, notifications, privacy });
|
||||
return presenter;
|
||||
}
|
||||
|
||||
async updateSponsorSettings(
|
||||
@@ -401,12 +543,15 @@ export class SponsorService {
|
||||
profile?: Partial<SponsorProfileDTO>;
|
||||
notifications?: Partial<NotificationSettingsDTO>;
|
||||
privacy?: Partial<PrivacySettingsDTO>;
|
||||
}
|
||||
): Promise<void> {
|
||||
},
|
||||
): Promise<SponsorSettingsUpdatePresenter> {
|
||||
this.logger.debug('[SponsorService] Updating sponsor settings.', { sponsorId, input });
|
||||
|
||||
// Mock implementation - in real app, this would persist to database
|
||||
// For now, just log the update
|
||||
this.logger.info('[SponsorService] Settings updated successfully.', { sponsorId });
|
||||
|
||||
const presenter = new SponsorSettingsUpdatePresenter();
|
||||
presenter.present({ success: true });
|
||||
return presenter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { AcceptSponsorshipOutputPort } from '@core/racing/application/ports/output/AcceptSponsorshipOutputPort';
|
||||
|
||||
export interface AcceptSponsorshipRequestResultViewModel {
|
||||
requestId: string;
|
||||
sponsorshipId: string;
|
||||
status: 'accepted';
|
||||
acceptedAt: Date;
|
||||
platformFee: number;
|
||||
netAmount: number;
|
||||
}
|
||||
|
||||
export class AcceptSponsorshipRequestPresenter {
|
||||
private result: AcceptSponsorshipRequestResultViewModel | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: AcceptSponsorshipOutputPort | null) {
|
||||
if (!output) {
|
||||
this.result = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.result = {
|
||||
requestId: output.requestId,
|
||||
sponsorshipId: output.sponsorshipId,
|
||||
status: output.status,
|
||||
acceptedAt: output.acceptedAt,
|
||||
platformFee: output.platformFee,
|
||||
netAmount: output.netAmount,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): AcceptSponsorshipRequestResultViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): AcceptSponsorshipRequestResultViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { AvailableLeagueDTO } from '../dtos/AvailableLeagueDTO';
|
||||
|
||||
export class AvailableLeaguesPresenter {
|
||||
private result: AvailableLeagueDTO[] | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(leagues: AvailableLeagueDTO[]) {
|
||||
this.result = leagues;
|
||||
}
|
||||
|
||||
getViewModel(): AvailableLeagueDTO[] | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): AvailableLeagueDTO[] | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GetEntitySponsorshipPricingOutputPort } from '@core/racing/application/ports/output/GetEntitySponsorshipPricingOutputPort';
|
||||
import type { GetSponsorshipPricingOutputPort } from '@core/racing/application/ports/output/GetSponsorshipPricingOutputPort';
|
||||
import { GetEntitySponsorshipPricingResultDTO } from '../dtos/GetEntitySponsorshipPricingResultDTO';
|
||||
|
||||
export class GetEntitySponsorshipPricingPresenter {
|
||||
@@ -8,34 +8,34 @@ export class GetEntitySponsorshipPricingPresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
async present(output: GetEntitySponsorshipPricingOutputPort | null) {
|
||||
present(output: GetSponsorshipPricingOutputPort | null) {
|
||||
if (!output) {
|
||||
this.result = { pricing: [] };
|
||||
this.result = {
|
||||
entityType: 'season',
|
||||
entityId: '',
|
||||
pricing: [],
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
const pricing = [];
|
||||
if (output.mainSlot) {
|
||||
pricing.push({
|
||||
id: `${output.entityType}-${output.entityId}-main`,
|
||||
level: 'main',
|
||||
price: output.mainSlot.price,
|
||||
currency: output.mainSlot.currency,
|
||||
});
|
||||
}
|
||||
if (output.secondarySlot) {
|
||||
pricing.push({
|
||||
id: `${output.entityType}-${output.entityId}-secondary`,
|
||||
level: 'secondary',
|
||||
price: output.secondarySlot.price,
|
||||
currency: output.secondarySlot.currency,
|
||||
});
|
||||
}
|
||||
|
||||
this.result = { pricing };
|
||||
this.result = {
|
||||
entityType: output.entityType,
|
||||
entityId: output.entityId,
|
||||
pricing: output.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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,31 @@ import type { PendingSponsorshipRequestsOutputPort } from '@core/racing/applicat
|
||||
import { GetPendingSponsorshipRequestsOutputDTO } from '../dtos/GetPendingSponsorshipRequestsOutputDTO';
|
||||
|
||||
export class GetPendingSponsorshipRequestsPresenter {
|
||||
present(outputPort: PendingSponsorshipRequestsOutputPort): GetPendingSponsorshipRequestsOutputDTO {
|
||||
return {
|
||||
private result: GetPendingSponsorshipRequestsOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(outputPort: PendingSponsorshipRequestsOutputPort | null) {
|
||||
if (!outputPort) {
|
||||
this.result = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.result = {
|
||||
entityType: outputPort.entityType,
|
||||
entityId: outputPort.entityId,
|
||||
requests: outputPort.requests,
|
||||
totalCount: outputPort.totalCount,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
getViewModel(): GetPendingSponsorshipRequestsOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): GetPendingSponsorshipRequestsOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,21 @@ import type { SponsorDashboardOutputPort } from '@core/racing/application/ports/
|
||||
import { SponsorDashboardDTO } from '../dtos/SponsorDashboardDTO';
|
||||
|
||||
export class GetSponsorDashboardPresenter {
|
||||
present(outputPort: SponsorDashboardOutputPort | null): SponsorDashboardDTO | null {
|
||||
return outputPort;
|
||||
private result: SponsorDashboardDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
}
|
||||
|
||||
present(outputPort: SponsorDashboardOutputPort | null) {
|
||||
this.result = outputPort ?? null;
|
||||
}
|
||||
|
||||
getViewModel(): SponsorDashboardDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): SponsorDashboardDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { GetSponsorOutputDTO } from '../dtos/GetSponsorOutputDTO';
|
||||
|
||||
interface GetSponsorOutputPort {
|
||||
sponsor: {
|
||||
id: string;
|
||||
name: string;
|
||||
logoUrl?: string;
|
||||
websiteUrl?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class GetSponsorPresenter {
|
||||
private result: GetSponsorOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetSponsorOutputPort | null) {
|
||||
if (!output) {
|
||||
this.result = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.result = {
|
||||
sponsor: {
|
||||
id: output.sponsor.id,
|
||||
name: output.sponsor.name,
|
||||
...(output.sponsor.logoUrl !== undefined ? { logoUrl: output.sponsor.logoUrl } : {}),
|
||||
...(output.sponsor.websiteUrl !== undefined ? { websiteUrl: output.sponsor.websiteUrl } : {}),
|
||||
},
|
||||
} as GetSponsorOutputDTO;
|
||||
}
|
||||
|
||||
getViewModel(): GetSponsorOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): GetSponsorOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,21 @@ import type { SponsorSponsorshipsOutputPort } from '@core/racing/application/por
|
||||
import { SponsorSponsorshipsDTO } from '../dtos/SponsorSponsorshipsDTO';
|
||||
|
||||
export class GetSponsorSponsorshipsPresenter {
|
||||
present(outputPort: SponsorSponsorshipsOutputPort | null): SponsorSponsorshipsDTO | null {
|
||||
return outputPort;
|
||||
private result: SponsorSponsorshipsDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
}
|
||||
|
||||
present(outputPort: SponsorSponsorshipsOutputPort | null) {
|
||||
this.result = outputPort ?? null;
|
||||
}
|
||||
|
||||
getViewModel(): SponsorSponsorshipsDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): SponsorSponsorshipsDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,24 @@ import type { GetSponsorsOutputPort } from '@core/racing/application/ports/outpu
|
||||
import { GetSponsorsOutputDTO } from '../dtos/GetSponsorsOutputDTO';
|
||||
|
||||
export class GetSponsorsPresenter {
|
||||
present(outputPort: GetSponsorsOutputPort): GetSponsorsOutputDTO {
|
||||
return {
|
||||
private result: GetSponsorsOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(outputPort: GetSponsorsOutputPort) {
|
||||
this.result = {
|
||||
sponsors: outputPort.sponsors,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
getViewModel(): GetSponsorsOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): GetSponsorsOutputDTO {
|
||||
if (!this.result) throw new Error('Presenter not presented');
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { LeagueDetailDTO } from '../dtos/LeagueDetailDTO';
|
||||
import { DriverDTO } from '../dtos/DriverDTO';
|
||||
import { RaceDTO } from '../dtos/RaceDTO';
|
||||
|
||||
export interface LeagueDetailViewModel {
|
||||
league: LeagueDetailDTO;
|
||||
drivers: DriverDTO[];
|
||||
races: RaceDTO[];
|
||||
}
|
||||
|
||||
export class LeagueDetailPresenter {
|
||||
private result: LeagueDetailViewModel | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(viewModel: LeagueDetailViewModel) {
|
||||
this.result = viewModel;
|
||||
}
|
||||
|
||||
getViewModel(): LeagueDetailViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): LeagueDetailViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { RejectSponsorshipRequestResultDTO } from '@core/racing/application/use-cases/RejectSponsorshipRequestUseCase';
|
||||
|
||||
export class RejectSponsorshipRequestPresenter {
|
||||
private result: RejectSponsorshipRequestResultDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: RejectSponsorshipRequestResultDTO | null) {
|
||||
this.result = output ?? null;
|
||||
}
|
||||
|
||||
getViewModel(): RejectSponsorshipRequestResultDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): RejectSponsorshipRequestResultDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { PaymentMethodDTO } from '../dtos/PaymentMethodDTO';
|
||||
import { InvoiceDTO } from '../dtos/InvoiceDTO';
|
||||
import { BillingStatsDTO } from '../dtos/BillingStatsDTO';
|
||||
|
||||
export interface SponsorBillingViewModel {
|
||||
paymentMethods: PaymentMethodDTO[];
|
||||
invoices: InvoiceDTO[];
|
||||
stats: BillingStatsDTO;
|
||||
}
|
||||
|
||||
export class SponsorBillingPresenter {
|
||||
private result: SponsorBillingViewModel | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(viewModel: SponsorBillingViewModel) {
|
||||
this.result = viewModel;
|
||||
}
|
||||
|
||||
getViewModel(): SponsorBillingViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): SponsorBillingViewModel {
|
||||
if (!this.result) throw new Error('Presenter not presented');
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { SponsorProfileDTO } from '../dtos/SponsorProfileDTO';
|
||||
import { NotificationSettingsDTO } from '../dtos/NotificationSettingsDTO';
|
||||
import { PrivacySettingsDTO } from '../dtos/PrivacySettingsDTO';
|
||||
|
||||
export interface SponsorSettingsViewModel {
|
||||
profile: SponsorProfileDTO;
|
||||
notifications: NotificationSettingsDTO;
|
||||
privacy: PrivacySettingsDTO;
|
||||
}
|
||||
|
||||
export class SponsorSettingsPresenter {
|
||||
private result: SponsorSettingsViewModel | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(viewModel: SponsorSettingsViewModel) {
|
||||
this.result = viewModel;
|
||||
}
|
||||
|
||||
getViewModel(): SponsorSettingsViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): SponsorSettingsViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
export interface SponsorSettingsUpdateViewModel {
|
||||
success: boolean;
|
||||
errorCode?: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export class SponsorSettingsUpdatePresenter {
|
||||
private result: SponsorSettingsUpdateViewModel | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(viewModel: SponsorSettingsUpdateViewModel) {
|
||||
this.result = viewModel;
|
||||
}
|
||||
|
||||
getViewModel(): SponsorSettingsUpdateViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): SponsorSettingsUpdateViewModel | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user