more seeds

This commit is contained in:
2025-12-27 11:58:35 +01:00
parent 91612e4256
commit 3efa978ee0
25 changed files with 806 additions and 55 deletions

View File

@@ -0,0 +1,97 @@
import type { UseCaseOutputPort } from '@core/shared/application/UseCaseOutputPort';
import type { GetAllLeaguesWithCapacityAndScoringResult } from '@core/racing/application/use-cases/GetAllLeaguesWithCapacityAndScoringUseCase';
import type {
AllLeaguesWithCapacityAndScoringDTO,
LeagueWithCapacityAndScoringDTO,
} from '../dtos/AllLeaguesWithCapacityAndScoringDTO';
export class AllLeaguesWithCapacityAndScoringPresenter
implements UseCaseOutputPort<GetAllLeaguesWithCapacityAndScoringResult>
{
private result: AllLeaguesWithCapacityAndScoringDTO | null = null;
present(result: GetAllLeaguesWithCapacityAndScoringResult): void {
const leagues: LeagueWithCapacityAndScoringDTO[] = result.leagues.map((summary) => {
const timingSummary = summary.preset
? formatTimingSummary(summary.preset.defaultTimings.mainRaceMinutes)
: undefined;
return {
id: summary.league.id.toString(),
name: summary.league.name.toString(),
description: summary.league.description?.toString() || '',
ownerId: summary.league.ownerId.toString(),
createdAt: summary.league.createdAt.toDate().toISOString(),
settings: {
maxDrivers: summary.maxDrivers,
...(summary.league.settings.sessionDuration !== undefined
? { sessionDuration: summary.league.settings.sessionDuration }
: {}),
...(summary.league.settings.qualifyingFormat !== undefined
? { qualifyingFormat: summary.league.settings.qualifyingFormat.toString() }
: {}),
},
usedSlots: summary.currentDrivers,
...mapSocialLinks(summary.league.socialLinks),
...(summary.scoringConfig && summary.game && summary.preset
? {
scoring: {
gameId: summary.game.id.toString(),
gameName: summary.game.name.toString(),
primaryChampionshipType: summary.preset.primaryChampionshipType,
scoringPresetId: summary.scoringConfig.scoringPresetId?.toString() ?? 'custom',
scoringPresetName: summary.preset.name,
dropPolicySummary: summary.preset.dropPolicySummary,
scoringPatternSummary: summary.preset.sessionSummary,
},
}
: {}),
...(timingSummary ? { timingSummary } : {}),
};
});
this.result = {
leagues,
totalCount: leagues.length,
};
}
getViewModel(): AllLeaguesWithCapacityAndScoringDTO {
if (!this.result) throw new Error('Presenter not presented');
return this.result;
}
}
function formatTimingSummary(mainRaceMinutes: number): string {
if (!Number.isFinite(mainRaceMinutes) || mainRaceMinutes <= 0) return '';
if (mainRaceMinutes >= 60 && mainRaceMinutes % 60 === 0) {
return `${mainRaceMinutes / 60}h Race`;
}
return `${mainRaceMinutes}m Race`;
}
type SocialLinksInput = {
discordUrl?: string | undefined;
youtubeUrl?: string | undefined;
websiteUrl?: string | undefined;
};
type SocialLinksOutput = {
discordUrl?: string;
youtubeUrl?: string;
websiteUrl?: string;
};
function mapSocialLinks(socialLinks: SocialLinksInput | undefined): { socialLinks: SocialLinksOutput } | {} {
if (!socialLinks) return {};
const mapped: SocialLinksOutput = {
...(socialLinks.discordUrl ? { discordUrl: socialLinks.discordUrl } : {}),
...(socialLinks.youtubeUrl ? { youtubeUrl: socialLinks.youtubeUrl } : {}),
...(socialLinks.websiteUrl ? { websiteUrl: socialLinks.websiteUrl } : {}),
};
return Object.keys(mapped).length > 0 ? { socialLinks: mapped } : {};
}