180 lines
5.9 KiB
TypeScript
180 lines
5.9 KiB
TypeScript
import { Driver } from '@core/racing/domain/entities/Driver';
|
|
import { League } from '@core/racing/domain/entities/League';
|
|
import { Team } from '@core/racing/domain/entities/Team';
|
|
import type { TeamJoinRequest, TeamMembership } from '@core/racing/domain/types/TeamMembership';
|
|
import { faker } from '@faker-js/faker';
|
|
|
|
export class RacingTeamFactory {
|
|
constructor(private readonly baseDate: Date) {}
|
|
|
|
createTeams(drivers: Driver[], leagues: League[]): Team[] {
|
|
const teamCount = 15;
|
|
|
|
return Array.from({ length: teamCount }, (_, idx) => {
|
|
const i = idx + 1;
|
|
const owner = faker.helpers.arrayElement(drivers);
|
|
const teamLeagues = faker.helpers.arrayElements(
|
|
leagues.map((l) => l.id.toString()),
|
|
{ min: 0, max: 3 },
|
|
);
|
|
|
|
return Team.create({
|
|
id: `team-${i}`,
|
|
name: faker.company.name() + ' Racing',
|
|
tag: faker.string.alpha({ length: 4, casing: 'upper' }),
|
|
description: faker.lorem.sentences(2),
|
|
ownerId: owner.id,
|
|
leagues: teamLeagues,
|
|
createdAt: faker.date.past({ years: 2, refDate: this.baseDate }),
|
|
});
|
|
});
|
|
}
|
|
|
|
createTeamMemberships(drivers: Driver[], teams: Team[]): TeamMembership[] {
|
|
const memberships: TeamMembership[] = [];
|
|
const usedDrivers = new Set<string>();
|
|
|
|
teams.forEach((team, teamIndex) => {
|
|
const availableDrivers = drivers.filter(d => !usedDrivers.has(d.id.toString()) && d.id.toString() !== team.ownerId.toString());
|
|
|
|
// Create varied team compositions
|
|
let memberCount: number;
|
|
let hasManager: boolean;
|
|
|
|
if (teamIndex % 5 === 0) {
|
|
// Solo teams (just owner)
|
|
memberCount = 0;
|
|
hasManager = false;
|
|
} else if (teamIndex % 5 === 1) {
|
|
// Small teams (2-3 members)
|
|
memberCount = faker.number.int({ min: 1, max: 2 });
|
|
hasManager = faker.datatype.boolean();
|
|
} else if (teamIndex % 5 === 2) {
|
|
// Medium teams (3-5 members)
|
|
memberCount = faker.number.int({ min: 2, max: 4 });
|
|
hasManager = true;
|
|
} else if (teamIndex % 5 === 3) {
|
|
// Large teams (5-7 members)
|
|
memberCount = faker.number.int({ min: 4, max: 6 });
|
|
hasManager = true;
|
|
} else {
|
|
// Mixed - sometimes with manager, sometimes without
|
|
memberCount = faker.number.int({ min: 1, max: 5 });
|
|
hasManager = faker.datatype.boolean();
|
|
}
|
|
|
|
const members = faker.helpers.arrayElements(availableDrivers, memberCount);
|
|
|
|
// Add owner
|
|
memberships.push({
|
|
teamId: team.id.toString(),
|
|
driverId: team.ownerId.toString(),
|
|
role: 'owner',
|
|
status: 'active',
|
|
joinedAt: faker.date.past({ years: 1, refDate: team.createdAt.toDate() }),
|
|
});
|
|
usedDrivers.add(team.ownerId.toString());
|
|
|
|
// Add manager if needed
|
|
if (hasManager && members.length > 0) {
|
|
const managerIndex = faker.number.int({ min: 0, max: members.length - 1 });
|
|
const manager = members[managerIndex]!;
|
|
memberships.push({
|
|
teamId: team.id.toString(),
|
|
driverId: manager.id.toString(),
|
|
role: 'manager',
|
|
status: 'active',
|
|
joinedAt: faker.date.past({ years: 1, refDate: team.createdAt.toDate() }),
|
|
});
|
|
usedDrivers.add(manager.id.toString());
|
|
}
|
|
|
|
// Add remaining members as drivers
|
|
members.forEach((driver) => {
|
|
if (!usedDrivers.has(driver.id.toString())) {
|
|
memberships.push({
|
|
teamId: team.id.toString(),
|
|
driverId: driver.id.toString(),
|
|
role: 'driver',
|
|
status: 'active',
|
|
joinedAt: faker.date.past({ years: 1, refDate: team.createdAt.toDate() }),
|
|
});
|
|
usedDrivers.add(driver.id.toString());
|
|
}
|
|
});
|
|
});
|
|
|
|
return memberships;
|
|
}
|
|
|
|
createTeamJoinRequests(
|
|
drivers: Driver[],
|
|
teams: Team[],
|
|
teamMemberships: TeamMembership[],
|
|
): TeamJoinRequest[] {
|
|
const membershipIds = new Set<string>(teamMemberships.map(m => `${m.teamId}:${m.driverId}`));
|
|
const requests: TeamJoinRequest[] = [];
|
|
|
|
const addRequest = (request: TeamJoinRequest): void => {
|
|
requests.push(request);
|
|
};
|
|
|
|
const team1 = teams[0];
|
|
if (team1) {
|
|
const candidateDriverIds = drivers
|
|
.map(d => d.id.toString())
|
|
.filter(driverId => !membershipIds.has(`${team1.id.toString()}:${driverId}`))
|
|
.slice(0, 8);
|
|
|
|
candidateDriverIds.forEach((driverId, idx) => {
|
|
addRequest({
|
|
id: `team-join-${team1.id.toString()}-${driverId}`,
|
|
teamId: team1.id.toString(),
|
|
driverId,
|
|
requestedAt: this.addDays(this.baseDate, -(5 + idx)),
|
|
...(idx % 3 === 0
|
|
? { message: 'Can I join as a substitute driver for endurance events?' }
|
|
: idx % 3 === 2
|
|
? { message: '' }
|
|
: {}),
|
|
});
|
|
});
|
|
|
|
// Conflict edge case: owner submits a join request to own team.
|
|
addRequest({
|
|
id: `team-join-${team1.id.toString()}-${team1.ownerId.toString()}-conflict`,
|
|
teamId: team1.id.toString(),
|
|
driverId: team1.ownerId.toString(),
|
|
requestedAt: this.addDays(this.baseDate, -1),
|
|
message: 'Testing edge case: owner submitted join request.',
|
|
});
|
|
}
|
|
|
|
const team3 = teams[2];
|
|
if (team3 && drivers[0]) {
|
|
const driverId = drivers[0].id.toString();
|
|
addRequest({
|
|
id: 'dup-team-join-req-1',
|
|
teamId: team3.id.toString(),
|
|
driverId,
|
|
requestedAt: this.addDays(this.baseDate, -10),
|
|
message: 'First request message (will be overwritten).',
|
|
});
|
|
|
|
addRequest({
|
|
id: 'dup-team-join-req-1',
|
|
teamId: team3.id.toString(),
|
|
driverId,
|
|
requestedAt: this.addDays(this.baseDate, -9),
|
|
message: 'Updated request message (duplicate id).',
|
|
});
|
|
}
|
|
|
|
return requests;
|
|
}
|
|
|
|
private addDays(date: Date, days: number): Date {
|
|
return new Date(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
}
|
|
|
|
} |