61 lines
1.4 KiB
TypeScript
61 lines
1.4 KiB
TypeScript
/**
|
|
* TeamRosterPresenter - Pure data transformer
|
|
* Transforms API response to view model without DI dependencies.
|
|
*/
|
|
|
|
import { apiClient } from '@/lib/apiClient';
|
|
|
|
export type TeamRole = 'owner' | 'manager' | 'driver' | 'member';
|
|
|
|
export interface DriverDTO {
|
|
id: string;
|
|
name: string;
|
|
avatarUrl?: string | undefined;
|
|
country?: string | undefined;
|
|
}
|
|
|
|
export interface TeamRosterMemberViewModel {
|
|
driver: DriverDTO;
|
|
role: TeamRole;
|
|
joinedAt: string;
|
|
rating: number | null;
|
|
overallRank: number | null;
|
|
}
|
|
|
|
export interface TeamRosterViewModel {
|
|
members: TeamRosterMemberViewModel[];
|
|
averageRating: number;
|
|
}
|
|
|
|
/**
|
|
* Fetch team roster via API and transform to view model.
|
|
*/
|
|
export async function getTeamRosterViewModel(
|
|
teamId: string
|
|
): Promise<TeamRosterViewModel> {
|
|
const response = await apiClient.teams.getMembers(teamId);
|
|
|
|
const members: TeamRosterMemberViewModel[] = response.members.map((member) => ({
|
|
driver: {
|
|
id: member.driverId,
|
|
name: member.driver?.name ?? 'Unknown',
|
|
avatarUrl: member.driver?.avatarUrl,
|
|
},
|
|
role: (member.role as TeamRole) ?? 'member',
|
|
joinedAt: member.joinedAt,
|
|
rating: null, // Would need from API
|
|
overallRank: null, // Would need from API
|
|
}));
|
|
|
|
const averageRating =
|
|
members.length > 0
|
|
? Math.round(
|
|
members.reduce((sum, m) => sum + (m.rating ?? 0), 0) / members.length
|
|
)
|
|
: 0;
|
|
|
|
return {
|
|
members,
|
|
averageRating,
|
|
};
|
|
} |