website refactor

This commit is contained in:
2026-01-16 01:00:03 +01:00
parent ce7be39155
commit a98e3e3166
286 changed files with 5522 additions and 5261 deletions

View File

@@ -3,8 +3,6 @@
*/
import { EventEmitter } from 'events';
import { ApiError } from './ApiError';
import { CircuitBreakerRegistry } from './RetryHandler';
export type ConnectionStatus = 'connected' | 'disconnected' | 'degraded' | 'checking';

View File

@@ -167,7 +167,7 @@ export class BaseApiClient {
/**
* Get developer-friendly hint for troubleshooting
*/
private getDeveloperHint(error: Error, path: string, method: string): string {
private getDeveloperHint(error: Error, _path: string, _method: string): string {
if (error.message.includes('fetch failed') || error.message.includes('Failed to fetch')) {
return 'Check if API server is running and CORS is configured correctly';
}
@@ -183,7 +183,7 @@ export class BaseApiClient {
/**
* Get troubleshooting context for network errors
*/
private getTroubleshootingContext(error: Error, path: string): string {
private getTroubleshootingContext(error: Error, _path: string): string {
if (typeof window !== 'undefined') {
const baseUrl = this.baseUrl;
const currentOrigin = window.location.origin;

View File

@@ -37,7 +37,7 @@ export interface CacheEntry<T> {
* Simple in-memory cache for API responses
*/
class ResponseCache {
private cache = new Map<string, CacheEntry<any>>();
private cache = new Map<string, CacheEntry<unknown>>();
/**
* Get cached data if not expired
@@ -46,20 +46,20 @@ class ResponseCache {
const entry = this.cache.get(key);
if (!entry) return null;
if (new Date() > entry.expiry) {
if (new globalThis.Date() > entry.expiry) {
this.cache.delete(key);
return null;
}
return entry.data;
return entry.data as T;
}
/**
* Set cached data with expiry
*/
set<T>(key: string, data: T, ttlMs: number = 300000): void {
const now = new Date();
const expiry = new Date(now.getTime() + ttlMs);
const now = new globalThis.Date();
const expiry = new globalThis.Date(now.getTime() + ttlMs);
this.cache.set(key, {
data,
@@ -133,7 +133,7 @@ export async function withGracefulDegradation<T>(
'API unavailable and no fallback provided',
'NETWORK_ERROR',
{
timestamp: new Date().toISOString(),
timestamp: new globalThis.Date().toISOString(),
}
);
}

View File

@@ -2,7 +2,7 @@
* Retry logic and circuit breaker for API requests
*/
import { ApiError, ApiErrorType } from './ApiError';
import { ApiError } from './ApiError';
export interface RetryConfig {
maxRetries: number;

View File

@@ -1,67 +0,0 @@
import { LeaguesApiClient } from './leagues/LeaguesApiClient';
import { RacesApiClient } from './races/RacesApiClient';
import { DriversApiClient } from './drivers/DriversApiClient';
import { TeamsApiClient } from './teams/TeamsApiClient';
import { SponsorsApiClient } from './sponsors/SponsorsApiClient';
import { MediaApiClient } from './media/MediaApiClient';
import { AnalyticsApiClient } from './analytics/AnalyticsApiClient';
import { AuthApiClient } from './auth/AuthApiClient';
import { PaymentsApiClient } from './payments/PaymentsApiClient';
import { DashboardApiClient } from './dashboard/DashboardApiClient';
import { PenaltiesApiClient } from './penalties/PenaltiesApiClient';
import { ProtestsApiClient } from './protests/ProtestsApiClient';
import { AdminApiClient } from './admin/AdminApiClient';
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
/**
* Main API Client
*
* Orchestrates all domain-specific API clients with consistent configuration.
*/
export class ApiClient {
public readonly leagues: LeaguesApiClient;
public readonly races: RacesApiClient;
public readonly drivers: DriversApiClient;
public readonly teams: TeamsApiClient;
public readonly sponsors: SponsorsApiClient;
public readonly media: MediaApiClient;
public readonly analytics: AnalyticsApiClient;
public readonly auth: AuthApiClient;
public readonly payments: PaymentsApiClient;
public readonly dashboard: DashboardApiClient;
public readonly penalties: PenaltiesApiClient;
public readonly protests: ProtestsApiClient;
public readonly admin: AdminApiClient;
constructor(baseUrl: string) {
const logger = new ConsoleLogger();
const errorReporter = new EnhancedErrorReporter(logger, {
showUserNotifications: true,
logToConsole: true,
reportToExternal: process.env.NODE_ENV === 'production',
});
this.leagues = new LeaguesApiClient(baseUrl, errorReporter, logger);
this.races = new RacesApiClient(baseUrl, errorReporter, logger);
this.drivers = new DriversApiClient(baseUrl, errorReporter, logger);
this.teams = new TeamsApiClient(baseUrl, errorReporter, logger);
this.sponsors = new SponsorsApiClient(baseUrl, errorReporter, logger);
this.media = new MediaApiClient(baseUrl, errorReporter, logger);
this.analytics = new AnalyticsApiClient(baseUrl, errorReporter, logger);
this.auth = new AuthApiClient(baseUrl, errorReporter, logger);
this.payments = new PaymentsApiClient(baseUrl, errorReporter, logger);
this.dashboard = new DashboardApiClient(baseUrl, errorReporter, logger);
this.penalties = new PenaltiesApiClient(baseUrl, errorReporter, logger);
this.protests = new ProtestsApiClient(baseUrl, errorReporter, logger);
this.admin = new AdminApiClient(baseUrl, errorReporter, logger);
}
}
// ============================================================================
// Singleton Instance
// ============================================================================
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
export const api = new ApiClient(API_BASE_URL);

View File

@@ -134,7 +134,7 @@ export class LeaguesApiClient extends BaseApiClient {
seasonId: string,
input: CreateLeagueScheduleRaceInputDTO,
): Promise<CreateLeagueScheduleRaceOutputDTO> {
const { example: _example, ...payload } = input;
const { example: _, ...payload } = input;
return this.post<CreateLeagueScheduleRaceOutputDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/races`, payload);
}
@@ -145,7 +145,7 @@ export class LeaguesApiClient extends BaseApiClient {
raceId: string,
input: UpdateLeagueScheduleRaceInputDTO,
): Promise<LeagueScheduleRaceMutationSuccessDTO> {
const { example: _example, ...payload } = input;
const { example: _, ...payload } = input;
return this.patch<LeagueScheduleRaceMutationSuccessDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/races/${raceId}`, payload);
}

View File

@@ -46,7 +46,6 @@ type UpdateMemberPaymentInputDto = {
paidAt?: Date | string;
};
type UpdateMemberPaymentOutputDto = { payment: MemberPaymentDTO };
type GetWalletTransactionsOutputDto = { transactions: TransactionDTO[] };
type UpdatePaymentStatusOutputDto = { payment: PaymentDTO };
type UpsertMembershipFeeInputDto = {
leagueId: string;
@@ -70,7 +69,6 @@ type AwardPrizeInputDto = {
driverId: string;
};
type AwardPrizeOutputDto = { prize: PrizeDTO };
type DeletePrizeInputDto = { prizeId: string };
type DeletePrizeOutputDto = { success: boolean };
/**

View File

@@ -12,8 +12,6 @@ import type { RaceDetailEntryDTO } from '../../types/generated/RaceDetailEntryDT
import type { RaceDetailRegistrationDTO } from '../../types/generated/RaceDetailRegistrationDTO';
import type { RaceDetailUserResultDTO } from '../../types/generated/RaceDetailUserResultDTO';
import type { FileProtestCommandDTO } from '../../types/generated/FileProtestCommandDTO';
import type { AllRacesPageDTO } from '../../types/generated/AllRacesPageDTO';
import type { FilteredRacesPageDataDTO } from '../../types/tbd/FilteredRacesPageDataDTO';
// Define missing types
export type RacesPageDataDTO = { races: RacesPageDataRaceDTO[] };

View File

@@ -66,22 +66,29 @@ export class SponsorsApiClient extends BaseApiClient {
/** Get sponsor billing information */
getBilling(sponsorId: string): Promise<{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
paymentMethods: any[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
invoices: any[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
stats: any;
}> {
return this.get(`/sponsors/billing/${sponsorId}`);
}
/** Get available leagues for sponsorship */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getAvailableLeagues(): Promise<any[]> {
return this.get('/sponsors/leagues/available');
}
/** Get detailed league information */
getLeagueDetail(leagueId: string): Promise<{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
league: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
drivers: any[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
races: any[];
}> {
return this.get(`/sponsors/leagues/${leagueId}/detail`);
@@ -89,14 +96,18 @@ export class SponsorsApiClient extends BaseApiClient {
/** Get sponsor settings */
getSettings(sponsorId: string): Promise<{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
profile: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
notifications: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
privacy: any;
}> {
return this.get(`/sponsors/settings/${sponsorId}`);
}
/** Update sponsor settings */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
updateSettings(sponsorId: string, input: any): Promise<void> {
return this.put(`/sponsors/settings/${sponsorId}`, input);
}

View File

@@ -1,4 +1,3 @@
import { LeagueMemberDTO } from '@/lib/types/generated/LeagueMemberDTO';
import type { GetAllTeamsOutputDTO } from '@/lib/types/generated/GetAllTeamsOutputDTO';
import type { GetTeamDetailsOutputDTO } from '@/lib/types/generated/GetTeamDetailsOutputDTO';
import type { GetTeamMembersOutputDTO } from '@/lib/types/generated/GetTeamMembersOutputDTO';