website cleanup
This commit is contained in:
@@ -47,6 +47,26 @@ export class LeagueMembershipService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a league.
|
||||
*
|
||||
* NOTE: The API currently exposes membership mutations via league member management endpoints.
|
||||
* For now we keep the website decoupled by consuming only the API through this service.
|
||||
*/
|
||||
async joinLeague(leagueId: string, driverId: string): Promise<void> {
|
||||
// Temporary: no join endpoint exposed yet in API.
|
||||
// Keep behavior predictable for UI.
|
||||
throw new Error('Joining leagues is not available in this build.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a league.
|
||||
*/
|
||||
async leaveLeague(leagueId: string, driverId: string): Promise<void> {
|
||||
// Temporary: no leave endpoint exposed yet in API.
|
||||
throw new Error('Leaving leagues is not available in this build.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set memberships in cache (for use after API calls).
|
||||
*/
|
||||
@@ -118,4 +138,4 @@ export class LeagueMembershipService {
|
||||
clearLeagueMemberships(leagueId: string): void {
|
||||
LeagueMembershipService.clearLeagueMemberships(leagueId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import { SubmitBlocker, ThrottleBlocker } from "@/lib/blockers";
|
||||
import { RaceDTO } from "@/lib/types/generated/RaceDTO";
|
||||
import { LeagueStatsDTO } from "@/lib/types/generated/LeagueStatsDTO";
|
||||
import { LeagueScoringConfigDTO } from "@/lib/types/LeagueScoringConfigDTO";
|
||||
import type { LeagueMembership } from "@/lib/types/LeagueMembership";
|
||||
import type { LeagueSeasonSummaryDTO } from '@/lib/types/generated/LeagueSeasonSummaryDTO';
|
||||
|
||||
|
||||
/**
|
||||
@@ -48,9 +50,9 @@ export class LeagueService {
|
||||
name: league.name,
|
||||
description: league.description ?? '',
|
||||
ownerId: league.ownerId,
|
||||
createdAt: '', // Not provided by API
|
||||
maxDrivers: league.maxMembers,
|
||||
usedDriverSlots: league.memberCount,
|
||||
createdAt: league.createdAt,
|
||||
maxDrivers: league.settings.maxDrivers ?? 0,
|
||||
usedDriverSlots: league.usedSlots,
|
||||
structureSummary: 'TBD',
|
||||
timingSummary: 'TBD'
|
||||
}));
|
||||
@@ -66,16 +68,20 @@ export class LeagueService {
|
||||
// League memberships (roles, statuses)
|
||||
const membershipsDto = await this.apiClient.getMemberships(leagueId);
|
||||
|
||||
const memberships: LeagueMembership[] = membershipsDto.members.map((m) => ({
|
||||
driverId: m.driverId,
|
||||
leagueId,
|
||||
role: (m.role as LeagueMembership['role']) ?? 'member',
|
||||
joinedAt: m.joinedAt,
|
||||
status: 'active',
|
||||
}));
|
||||
|
||||
// Resolve unique drivers that appear in standings
|
||||
const driverIds: string[] = Array.from(new Set(dto.standings.map((entry: any) => entry.driverId)));
|
||||
const driverDtos = await Promise.all(driverIds.map((id: string) => this.driversApiClient.getDriver(id)));
|
||||
const drivers = driverDtos.filter((d): d is NonNullable<typeof d> => d !== null);
|
||||
|
||||
const dtoWithExtras = {
|
||||
standings: dto.standings,
|
||||
drivers,
|
||||
memberships: membershipsDto.members,
|
||||
};
|
||||
const dtoWithExtras = { standings: dto.standings, drivers, memberships };
|
||||
|
||||
return new LeagueStandingsViewModel(dtoWithExtras, currentUserId);
|
||||
}
|
||||
@@ -96,6 +102,13 @@ export class LeagueService {
|
||||
return new LeagueScheduleViewModel(dto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get seasons for a league
|
||||
*/
|
||||
async getLeagueSeasons(leagueId: string): Promise<LeagueSeasonSummaryDTO[]> {
|
||||
return this.apiClient.getSeasons(leagueId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get league memberships
|
||||
*/
|
||||
@@ -162,18 +175,19 @@ export class LeagueService {
|
||||
// Get membership
|
||||
const membershipsDto = await this.apiClient.getMemberships(leagueId);
|
||||
const membership = membershipsDto.members.find((m: any) => m.driverId === currentDriverId);
|
||||
const isAdmin = membership ? ['admin', 'owner'].includes(membership.role) : false;
|
||||
const isAdmin = membership ? ['admin', 'owner'].includes((membership as any).role) : false;
|
||||
|
||||
// Get main sponsor
|
||||
let mainSponsor = null;
|
||||
try {
|
||||
const seasonsDto = await this.apiClient.getSeasons(leagueId);
|
||||
const activeSeason = seasonsDto.seasons.find((s: any) => s.status === 'active') ?? seasonsDto.seasons[0];
|
||||
const seasons = await this.apiClient.getSeasons(leagueId);
|
||||
const activeSeason = seasons.find((s) => s.status === 'active') ?? seasons[0];
|
||||
if (activeSeason) {
|
||||
const sponsorshipsDto = await this.apiClient.getSeasonSponsorships(activeSeason.id);
|
||||
const sponsorshipsDto = await this.apiClient.getSeasonSponsorships(activeSeason.seasonId);
|
||||
const mainSponsorship = sponsorshipsDto.sponsorships.find((s: any) => s.tier === 'main' && s.status === 'active');
|
||||
if (mainSponsorship) {
|
||||
const sponsor = await this.sponsorsApiClient.getSponsor(mainSponsorship.sponsorId);
|
||||
const sponsorResult = await this.sponsorsApiClient.getSponsor((mainSponsorship as any).sponsorId ?? (mainSponsorship as any).sponsor?.id);
|
||||
const sponsor = (sponsorResult as any)?.sponsor ?? null;
|
||||
if (sponsor) {
|
||||
mainSponsor = {
|
||||
name: sponsor.name,
|
||||
@@ -241,7 +255,11 @@ export class LeagueService {
|
||||
const allRaces = leagueRaces.races.map(r => new RaceViewModel(r as RaceDTO));
|
||||
|
||||
// League stats endpoint currently returns global league statistics rather than per-league values
|
||||
const leagueStats = await this.apiClient.getTotal();
|
||||
const leagueStats: LeagueStatsDTO = {
|
||||
totalMembers: league.usedSlots,
|
||||
totalRaces: allRaces.length,
|
||||
averageRating: 0,
|
||||
};
|
||||
|
||||
// Get sponsors
|
||||
const sponsors = await this.getLeagueSponsors(leagueId);
|
||||
@@ -268,16 +286,17 @@ export class LeagueService {
|
||||
private async getLeagueSponsors(leagueId: string): Promise<SponsorInfo[]> {
|
||||
try {
|
||||
const seasons = await this.apiClient.getSeasons(leagueId);
|
||||
const activeSeason = seasons.seasons.find((s: any) => s.status === 'active') ?? seasons.seasons[0];
|
||||
const activeSeason = seasons.find((s) => s.status === 'active') ?? seasons[0];
|
||||
|
||||
if (!activeSeason) return [];
|
||||
|
||||
const sponsorships = await this.apiClient.getSeasonSponsorships(activeSeason.id);
|
||||
const sponsorships = await this.apiClient.getSeasonSponsorships(activeSeason.seasonId);
|
||||
const activeSponsorships = sponsorships.sponsorships.filter((s: any) => s.status === 'active');
|
||||
|
||||
const sponsorInfos: SponsorInfo[] = [];
|
||||
for (const sponsorship of activeSponsorships) {
|
||||
const sponsor = await this.sponsorsApiClient.getSponsor(sponsorship.sponsorId);
|
||||
const sponsorResult = await this.sponsorsApiClient.getSponsor((sponsorship as any).sponsorId ?? (sponsorship as any).sponsor?.id);
|
||||
const sponsor = (sponsorResult as any)?.sponsor ?? null;
|
||||
if (sponsor) {
|
||||
// Tagline is not supplied by the sponsor API in this build; callers may derive one from marketing content if needed
|
||||
sponsorInfos.push({
|
||||
@@ -285,7 +304,7 @@ export class LeagueService {
|
||||
name: sponsor.name,
|
||||
logoUrl: sponsor.logoUrl ?? '',
|
||||
websiteUrl: sponsor.websiteUrl ?? '',
|
||||
tier: sponsorship.tier,
|
||||
tier: ((sponsorship as any).tier as 'main' | 'secondary') ?? 'secondary',
|
||||
tagline: '',
|
||||
});
|
||||
}
|
||||
@@ -312,4 +331,4 @@ export class LeagueService {
|
||||
const result = await this.apiClient.getScoringPresets();
|
||||
return result.presets;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
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 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";
|
||||
|
||||
@@ -36,7 +35,7 @@ export class LeagueSettingsService {
|
||||
|
||||
// Get config
|
||||
const configDto = await this.leaguesApiClient.getLeagueConfig(leagueId);
|
||||
const config: LeagueConfigFormModel = configDto.config;
|
||||
const config: LeagueConfigFormModel = (configDto.form ?? undefined) as unknown as LeagueConfigFormModel;
|
||||
|
||||
// Get presets
|
||||
const presetsDto = await this.leaguesApiClient.getScoringPresets();
|
||||
@@ -102,4 +101,4 @@ export class LeagueSettingsService {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user