website refactor
This commit is contained in:
@@ -1,283 +0,0 @@
|
||||
import { LeaguesApiClient } from "@/lib/api/leagues/LeaguesApiClient";
|
||||
import { DriversApiClient } from "@/lib/api/drivers/DriversApiClient";
|
||||
import type { LeagueConfigFormModel } from "@/lib/types/LeagueConfigFormModel";
|
||||
import type { LeagueScoringPresetDTO } from "@/lib/types/generated/LeagueScoringPresetDTO";
|
||||
import { LeagueSettingsViewModel } from "@/lib/view-models/LeagueSettingsViewModel";
|
||||
import { DriverSummaryViewModel } from "@/lib/view-models/DriverSummaryViewModel";
|
||||
import type { LeagueScoringPresetViewModel } from "@/lib/view-models/LeagueScoringPresetViewModel";
|
||||
import type { CustomPointsConfig } from "@/lib/view-models/ScoringConfigurationViewModel";
|
||||
|
||||
/**
|
||||
* 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,
|
||||
createdAt: leagueDto.createdAt || new Date().toISOString(),
|
||||
};
|
||||
|
||||
// Get config
|
||||
const configDto = await this.leaguesApiClient.getLeagueConfig(leagueId);
|
||||
const config: LeagueConfigFormModel = (configDto.form ?? undefined) as unknown as LeagueConfigFormModel;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a scoring preset
|
||||
*/
|
||||
selectScoringPreset(
|
||||
currentForm: LeagueConfigFormModel,
|
||||
presetId: string
|
||||
): LeagueConfigFormModel {
|
||||
return {
|
||||
...currentForm,
|
||||
scoring: {
|
||||
...currentForm.scoring,
|
||||
patternId: presetId,
|
||||
customScoringEnabled: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle custom scoring
|
||||
*/
|
||||
toggleCustomScoring(currentForm: LeagueConfigFormModel): LeagueConfigFormModel {
|
||||
return {
|
||||
...currentForm,
|
||||
scoring: {
|
||||
...currentForm.scoring,
|
||||
customScoringEnabled: !currentForm.scoring.customScoringEnabled,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update championship settings
|
||||
*/
|
||||
updateChampionship(
|
||||
currentForm: LeagueConfigFormModel,
|
||||
key: keyof LeagueConfigFormModel['championships'],
|
||||
value: boolean
|
||||
): LeagueConfigFormModel {
|
||||
return {
|
||||
...currentForm,
|
||||
championships: {
|
||||
...currentForm.championships,
|
||||
[key]: value,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get preset emoji based on name
|
||||
*/
|
||||
getPresetEmoji(preset: LeagueScoringPresetViewModel): string {
|
||||
const name = preset.name.toLowerCase();
|
||||
if (name.includes('sprint') || name.includes('double')) return '⚡';
|
||||
if (name.includes('endurance') || name.includes('long')) return '🏆';
|
||||
if (name.includes('club') || name.includes('casual')) return '🏅';
|
||||
return '🏁';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get preset description based on name
|
||||
*/
|
||||
getPresetDescription(preset: LeagueScoringPresetViewModel): string {
|
||||
const name = preset.name.toLowerCase();
|
||||
if (name.includes('sprint')) return 'Sprint + Feature race';
|
||||
if (name.includes('endurance')) return 'Long-form endurance';
|
||||
if (name.includes('club')) return 'Casual league format';
|
||||
return preset.sessionSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get preset info content for flyout
|
||||
*/
|
||||
getPresetInfoContent(presetName: string): { title: string; description: string; details: string[] } {
|
||||
const name = presetName.toLowerCase();
|
||||
if (name.includes('sprint')) {
|
||||
return {
|
||||
title: 'Sprint + Feature Format',
|
||||
description: 'A two-race weekend format with a shorter sprint race and a longer feature race.',
|
||||
details: [
|
||||
'Sprint race typically awards reduced points (e.g., 8-6-4-3-2-1)',
|
||||
'Feature race awards full points (e.g., 25-18-15-12-10-8-6-4-2-1)',
|
||||
'Grid for feature often based on sprint results',
|
||||
'Great for competitive leagues with time for multiple races',
|
||||
],
|
||||
};
|
||||
}
|
||||
if (name.includes('endurance') || name.includes('long')) {
|
||||
return {
|
||||
title: 'Endurance Format',
|
||||
description: 'Long-form racing focused on consistency and strategy over raw pace.',
|
||||
details: [
|
||||
'Single race per weekend, longer duration (60-90+ minutes)',
|
||||
'Higher points for finishing (rewards reliability)',
|
||||
'Often includes mandatory pit stops',
|
||||
'Best for serious leagues with dedicated racers',
|
||||
],
|
||||
};
|
||||
}
|
||||
if (name.includes('club') || name.includes('casual')) {
|
||||
return {
|
||||
title: 'Club/Casual Format',
|
||||
description: 'Relaxed format perfect for community leagues and casual racing.',
|
||||
details: [
|
||||
'Simple points structure, easy to understand',
|
||||
'Typically single race per weekend',
|
||||
'Lower stakes, focus on participation',
|
||||
'Great for beginners or mixed-skill leagues',
|
||||
],
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: 'Standard Race Format',
|
||||
description: 'Traditional single-race weekend with standard F1-style points.',
|
||||
details: [
|
||||
'Points: 25-18-15-12-10-8-6-4-2-1 for top 10',
|
||||
'Bonus points for pole position and fastest lap',
|
||||
'One race per weekend',
|
||||
'The most common format used in sim racing',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get championship info content for flyout
|
||||
*/
|
||||
getChampionshipInfoContent(key: string): { title: string; description: string; details: string[] } {
|
||||
const info: Record<string, { title: string; description: string; details: string[] }> = {
|
||||
enableDriverChampionship: {
|
||||
title: 'Driver Championship',
|
||||
description: 'Track individual driver performance across all races in the season.',
|
||||
details: [
|
||||
'Each driver accumulates points based on race finishes',
|
||||
'The driver with most points at season end wins',
|
||||
'Standard in all racing leagues',
|
||||
'Shows overall driver skill and consistency',
|
||||
],
|
||||
},
|
||||
enableTeamChampionship: {
|
||||
title: 'Team Championship',
|
||||
description: 'Combine points from all drivers within a team for team standings.',
|
||||
details: [
|
||||
'All drivers\' points count toward team total',
|
||||
'Rewards having consistent performers across the roster',
|
||||
'Creates team strategy opportunities',
|
||||
'Only available in Teams mode leagues',
|
||||
],
|
||||
},
|
||||
enableNationsChampionship: {
|
||||
title: 'Nations Cup',
|
||||
description: 'Group drivers by nationality for international competition.',
|
||||
details: [
|
||||
'Drivers represent their country automatically',
|
||||
'Points pooled by nationality',
|
||||
'Adds international rivalry element',
|
||||
'Great for diverse, international leagues',
|
||||
],
|
||||
},
|
||||
enableTrophyChampionship: {
|
||||
title: 'Trophy Championship',
|
||||
description: 'A special category championship for specific classes or groups.',
|
||||
details: [
|
||||
'Custom category you define (e.g., Am drivers, rookies)',
|
||||
'Separate standings from main championship',
|
||||
'Encourages participation from all skill levels',
|
||||
'Can be used for gentleman drivers, newcomers, etc.',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
return info[key] || {
|
||||
title: 'Championship',
|
||||
description: 'A championship standings category.',
|
||||
details: ['Enable to track this type of championship.'],
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user