refactor core presenters

This commit is contained in:
2025-12-19 19:42:19 +01:00
parent 8116fe888f
commit 94fc538f44
228 changed files with 2817 additions and 3097 deletions

View File

@@ -16,6 +16,7 @@ import { InMemoryRaceRepository } from '@adapters/racing/persistence/inmemory/In
import { InMemoryDriverRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverRepository';
import { InMemoryStandingRepository } from '@adapters/racing/persistence/inmemory/InMemoryStandingRepository';
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
import { listLeagueScoringPresets } from '@adapters/bootstrap/LeagueScoringPresets';
// Import use cases
import { GetAllLeaguesWithCapacityUseCase } from '@core/racing/application/use-cases/GetAllLeaguesWithCapacityUseCase';
@@ -131,4 +132,8 @@ export const LeagueProviders: Provider[] = [
GetLeagueScheduleUseCase,
GetLeagueStatsUseCase,
GetLeagueAdminPermissionsUseCase,
{
provide: ListLeagueScoringPresetsUseCase,
useFactory: () => new ListLeagueScoringPresetsUseCase(listLeagueScoringPresets()),
},
];

View File

@@ -14,6 +14,7 @@ import { UpdateLeagueMemberRoleUseCase } from '@core/racing/application/use-case
import { GetLeagueOwnerSummaryUseCase } from '@core/racing/application/use-cases/GetLeagueOwnerSummaryUseCase';
import { GetLeagueProtestsUseCase } from '@core/racing/application/use-cases/GetLeagueProtestsUseCase';
import type { Logger } from '@core/shared/application/Logger';
import { Result } from '@core/shared/application/Result';
describe('LeagueService', () => {
let service: LeagueService;
@@ -60,9 +61,7 @@ describe('LeagueService', () => {
});
it('should get total leagues', async () => {
mockGetTotalLeaguesUseCase.execute.mockImplementation(async (params, presenter) => {
presenter.present({ totalLeagues: 5 });
});
mockGetTotalLeaguesUseCase.execute.mockResolvedValue(Result.ok({ totalLeagues: 5 }));
const result = await service.getTotalLeagues();

View File

@@ -10,30 +10,27 @@ import { RejectJoinRequestInputDTO } from './dtos/RejectJoinRequestInputDTO';
import { RemoveLeagueMemberInputDTO } from './dtos/RemoveLeagueMemberInputDTO';
import { UpdateLeagueMemberRoleInputDTO } from './dtos/UpdateLeagueMemberRoleInputDTO';
import { LeagueAdminDTO } from './dtos/LeagueAdminDTO';
import { LeagueAdminPermissionsDTO } from './dtos/LeagueAdminPermissionsDTO';
import { LeagueAdminProtestsDTO } from './dtos/LeagueAdminProtestsDTO';
import { LeagueMembershipsDTO } from './dtos/LeagueMembershipsDTO';
import { LeagueSeasonSummaryDTO } from './dtos/LeagueSeasonSummaryDTO';
import { GetSeasonSponsorshipsOutputDTO } from './dtos/GetSeasonSponsorshipsOutputDTO';
import { GetLeagueRacesOutputDTO } from './dtos/GetLeagueRacesOutputDTO';
import { RejectJoinRequestOutputDTO } from './dtos/RejectJoinRequestOutputDTO';
import { RemoveLeagueMemberOutputDTO } from './dtos/RemoveLeagueMemberOutputDTO';
import { TransferLeagueOwnershipOutputDTO } from './dtos/TransferLeagueOwnershipOutputDTO';
import { UpdateLeagueMemberRoleOutputDTO } from './dtos/UpdateLeagueMemberRoleOutputDTO';
// Core imports for view models
import type { LeagueScoringConfigViewModel } from '@core/racing/application/presenters/ILeagueScoringConfigPresenter';
import type { LeagueScoringPresetsViewModel } from '@core/racing/application/presenters/ILeagueScoringPresetsPresenter';
import type { AllLeaguesWithCapacityViewModel } from '@core/racing/application/presenters/IAllLeaguesWithCapacityPresenter';
import type { GetTotalLeaguesViewModel } from '@core/racing/application/presenters/IGetTotalLeaguesPresenter';
import type { LeagueScoringConfigViewModel } from './presenters/LeagueScoringConfigPresenter';
import type { LeagueScoringPresetsViewModel } from './presenters/LeagueScoringPresetsPresenter';
import type { AllLeaguesWithCapacityDTO as AllLeaguesWithCapacityViewModel } from '../dtos/AllLeaguesWithCapacityDTO';
import type { GetLeagueJoinRequestsViewModel } from '@core/racing/application/presenters/IGetLeagueJoinRequestsPresenter';
import type { ApproveLeagueJoinRequestViewModel } from '@core/racing/application/presenters/IApproveLeagueJoinRequestPresenter';
import type { RejectLeagueJoinRequestViewModel } from '@core/racing/application/presenters/IRejectLeagueJoinRequestPresenter';
import { TotalLeaguesDTO } from './dtos/TotalLeaguesDTO';
import type { ApproveLeagueJoinRequestDTO } from './dtos/ApproveLeagueJoinRequestDTO';
import type { JoinLeagueOutputDTO } from './dtos/JoinLeagueOutputDTO';
import type { GetLeagueAdminPermissionsViewModel } from '@core/racing/application/presenters/IGetLeagueAdminPermissionsPresenter';
import type { RemoveLeagueMemberViewModel } from '@core/racing/application/presenters/IRemoveLeagueMemberPresenter';
import type { UpdateLeagueMemberRoleViewModel } from '@core/racing/application/presenters/IUpdateLeagueMemberRolePresenter';
import type { GetLeagueOwnerSummaryViewModel } from '@core/racing/application/presenters/IGetLeagueOwnerSummaryPresenter';
import type { LeagueStandingsViewModel } from '@core/racing/application/presenters/ILeagueStandingsPresenter';
import type { LeagueStatsViewModel } from '@core/racing/application/presenters/ILeagueStatsPresenter';
import type { LeagueConfigFormViewModel } from '@core/racing/application/presenters/ILeagueFullConfigPresenter';
import type { CreateLeagueViewModel } from '@core/racing/application/presenters/ICreateLeaguePresenter';
import type { JoinLeagueViewModel } from '@core/racing/application/presenters/IJoinLeaguePresenter';
import type { TransferLeagueOwnershipViewModel } from '@core/racing/application/presenters/ITransferLeagueOwnershipPresenter';
import type { CreateLeagueViewModel } from './dtos/CreateLeagueDTO';
// Core imports
import type { Logger } from '@core/shared/application/Logger';
@@ -67,22 +64,22 @@ import { AllLeaguesWithCapacityPresenter } from './presenters/AllLeaguesWithCapa
import { TotalLeaguesPresenter } from './presenters/TotalLeaguesPresenter';
import { LeagueScoringConfigPresenter } from './presenters/LeagueScoringConfigPresenter';
import { LeagueScoringPresetsPresenter } from './presenters/LeagueScoringPresetsPresenter';
import { ApproveLeagueJoinRequestPresenter } from './presenters/ApproveLeagueJoinRequestPresenter';
import { mapApproveLeagueJoinRequestPortToDTO } from './presenters/ApproveLeagueJoinRequestPresenter';
import { GetLeagueAdminPermissionsPresenter } from './presenters/GetLeagueAdminPermissionsPresenter';
import { GetLeagueOwnerSummaryPresenter } from './presenters/GetLeagueOwnerSummaryPresenter';
import { mapGetLeagueOwnerSummaryOutputPortToDTO } from './presenters/GetLeagueOwnerSummaryPresenter';
import { LeagueJoinRequestsPresenter } from './presenters/LeagueJoinRequestsPresenter';
import { LeagueSchedulePresenter } from './presenters/LeagueSchedulePresenter';
import { mapGetLeagueScheduleOutputPortToDTO } from './presenters/LeagueSchedulePresenter';
import { LeagueStatsPresenter } from './presenters/LeagueStatsPresenter';
import { RejectLeagueJoinRequestPresenter } from './presenters/RejectLeagueJoinRequestPresenter';
import { RemoveLeagueMemberPresenter } from './presenters/RemoveLeagueMemberPresenter';
import { UpdateLeagueMemberRolePresenter } from './presenters/UpdateLeagueMemberRolePresenter';
import { mapRejectLeagueJoinRequestOutputPortToDTO } from './presenters/RejectLeagueJoinRequestPresenter';
import { mapRemoveLeagueMemberOutputPortToDTO } from './presenters/RemoveLeagueMemberPresenter';
import { mapUpdateLeagueMemberRoleOutputPortToDTO } from './presenters/UpdateLeagueMemberRolePresenter';
import { CreateLeaguePresenter } from './presenters/CreateLeaguePresenter';
import { JoinLeaguePresenter } from './presenters/JoinLeaguePresenter';
import { TransferLeagueOwnershipPresenter } from './presenters/TransferLeagueOwnershipPresenter';
import { GetLeagueProtestsPresenter } from './presenters/GetLeagueProtestsPresenter';
import { GetLeagueSeasonsPresenter } from './presenters/GetLeagueSeasonsPresenter';
import { GetLeagueMembershipsPresenter } from './presenters/GetLeagueMembershipsPresenter';
import { mapJoinLeagueOutputPortToDTO } from './presenters/JoinLeaguePresenter';
import { mapTransferLeagueOwnershipOutputPortToDTO } from './presenters/TransferLeagueOwnershipPresenter';
import { mapGetLeagueProtestsOutputPortToDTO } from './presenters/GetLeagueProtestsPresenter';
import { mapGetLeagueSeasonsOutputPortToDTO } from './presenters/GetLeagueSeasonsPresenter';
import { LeagueConfigPresenter } from './presenters/LeagueConfigPresenter';
import { LeagueStandingsPresenter } from './presenters/LeagueStandingsPresenter';
// Tokens
import { LOGGER_TOKEN } from './LeagueProviders';
@@ -126,7 +123,7 @@ export class LeagueService {
return presenter.getViewModel()!;
}
async getTotalLeagues(): Promise<GetTotalLeaguesViewModel> {
async getTotalLeagues(): Promise<TotalLeaguesDTO> {
this.logger.debug('[LeagueService] Fetching total leagues count.');
const result = await this.getTotalLeaguesUseCase.execute();
if (result.isErr()) {
@@ -148,26 +145,22 @@ export class LeagueService {
return presenter.getViewModel();
}
async approveLeagueJoinRequest(input: ApproveJoinRequestInputDTO): Promise<ApproveLeagueJoinRequestViewModel> {
async approveLeagueJoinRequest(input: ApproveJoinRequestInputDTO): Promise<ApproveLeagueJoinRequestDTO> {
this.logger.debug('Approving join request:', input);
const result = await this.approveLeagueJoinRequestUseCase.execute({ leagueId: input.leagueId, requestId: input.requestId });
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new ApproveLeagueJoinRequestPresenter();
presenter.present(result.unwrap());
return presenter.getViewModel();
return mapApproveLeagueJoinRequestPortToDTO(result.unwrap());
}
async rejectLeagueJoinRequest(input: RejectJoinRequestInputDTO): Promise<RejectLeagueJoinRequestViewModel> {
async rejectLeagueJoinRequest(input: RejectJoinRequestInputDTO): Promise<RejectJoinRequestOutputDTO> {
this.logger.debug('Rejecting join request:', input);
const result = await this.rejectLeagueJoinRequestUseCase.execute({ requestId: input.requestId });
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new RejectLeagueJoinRequestPresenter();
presenter.present(result.unwrap());
return presenter.getViewModel();
return mapRejectLeagueJoinRequestOutputPortToDTO(result.unwrap());
}
async getLeagueAdminPermissions(query: GetLeagueAdminPermissionsInputDTO): Promise<GetLeagueAdminPermissionsViewModel> {
@@ -179,40 +172,34 @@ export class LeagueService {
return presenter.getViewModel()!;
}
async removeLeagueMember(input: RemoveLeagueMemberInputDTO): Promise<RemoveLeagueMemberViewModel> {
async removeLeagueMember(input: RemoveLeagueMemberInputDTO): Promise<RemoveLeagueMemberOutputDTO> {
this.logger.debug('Removing league member', { leagueId: input.leagueId, targetDriverId: input.targetDriverId });
const result = await this.removeLeagueMemberUseCase.execute({ leagueId: input.leagueId, targetDriverId: input.targetDriverId });
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new RemoveLeagueMemberPresenter();
presenter.present(result.unwrap());
return presenter.getViewModel();
return mapRemoveLeagueMemberOutputPortToDTO(result.unwrap());
}
async updateLeagueMemberRole(input: UpdateLeagueMemberRoleInputDTO): Promise<UpdateLeagueMemberRoleViewModel> {
async updateLeagueMemberRole(input: UpdateLeagueMemberRoleInputDTO): Promise<UpdateLeagueMemberRoleOutputDTO> {
this.logger.debug('Updating league member role', { leagueId: input.leagueId, targetDriverId: input.targetDriverId, newRole: input.newRole });
const result = await this.updateLeagueMemberRoleUseCase.execute({ leagueId: input.leagueId, targetDriverId: input.targetDriverId, newRole: input.newRole });
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new UpdateLeagueMemberRolePresenter();
presenter.present(result.unwrap());
return presenter.getViewModel();
return mapUpdateLeagueMemberRoleOutputPortToDTO(result.unwrap());
}
async getLeagueOwnerSummary(query: GetLeagueOwnerSummaryQueryDTO): Promise<GetLeagueOwnerSummaryViewModel> {
async getLeagueOwnerSummary(query: GetLeagueOwnerSummaryQueryDTO): Promise<LeagueOwnerSummaryDTO | null> {
this.logger.debug('Getting league owner summary:', query);
const result = await this.getLeagueOwnerSummaryUseCase.execute({ ownerId: query.ownerId });
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new GetLeagueOwnerSummaryPresenter();
presenter.present(result.unwrap());
return presenter.getViewModel();
return mapGetLeagueOwnerSummaryOutputPortToDTO(result.unwrap());
}
async getLeagueFullConfig(query: GetLeagueAdminConfigQueryDTO): Promise<LeagueConfigFormViewModel | null> {
async getLeagueFullConfig(query: GetLeagueAdminConfigQueryDTO): Promise<LeagueConfigFormModelDTO | null> {
this.logger.debug('Getting league full config', { query });
try {
@@ -221,7 +208,9 @@ export class LeagueService {
this.logger.error('Error getting league full config', new Error(result.unwrapErr().code));
return null;
}
return result.unwrap();
const presenter = new LeagueConfigPresenter();
presenter.present(result.unwrap());
return presenter.getViewModel();
} catch (error) {
this.logger.error('Error getting league full config', error instanceof Error ? error : new Error(String(error)));
return null;
@@ -234,9 +223,7 @@ export class LeagueService {
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new GetLeagueProtestsPresenter();
presenter.present(result.unwrap());
return presenter.getViewModel() as LeagueAdminProtestsDTO;
return mapGetLeagueProtestsOutputPortToDTO(result.unwrap());
}
async getLeagueSeasons(query: GetLeagueSeasonsQueryDTO): Promise<LeagueSeasonSummaryDTO[]> {
@@ -245,9 +232,7 @@ export class LeagueService {
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new GetLeagueSeasonsPresenter();
presenter.present(result.unwrap());
return presenter.getViewModel().seasons;
return mapGetLeagueSeasonsOutputPortToDTO(result.unwrap());
}
async getLeagueMemberships(leagueId: string): Promise<LeagueMembershipsDTO> {
@@ -261,25 +246,27 @@ export class LeagueService {
return presenter.getViewModel().memberships as LeagueMembershipsDTO;
}
async getLeagueStandings(leagueId: string): Promise<LeagueStandingsViewModel> {
async getLeagueStandings(leagueId: string): Promise<LeagueStandingsDTO> {
this.logger.debug('Getting league standings', { leagueId });
const result = await this.getLeagueStandingsUseCase.execute(leagueId);
// The use case returns a view model directly, so we return it as-is
return result as unknown as LeagueStandingsViewModel;
const result = await this.getLeagueStandingsUseCase.execute({ leagueId });
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new LeagueStandingsPresenter();
presenter.present(result.unwrap());
return presenter.getViewModel();
}
async getLeagueSchedule(leagueId: string): Promise<ReturnType<LeagueSchedulePresenter['getViewModel']>> {
async getLeagueSchedule(leagueId: string): Promise<LeagueScheduleDTO> {
this.logger.debug('Getting league schedule', { leagueId });
const result = await this.getLeagueScheduleUseCase.execute({ leagueId });
if (result.isErr()) {
throw new Error(result.unwrapErr().code);
}
const presenter = new LeagueSchedulePresenter();
presenter.present(result.unwrap());
return presenter.getViewModel()!;
return mapGetLeagueScheduleOutputPortToDTO(result.unwrap());
}
async getLeagueStats(leagueId: string): Promise<LeagueStatsViewModel> {
async getLeagueStats(leagueId: string): Promise<LeagueStatsDTO> {
this.logger.debug('Getting league stats', { leagueId });
const result = await this.getLeagueStatsUseCase.execute({ leagueId });
if (result.isErr()) {
@@ -404,7 +391,7 @@ export class LeagueService {
return presenter.getViewModel()!;
}
async joinLeague(leagueId: string, driverId: string): Promise<JoinLeagueViewModel> {
async joinLeague(leagueId: string, driverId: string): Promise<JoinLeagueOutputDTO> {
this.logger.debug('Joining league', { leagueId, driverId });
const result = await this.joinLeagueUseCase.execute({ leagueId, driverId });
@@ -415,12 +402,10 @@ export class LeagueService {
error: error.code,
};
}
const presenter = new JoinLeaguePresenter();
presenter.present(result.unwrap());
return presenter.getViewModel();
return mapJoinLeagueOutputPortToDTO(result.unwrap());
}
async transferLeagueOwnership(leagueId: string, currentOwnerId: string, newOwnerId: string): Promise<TransferLeagueOwnershipViewModel> {
async transferLeagueOwnership(leagueId: string, currentOwnerId: string, newOwnerId: string): Promise<TransferLeagueOwnershipOutputDTO> {
this.logger.debug('Transferring league ownership', { leagueId, currentOwnerId, newOwnerId });
const result = await this.transferLeagueOwnershipUseCase.execute({ leagueId, currentOwnerId, newOwnerId });
@@ -431,9 +416,7 @@ export class LeagueService {
error: error.code,
};
}
const presenter = new TransferLeagueOwnershipPresenter();
presenter.present({ success: true });
return presenter.getViewModel();
return mapTransferLeagueOwnershipOutputPortToDTO(result.unwrap());
}
async getSeasonSponsorships(seasonId: string): Promise<GetSeasonSponsorshipsOutputDTO> {

View File

@@ -1,16 +1,43 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber, IsArray, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';
import { LeagueWithCapacityDTO } from './LeagueWithCapacityDTO';
export class LeagueWithCapacityDTO {
@ApiProperty()
id!: string;
@ApiProperty()
name!: string;
@ApiProperty()
description!: string;
@ApiProperty()
ownerId!: string;
@ApiProperty()
settings!: {
maxDrivers: number;
sessionDuration?: number;
visibility?: string;
};
@ApiProperty()
createdAt!: string;
@ApiProperty({ nullable: true })
socialLinks?: {
discordUrl?: string;
youtubeUrl?: string;
websiteUrl?: string;
};
@ApiProperty()
usedSlots!: number;
}
export class AllLeaguesWithCapacityDTO {
@ApiProperty({ type: [LeagueWithCapacityDTO] })
@IsArray()
@ValidateNested({ each: true })
@Type(() => LeagueWithCapacityDTO)
leagues: LeagueWithCapacityDTO[];
leagues!: LeagueWithCapacityDTO[];
@ApiProperty()
@IsNumber()
totalCount: number;
totalCount!: number;
}

View File

@@ -0,0 +1,4 @@
export interface ApproveLeagueJoinRequestDTO {
success: boolean;
message: string;
}

View File

@@ -0,0 +1,4 @@
export interface CreateLeagueViewModel {
leagueId: string;
success: boolean;
}

View File

@@ -0,0 +1,8 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber } from 'class-validator';
export class TotalLeaguesDTO {
@ApiProperty()
@IsNumber()
totalLeagues: number;
}

View File

@@ -1,21 +1,22 @@
import { IAllLeaguesWithCapacityPresenter, AllLeaguesWithCapacityResultDTO, AllLeaguesWithCapacityViewModel } from '@core/racing/application/presenters/IAllLeaguesWithCapacityPresenter';
import type { AllLeaguesWithCapacityOutputPort } from '@core/racing/application/ports/output/AllLeaguesWithCapacityOutputPort';
import { AllLeaguesWithCapacityDTO, LeagueWithCapacityDTO } from '../dtos/AllLeaguesWithCapacityDTO';
export class AllLeaguesWithCapacityPresenter implements IAllLeaguesWithCapacityPresenter {
private result: AllLeaguesWithCapacityViewModel | null = null;
export class AllLeaguesWithCapacityPresenter {
private result: AllLeaguesWithCapacityDTO | null = null;
reset() {
this.result = null;
}
present(dto: AllLeaguesWithCapacityResultDTO) {
const leagues = dto.leagues.map(league => ({
present(output: AllLeaguesWithCapacityOutputPort) {
const leagues: LeagueWithCapacityDTO[] = output.leagues.map(league => ({
id: league.id,
name: league.name,
description: league.description,
ownerId: league.ownerId,
settings: { maxDrivers: league.settings.maxDrivers || 0 },
createdAt: league.createdAt.toISOString(),
usedSlots: dto.memberCounts.get(league.id) || 0,
usedSlots: output.memberCounts[league.id] || 0,
socialLinks: league.socialLinks,
}));
this.result = {
@@ -24,7 +25,7 @@ export class AllLeaguesWithCapacityPresenter implements IAllLeaguesWithCapacityP
};
}
getViewModel(): AllLeaguesWithCapacityViewModel | null {
getViewModel(): AllLeaguesWithCapacityDTO | null {
return this.result;
}
}

View File

@@ -1,18 +1,6 @@
import { IApproveLeagueJoinRequestPresenter, ApproveLeagueJoinRequestResultPort, ApproveLeagueJoinRequestViewModel } from '@core/racing/application/presenters/IApproveLeagueJoinRequestPresenter';
import type { ApproveLeagueJoinRequestResultPort } from '@core/racing/application/ports/output/ApproveLeagueJoinRequestResultPort';
import type { ApproveLeagueJoinRequestDTO } from '../dtos/ApproveLeagueJoinRequestDTO';
export class ApproveLeagueJoinRequestPresenter implements IApproveLeagueJoinRequestPresenter {
private result: ApproveLeagueJoinRequestViewModel | null = null;
reset() {
this.result = null;
}
present(dto: ApproveLeagueJoinRequestResultPort) {
this.result = dto;
}
getViewModel(): ApproveLeagueJoinRequestViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
export function mapApproveLeagueJoinRequestPortToDTO(port: ApproveLeagueJoinRequestResultPort): ApproveLeagueJoinRequestDTO {
return port;
}

View File

@@ -1,13 +1,14 @@
import { ICreateLeaguePresenter, CreateLeagueResultDTO, CreateLeagueViewModel } from '@core/racing/application/presenters/ICreateLeaguePresenter';
import type { CreateLeagueWithSeasonAndScoringOutputPort } from '@core/racing/application/ports/output/CreateLeagueWithSeasonAndScoringOutputPort';
import type { CreateLeagueViewModel } from '../dtos/CreateLeagueDTO';
export class CreateLeaguePresenter implements ICreateLeaguePresenter {
export class CreateLeaguePresenter {
private result: CreateLeagueViewModel | null = null;
reset() {
this.result = null;
}
present(dto: CreateLeagueResultDTO): void {
present(dto: CreateLeagueWithSeasonAndScoringOutputPort): void {
this.result = {
leagueId: dto.leagueId,
success: true,

View File

@@ -1,17 +0,0 @@
import { IGetLeagueAdminPermissionsPresenter, GetLeagueAdminPermissionsResultDTO, GetLeagueAdminPermissionsViewModel } from '@core/racing/application/presenters/IGetLeagueAdminPermissionsPresenter';
export class GetLeagueAdminPermissionsPresenter implements IGetLeagueAdminPermissionsPresenter {
private result: GetLeagueAdminPermissionsViewModel | null = null;
reset() {
this.result = null;
}
present(dto: GetLeagueAdminPermissionsResultDTO) {
this.result = dto;
}
getViewModel(): GetLeagueAdminPermissionsViewModel | null {
return this.result;
}
}

View File

@@ -1,47 +0,0 @@
import { IGetLeagueMembershipsPresenter, GetLeagueMembershipsResultDTO, GetLeagueMembershipsViewModel } from '@core/racing/application/presenters/IGetLeagueMembershipsPresenter';
import { LeagueMembershipsDTO } from '../dtos/LeagueMembershipsDTO';
export class GetLeagueMembershipsPresenter implements IGetLeagueMembershipsPresenter {
private result: GetLeagueMembershipsViewModel | null = null;
reset() {
this.result = null;
}
present(dto: GetLeagueMembershipsResultDTO) {
const driverMap = new Map(dto.drivers.map(d => [d.id, d]));
const members = dto.memberships.map(membership => ({
driverId: membership.driverId,
driver: driverMap.get(membership.driverId)!,
role: this.mapRole(membership.role) as 'owner' | 'manager' | 'member',
joinedAt: membership.joinedAt,
}));
this.result = { memberships: { members } };
}
private mapRole(role: string): 'owner' | 'manager' | 'member' {
switch (role) {
case 'owner':
return 'owner';
case 'admin':
return 'manager'; // Map admin to manager for API
case 'steward':
return 'member'; // Map steward to member for API
case 'member':
return 'member';
default:
return 'member';
}
}
getViewModel(): GetLeagueMembershipsViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
// API-specific method
get apiViewModel(): LeagueMembershipsDTO | null {
if (!this.result?.memberships) return null;
return this.result.memberships as LeagueMembershipsViewModel;
}
}

View File

@@ -1,18 +1,19 @@
import { IGetLeagueOwnerSummaryPresenter, GetLeagueOwnerSummaryResultDTO, GetLeagueOwnerSummaryViewModel } from '@core/racing/application/presenters/IGetLeagueOwnerSummaryPresenter';
import { GetLeagueOwnerSummaryOutputPort } from '@core/racing/application/ports/output/GetLeagueOwnerSummaryOutputPort';
import { LeagueOwnerSummaryDTO } from '../dtos/LeagueOwnerSummaryDTO';
export class GetLeagueOwnerSummaryPresenter implements IGetLeagueOwnerSummaryPresenter {
private result: GetLeagueOwnerSummaryViewModel | null = null;
export function mapGetLeagueOwnerSummaryOutputPortToDTO(output: GetLeagueOwnerSummaryOutputPort): LeagueOwnerSummaryDTO | null {
if (!output.summary) return null;
reset() {
this.result = null;
}
present(dto: GetLeagueOwnerSummaryResultDTO) {
this.result = { summary: dto.summary };
}
getViewModel(): GetLeagueOwnerSummaryViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
return {
driver: {
id: output.summary.driver.id,
iracingId: output.summary.driver.iracingId,
name: output.summary.driver.name,
country: output.summary.driver.country,
bio: output.summary.driver.bio,
joinedAt: output.summary.driver.joinedAt,
},
rating: output.summary.rating,
rank: output.summary.rank,
};
}

View File

@@ -1,30 +1,47 @@
import { IGetLeagueProtestsPresenter, GetLeagueProtestsResultDTO, GetLeagueProtestsViewModel } from '@core/racing/application/presenters/IGetLeagueProtestsPresenter';
import { GetLeagueProtestsOutputPort } from '@core/racing/application/ports/output/GetLeagueProtestsOutputPort';
import { LeagueAdminProtestsDTO } from '../dtos/LeagueAdminProtestsDTO';
import { ProtestDTO } from '../dtos/ProtestDTO';
import { RaceDTO } from '../../race/dtos/RaceDTO';
import { DriverDTO } from '../../driver/dtos/DriverDTO';
export class GetLeagueProtestsPresenter implements IGetLeagueProtestsPresenter {
private result: GetLeagueProtestsViewModel | null = null;
export function mapGetLeagueProtestsOutputPortToDTO(output: GetLeagueProtestsOutputPort): LeagueAdminProtestsDTO {
const protests: ProtestDTO[] = output.protests.map(protest => ({
id: protest.id,
raceId: protest.raceId,
protestingDriverId: protest.protestingDriverId,
accusedDriverId: protest.accusedDriverId,
submittedAt: new Date(protest.filedAt),
description: protest.incident.description,
status: protest.status as 'pending' | 'accepted' | 'rejected', // TODO: map properly
}));
reset() {
this.result = null;
}
present(dto: GetLeagueProtestsResultDTO) {
const racesById = {};
dto.races.forEach(race => {
racesById[race.id] = race;
});
const driversById = {};
dto.drivers.forEach(driver => {
driversById[driver.id] = driver;
});
this.result = {
protests: dto.protests,
racesById,
driversById,
const racesById: { [raceId: string]: RaceDTO } = {};
for (const raceId in output.racesById) {
const race = output.racesById[raceId];
racesById[raceId] = {
id: race.id,
name: race.track, // assuming name is track
date: race.scheduledAt,
leagueName: undefined, // TODO: get league name if needed
};
}
getViewModel(): GetLeagueProtestsViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
const driversById: { [driverId: string]: DriverDTO } = {};
for (const driverId in output.driversById) {
const driver = output.driversById[driverId];
driversById[driverId] = {
id: driver.id,
iracingId: driver.iracingId,
name: driver.name,
country: driver.country,
bio: driver.bio,
joinedAt: driver.joinedAt,
};
}
return {
protests,
racesById,
driversById,
};
}

View File

@@ -1,27 +1,14 @@
import { IGetLeagueSeasonsPresenter, GetLeagueSeasonsResultDTO, GetLeagueSeasonsViewModel } from '@core/racing/application/presenters/IGetLeagueSeasonsPresenter';
import { GetLeagueSeasonsOutputPort } from '@core/racing/application/ports/output/GetLeagueSeasonsOutputPort';
import { LeagueSeasonSummaryDTO } from '../dtos/LeagueSeasonSummaryDTO';
export class GetLeagueSeasonsPresenter implements IGetLeagueSeasonsPresenter {
private result: GetLeagueSeasonsViewModel | null = null;
reset() {
this.result = null;
}
present(dto: GetLeagueSeasonsResultDTO) {
const seasons = dto.seasons.map(season => ({
seasonId: season.id,
name: season.name,
status: season.status,
startDate: season.startDate,
endDate: season.endDate,
isPrimary: season.isPrimary,
isParallelActive: season.isParallelActive,
}));
this.result = { seasons };
}
getViewModel(): GetLeagueSeasonsViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
export function mapGetLeagueSeasonsOutputPortToDTO(output: GetLeagueSeasonsOutputPort): LeagueSeasonSummaryDTO[] {
return output.seasons.map(season => ({
seasonId: season.seasonId,
name: season.name,
status: season.status,
startDate: season.startDate,
endDate: season.endDate,
isPrimary: season.isPrimary,
isParallelActive: season.isParallelActive,
}));
}

View File

@@ -1,21 +1,9 @@
import { IJoinLeaguePresenter, JoinLeagueResultDTO, JoinLeagueViewModel } from '@core/racing/application/presenters/IJoinLeaguePresenter';
import type { JoinLeagueOutputPort } from '@core/racing/application/ports/output/JoinLeagueOutputPort';
import type { JoinLeagueOutputDTO } from '../dtos/JoinLeagueOutputDTO';
export class JoinLeaguePresenter implements IJoinLeaguePresenter {
private result: JoinLeagueViewModel | null = null;
reset() {
this.result = null;
}
present(dto: JoinLeagueResultDTO): void {
this.result = {
success: true,
membershipId: dto.id,
};
}
getViewModel(): JoinLeagueViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
export function mapJoinLeagueOutputPortToDTO(port: JoinLeagueOutputPort): JoinLeagueOutputDTO {
return {
success: true,
membershipId: port.membershipId,
};
}

View File

@@ -1,15 +1,16 @@
import { ILeagueFullConfigPresenter, LeagueFullConfigData, LeagueConfigFormViewModel } from '@core/racing/application/presenters/ILeagueFullConfigPresenter';
import { LeagueFullConfigOutputPort } from '@core/racing/application/ports/output/LeagueFullConfigOutputPort';
import { LeagueConfigFormModelDTO } from '../dtos/LeagueConfigFormModelDTO';
import type { Presenter } from '@core/shared/presentation';
export class LeagueConfigPresenter implements ILeagueFullConfigPresenter {
private result: LeagueConfigFormViewModel | null = null;
export class LeagueConfigPresenter implements Presenter<LeagueFullConfigOutputPort, LeagueConfigFormModelDTO> {
private result: LeagueConfigFormModelDTO | null = null;
reset() {
this.result = null;
}
present(dto: LeagueFullConfigData) {
// Map from LeagueFullConfigData to LeagueConfigFormViewModel
present(dto: LeagueFullConfigOutputPort) {
// Map from LeagueFullConfigOutputPort to LeagueConfigFormModelDTO
const league = dto.league;
const settings = league.settings;
const stewarding = settings.stewarding;
@@ -20,64 +21,9 @@ export class LeagueConfigPresenter implements ILeagueFullConfigPresenter {
name: league.name,
description: league.description,
visibility: 'public', // TODO: Map visibility from league
gameId: 'iracing', // TODO: Map from game
},
structure: {
mode: 'solo', // TODO: Map from league settings
maxDrivers: settings.maxDrivers || 32,
multiClassEnabled: false, // TODO: Map
},
championships: {
enableDriverChampionship: true, // TODO: Map
enableTeamChampionship: false,
enableNationsChampionship: false,
enableTrophyChampionship: false,
},
scoring: {
customScoringEnabled: false, // TODO: Map
},
dropPolicy: {
strategy: 'none', // TODO: Map
},
timings: {
practiceMinutes: 30, // TODO: Map
qualifyingMinutes: 15,
mainRaceMinutes: 60,
sessionCount: 1,
roundsPlanned: 10, // TODO: Map
},
stewarding: {
decisionMode: stewarding?.decisionMode || 'admin_only',
requireDefense: stewarding?.requireDefense || false,
defenseTimeLimit: stewarding?.defenseTimeLimit || 48,
voteTimeLimit: stewarding?.voteTimeLimit || 72,
protestDeadlineHours: stewarding?.protestDeadlineHours || 48,
stewardingClosesHours: stewarding?.stewardingClosesHours || 168,
notifyAccusedOnProtest: stewarding?.notifyAccusedOnProtest || true,
notifyOnVoteRequired: stewarding?.notifyOnVoteRequired || true,
requiredVotes: stewarding?.requiredVotes,
},
};
}
getViewModel(): LeagueConfigFormViewModel | null {
return this.result;
}
// API-specific method to get the DTO
get viewModel(): LeagueConfigFormModelDTO | null {
if (!this.result) return null;
// Map from LeagueConfigFormViewModel to LeagueConfigFormModelDto
return {
leagueId: this.result.leagueId,
basics: {
name: this.result.basics.name,
description: this.result.basics.description,
visibility: this.result.basics.visibility as 'public' | 'private',
},
structure: {
mode: this.result.structure.mode as 'solo' | 'team',
},
championships: [], // TODO: Map championships
scoring: {
@@ -85,8 +31,8 @@ export class LeagueConfigPresenter implements ILeagueFullConfigPresenter {
points: 25, // TODO: Map points
},
dropPolicy: {
strategy: this.result.dropPolicy.strategy as 'none' | 'worst_n',
n: this.result.dropPolicy.n,
strategy: 'none', // TODO: Map
n: 0,
},
timings: {
raceDayOfWeek: 'sunday', // TODO: Map from timings
@@ -94,16 +40,20 @@ export class LeagueConfigPresenter implements ILeagueFullConfigPresenter {
raceTimeMinute: 0,
},
stewarding: {
decisionMode: this.result.stewarding.decisionMode === 'steward_vote' ? 'committee_vote' : 'single_steward',
requireDefense: this.result.stewarding.requireDefense,
defenseTimeLimit: this.result.stewarding.defenseTimeLimit,
voteTimeLimit: this.result.stewarding.voteTimeLimit,
protestDeadlineHours: this.result.stewarding.protestDeadlineHours,
stewardingClosesHours: this.result.stewarding.stewardingClosesHours,
notifyAccusedOnProtest: this.result.stewarding.notifyAccusedOnProtest,
notifyOnVoteRequired: this.result.stewarding.notifyOnVoteRequired,
requiredVotes: this.result.stewarding.requiredVotes,
decisionMode: stewarding?.decisionMode === 'steward_vote' ? 'committee_vote' : 'single_steward',
requireDefense: stewarding?.requireDefense || false,
defenseTimeLimit: stewarding?.defenseTimeLimit || 48,
voteTimeLimit: stewarding?.voteTimeLimit || 72,
protestDeadlineHours: stewarding?.protestDeadlineHours || 48,
stewardingClosesHours: stewarding?.stewardingClosesHours || 168,
notifyAccusedOnProtest: stewarding?.notifyAccusedOnProtest || true,
notifyOnVoteRequired: stewarding?.notifyOnVoteRequired || true,
requiredVotes: stewarding?.requiredVotes || 0,
},
};
}
getViewModel(): LeagueConfigFormModelDTO | null {
return this.result;
}
}

View File

@@ -1,27 +0,0 @@
import { IGetLeagueJoinRequestsPresenter, GetLeagueJoinRequestsResultDTO, GetLeagueJoinRequestsViewModel } from '@core/racing/application/presenters/IGetLeagueJoinRequestsPresenter';
export class LeagueJoinRequestsPresenter implements IGetLeagueJoinRequestsPresenter {
private result: GetLeagueJoinRequestsViewModel | null = null;
reset() {
this.result = null;
}
present(dto: GetLeagueJoinRequestsResultDTO) {
const driverMap = new Map(dto.drivers.map(d => [d.id, d]));
const joinRequests = dto.joinRequests.map(request => ({
id: request.id,
leagueId: request.leagueId,
driverId: request.driverId,
requestedAt: request.requestedAt,
message: request.message,
driver: driverMap.get(request.driverId) || null,
}));
this.result = { joinRequests };
}
getViewModel(): GetLeagueJoinRequestsViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
}

View File

@@ -1,23 +1,14 @@
import { IGetLeagueSchedulePresenter, GetLeagueScheduleResultDTO, LeagueScheduleViewModel } from '@core/racing/application/presenters/IGetLeagueSchedulePresenter';
import { GetLeagueScheduleOutputPort } from '@core/racing/application/ports/output/GetLeagueScheduleOutputPort';
import { LeagueScheduleDTO } from '../dtos/LeagueScheduleDTO';
import { RaceDTO } from '../../race/dtos/RaceDTO';
export class LeagueSchedulePresenter implements IGetLeagueSchedulePresenter {
private result: LeagueScheduleViewModel | null = null;
reset() {
this.result = null;
}
present(dto: GetLeagueScheduleResultDTO) {
this.result = {
races: dto.races.map(race => ({
id: race.id,
name: race.name,
date: race.scheduledAt.toISOString(),
})),
};
}
getViewModel(): LeagueScheduleViewModel | null {
return this.result;
}
export function mapGetLeagueScheduleOutputPortToDTO(output: GetLeagueScheduleOutputPort): LeagueScheduleDTO {
return {
races: output.races.map(race => ({
id: race.id,
name: race.name,
date: race.scheduledAt.toISOString(),
leagueName: undefined, // TODO: get league name if needed
})),
};
}

View File

@@ -1,20 +1,37 @@
import type { ChampionshipConfig } from '@core/racing/domain/types/ChampionshipConfig';
import type { BonusRule } from '@core/racing/domain/types/BonusRule';
import type {
ILeagueScoringConfigPresenter,
LeagueScoringConfigData,
LeagueScoringConfigViewModel,
LeagueScoringChampionshipViewModel,
} from '@core/racing/application/presenters/ILeagueScoringConfigPresenter';
import type { LeagueScoringConfigOutputPort } from '@core/racing/application/ports/output/LeagueScoringConfigOutputPort';
import type { LeagueScoringPresetOutputPort } from '@core/racing/application/ports/output/LeagueScoringPresetOutputPort';
export class LeagueScoringConfigPresenter implements ILeagueScoringConfigPresenter {
export interface LeagueScoringChampionshipViewModel {
id: string;
name: string;
type: string;
sessionTypes: string[];
pointsPreview: Array<{ sessionType: string; position: number; points: number }>;
bonusSummary: string[];
dropPolicyDescription: string;
}
export interface LeagueScoringConfigViewModel {
leagueId: string;
seasonId: string;
gameId: string;
gameName: string;
scoringPresetId?: string;
scoringPresetName?: string;
dropPolicySummary: string;
championships: LeagueScoringChampionshipViewModel[];
}
export class LeagueScoringConfigPresenter {
private viewModel: LeagueScoringConfigViewModel | null = null;
reset(): void {
this.viewModel = null;
}
present(data: LeagueScoringConfigData): LeagueScoringConfigViewModel {
present(data: LeagueScoringConfigOutputPort): LeagueScoringConfigViewModel {
const championships: LeagueScoringChampionshipViewModel[] =
data.championships.map((champ) => this.mapChampionship(champ));

View File

@@ -1,19 +1,22 @@
import type {
ILeagueScoringPresetsPresenter,
LeagueScoringPresetsResultDTO,
LeagueScoringPresetsViewModel,
} from '@core/racing/application/presenters/ILeagueScoringPresetsPresenter';
import type { LeagueScoringPresetsOutputPort } from '@core/racing/application/ports/output/LeagueScoringPresetsOutputPort';
import type { LeagueScoringPresetOutputPort } from '@core/racing/application/ports/output/LeagueScoringPresetOutputPort';
export class LeagueScoringPresetsPresenter implements ILeagueScoringPresetsPresenter {
export interface LeagueScoringPresetsViewModel {
presets: LeagueScoringPresetOutputPort[];
totalCount: number;
}
export class LeagueScoringPresetsPresenter {
private viewModel: LeagueScoringPresetsViewModel | null = null;
reset(): void {
this.viewModel = null;
}
present(dto: LeagueScoringPresetsResultDTO): void {
present(output: LeagueScoringPresetsOutputPort): void {
this.viewModel = {
presets: dto.presets,
presets: output.presets,
totalCount: output.presets.length,
};
}

View File

@@ -1,26 +1,29 @@
import { ILeagueStandingsPresenter, LeagueStandingsResultDTO, LeagueStandingsViewModel } from '@core/racing/application/presenters/ILeagueStandingsPresenter';
import { LeagueStandingsOutputPort } from '@core/racing/application/ports/output/LeagueStandingsOutputPort';
import { LeagueStandingsDTO } from '../dtos/LeagueStandingsDTO';
import type { Presenter } from '@core/shared/presentation';
export class LeagueStandingsPresenter implements ILeagueStandingsPresenter {
private result: LeagueStandingsViewModel | null = null;
export class LeagueStandingsPresenter implements Presenter<LeagueStandingsOutputPort, LeagueStandingsDTO> {
private result: LeagueStandingsDTO | null = null;
reset() {
this.result = null;
}
present(dto: LeagueStandingsResultDTO) {
const driverMap = new Map(dto.drivers.map(d => [d.id, { id: d.id, name: d.name }]));
const standings = dto.standings
.sort((a, b) => a.position - b.position)
.map(standing => ({
driverId: standing.driverId,
driver: driverMap.get(standing.driverId)!,
points: standing.points,
rank: standing.position,
}));
present(dto: LeagueStandingsOutputPort) {
const standings = dto.standings.map(standing => ({
driverId: standing.driverId,
driver: {
id: standing.driver.id,
name: standing.driver.name,
// Add other DriverDto fields if needed, but for now just id and name
},
points: standing.points,
rank: standing.rank,
}));
this.result = { standings };
}
getViewModel(): LeagueStandingsViewModel {
getViewModel(): LeagueStandingsDTO {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}

View File

@@ -1,17 +1,19 @@
import { ILeagueStatsPresenter, LeagueStatsResultDTO, LeagueStatsViewModel } from '@core/racing/application/presenters/ILeagueStatsPresenter';
import { LeagueStatsOutputPort } from '@core/racing/application/ports/output/LeagueStatsOutputPort';
import { LeagueStatsDTO } from '../dtos/LeagueStatsDTO';
import type { Presenter } from '@core/shared/presentation';
export class LeagueStatsPresenter implements ILeagueStatsPresenter {
private result: LeagueStatsViewModel | null = null;
export class LeagueStatsPresenter implements Presenter<LeagueStatsOutputPort, LeagueStatsDTO> {
private result: LeagueStatsDTO | null = null;
reset() {
this.result = null;
}
present(dto: LeagueStatsResultDTO) {
present(dto: LeagueStatsOutputPort) {
this.result = dto;
}
getViewModel(): LeagueStatsViewModel | null {
getViewModel(): LeagueStatsDTO | null {
return this.result;
}
}

View File

@@ -1,18 +1,9 @@
import { IRejectLeagueJoinRequestPresenter, RejectLeagueJoinRequestResultDTO, RejectLeagueJoinRequestViewModel } from '@core/racing/application/presenters/IRejectLeagueJoinRequestPresenter';
import type { RejectLeagueJoinRequestOutputPort } from '@core/racing/application/ports/output/RejectLeagueJoinRequestOutputPort';
import type { RejectJoinRequestOutputDTO } from '../dtos/RejectJoinRequestOutputDTO';
export class RejectLeagueJoinRequestPresenter implements IRejectLeagueJoinRequestPresenter {
private result: RejectLeagueJoinRequestViewModel | null = null;
reset() {
this.result = null;
}
present(dto: RejectLeagueJoinRequestResultDTO) {
this.result = dto;
}
getViewModel(): RejectLeagueJoinRequestViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
export function mapRejectLeagueJoinRequestOutputPortToDTO(port: RejectLeagueJoinRequestOutputPort): RejectJoinRequestOutputDTO {
return {
success: port.success,
message: port.message,
};
}

View File

@@ -1,18 +1,8 @@
import { IRemoveLeagueMemberPresenter, RemoveLeagueMemberResultDTO, RemoveLeagueMemberViewModel } from '@core/racing/application/presenters/IRemoveLeagueMemberPresenter';
import type { RemoveLeagueMemberOutputPort } from '@core/racing/application/ports/output/RemoveLeagueMemberOutputPort';
import type { RemoveLeagueMemberOutputDTO } from '../dtos/RemoveLeagueMemberOutputDTO';
export class RemoveLeagueMemberPresenter implements IRemoveLeagueMemberPresenter {
private result: RemoveLeagueMemberViewModel | null = null;
reset() {
this.result = null;
}
present(dto: RemoveLeagueMemberResultDTO) {
this.result = dto;
}
getViewModel(): RemoveLeagueMemberViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
export function mapRemoveLeagueMemberOutputPortToDTO(port: RemoveLeagueMemberOutputPort): RemoveLeagueMemberOutputDTO {
return {
success: port.success,
};
}

View File

@@ -1,20 +1,20 @@
import { IGetTotalLeaguesPresenter, GetTotalLeaguesResultDTO, GetTotalLeaguesViewModel } from '@core/racing/application/presenters/IGetTotalLeaguesPresenter';
import { LeagueStatsDTO } from '../dtos/LeagueStatsDTO';
import { GetTotalLeaguesOutputPort } from '@core/racing/application/ports/output/GetTotalLeaguesOutputPort';
import { TotalLeaguesDTO } from '../dtos/TotalLeaguesDTO';
export class TotalLeaguesPresenter implements IGetTotalLeaguesPresenter {
private result: LeagueStatsDto | null = null;
export class TotalLeaguesPresenter {
private result: TotalLeaguesDTO | null = null;
reset() {
this.result = null;
}
present(dto: GetTotalLeaguesResultDTO) {
present(output: GetTotalLeaguesOutputPort) {
this.result = {
totalLeagues: dto.totalLeagues,
totalLeagues: output.totalLeagues,
};
}
getViewModel(): LeagueStatsDto | null {
getViewModel(): TotalLeaguesDTO | null {
return this.result;
}
}

View File

@@ -1,20 +1,8 @@
import { ITransferLeagueOwnershipPresenter, TransferLeagueOwnershipResultDTO, TransferLeagueOwnershipViewModel } from '@core/racing/application/presenters/ITransferLeagueOwnershipPresenter';
import type { TransferLeagueOwnershipOutputPort } from '@core/racing/application/ports/output/TransferLeagueOwnershipOutputPort';
import type { TransferLeagueOwnershipOutputDTO } from '../dtos/TransferLeagueOwnershipOutputDTO';
export class TransferLeagueOwnershipPresenter implements ITransferLeagueOwnershipPresenter {
private result: TransferLeagueOwnershipViewModel | null = null;
reset() {
this.result = null;
}
present(dto: TransferLeagueOwnershipResultDTO): void {
this.result = {
success: dto.success,
};
}
getViewModel(): TransferLeagueOwnershipViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
export function mapTransferLeagueOwnershipOutputPortToDTO(port: TransferLeagueOwnershipOutputPort): TransferLeagueOwnershipOutputDTO {
return {
success: port.success,
};
}

View File

@@ -1,18 +1,8 @@
import { IUpdateLeagueMemberRolePresenter, UpdateLeagueMemberRoleResultDTO, UpdateLeagueMemberRoleViewModel } from '@core/racing/application/presenters/IUpdateLeagueMemberRolePresenter';
import type { UpdateLeagueMemberRoleOutputPort } from '@core/racing/application/ports/output/UpdateLeagueMemberRoleOutputPort';
import type { UpdateLeagueMemberRoleOutputDTO } from '../dtos/UpdateLeagueMemberRoleOutputDTO';
export class UpdateLeagueMemberRolePresenter implements IUpdateLeagueMemberRolePresenter {
private result: UpdateLeagueMemberRoleViewModel | null = null;
reset() {
this.result = null;
}
present(dto: UpdateLeagueMemberRoleResultDTO) {
this.result = dto;
}
getViewModel(): UpdateLeagueMemberRoleViewModel {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
export function mapUpdateLeagueMemberRoleOutputPortToDTO(port: UpdateLeagueMemberRoleOutputPort): UpdateLeagueMemberRoleOutputDTO {
return {
success: port.success,
};
}