This commit is contained in:
2025-12-11 21:06:25 +01:00
parent c49ea2598d
commit ec3ddc3a5c
227 changed files with 3496 additions and 2083 deletions

View File

@@ -3,6 +3,8 @@ import type { Protest } from '@gridpilot/racing/domain/entities/Protest';
import type { Race } from '@gridpilot/racing/domain/entities/Race';
import type { DriverDTO } from '@gridpilot/racing/application/dto/DriverDTO';
import type { LeagueConfigFormModel } from '@gridpilot/racing/application';
import type { LeagueConfigFormViewModel } from '@gridpilot/racing/application/presenters/ILeagueFullConfigPresenter';
import { LeagueFullConfigPresenter } from '@/lib/presenters/LeagueFullConfigPresenter';
import type { MembershipRole } from '@/lib/leagueMembership';
import { EntityMappers } from '@gridpilot/racing/application/mappers/EntityMappers';
import {
@@ -38,6 +40,14 @@ export interface LeagueOwnerSummaryViewModel {
rank: number | null;
}
export interface LeagueSummaryViewModel {
id: string;
ownerId: string;
settings: {
pointsSystem: string;
};
}
export interface LeagueAdminProtestsViewModel {
protests: Protest[];
racesById: ProtestRaceSummary;
@@ -79,14 +89,23 @@ export async function loadLeagueJoinRequests(leagueId: string): Promise<LeagueJo
driversById[dto.id] = dto;
}
return requests.map((request) => ({
id: request.id,
leagueId: request.leagueId,
driverId: request.driverId,
requestedAt: request.requestedAt,
message: request.message,
driver: driversById[request.driverId],
}));
return requests.map((request) => {
const base: LeagueJoinRequestViewModel = {
id: request.id,
leagueId: request.leagueId,
driverId: request.driverId,
requestedAt: request.requestedAt,
};
const message = request.message;
const driver = driversById[request.driverId];
return {
...base,
...(typeof message === 'string' && message.length > 0 ? { message } : {}),
...(driver ? { driver } : {}),
};
});
}
/**
@@ -104,6 +123,7 @@ export async function approveLeagueJoinRequest(
}
await membershipRepo.saveMembership({
id: request.id,
leagueId: request.leagueId,
driverId: request.driverId,
role: 'member',
@@ -203,12 +223,17 @@ export async function updateLeagueMemberRole(
/**
* Load owner summary (DTO + rating/rank) for a league.
*/
export async function loadLeagueOwnerSummary(league: League): Promise<LeagueOwnerSummaryViewModel | null> {
export async function loadLeagueOwnerSummary(params: {
ownerId: string;
}): Promise<LeagueOwnerSummaryViewModel | null> {
const driverRepo = getDriverRepository();
const entity = await driverRepo.findById(league.ownerId);
const entity = await driverRepo.findById(params.ownerId);
if (!entity) return null;
const ownerDriver = EntityMappers.toDriverDTO(entity);
if (!ownerDriver) {
return null;
}
const stats = getDriverStats(ownerDriver.id);
const allRankings = getAllDriverRankings();
@@ -243,10 +268,52 @@ export async function loadLeagueOwnerSummary(league: League): Promise<LeagueOwne
/**
* Load league full config form.
*/
export async function loadLeagueConfig(leagueId: string): Promise<LeagueAdminConfigViewModel> {
export async function loadLeagueConfig(
leagueId: string,
): Promise<LeagueAdminConfigViewModel> {
const useCase = getGetLeagueFullConfigUseCase();
const form = await useCase.execute({ leagueId });
return { form };
const presenter = new LeagueFullConfigPresenter();
await useCase.execute({ leagueId }, presenter);
const fullConfig = presenter.getViewModel();
if (!fullConfig) {
return { form: null };
}
const formModel: LeagueConfigFormModel = {
leagueId: fullConfig.leagueId,
basics: {
...fullConfig.basics,
visibility: fullConfig.basics.visibility as LeagueConfigFormModel['basics']['visibility'],
},
structure: {
...fullConfig.structure,
mode: fullConfig.structure.mode as LeagueConfigFormModel['structure']['mode'],
},
championships: fullConfig.championships,
scoring: fullConfig.scoring,
dropPolicy: {
strategy: fullConfig.dropPolicy.strategy as LeagueConfigFormModel['dropPolicy']['strategy'],
...(fullConfig.dropPolicy.n !== undefined ? { n: fullConfig.dropPolicy.n } : {}),
},
timings: fullConfig.timings,
stewarding: {
decisionMode: fullConfig.stewarding.decisionMode as LeagueConfigFormModel['stewarding']['decisionMode'],
...(fullConfig.stewarding.requiredVotes !== undefined
? { requiredVotes: fullConfig.stewarding.requiredVotes }
: {}),
requireDefense: fullConfig.stewarding.requireDefense,
defenseTimeLimit: fullConfig.stewarding.defenseTimeLimit,
voteTimeLimit: fullConfig.stewarding.voteTimeLimit,
protestDeadlineHours: fullConfig.stewarding.protestDeadlineHours,
stewardingClosesHours: fullConfig.stewarding.stewardingClosesHours,
notifyAccusedOnProtest: fullConfig.stewarding.notifyAccusedOnProtest,
notifyOnVoteRequired: fullConfig.stewarding.notifyOnVoteRequired,
},
};
return { form: formModel };
}
/**