refactor league module (wip)
This commit is contained in:
@@ -1,13 +1,12 @@
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import { AllLeaguesWithCapacityDTO, LeagueWithCapacityDTO } from '../dtos/AllLeaguesWithCapacityDTO';
|
||||
import type { GetAllLeaguesWithCapacityResult } from '@core/racing/application/use-cases/GetAllLeaguesWithCapacityUseCase';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
|
||||
export class AllLeaguesWithCapacityPresenter implements UseCaseOutputPort<GetAllLeaguesWithCapacityResult, 'REPOSITORY_ERROR'> {
|
||||
present(result: Result<GetAllLeaguesWithCapacityResult, ApplicationErrorCode<'REPOSITORY_ERROR'>>): AllLeaguesWithCapacityDTO {
|
||||
const output = result.unwrap();
|
||||
const leagues: LeagueWithCapacityDTO[] = output.leagues.map(league => ({
|
||||
export class AllLeaguesWithCapacityPresenter implements UseCaseOutputPort<GetAllLeaguesWithCapacityResult> {
|
||||
private result: AllLeaguesWithCapacityDTO | null = null;
|
||||
|
||||
present(result: GetAllLeaguesWithCapacityResult): void {
|
||||
const leagues: LeagueWithCapacityDTO[] = result.leagues.map(league => ({
|
||||
id: league.league.id.toString(),
|
||||
name: league.league.name.toString(),
|
||||
description: league.league.description?.toString() || '',
|
||||
@@ -17,9 +16,14 @@ export class AllLeaguesWithCapacityPresenter implements UseCaseOutputPort<GetAll
|
||||
usedSlots: league.currentDrivers,
|
||||
socialLinks: league.league.socialLinks || {},
|
||||
}));
|
||||
return {
|
||||
this.result = {
|
||||
leagues,
|
||||
totalCount: leagues.length,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): AllLeaguesWithCapacityDTO {
|
||||
if (!this.result) throw new Error('Presenter not presented');
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
import type { ApproveLeagueJoinRequestResultPort } from '@core/racing/application/ports/output/ApproveLeagueJoinRequestResultPort';
|
||||
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import { ApproveLeagueJoinRequestResult } from '@core/racing/application/use-cases/ApproveLeagueJoinRequestUseCase';
|
||||
import type { ApproveLeagueJoinRequestDTO } from '../dtos/ApproveLeagueJoinRequestDTO';
|
||||
|
||||
export class ApproveLeagueJoinRequestPresenter {
|
||||
export class ApproveLeagueJoinRequestPresenter implements UseCaseOutputPort<ApproveLeagueJoinRequestResult> {
|
||||
private result: ApproveLeagueJoinRequestDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: ApproveLeagueJoinRequestResultPort) {
|
||||
present(output: ApproveLeagueJoinRequestResult) {
|
||||
this.result = output;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CreateLeagueWithSeasonAndScoringOutputPort } from '@core/racing/application/ports/output/CreateLeagueWithSeasonAndScoringOutputPort';
|
||||
import { CreateLeagueWithSeasonAndScoringResult } from '@core/racing/application/use-cases/CreateLeagueWithSeasonAndScoringUseCase';
|
||||
import type { CreateLeagueViewModel } from '../dtos/CreateLeagueDTO';
|
||||
|
||||
export class CreateLeaguePresenter {
|
||||
@@ -8,9 +8,9 @@ export class CreateLeaguePresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(dto: CreateLeagueWithSeasonAndScoringOutputPort): void {
|
||||
present(dto: CreateLeagueWithSeasonAndScoringResult): void {
|
||||
this.result = {
|
||||
leagueId: dto.leagueId,
|
||||
leagueId: dto.league.id.toString(),
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import type { GetLeagueAdminPermissionsOutputPort } from '@core/racing/application/ports/output/GetLeagueAdminPermissionsOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import type { GetLeagueAdminPermissionsResult } from '@core/racing/application/use-cases/GetLeagueAdminPermissionsUseCase';
|
||||
import { LeagueAdminPermissionsDTO } from '../dtos/LeagueAdminPermissionsDTO';
|
||||
import type { Presenter } from '@core/shared/presentation';
|
||||
|
||||
export class GetLeagueAdminPermissionsPresenter implements Presenter<GetLeagueAdminPermissionsOutputPort, LeagueAdminPermissionsDTO> {
|
||||
export class GetLeagueAdminPermissionsPresenter implements UseCaseOutputPort<GetLeagueAdminPermissionsResult> {
|
||||
private result: LeagueAdminPermissionsDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(port: GetLeagueAdminPermissionsOutputPort): void {
|
||||
present(port: GetLeagueAdminPermissionsResult): void {
|
||||
this.result = {
|
||||
canRemoveMember: port.canRemoveMember,
|
||||
canUpdateRoles: port.canUpdateRoles,
|
||||
canRemoveMember: port.permissions.canManageMembers,
|
||||
canUpdateRoles: port.permissions.canManageMembers,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): LeagueAdminPermissionsDTO | null {
|
||||
getResponseModel(): LeagueAdminPermissionsDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,34 @@
|
||||
import { GetLeagueMembershipsPresenter } from './GetLeagueMembershipsPresenter';
|
||||
import type { GetLeagueMembershipsOutputPort } from '@core/racing/application/ports/output/GetLeagueMembershipsOutputPort';
|
||||
import type { GetLeagueMembershipsResult } from '@core/racing/application/use-cases/GetLeagueMembershipsUseCase';
|
||||
|
||||
describe('GetLeagueMembershipsPresenter', () => {
|
||||
it('presents memberships correctly', () => {
|
||||
const presenter = new GetLeagueMembershipsPresenter();
|
||||
const output: GetLeagueMembershipsOutputPort = {
|
||||
memberships: {
|
||||
members: [
|
||||
{
|
||||
const output: GetLeagueMembershipsResult = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
league: {} as any,
|
||||
memberships: [
|
||||
{
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
membership: {
|
||||
driverId: 'driver-1',
|
||||
driver: { id: 'driver-1', name: 'John Doe' },
|
||||
role: 'member',
|
||||
joinedAt: new Date('2023-01-01'),
|
||||
},
|
||||
],
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
joinedAt: {} as any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
driver: { id: 'driver-1', name: 'John Doe' } as any,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
presenter.present(output);
|
||||
const vm = presenter.getViewModel();
|
||||
const vm = presenter.getViewModel()!;
|
||||
|
||||
expect(vm).not.toBeNull();
|
||||
expect(vm!.memberships.members).toHaveLength(1);
|
||||
expect(vm!.memberships.members[0].driverId).toBe('driver-1');
|
||||
expect(vm!.memberships.members[0].driver.name).toBe('John Doe');
|
||||
expect(vm!.memberships.members[0]!.driverId).toBe('driver-1');
|
||||
expect(vm!.memberships.members[0]!.driver.name).toBe('John Doe');
|
||||
});
|
||||
});
|
||||
@@ -1,24 +1,35 @@
|
||||
import type { GetLeagueMembershipsOutputPort } from '@core/racing/application/ports/output/GetLeagueMembershipsOutputPort';
|
||||
import { LeagueMembershipsDTO, LeagueMemberDTO } from '../dtos/LeagueMembershipsDTO';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import { GetLeagueMembershipsResult } from '@core/racing/application/use-cases/GetLeagueMembershipsUseCase';
|
||||
import { LeagueMembershipsDTO } from '../dtos/LeagueMembershipsDTO';
|
||||
import type { LeagueMemberDTO } from '../dtos/LeagueMemberDTO';
|
||||
|
||||
export interface GetLeagueMembershipsViewModel {
|
||||
memberships: LeagueMembershipsDTO;
|
||||
}
|
||||
|
||||
export class GetLeagueMembershipsPresenter {
|
||||
export class GetLeagueMembershipsPresenter implements UseCaseOutputPort<GetLeagueMembershipsResult> {
|
||||
private result: GetLeagueMembershipsViewModel | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetLeagueMembershipsOutputPort) {
|
||||
const members: LeagueMemberDTO[] = output.memberships.members.map(member => ({
|
||||
driverId: member.driverId,
|
||||
driver: member.driver,
|
||||
role: member.role,
|
||||
joinedAt: member.joinedAt,
|
||||
}));
|
||||
present(result: GetLeagueMembershipsResult) {
|
||||
const members: LeagueMemberDTO[] = result.memberships
|
||||
.filter(({ driver }) => driver !== null)
|
||||
.map(({ membership, driver }) => ({
|
||||
driverId: membership.driverId.toString(),
|
||||
driver: {
|
||||
id: driver!.id,
|
||||
iracingId: driver!.iracingId.toString(),
|
||||
name: driver!.name.toString(),
|
||||
country: driver!.country.toString(),
|
||||
joinedAt: driver!.joinedAt.toDate().toISOString(),
|
||||
...(driver!.bio ? { bio: driver!.bio.toString() } : {}),
|
||||
},
|
||||
role: membership.role.toString() as 'owner' | 'manager' | 'member',
|
||||
joinedAt: membership.joinedAt.toDate(),
|
||||
}));
|
||||
this.result = {
|
||||
memberships: {
|
||||
members,
|
||||
|
||||
@@ -66,7 +66,7 @@ export class GetLeagueProtestsPresenter implements Presenter<GetLeagueProtestsRe
|
||||
iracingId: protestingDriver.iracingId.toString(),
|
||||
name: protestingDriver.name.toString(),
|
||||
country: protestingDriver.country.toString(),
|
||||
bio: protestingDriver.bio?.toString(),
|
||||
bio: protestingDriver.bio?.toString() || '',
|
||||
joinedAt: protestingDriver.joinedAt.toDate().toISOString(),
|
||||
};
|
||||
}
|
||||
@@ -76,8 +76,8 @@ export class GetLeagueProtestsPresenter implements Presenter<GetLeagueProtestsRe
|
||||
iracingId: accusedDriver.iracingId.toString(),
|
||||
name: accusedDriver.name.toString(),
|
||||
country: accusedDriver.country.toString(),
|
||||
bio: accusedDriver.bio?.toString(),
|
||||
joinedAt: accusedDriver.joinedAt.toISOString(),
|
||||
bio: accusedDriver.bio?.toString() || '',
|
||||
joinedAt: accusedDriver.joinedAt.toDate().toISOString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,34 @@
|
||||
import type { GetSeasonSponsorshipsOutputPort } from '@core/racing/application/ports/output/GetSeasonSponsorshipsOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetSeasonSponsorshipsResult } from '@core/racing/application/use-cases/GetSeasonSponsorshipsUseCase';
|
||||
import { GetSeasonSponsorshipsOutputDTO } from '../dtos/GetSeasonSponsorshipsOutputDTO';
|
||||
import { SponsorshipDetailDTO } from '../../sponsor/dtos/SponsorshipDetailDTO';
|
||||
|
||||
export class GetSeasonSponsorshipsPresenter {
|
||||
export class GetSeasonSponsorshipsPresenter implements UseCaseOutputPort<GetSeasonSponsorshipsResult> {
|
||||
private result: GetSeasonSponsorshipsOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetSeasonSponsorshipsOutputPort) {
|
||||
present(result: GetSeasonSponsorshipsResult): void {
|
||||
this.result = {
|
||||
sponsorships: output?.sponsorships ?? [],
|
||||
sponsorships: result.sponsorships.map(s => ({
|
||||
id: s.id,
|
||||
leagueId: s.leagueId.toString(),
|
||||
leagueName: s.leagueName.toString(),
|
||||
seasonId: s.seasonId,
|
||||
seasonName: s.seasonName,
|
||||
seasonStartDate: s.seasonStartDate,
|
||||
seasonEndDate: s.seasonEndDate,
|
||||
tier: s.tier as 'main' | 'secondary',
|
||||
status: s.status as 'pending' | 'active' | 'expired' | 'cancelled',
|
||||
pricing: s.pricing,
|
||||
platformFee: s.platformFee,
|
||||
netAmount: s.netAmount,
|
||||
metrics: s.metrics,
|
||||
createdAt: s.createdAt,
|
||||
activatedAt: s.activatedAt,
|
||||
} as SponsorshipDetailDTO)),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
import type { JoinLeagueOutputPort } from '@core/racing/application/ports/output/JoinLeagueOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { JoinLeagueResult } from '@core/racing/application/use-cases/JoinLeagueUseCase';
|
||||
import type { JoinLeagueOutputDTO } from '../dtos/JoinLeagueOutputDTO';
|
||||
|
||||
export class JoinLeaguePresenter {
|
||||
export class JoinLeaguePresenter implements UseCaseOutputPort<JoinLeagueResult> {
|
||||
private result: JoinLeagueOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: JoinLeagueOutputPort) {
|
||||
present(result: JoinLeagueResult): void {
|
||||
this.result = {
|
||||
success: true,
|
||||
membershipId: output.membershipId,
|
||||
membershipId: result.membership.id.toString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { LeagueAdminDTO } from '../dtos/LeagueAdminDTO';
|
||||
import { LeagueJoinRequestDTO } from '../dtos/LeagueJoinRequestDTO';
|
||||
import { LeagueOwnerSummaryDTO } from '../dtos/LeagueOwnerSummaryDTO';
|
||||
import { LeagueConfigFormModelDTO } from '../dtos/LeagueConfigFormModelDTO';
|
||||
import { LeagueAdminProtestsDTO } from '../dtos/LeagueAdminProtestsDTO';
|
||||
import { LeagueSeasonSummaryDTO } from '../dtos/LeagueSeasonSummaryDTO';
|
||||
|
||||
export class LeagueAdminPresenter {
|
||||
private result: LeagueAdminDTO | null = null;
|
||||
@@ -15,11 +20,11 @@ export class LeagueAdminPresenter {
|
||||
seasons: unknown[];
|
||||
}) {
|
||||
this.result = {
|
||||
joinRequests: data.joinRequests,
|
||||
ownerSummary: data.ownerSummary,
|
||||
config: { form: data.config },
|
||||
protests: data.protests,
|
||||
seasons: data.seasons,
|
||||
joinRequests: data.joinRequests as LeagueJoinRequestDTO[],
|
||||
ownerSummary: data.ownerSummary as LeagueOwnerSummaryDTO | null,
|
||||
config: { form: data.config as LeagueConfigFormModelDTO | null },
|
||||
protests: data.protests as LeagueAdminProtestsDTO,
|
||||
seasons: data.seasons as LeagueSeasonSummaryDTO[],
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { LeagueConfigPresenter } from './LeagueConfigPresenter';
|
||||
import type { LeagueFullConfigOutputPort } from '@core/racing/application/ports/output/LeagueFullConfigOutputPort';
|
||||
|
||||
describe('LeagueConfigPresenter', () => {
|
||||
const createFullConfig = (overrides: Partial<LeagueFullConfigOutputPort> = {}): LeagueFullConfigOutputPort => {
|
||||
const base: LeagueFullConfigOutputPort = {
|
||||
const createFullConfig = (overrides: Partial<any> = {}): any => {
|
||||
const base: any = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
league: {
|
||||
id: 'league-1',
|
||||
@@ -65,8 +65,8 @@ describe('LeagueConfigPresenter', () => {
|
||||
const presenter = new LeagueConfigPresenter();
|
||||
const fullConfig = createFullConfig();
|
||||
|
||||
presenter.present(fullConfig);
|
||||
const vm = presenter.getViewModel();
|
||||
presenter.present({ config: fullConfig });
|
||||
const vm = presenter.getViewModel()!;
|
||||
|
||||
expect(vm).not.toBeNull();
|
||||
expect(vm!.leagueId).toBe('league-1');
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import { LeagueFullConfigOutputPort } from '@core/racing/application/ports/output/LeagueFullConfigOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetLeagueFullConfigResult } from '@core/racing/application/use-cases/GetLeagueFullConfigUseCase';
|
||||
import { LeagueConfigFormModelDTO } from '../dtos/LeagueConfigFormModelDTO';
|
||||
import type { Presenter } from '@core/shared/presentation';
|
||||
|
||||
export class LeagueConfigPresenter implements Presenter<LeagueFullConfigOutputPort, LeagueConfigFormModelDTO> {
|
||||
export class LeagueConfigPresenter implements UseCaseOutputPort<GetLeagueFullConfigResult> {
|
||||
private result: LeagueConfigFormModelDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(dto: LeagueFullConfigOutputPort) {
|
||||
present(result: GetLeagueFullConfigResult): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const dto = result.config as any;
|
||||
const league = dto.league;
|
||||
const settings = league.settings;
|
||||
const stewarding = dto.activeSeason?.stewardingConfig;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { LeagueJoinRequestsPresenter } from './LeagueJoinRequestsPresenter';
|
||||
import type { GetLeagueJoinRequestsOutputPort } from '@core/racing/application/ports/output/GetLeagueJoinRequestsOutputPort';
|
||||
import type { GetLeagueJoinRequestsResult } from '@core/racing/application/use-cases/GetLeagueJoinRequestsUseCase';
|
||||
|
||||
describe('LeagueJoinRequestsPresenter', () => {
|
||||
it('presents join requests correctly', () => {
|
||||
const presenter = new LeagueJoinRequestsPresenter();
|
||||
const output: GetLeagueJoinRequestsOutputPort = {
|
||||
const output: GetLeagueJoinRequestsResult = {
|
||||
joinRequests: [
|
||||
{
|
||||
id: 'req-1',
|
||||
@@ -12,17 +12,18 @@ describe('LeagueJoinRequestsPresenter', () => {
|
||||
driverId: 'driver-1',
|
||||
requestedAt: new Date('2023-01-01'),
|
||||
message: 'Please accept me',
|
||||
driver: { id: 'driver-1', name: 'John Doe' },
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
driver: { id: 'driver-1', name: 'John Doe' } as any,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
presenter.present(output);
|
||||
const vm = presenter.getViewModel();
|
||||
const vm = presenter.getViewModel()!;
|
||||
|
||||
expect(vm).not.toBeNull();
|
||||
expect(vm!.joinRequests).toHaveLength(1);
|
||||
expect(vm!.joinRequests[0].id).toBe('req-1');
|
||||
expect(vm!.joinRequests[0].driver.name).toBe('John Doe');
|
||||
expect(vm.joinRequests).toHaveLength(1);
|
||||
expect(vm.joinRequests[0]!.id).toBe('req-1');
|
||||
expect(vm.joinRequests[0]!.driver.name).toBe('John Doe');
|
||||
});
|
||||
});
|
||||
@@ -1,25 +1,29 @@
|
||||
import type { GetLeagueJoinRequestsOutputPort } from '@core/racing/application/ports/output/GetLeagueJoinRequestsOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import { GetLeagueJoinRequestsResult } from '@core/racing/application/use-cases/GetLeagueJoinRequestsUseCase';
|
||||
import { LeagueJoinRequestWithDriverDTO } from '../dtos/LeagueJoinRequestWithDriverDTO';
|
||||
|
||||
export interface LeagueJoinRequestsViewModel {
|
||||
joinRequests: LeagueJoinRequestWithDriverDTO[];
|
||||
}
|
||||
|
||||
export class LeagueJoinRequestsPresenter {
|
||||
export class LeagueJoinRequestsPresenter implements UseCaseOutputPort<GetLeagueJoinRequestsResult> {
|
||||
private result: LeagueJoinRequestsViewModel | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetLeagueJoinRequestsOutputPort) {
|
||||
const joinRequests: LeagueJoinRequestWithDriverDTO[] = output.joinRequests.map(request => ({
|
||||
id: request.id,
|
||||
leagueId: request.leagueId,
|
||||
driverId: request.driverId,
|
||||
requestedAt: request.requestedAt,
|
||||
message: request.message,
|
||||
driver: request.driver,
|
||||
present(result: GetLeagueJoinRequestsResult) {
|
||||
const joinRequests: LeagueJoinRequestWithDriverDTO[] = result.joinRequests.map(item => ({
|
||||
id: item.id,
|
||||
leagueId: item.leagueId,
|
||||
driverId: item.driverId,
|
||||
requestedAt: item.requestedAt,
|
||||
...(item.message ? { message: item.message } : {}),
|
||||
driver: {
|
||||
id: item.driver.id,
|
||||
name: item.driver.name.toString(),
|
||||
},
|
||||
}));
|
||||
this.result = {
|
||||
joinRequests,
|
||||
|
||||
@@ -1,42 +1,33 @@
|
||||
import { LeagueOwnerSummaryPresenter } from './LeagueOwnerSummaryPresenter';
|
||||
import type { GetLeagueOwnerSummaryOutputPort } from '@core/racing/application/ports/output/GetLeagueOwnerSummaryOutputPort';
|
||||
import type { GetLeagueOwnerSummaryResult } from '@core/racing/application/use-cases/GetLeagueOwnerSummaryUseCase';
|
||||
|
||||
describe('LeagueOwnerSummaryPresenter', () => {
|
||||
it('presents owner summary correctly', () => {
|
||||
const presenter = new LeagueOwnerSummaryPresenter();
|
||||
const output: GetLeagueOwnerSummaryOutputPort = {
|
||||
summary: {
|
||||
driver: {
|
||||
id: 'driver-1',
|
||||
iracingId: '12345',
|
||||
name: 'John Doe',
|
||||
country: 'US',
|
||||
bio: 'Racing enthusiast',
|
||||
joinedAt: '2023-01-01',
|
||||
},
|
||||
rating: 1500,
|
||||
rank: 100,
|
||||
},
|
||||
const output: GetLeagueOwnerSummaryResult = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
league: {} as any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
owner: {
|
||||
id: 'driver-1',
|
||||
iracingId: '12345',
|
||||
name: 'John Doe',
|
||||
country: 'US',
|
||||
bio: 'Racing enthusiast',
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
joinedAt: {} as any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} as any,
|
||||
rating: 1500,
|
||||
rank: 100,
|
||||
};
|
||||
|
||||
presenter.present(output);
|
||||
const vm = presenter.getViewModel();
|
||||
const vm = presenter.getViewModel()!;
|
||||
|
||||
expect(vm).not.toBeNull();
|
||||
expect(vm!.driver.id).toBe('driver-1');
|
||||
expect(vm!.rating).toBe(1500);
|
||||
expect(vm!.rank).toBe(100);
|
||||
});
|
||||
|
||||
it('handles null summary', () => {
|
||||
const presenter = new LeagueOwnerSummaryPresenter();
|
||||
const output: GetLeagueOwnerSummaryOutputPort = {
|
||||
summary: null,
|
||||
};
|
||||
|
||||
presenter.present(output);
|
||||
const vm = presenter.getViewModel();
|
||||
|
||||
expect(vm).toBeNull();
|
||||
expect(vm.driver.id).toBe('driver-1');
|
||||
expect(vm.rating).toBe(1500);
|
||||
expect(vm.rank).toBe(100);
|
||||
});
|
||||
});
|
||||
@@ -1,29 +1,26 @@
|
||||
import type { GetLeagueOwnerSummaryOutputPort } from '@core/racing/application/ports/output/GetLeagueOwnerSummaryOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import { GetLeagueOwnerSummaryResult } from '@core/racing/application/use-cases/GetLeagueOwnerSummaryUseCase';
|
||||
import { LeagueOwnerSummaryDTO } from '../dtos/LeagueOwnerSummaryDTO';
|
||||
|
||||
export class LeagueOwnerSummaryPresenter {
|
||||
export class LeagueOwnerSummaryPresenter implements UseCaseOutputPort<GetLeagueOwnerSummaryResult> {
|
||||
private result: LeagueOwnerSummaryDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetLeagueOwnerSummaryOutputPort) {
|
||||
if (!output.summary) {
|
||||
this.result = null;
|
||||
return;
|
||||
}
|
||||
present(result: GetLeagueOwnerSummaryResult) {
|
||||
this.result = {
|
||||
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,
|
||||
id: result.owner.id,
|
||||
iracingId: result.owner.iracingId.toString(),
|
||||
name: result.owner.name.toString(),
|
||||
country: result.owner.country.toString(),
|
||||
joinedAt: result.owner.joinedAt.toDate().toISOString(),
|
||||
...(result.owner.bio ? { bio: result.owner.bio.toString() } : {}),
|
||||
},
|
||||
rating: output.summary.rating,
|
||||
rank: output.summary.rank,
|
||||
rating: result.rating,
|
||||
rank: result.rank,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
import { GetLeagueScheduleOutputPort } from '@core/racing/application/ports/output/GetLeagueScheduleOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
import { GetLeagueScheduleResult } from '@core/racing/application/use-cases/GetLeagueScheduleUseCase';
|
||||
import { LeagueScheduleDTO } from '../dtos/LeagueScheduleDTO';
|
||||
import { RaceDTO } from '../../race/dtos/RaceDTO';
|
||||
|
||||
export class LeagueSchedulePresenter {
|
||||
export class LeagueSchedulePresenter implements UseCaseOutputPort<GetLeagueScheduleResult> {
|
||||
private result: LeagueScheduleDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetLeagueScheduleOutputPort, leagueName?: string) {
|
||||
present(result: GetLeagueScheduleResult, leagueName?: string) {
|
||||
this.result = {
|
||||
races: output.races.map<RaceDTO>(race => ({
|
||||
id: race.id,
|
||||
name: race.name,
|
||||
date: race.scheduledAt.toISOString(),
|
||||
leagueName,
|
||||
races: result.races.map(race => ({
|
||||
id: race.race.id,
|
||||
name: `${race.race.track} - ${race.race.car}`,
|
||||
date: race.race.scheduledAt.toISOString(),
|
||||
...(leagueName ? { leagueName } : {}),
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -25,19 +26,19 @@ export class LeagueSchedulePresenter {
|
||||
}
|
||||
}
|
||||
|
||||
export class LeagueRacesPresenter {
|
||||
export class LeagueRacesPresenter implements UseCaseOutputPort<GetLeagueScheduleResult> {
|
||||
private result: RaceDTO[] | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetLeagueScheduleOutputPort, leagueName?: string) {
|
||||
this.result = output.races.map<RaceDTO>(race => ({
|
||||
id: race.id,
|
||||
name: race.name,
|
||||
date: race.scheduledAt.toISOString(),
|
||||
leagueName,
|
||||
present(result: GetLeagueScheduleResult, leagueName?: string) {
|
||||
this.result = result.races.map(race => ({
|
||||
id: race.race.id,
|
||||
name: `${race.race.track} - ${race.race.car}`,
|
||||
date: race.race.scheduledAt.toISOString(),
|
||||
...(leagueName ? { leagueName } : {}),
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetLeagueScoringConfigResult } from '@core/racing/application/use-cases/GetLeagueScoringConfigUseCase';
|
||||
import type { ChampionshipConfig } from '@core/racing/domain/types/ChampionshipConfig';
|
||||
import type { BonusRule } from '@core/racing/domain/types/BonusRule';
|
||||
import type { LeagueScoringConfigOutputPort } from '@core/racing/application/ports/output/LeagueScoringConfigOutputPort';
|
||||
import type { LeagueScoringPresetOutputPort } from '@core/racing/application/ports/output/LeagueScoringPresetOutputPort';
|
||||
|
||||
export interface LeagueScoringChampionshipViewModel {
|
||||
id: string;
|
||||
@@ -24,33 +24,31 @@ export interface LeagueScoringConfigViewModel {
|
||||
championships: LeagueScoringChampionshipViewModel[];
|
||||
}
|
||||
|
||||
export class LeagueScoringConfigPresenter {
|
||||
export class LeagueScoringConfigPresenter implements UseCaseOutputPort<GetLeagueScoringConfigResult> {
|
||||
private viewModel: LeagueScoringConfigViewModel | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.viewModel = null;
|
||||
}
|
||||
|
||||
present(data: LeagueScoringConfigOutputPort): LeagueScoringConfigViewModel {
|
||||
present(result: GetLeagueScoringConfigResult): void {
|
||||
const championships: LeagueScoringChampionshipViewModel[] =
|
||||
data.championships.map((champ) => this.mapChampionship(champ));
|
||||
result.scoringConfig.championships.map((champ) => this.mapChampionship(champ));
|
||||
|
||||
const dropPolicySummary =
|
||||
data.preset?.dropPolicySummary ??
|
||||
this.deriveDropPolicyDescriptionFromChampionships(data.championships);
|
||||
result.preset?.dropPolicySummary ??
|
||||
this.deriveDropPolicyDescriptionFromChampionships(result.scoringConfig.championships);
|
||||
|
||||
this.viewModel = {
|
||||
leagueId: data.leagueId,
|
||||
seasonId: data.seasonId,
|
||||
gameId: data.gameId,
|
||||
gameName: data.gameName,
|
||||
scoringPresetId: data.scoringPresetId ?? 'custom',
|
||||
scoringPresetName: data.preset?.name ?? 'Custom',
|
||||
leagueId: result.league.id.toString(),
|
||||
seasonId: result.season.id,
|
||||
gameId: result.game.id.toString(),
|
||||
gameName: result.game.name.toString(),
|
||||
scoringPresetId: result.scoringConfig.scoringPresetId?.toString() ?? 'custom',
|
||||
scoringPresetName: result.preset?.name ?? 'Custom',
|
||||
dropPolicySummary,
|
||||
championships,
|
||||
};
|
||||
|
||||
return this.viewModel;
|
||||
}
|
||||
|
||||
getViewModel(): LeagueScoringConfigViewModel | null {
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import type { LeagueScoringPresetsOutputPort } from '@core/racing/application/ports/output/LeagueScoringPresetsOutputPort';
|
||||
import type { LeagueScoringPresetOutputPort } from '@core/racing/application/ports/output/LeagueScoringPresetOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { ListLeagueScoringPresetsResult, LeagueScoringPreset } from '@core/racing/application/use-cases/ListLeagueScoringPresetsUseCase';
|
||||
|
||||
export interface LeagueScoringPresetsViewModel {
|
||||
presets: LeagueScoringPresetOutputPort[];
|
||||
presets: LeagueScoringPreset[];
|
||||
totalCount: number;
|
||||
}
|
||||
|
||||
export class LeagueScoringPresetsPresenter {
|
||||
export class LeagueScoringPresetsPresenter implements UseCaseOutputPort<ListLeagueScoringPresetsResult> {
|
||||
private viewModel: LeagueScoringPresetsViewModel | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.viewModel = null;
|
||||
}
|
||||
|
||||
present(output: LeagueScoringPresetsOutputPort): void {
|
||||
present(result: ListLeagueScoringPresetsResult): void {
|
||||
this.viewModel = {
|
||||
presets: output.presets,
|
||||
totalCount: output.presets.length,
|
||||
presets: result.presets,
|
||||
totalCount: result.presets.length,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import { LeagueStandingsOutputPort } from '@core/racing/application/ports/output/LeagueStandingsOutputPort';
|
||||
import type { GetLeagueStandingsResult } from '@core/racing/application/use-cases/GetLeagueStandingsUseCase';
|
||||
import { LeagueStandingsDTO } from '../dtos/LeagueStandingsDTO';
|
||||
import type { Presenter } from '@core/shared/presentation';
|
||||
|
||||
export class LeagueStandingsPresenter implements Presenter<LeagueStandingsOutputPort, LeagueStandingsDTO> {
|
||||
export class LeagueStandingsPresenter implements Presenter<GetLeagueStandingsResult, LeagueStandingsDTO> {
|
||||
private result: LeagueStandingsDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(dto: LeagueStandingsOutputPort) {
|
||||
present(dto: GetLeagueStandingsResult) {
|
||||
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
|
||||
iracingId: standing.driver.iracingId.toString(),
|
||||
name: standing.driver.name.toString(),
|
||||
country: standing.driver.country.toString(),
|
||||
...(standing.driver.bio ? { bio: standing.driver.bio.toString() } : {}),
|
||||
joinedAt: standing.driver.joinedAt.toString(),
|
||||
},
|
||||
points: standing.points,
|
||||
rank: standing.rank,
|
||||
@@ -23,7 +26,7 @@ export class LeagueStandingsPresenter implements Presenter<LeagueStandingsOutput
|
||||
this.result = { standings };
|
||||
}
|
||||
|
||||
getViewModel(): LeagueStandingsDTO {
|
||||
getResponseModel(): LeagueStandingsDTO {
|
||||
if (!this.result) throw new Error('Presenter not presented');
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import { LeagueStatsOutputPort } from '@core/racing/application/ports/output/LeagueStatsOutputPort';
|
||||
import type { GetLeagueStatsResult } from '@core/racing/application/use-cases/GetLeagueStatsUseCase';
|
||||
import { LeagueStatsDTO } from '../dtos/LeagueStatsDTO';
|
||||
import type { Presenter } from '@core/shared/presentation';
|
||||
|
||||
export class LeagueStatsPresenter implements Presenter<LeagueStatsOutputPort, LeagueStatsDTO> {
|
||||
export class LeagueStatsPresenter implements Presenter<GetLeagueStatsResult, LeagueStatsDTO> {
|
||||
private result: LeagueStatsDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(dto: LeagueStatsOutputPort) {
|
||||
this.result = dto;
|
||||
present(dto: GetLeagueStatsResult) {
|
||||
this.result = {
|
||||
totalMembers: dto.driverCount,
|
||||
totalRaces: dto.raceCount,
|
||||
averageRating: dto.averageRating,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): LeagueStatsDTO | null {
|
||||
getResponseModel(): LeagueStatsDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,18 @@
|
||||
import type { RejectLeagueJoinRequestOutputPort } from '@core/racing/application/ports/output/RejectLeagueJoinRequestOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { RejectLeagueJoinRequestResult } from '@core/racing/application/use-cases/RejectLeagueJoinRequestUseCase';
|
||||
import type { RejectJoinRequestOutputDTO } from '../dtos/RejectJoinRequestOutputDTO';
|
||||
|
||||
export class RejectLeagueJoinRequestPresenter {
|
||||
export class RejectLeagueJoinRequestPresenter implements UseCaseOutputPort<RejectLeagueJoinRequestResult> {
|
||||
private result: RejectJoinRequestOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: RejectLeagueJoinRequestOutputPort) {
|
||||
present(_result: RejectLeagueJoinRequestResult): void {
|
||||
this.result = {
|
||||
success: output.success,
|
||||
message: output.message,
|
||||
success: true,
|
||||
message: 'Join request rejected successfully',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import type { RemoveLeagueMemberOutputPort } from '@core/racing/application/ports/output/RemoveLeagueMemberOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { RemoveLeagueMemberResult } from '@core/racing/application/use-cases/RemoveLeagueMemberUseCase';
|
||||
import type { RemoveLeagueMemberOutputDTO } from '../dtos/RemoveLeagueMemberOutputDTO';
|
||||
|
||||
export class RemoveLeagueMemberPresenter {
|
||||
export class RemoveLeagueMemberPresenter implements UseCaseOutputPort<RemoveLeagueMemberResult> {
|
||||
private result: RemoveLeagueMemberOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: RemoveLeagueMemberOutputPort) {
|
||||
present(_result: RemoveLeagueMemberResult): void {
|
||||
this.result = {
|
||||
success: output.success,
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { GetTotalLeaguesOutputPort } from '@core/racing/application/ports/output/GetTotalLeaguesOutputPort';
|
||||
import type { GetTotalLeaguesResult } from '@core/racing/application/use-cases/GetTotalLeaguesUseCase';
|
||||
import { TotalLeaguesDTO } from '../dtos/TotalLeaguesDTO';
|
||||
|
||||
export class TotalLeaguesPresenter {
|
||||
@@ -8,13 +8,13 @@ export class TotalLeaguesPresenter {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: GetTotalLeaguesOutputPort) {
|
||||
present(output: GetTotalLeaguesResult) {
|
||||
this.result = {
|
||||
totalLeagues: output.totalLeagues,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): TotalLeaguesDTO | null {
|
||||
getResponseModel(): TotalLeaguesDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
import type { TransferLeagueOwnershipOutputPort } from '@core/racing/application/ports/output/TransferLeagueOwnershipOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { TransferLeagueOwnershipResult } from '@core/racing/application/use-cases/TransferLeagueOwnershipUseCase';
|
||||
import type { TransferLeagueOwnershipOutputDTO } from '../dtos/TransferLeagueOwnershipOutputDTO';
|
||||
|
||||
export class TransferLeagueOwnershipPresenter {
|
||||
export class TransferLeagueOwnershipPresenter implements UseCaseOutputPort<TransferLeagueOwnershipResult> {
|
||||
private result: TransferLeagueOwnershipOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: TransferLeagueOwnershipOutputPort) {
|
||||
present(_result: TransferLeagueOwnershipResult): void {
|
||||
this.result = {
|
||||
success: output.success,
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import type { UpdateLeagueMemberRoleOutputPort } from '@core/racing/application/ports/output/UpdateLeagueMemberRoleOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { UpdateLeagueMemberRoleResult } from '@core/racing/application/use-cases/UpdateLeagueMemberRoleUseCase';
|
||||
import type { UpdateLeagueMemberRoleOutputDTO } from '../dtos/UpdateLeagueMemberRoleOutputDTO';
|
||||
|
||||
export class UpdateLeagueMemberRolePresenter {
|
||||
export class UpdateLeagueMemberRolePresenter implements UseCaseOutputPort<UpdateLeagueMemberRoleResult> {
|
||||
private result: UpdateLeagueMemberRoleOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(output: UpdateLeagueMemberRoleOutputPort) {
|
||||
present(_result: UpdateLeagueMemberRoleResult): void {
|
||||
this.result = {
|
||||
success: output.success,
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user