105 lines
3.7 KiB
TypeScript
105 lines
3.7 KiB
TypeScript
import { LeaguesApiClient } from "@/lib/api/leagues/LeaguesApiClient";
|
|
import { DriversApiClient } from "@/lib/api/drivers/DriversApiClient";
|
|
import type { LeagueConfigFormModel } from "@core/racing/application";
|
|
import type { LeagueScoringPresetDTO } from "@core/racing/application/ports/LeagueScoringPresetProvider";
|
|
import type { GetDriverOutputDTO } from "@/lib/types/generated/GetDriverOutputDTO";
|
|
import { LeagueSettingsViewModel } from "@/lib/view-models/LeagueSettingsViewModel";
|
|
import { DriverSummaryViewModel } from "@/lib/view-models/DriverSummaryViewModel";
|
|
|
|
/**
|
|
* League Settings Service
|
|
*
|
|
* Orchestrates league settings operations by coordinating API calls and view model creation.
|
|
* All dependencies are injected via constructor.
|
|
*/
|
|
export class LeagueSettingsService {
|
|
constructor(
|
|
private readonly leaguesApiClient: LeaguesApiClient,
|
|
private readonly driversApiClient: DriversApiClient
|
|
) {}
|
|
|
|
/**
|
|
* Get league settings with view model transformation
|
|
*/
|
|
async getLeagueSettings(leagueId: string): Promise<LeagueSettingsViewModel | null> {
|
|
try {
|
|
// Get league basic info (includes ownerId in DTO)
|
|
const allLeagues = await this.leaguesApiClient.getAllWithCapacity();
|
|
const leagueDto = allLeagues.leagues.find(l => l.id === leagueId);
|
|
if (!leagueDto) return null;
|
|
|
|
const league = {
|
|
id: leagueDto.id,
|
|
name: leagueDto.name,
|
|
ownerId: leagueDto.ownerId,
|
|
};
|
|
|
|
// Get config
|
|
const configDto = await this.leaguesApiClient.getLeagueConfig(leagueId);
|
|
const config: LeagueConfigFormModel = configDto.config;
|
|
|
|
// Get presets
|
|
const presetsDto = await this.leaguesApiClient.getScoringPresets();
|
|
const presets: LeagueScoringPresetDTO[] = presetsDto.presets;
|
|
|
|
// Get leaderboard once so we can hydrate rating / rank for owner + members
|
|
const leaderboardDto = await this.driversApiClient.getLeaderboard();
|
|
const leaderboardByDriverId = new Map(
|
|
leaderboardDto.drivers.map(driver => [driver.id, driver])
|
|
);
|
|
|
|
// Get owner
|
|
const ownerDriver = await this.driversApiClient.getDriver(league.ownerId);
|
|
let owner: DriverSummaryViewModel | null = null;
|
|
if (ownerDriver) {
|
|
const ownerStats = leaderboardByDriverId.get(ownerDriver.id);
|
|
owner = new DriverSummaryViewModel({
|
|
driver: ownerDriver,
|
|
rating: ownerStats?.rating ?? null,
|
|
rank: ownerStats?.rank ?? null,
|
|
});
|
|
}
|
|
|
|
// Get members
|
|
const membershipsDto = await this.leaguesApiClient.getMemberships(leagueId);
|
|
const members: DriverSummaryViewModel[] = [];
|
|
for (const member of membershipsDto.members) {
|
|
if (member.driverId !== league.ownerId && member.role !== 'owner') {
|
|
const driver = await this.driversApiClient.getDriver(member.driverId);
|
|
if (driver) {
|
|
const memberStats = leaderboardByDriverId.get(driver.id);
|
|
members.push(new DriverSummaryViewModel({
|
|
driver,
|
|
rating: memberStats?.rating ?? null,
|
|
rank: memberStats?.rank ?? null,
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
return new LeagueSettingsViewModel({
|
|
league,
|
|
config,
|
|
presets,
|
|
owner,
|
|
members,
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to load league settings:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Transfer league ownership
|
|
*/
|
|
async transferOwnership(leagueId: string, currentOwnerId: string, newOwnerId: string): Promise<boolean> {
|
|
try {
|
|
const result = await this.leaguesApiClient.transferOwnership(leagueId, currentOwnerId, newOwnerId);
|
|
return result.success;
|
|
} catch (error) {
|
|
console.error('Failed to transfer ownership:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
} |