website refactor
This commit is contained in:
@@ -1,37 +1,33 @@
|
||||
import { AdminApiClient } from '@/lib/api/admin/AdminApiClient';
|
||||
import { AdminService } from '@/lib/services/admin/AdminService';
|
||||
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
|
||||
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
||||
import { Mutation } from '@/lib/contracts/mutations/Mutation';
|
||||
import { Result } from '@/lib/contracts/Result';
|
||||
import { MutationError, mapToMutationError } from '@/lib/contracts/mutations/MutationError';
|
||||
|
||||
/**
|
||||
* DeleteUserMutation
|
||||
*
|
||||
*
|
||||
* Framework-agnostic mutation for deleting users.
|
||||
* Called from Server Actions.
|
||||
*
|
||||
*
|
||||
* Input: { userId: string }
|
||||
* Output: void
|
||||
*
|
||||
* Output: Result<void, MutationError>
|
||||
*
|
||||
* Pattern: Server Action → Mutation → Service → API Client
|
||||
*/
|
||||
export class DeleteUserMutation implements Mutation<{ userId: string }, void> {
|
||||
private service: AdminService;
|
||||
|
||||
constructor() {
|
||||
// Manual DI for serverless
|
||||
const logger = new ConsoleLogger();
|
||||
const errorReporter = new EnhancedErrorReporter(logger, {
|
||||
showUserNotifications: true,
|
||||
logToConsole: true,
|
||||
reportToExternal: process.env.NODE_ENV === 'production',
|
||||
});
|
||||
const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
|
||||
const apiClient = new AdminApiClient(baseUrl, errorReporter, logger);
|
||||
this.service = new AdminService(apiClient);
|
||||
export class DeleteUserMutation {
|
||||
async execute(input: { userId: string }): Promise<Result<void, MutationError>> {
|
||||
try {
|
||||
// Manual construction: Service creates its own dependencies
|
||||
const service = new AdminService();
|
||||
|
||||
const result = await service.deleteUser(input.userId);
|
||||
|
||||
if (result.isErr()) {
|
||||
return Result.err(mapToMutationError(result.getError()));
|
||||
}
|
||||
|
||||
return Result.ok(undefined);
|
||||
} catch (err) {
|
||||
return Result.err('deleteFailed');
|
||||
}
|
||||
}
|
||||
|
||||
async execute(input: { userId: string }): Promise<void> {
|
||||
await this.service.deleteUser(input.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,33 @@
|
||||
import { AdminApiClient } from '@/lib/api/admin/AdminApiClient';
|
||||
import { AdminService } from '@/lib/services/admin/AdminService';
|
||||
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
|
||||
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
||||
import { Mutation } from '@/lib/contracts/mutations/Mutation';
|
||||
import { Result } from '@/lib/contracts/Result';
|
||||
import { MutationError, mapToMutationError } from '@/lib/contracts/mutations/MutationError';
|
||||
|
||||
/**
|
||||
* UpdateUserStatusMutation
|
||||
*
|
||||
*
|
||||
* Framework-agnostic mutation for updating user status.
|
||||
* Called from Server Actions.
|
||||
*
|
||||
*
|
||||
* Input: { userId: string; status: string }
|
||||
* Output: void
|
||||
*
|
||||
* Output: Result<void, MutationError>
|
||||
*
|
||||
* Pattern: Server Action → Mutation → Service → API Client
|
||||
*/
|
||||
export class UpdateUserStatusMutation implements Mutation<{ userId: string; status: string }, void> {
|
||||
private service: AdminService;
|
||||
|
||||
constructor() {
|
||||
// Manual DI for serverless
|
||||
const logger = new ConsoleLogger();
|
||||
const errorReporter = new EnhancedErrorReporter(logger, {
|
||||
showUserNotifications: true,
|
||||
logToConsole: true,
|
||||
reportToExternal: process.env.NODE_ENV === 'production',
|
||||
});
|
||||
const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
|
||||
const apiClient = new AdminApiClient(baseUrl, errorReporter, logger);
|
||||
this.service = new AdminService(apiClient);
|
||||
export class UpdateUserStatusMutation {
|
||||
async execute(input: { userId: string; status: string }): Promise<Result<void, MutationError>> {
|
||||
try {
|
||||
// Manual construction: Service creates its own dependencies
|
||||
const service = new AdminService();
|
||||
|
||||
const result = await service.updateUserStatus(input.userId, input.status);
|
||||
|
||||
if (result.isErr()) {
|
||||
return Result.err(mapToMutationError(result.getError()));
|
||||
}
|
||||
|
||||
return Result.ok(undefined);
|
||||
} catch (err) {
|
||||
return Result.err('updateFailed');
|
||||
}
|
||||
}
|
||||
|
||||
async execute(input: { userId: string; status: string }): Promise<void> {
|
||||
await this.service.updateUserStatus(input.userId, input.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/website/lib/mutations/auth/ForgotPasswordMutation.ts
Normal file
26
apps/website/lib/mutations/auth/ForgotPasswordMutation.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Forgot Password Mutation
|
||||
*
|
||||
* Framework-agnostic mutation for forgot password 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';
|
||||
import { ForgotPasswordDTO } from '@/lib/types/generated/ForgotPasswordDTO';
|
||||
import { ForgotPasswordResult } from '@/lib/mutations/auth/types/ForgotPasswordResult';
|
||||
|
||||
export class ForgotPasswordMutation {
|
||||
async execute(params: ForgotPasswordDTO): Promise<Result<ForgotPasswordResult, string>> {
|
||||
try {
|
||||
const authService = new AuthService();
|
||||
const result = await authService.forgotPassword(params);
|
||||
return Result.ok(result);
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Failed to send reset link';
|
||||
return Result.err(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/website/lib/mutations/auth/LoginMutation.ts
Normal file
26
apps/website/lib/mutations/auth/LoginMutation.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Login Mutation
|
||||
*
|
||||
* Framework-agnostic mutation for login 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';
|
||||
import { SessionViewModel } from '@/lib/view-models/SessionViewModel';
|
||||
import { LoginParamsDTO } from '@/lib/types/generated/LoginParamsDTO';
|
||||
|
||||
export class LoginMutation {
|
||||
async execute(params: LoginParamsDTO): Promise<Result<SessionViewModel, string>> {
|
||||
try {
|
||||
const authService = new AuthService();
|
||||
const session = await authService.login(params);
|
||||
return Result.ok(session);
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Login failed';
|
||||
return Result.err(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/website/lib/mutations/auth/ResetPasswordMutation.ts
Normal file
26
apps/website/lib/mutations/auth/ResetPasswordMutation.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Reset Password Mutation
|
||||
*
|
||||
* Framework-agnostic mutation for reset password 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';
|
||||
import { ResetPasswordDTO } from '@/lib/types/generated/ResetPasswordDTO';
|
||||
import { ResetPasswordResult } from '@/lib/mutations/auth/types/ResetPasswordResult';
|
||||
|
||||
export class ResetPasswordMutation {
|
||||
async execute(params: ResetPasswordDTO): Promise<Result<ResetPasswordResult, string>> {
|
||||
try {
|
||||
const authService = new AuthService();
|
||||
const result = await authService.resetPassword(params);
|
||||
return Result.ok(result);
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Failed to reset password';
|
||||
return Result.err(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
apps/website/lib/mutations/auth/SignupMutation.ts
Normal file
26
apps/website/lib/mutations/auth/SignupMutation.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Signup Mutation
|
||||
*
|
||||
* Framework-agnostic mutation for signup 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';
|
||||
import { SessionViewModel } from '@/lib/view-models/SessionViewModel';
|
||||
import { SignupParamsDTO } from '@/lib/types/generated/SignupParamsDTO';
|
||||
|
||||
export class SignupMutation {
|
||||
async execute(params: SignupParamsDTO): Promise<Result<SessionViewModel, string>> {
|
||||
try {
|
||||
const authService = new AuthService();
|
||||
const session = await authService.signup(params);
|
||||
return Result.ok(session);
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Signup failed';
|
||||
return Result.err(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Forgot Password Mutation Result
|
||||
*
|
||||
* Result type for forgot password operations.
|
||||
* This represents the successful outcome of a forgot password mutation.
|
||||
*/
|
||||
|
||||
export interface ForgotPasswordResult {
|
||||
message: string;
|
||||
magicLink?: string;
|
||||
}
|
||||
10
apps/website/lib/mutations/auth/types/ResetPasswordResult.ts
Normal file
10
apps/website/lib/mutations/auth/types/ResetPasswordResult.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Reset Password Mutation Result
|
||||
*
|
||||
* Result type for reset password operations.
|
||||
* This represents the successful outcome of a reset password mutation.
|
||||
*/
|
||||
|
||||
export interface ResetPasswordResult {
|
||||
message: string;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Result } from '@/lib/contracts/Result';
|
||||
import type { Mutation } from '@/lib/contracts/mutations/Mutation';
|
||||
import type { DomainError } from '@/lib/contracts/services/Service';
|
||||
import { DriverProfileUpdateService } from '@/lib/services/drivers/DriverProfileUpdateService';
|
||||
|
||||
export interface UpdateDriverProfileCommand {
|
||||
bio?: string;
|
||||
country?: string;
|
||||
}
|
||||
|
||||
type UpdateDriverProfileMutationError = 'DRIVER_PROFILE_UPDATE_FAILED';
|
||||
|
||||
const mapToMutationError = (_error: DomainError): UpdateDriverProfileMutationError => {
|
||||
return 'DRIVER_PROFILE_UPDATE_FAILED';
|
||||
};
|
||||
|
||||
export class UpdateDriverProfileMutation
|
||||
implements Mutation<UpdateDriverProfileCommand, void, UpdateDriverProfileMutationError>
|
||||
{
|
||||
async execute(
|
||||
command: UpdateDriverProfileCommand,
|
||||
): Promise<Result<void, UpdateDriverProfileMutationError>> {
|
||||
const service = new DriverProfileUpdateService();
|
||||
const result = await service.updateProfile({ bio: command.bio, country: command.country });
|
||||
|
||||
if (result.isErr()) {
|
||||
return Result.err(mapToMutationError(result.getError()));
|
||||
}
|
||||
|
||||
return Result.ok(undefined);
|
||||
}
|
||||
}
|
||||
36
apps/website/lib/mutations/leagues/CreateLeagueMutation.ts
Normal file
36
apps/website/lib/mutations/leagues/CreateLeagueMutation.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
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';
|
||||
import type { CreateLeagueInputDTO } from '@/lib/types/generated/CreateLeagueInputDTO';
|
||||
|
||||
/**
|
||||
* CreateLeagueMutation
|
||||
*
|
||||
* Framework-agnostic mutation for league creation.
|
||||
* Can be called from Server Actions or other contexts.
|
||||
*/
|
||||
export class CreateLeagueMutation {
|
||||
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 createLeague(input: CreateLeagueInputDTO): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.createLeague(input);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('createLeague failed:', error);
|
||||
return Result.err('Failed to create league');
|
||||
}
|
||||
}
|
||||
}
|
||||
57
apps/website/lib/mutations/leagues/ProtestReviewMutation.ts
Normal file
57
apps/website/lib/mutations/leagues/ProtestReviewMutation.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { Result } from '@/lib/contracts/Result';
|
||||
import { ProtestService } from '@/lib/services/protests/ProtestService';
|
||||
import { ProtestsApiClient } from '@/lib/api/protests/ProtestsApiClient';
|
||||
import { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';
|
||||
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
||||
import type { ApplyPenaltyCommandDTO } from '@/lib/types/generated/ApplyPenaltyCommandDTO';
|
||||
import type { RequestProtestDefenseCommandDTO } from '@/lib/types/generated/RequestProtestDefenseCommandDTO';
|
||||
|
||||
/**
|
||||
* ProtestReviewMutation
|
||||
*
|
||||
* Framework-agnostic mutation for protest review operations.
|
||||
* Can be called from Server Actions or other contexts.
|
||||
*/
|
||||
export class ProtestReviewMutation {
|
||||
private service: ProtestService;
|
||||
|
||||
constructor() {
|
||||
// Manual wiring for serverless
|
||||
const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';
|
||||
const errorReporter = new ConsoleErrorReporter();
|
||||
const logger = new ConsoleLogger();
|
||||
const apiClient = new ProtestsApiClient(baseUrl, errorReporter, logger);
|
||||
|
||||
this.service = new ProtestService(apiClient);
|
||||
}
|
||||
|
||||
async applyPenalty(input: ApplyPenaltyCommandDTO): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.applyPenalty(input);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('applyPenalty failed:', error);
|
||||
return Result.err('Failed to apply penalty');
|
||||
}
|
||||
}
|
||||
|
||||
async requestDefense(input: RequestProtestDefenseCommandDTO): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.requestDefense(input);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('requestDefense failed:', error);
|
||||
return Result.err('Failed to request defense');
|
||||
}
|
||||
}
|
||||
|
||||
async reviewProtest(input: { protestId: string; stewardId: string; decision: string; decisionNotes: string }): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.reviewProtest(input as any);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('reviewProtest failed:', error);
|
||||
return Result.err('Failed to review protest');
|
||||
}
|
||||
}
|
||||
}
|
||||
66
apps/website/lib/mutations/leagues/RosterAdminMutation.ts
Normal file
66
apps/website/lib/mutations/leagues/RosterAdminMutation.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
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';
|
||||
import type { MembershipRole } from '@/lib/types/MembershipRole';
|
||||
|
||||
/**
|
||||
* RosterAdminMutation
|
||||
*
|
||||
* Framework-agnostic mutation for roster administration operations.
|
||||
* Can be called from Server Actions or other contexts.
|
||||
*/
|
||||
export class RosterAdminMutation {
|
||||
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 approveJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.approveJoinRequest(leagueId, joinRequestId);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('approveJoinRequest failed:', error);
|
||||
return Result.err('Failed to approve join request');
|
||||
}
|
||||
}
|
||||
|
||||
async rejectJoinRequest(leagueId: string, joinRequestId: string): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.rejectJoinRequest(leagueId, joinRequestId);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('rejectJoinRequest failed:', error);
|
||||
return Result.err('Failed to reject join request');
|
||||
}
|
||||
}
|
||||
|
||||
async updateMemberRole(leagueId: string, driverId: string, role: MembershipRole): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.updateMemberRole(leagueId, driverId, role);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('updateMemberRole failed:', error);
|
||||
return Result.err('Failed to update member role');
|
||||
}
|
||||
}
|
||||
|
||||
async removeMember(leagueId: string, driverId: string): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.removeMember(leagueId, driverId);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('removeMember failed:', error);
|
||||
return Result.err('Failed to remove member');
|
||||
}
|
||||
}
|
||||
}
|
||||
77
apps/website/lib/mutations/leagues/ScheduleAdminMutation.ts
Normal file
77
apps/website/lib/mutations/leagues/ScheduleAdminMutation.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
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';
|
||||
import type { CreateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/CreateLeagueScheduleRaceInputDTO';
|
||||
import type { UpdateLeagueScheduleRaceInputDTO } from '@/lib/types/generated/UpdateLeagueScheduleRaceInputDTO';
|
||||
|
||||
/**
|
||||
* ScheduleAdminMutation
|
||||
*
|
||||
* Framework-agnostic mutation for schedule administration operations.
|
||||
* Can be called from Server Actions or other contexts.
|
||||
*/
|
||||
export class ScheduleAdminMutation {
|
||||
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 publishSchedule(leagueId: string, seasonId: string): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.publishAdminSchedule(leagueId, seasonId);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('publishSchedule failed:', error);
|
||||
return Result.err('Failed to publish schedule');
|
||||
}
|
||||
}
|
||||
|
||||
async unpublishSchedule(leagueId: string, seasonId: string): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.unpublishAdminSchedule(leagueId, seasonId);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('unpublishSchedule failed:', error);
|
||||
return Result.err('Failed to unpublish schedule');
|
||||
}
|
||||
}
|
||||
|
||||
async createRace(leagueId: string, seasonId: string, input: { track: string; car: string; scheduledAtIso: string }): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.createAdminScheduleRace(leagueId, seasonId, input);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('createRace failed:', error);
|
||||
return Result.err('Failed to create race');
|
||||
}
|
||||
}
|
||||
|
||||
async updateRace(leagueId: string, seasonId: string, raceId: string, input: Partial<{ track: string; car: string; scheduledAtIso: string }>): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.updateAdminScheduleRace(leagueId, seasonId, raceId, input);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('updateRace failed:', error);
|
||||
return Result.err('Failed to update race');
|
||||
}
|
||||
}
|
||||
|
||||
async deleteRace(leagueId: string, seasonId: string, raceId: string): Promise<Result<void, string>> {
|
||||
try {
|
||||
await this.service.deleteAdminScheduleRace(leagueId, seasonId, raceId);
|
||||
return Result.ok(undefined);
|
||||
} catch (error) {
|
||||
console.error('deleteRace failed:', error);
|
||||
return Result.err('Failed to delete race');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Complete Onboarding Mutation
|
||||
*
|
||||
* Framework-agnostic mutation for completing onboarding.
|
||||
* Called from Server Actions.
|
||||
*
|
||||
* Pattern: Server Action → Mutation → Service → API Client
|
||||
*/
|
||||
|
||||
import { Result } from '@/lib/contracts/Result';
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Mutation } from '@/lib/contracts/mutations/Mutation';
|
||||
import { Result } from '@/lib/contracts/Result';
|
||||
import { OnboardingService } from '@/lib/services/onboarding/OnboardingService';
|
||||
import { RequestAvatarGenerationInputDTO } from '@/lib/types/generated/RequestAvatarGenerationInputDTO';
|
||||
import { GenerateAvatarsViewDataBuilder } from '@/lib/builders/view-data/GenerateAvatarsViewDataBuilder';
|
||||
import { GenerateAvatarsViewData } from '@/lib/builders/view-data/GenerateAvatarsViewData';
|
||||
|
||||
export class GenerateAvatarsMutation implements Mutation<RequestAvatarGenerationInputDTO, GenerateAvatarsViewData, string> {
|
||||
async execute(input: RequestAvatarGenerationInputDTO): Promise<Result<GenerateAvatarsViewData, string>> {
|
||||
const service = new OnboardingService();
|
||||
const result = await service.generateAvatars(input);
|
||||
|
||||
if (result.isErr()) {
|
||||
return Result.err(result.getError().message);
|
||||
}
|
||||
|
||||
const output = GenerateAvatarsViewDataBuilder.build(result.unwrap());
|
||||
return Result.ok(output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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 type AcceptSponsorshipRequestMutationError =
|
||||
| 'ACCEPT_SPONSORSHIP_REQUEST_FAILED';
|
||||
|
||||
export class AcceptSponsorshipRequestMutation
|
||||
implements Mutation<AcceptSponsorshipRequestCommand, void, AcceptSponsorshipRequestMutationError>
|
||||
{
|
||||
private readonly service: SponsorshipRequestsService;
|
||||
|
||||
constructor() {
|
||||
this.service = new SponsorshipRequestsService();
|
||||
}
|
||||
|
||||
async execute(
|
||||
command: AcceptSponsorshipRequestCommand,
|
||||
): Promise<ResultType<void, AcceptSponsorshipRequestMutationError>> {
|
||||
const result = await this.service.acceptRequest(command);
|
||||
|
||||
if (result.isErr()) {
|
||||
return Result.err('ACCEPT_SPONSORSHIP_REQUEST_FAILED');
|
||||
}
|
||||
|
||||
return Result.ok(undefined);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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 type RejectSponsorshipRequestMutationError =
|
||||
| 'REJECT_SPONSORSHIP_REQUEST_FAILED';
|
||||
|
||||
export class RejectSponsorshipRequestMutation
|
||||
implements Mutation<RejectSponsorshipRequestCommand, void, RejectSponsorshipRequestMutationError>
|
||||
{
|
||||
private readonly service: SponsorshipRequestsService;
|
||||
|
||||
constructor() {
|
||||
this.service = new SponsorshipRequestsService();
|
||||
}
|
||||
|
||||
async execute(
|
||||
command: RejectSponsorshipRequestCommand,
|
||||
): Promise<ResultType<void, RejectSponsorshipRequestMutationError>> {
|
||||
const result = await this.service.rejectRequest(command);
|
||||
|
||||
if (result.isErr()) {
|
||||
return Result.err('REJECT_SPONSORSHIP_REQUEST_FAILED');
|
||||
}
|
||||
|
||||
return Result.ok(undefined);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user