Files
gridpilot.gg/apps/website/lib/services/leagues/LeagueSettingsService.ts

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;
}
}
}