code quality
This commit is contained in:
@@ -6,7 +6,7 @@ import { useEffectiveDriverId } from "@/hooks/useEffectiveDriverId";
|
|||||||
import { ApiConnectionMonitor } from '@/lib/gateways/api/base/ApiConnectionMonitor';
|
import { ApiConnectionMonitor } from '@/lib/gateways/api/base/ApiConnectionMonitor';
|
||||||
import { CircuitBreakerRegistry } from '@/lib/gateways/api/base/RetryHandler';
|
import { CircuitBreakerRegistry } from '@/lib/gateways/api/base/RetryHandler';
|
||||||
import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';
|
import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';
|
||||||
import { ChevronUp, Wrench, X } from 'lucide-react';
|
import { ChevronDown, ChevronUp, Wrench, X } from 'lucide-react';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
// Import our new components
|
// Import our new components
|
||||||
|
|||||||
@@ -64,13 +64,18 @@ interface NavigatorWithConnection extends Navigator {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ErrorAnalyticsDashboardProps {
|
||||||
|
refreshInterval?: number;
|
||||||
|
showInProduction?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Comprehensive Error Analytics Dashboard
|
* Comprehensive Error Analytics Dashboard
|
||||||
* Shows real-time error statistics, API metrics, and environment details
|
* Shows real-time error statistics, API metrics, and environment details
|
||||||
*/
|
*/
|
||||||
export function ErrorAnalyticsDashboard({
|
export function ErrorAnalyticsDashboard({
|
||||||
refreshInterval = 5000,
|
refreshInterval = 5000,
|
||||||
showInProduction = false
|
showInProduction = false
|
||||||
}: ErrorAnalyticsDashboardProps) {
|
}: ErrorAnalyticsDashboardProps) {
|
||||||
const [stats, setStats] = useState<ErrorStats | null>(null);
|
const [stats, setStats] = useState<ErrorStats | null>(null);
|
||||||
const [isExpanded, setIsExpanded] = useState(true);
|
const [isExpanded, setIsExpanded] = useState(true);
|
||||||
|
|||||||
@@ -54,13 +54,13 @@ export function LeagueOwnershipTransfer({
|
|||||||
{ownerSummary ? (
|
{ownerSummary ? (
|
||||||
<DriverSummaryPill
|
<DriverSummaryPill
|
||||||
driver={new DriverViewModel({
|
driver={new DriverViewModel({
|
||||||
id: ownerSummary.driver.id,
|
id: ownerSummary.id,
|
||||||
name: ownerSummary.driver.name,
|
name: ownerSummary.name,
|
||||||
avatarUrl: ownerSummary.driver.avatarUrl ?? null,
|
avatarUrl: ownerSummary.avatarUrl ?? null,
|
||||||
iracingId: ownerSummary.driver.iracingId,
|
iracingId: undefined, // Missing in summary
|
||||||
country: ownerSummary.driver.country,
|
country: '—', // Missing in summary
|
||||||
bio: ownerSummary.driver.bio,
|
bio: undefined, // Missing in summary
|
||||||
joinedAt: ownerSummary.driver.joinedAt,
|
joinedAt: '—', // Missing in summary
|
||||||
})}
|
})}
|
||||||
rating={ownerSummary.rating}
|
rating={ownerSummary.rating}
|
||||||
rank={ownerSummary.rank}
|
rank={ownerSummary.rank}
|
||||||
@@ -98,8 +98,8 @@ export function LeagueOwnershipTransfer({
|
|||||||
options={[
|
options={[
|
||||||
{ value: '', label: 'Select new owner...' },
|
{ value: '', label: 'Select new owner...' },
|
||||||
...settings.members.map((member) => ({
|
...settings.members.map((member) => ({
|
||||||
value: member.driver.id,
|
value: member.id,
|
||||||
label: member.driver.name,
|
label: member.name,
|
||||||
})),
|
})),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { LeagueCard } from '@/components/leagues/LeagueCardWrapper';
|
import { LeagueCard } from '@/components/leagues/LeagueCardWrapper';
|
||||||
import { LeagueSummaryViewModelBuilder } from '@/lib/builders/view-models/LeagueSummaryViewModelBuilder';
|
import { LeagueSummaryViewModel } from '@/lib/view-models/LeagueSummaryViewModel';
|
||||||
import { routes } from '@/lib/routing/RouteConfig';
|
import { routes } from '@/lib/routing/RouteConfig';
|
||||||
import type { LeaguesViewData } from '@/lib/view-data/LeaguesViewData';
|
import type { LeaguesViewData } from '@/lib/view-data/LeaguesViewData';
|
||||||
import { Button } from '@/ui/Button';
|
import { Button } from '@/ui/Button';
|
||||||
@@ -129,8 +129,8 @@ export function LeagueSlider({
|
|||||||
hideScrollbar
|
hideScrollbar
|
||||||
>
|
>
|
||||||
{leagues.map((league) => {
|
{leagues.map((league) => {
|
||||||
const viewModel = LeagueSummaryViewModelBuilder.build(league);
|
const viewModel = new LeagueSummaryViewModel(league);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack key={league.id} flexShrink={0} w="320px">
|
<Stack key={league.id} flexShrink={0} w="320px">
|
||||||
<Link href={routes.league.detail(league.id)} block>
|
<Link href={routes.league.detail(league.id)} block>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useInject } from '@/lib/di/hooks/useInject';
|
|||||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||||
import { DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';
|
import { DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||||
import { ApiError } from '@/lib/gateways/api/base/ApiError';
|
import { ApiError } from '@/lib/gateways/api/base/ApiError';
|
||||||
|
import type { ProfileViewData } from '@/lib/view-data/ProfileViewData';
|
||||||
import { DriverProfileViewModel, type DriverProfileViewModelData } from '@/lib/view-models/DriverProfileViewModel';
|
import { DriverProfileViewModel, type DriverProfileViewModelData } from '@/lib/view-models/DriverProfileViewModel';
|
||||||
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
||||||
|
|
||||||
@@ -25,13 +26,13 @@ export function useDriverProfile(
|
|||||||
driver: dto.currentDriver ? {
|
driver: dto.currentDriver ? {
|
||||||
id: dto.currentDriver.id,
|
id: dto.currentDriver.id,
|
||||||
name: dto.currentDriver.name,
|
name: dto.currentDriver.name,
|
||||||
countryCode: dto.currentDriver.countryCode || '',
|
countryCode: dto.currentDriver.country || '',
|
||||||
countryFlag: dto.currentDriver.countryFlag || '',
|
countryFlag: '',
|
||||||
avatarUrl: dto.currentDriver.avatarUrl || '',
|
avatarUrl: dto.currentDriver.avatarUrl || '',
|
||||||
bio: dto.currentDriver.bio || null,
|
bio: dto.currentDriver.bio || null,
|
||||||
iracingId: dto.currentDriver.iracingId || null,
|
iracingId: dto.currentDriver.iracingId || null,
|
||||||
joinedAtLabel: dto.currentDriver.joinedAt || '',
|
joinedAtLabel: dto.currentDriver.joinedAt || '',
|
||||||
globalRankLabel: dto.currentDriver.globalRank || '',
|
globalRankLabel: dto.currentDriver.globalRank?.toString() || '',
|
||||||
} : {
|
} : {
|
||||||
id: '',
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
@@ -44,8 +45,8 @@ export function useDriverProfile(
|
|||||||
globalRankLabel: '',
|
globalRankLabel: '',
|
||||||
},
|
},
|
||||||
stats: dto.stats ? {
|
stats: dto.stats ? {
|
||||||
ratingLabel: dto.stats.rating || '',
|
ratingLabel: dto.stats.rating?.toString() || '',
|
||||||
globalRankLabel: dto.stats.globalRank || '',
|
globalRankLabel: dto.stats.overallRank?.toString() || '',
|
||||||
totalRacesLabel: dto.stats.totalRaces?.toString() || '',
|
totalRacesLabel: dto.stats.totalRaces?.toString() || '',
|
||||||
winsLabel: dto.stats.wins?.toString() || '',
|
winsLabel: dto.stats.wins?.toString() || '',
|
||||||
podiumsLabel: dto.stats.podiums?.toString() || '',
|
podiumsLabel: dto.stats.podiums?.toString() || '',
|
||||||
@@ -85,14 +86,6 @@ export function useDriverProfile(
|
|||||||
icon: a.icon as any,
|
icon: a.icon as any,
|
||||||
rarityLabel: a.rarity || '',
|
rarityLabel: a.rarity || '',
|
||||||
})) || [],
|
})) || [],
|
||||||
friends: dto.extendedProfile.friends?.map(f => ({
|
|
||||||
id: f.id,
|
|
||||||
name: f.name,
|
|
||||||
countryFlag: f.countryFlag || '',
|
|
||||||
avatarUrl: f.avatarUrl || '',
|
|
||||||
href: `/drivers/${f.id}`,
|
|
||||||
})) || [],
|
|
||||||
friendsCountLabel: dto.extendedProfile.friendsCount?.toString() || '',
|
|
||||||
} : null,
|
} : null,
|
||||||
};
|
};
|
||||||
return new DriverProfileViewModel(viewData);
|
return new DriverProfileViewModel(viewData);
|
||||||
|
|||||||
@@ -6,6 +6,11 @@ import type { LeagueWithCapacityAndScoringDTO } from '@/lib/types/generated/Leag
|
|||||||
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
||||||
|
|
||||||
|
|
||||||
|
interface UseLeagueDetailOptions {
|
||||||
|
leagueId: string;
|
||||||
|
queryOptions?: UseQueryOptions<LeagueWithCapacityAndScoringDTO, ApiError>;
|
||||||
|
}
|
||||||
|
|
||||||
interface UseLeagueMembershipsOptions {
|
interface UseLeagueMembershipsOptions {
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
queryOptions?: UseQueryOptions<LeagueMembershipsDTO, ApiError>;
|
queryOptions?: UseQueryOptions<LeagueMembershipsDTO, ApiError>;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import type { WithdrawFromRaceParamsDTO } from '../../../types/generated/Withdra
|
|||||||
import { BaseApiClient } from '../base/BaseApiClient';
|
import { BaseApiClient } from '../base/BaseApiClient';
|
||||||
|
|
||||||
// Define missing types
|
// Define missing types
|
||||||
|
export type { RaceDetailDTO };
|
||||||
export type RacesPageDataDTO = { races: RacesPageDataRaceDTO[] };
|
export type RacesPageDataDTO = { races: RacesPageDataRaceDTO[] };
|
||||||
export type ImportRaceResultsSummaryDTO = {
|
export type ImportRaceResultsSummaryDTO = {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
|||||||
@@ -41,7 +41,17 @@ export class ProtestReviewMutation implements Mutation<ApplyPenaltyCommand | Req
|
|||||||
|
|
||||||
async applyPenalty(input: ApplyPenaltyCommand): Promise<Result<void, DomainError>> {
|
async applyPenalty(input: ApplyPenaltyCommand): Promise<Result<void, DomainError>> {
|
||||||
try {
|
try {
|
||||||
const result = await this.service.applyPenalty(input);
|
const dto = {
|
||||||
|
raceId: input.raceId,
|
||||||
|
driverId: input.accusedDriverId,
|
||||||
|
stewardId: 'system', // Missing in command
|
||||||
|
type: input.penaltyType,
|
||||||
|
value: input.penaltyValue,
|
||||||
|
reason: input.reason,
|
||||||
|
protestId: input.protestId,
|
||||||
|
notes: input.stewardNotes
|
||||||
|
};
|
||||||
|
const result = await this.service.applyPenalty(dto);
|
||||||
if (result.isErr()) {
|
if (result.isErr()) {
|
||||||
return Result.err(result.getError());
|
return Result.err(result.getError());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,14 @@ export class PaymentService implements Service {
|
|||||||
|
|
||||||
async getWallet(leagueId: string): Promise<WalletViewModel> {
|
async getWallet(leagueId: string): Promise<WalletViewModel> {
|
||||||
const data = await this.apiClient.getWallet({ leagueId });
|
const data = await this.apiClient.getWallet({ leagueId });
|
||||||
return new WalletViewModel({ ...data.wallet, transactions: data.transactions });
|
const transactions = data.transactions.map(t => ({
|
||||||
|
...t,
|
||||||
|
type: t.type as any,
|
||||||
|
fee: 0,
|
||||||
|
netAmount: t.amount,
|
||||||
|
date: t.createdAt,
|
||||||
|
status: 'completed' as const
|
||||||
|
}));
|
||||||
|
return new WalletViewModel({ ...data.wallet, transactions });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,14 @@ export class WalletService implements Service {
|
|||||||
|
|
||||||
async getWallet(leagueId: string): Promise<WalletViewModel> {
|
async getWallet(leagueId: string): Promise<WalletViewModel> {
|
||||||
const data = await this.apiClient.getWallet({ leagueId });
|
const data = await this.apiClient.getWallet({ leagueId });
|
||||||
return new WalletViewModel({ ...data.wallet, transactions: data.transactions });
|
const transactions = data.transactions.map(t => ({
|
||||||
|
...t,
|
||||||
|
type: t.type as any,
|
||||||
|
fee: 0, // DTO missing fee
|
||||||
|
netAmount: t.amount, // DTO missing netAmount
|
||||||
|
date: t.createdAt, // Map createdAt to date
|
||||||
|
status: 'completed' as const // DTO missing status
|
||||||
|
}));
|
||||||
|
return new WalletViewModel({ ...data.wallet, transactions });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import { ApiError } from '@/lib/gateways/api/base/ApiError';
|
|||||||
import { RacesApiClient } from '@/lib/gateways/api/races/RacesApiClient';
|
import { RacesApiClient } from '@/lib/gateways/api/races/RacesApiClient';
|
||||||
import { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';
|
import { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';
|
||||||
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
||||||
|
import type { ImportRaceResultsSummaryViewData } from '@/lib/view-data/ImportRaceResultsSummaryViewData';
|
||||||
import { ImportRaceResultsSummaryViewModel } from '@/lib/view-models/ImportRaceResultsSummaryViewModel';
|
import { ImportRaceResultsSummaryViewModel } from '@/lib/view-models/ImportRaceResultsSummaryViewModel';
|
||||||
import { RaceResultsDetailViewModel } from '@/lib/view-models/RaceResultsDetailViewModel';
|
import { RaceResultsDetailViewModel } from '@/lib/view-models/RaceResultsDetailViewModel';
|
||||||
|
import type { RaceWithSOFViewData } from '@/lib/view-data/RaceWithSOFViewData';
|
||||||
import { RaceWithSOFViewModel } from '@/lib/view-models/RaceWithSOFViewModel';
|
import { RaceWithSOFViewModel } from '@/lib/view-models/RaceWithSOFViewModel';
|
||||||
import { injectable, unmanaged } from 'inversify';
|
import { injectable, unmanaged } from 'inversify';
|
||||||
|
|
||||||
@@ -46,14 +48,21 @@ export class RaceResultsService implements Service {
|
|||||||
|
|
||||||
async importResults(raceId: string, input: any): Promise<any> {
|
async importResults(raceId: string, input: any): Promise<any> {
|
||||||
const res = await this.apiClient.importResults(raceId, input);
|
const res = await this.apiClient.importResults(raceId, input);
|
||||||
return new ImportRaceResultsSummaryViewModel(res);
|
const viewData: ImportRaceResultsSummaryViewData = {
|
||||||
|
success: res.success,
|
||||||
|
raceId: res.raceId,
|
||||||
|
driversProcessed: res.driversProcessed,
|
||||||
|
resultsRecorded: res.resultsRecorded,
|
||||||
|
errors: res.errors || [],
|
||||||
|
};
|
||||||
|
return new ImportRaceResultsSummaryViewModel(viewData);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get race results detail
|
* Get race results detail
|
||||||
* Returns results for a specific race
|
* Returns results for a specific race
|
||||||
*/
|
*/
|
||||||
async getRaceResultsDetail(raceId: string): Promise<Result<unknown, DomainError>> {
|
async getRaceResultsDetail(raceId: string): Promise<Result<any, DomainError>> {
|
||||||
try {
|
try {
|
||||||
const data = await this.apiClient.getResultsDetail(raceId);
|
const data = await this.apiClient.getResultsDetail(raceId);
|
||||||
return Result.ok(data);
|
return Result.ok(data);
|
||||||
@@ -78,7 +87,12 @@ export class RaceResultsService implements Service {
|
|||||||
async getWithSOF(raceId: string): Promise<any> {
|
async getWithSOF(raceId: string): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const data = await this.apiClient.getWithSOF(raceId);
|
const data = await this.apiClient.getWithSOF(raceId);
|
||||||
return new RaceWithSOFViewModel(data);
|
const viewData: RaceWithSOFViewData = {
|
||||||
|
id: data.id,
|
||||||
|
track: data.track,
|
||||||
|
strengthOfField: data.strengthOfField ?? null,
|
||||||
|
};
|
||||||
|
return new RaceWithSOFViewModel(viewData);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,17 @@ export class SponsorshipService implements Service {
|
|||||||
async getSponsorSponsorships(sponsorId: string): Promise<SponsorSponsorshipsViewModel | null> {
|
async getSponsorSponsorships(sponsorId: string): Promise<SponsorSponsorshipsViewModel | null> {
|
||||||
const data = await this.apiClient.getSponsorships(sponsorId);
|
const data = await this.apiClient.getSponsorships(sponsorId);
|
||||||
if (!data) return null;
|
if (!data) return null;
|
||||||
return new SponsorSponsorshipsViewModel(data);
|
|
||||||
|
const mappedData = {
|
||||||
|
...data,
|
||||||
|
sponsorships: data.sponsorships.map(s => ({
|
||||||
|
...s,
|
||||||
|
type: 'league', // DTO missing type
|
||||||
|
entityName: s.leagueName, // DTO missing entityName
|
||||||
|
price: s.amount // DTO missing price
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
return new SponsorSponsorshipsViewModel(mappedData as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export interface LeaguesViewData extends ViewData {
|
|||||||
scoring: {
|
scoring: {
|
||||||
gameId: string;
|
gameId: string;
|
||||||
gameName: string;
|
gameName: string;
|
||||||
primaryChampionshipType: string;
|
primaryChampionshipType: 'driver' | 'team' | 'nations' | 'trophy';
|
||||||
scoringPresetId: string;
|
scoringPresetId: string;
|
||||||
scoringPresetName: string;
|
scoringPresetName: string;
|
||||||
dropPolicySummary: string;
|
dropPolicySummary: string;
|
||||||
|
|||||||
@@ -55,13 +55,13 @@ export interface ProfileViewData extends ViewData {
|
|||||||
icon: 'trophy' | 'medal' | 'star' | 'crown' | 'target' | 'zap';
|
icon: 'trophy' | 'medal' | 'star' | 'crown' | 'target' | 'zap';
|
||||||
rarityLabel: string;
|
rarityLabel: string;
|
||||||
}>;
|
}>;
|
||||||
friends: Array<{
|
friends?: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
countryFlag: string;
|
countryFlag: string;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
href: string;
|
href: string;
|
||||||
}>;
|
}>;
|
||||||
friendsCountLabel: string;
|
friendsCountLabel?: string;
|
||||||
} | null;
|
} | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,11 @@ export interface TeamDetailData {
|
|||||||
region?: string;
|
region?: string;
|
||||||
languages?: string[] | null;
|
languages?: string[] | null;
|
||||||
category?: string;
|
category?: string;
|
||||||
membership?: string | null;
|
membership?: {
|
||||||
|
role: string;
|
||||||
|
joinedAt: string;
|
||||||
|
isActive: boolean;
|
||||||
|
} | null;
|
||||||
canManage: boolean;
|
canManage: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ export interface TeamSummaryViewData {
|
|||||||
tag: string;
|
tag: string;
|
||||||
memberCount: number;
|
memberCount: number;
|
||||||
description?: string;
|
description?: string;
|
||||||
totalWins: number;
|
totalWins?: number;
|
||||||
totalRaces: number;
|
totalRaces?: number;
|
||||||
performanceLevel: 'beginner' | 'intermediate' | 'advanced' | 'pro';
|
performanceLevel?: string;
|
||||||
isRecruiting: boolean;
|
isRecruiting: boolean;
|
||||||
specialization: 'endurance' | 'sprint' | 'mixed' | undefined;
|
specialization?: string;
|
||||||
region: string | undefined;
|
region?: string;
|
||||||
languages: string[];
|
languages?: string[];
|
||||||
leagues: string[];
|
leagues?: string[];
|
||||||
logoUrl: string | undefined;
|
logoUrl?: string;
|
||||||
rating: number | undefined;
|
rating?: number;
|
||||||
category: string | undefined;
|
category?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ViewModel } from "../contracts/view-models/ViewModel";
|
|||||||
import { ProfileViewData } from "../view-data/ProfileViewData";
|
import { ProfileViewData } from "../view-data/ProfileViewData";
|
||||||
import { DriverProfileDriverSummaryViewModel } from "./DriverProfileDriverSummaryViewModel";
|
import { DriverProfileDriverSummaryViewModel } from "./DriverProfileDriverSummaryViewModel";
|
||||||
|
|
||||||
export { DriverProfileDriverSummaryViewModel as DriverProfileSocialSummaryViewModel };
|
export { DriverProfileDriverSummaryViewModel };
|
||||||
|
|
||||||
export interface DriverProfileStatsViewModel extends ViewModel {
|
export interface DriverProfileStatsViewModel extends ViewModel {
|
||||||
totalRaces: number;
|
totalRaces: number;
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ import type { DriverSummaryData } from "../view-data/DriverSummaryData";
|
|||||||
* Client-only UI helper built from ViewData.
|
* Client-only UI helper built from ViewData.
|
||||||
*/
|
*/
|
||||||
export class DriverSummaryViewModel extends ViewModel {
|
export class DriverSummaryViewModel extends ViewModel {
|
||||||
constructor(private readonly viewData: DriverSummaryData) {
|
constructor(private readonly viewData: any) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
get id(): string {
|
get id(): string {
|
||||||
return this.viewData.driverId;
|
return this.viewData.driverId || this.viewData.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
get name(): string {
|
get name(): string {
|
||||||
return this.viewData.driverName;
|
return this.viewData.driverName || this.viewData.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
get avatarUrl(): string | null {
|
get avatarUrl(): string | null {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { ViewModel } from "../contracts/view-models/ViewModel";
|
|||||||
import type { LeagueScheduleViewData } from "../view-data/LeagueScheduleViewData";
|
import type { LeagueScheduleViewData } from "../view-data/LeagueScheduleViewData";
|
||||||
import { LeagueScheduleRaceViewModel } from "./LeagueScheduleRaceViewModel";
|
import { LeagueScheduleRaceViewModel } from "./LeagueScheduleRaceViewModel";
|
||||||
|
|
||||||
|
export { LeagueScheduleRaceViewModel };
|
||||||
|
|
||||||
export class LeagueScheduleViewModel extends ViewModel {
|
export class LeagueScheduleViewModel extends ViewModel {
|
||||||
readonly races: LeagueScheduleRaceViewModel[];
|
readonly races: LeagueScheduleRaceViewModel[];
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { ViewModel } from "../contracts/view-models/ViewModel";
|
import { ViewModel } from "../contracts/view-models/ViewModel";
|
||||||
import type { CustomPointsConfig, ScoringConfigurationViewData } from "../view-data/ScoringConfigurationViewData";
|
import type { CustomPointsConfig, ScoringConfigurationViewData } from "../view-data/ScoringConfigurationViewData";
|
||||||
|
|
||||||
|
export type { CustomPointsConfig };
|
||||||
import { LeagueScoringPresetViewModel } from './LeagueScoringPresetViewModel';
|
import { LeagueScoringPresetViewModel } from './LeagueScoringPresetViewModel';
|
||||||
|
|
||||||
export class ScoringConfigurationViewModel extends ViewModel {
|
export class ScoringConfigurationViewModel extends ViewModel {
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ export class TeamSummaryViewModel extends ViewModel {
|
|||||||
get tag(): string { return this.data.tag; }
|
get tag(): string { return this.data.tag; }
|
||||||
get memberCount(): number { return this.data.memberCount; }
|
get memberCount(): number { return this.data.memberCount; }
|
||||||
get description(): string | undefined { return this.data.description; }
|
get description(): string | undefined { return this.data.description; }
|
||||||
get totalWins(): number { return this.data.totalWins; }
|
get totalWins(): number { return this.data.totalWins || 0; }
|
||||||
get totalRaces(): number { return this.data.totalRaces; }
|
get totalRaces(): number { return this.data.totalRaces || 0; }
|
||||||
get performanceLevel(): string { return this.data.performanceLevel; }
|
get performanceLevel(): string { return this.data.performanceLevel || 'beginner'; }
|
||||||
get isRecruiting(): boolean { return this.data.isRecruiting; }
|
get isRecruiting(): boolean { return this.data.isRecruiting; }
|
||||||
get specialization(): string | undefined { return this.data.specialization; }
|
get specialization(): string | undefined { return this.data.specialization; }
|
||||||
get region(): string | undefined { return this.data.region; }
|
get region(): string | undefined { return this.data.region; }
|
||||||
get languages(): string[] { return this.data.languages; }
|
get languages(): string[] { return this.data.languages || []; }
|
||||||
get leagues(): string[] { return this.data.leagues; }
|
get leagues(): string[] { return this.data.leagues || []; }
|
||||||
get logoUrl(): string | undefined { return this.data.logoUrl; }
|
get logoUrl(): string | undefined { return this.data.logoUrl; }
|
||||||
get rating(): number | undefined { return this.data.rating; }
|
get rating(): number | undefined { return this.data.rating; }
|
||||||
get category(): string | undefined { return this.data.category; }
|
get category(): string | undefined { return this.data.category; }
|
||||||
|
|||||||
Reference in New Issue
Block a user