Files
gridpilot.gg/core/racing/application/use-cases/LeaveTeamUseCase.ts
2025-12-21 00:43:42 +01:00

101 lines
3.1 KiB
TypeScript

import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { Team } from '../../domain/entities/Team';
import type { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
import type { ITeamRepository } from '../../domain/repositories/ITeamRepository';
import type { TeamMembership } from '../../domain/types/TeamMembership';
export type LeaveTeamErrorCode =
| 'TEAM_NOT_FOUND'
| 'NOT_MEMBER'
| 'OWNER_CANNOT_LEAVE'
| 'REPOSITORY_ERROR';
export type LeaveTeamInput = {
teamId: string;
driverId: string;
};
export interface LeaveTeamResult {
team: Team;
previousMembership: TeamMembership;
}
export class LeaveTeamUseCase {
constructor(
private readonly teamRepository: ITeamRepository,
private readonly membershipRepository: ITeamMembershipRepository,
private readonly logger: Logger,
private readonly output: UseCaseOutputPort<LeaveTeamResult>,
) {}
async execute(
input: LeaveTeamInput,
): Promise<
Result<void, ApplicationErrorCode<LeaveTeamErrorCode, { message: string }>>
> {
this.logger.debug('Attempting to leave team', { input });
const { teamId, driverId } = input;
try {
const team = await this.teamRepository.findById(teamId);
if (!team) {
const error = new Error(`Team ${teamId} not found`);
this.logger.error('Team not found', error);
return Result.err({
code: 'TEAM_NOT_FOUND',
details: { message: `Team ${teamId} not found` },
});
}
const membership = await this.membershipRepository.getMembership(
teamId,
driverId,
);
if (!membership) {
this.logger.warn('Driver is not a member of this team', {
driverId,
teamId,
});
return Result.err({
code: 'NOT_MEMBER',
details: { message: 'Not a member of this team' },
});
}
if (membership.role === 'owner') {
this.logger.warn('Team owner cannot leave', { driverId, teamId });
return Result.err({
code: 'OWNER_CANNOT_LEAVE',
details: {
message:
'Team owner cannot leave. Transfer ownership or disband team first.',
},
});
}
await this.membershipRepository.removeMembership(teamId, driverId);
this.logger.info('Driver successfully left team', { driverId, teamId });
const result: LeaveTeamResult = {
team,
previousMembership: membership,
};
this.output.present(result);
return Result.ok(undefined);
} catch (error) {
this.logger.error(
'Failed to leave team due to an unexpected error',
error instanceof Error ? error : new Error('Unknown error'),
);
return Result.err({
code: 'REPOSITORY_ERROR',
details: {
message: error instanceof Error ? error.message : 'Unknown error',
},
});
}
}
}