website refactor

This commit is contained in:
2026-01-14 10:51:05 +01:00
parent 4522d41aef
commit 0d89ad027e
291 changed files with 6887 additions and 3685 deletions

View File

@@ -1,6 +1,7 @@
import { AdminService } from '@/lib/services/admin/AdminService';
import { Result } from '@/lib/contracts/Result';
import { MutationError, mapToMutationError } from '@/lib/contracts/mutations/MutationError';
import { Mutation } from '@/lib/contracts/mutations/Mutation';
/**
* DeleteUserMutation
@@ -13,7 +14,7 @@ import { MutationError, mapToMutationError } from '@/lib/contracts/mutations/Mut
*
* Pattern: Server Action → Mutation → Service → API Client
*/
export class DeleteUserMutation {
export class DeleteUserMutation implements Mutation<{ userId: string }, void, MutationError> {
async execute(input: { userId: string }): Promise<Result<void, MutationError>> {
try {
// Manual construction: Service creates its own dependencies

View File

@@ -1,6 +1,7 @@
import { AdminService } from '@/lib/services/admin/AdminService';
import { Result } from '@/lib/contracts/Result';
import { MutationError, mapToMutationError } from '@/lib/contracts/mutations/MutationError';
import { Mutation } from '@/lib/contracts/mutations/Mutation';
/**
* UpdateUserStatusMutation
@@ -13,7 +14,7 @@ import { MutationError, mapToMutationError } from '@/lib/contracts/mutations/Mut
*
* Pattern: Server Action → Mutation → Service → API Client
*/
export class UpdateUserStatusMutation {
export class UpdateUserStatusMutation implements Mutation<{ userId: string; status: string }, void, MutationError> {
async execute(input: { userId: string; status: string }): Promise<Result<void, MutationError>> {
try {
// Manual construction: Service creates its own dependencies

View File

@@ -0,0 +1,24 @@
/**
* Logout Mutation
*
* Framework-agnostic mutation for logout operations.
* Called from Server Actions.
*
* Pattern: Server Action → Mutation → Service → API Client
*/
import { Result } from '@/lib/contracts/Result';
import { AuthService } from '@/lib/services/auth/AuthService';
export class LogoutMutation {
async execute(): Promise<Result<void, string>> {
try {
const authService = new AuthService();
await authService.logout();
return Result.ok(undefined);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Logout failed';
return Result.err(errorMessage);
}
}
}

View File

@@ -8,7 +8,7 @@ import type { CreateLeagueInputDTO } from '@/lib/types/generated/CreateLeagueInp
/**
* CreateLeagueMutation
*
* Framework-agnostic mutation for league creation.
* Framework-agnostic mutation for creating leagues.
* Can be called from Server Actions or other contexts.
*/
export class CreateLeagueMutation {
@@ -24,12 +24,12 @@ export class CreateLeagueMutation {
this.service = new LeagueService(apiClient);
}
async createLeague(input: CreateLeagueInputDTO): Promise<Result<void, string>> {
async execute(input: CreateLeagueInputDTO): Promise<Result<string, string>> {
try {
await this.service.createLeague(input);
return Result.ok(undefined);
const result = await this.service.createLeague(input);
return Result.ok(result.leagueId);
} catch (error) {
console.error('createLeague failed:', error);
console.error('CreateLeagueMutation failed:', error);
return Result.err('Failed to create league');
}
}

View File

@@ -0,0 +1,80 @@
import { Result } from '@/lib/contracts/Result';
import { LeagueService } from '@/lib/services/leagues/LeagueService';
import { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';
import { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
/**
* StewardingMutation
*
* Framework-agnostic mutation for stewarding operations.
* Can be called from Server Actions or other contexts.
*/
export class StewardingMutation {
private service: LeagueService;
constructor() {
// Manual wiring for serverless
const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';
const errorReporter = new ConsoleErrorReporter();
const logger = new ConsoleLogger();
const apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);
this.service = new LeagueService(apiClient);
}
async applyPenalty(input: {
protestId: string;
penaltyType: string;
penaltyValue: number;
stewardNotes: string;
raceId: string;
accusedDriverId: string;
reason: string;
}): Promise<Result<void, string>> {
try {
// TODO: Implement when penalty API is available
// For now, return success
console.log('applyPenalty called with:', input);
return Result.ok(undefined);
} catch (error) {
console.error('applyPenalty failed:', error);
return Result.err('Failed to apply penalty');
}
}
async requestDefense(input: {
protestId: string;
stewardId: string;
}): Promise<Result<void, string>> {
try {
// TODO: Implement when defense API is available
// For now, return success
console.log('requestDefense called with:', input);
return Result.ok(undefined);
} catch (error) {
console.error('requestDefense failed:', error);
return Result.err('Failed to request defense');
}
}
async quickPenalty(input: {
leagueId: string;
driverId: string;
raceId: string;
penaltyType: string;
penaltyValue: number;
reason: string;
adminId: string;
}): Promise<Result<void, string>> {
try {
// TODO: Implement when quick penalty API is available
// For now, return success
console.log('quickPenalty called with:', input);
return Result.ok(undefined);
} catch (error) {
console.error('quickPenalty failed:', error);
return Result.err('Failed to apply quick penalty');
}
}
}

View File

@@ -0,0 +1,49 @@
import { Result } from '@/lib/contracts/Result';
import { LeagueService } from '@/lib/services/leagues/LeagueService';
import { LeaguesApiClient } from '@/lib/api/leagues/LeaguesApiClient';
import { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
/**
* WalletMutation
*
* Framework-agnostic mutation for wallet operations.
* Can be called from Server Actions or other contexts.
*/
export class WalletMutation {
private service: LeagueService;
constructor() {
// Manual wiring for serverless
const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';
const errorReporter = new ConsoleErrorReporter();
const logger = new ConsoleLogger();
const apiClient = new LeaguesApiClient(baseUrl, errorReporter, logger);
this.service = new LeagueService(apiClient);
}
async withdraw(leagueId: string, amount: number): Promise<Result<void, string>> {
try {
// TODO: Implement when wallet withdrawal API is available
// For now, return success
console.log('withdraw called with:', { leagueId, amount });
return Result.ok(undefined);
} catch (error) {
console.error('withdraw failed:', error);
return Result.err('Failed to withdraw funds');
}
}
async exportTransactions(leagueId: string): Promise<Result<void, string>> {
try {
// TODO: Implement when export API is available
// For now, return success
console.log('exportTransactions called with:', { leagueId });
return Result.ok(undefined);
} catch (error) {
console.error('exportTransactions failed:', error);
return Result.err('Failed to export transactions');
}
}
}

View File

@@ -8,27 +8,23 @@
*/
import { Result } from '@/lib/contracts/Result';
import { Mutation } from '@/lib/contracts/mutations/Mutation';
import { mapToMutationError } from '@/lib/contracts/mutations/MutationError';
import { OnboardingService } from '@/lib/services/onboarding/OnboardingService';
import { CompleteOnboardingInputDTO } from '@/lib/types/generated/CompleteOnboardingInputDTO';
import { CompleteOnboardingViewDataBuilder } from '@/lib/builders/view-data/CompleteOnboardingViewDataBuilder';
import { CompleteOnboardingViewData } from '@/lib/builders/view-data/CompleteOnboardingViewData';
export class CompleteOnboardingMutation {
export class CompleteOnboardingMutation implements Mutation<CompleteOnboardingInputDTO, CompleteOnboardingViewData, string> {
async execute(params: CompleteOnboardingInputDTO): Promise<Result<CompleteOnboardingViewData, string>> {
try {
const onboardingService = new OnboardingService();
const result = await onboardingService.completeOnboarding(params);
if (result.isErr()) {
const error = result.getError();
return Result.err(error.message || 'Failed to complete onboarding');
}
const output = CompleteOnboardingViewDataBuilder.build(result.unwrap());
return Result.ok(output);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Failed to complete onboarding';
return Result.err(errorMessage);
const onboardingService = new OnboardingService();
const result = await onboardingService.completeOnboarding(params);
if (result.isErr()) {
return Result.err(mapToMutationError(result.getError()));
}
const output = CompleteOnboardingViewDataBuilder.build(result.unwrap());
return Result.ok(output);
}
}

View File

@@ -1,5 +1,6 @@
import { Mutation } from '@/lib/contracts/mutations/Mutation';
import { Result } from '@/lib/contracts/Result';
import { mapToMutationError } from '@/lib/contracts/mutations/MutationError';
import { OnboardingService } from '@/lib/services/onboarding/OnboardingService';
import { RequestAvatarGenerationInputDTO } from '@/lib/types/generated/RequestAvatarGenerationInputDTO';
import { GenerateAvatarsViewDataBuilder } from '@/lib/builders/view-data/GenerateAvatarsViewDataBuilder';
@@ -11,7 +12,7 @@ export class GenerateAvatarsMutation implements Mutation<RequestAvatarGeneration
const result = await service.generateAvatars(input);
if (result.isErr()) {
return Result.err(result.getError().message);
return Result.err(mapToMutationError(result.getError()));
}
const output = GenerateAvatarsViewDataBuilder.build(result.unwrap());

View File

@@ -1,8 +1,11 @@
import { SponsorshipRequestsService } from '@/lib/services/sponsors/SponsorshipRequestsService';
import type { AcceptSponsorshipRequestCommand } from '@/lib/services/sponsors/SponsorshipRequestsService';
import type { Mutation } from '@/lib/contracts/mutations/Mutation';
import { Result } from '@/lib/contracts/Result';
import type { Result as ResultType } from '@/lib/contracts/Result';
export interface AcceptSponsorshipRequestCommand {
requestId: string;
actorDriverId: string;
}
export type AcceptSponsorshipRequestMutationError =
| 'ACCEPT_SPONSORSHIP_REQUEST_FAILED';
@@ -18,7 +21,7 @@ export class AcceptSponsorshipRequestMutation
async execute(
command: AcceptSponsorshipRequestCommand,
): Promise<ResultType<void, AcceptSponsorshipRequestMutationError>> {
): Promise<Result<void, AcceptSponsorshipRequestMutationError>> {
const result = await this.service.acceptRequest(command);
if (result.isErr()) {

View File

@@ -1,8 +1,12 @@
import { SponsorshipRequestsService } from '@/lib/services/sponsors/SponsorshipRequestsService';
import type { RejectSponsorshipRequestCommand } from '@/lib/services/sponsors/SponsorshipRequestsService';
import type { Mutation } from '@/lib/contracts/mutations/Mutation';
import { Result } from '@/lib/contracts/Result';
import type { Result as ResultType } from '@/lib/contracts/Result';
export interface RejectSponsorshipRequestCommand {
requestId: string;
actorDriverId: string;
reason: string | null;
}
export type RejectSponsorshipRequestMutationError =
| 'REJECT_SPONSORSHIP_REQUEST_FAILED';
@@ -18,7 +22,7 @@ export class RejectSponsorshipRequestMutation
async execute(
command: RejectSponsorshipRequestCommand,
): Promise<ResultType<void, RejectSponsorshipRequestMutationError>> {
): Promise<Result<void, RejectSponsorshipRequestMutationError>> {
const result = await this.service.rejectRequest(command);
if (result.isErr()) {