website refactor
This commit is contained in:
@@ -1,14 +1,20 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { LEAGUE_MEMBERSHIP_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
|
||||
export function useLeagueMembershipMutation() {
|
||||
const leagueMembershipService = useInject(LEAGUE_MEMBERSHIP_SERVICE_TOKEN);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const joinLeagueMutation = useMutation({
|
||||
mutationFn: ({ leagueId, driverId }: { leagueId: string; driverId: string }) =>
|
||||
leagueMembershipService.joinLeague(leagueId, driverId),
|
||||
mutationFn: async ({ leagueId, driverId }: { leagueId: string; driverId: string }) => {
|
||||
const result = await leagueMembershipService.joinLeague(leagueId, driverId);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['leagueMemberships'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['allLeagues'] });
|
||||
@@ -16,8 +22,13 @@ export function useLeagueMembershipMutation() {
|
||||
});
|
||||
|
||||
const leaveLeagueMutation = useMutation({
|
||||
mutationFn: ({ leagueId, driverId }: { leagueId: string; driverId: string }) =>
|
||||
leagueMembershipService.leaveLeague(leagueId, driverId),
|
||||
mutationFn: async ({ leagueId, driverId }: { leagueId: string; driverId: string }) => {
|
||||
const result = await leagueMembershipService.leaveLeague(leagueId, driverId);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['leagueMemberships'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['allLeagues'] });
|
||||
@@ -28,4 +39,4 @@ export function useLeagueMembershipMutation() {
|
||||
joinLeague: joinLeagueMutation,
|
||||
leaveLeague: leaveLeagueMutation,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,13 @@ export function useLeagueRosterAdmin(leagueId: string, options?: UseQueryOptions
|
||||
|
||||
return useQuery<LeagueRosterMemberDTO[], ApiError>({
|
||||
queryKey: ['league-roster-admin', leagueId],
|
||||
queryFn: () => leagueService.getAdminRosterMembers(leagueId),
|
||||
queryFn: async () => {
|
||||
const result = await leagueService.getAdminRosterMembers(leagueId);
|
||||
if (result.isErr()) {
|
||||
throw new ApiError(result.getError().message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
@@ -36,7 +42,13 @@ export function useLeagueJoinRequests(leagueId: string, options?: UseQueryOption
|
||||
|
||||
return useQuery<LeagueRosterJoinRequestDTO[], ApiError>({
|
||||
queryKey: ['league-join-requests', leagueId],
|
||||
queryFn: () => leagueService.getAdminRosterJoinRequests(leagueId),
|
||||
queryFn: async () => {
|
||||
const result = await leagueService.getAdminRosterJoinRequests(leagueId);
|
||||
if (result.isErr()) {
|
||||
throw new ApiError(result.getError().message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
@@ -48,7 +60,11 @@ export function useUpdateMemberRole(
|
||||
|
||||
return useMutation<{ success: boolean }, ApiError, UpdateMemberRoleInput>({
|
||||
mutationFn: async (input) => {
|
||||
return leagueService.updateMemberRole(input.leagueId, input.driverId, input.newRole);
|
||||
const result = await leagueService.updateMemberRole(input.leagueId, input.driverId, input.newRole);
|
||||
if (result.isErr()) {
|
||||
throw new ApiError(result.getError().message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
...options,
|
||||
});
|
||||
@@ -61,7 +77,11 @@ export function useRemoveMember(
|
||||
|
||||
return useMutation<{ success: boolean }, ApiError, RemoveMemberInput>({
|
||||
mutationFn: async (input) => {
|
||||
return leagueService.removeMember(input.leagueId, input.driverId);
|
||||
const result = await leagueService.removeMember(input.leagueId, input.driverId);
|
||||
if (result.isErr()) {
|
||||
throw new ApiError(result.getError().message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
...options,
|
||||
});
|
||||
@@ -74,7 +94,11 @@ export function useApproveJoinRequest(
|
||||
|
||||
return useMutation<{ success: boolean }, ApiError, JoinRequestActionInput>({
|
||||
mutationFn: async (input) => {
|
||||
return leagueService.approveJoinRequest(input.leagueId, input.requestId);
|
||||
const result = await leagueService.approveJoinRequest(input.leagueId, input.requestId);
|
||||
if (result.isErr()) {
|
||||
throw new ApiError(result.getError().message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
...options,
|
||||
});
|
||||
@@ -87,8 +111,12 @@ export function useRejectJoinRequest(
|
||||
|
||||
return useMutation<{ success: boolean }, ApiError, JoinRequestActionInput>({
|
||||
mutationFn: async (input) => {
|
||||
return leagueService.rejectJoinRequest(input.leagueId, input.requestId);
|
||||
const result = await leagueService.rejectJoinRequest(input.leagueId, input.requestId);
|
||||
if (result.isErr()) {
|
||||
throw new ApiError(result.getError().message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,21 +3,19 @@ import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { LEAGUE_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||
import { LeagueScheduleViewModel, LeagueScheduleRaceViewModel } from '@/lib/view-models/LeagueScheduleViewModel';
|
||||
import type { LeagueScheduleDTO } from '@/lib/types/generated/LeagueScheduleDTO';
|
||||
import type { RaceDTO } from '@/lib/types/generated/RaceDTO';
|
||||
|
||||
function mapRaceDtoToViewModel(race: RaceDTO): LeagueScheduleRaceViewModel {
|
||||
const scheduledAt = race.date ? new Date(race.date) : new Date(0);
|
||||
const now = new Date();
|
||||
const isPast = scheduledAt.getTime() < now.getTime();
|
||||
const isUpcoming = !isPast;
|
||||
|
||||
return {
|
||||
id: race.id,
|
||||
name: race.name,
|
||||
scheduledAt,
|
||||
isPast,
|
||||
isUpcoming,
|
||||
isUpcoming: !isPast,
|
||||
status: isPast ? 'completed' : 'scheduled',
|
||||
track: undefined,
|
||||
car: undefined,
|
||||
@@ -32,7 +30,11 @@ export function useLeagueSchedule(leagueId: string) {
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['leagueSchedule', leagueId],
|
||||
queryFn: async (): Promise<LeagueScheduleViewModel> => {
|
||||
const dto = await leagueService.getLeagueSchedule(leagueId);
|
||||
const result = await leagueService.getLeagueSchedule(leagueId);
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.getError().message);
|
||||
}
|
||||
const dto = result.unwrap();
|
||||
const races = dto.races.map(mapRaceDtoToViewModel);
|
||||
return new LeagueScheduleViewModel(races);
|
||||
},
|
||||
@@ -40,4 +42,4 @@ export function useLeagueSchedule(leagueId: string) {
|
||||
});
|
||||
|
||||
return enhanceQueryResult(queryResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { LeagueRoleUtility } from '@/lib/utilities/LeagueRoleUtility';
|
||||
import { LeagueAdminScheduleViewModel } from '@/lib/view-models/LeagueAdminScheduleViewModel';
|
||||
import { LeagueScheduleRaceViewModel } from '@/lib/view-models/LeagueScheduleViewModel';
|
||||
import { LeagueSeasonSummaryViewModel } from '@/lib/view-models/LeagueSeasonSummaryViewModel';
|
||||
import type { LeagueScheduleDTO } from '@/lib/types/generated/LeagueScheduleDTO';
|
||||
import type { RaceDTO } from '@/lib/types/generated/RaceDTO';
|
||||
import type { LeagueSeasonSummaryDTO } from '@/lib/types/generated/LeagueSeasonSummaryDTO';
|
||||
|
||||
@@ -13,14 +12,13 @@ function mapRaceDtoToViewModel(race: RaceDTO): LeagueScheduleRaceViewModel {
|
||||
const scheduledAt = race.date ? new Date(race.date) : new Date(0);
|
||||
const now = new Date();
|
||||
const isPast = scheduledAt.getTime() < now.getTime();
|
||||
const isUpcoming = !isPast;
|
||||
|
||||
return {
|
||||
id: race.id,
|
||||
name: race.name,
|
||||
scheduledAt,
|
||||
isPast,
|
||||
isUpcoming,
|
||||
isUpcoming: !isPast,
|
||||
status: isPast ? 'completed' : 'scheduled',
|
||||
track: undefined,
|
||||
car: undefined,
|
||||
@@ -49,7 +47,11 @@ export function useLeagueSeasons(leagueId: string, isAdmin: boolean) {
|
||||
return usePageData({
|
||||
queryKey: ['leagueSeasons', leagueId],
|
||||
queryFn: async (): Promise<LeagueSeasonSummaryViewModel[]> => {
|
||||
const dtos = await leagueService.getLeagueSeasonSummaries(leagueId);
|
||||
const result = await leagueService.getLeagueSeasonSummaries(leagueId);
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.getError().message);
|
||||
}
|
||||
const dtos = result.unwrap();
|
||||
return dtos.map((dto: LeagueSeasonSummaryDTO) => new LeagueSeasonSummaryViewModel(dto));
|
||||
},
|
||||
enabled: !!leagueId && !!isAdmin,
|
||||
@@ -62,7 +64,11 @@ export function useLeagueAdminSchedule(leagueId: string, selectedSeasonId: strin
|
||||
return usePageData({
|
||||
queryKey: ['adminSchedule', leagueId, selectedSeasonId],
|
||||
queryFn: async (): Promise<LeagueAdminScheduleViewModel> => {
|
||||
const dto = await leagueService.getAdminSchedule(leagueId, selectedSeasonId);
|
||||
const result = await leagueService.getAdminSchedule(leagueId, selectedSeasonId);
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.getError().message);
|
||||
}
|
||||
const dto = result.unwrap();
|
||||
const races = dto.races.map(mapRaceDtoToViewModel);
|
||||
return new LeagueAdminScheduleViewModel({
|
||||
seasonId: dto.seasonId,
|
||||
@@ -72,4 +78,4 @@ export function useLeagueAdminSchedule(leagueId: string, selectedSeasonId: strin
|
||||
},
|
||||
enabled: !!leagueId && !!selectedSeasonId && !!isAdmin,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { usePageMutation } from '@/lib/page/usePageData';
|
||||
|
||||
export function useLeagueStewardingMutations(onRefetch: () => void) {
|
||||
const acceptProtestMutation = usePageMutation(
|
||||
async (variables: { protestId: string; penaltyType: string; penaltyValue: number; stewardNotes: string; raceId: string; accusedDriverId: string; reason: string }) => {
|
||||
async (_variables: { protestId: string; penaltyType: string; penaltyValue: number; stewardNotes: string; raceId: string; accusedDriverId: string; reason: string }) => {
|
||||
// TODO: Implement protest review and penalty application
|
||||
// await leagueStewardingService.reviewProtest({
|
||||
// protestId: variables.protestId,
|
||||
@@ -28,7 +28,7 @@ export function useLeagueStewardingMutations(onRefetch: () => void) {
|
||||
);
|
||||
|
||||
const rejectProtestMutation = usePageMutation(
|
||||
async (variables: { protestId: string; stewardNotes: string }) => {
|
||||
async (_variables: { protestId: string; stewardNotes: string }) => {
|
||||
// TODO: Implement protest rejection
|
||||
// await leagueStewardingService.reviewProtest({
|
||||
// protestId: variables.protestId,
|
||||
|
||||
@@ -22,7 +22,7 @@ export function useLeagueWalletPageData(leagueId: string) {
|
||||
amount: t.amount,
|
||||
fee: t.fee,
|
||||
netAmount: t.netAmount,
|
||||
date: new Date(t.date),
|
||||
date: new globalThis.Date(t.date),
|
||||
status: t.status,
|
||||
reference: t.reference,
|
||||
}));
|
||||
@@ -48,6 +48,6 @@ export function useLeagueWalletPageData(leagueId: string) {
|
||||
* @deprecated Use useLeagueWalletWithdrawalWithBlockers instead
|
||||
* This wrapper maintains backward compatibility while using the new blocker-aware hook
|
||||
*/
|
||||
export function useLeagueWalletWithdrawal(leagueId: string, data: any, refetch: () => void) {
|
||||
export function useLeagueWalletWithdrawal(leagueId: string, data: LeagueWalletViewModel | null, refetch: () => void) {
|
||||
return useLeagueWalletWithdrawalWithBlockers(leagueId, data, refetch);
|
||||
}
|
||||
@@ -3,13 +3,15 @@
|
||||
import { usePageMutation } from '@/lib/page/usePageData';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { LEAGUE_WALLET_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { SubmitBlocker, ThrottleBlocker } from '@/lib/blockers';
|
||||
import { SubmitBlocker } from '@/lib/blockers/SubmitBlocker';
|
||||
import { ThrottleBlocker } from '@/lib/blockers/ThrottleBlocker';
|
||||
import type { LeagueWalletViewModel } from '@/lib/view-models/LeagueWalletViewModel';
|
||||
|
||||
/**
|
||||
* Hook for wallet withdrawals with client-side blockers
|
||||
* Handles UX prevention mechanisms (rate limiting, duplicate submission prevention)
|
||||
*/
|
||||
export function useLeagueWalletWithdrawalWithBlockers(leagueId: string, data: any, refetch: () => void) {
|
||||
export function useLeagueWalletWithdrawalWithBlockers(leagueId: string, data: LeagueWalletViewModel | null, refetch: () => void) {
|
||||
const leagueWalletService = useInject(LEAGUE_WALLET_SERVICE_TOKEN);
|
||||
|
||||
// Client-side blockers for UX improvement
|
||||
@@ -18,11 +20,11 @@ export function useLeagueWalletWithdrawalWithBlockers(leagueId: string, data: an
|
||||
|
||||
const withdrawMutation = usePageMutation(
|
||||
async ({ amount }: { amount: number }) => {
|
||||
if (!data) throw new Error('Wallet data not available');
|
||||
if (!data) throw new globalThis.Error('Wallet data not available');
|
||||
|
||||
// Client-side blockers (UX only, not security)
|
||||
if (!submitBlocker.canExecute() || !throttle.canExecute()) {
|
||||
throw new Error('Request blocked due to rate limiting');
|
||||
throw new globalThis.Error('Request blocked due to rate limiting');
|
||||
}
|
||||
|
||||
submitBlocker.block();
|
||||
@@ -38,7 +40,7 @@ export function useLeagueWalletWithdrawalWithBlockers(leagueId: string, data: an
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.message || 'Withdrawal failed');
|
||||
throw new globalThis.Error(result.message || 'Withdrawal failed');
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -7,7 +7,7 @@ export function usePenaltyMutation() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const applyPenaltyMutation = useMutation({
|
||||
mutationFn: (command: any) => penaltyService.applyPenalty(command),
|
||||
mutationFn: (command: unknown) => penaltyService.applyPenalty(command),
|
||||
onSuccess: () => {
|
||||
// Invalidate relevant queries to refresh data
|
||||
queryClient.invalidateQueries({ queryKey: ['leagueStewardingData'] });
|
||||
|
||||
@@ -2,15 +2,23 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { LEAGUE_STEWARDING_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
|
||||
export function useProtestDetail(leagueId: string, protestId: string, enabled: boolean = true) {
|
||||
const leagueStewardingService = useInject(LEAGUE_STEWARDING_SERVICE_TOKEN);
|
||||
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['protestDetail', leagueId, protestId],
|
||||
queryFn: () => leagueStewardingService.getProtestDetailViewModel(leagueId, protestId),
|
||||
queryFn: async () => {
|
||||
const result = await leagueStewardingService.getProtestDetailViewModel(leagueId, protestId);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
enabled: enabled && !!leagueId && !!protestId,
|
||||
});
|
||||
|
||||
return enhanceQueryResult(queryResult);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user