website refactor
This commit is contained in:
@@ -21,8 +21,27 @@ import { DomainError, Service } from '@/lib/contracts/services/Service';
|
||||
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
||||
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
|
||||
import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';
|
||||
import { getWebsiteServerEnv } from '@/lib/config/env';
|
||||
import { isProductionEnvironment } from '@/lib/config/env';
|
||||
import { AllLeaguesWithCapacityAndScoringDTO } from '@/lib/types/AllLeaguesWithCapacityAndScoringDTO';
|
||||
import type { LeagueWithCapacityAndScoringDTO } from '@/lib/types/generated/LeagueWithCapacityAndScoringDTO';
|
||||
|
||||
export interface LeagueScheduleAdminData {
|
||||
leagueId: string;
|
||||
seasonId: string;
|
||||
seasons: LeagueSeasonSummaryDTO[];
|
||||
schedule: LeagueScheduleDTO;
|
||||
}
|
||||
|
||||
export interface LeagueRosterAdminData {
|
||||
leagueId: string;
|
||||
members: LeagueRosterMemberDTO[];
|
||||
joinRequests: LeagueRosterJoinRequestDTO[];
|
||||
}
|
||||
|
||||
export interface LeagueDetailData {
|
||||
league: LeagueWithCapacityAndScoringDTO;
|
||||
apiDto: AllLeaguesWithCapacityAndScoringDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
* League Service - DTO Only
|
||||
@@ -40,11 +59,10 @@ export class LeagueService implements Service {
|
||||
constructor() {
|
||||
const baseUrl = getWebsiteApiBaseUrl();
|
||||
const logger = new ConsoleLogger();
|
||||
const { NODE_ENV } = getWebsiteServerEnv();
|
||||
const errorReporter = new EnhancedErrorReporter(logger, {
|
||||
showUserNotifications: false,
|
||||
logToConsole: true,
|
||||
reportToExternal: NODE_ENV === 'production',
|
||||
reportToExternal: isProductionEnvironment(),
|
||||
});
|
||||
this.apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);
|
||||
// Optional clients can be initialized if needed
|
||||
@@ -54,9 +72,73 @@ export class LeagueService implements Service {
|
||||
try {
|
||||
const dto = await this.apiClient.getAllWithCapacityAndScoring();
|
||||
return Result.ok(dto);
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
console.error('LeagueService.getAllLeagues failed:', error);
|
||||
return Result.err({ type: 'serverError', message: 'Failed to fetch leagues' });
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch leagues' });
|
||||
}
|
||||
}
|
||||
|
||||
async getLeagueDetailData(leagueId: string): Promise<Result<LeagueDetailData, DomainError>> {
|
||||
try {
|
||||
const apiDto = await this.apiClient.getAllWithCapacityAndScoring();
|
||||
|
||||
if (!apiDto || !apiDto.leagues) {
|
||||
return Result.err({ type: 'notFound', message: 'Leagues not found' });
|
||||
}
|
||||
|
||||
const league = apiDto.leagues.find(l => l.id === leagueId);
|
||||
if (!league) {
|
||||
return Result.err({ type: 'notFound', message: 'League not found' });
|
||||
}
|
||||
|
||||
return Result.ok({
|
||||
league,
|
||||
apiDto,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
console.error('LeagueService.getLeagueDetailData failed:', error);
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch league detail' });
|
||||
}
|
||||
}
|
||||
|
||||
async getScheduleAdminData(leagueId: string, seasonId?: string): Promise<Result<LeagueScheduleAdminData, DomainError>> {
|
||||
try {
|
||||
const seasons = await this.apiClient.getSeasons(leagueId);
|
||||
|
||||
if (!seasons || seasons.length === 0) {
|
||||
return Result.err({ type: 'notFound', message: 'No seasons found for league' });
|
||||
}
|
||||
|
||||
const targetSeasonId = seasonId || (seasons.find(s => s.status === 'active')?.seasonId || seasons[0].seasonId);
|
||||
const schedule = await this.apiClient.getSchedule(leagueId, targetSeasonId);
|
||||
|
||||
return Result.ok({
|
||||
leagueId,
|
||||
seasonId: targetSeasonId,
|
||||
seasons,
|
||||
schedule,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
console.error('LeagueService.getScheduleAdminData failed:', error);
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch schedule admin data' });
|
||||
}
|
||||
}
|
||||
|
||||
async getRosterAdminData(leagueId: string): Promise<Result<LeagueRosterAdminData, DomainError>> {
|
||||
try {
|
||||
const [members, joinRequests] = await Promise.all([
|
||||
this.apiClient.getAdminRosterMembers(leagueId),
|
||||
this.apiClient.getAdminRosterJoinRequests(leagueId),
|
||||
]);
|
||||
|
||||
return Result.ok({
|
||||
leagueId,
|
||||
members,
|
||||
joinRequests,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
console.error('LeagueService.getRosterAdminData failed:', error);
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch roster data' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,41 +146,76 @@ export class LeagueService implements Service {
|
||||
return Result.err({ type: 'notImplemented', message: 'League standings endpoint not implemented' });
|
||||
}
|
||||
|
||||
async getLeagueStats(): Promise<TotalLeaguesDTO> {
|
||||
return this.apiClient.getTotal();
|
||||
async getLeagueStats(): Promise<Result<TotalLeaguesDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.getTotal();
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch league stats' });
|
||||
}
|
||||
}
|
||||
|
||||
async getLeagueSchedule(leagueId: string): Promise<LeagueScheduleDTO> {
|
||||
return this.apiClient.getSchedule(leagueId);
|
||||
async getLeagueSchedule(leagueId: string): Promise<Result<LeagueScheduleDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.getSchedule(leagueId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch league schedule' });
|
||||
}
|
||||
}
|
||||
|
||||
async getLeagueSeasons(leagueId: string): Promise<LeagueSeasonSummaryDTO[]> {
|
||||
return this.apiClient.getSeasons(leagueId);
|
||||
async getLeagueSeasons(leagueId: string): Promise<Result<LeagueSeasonSummaryDTO[], DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.getSeasons(leagueId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch league seasons' });
|
||||
}
|
||||
}
|
||||
|
||||
async getLeagueSeasonSummaries(leagueId: string): Promise<LeagueSeasonSummaryDTO[]> {
|
||||
return this.apiClient.getSeasons(leagueId);
|
||||
async getLeagueSeasonSummaries(leagueId: string): Promise<Result<LeagueSeasonSummaryDTO[], DomainError>> {
|
||||
return this.getLeagueSeasons(leagueId);
|
||||
}
|
||||
|
||||
async getAdminSchedule(leagueId: string, seasonId: string): Promise<LeagueScheduleDTO> {
|
||||
return this.apiClient.getSchedule(leagueId, seasonId);
|
||||
async getAdminSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueScheduleDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.getSchedule(leagueId, seasonId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch admin schedule' });
|
||||
}
|
||||
}
|
||||
|
||||
async publishAdminSchedule(leagueId: string, seasonId: string): Promise<LeagueSeasonSchedulePublishOutputDTO> {
|
||||
return this.apiClient.publishSeasonSchedule(leagueId, seasonId);
|
||||
async publishAdminSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueSeasonSchedulePublishOutputDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.publishSeasonSchedule(leagueId, seasonId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to publish schedule' });
|
||||
}
|
||||
}
|
||||
|
||||
async unpublishAdminSchedule(leagueId: string, seasonId: string): Promise<LeagueSeasonSchedulePublishOutputDTO> {
|
||||
return this.apiClient.unpublishSeasonSchedule(leagueId, seasonId);
|
||||
async unpublishAdminSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueSeasonSchedulePublishOutputDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.unpublishSeasonSchedule(leagueId, seasonId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to unpublish schedule' });
|
||||
}
|
||||
}
|
||||
|
||||
async createAdminScheduleRace(
|
||||
leagueId: string,
|
||||
seasonId: string,
|
||||
input: { track: string; car: string; scheduledAtIso: string },
|
||||
): Promise<CreateLeagueScheduleRaceOutputDTO> {
|
||||
const payload: CreateLeagueScheduleRaceInputDTO = { ...input, example: '' };
|
||||
return this.apiClient.createSeasonScheduleRace(leagueId, seasonId, payload);
|
||||
): Promise<Result<CreateLeagueScheduleRaceOutputDTO, DomainError>> {
|
||||
try {
|
||||
const payload: CreateLeagueScheduleRaceInputDTO = { ...input, example: '' };
|
||||
const data = await this.apiClient.createSeasonScheduleRace(leagueId, seasonId, payload);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to create race' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateAdminScheduleRace(
|
||||
@@ -106,33 +223,48 @@ export class LeagueService implements Service {
|
||||
seasonId: string,
|
||||
raceId: string,
|
||||
input: Partial<{ track: string; car: string; scheduledAtIso: string }>,
|
||||
): Promise<LeagueScheduleRaceMutationSuccessDTO> {
|
||||
const payload: UpdateLeagueScheduleRaceInputDTO = { ...input, example: '' };
|
||||
return this.apiClient.updateSeasonScheduleRace(leagueId, seasonId, raceId, payload);
|
||||
): Promise<Result<LeagueScheduleRaceMutationSuccessDTO, DomainError>> {
|
||||
try {
|
||||
const payload: UpdateLeagueScheduleRaceInputDTO = { ...input, example: '' };
|
||||
const data = await this.apiClient.updateSeasonScheduleRace(leagueId, seasonId, raceId, payload);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to update race' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteAdminScheduleRace(leagueId: string, seasonId: string, raceId: string): Promise<LeagueScheduleRaceMutationSuccessDTO> {
|
||||
return this.apiClient.deleteSeasonScheduleRace(leagueId, seasonId, raceId);
|
||||
async deleteAdminScheduleRace(leagueId: string, seasonId: string, raceId: string): Promise<Result<LeagueScheduleRaceMutationSuccessDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.deleteSeasonScheduleRace(leagueId, seasonId, raceId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to delete race' });
|
||||
}
|
||||
}
|
||||
|
||||
async getLeagueScheduleDto(leagueId: string, seasonId: string): Promise<LeagueScheduleDTO> {
|
||||
return this.apiClient.getSchedule(leagueId, seasonId);
|
||||
async getLeagueScheduleDto(leagueId: string, seasonId: string): Promise<Result<LeagueScheduleDTO, DomainError>> {
|
||||
return this.getAdminSchedule(leagueId, seasonId);
|
||||
}
|
||||
|
||||
async publishLeagueSeasonSchedule(leagueId: string, seasonId: string): Promise<LeagueSeasonSchedulePublishOutputDTO> {
|
||||
return this.apiClient.publishSeasonSchedule(leagueId, seasonId);
|
||||
async publishLeagueSeasonSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueSeasonSchedulePublishOutputDTO, DomainError>> {
|
||||
return this.publishAdminSchedule(leagueId, seasonId);
|
||||
}
|
||||
|
||||
async unpublishLeagueSeasonSchedule(leagueId: string, seasonId: string): Promise<LeagueSeasonSchedulePublishOutputDTO> {
|
||||
return this.apiClient.unpublishSeasonSchedule(leagueId, seasonId);
|
||||
async unpublishLeagueSeasonSchedule(leagueId: string, seasonId: string): Promise<Result<LeagueSeasonSchedulePublishOutputDTO, DomainError>> {
|
||||
return this.unpublishAdminSchedule(leagueId, seasonId);
|
||||
}
|
||||
|
||||
async createLeagueSeasonScheduleRace(
|
||||
leagueId: string,
|
||||
seasonId: string,
|
||||
input: CreateLeagueScheduleRaceInputDTO,
|
||||
): Promise<CreateLeagueScheduleRaceOutputDTO> {
|
||||
return this.apiClient.createSeasonScheduleRace(leagueId, seasonId, input);
|
||||
): Promise<Result<CreateLeagueScheduleRaceOutputDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.createSeasonScheduleRace(leagueId, seasonId, input);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to create race' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateLeagueSeasonScheduleRace(
|
||||
@@ -140,52 +272,93 @@ export class LeagueService implements Service {
|
||||
seasonId: string,
|
||||
raceId: string,
|
||||
input: UpdateLeagueScheduleRaceInputDTO,
|
||||
): Promise<LeagueScheduleRaceMutationSuccessDTO> {
|
||||
return this.apiClient.updateSeasonScheduleRace(leagueId, seasonId, raceId, input);
|
||||
): Promise<Result<LeagueScheduleRaceMutationSuccessDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.updateSeasonScheduleRace(leagueId, seasonId, raceId, input);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to update race' });
|
||||
}
|
||||
}
|
||||
|
||||
async deleteLeagueSeasonScheduleRace(
|
||||
leagueId: string,
|
||||
seasonId: string,
|
||||
raceId: string,
|
||||
): Promise<LeagueScheduleRaceMutationSuccessDTO> {
|
||||
return this.apiClient.deleteSeasonScheduleRace(leagueId, seasonId, raceId);
|
||||
): Promise<Result<LeagueScheduleRaceMutationSuccessDTO, DomainError>> {
|
||||
return this.deleteAdminScheduleRace(leagueId, seasonId, raceId);
|
||||
}
|
||||
|
||||
async getLeagueMemberships(leagueId: string): Promise<LeagueMembershipsDTO> {
|
||||
return this.apiClient.getMemberships(leagueId);
|
||||
async getLeagueMemberships(leagueId: string): Promise<Result<LeagueMembershipsDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.getMemberships(leagueId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch memberships' });
|
||||
}
|
||||
}
|
||||
|
||||
async createLeague(input: CreateLeagueInputDTO): Promise<CreateLeagueOutputDTO> {
|
||||
return this.apiClient.create(input);
|
||||
async createLeague(input: CreateLeagueInputDTO): Promise<Result<CreateLeagueOutputDTO, DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.create(input);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to create league' });
|
||||
}
|
||||
}
|
||||
|
||||
async removeMember(leagueId: string, targetDriverId: string): Promise<{ success: boolean }> {
|
||||
const dto = await this.apiClient.removeRosterMember(leagueId, targetDriverId);
|
||||
return { success: dto.success };
|
||||
async removeMember(leagueId: string, targetDriverId: string): Promise<Result<{ success: boolean }, DomainError>> {
|
||||
try {
|
||||
const dto = await this.apiClient.removeRosterMember(leagueId, targetDriverId);
|
||||
return Result.ok({ success: dto.success });
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to remove member' });
|
||||
}
|
||||
}
|
||||
|
||||
async updateMemberRole(leagueId: string, targetDriverId: string, newRole: MembershipRole): Promise<{ success: boolean }> {
|
||||
const dto = await this.apiClient.updateRosterMemberRole(leagueId, targetDriverId, newRole);
|
||||
return { success: dto.success };
|
||||
async updateMemberRole(leagueId: string, targetDriverId: string, newRole: MembershipRole): Promise<Result<{ success: boolean }, DomainError>> {
|
||||
try {
|
||||
const dto = await this.apiClient.updateRosterMemberRole(leagueId, targetDriverId, newRole);
|
||||
return Result.ok({ success: dto.success });
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to update member role' });
|
||||
}
|
||||
}
|
||||
|
||||
async getAdminRosterMembers(leagueId: string): Promise<LeagueRosterMemberDTO[]> {
|
||||
return this.apiClient.getAdminRosterMembers(leagueId);
|
||||
async getAdminRosterMembers(leagueId: string): Promise<Result<LeagueRosterMemberDTO[], DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.getAdminRosterMembers(leagueId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch roster members' });
|
||||
}
|
||||
}
|
||||
|
||||
async getAdminRosterJoinRequests(leagueId: string): Promise<LeagueRosterJoinRequestDTO[]> {
|
||||
return this.apiClient.getAdminRosterJoinRequests(leagueId);
|
||||
async getAdminRosterJoinRequests(leagueId: string): Promise<Result<LeagueRosterJoinRequestDTO[], DomainError>> {
|
||||
try {
|
||||
const data = await this.apiClient.getAdminRosterJoinRequests(leagueId);
|
||||
return Result.ok(data);
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to fetch join requests' });
|
||||
}
|
||||
}
|
||||
|
||||
async approveJoinRequest(leagueId: string, joinRequestId: string): Promise<{ success: boolean }> {
|
||||
const dto = await this.apiClient.approveRosterJoinRequest(leagueId, joinRequestId);
|
||||
return { success: dto.success };
|
||||
async approveJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<{ success: boolean }, DomainError>> {
|
||||
try {
|
||||
const dto = await this.apiClient.approveRosterJoinRequest(leagueId, joinRequestId);
|
||||
return Result.ok({ success: dto.success });
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to approve join request' });
|
||||
}
|
||||
}
|
||||
|
||||
async rejectJoinRequest(leagueId: string, joinRequestId: string): Promise<{ success: boolean }> {
|
||||
const dto = await this.apiClient.rejectRosterJoinRequest(leagueId, joinRequestId);
|
||||
return { success: dto.success };
|
||||
async rejectJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<{ success: boolean }, DomainError>> {
|
||||
try {
|
||||
const dto = await this.apiClient.rejectRosterJoinRequest(leagueId, joinRequestId);
|
||||
return Result.ok({ success: dto.success });
|
||||
} catch (error: unknown) {
|
||||
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to reject join request' });
|
||||
}
|
||||
}
|
||||
|
||||
async getLeagueDetail(): Promise<Result<never, DomainError>> {
|
||||
@@ -199,4 +372,4 @@ export class LeagueService implements Service {
|
||||
async getScoringPresets(): Promise<Result<never, DomainError>> {
|
||||
return Result.err({ type: 'notImplemented', message: 'Scoring presets endpoint not implemented' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user