This commit is contained in:
2025-12-18 14:48:37 +01:00
parent b476bb7e99
commit f54fa5de5b
23 changed files with 699 additions and 543 deletions

View File

@@ -1,35 +1,68 @@
import { LeagueMemberDTO } from '@/lib/types/generated/LeagueMemberDTO';
import { LeagueMemberViewModel } from '@/lib/view-models/LeagueMemberViewModel';
import type { LeaguesApiClient } from '../../api/leagues/LeaguesApiClient';
import { apiClient } from '@/lib/apiClient';
import { LeagueMembership } from '@/lib/types/LeagueMembership';
import { MembershipRole } from '@/lib/types/MembershipRole';
import { MembershipStatus } from '@/lib/types/MembershipStatus';
// TODO: Move to generated types when available
type LeagueMembershipsDTO = {
members: LeagueMemberDTO[];
};
/**
* League Membership Service
*
* Orchestrates league membership operations by coordinating API calls and view model creation.
* All dependencies are injected via constructor.
*/
export class LeagueMembershipService {
constructor(
private readonly apiClient: LeaguesApiClient
) {}
// In-memory cache for memberships (populated via API calls)
private static leagueMemberships = new Map<string, LeagueMembership[]>();
/**
* Get league memberships with view model transformation
* Get a specific membership from cache.
*/
async getLeagueMemberships(leagueId: string, currentUserId: string): Promise<LeagueMemberViewModel[]> {
const dto: LeagueMembershipsDTO = await this.apiClient.getMemberships(leagueId);
return dto.members.map((member: LeagueMemberDTO) => new LeagueMemberViewModel(member, currentUserId));
static getMembership(leagueId: string, driverId: string): LeagueMembership | null {
const list = this.leagueMemberships.get(leagueId);
if (!list) return null;
return list.find((m) => m.driverId === driverId) ?? null;
}
/**
* Remove a member from league
* Get all members of a league from cache.
*/
async removeMember(leagueId: string, performerDriverId: string, targetDriverId: string): Promise<{ success: boolean }> {
return await this.apiClient.removeMember(leagueId, performerDriverId, targetDriverId);
static getLeagueMembers(leagueId: string): LeagueMembership[] {
return [...(this.leagueMemberships.get(leagueId) ?? [])];
}
/**
* Fetch and cache memberships for a league via API.
*/
static async fetchLeagueMemberships(leagueId: string): Promise<LeagueMembership[]> {
try {
const result = await apiClient.leagues.getMemberships(leagueId);
const memberships: LeagueMembership[] = result.members.map(member => ({
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
joinedAt: member.joinedAt,
}));
this.setLeagueMemberships(leagueId, memberships);
return memberships;
} catch (error) {
console.error('Failed to fetch league memberships:', error);
return [];
}
}
/**
* Set memberships in cache (for use after API calls).
*/
static setLeagueMemberships(leagueId: string, memberships: LeagueMembership[]): void {
this.leagueMemberships.set(leagueId, memberships);
}
/**
* Clear cached memberships for a league.
*/
static clearLeagueMemberships(leagueId: string): void {
this.leagueMemberships.delete(leagueId);
}
/**
* Get iterator for cached memberships (for utility functions).
*/
static getCachedMembershipsIterator(): IterableIterator<[string, LeagueMembership[]]> {
return this.leagueMemberships.entries();
}
}