refactor core presenters
This commit is contained in:
@@ -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()),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface ApproveLeagueJoinRequestDTO {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
4
apps/api/src/domain/league/dtos/CreateLeagueDTO.ts
Normal file
4
apps/api/src/domain/league/dtos/CreateLeagueDTO.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface CreateLeagueViewModel {
|
||||
leagueId: string;
|
||||
success: boolean;
|
||||
}
|
||||
8
apps/api/src/domain/league/dtos/TotalLeaguesDTO.ts
Normal file
8
apps/api/src/domain/league/dtos/TotalLeaguesDTO.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNumber } from 'class-validator';
|
||||
|
||||
export class TotalLeaguesDTO {
|
||||
@ApiProperty()
|
||||
@IsNumber()
|
||||
totalLeagues: number;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
}));
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user