resolve manual DTOs

This commit is contained in:
2025-12-18 22:19:40 +01:00
parent 4a3087ae35
commit d617654928
179 changed files with 3716 additions and 1257 deletions

View File

@@ -1,18 +1,8 @@
import { AnalyticsApiClient } from '../../api/analytics/AnalyticsApiClient';
import { RecordPageViewOutputViewModel } from '../../view-models/RecordPageViewOutputViewModel';
import { RecordEngagementOutputViewModel } from '../../view-models/RecordEngagementOutputViewModel';
// TODO: Create proper DTOs in generated types
interface RecordPageViewInputDTO {
path: string;
userId?: string;
}
interface RecordEngagementInputDTO {
eventType: string;
userId?: string;
metadata?: Record<string, unknown>;
}
import { RecordPageViewInputDTO } from '../../types/generated/RecordPageViewInputDTO';
import { RecordEngagementInputDTO } from '../../types/generated/RecordEngagementInputDTO';
/**
* Analytics Service

View File

@@ -1,7 +1,7 @@
import { apiClient } from '@/lib/apiClient';
import { LeagueMembership } from '@/lib/types/LeagueMembership';
import { MembershipRole } from '@/lib/types/MembershipRole';
import { MembershipStatus } from '@/lib/types/MembershipStatus';
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';
export class LeagueMembershipService {
// In-memory cache for memberships (populated via API calls)

View File

@@ -15,7 +15,6 @@ import { LeagueDetailViewModel } from "@/lib/view-models/LeagueDetailViewModel";
import { LeagueDetailPageViewModel, SponsorInfo } from "@/lib/view-models/LeagueDetailPageViewModel";
import { RaceViewModel } from "@/lib/view-models/RaceViewModel";
import { SubmitBlocker, ThrottleBlocker } from "@/lib/blockers";
import { DriverDTO } from "@/lib/types/DriverDTO";
import { RaceDTO } from "@/lib/types/generated/RaceDTO";
import { LeagueScoringConfigDTO } from "@/lib/types/LeagueScoringConfigDTO";
import { LeagueStatsDTO } from "@/lib/types/generated/LeagueStatsDTO";

View File

@@ -1,8 +1,8 @@
import { LeaguesApiClient } from "@/lib/api/leagues/LeaguesApiClient";
import { DriversApiClient } from "@/lib/api/drivers/DriversApiClient";
import type { LeagueConfigFormModel } from "@/lib/types/LeagueConfigFormModel";
import type { LeagueScoringPresetDTO } from "@/lib/types/LeagueScoringPresetDTO";
import type { DriverDTO } from "@/lib/types/DriverDTO";
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 { LeagueSettingsViewModel } from "@/lib/view-models/LeagueSettingsViewModel";
import { DriverSummaryViewModel } from "@/lib/view-models/DriverSummaryViewModel";
@@ -50,7 +50,7 @@ export class LeagueSettingsService {
// TODO: get rating and rank from API
owner = new DriverSummaryViewModel({
driver: ownerDriver,
rating: ownerDriver.rating ?? null,
rating: null, // TODO: get from API
rank: null, // TODO: get from API
});
}
@@ -64,7 +64,7 @@ export class LeagueSettingsService {
if (driver) {
members.push(new DriverSummaryViewModel({
driver,
rating: driver.rating ?? null,
rating: null, // TODO: get from API
rank: null, // TODO: get from API
}));
}

View File

@@ -1,26 +1,23 @@
import { apiClient } from '@/lib/apiClient';
import { LeagueWizardCommandModel } from '@/lib/command-models/leagues/LeagueWizardCommandModel';
import { CreateLeagueResult } from '@/lib/types/CreateLeagueResult';
import { CreateLeagueOutputDTO } from '@/lib/types/generated/CreateLeagueOutputDTO';
export class LeagueWizardService {
static async createLeague(
form: LeagueWizardCommandModel,
ownerId: string,
): Promise<CreateLeagueResult> {
): Promise<CreateLeagueOutputDTO> {
const command = form.toCreateLeagueCommand(ownerId);
const result = await apiClient.leagues.create(command);
return {
leagueId: result.leagueId,
success: result.success,
};
return result;
}
// Static method for backward compatibility
static async createLeagueFromConfig(
form: LeagueWizardCommandModel,
ownerId: string,
): Promise<CreateLeagueResult> {
): Promise<CreateLeagueOutputDTO> {
return this.createLeague(form, ownerId);
}
}

View File

@@ -83,9 +83,9 @@ describe('MediaService', () => {
const expectedOutput = {
id: 'media-123',
url: 'https://example.com/image.jpg',
type: 'image' as const,
category: 'avatar' as const,
uploadedAt: new Date('2023-01-15'),
type: 'image',
category: 'avatar',
uploadedAt: '2023-01-15T00:00:00.000Z',
size: 2048000,
};
mockApiClient.getMedia.mockResolvedValue(expectedOutput);
@@ -98,7 +98,7 @@ describe('MediaService', () => {
expect(result.url).toBe('https://example.com/image.jpg');
expect(result.type).toBe('image');
expect(result.category).toBe('avatar');
expect(result.uploadedAt).toEqual(new Date('2023-01-15'));
expect(result.uploadedAt).toEqual(new Date('2023-01-15T00:00:00.000Z'));
expect(result.size).toBe(2048000);
expect(result.formattedSize).toBe('2000.00 KB');
});
@@ -109,8 +109,8 @@ describe('MediaService', () => {
const expectedOutput = {
id: 'media-456',
url: 'https://example.com/video.mp4',
type: 'video' as const,
uploadedAt: new Date('2023-02-20'),
type: 'video',
uploadedAt: '2023-02-20T00:00:00.000Z',
};
mockApiClient.getMedia.mockResolvedValue(expectedOutput);

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, vi, Mocked } from 'vitest';
import { MembershipFeeService, GetMembershipFeesOutputDto } from './MembershipFeeService';
import { MembershipFeeService } from './MembershipFeeService';
import { PaymentsApiClient } from '../../api/payments/PaymentsApiClient';
import { MembershipFeeViewModel } from '../../view-models';
import type { MembershipFeeDto } from '../../types/generated';
@@ -17,36 +17,30 @@ describe('MembershipFeeService', () => {
});
describe('getMembershipFees', () => {
it('should call apiClient.getMembershipFees with correct leagueId and return mapped view models', async () => {
it('should call apiClient.getMembershipFees with correct leagueId and return fee and payments', async () => {
const leagueId = 'league-123';
const mockFees: MembershipFeeDto[] = [
{ id: 'fee-1', leagueId: 'league-123' },
{ id: 'fee-2', leagueId: 'league-123' },
];
const mockOutput: GetMembershipFeesOutputDto = { fees: mockFees };
const mockFee: MembershipFeeDto = { id: 'fee-1', leagueId: 'league-123', seasonId: undefined, type: 'season', amount: 100, enabled: true, createdAt: new Date(), updatedAt: new Date() };
const mockPayments: any[] = [];
const mockOutput = { fee: mockFee, payments: mockPayments };
mockApiClient.getMembershipFees.mockResolvedValue(mockOutput);
const result = await service.getMembershipFees(leagueId);
expect(mockApiClient.getMembershipFees).toHaveBeenCalledWith(leagueId);
expect(result).toHaveLength(2);
expect(result[0]).toBeInstanceOf(MembershipFeeViewModel);
expect(result[0].id).toEqual('fee-1');
expect(result[0].leagueId).toEqual('league-123');
expect(result[1]).toBeInstanceOf(MembershipFeeViewModel);
expect(result[1].id).toEqual('fee-2');
expect(result[1].leagueId).toEqual('league-123');
expect(mockApiClient.getMembershipFees).toHaveBeenCalledWith({ leagueId });
expect(result.fee).toBeInstanceOf(MembershipFeeViewModel);
expect(result.fee!.id).toEqual('fee-1');
expect(result.payments).toEqual([]);
});
it('should return empty array when no fees are returned', async () => {
it('should return null fee when no fee is returned', async () => {
const leagueId = 'league-456';
const mockOutput: GetMembershipFeesOutputDto = { fees: [] };
const mockOutput = { fee: null, payments: [] };
mockApiClient.getMembershipFees.mockResolvedValue(mockOutput);
const result = await service.getMembershipFees(leagueId);
expect(mockApiClient.getMembershipFees).toHaveBeenCalledWith(leagueId);
expect(result).toEqual([]);
expect(mockApiClient.getMembershipFees).toHaveBeenCalledWith({ leagueId });
expect(result.fee).toBeNull();
});
});
});

View File

@@ -4,7 +4,8 @@ import { PaymentsApiClient } from '../../api/payments/PaymentsApiClient';
// TODO: This DTO should be generated from OpenAPI spec when the endpoint is added
export interface GetMembershipFeesOutputDto {
fees: MembershipFeeDto[];
fee: MembershipFeeDto | null;
payments: import('./MemberPaymentDto').MemberPaymentDto[];
}
/**
@@ -21,8 +22,11 @@ export class MembershipFeeService {
/**
* Get membership fees by league ID with view model transformation
*/
async getMembershipFees(leagueId: string): Promise<MembershipFeeViewModel[]> {
const dto = await this.apiClient.getMembershipFees(leagueId);
return dto.fees.map((fee: MembershipFeeDto) => new MembershipFeeViewModel(fee));
async getMembershipFees(leagueId: string): Promise<{ fee: MembershipFeeViewModel | null; payments: any[] }> {
const dto = await this.apiClient.getMembershipFees({ leagueId });
return {
fee: dto.fee ? new MembershipFeeViewModel(dto.fee) : null,
payments: dto.payments // TODO: map to view models if needed
};
}
}

View File

@@ -42,7 +42,7 @@ describe('PaymentService', () => {
const result = await service.getPayments();
expect(mockApiClient.getPayments).toHaveBeenCalledWith(undefined, undefined);
expect(mockApiClient.getPayments).toHaveBeenCalledWith(undefined);
expect(result).toHaveLength(1);
expect(result[0]).toBeInstanceOf(PaymentViewModel);
expect(result[0].id).toBe('payment-1');
@@ -54,7 +54,7 @@ describe('PaymentService', () => {
await service.getPayments('league-1', 'user-1');
expect(mockApiClient.getPayments).toHaveBeenCalledWith('league-1', 'user-1');
expect(mockApiClient.getPayments).toHaveBeenCalledWith({ leagueId: 'league-1', payerId: 'user-1' });
});
});
@@ -189,7 +189,7 @@ describe('PaymentService', () => {
const result = await service.getPrizes();
expect(mockApiClient.getPrizes).toHaveBeenCalledWith(undefined, undefined);
expect(mockApiClient.getPrizes).toHaveBeenCalledWith(undefined);
expect(result).toHaveLength(1);
expect(result[0]).toBeInstanceOf(PrizeViewModel);
expect(result[0].id).toBe('prize-1');
@@ -201,7 +201,7 @@ describe('PaymentService', () => {
await service.getPrizes('league-1', 'season-1');
expect(mockApiClient.getPrizes).toHaveBeenCalledWith('league-1', 'season-1');
expect(mockApiClient.getPrizes).toHaveBeenCalledWith({ leagueId: 'league-1', seasonId: 'season-1' });
});
});
@@ -232,9 +232,9 @@ describe('PaymentService', () => {
mockApiClient.getWallet.mockResolvedValue(mockResponse);
const result = await service.getWallet('user-1');
const result = await service.getWallet('league-1');
expect(mockApiClient.getWallet).toHaveBeenCalledWith('user-1');
expect(mockApiClient.getWallet).toHaveBeenCalledWith({ leagueId: 'league-1' });
expect(result).toBeInstanceOf(WalletViewModel);
expect(result.id).toBe('wallet-1');
expect(result.balance).toBe(1000);

View File

@@ -31,8 +31,9 @@ export class PaymentService {
/**
* Get all payments with optional filters
*/
async getPayments(leagueId?: string, driverId?: string): Promise<PaymentViewModel[]> {
const dto = await this.apiClient.getPayments(leagueId, driverId);
async getPayments(leagueId?: string, payerId?: string): Promise<PaymentViewModel[]> {
const query = leagueId || payerId ? { leagueId, payerId } : undefined;
const dto = await this.apiClient.getPayments(query);
return dto.payments.map((payment: PaymentDTO) => new PaymentViewModel(payment));
}
@@ -60,8 +61,8 @@ export class PaymentService {
/**
* Get membership fees for a league
*/
async getMembershipFees(leagueId: string): Promise<MembershipFeeViewModel | null> {
const dto = await this.apiClient.getMembershipFees(leagueId);
async getMembershipFees(leagueId: string, driverId?: string): Promise<MembershipFeeViewModel | null> {
const dto = await this.apiClient.getMembershipFees({ leagueId, driverId });
return dto.fee ? new MembershipFeeViewModel(dto.fee) : null;
}
@@ -69,22 +70,23 @@ export class PaymentService {
* Get prizes with optional filters
*/
async getPrizes(leagueId?: string, seasonId?: string): Promise<PrizeViewModel[]> {
const dto = await this.apiClient.getPrizes(leagueId, seasonId);
const query = leagueId || seasonId ? { leagueId, seasonId } : undefined;
const dto = await this.apiClient.getPrizes(query);
return dto.prizes.map((prize: PrizeDto) => new PrizeViewModel(prize));
}
/**
* Get wallet for a driver
* Get wallet for a league
*/
async getWallet(driverId: string): Promise<WalletViewModel> {
const dto = await this.apiClient.getWallet(driverId);
async getWallet(leagueId: string): Promise<WalletViewModel> {
const dto = await this.apiClient.getWallet({ leagueId });
return new WalletViewModel({ ...dto.wallet, transactions: dto.transactions });
}
/**
* Get payment history for a user (driver)
*/
async getPaymentHistory(driverId: string): Promise<PaymentViewModel[]> {
return await this.getPayments(undefined, driverId);
async getPaymentHistory(payerId: string): Promise<PaymentViewModel[]> {
return await this.getPayments(undefined, payerId);
}
}

View File

@@ -42,9 +42,9 @@ describe('WalletService', () => {
mockApiClient.getWallet.mockResolvedValue(mockResponse);
const result = await service.getWallet('user-1');
const result = await service.getWallet('league-1');
expect(mockApiClient.getWallet).toHaveBeenCalledWith('user-1');
expect(mockApiClient.getWallet).toHaveBeenCalledWith({ leagueId: 'league-1' });
expect(result).toBeInstanceOf(WalletViewModel);
expect(result.id).toBe('wallet-1');
expect(result.balance).toBe(1000);
@@ -69,7 +69,7 @@ describe('WalletService', () => {
mockApiClient.getWallet.mockResolvedValue(mockResponse);
const result = await service.getWallet('user-1');
const result = await service.getWallet('league-1');
expect(result.transactions).toHaveLength(0);
});

View File

@@ -102,8 +102,10 @@ describe('RaceResultsService', () => {
const input = { raceId, results: [{ position: 1 }] };
const mockDto = {
success: true,
raceId,
importedCount: 10,
driversProcessed: 10,
resultsRecorded: 10,
errors: ['Error 1'],
};
@@ -114,7 +116,8 @@ describe('RaceResultsService', () => {
expect(mockApiClient.importResults).toHaveBeenCalledWith(raceId, input);
expect(result).toBeInstanceOf(ImportRaceResultsSummaryViewModel);
expect(result.raceId).toBe(raceId);
expect(result.importedCount).toBe(10);
expect(result.driversProcessed).toBe(10);
expect(result.resultsRecorded).toBe(10);
expect(result.errors).toEqual(['Error 1']);
});
@@ -123,8 +126,10 @@ describe('RaceResultsService', () => {
const input = { raceId, results: [] };
const mockDto = {
success: true,
raceId,
importedCount: 5,
driversProcessed: 5,
resultsRecorded: 5,
errors: [],
};
@@ -132,7 +137,8 @@ describe('RaceResultsService', () => {
const result = await service.importResults(raceId, input);
expect(result.importedCount).toBe(5);
expect(result.driversProcessed).toBe(5);
expect(result.resultsRecorded).toBe(5);
expect(result.errors).toEqual([]);
});

View File

@@ -2,15 +2,16 @@ import { RacesApiClient } from '../../api/races/RacesApiClient';
import { RaceResultsDetailViewModel } from '../../view-models/RaceResultsDetailViewModel';
import { RaceWithSOFViewModel } from '../../view-models/RaceWithSOFViewModel';
import { ImportRaceResultsSummaryViewModel } from '../../view-models/ImportRaceResultsSummaryViewModel';
import type { ImportRaceResultsDTO } from '../../types/generated/ImportRaceResultsDTO';
// TODO: Move this type to apps/website/lib/types/generated when available
type ImportRaceResultsInputDto = { raceId: string; results: Array<unknown> };
// TODO: Move this type to apps/website/lib/types/generated when available
// Define types
type ImportRaceResultsInputDto = ImportRaceResultsDTO;
type ImportRaceResultsSummaryDto = {
success: boolean;
raceId: string;
importedCount: number;
errors: string[];
driversProcessed: number;
resultsRecorded: number;
errors?: string[];
};
/**
@@ -41,10 +42,10 @@ export class RaceResultsService {
}
/**
* Import race results and get summary
*/
async importResults(raceId: string, input: ImportRaceResultsInputDto): Promise<ImportRaceResultsSummaryViewModel> {
const dto = await this.apiClient.importResults(raceId, input) as ImportRaceResultsSummaryDto;
return new ImportRaceResultsSummaryViewModel(dto);
}
* Import race results and get summary
*/
async importResults(raceId: string, input: ImportRaceResultsInputDto): Promise<ImportRaceResultsSummaryViewModel> {
const dto = await this.apiClient.importResults(raceId, input);
return new ImportRaceResultsSummaryViewModel(dto);
}
}

View File

@@ -16,6 +16,10 @@ describe('SponsorService', () => {
getSponsorships: vi.fn(),
create: vi.fn(),
getPricing: vi.fn(),
getSponsor: vi.fn(),
getPendingSponsorshipRequests: vi.fn(),
acceptSponsorshipRequest: vi.fn(),
rejectSponsorshipRequest: vi.fn(),
} as Mocked<SponsorsApiClient>;
service = new SponsorService(mockApiClient);

View File

@@ -29,11 +29,16 @@ describe('TeamService', () => {
{
id: 'team-1',
name: 'Test Team',
logoUrl: 'https://example.com/logo.png',
tag: 'TT',
description: 'A test team',
memberCount: 5,
rating: 1500,
leagues: ['league-1'],
specialization: 'endurance' as const,
region: 'EU',
languages: ['en'],
},
],
totalCount: 1,
};
mockApiClient.getAll.mockResolvedValue(mockDto);
@@ -45,6 +50,7 @@ describe('TeamService', () => {
expect(result[0]).toBeInstanceOf(TeamSummaryViewModel);
expect(result[0].id).toBe('team-1');
expect(result[0].name).toBe('Test Team');
expect(result[0].tag).toBe('TT');
});
it('should throw error when apiClient.getAll fails', async () => {
@@ -58,13 +64,24 @@ describe('TeamService', () => {
describe('getTeamDetails', () => {
it('should call apiClient.getDetails and return TeamDetailsViewModel when data exists', async () => {
const mockDto = {
id: 'team-1',
name: 'Test Team',
description: 'A test team',
logoUrl: 'https://example.com/logo.png',
memberCount: 5,
ownerId: 'owner-1',
members: [],
team: {
id: 'team-1',
name: 'Test Team',
tag: 'TT',
description: 'A test team',
ownerId: 'owner-1',
leagues: ['league-1'],
createdAt: '2023-01-01T00:00:00Z',
specialization: 'endurance',
region: 'EU',
languages: ['en'],
},
membership: {
role: 'member',
joinedAt: '2023-01-01T00:00:00Z',
isActive: true,
},
canManage: false,
};
mockApiClient.getDetails.mockResolvedValue(mockDto);
@@ -75,6 +92,7 @@ describe('TeamService', () => {
expect(result).toBeInstanceOf(TeamDetailsViewModel);
expect(result?.id).toBe('team-1');
expect(result?.name).toBe('Test Team');
expect(result?.tag).toBe('TT');
});
it('should return null when apiClient.getDetails returns null', async () => {
@@ -100,11 +118,17 @@ describe('TeamService', () => {
members: [
{
driverId: 'driver-1',
driver: { id: 'driver-1', name: 'Driver One', avatarUrl: 'avatar.png', iracingId: '123', rating: 1400 },
role: 'member',
driverName: 'Driver One',
role: 'member' as const,
joinedAt: '2023-01-01T00:00:00Z',
isActive: true,
avatarUrl: 'avatar.png',
},
],
totalCount: 1,
ownerCount: 0,
managerCount: 0,
memberCount: 1,
};
mockApiClient.getMembers.mockResolvedValue(mockDto);
@@ -176,14 +200,35 @@ describe('TeamService', () => {
describe('getDriverTeam', () => {
it('should call apiClient.getDriverTeam and return the result', async () => {
const mockOutput = { teamId: 'team-1', teamName: 'Test Team', role: 'member' };
const mockOutput = {
team: {
id: 'team-1',
name: 'Test Team',
tag: 'TT',
description: 'A test team',
ownerId: 'owner-1',
leagues: [],
specialization: 'endurance' as const,
region: 'EU',
languages: ['en'],
},
membership: {
role: 'member',
joinedAt: '2023-01-01T00:00:00Z',
isActive: true,
},
isOwner: false,
canManage: false,
};
mockApiClient.getDriverTeam.mockResolvedValue(mockOutput);
const result = await service.getDriverTeam('driver-1');
expect(mockApiClient.getDriverTeam).toHaveBeenCalledWith('driver-1');
expect(result).toEqual(mockOutput);
expect(result?.teamId).toBe('team-1');
expect(result?.teamName).toBe('Test Team');
expect(result?.role).toBe('member');
});
it('should return null when apiClient.getDriverTeam returns null', async () => {

View File

@@ -6,16 +6,15 @@ import { UpdateTeamViewModel } from '@/lib/view-models/UpdateTeamViewModel';
import { DriverTeamViewModel } from '@/lib/view-models/DriverTeamViewModel';
import { LeagueMemberDTO } from '@/lib/types/generated/LeagueMemberDTO';
import type { TeamsApiClient } from '../../api/teams/TeamsApiClient';
// TODO: Move these types to apps/website/lib/types/generated when available
type DriverDTO = { id: string; name: string; avatarUrl?: string; iracingId?: string; rating?: number };
type CreateTeamInputDto = { name: string; tag: string; description?: string };
type CreateTeamOutputDto = { id: string; success: boolean };
type UpdateTeamInputDto = { name?: string; tag?: string; description?: string };
type UpdateTeamOutputDto = { success: boolean };
type DriverTeamDto = { teamId: string; teamName: string; role: string };
type TeamSummaryDTO = { id: string; name: string; logoUrl?: string; memberCount: number; rating: number };
type TeamMemberDTO = { driverId: string; driver?: DriverDTO; role: string; joinedAt: string };
import type { GetAllTeamsOutputDTO, TeamListItemDTO } from '@/lib/types/generated/GetAllTeamsOutputDTO';
import type { GetTeamDetailsOutputDTO } from '@/lib/types/generated/GetTeamDetailsOutputDTO';
import type { GetTeamMembersOutputDTO, TeamMemberDTO } from '@/lib/types/generated/GetTeamMembersOutputDTO';
import type { CreateTeamInputDTO } from '@/lib/types/generated/CreateTeamInputDTO';
import type { CreateTeamOutputDTO } from '@/lib/types/generated/CreateTeamOutputDTO';
import type { UpdateTeamInputDTO } from '@/lib/types/generated/UpdateTeamInputDTO';
import type { UpdateTeamOutputDTO } from '@/lib/types/generated/UpdateTeamOutputDTO';
import type { GetDriverTeamOutputDTO } from '@/lib/types/generated/GetDriverTeamOutputDTO';
import type { GetTeamMembershipOutputDTO } from '@/lib/types/generated/GetTeamMembershipOutputDTO';
/**
* Team Service
@@ -32,15 +31,15 @@ export class TeamService {
* Get all teams with view model transformation
*/
async getAllTeams(): Promise<TeamSummaryViewModel[]> {
const dto = await this.apiClient.getAll();
return dto.teams.map((team: TeamSummaryDTO) => new TeamSummaryViewModel(team));
const dto: GetAllTeamsOutputDTO = await this.apiClient.getAll();
return dto.teams.map((team: TeamListItemDTO) => new TeamSummaryViewModel(team));
}
/**
* Get team details with view model transformation
*/
async getTeamDetails(teamId: string, currentUserId: string): Promise<TeamDetailsViewModel | null> {
const dto = await this.apiClient.getDetails(teamId);
const dto: GetTeamDetailsOutputDTO | null = await this.apiClient.getDetails(teamId);
if (!dto) {
return null;
}
@@ -51,40 +50,40 @@ export class TeamService {
* Get team members with view model transformation
*/
async getTeamMembers(teamId: string, currentUserId: string, teamOwnerId: string): Promise<TeamMemberViewModel[]> {
const dto = await this.apiClient.getMembers(teamId);
const dto: GetTeamMembersOutputDTO = await this.apiClient.getMembers(teamId);
return dto.members.map((member: TeamMemberDTO) => new TeamMemberViewModel(member, currentUserId, teamOwnerId));
}
/**
* Create a new team with view model transformation
*/
async createTeam(input: CreateTeamInputDto): Promise<CreateTeamViewModel> {
const dto = await this.apiClient.create(input);
async createTeam(input: CreateTeamInputDTO): Promise<CreateTeamViewModel> {
const dto: CreateTeamOutputDTO = await this.apiClient.create(input);
return new CreateTeamViewModel(dto);
}
/**
* Update team with view model transformation
*/
async updateTeam(teamId: string, input: UpdateTeamInputDto): Promise<UpdateTeamViewModel> {
const dto = await this.apiClient.update(teamId, input);
async updateTeam(teamId: string, input: UpdateTeamInputDTO): Promise<UpdateTeamViewModel> {
const dto: UpdateTeamOutputDTO = await this.apiClient.update(teamId, input);
return new UpdateTeamViewModel(dto);
}
/**
* Get driver's team with view model transformation
*/
async getDriverTeam(driverId: string): Promise<DriverTeamViewModel | null> {
const dto = await this.apiClient.getDriverTeam(driverId);
return dto ? new DriverTeamViewModel(dto) : null;
}
* Get driver's team with view model transformation
*/
async getDriverTeam(driverId: string): Promise<DriverTeamViewModel | null> {
const dto: GetDriverTeamOutputDTO | null = await this.apiClient.getDriverTeam(driverId);
return dto ? new DriverTeamViewModel(dto) : null;
}
/**
* Get team membership for a driver
*/
async getMembership(teamId: string, driverId: string): Promise<LeagueMemberDTO | null> {
return this.apiClient.getMembership(teamId, driverId);
}
/**
* Get team membership for a driver
*/
async getMembership(teamId: string, driverId: string): Promise<GetTeamMembershipOutputDTO | null> {
return this.apiClient.getMembership(teamId, driverId);
}
/**
* Remove a driver from the team