wip
This commit is contained in:
121
apps/website/lib/presenters/TeamAdminPresenter.ts
Normal file
121
apps/website/lib/presenters/TeamAdminPresenter.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import type { Team, TeamJoinRequest } from '@gridpilot/racing';
|
||||
import type { DriverDTO } from '@gridpilot/racing/application/dto/DriverDTO';
|
||||
import { EntityMappers } from '@gridpilot/racing/application/mappers/EntityMappers';
|
||||
import {
|
||||
getDriverRepository,
|
||||
getGetTeamJoinRequestsUseCase,
|
||||
getApproveTeamJoinRequestUseCase,
|
||||
getRejectTeamJoinRequestUseCase,
|
||||
getUpdateTeamUseCase,
|
||||
} from '@/lib/di-container';
|
||||
|
||||
export interface TeamAdminJoinRequestViewModel {
|
||||
id: string;
|
||||
teamId: string;
|
||||
driverId: string;
|
||||
requestedAt: Date;
|
||||
message?: string;
|
||||
driver?: DriverDTO;
|
||||
}
|
||||
|
||||
export interface TeamAdminTeamSummaryViewModel {
|
||||
id: string;
|
||||
name: string;
|
||||
tag: string;
|
||||
description: string;
|
||||
ownerId: string;
|
||||
}
|
||||
|
||||
export interface TeamAdminViewModel {
|
||||
team: TeamAdminTeamSummaryViewModel;
|
||||
requests: TeamAdminJoinRequestViewModel[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load join requests plus driver DTOs for a team.
|
||||
*/
|
||||
export async function loadTeamAdminViewModel(team: Team): Promise<TeamAdminViewModel> {
|
||||
const requests = await loadTeamJoinRequests(team.id);
|
||||
return {
|
||||
team: {
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
tag: team.tag,
|
||||
description: team.description,
|
||||
ownerId: team.ownerId,
|
||||
},
|
||||
requests,
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadTeamJoinRequests(teamId: string): Promise<TeamAdminJoinRequestViewModel[]> {
|
||||
const getRequestsUseCase = getGetTeamJoinRequestsUseCase();
|
||||
await getRequestsUseCase.execute({ teamId });
|
||||
const presenterVm = getRequestsUseCase.presenter.getViewModel();
|
||||
|
||||
const driverRepo = getDriverRepository();
|
||||
const allDrivers = await driverRepo.findAll();
|
||||
const driversById: Record<string, DriverDTO> = {};
|
||||
|
||||
for (const driver of allDrivers) {
|
||||
const dto = EntityMappers.toDriverDTO(driver);
|
||||
if (dto) {
|
||||
driversById[dto.id] = dto;
|
||||
}
|
||||
}
|
||||
|
||||
return presenterVm.requests.map((req) => ({
|
||||
id: req.requestId,
|
||||
teamId: req.teamId,
|
||||
driverId: req.driverId,
|
||||
requestedAt: new Date(req.requestedAt),
|
||||
message: req.message,
|
||||
driver: driversById[req.driverId],
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve a team join request and return updated request view models.
|
||||
*/
|
||||
export async function approveTeamJoinRequestAndReload(
|
||||
requestId: string,
|
||||
teamId: string,
|
||||
): Promise<TeamAdminJoinRequestViewModel[]> {
|
||||
const useCase = getApproveTeamJoinRequestUseCase();
|
||||
await useCase.execute({ requestId });
|
||||
return loadTeamJoinRequests(teamId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject a team join request and return updated request view models.
|
||||
*/
|
||||
export async function rejectTeamJoinRequestAndReload(
|
||||
requestId: string,
|
||||
teamId: string,
|
||||
): Promise<TeamAdminJoinRequestViewModel[]> {
|
||||
const useCase = getRejectTeamJoinRequestUseCase();
|
||||
await useCase.execute({ requestId });
|
||||
return loadTeamJoinRequests(teamId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update team basic details.
|
||||
*/
|
||||
export async function updateTeamDetails(params: {
|
||||
teamId: string;
|
||||
name: string;
|
||||
tag: string;
|
||||
description: string;
|
||||
updatedByDriverId: string;
|
||||
}): Promise<void> {
|
||||
const useCase = getUpdateTeamUseCase();
|
||||
await useCase.execute({
|
||||
teamId: params.teamId,
|
||||
updates: {
|
||||
name: params.name,
|
||||
tag: params.tag,
|
||||
description: params.description,
|
||||
},
|
||||
updatedBy: params.updatedByDriverId,
|
||||
});
|
||||
}
|
||||
76
apps/website/lib/presenters/TeamStandingsPresenter.ts
Normal file
76
apps/website/lib/presenters/TeamStandingsPresenter.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { getStandingRepository, getLeagueRepository, getTeamMembershipRepository } from '@/lib/di-container';
|
||||
|
||||
export interface TeamLeagueStandingViewModel {
|
||||
leagueId: string;
|
||||
leagueName: string;
|
||||
position: number;
|
||||
points: number;
|
||||
wins: number;
|
||||
racesCompleted: number;
|
||||
}
|
||||
|
||||
export interface TeamStandingsViewModel {
|
||||
standings: TeamLeagueStandingViewModel[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute team standings across the given leagues for a team.
|
||||
* Mirrors the previous TeamStandings component logic but keeps it out of the UI layer.
|
||||
*/
|
||||
export async function loadTeamStandings(
|
||||
teamId: string,
|
||||
leagues: string[],
|
||||
): Promise<TeamStandingsViewModel> {
|
||||
const standingRepo = getStandingRepository();
|
||||
const leagueRepo = getLeagueRepository();
|
||||
const teamMembershipRepo = getTeamMembershipRepository();
|
||||
|
||||
const members = await teamMembershipRepo.getTeamMembers(teamId);
|
||||
const memberIds = members.map((m) => m.driverId);
|
||||
|
||||
const teamStandings: TeamLeagueStandingViewModel[] = [];
|
||||
|
||||
for (const leagueId of leagues) {
|
||||
const league = await leagueRepo.findById(leagueId);
|
||||
if (!league) continue;
|
||||
|
||||
const leagueStandings = await standingRepo.findByLeagueId(leagueId);
|
||||
|
||||
let totalPoints = 0;
|
||||
let totalWins = 0;
|
||||
let totalRaces = 0;
|
||||
|
||||
for (const standing of leagueStandings) {
|
||||
if (memberIds.includes(standing.driverId)) {
|
||||
totalPoints += standing.points;
|
||||
totalWins += standing.wins;
|
||||
totalRaces = Math.max(totalRaces, standing.racesCompleted);
|
||||
}
|
||||
}
|
||||
|
||||
// Simplified team position based on total points (same spirit as previous logic)
|
||||
const allTeamPoints = leagueStandings
|
||||
.filter((s) => memberIds.includes(s.driverId))
|
||||
.reduce((sum, s) => sum + s.points, 0);
|
||||
|
||||
const position =
|
||||
leagueStandings
|
||||
.filter((_, idx, arr) => {
|
||||
const teamPoints = arr
|
||||
.filter((s) => memberIds.includes(s.driverId))
|
||||
.reduce((sum, s) => sum + s.points, 0);
|
||||
return teamPoints > allTeamPoints;
|
||||
}).length + 1;
|
||||
|
||||
teamStandings.push({
|
||||
leagueId,
|
||||
leagueName: league.name,
|
||||
position,
|
||||
points: totalPoints,
|
||||
wins: totalWins,
|
||||
racesCompleted: totalRaces,
|
||||
});
|
||||
}
|
||||
|
||||
return { standings: teamStandings };
|
||||
}
|
||||
Reference in New Issue
Block a user