refactor driver module (wip)
This commit is contained in:
@@ -2,15 +2,17 @@ import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { TeamService } from './TeamService';
|
||||
import { GetAllTeamsUseCase } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { AllTeamsPresenter } from './presenters/AllTeamsPresenter';
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { DriverTeamPresenter } from './presenters/DriverTeamPresenter';
|
||||
import { DriverTeamViewModel } from './dtos/TeamDto';
|
||||
|
||||
describe('TeamService', () => {
|
||||
let service: TeamService;
|
||||
let getAllTeamsUseCase: jest.Mocked<GetAllTeamsUseCase>;
|
||||
let getDriverTeamUseCase: jest.Mocked<GetDriverTeamUseCase>;
|
||||
let logger: jest.Mocked<Logger>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const mockGetAllTeamsUseCase = {
|
||||
@@ -46,7 +48,6 @@ describe('TeamService', () => {
|
||||
service = module.get<TeamService>(TeamService);
|
||||
getAllTeamsUseCase = module.get(GetAllTeamsUseCase);
|
||||
getDriverTeamUseCase = module.get(GetDriverTeamUseCase);
|
||||
logger = module.get('Logger');
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
@@ -56,12 +57,14 @@ describe('TeamService', () => {
|
||||
describe('getAll', () => {
|
||||
it('should call use case and return result', async () => {
|
||||
const mockResult = { isOk: () => true, value: { teams: [], totalCount: 0 } };
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getAllTeamsUseCase.execute.mockResolvedValue(mockResult as any);
|
||||
|
||||
const mockPresenter = {
|
||||
present: jest.fn(),
|
||||
getViewModel: jest.fn().mockReturnValue({ teams: [], totalCount: 0 }),
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(AllTeamsPresenter as any) = jest.fn().mockImplementation(() => mockPresenter);
|
||||
|
||||
const result = await service.getAll();
|
||||
@@ -74,12 +77,14 @@ describe('TeamService', () => {
|
||||
describe('getDriverTeam', () => {
|
||||
it('should call use case and return result', async () => {
|
||||
const mockResult = { isOk: () => true, value: {} };
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getDriverTeamUseCase.execute.mockResolvedValue(mockResult as any);
|
||||
|
||||
const mockPresenter = {
|
||||
present: jest.fn(),
|
||||
getViewModel: jest.fn().mockReturnValue({} as DriverTeamViewModel),
|
||||
};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(DriverTeamPresenter as any) = jest.fn().mockImplementation(() => mockPresenter);
|
||||
|
||||
const result = await service.getDriverTeam('driver1');
|
||||
@@ -90,6 +95,7 @@ describe('TeamService', () => {
|
||||
|
||||
it('should return null on error', async () => {
|
||||
const mockResult = { isErr: () => true, error: {} };
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getDriverTeamUseCase.execute.mockResolvedValue(mockResult as any);
|
||||
|
||||
const result = await service.getDriverTeam('driver1');
|
||||
|
||||
@@ -12,14 +12,18 @@ import { GetTeamMembershipOutputDTO } from './dtos/GetTeamMembershipOutputDTO';
|
||||
|
||||
// Core imports
|
||||
import type { Logger } from '@core/shared/application/Logger';
|
||||
import type { ITeamRepository } from '@core/racing/domain/repositories/ITeamRepository';
|
||||
import type { ITeamMembershipRepository } from '@core/racing/domain/repositories/ITeamMembershipRepository';
|
||||
import type { IDriverRepository } from '@core/racing/domain/repositories/IDriverRepository';
|
||||
import type { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
|
||||
|
||||
// Use cases
|
||||
import { GetAllTeamsUseCase } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { GetTeamDetailsUseCase } from '@core/racing/application/use-cases/GetTeamDetailsUseCase';
|
||||
import { GetTeamMembersUseCase } from '@core/racing/application/use-cases/GetTeamMembersUseCase';
|
||||
import { GetTeamJoinRequestsUseCase } from '@core/racing/application/use-cases/GetTeamJoinRequestsUseCase';
|
||||
import { CreateTeamUseCase } from '@core/racing/application/use-cases/CreateTeamUseCase';
|
||||
import { UpdateTeamUseCase } from '@core/racing/application/use-cases/UpdateTeamUseCase';
|
||||
import { CreateTeamUseCase, CreateTeamInput } from '@core/racing/application/use-cases/CreateTeamUseCase';
|
||||
import { UpdateTeamUseCase, UpdateTeamInput } from '@core/racing/application/use-cases/UpdateTeamUseCase';
|
||||
import { GetDriverTeamUseCase } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
|
||||
import { GetTeamMembershipUseCase } from '@core/racing/application/use-cases/GetTeamMembershipUseCase';
|
||||
|
||||
@@ -34,97 +38,90 @@ import { CreateTeamPresenter } from './presenters/CreateTeamPresenter';
|
||||
import { UpdateTeamPresenter } from './presenters/UpdateTeamPresenter';
|
||||
|
||||
// Tokens
|
||||
import { LOGGER_TOKEN } from './TeamProviders';
|
||||
import { TEAM_REPOSITORY_TOKEN, TEAM_MEMBERSHIP_REPOSITORY_TOKEN, DRIVER_REPOSITORY_TOKEN, IMAGE_SERVICE_TOKEN, LOGGER_TOKEN } from './TeamProviders';
|
||||
|
||||
@Injectable()
|
||||
export class TeamService {
|
||||
constructor(
|
||||
private readonly getAllTeamsUseCase: GetAllTeamsUseCase,
|
||||
private readonly getTeamDetailsUseCase: GetTeamDetailsUseCase,
|
||||
private readonly getTeamMembersUseCase: GetTeamMembersUseCase,
|
||||
private readonly getTeamJoinRequestsUseCase: GetTeamJoinRequestsUseCase,
|
||||
private readonly createTeamUseCase: CreateTeamUseCase,
|
||||
private readonly updateTeamUseCase: UpdateTeamUseCase,
|
||||
private readonly getDriverTeamUseCase: GetDriverTeamUseCase,
|
||||
private readonly getTeamMembershipUseCase: GetTeamMembershipUseCase,
|
||||
@Inject(TEAM_REPOSITORY_TOKEN) private readonly teamRepository: ITeamRepository,
|
||||
@Inject(TEAM_MEMBERSHIP_REPOSITORY_TOKEN) private readonly membershipRepository: ITeamMembershipRepository,
|
||||
@Inject(DRIVER_REPOSITORY_TOKEN) private readonly driverRepository: IDriverRepository,
|
||||
@Inject(IMAGE_SERVICE_TOKEN) private readonly imageService: IImageServicePort,
|
||||
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
||||
) {}
|
||||
|
||||
async getAll(): Promise<any> { // TODO: type
|
||||
async getAll(): Promise<GetAllTeamsOutputDTO> {
|
||||
this.logger.debug('[TeamService] Fetching all teams.');
|
||||
|
||||
const result = await this.getAllTeamsUseCase.execute();
|
||||
const presenter = new AllTeamsPresenter();
|
||||
const useCase = new GetAllTeamsUseCase(this.teamRepository, this.membershipRepository, this.logger, presenter);
|
||||
const result = await useCase.execute();
|
||||
if (result.isErr()) {
|
||||
this.logger.error('Error fetching all teams', result.error);
|
||||
await presenter.present({ teams: [], totalCount: 0 });
|
||||
return presenter.responseModel;
|
||||
this.logger.error('Error fetching all teams', result.error?.details?.message || 'Unknown error');
|
||||
return { teams: [], totalCount: 0 };
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter.responseModel;
|
||||
}
|
||||
|
||||
async getDetails(teamId: string, userId?: string): Promise<TeamDetailsPresenter> {
|
||||
async getDetails(teamId: string, userId?: string): Promise<GetTeamDetailsOutputDTO | null> {
|
||||
this.logger.debug(`[TeamService] Fetching team details for teamId: ${teamId}, userId: ${userId}`);
|
||||
|
||||
const presenter = new TeamDetailsPresenter();
|
||||
const result = await this.getTeamDetailsUseCase.execute({ teamId, driverId: userId || '' });
|
||||
const useCase = new GetTeamDetailsUseCase(this.teamRepository, this.membershipRepository, presenter);
|
||||
const result = await useCase.execute({ teamId, driverId: userId || '' });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching team details for teamId: ${teamId}`, result.error);
|
||||
return presenter;
|
||||
this.logger.error(`Error fetching team details for teamId: ${teamId}: ${result.error?.details?.message || 'Unknown error'}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter;
|
||||
return presenter.getResponseModel();
|
||||
}
|
||||
|
||||
async getMembers(teamId: string): Promise<TeamMembersPresenter> {
|
||||
async getMembers(teamId: string): Promise<GetTeamMembersOutputDTO> {
|
||||
this.logger.debug(`[TeamService] Fetching team members for teamId: ${teamId}`);
|
||||
|
||||
const presenter = new TeamMembersPresenter();
|
||||
const result = await this.getTeamMembersUseCase.execute({ teamId });
|
||||
const useCase = new GetTeamMembersUseCase(this.membershipRepository, this.driverRepository, this.imageService, this.logger, presenter);
|
||||
const result = await useCase.execute({ teamId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching team members for teamId: ${teamId}`, result.error);
|
||||
await presenter.present({
|
||||
this.logger.error(`Error fetching team members for teamId: ${teamId}: ${result.error?.details?.message || 'Unknown error'}`);
|
||||
return {
|
||||
members: [],
|
||||
totalCount: 0,
|
||||
ownerCount: 0,
|
||||
managerCount: 0,
|
||||
memberCount: 0,
|
||||
} as unknown as any);
|
||||
return presenter;
|
||||
};
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter;
|
||||
return presenter.getResponseModel()!;
|
||||
}
|
||||
|
||||
async getJoinRequests(teamId: string): Promise<TeamJoinRequestsPresenter> {
|
||||
async getJoinRequests(teamId: string): Promise<GetTeamJoinRequestsOutputDTO> {
|
||||
this.logger.debug(`[TeamService] Fetching team join requests for teamId: ${teamId}`);
|
||||
|
||||
const presenter = new TeamJoinRequestsPresenter();
|
||||
const result = await this.getTeamJoinRequestsUseCase.execute({ teamId });
|
||||
const useCase = new GetTeamJoinRequestsUseCase(this.membershipRepository, this.driverRepository, this.teamRepository, presenter);
|
||||
const result = await useCase.execute({ teamId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching team join requests for teamId: ${teamId}`, result.error);
|
||||
await presenter.present({
|
||||
this.logger.error(new Error(`Error fetching team join requests for teamId: ${teamId}: ${result.error?.details?.message || 'Unknown error'}`));
|
||||
return {
|
||||
requests: [],
|
||||
pendingCount: 0,
|
||||
totalCount: 0,
|
||||
} as unknown as any);
|
||||
return presenter;
|
||||
};
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter;
|
||||
return presenter.getResponseModel()!;
|
||||
}
|
||||
|
||||
async create(input: CreateTeamInputDTO, userId?: string): Promise<CreateTeamPresenter> {
|
||||
async create(input: CreateTeamInputDTO, userId?: string): Promise<CreateTeamOutputDTO> {
|
||||
this.logger.debug('[TeamService] Creating team', { input, userId });
|
||||
|
||||
const presenter = new CreateTeamPresenter();
|
||||
|
||||
const command = {
|
||||
const command: CreateTeamInput = {
|
||||
name: input.name,
|
||||
tag: input.tag,
|
||||
description: input.description ?? '',
|
||||
@@ -132,68 +129,66 @@ export class TeamService {
|
||||
leagues: [],
|
||||
};
|
||||
|
||||
const result = await this.createTeamUseCase.execute(command as any);
|
||||
const useCase = new CreateTeamUseCase(this.teamRepository, this.membershipRepository, this.logger, presenter);
|
||||
const result = await useCase.execute(command);
|
||||
if (result.isErr()) {
|
||||
this.logger.error('Error creating team', result.error);
|
||||
presenter.presentError();
|
||||
return presenter;
|
||||
this.logger.error(`Error creating team: ${result.error?.details?.message || 'Unknown error'}`);
|
||||
return { id: '', success: false };
|
||||
}
|
||||
|
||||
presenter.presentSuccess(result.value);
|
||||
return presenter;
|
||||
return presenter.responseModel;
|
||||
}
|
||||
|
||||
async update(teamId: string, input: UpdateTeamInputDTO, userId?: string): Promise<UpdateTeamPresenter> {
|
||||
async update(teamId: string, input: UpdateTeamInputDTO, userId?: string): Promise<UpdateTeamOutputDTO> {
|
||||
this.logger.debug(`[TeamService] Updating team ${teamId}`, { input, userId });
|
||||
|
||||
const presenter = new UpdateTeamPresenter();
|
||||
|
||||
const command = {
|
||||
const command: UpdateTeamInput = {
|
||||
teamId,
|
||||
updates: {
|
||||
name: input.name,
|
||||
tag: input.tag,
|
||||
description: input.description,
|
||||
...(input.name !== undefined && { name: input.name }),
|
||||
...(input.tag !== undefined && { tag: input.tag }),
|
||||
...(input.description !== undefined && { description: input.description }),
|
||||
},
|
||||
updatedBy: userId || '',
|
||||
};
|
||||
|
||||
const result = await this.updateTeamUseCase.execute(command as any);
|
||||
const useCase = new UpdateTeamUseCase(this.teamRepository, this.membershipRepository, presenter);
|
||||
const result = await useCase.execute(command);
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error updating team ${teamId}`, result.error);
|
||||
presenter.presentError();
|
||||
return presenter;
|
||||
this.logger.error(`Error updating team ${teamId}: ${result.error?.details?.message || 'Unknown error'}`);
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
presenter.presentSuccess();
|
||||
return presenter;
|
||||
return presenter.responseModel;
|
||||
}
|
||||
|
||||
async getDriverTeam(driverId: string): Promise<DriverTeamPresenter> {
|
||||
async getDriverTeam(driverId: string): Promise<GetDriverTeamOutputDTO | null> {
|
||||
this.logger.debug(`[TeamService] Fetching driver team for driverId: ${driverId}`);
|
||||
|
||||
const presenter = new DriverTeamPresenter();
|
||||
const result = await this.getDriverTeamUseCase.execute({ driverId });
|
||||
const useCase = new GetDriverTeamUseCase(this.teamRepository, this.membershipRepository, this.logger, presenter);
|
||||
const result = await useCase.execute({ driverId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching driver team for driverId: ${driverId}`, result.error);
|
||||
return presenter;
|
||||
this.logger.error(`Error fetching driver team for driverId: ${driverId}: ${result.error?.details?.message || 'Unknown error'}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
await presenter.present(result.value);
|
||||
return presenter;
|
||||
return presenter.getResponseModel();
|
||||
}
|
||||
|
||||
async getMembership(teamId: string, driverId: string): Promise<TeamMembershipPresenter> {
|
||||
async getMembership(teamId: string, driverId: string): Promise<GetTeamMembershipOutputDTO | null> {
|
||||
this.logger.debug(`[TeamService] Fetching team membership for teamId: ${teamId}, driverId: ${driverId}`);
|
||||
|
||||
const presenter = new TeamMembershipPresenter();
|
||||
const result = await this.getTeamMembershipUseCase.execute({ teamId, driverId });
|
||||
const useCase = new GetTeamMembershipUseCase(this.membershipRepository, this.logger, presenter);
|
||||
const result = await useCase.execute({ teamId, driverId });
|
||||
if (result.isErr()) {
|
||||
this.logger.error(`Error fetching team membership for teamId: ${teamId}, driverId: ${driverId}`, result.error);
|
||||
return presenter;
|
||||
this.logger.error(`Error fetching team membership for teamId: ${teamId}, driverId: ${driverId}: ${result.error?.details?.message || 'Unknown error'}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
presenter.present(result.value as any);
|
||||
return presenter;
|
||||
return presenter.responseModel;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,26 @@
|
||||
import type { GetAllTeamsErrorCode, GetAllTeamsResult } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { Result } from '@core/shared/application/Result';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetAllTeamsResult } from '@core/racing/application/use-cases/GetAllTeamsUseCase';
|
||||
import { GetAllTeamsOutputDTO } from '../dtos/GetAllTeamsOutputDTO';
|
||||
|
||||
export type GetAllTeamsError = ApplicationErrorCode<GetAllTeamsErrorCode, { message: string }>;
|
||||
|
||||
export class AllTeamsPresenter {
|
||||
export class AllTeamsPresenter implements UseCaseOutputPort<GetAllTeamsResult> {
|
||||
private model: GetAllTeamsOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.model = null;
|
||||
}
|
||||
|
||||
present(result: Result<GetAllTeamsResult, GetAllTeamsError>): void {
|
||||
if (result.isErr()) {
|
||||
const error = result.unwrapErr();
|
||||
throw new Error(error.details?.message ?? 'Failed to get teams');
|
||||
}
|
||||
|
||||
const output = result.unwrap();
|
||||
|
||||
present(result: GetAllTeamsResult): void {
|
||||
this.model = {
|
||||
teams: output.teams.map(team => ({
|
||||
teams: result.teams.map(team => ({
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
tag: team.tag,
|
||||
description: team.description,
|
||||
name: team.name.toString(),
|
||||
tag: team.tag.toString(),
|
||||
description: team.description?.toString() || '',
|
||||
memberCount: team.memberCount,
|
||||
leagues: team.leagues || [],
|
||||
leagues: team.leagues?.map(l => l.toString()) || [],
|
||||
// Note: specialization, region, languages not available in output
|
||||
})),
|
||||
totalCount: output.totalCount ?? output.teams.length,
|
||||
totalCount: result.totalCount ?? result.teams.length,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,17 @@
|
||||
import type { Result } from '@core/shared/application/Result';
|
||||
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
|
||||
import type { CreateTeamErrorCode, CreateTeamResult } from '@core/racing/application/use-cases/CreateTeamUseCase';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { CreateTeamResult } from '@core/racing/application/use-cases/CreateTeamUseCase';
|
||||
import type { CreateTeamOutputDTO } from '../dtos/CreateTeamOutputDTO';
|
||||
|
||||
export type CreateTeamError = ApplicationErrorCode<CreateTeamErrorCode, { message: string }>;
|
||||
|
||||
export class CreateTeamPresenter {
|
||||
export class CreateTeamPresenter implements UseCaseOutputPort<CreateTeamResult> {
|
||||
private model: CreateTeamOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.model = null;
|
||||
}
|
||||
|
||||
present(result: Result<CreateTeamResult, CreateTeamError>): void {
|
||||
if (result.isErr()) {
|
||||
const error = result.unwrapErr();
|
||||
// Validation and expected domain errors map to an unsuccessful DTO
|
||||
if (error.code === 'VALIDATION_ERROR' || error.code === 'LEAGUE_NOT_FOUND') {
|
||||
this.model = {
|
||||
id: '',
|
||||
success: false,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(error.details?.message ?? 'Failed to create team');
|
||||
}
|
||||
|
||||
const output = result.unwrap();
|
||||
|
||||
present(result: CreateTeamResult): void {
|
||||
this.model = {
|
||||
id: output.team.id,
|
||||
id: result.team.id,
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,38 +1,39 @@
|
||||
import { DriverTeamOutputPort } from '@core/racing/application/ports/output/DriverTeamOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetDriverTeamResult } from '@core/racing/application/use-cases/GetDriverTeamUseCase';
|
||||
import { GetDriverTeamOutputDTO } from '../dtos/GetDriverTeamOutputDTO';
|
||||
|
||||
export class DriverTeamPresenter {
|
||||
export class DriverTeamPresenter implements UseCaseOutputPort<GetDriverTeamResult> {
|
||||
private result: GetDriverTeamOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
async present(output: DriverTeamOutputPort) {
|
||||
const isOwner = output.team.ownerId === output.driverId;
|
||||
const canManage = isOwner || output.membership.role === 'owner' || output.membership.role === 'manager';
|
||||
present(result: GetDriverTeamResult): void {
|
||||
const isOwner = result.team.ownerId.toString() === result.driverId;
|
||||
const canManage = isOwner || result.membership.role === 'owner' || result.membership.role === 'manager';
|
||||
|
||||
this.result = {
|
||||
team: {
|
||||
id: output.team.id,
|
||||
name: output.team.name,
|
||||
tag: output.team.tag,
|
||||
description: output.team.description || '',
|
||||
ownerId: output.team.ownerId,
|
||||
leagues: output.team.leagues || [],
|
||||
createdAt: output.team.createdAt.toISOString(),
|
||||
id: result.team.id,
|
||||
name: result.team.name.toString(),
|
||||
tag: result.team.tag.toString(),
|
||||
description: result.team.description?.toString() || '',
|
||||
ownerId: result.team.ownerId.toString(),
|
||||
leagues: result.team.leagues?.map(l => l.toString()) || [],
|
||||
createdAt: result.team.createdAt.toDate().toISOString(),
|
||||
},
|
||||
membership: {
|
||||
role: output.membership.role === 'driver' ? 'member' : output.membership.role,
|
||||
joinedAt: output.membership.joinedAt.toISOString(),
|
||||
isActive: output.membership.status === 'active',
|
||||
role: result.membership.role === 'driver' ? 'member' : result.membership.role,
|
||||
joinedAt: result.membership.joinedAt.toISOString(),
|
||||
isActive: result.membership.status === 'active',
|
||||
},
|
||||
isOwner,
|
||||
canManage,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): GetDriverTeamOutputDTO | null {
|
||||
getResponseModel(): GetDriverTeamOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,37 @@
|
||||
import type { GetTeamDetailsOutputPort } from '@core/racing/application/ports/output/GetTeamDetailsOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetTeamDetailsResult } from '@core/racing/application/use-cases/GetTeamDetailsUseCase';
|
||||
import type { GetTeamDetailsOutputDTO } from '../dtos/GetTeamDetailsOutputDTO';
|
||||
|
||||
export class TeamDetailsPresenter {
|
||||
export class TeamDetailsPresenter implements UseCaseOutputPort<GetTeamDetailsResult> {
|
||||
private result: GetTeamDetailsOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
async present(outputPort: GetTeamDetailsOutputPort): Promise<void> {
|
||||
present(result: GetTeamDetailsResult): void {
|
||||
this.result = {
|
||||
team: {
|
||||
id: outputPort.team.id,
|
||||
name: outputPort.team.name,
|
||||
tag: outputPort.team.tag,
|
||||
description: outputPort.team.description,
|
||||
ownerId: outputPort.team.ownerId,
|
||||
leagues: outputPort.team.leagues,
|
||||
createdAt: outputPort.team.createdAt.toISOString(),
|
||||
id: result.team.id,
|
||||
name: result.team.name.toString(),
|
||||
tag: result.team.tag.toString(),
|
||||
description: result.team.description?.toString() || '',
|
||||
ownerId: result.team.ownerId.toString(),
|
||||
leagues: result.team.leagues?.map(l => l.toString()) || [],
|
||||
createdAt: result.team.createdAt.toDate().toISOString(),
|
||||
},
|
||||
membership: outputPort.membership
|
||||
membership: result.membership
|
||||
? {
|
||||
role: outputPort.membership.role,
|
||||
joinedAt: outputPort.membership.joinedAt.toISOString(),
|
||||
isActive: outputPort.membership.isActive,
|
||||
role: result.membership.role === 'driver' ? 'member' : result.membership.role,
|
||||
joinedAt: result.membership.joinedAt.toISOString(),
|
||||
isActive: result.membership.status === 'active',
|
||||
}
|
||||
: null,
|
||||
canManage: outputPort.canManage,
|
||||
canManage: result.canManage,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): GetTeamDetailsOutputDTO | null {
|
||||
getResponseModel(): GetTeamDetailsOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,31 @@
|
||||
import type { TeamJoinRequestsOutputPort } from '@core/racing/application/ports/output/TeamJoinRequestsOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetTeamJoinRequestsResult } from '@core/racing/application/use-cases/GetTeamJoinRequestsUseCase';
|
||||
import type { GetTeamJoinRequestsOutputDTO } from '../dtos/GetTeamJoinRequestsOutputDTO';
|
||||
|
||||
export class TeamJoinRequestsPresenter {
|
||||
export class TeamJoinRequestsPresenter implements UseCaseOutputPort<GetTeamJoinRequestsResult> {
|
||||
private result: GetTeamJoinRequestsOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
async present(outputPort: TeamJoinRequestsOutputPort): Promise<void> {
|
||||
present(result: GetTeamJoinRequestsResult): void {
|
||||
this.result = {
|
||||
requests: outputPort.requests.map(request => ({
|
||||
requestId: request.requestId,
|
||||
requests: result.joinRequests.map(request => ({
|
||||
requestId: request.id,
|
||||
driverId: request.driverId,
|
||||
driverName: request.driverName,
|
||||
driverName: request.driver.name.toString(),
|
||||
teamId: request.teamId,
|
||||
status: request.status,
|
||||
status: 'pending',
|
||||
requestedAt: request.requestedAt.toISOString(),
|
||||
avatarUrl: request.avatarUrl,
|
||||
avatarUrl: '', // TODO: get avatar
|
||||
})),
|
||||
pendingCount: outputPort.pendingCount,
|
||||
totalCount: outputPort.totalCount,
|
||||
pendingCount: result.joinRequests.length,
|
||||
totalCount: result.joinRequests.length,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): GetTeamJoinRequestsOutputDTO | null {
|
||||
getResponseModel(): GetTeamJoinRequestsOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,40 @@
|
||||
import type { TeamMembersOutputPort } from '@core/racing/application/ports/output/TeamMembersOutputPort';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetTeamMembersResult } from '@core/racing/application/use-cases/GetTeamMembersUseCase';
|
||||
import type { GetTeamMembersOutputDTO } from '../dtos/GetTeamMembersOutputDTO';
|
||||
|
||||
export class TeamMembersPresenter {
|
||||
export class TeamMembersPresenter implements UseCaseOutputPort<GetTeamMembersResult> {
|
||||
private result: GetTeamMembersOutputDTO | null = null;
|
||||
|
||||
reset() {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
async present(outputPort: TeamMembersOutputPort): Promise<void> {
|
||||
present(result: GetTeamMembersResult): void {
|
||||
const members = result.members
|
||||
.filter(member => member.driver !== null)
|
||||
.map(member => ({
|
||||
driverId: member.membership.driverId,
|
||||
driverName: member.driver!.name.toString(),
|
||||
role: (member.membership.role === 'driver' ? 'member' : member.membership.role) as 'owner' | 'manager' | 'member',
|
||||
joinedAt: member.membership.joinedAt.toISOString(),
|
||||
isActive: member.membership.status === 'active',
|
||||
avatarUrl: '', // TODO: get avatar
|
||||
}));
|
||||
|
||||
const ownerCount = result.members.filter(m => m.membership.role === 'owner').length;
|
||||
const managerCount = result.members.filter(m => m.membership.role === 'manager').length;
|
||||
const memberCount = result.members.filter(m => m.membership.role === 'driver').length;
|
||||
|
||||
this.result = {
|
||||
members: outputPort.members.map(member => ({
|
||||
driverId: member.driverId,
|
||||
driverName: member.driverName,
|
||||
role: member.role,
|
||||
joinedAt: member.joinedAt.toISOString(),
|
||||
isActive: member.isActive,
|
||||
avatarUrl: member.avatarUrl,
|
||||
})),
|
||||
totalCount: outputPort.totalCount,
|
||||
ownerCount: outputPort.ownerCount,
|
||||
managerCount: outputPort.managerCount,
|
||||
memberCount: outputPort.memberCount,
|
||||
members,
|
||||
totalCount: members.length,
|
||||
ownerCount,
|
||||
managerCount,
|
||||
memberCount,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): GetTeamMembersOutputDTO | null {
|
||||
getResponseModel(): GetTeamMembersOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,19 @@
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { GetTeamMembershipResult } from '@core/racing/application/use-cases/GetTeamMembershipUseCase';
|
||||
import type { GetTeamMembershipOutputDTO } from '../dtos/GetTeamMembershipOutputDTO';
|
||||
|
||||
export class TeamMembershipPresenter {
|
||||
export class TeamMembershipPresenter implements UseCaseOutputPort<GetTeamMembershipResult> {
|
||||
private result: GetTeamMembershipOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
present(membership: GetTeamMembershipOutputDTO | null): void {
|
||||
if (!membership) {
|
||||
this.result = null;
|
||||
return;
|
||||
}
|
||||
|
||||
this.result = {
|
||||
role: membership.role,
|
||||
joinedAt: membership.joinedAt,
|
||||
isActive: membership.isActive,
|
||||
};
|
||||
present(result: GetTeamMembershipResult): void {
|
||||
this.result = result.membership;
|
||||
}
|
||||
|
||||
getViewModel(): GetTeamMembershipOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): GetTeamMembershipOutputDTO | null {
|
||||
getResponseModel(): GetTeamMembershipOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
|
||||
import type { UpdateTeamResult } from '@core/racing/application/use-cases/UpdateTeamUseCase';
|
||||
import type { UpdateTeamOutputDTO } from '../dtos/UpdateTeamOutputDTO';
|
||||
|
||||
export class UpdateTeamPresenter {
|
||||
export class UpdateTeamPresenter implements UseCaseOutputPort<UpdateTeamResult> {
|
||||
private result: UpdateTeamOutputDTO | null = null;
|
||||
|
||||
reset(): void {
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
presentSuccess(): void {
|
||||
present(_result: UpdateTeamResult): void {
|
||||
this.result = {
|
||||
success: true,
|
||||
};
|
||||
}
|
||||
|
||||
presentError(): void {
|
||||
this.result = {
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
getViewModel(): UpdateTeamOutputDTO | null {
|
||||
getResponseModel(): UpdateTeamOutputDTO | null {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
get viewModel(): UpdateTeamOutputDTO {
|
||||
get responseModel(): UpdateTeamOutputDTO {
|
||||
if (!this.result) {
|
||||
throw new Error('Presenter not presented');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user