website cleanup
This commit is contained in:
@@ -2,6 +2,7 @@ import { AuthApiClient } from '../../api/auth/AuthApiClient';
|
||||
import { SessionViewModel } from '../../view-models/SessionViewModel';
|
||||
import type { LoginParams } from '../../types/generated/LoginParams';
|
||||
import type { SignupParams } from '../../types/generated/SignupParams';
|
||||
import type { LoginWithIracingCallbackParams } from '../../types/generated/LoginWithIracingCallbackParams';
|
||||
|
||||
/**
|
||||
* Auth Service
|
||||
@@ -55,4 +56,16 @@ export class AuthService {
|
||||
getIracingAuthUrl(returnTo?: string): string {
|
||||
return this.apiClient.getIracingAuthUrl(returnTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Login with iRacing callback
|
||||
*/
|
||||
async loginWithIracingCallback(params: LoginWithIracingCallbackParams): Promise<SessionViewModel> {
|
||||
try {
|
||||
const dto = await this.apiClient.loginWithIracingCallback(params);
|
||||
return new SessionViewModel(dto.user);
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { DriversApiClient } from '../../api/drivers/DriversApiClient';
|
||||
import { DriverRegistrationStatusViewModel } from '../../view-models';
|
||||
import { DriverRegistrationStatusViewModel } from '../../view-models/DriverRegistrationStatusViewModel';
|
||||
|
||||
/**
|
||||
* Driver Registration Service
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { apiClient } from '@/lib/apiClient';
|
||||
import type { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
|
||||
import type { MembershipRole } from '@core/racing/domain/entities/MembershipRole';
|
||||
import type { MembershipStatus } from '@core/racing/domain/entities/MembershipStatus';
|
||||
import type { LeagueMembership } from '@/lib/types/LeagueMembership';
|
||||
|
||||
export class LeagueMembershipService {
|
||||
// In-memory cache for memberships (populated via API calls)
|
||||
@@ -33,12 +31,12 @@ export class LeagueMembershipService {
|
||||
static async fetchLeagueMemberships(leagueId: string): Promise<LeagueMembership[]> {
|
||||
try {
|
||||
const result = await apiClient.leagues.getMemberships(leagueId);
|
||||
const memberships: LeagueMembership[] = result.members.map(member => ({
|
||||
const memberships: LeagueMembership[] = result.members.map((member: any) => ({
|
||||
id: `${member.driverId}-${leagueId}`, // Generate ID since API doesn't provide it
|
||||
leagueId,
|
||||
driverId: member.driverId,
|
||||
role: member.role as MembershipRole,
|
||||
status: 'active' as MembershipStatus, // Assume active since API returns current members
|
||||
role: member.role,
|
||||
status: 'active', // Assume active since API returns current members
|
||||
joinedAt: member.joinedAt,
|
||||
}));
|
||||
this.setLeagueMemberships(leagueId, memberships);
|
||||
@@ -70,6 +68,20 @@ export class LeagueMembershipService {
|
||||
return this.leagueMemberships.entries();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all memberships for a specific driver across all leagues.
|
||||
*/
|
||||
static getAllMembershipsForDriver(driverId: string): LeagueMembership[] {
|
||||
const allMemberships: LeagueMembership[] = [];
|
||||
for (const [leagueId, memberships] of this.leagueMemberships.entries()) {
|
||||
const driverMembership = memberships.find(m => m.driverId === driverId);
|
||||
if (driverMembership) {
|
||||
allMemberships.push(driverMembership);
|
||||
}
|
||||
}
|
||||
return allMemberships;
|
||||
}
|
||||
|
||||
// Instance methods that delegate to static methods for consistency with service pattern
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@ import { DriversApiClient } from "@/lib/api/drivers/DriversApiClient";
|
||||
import { SponsorsApiClient } from "@/lib/api/sponsors/SponsorsApiClient";
|
||||
import { RacesApiClient } from "@/lib/api/races/RacesApiClient";
|
||||
import { CreateLeagueInputDTO } from "@/lib/types/generated/CreateLeagueInputDTO";
|
||||
import { CreateLeagueOutputDTO } from "@/lib/types/generated/CreateLeagueOutputDTO";
|
||||
import { LeagueWithCapacityDTO } from "@/lib/types/generated/LeagueWithCapacityDTO";
|
||||
import { CreateLeagueViewModel } from "@/lib/view-models/CreateLeagueViewModel";
|
||||
import { LeagueMembershipsViewModel } from "@/lib/view-models/LeagueMembershipsViewModel";
|
||||
@@ -11,14 +12,12 @@ import { LeagueStandingsViewModel } from "@/lib/view-models/LeagueStandingsViewM
|
||||
import { LeagueStatsViewModel } from "@/lib/view-models/LeagueStatsViewModel";
|
||||
import { LeagueSummaryViewModel } from "@/lib/view-models/LeagueSummaryViewModel";
|
||||
import { RemoveMemberViewModel } from "@/lib/view-models/RemoveMemberViewModel";
|
||||
import { LeagueDetailViewModel } from "@/lib/view-models/LeagueDetailViewModel";
|
||||
import { LeaguePageDetailViewModel } from "@/lib/view-models/LeaguePageDetailViewModel";
|
||||
import { LeagueDetailPageViewModel, SponsorInfo } from "@/lib/view-models/LeagueDetailPageViewModel";
|
||||
import { RaceViewModel } from "@/lib/view-models/RaceViewModel";
|
||||
import { SubmitBlocker, ThrottleBlocker } from "@/lib/blockers";
|
||||
import { RaceDTO } from "@/lib/types/generated/RaceDTO";
|
||||
import { LeagueScoringConfigDTO } from "@/lib/types/LeagueScoringConfigDTO";
|
||||
import { LeagueStatsDTO } from "@/lib/types/generated/LeagueStatsDTO";
|
||||
import { LeagueMembershipsDTO } from "@/lib/types/generated/LeagueMembershipsDTO";
|
||||
|
||||
|
||||
/**
|
||||
@@ -43,7 +42,17 @@ export class LeagueService {
|
||||
*/
|
||||
async getAllLeagues(): Promise<LeagueSummaryViewModel[]> {
|
||||
const dto = await this.apiClient.getAllWithCapacity();
|
||||
return dto.leagues.map((league: LeagueWithCapacityDTO) => new LeagueSummaryViewModel(league));
|
||||
return dto.leagues.map((league: LeagueWithCapacityDTO) => ({
|
||||
id: league.id,
|
||||
name: league.name,
|
||||
description: league.description ?? '',
|
||||
ownerId: league.ownerId,
|
||||
createdAt: '', // Not provided by API
|
||||
maxDrivers: league.maxMembers,
|
||||
usedDriverSlots: league.memberCount,
|
||||
structureSummary: 'TBD',
|
||||
timingSummary: 'TBD'
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +66,8 @@ export class LeagueService {
|
||||
const membershipsDto = await this.apiClient.getMemberships(leagueId);
|
||||
|
||||
// Resolve unique drivers that appear in standings
|
||||
const driverIds = Array.from(new Set(dto.standings.map(entry => entry.driverId)));
|
||||
const driverDtos = await Promise.all(driverIds.map(id => this.driversApiClient.getDriver(id)));
|
||||
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 = {
|
||||
@@ -95,15 +104,17 @@ export class LeagueService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new league
|
||||
*/
|
||||
async createLeague(input: CreateLeagueInputDTO): Promise<void> {
|
||||
if (!this.submitBlocker.canExecute() || !this.throttle.canExecute()) return;
|
||||
* Create a new league
|
||||
*/
|
||||
async createLeague(input: CreateLeagueInputDTO): Promise<CreateLeagueOutputDTO> {
|
||||
if (!this.submitBlocker.canExecute() || !this.throttle.canExecute()) {
|
||||
throw new Error('Cannot execute at this time');
|
||||
}
|
||||
|
||||
this.submitBlocker.block();
|
||||
this.throttle.block();
|
||||
try {
|
||||
await this.apiClient.create(input);
|
||||
return await this.apiClient.create(input);
|
||||
} finally {
|
||||
this.submitBlocker.release();
|
||||
}
|
||||
@@ -127,12 +138,12 @@ export class LeagueService {
|
||||
/**
|
||||
* Get league detail with owner, membership, and sponsor info
|
||||
*/
|
||||
async getLeagueDetail(leagueId: string, currentDriverId: string): Promise<LeagueDetailViewModel | null> {
|
||||
async getLeagueDetail(leagueId: string, currentDriverId: string): Promise<LeaguePageDetailViewModel | null> {
|
||||
// For now, assume league data comes from getAllWithCapacity or a new endpoint
|
||||
// Since API may not have detailed league, we'll mock or assume
|
||||
// In real implementation, add getLeagueDetail to API
|
||||
const allLeagues = await this.apiClient.getAllWithCapacity();
|
||||
const leagueDto = allLeagues.leagues.find(l => l.id === leagueId);
|
||||
const leagueDto = allLeagues.leagues.find((l: any) => l.id === leagueId);
|
||||
if (!leagueDto) return null;
|
||||
|
||||
// LeagueWithCapacityDTO already carries core fields; fall back to placeholder description/owner when not provided
|
||||
@@ -149,7 +160,7 @@ export class LeagueService {
|
||||
|
||||
// Get membership
|
||||
const membershipsDto = await this.apiClient.getMemberships(leagueId);
|
||||
const membership = membershipsDto.members.find(m => m.driverId === currentDriverId);
|
||||
const membership = membershipsDto.members.find((m: any) => m.driverId === currentDriverId);
|
||||
const isAdmin = membership ? ['admin', 'owner'].includes(membership.role) : false;
|
||||
|
||||
// Get main sponsor
|
||||
@@ -175,15 +186,31 @@ export class LeagueService {
|
||||
console.warn('Failed to load main sponsor:', error);
|
||||
}
|
||||
|
||||
return new LeagueDetailViewModel(
|
||||
league.id,
|
||||
league.name,
|
||||
league.description,
|
||||
league.ownerId,
|
||||
ownerName,
|
||||
mainSponsor,
|
||||
isAdmin
|
||||
);
|
||||
return new LeaguePageDetailViewModel({
|
||||
league: {
|
||||
id: league.id,
|
||||
name: league.name,
|
||||
game: 'iRacing',
|
||||
tier: 'standard',
|
||||
season: 'Season 1',
|
||||
description: league.description,
|
||||
drivers: 0,
|
||||
races: 0,
|
||||
completedRaces: 0,
|
||||
totalImpressions: 0,
|
||||
avgViewsPerRace: 0,
|
||||
engagement: 0,
|
||||
rating: 0,
|
||||
seasonStatus: 'active',
|
||||
seasonDates: { start: new Date().toISOString(), end: new Date().toISOString() },
|
||||
sponsorSlots: {
|
||||
main: { available: true, price: 800, benefits: [] },
|
||||
secondary: { available: 2, total: 2, price: 250, benefits: [] }
|
||||
}
|
||||
},
|
||||
drivers: [],
|
||||
races: []
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +220,7 @@ export class LeagueService {
|
||||
try {
|
||||
// Get league basic info
|
||||
const allLeagues = await this.apiClient.getAllWithCapacity();
|
||||
const league = allLeagues.leagues.find(l => l.id === leagueId);
|
||||
const league = allLeagues.leagues.find((l: any) => l.id === leagueId);
|
||||
if (!league) return null;
|
||||
|
||||
// Get owner
|
||||
@@ -206,7 +233,7 @@ export class LeagueService {
|
||||
const memberships = await this.apiClient.getMemberships(leagueId);
|
||||
const driverIds = memberships.members.map(m => m.driverId);
|
||||
const driverDtos = await Promise.all(driverIds.map(id => this.driversApiClient.getDriver(id)));
|
||||
const drivers = driverDtos.filter((d): d is NonNullable<typeof d> => d !== null);
|
||||
const drivers = driverDtos.filter((d: any): d is NonNullable<typeof d> => d !== null);
|
||||
|
||||
// Get all races for this league via the leagues API helper
|
||||
const leagueRaces = await this.apiClient.getRaces(leagueId);
|
||||
@@ -276,4 +303,12 @@ export class LeagueService {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get league scoring presets
|
||||
*/
|
||||
async getScoringPresets(): Promise<any[]> {
|
||||
const result = await this.apiClient.getScoringPresets();
|
||||
return result.presets;
|
||||
}
|
||||
}
|
||||
@@ -54,4 +54,18 @@ export class MediaService {
|
||||
getDriverAvatar(driverId: string): string {
|
||||
return `/api/media/avatar/${driverId}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get league cover URL
|
||||
*/
|
||||
getLeagueCover(leagueId: string): string {
|
||||
return `/api/media/leagues/${leagueId}/cover`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get league logo URL
|
||||
*/
|
||||
getLeagueLogo(leagueId: string): string {
|
||||
return `/api/media/leagues/${leagueId}/logo`;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import type { SponsorsApiClient } from '../../api/sponsors/SponsorsApiClient';
|
||||
import type { GetEntitySponsorshipPricingResultDto } from '../../api/sponsors/SponsorsApiClient';
|
||||
import {
|
||||
SponsorshipPricingViewModel,
|
||||
SponsorSponsorshipsViewModel,
|
||||
SponsorshipRequestViewModel
|
||||
} from '../../view-models';
|
||||
import { SponsorshipPricingViewModel } from '../../view-models/SponsorshipPricingViewModel';
|
||||
import { SponsorSponsorshipsViewModel } from '../../view-models/SponsorSponsorshipsViewModel';
|
||||
import { SponsorshipRequestViewModel } from '../../view-models/SponsorshipRequestViewModel';
|
||||
import type { SponsorSponsorshipsDTO } from '../../types/generated';
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user