/** * LeagueAdminPresenter - Pure data transformer * Transforms API responses to view models without DI dependencies. * All data fetching is done via apiClient. */ import { apiClient } from '@/lib/apiClient'; import type { LeagueJoinRequestViewModel as ApiLeagueJoinRequestViewModel, LeagueConfigFormModelDto, LeagueSeasonSummaryViewModel as ApiLeagueSeasonSummaryViewModel, DriverDTO, } from '@/lib/apiClient'; // ============================================================================ // View Model Types // ============================================================================ export interface LeagueJoinRequestViewModel { id: string; leagueId: string; driverId: string; requestedAt: Date; message?: string | undefined; driver?: DriverDTO | undefined; } export interface ProtestDriverSummary { [driverId: string]: DriverDTO; } export interface ProtestRaceSummary { [raceId: string]: { id: string; name: string; scheduledTime: string; }; } export interface LeagueOwnerSummaryViewModel { driver: DriverDTO; rating: number | null; rank: number | null; } export interface LeagueSummaryViewModel { id: string; ownerId: string; settings: { pointsSystem: string; }; } export interface LeagueAdminProtestsViewModel { protests: Array<{ id: string; raceId: string; complainantId: string; defendantId: string; description: string; status: string; createdAt: string; }>; racesById: ProtestRaceSummary; driversById: ProtestDriverSummary; } export interface LeagueAdminConfigViewModel { form: LeagueConfigFormModelDto | null; } export interface LeagueAdminPermissionsViewModel { canRemoveMember: boolean; canUpdateRoles: boolean; } export interface LeagueSeasonSummaryViewModel { seasonId: string; name: string; status: string; startDate?: Date | undefined; endDate?: Date | undefined; isPrimary: boolean; isParallelActive: boolean; } export interface LeagueAdminViewModel { joinRequests: LeagueJoinRequestViewModel[]; ownerSummary: LeagueOwnerSummaryViewModel | null; config: LeagueAdminConfigViewModel; protests: LeagueAdminProtestsViewModel; } export type MembershipRole = 'owner' | 'admin' | 'member'; // ============================================================================ // Data Fetching Functions (using apiClient) // ============================================================================ /** * Load join requests for a league via API. */ export async function loadLeagueJoinRequests(leagueId: string): Promise { const requests = await apiClient.leagues.getJoinRequests(leagueId); return requests.map((request: ApiLeagueJoinRequestViewModel) => { const viewModel: LeagueJoinRequestViewModel = { id: request.id, leagueId: request.leagueId, driverId: request.driverId, requestedAt: new Date(request.requestedAt), }; if (request.message) { viewModel.message = request.message; } return viewModel; }); } /** * Approve a league join request and return updated join requests. */ export async function approveLeagueJoinRequest( leagueId: string, requestId: string ): Promise { await apiClient.leagues.approveJoinRequest(leagueId, requestId); return loadLeagueJoinRequests(leagueId); } /** * Reject a league join request. */ export async function rejectLeagueJoinRequest( leagueId: string, requestId: string ): Promise { await apiClient.leagues.rejectJoinRequest(leagueId, requestId); return loadLeagueJoinRequests(leagueId); } /** * Get permissions for a performer on league membership actions. */ export async function getLeagueAdminPermissions( leagueId: string, performerDriverId: string ): Promise { const permissions = await apiClient.leagues.getAdminPermissions(leagueId, performerDriverId); return { canRemoveMember: permissions.canManageMembers || permissions.isOwner || permissions.isAdmin, canUpdateRoles: permissions.isOwner, }; } /** * Remove a member from the league. */ export async function removeLeagueMember( leagueId: string, performerDriverId: string, targetDriverId: string ): Promise { await apiClient.leagues.removeMember(leagueId, performerDriverId, targetDriverId); } /** * Update a member's role. */ export async function updateLeagueMemberRole( leagueId: string, performerDriverId: string, targetDriverId: string, newRole: MembershipRole ): Promise { await apiClient.leagues.updateMemberRole(leagueId, performerDriverId, targetDriverId, newRole); } /** * Load owner summary for a league. */ export async function loadLeagueOwnerSummary(params: { leagueId: string; ownerId: string; }): Promise { const ownerSummary = await apiClient.leagues.getOwnerSummary(params.leagueId, params.ownerId); if (!ownerSummary) { return null; } // For now, return a simplified version - the API should provide driver details return { driver: { id: params.ownerId, name: ownerSummary.leagueName, // This would need to be populated from API }, rating: null, rank: null, }; } /** * Load league full config form. */ export async function loadLeagueConfig( leagueId: string ): Promise { const config = await apiClient.leagues.getConfig(leagueId); return { form: config, }; } /** * Load protests for a league. */ export async function loadLeagueProtests(leagueId: string): Promise { const protestsData = await apiClient.leagues.getProtests(leagueId); // Transform the API response const racesById: ProtestRaceSummary = {}; const driversById: ProtestDriverSummary = {}; return { protests: protestsData.protests.map((p) => ({ id: p.id, raceId: p.raceId, complainantId: p.complainantId, defendantId: p.defendantId, description: p.description, status: p.status, createdAt: p.createdAt, })), racesById, driversById, }; } /** * Load seasons for a league. */ export async function loadLeagueSeasons(leagueId: string): Promise { const seasons = await apiClient.leagues.getSeasons(leagueId); const activeCount = seasons.filter((s: ApiLeagueSeasonSummaryViewModel) => s.status === 'active').length; return seasons.map((s: ApiLeagueSeasonSummaryViewModel) => { const viewModel: LeagueSeasonSummaryViewModel = { seasonId: s.id, name: s.name, status: s.status, isPrimary: false, // Would need to be provided by API isParallelActive: activeCount > 1 && s.status === 'active', }; if (s.startDate) { viewModel.startDate = new Date(s.startDate); } if (s.endDate) { viewModel.endDate = new Date(s.endDate); } return viewModel; }); }