refactor
This commit is contained in:
@@ -1,81 +1,82 @@
|
||||
'use client';
|
||||
|
||||
import type {
|
||||
LeagueMembership as DomainLeagueMembership,
|
||||
MembershipRole,
|
||||
MembershipStatus,
|
||||
} from '@gridpilot/racing/domain/entities/LeagueMembership';
|
||||
import { apiClient } from '@/lib/apiClient';
|
||||
|
||||
/**
|
||||
* Lightweight league membership model mirroring the domain type but with
|
||||
* a stringified joinedAt for easier UI formatting.
|
||||
* Membership role types - these are defined locally to avoid core dependencies
|
||||
*/
|
||||
export interface LeagueMembership extends Omit<DomainLeagueMembership, 'joinedAt'> {
|
||||
export type MembershipRole = 'owner' | 'admin' | 'steward' | 'member';
|
||||
export type MembershipStatus = 'active' | 'inactive' | 'pending';
|
||||
|
||||
/**
|
||||
* Lightweight league membership model for UI.
|
||||
*/
|
||||
export interface LeagueMembership {
|
||||
id: string;
|
||||
leagueId: string;
|
||||
driverId: string;
|
||||
role: MembershipRole;
|
||||
status: MembershipStatus;
|
||||
joinedAt: string;
|
||||
}
|
||||
|
||||
// In-memory cache for memberships (populated via API calls)
|
||||
const leagueMemberships = new Map<string, LeagueMembership[]>();
|
||||
|
||||
/**
|
||||
* Initialize league memberships once from the in-memory league membership repository
|
||||
* that is seeded via the static racing seed in the DI container.
|
||||
*
|
||||
* This avoids depending on raw testing-support seed exports and keeps all demo
|
||||
* membership data flowing through the same in-memory repositories used elsewhere.
|
||||
* Get a specific membership from cache.
|
||||
*/
|
||||
(async function initializeLeagueMembershipsFromRepository() {
|
||||
if (leagueMemberships.size > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { getLeagueRepository, getLeagueMembershipRepository } = await import('./di-container');
|
||||
const leagueRepo = getLeagueRepository();
|
||||
const membershipRepo = getLeagueMembershipRepository();
|
||||
|
||||
const allLeagues = await leagueRepo.findAll();
|
||||
const byLeague = new Map<string, LeagueMembership[]>();
|
||||
|
||||
for (const league of allLeagues) {
|
||||
const memberships = await membershipRepo.getLeagueMembers(league.id);
|
||||
|
||||
const mapped: LeagueMembership[] = memberships.map((membership) => ({
|
||||
id: membership.id,
|
||||
leagueId: membership.leagueId,
|
||||
driverId: membership.driverId,
|
||||
role: membership.role,
|
||||
status: membership.status,
|
||||
joinedAt:
|
||||
membership.joinedAt instanceof Date
|
||||
? membership.joinedAt.toISOString()
|
||||
: new Date().toISOString(),
|
||||
}));
|
||||
|
||||
byLeague.set(league.id, mapped);
|
||||
}
|
||||
|
||||
for (const [leagueId, list] of byLeague.entries()) {
|
||||
leagueMemberships.set(leagueId, list);
|
||||
}
|
||||
} catch (error) {
|
||||
// In alpha/demo mode we tolerate failures here; callers will see empty memberships.
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Failed to initialize league memberships from repository', error);
|
||||
}
|
||||
})();
|
||||
|
||||
export function getMembership(leagueId: string, driverId: string): LeagueMembership | null {
|
||||
const list = leagueMemberships.get(leagueId);
|
||||
if (!list) return null;
|
||||
return list.find((m) => m.driverId === driverId) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all members of a league from cache.
|
||||
*/
|
||||
export function getLeagueMembers(leagueId: string): LeagueMembership[] {
|
||||
return [...(leagueMemberships.get(leagueId) ?? [])];
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a driver's primary league from in-memory league memberships.
|
||||
* Fetch and cache memberships for a league via API.
|
||||
*/
|
||||
export async function 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,
|
||||
}));
|
||||
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).
|
||||
*/
|
||||
export function setLeagueMemberships(leagueId: string, memberships: LeagueMembership[]): void {
|
||||
leagueMemberships.set(leagueId, memberships);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cached memberships for a league.
|
||||
*/
|
||||
export function clearLeagueMemberships(leagueId: string): void {
|
||||
leagueMemberships.delete(leagueId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a driver's primary league from cached memberships.
|
||||
* Prefers any active membership and returns the first matching league.
|
||||
*/
|
||||
export function getPrimaryLeagueIdForDriver(driverId: string): string | null {
|
||||
@@ -87,10 +88,11 @@ export function getPrimaryLeagueIdForDriver(driverId: string): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a driver is owner or admin of a league.
|
||||
*/
|
||||
export function isOwnerOrAdmin(leagueId: string, driverId: string): boolean {
|
||||
const membership = getMembership(leagueId, driverId);
|
||||
if (!membership) return false;
|
||||
return membership.role === 'owner' || membership.role === 'admin';
|
||||
}
|
||||
|
||||
export type { MembershipRole, MembershipStatus };
|
||||
}
|
||||
Reference in New Issue
Block a user