Files
gridpilot.gg/packages/racing/domain/entities/LeagueMembership.ts
2025-12-11 13:50:38 +01:00

81 lines
2.1 KiB
TypeScript

/**
* Domain Entity: LeagueMembership and JoinRequest
*
* Represents a driver's membership in a league and join requests.
*/
import type { IEntity } from '@gridpilot/shared/domain';
import { RacingDomainValidationError } from '../errors/RacingDomainError';
export type MembershipRole = 'owner' | 'admin' | 'steward' | 'member';
export type MembershipStatus = 'active' | 'pending' | 'none';
export interface LeagueMembershipProps {
id?: string;
leagueId: string;
driverId: string;
role: MembershipRole;
status?: MembershipStatus;
joinedAt?: Date;
}
export class LeagueMembership implements IEntity<string> {
readonly id: string;
readonly leagueId: string;
readonly driverId: string;
readonly role: MembershipRole;
readonly status: MembershipStatus;
readonly joinedAt: Date;
private constructor(props: Required<LeagueMembershipProps>) {
this.id = props.id;
this.leagueId = props.leagueId;
this.driverId = props.driverId;
this.role = props.role;
this.status = props.status;
this.joinedAt = props.joinedAt;
}
static create(props: LeagueMembershipProps): LeagueMembership {
this.validate(props);
const id =
props.id && props.id.trim().length > 0
? props.id
: `${props.leagueId}:${props.driverId}`;
const status = props.status ?? 'pending';
const joinedAt = props.joinedAt ?? new Date();
return new LeagueMembership({
id,
leagueId: props.leagueId,
driverId: props.driverId,
role: props.role,
status,
joinedAt,
});
}
private static validate(props: LeagueMembershipProps): void {
if (!props.leagueId || props.leagueId.trim().length === 0) {
throw new RacingDomainValidationError('League ID is required');
}
if (!props.driverId || props.driverId.trim().length === 0) {
throw new RacingDomainValidationError('Driver ID is required');
}
if (!props.role) {
throw new RacingDomainValidationError('Membership role is required');
}
}
}
export interface JoinRequest {
id: string;
leagueId: string;
driverId: string;
requestedAt: Date;
message?: string;
}