website refactor
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
export { useCurrentSession } from './useCurrentSession';
|
||||
export { useLogin } from './useLogin';
|
||||
export { useLogout } from './useLogout';
|
||||
export { useSignup } from './useSignup';
|
||||
export { useForgotPassword } from './useForgotPassword';
|
||||
export { useResetPassword } from './useResetPassword';
|
||||
@@ -12,7 +12,15 @@ export function useCurrentSession(
|
||||
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['currentSession'],
|
||||
queryFn: () => sessionService.getSession(),
|
||||
queryFn: async () => {
|
||||
const result = await sessionService.getSession();
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
const session = result.unwrap();
|
||||
return session ? new SessionViewModel(session.user) : null;
|
||||
},
|
||||
initialData: options?.initialData,
|
||||
...options,
|
||||
});
|
||||
|
||||
@@ -9,7 +9,13 @@ export function useLogout(
|
||||
const authService = useInject(AUTH_SERVICE_TOKEN);
|
||||
|
||||
return useMutation<void, ApiError, void>({
|
||||
mutationFn: () => authService.logout(),
|
||||
mutationFn: async () => {
|
||||
const result = await authService.logout();
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export { useCurrentDriver } from './useCurrentDriver';
|
||||
export { useDriverLeaderboard } from '@/lib/hooks/useDriverLeaderboard';
|
||||
export { useDriverProfile } from './useDriverProfile';
|
||||
export { useUpdateDriverProfile } from './useUpdateDriverProfile';
|
||||
export { useCreateDriver } from './useCreateDriver';
|
||||
export { useFindDriverById } from './useFindDriverById';
|
||||
@@ -3,17 +3,22 @@ import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
|
||||
type DriverData = any; // Replace with actual type
|
||||
import type { DriverDTO } from '@/lib/types/generated/DriverDTO';
|
||||
|
||||
export function useCurrentDriver(
|
||||
options?: Omit<UseQueryOptions<DriverData, ApiError>, 'queryKey' | 'queryFn'>
|
||||
options?: Omit<UseQueryOptions<DriverDTO | null, ApiError>, 'queryKey' | 'queryFn'>
|
||||
) {
|
||||
const driverService = useInject(DRIVER_SERVICE_TOKEN);
|
||||
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['currentDriver'],
|
||||
queryFn: () => driverService.getCurrentDriver(),
|
||||
queryFn: async () => {
|
||||
const result = await driverService.getCurrentDriver();
|
||||
if (result.isErr()) {
|
||||
throw result.getError();
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
...options,
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
import { DriverProfileViewModel } from '@/lib/view-models/DriverProfileViewModel';
|
||||
import { DriverProfileViewModel, type DriverProfileViewModelData } from '@/lib/view-models/DriverProfileViewModel';
|
||||
|
||||
export function useDriverProfile(
|
||||
driverId: string,
|
||||
@@ -13,10 +13,17 @@ export function useDriverProfile(
|
||||
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['driverProfile', driverId],
|
||||
queryFn: () => driverService.getDriverProfile(driverId),
|
||||
queryFn: async () => {
|
||||
const result = await driverService.getDriverProfile(driverId);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new globalThis.Date().toISOString() });
|
||||
}
|
||||
return new DriverProfileViewModel(result.unwrap() as unknown as DriverProfileViewModelData);
|
||||
},
|
||||
enabled: !!driverId,
|
||||
...options,
|
||||
});
|
||||
|
||||
return enhanceQueryResult(queryResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,17 @@ export function useFindDriverById(
|
||||
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['driver', driverId],
|
||||
queryFn: () => driverService.findById(driverId),
|
||||
queryFn: async () => {
|
||||
const result = await driverService.findById(driverId);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
enabled: !!driverId,
|
||||
...options,
|
||||
});
|
||||
|
||||
return enhanceQueryResult(queryResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useMutation, UseMutationOptions } from '@tanstack/react-query';
|
||||
import { OnboardingService } from '@/lib/services/onboarding/OnboardingService';
|
||||
import { Result } from '@/lib/contracts/Result';
|
||||
import { DomainError } from '@/lib/contracts/services/Service';
|
||||
|
||||
@@ -21,8 +20,7 @@ export function useGenerateAvatars(
|
||||
options?: Omit<UseMutationOptions<Result<GenerateAvatarsResult, DomainError>, Error, GenerateAvatarsParams>, 'mutationFn'>
|
||||
) {
|
||||
return useMutation<Result<GenerateAvatarsResult, DomainError>, Error, GenerateAvatarsParams>({
|
||||
mutationFn: async (params) => {
|
||||
const service = new OnboardingService();
|
||||
mutationFn: async (_params) => {
|
||||
// This method doesn't exist in the service yet, but the hook is now created
|
||||
// The service will need to implement this or we need to adjust the architecture
|
||||
return Result.ok({ success: false, errorMessage: 'Not implemented' });
|
||||
|
||||
@@ -10,7 +10,13 @@ export function useFileProtest(
|
||||
const raceService = useInject(RACE_SERVICE_TOKEN);
|
||||
|
||||
return useMutation<void, ApiError, FileProtestCommandDTO>({
|
||||
mutationFn: (command) => raceService.fileProtest(command),
|
||||
mutationFn: async (command) => {
|
||||
const result = await raceService.fileProtest(command);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,13 @@ export function useRegisterForRace(
|
||||
const raceService = useInject(RACE_SERVICE_TOKEN);
|
||||
|
||||
return useMutation<void, ApiError, RegisterForRaceParams>({
|
||||
mutationFn: (params) => raceService.registerForRace(params.raceId, params.leagueId, params.driverId),
|
||||
mutationFn: async (params) => {
|
||||
const result = await raceService.registerForRace(params.raceId, params.leagueId, params.driverId);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,7 +14,13 @@ export function useWithdrawFromRace(
|
||||
const raceService = useInject(RACE_SERVICE_TOKEN);
|
||||
|
||||
return useMutation<void, ApiError, WithdrawFromRaceParams>({
|
||||
mutationFn: (params) => raceService.withdrawFromRace(params.raceId, params.driverId),
|
||||
mutationFn: async (params) => {
|
||||
const result = await raceService.withdrawFromRace(params.raceId, params.driverId);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export { useAvailableLeagues } from './useAvailableLeagues';
|
||||
export { useSponsorDashboard } from './useSponsorDashboard';
|
||||
export { useSponsorSponsorships } from './useSponsorSponsorships';
|
||||
export { useSponsorBilling } from './useSponsorBilling';
|
||||
export { useSponsorLeagueDetail } from './useSponsorLeagueDetail';
|
||||
@@ -11,7 +11,7 @@ export function useSponsorBilling(sponsorId: string) {
|
||||
queryFn: async () => {
|
||||
const result = await sponsorService.getBilling(sponsorId);
|
||||
if (result.isErr()) {
|
||||
throw result.getError();
|
||||
throw new Error(result.getError().message);
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
@@ -19,4 +19,4 @@ export function useSponsorBilling(sponsorId: string) {
|
||||
});
|
||||
|
||||
return enhanceQueryResult(queryResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useAuth } from '@/lib/auth/AuthContext';
|
||||
import React from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export function useSponsorMode(): boolean {
|
||||
const { session } = useAuth();
|
||||
const [isSponsor, setIsSponsor] = React.useState(false);
|
||||
const [isSponsor, setIsSponsor] = useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (!session) {
|
||||
setIsSponsor(false);
|
||||
return;
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
export { useAllTeams } from './useAllTeams';
|
||||
export { useTeamDetails } from './useTeamDetails';
|
||||
export { useTeamMembers } from './useTeamMembers';
|
||||
export { useTeamJoinRequests } from './useTeamJoinRequests';
|
||||
export { useCreateTeam } from './useCreateTeam';
|
||||
export { useUpdateTeam } from './useUpdateTeam';
|
||||
export { useTeamMembership } from './useTeamMembership';
|
||||
export { useApproveJoinRequest } from './useApproveJoinRequest';
|
||||
export { useRejectJoinRequest } from './useRejectJoinRequest';
|
||||
export { useTeamStandings } from './useTeamStandings';
|
||||
export { useJoinTeam } from './useJoinTeam';
|
||||
export { useLeaveTeam } from './useLeaveTeam';
|
||||
export { useTeamRoster } from './useTeamRoster';
|
||||
@@ -7,7 +7,13 @@ export function useApproveJoinRequest(options?: Omit<UseMutationOptions<void, Ap
|
||||
const teamJoinService = useInject(TEAM_JOIN_SERVICE_TOKEN);
|
||||
|
||||
return useMutation<void, ApiError, void>({
|
||||
mutationFn: () => teamJoinService.approveJoinRequest(),
|
||||
mutationFn: async () => {
|
||||
const result = await teamJoinService.approveJoinRequest();
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { useMutation, UseMutationOptions } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { TEAM_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
|
||||
interface JoinTeamParams {
|
||||
@@ -10,8 +8,6 @@ interface JoinTeamParams {
|
||||
}
|
||||
|
||||
export function useJoinTeam(options?: Omit<UseMutationOptions<void, ApiError, JoinTeamParams>, 'mutationFn'>) {
|
||||
const teamService = useInject(TEAM_SERVICE_TOKEN);
|
||||
|
||||
return useMutation<void, ApiError, JoinTeamParams>({
|
||||
mutationFn: async (params) => {
|
||||
// Note: Team join functionality would need to be added to teamService
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { useMutation, UseMutationOptions } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { TEAM_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
|
||||
interface LeaveTeamParams {
|
||||
@@ -9,8 +7,6 @@ interface LeaveTeamParams {
|
||||
}
|
||||
|
||||
export function useLeaveTeam(options?: Omit<UseMutationOptions<void, ApiError, LeaveTeamParams>, 'mutationFn'>) {
|
||||
const teamService = useInject(TEAM_SERVICE_TOKEN);
|
||||
|
||||
return useMutation<void, ApiError, LeaveTeamParams>({
|
||||
mutationFn: async (params) => {
|
||||
// Note: Leave team functionality would need to be added to teamService
|
||||
|
||||
@@ -7,7 +7,13 @@ export function useRejectJoinRequest(options?: Omit<UseMutationOptions<void, Api
|
||||
const teamJoinService = useInject(TEAM_JOIN_SERVICE_TOKEN);
|
||||
|
||||
return useMutation<void, ApiError, void>({
|
||||
mutationFn: () => teamJoinService.rejectJoinRequest(),
|
||||
mutationFn: async () => {
|
||||
const result = await teamJoinService.rejectJoinRequest();
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
},
|
||||
...options,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,23 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { TEAM_JOIN_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
|
||||
export function useTeamJoinRequests(teamId: string, currentUserId: string, isOwner: boolean) {
|
||||
const teamJoinService = useInject(TEAM_JOIN_SERVICE_TOKEN);
|
||||
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['teamJoinRequests', teamId, currentUserId, isOwner],
|
||||
queryFn: () => teamJoinService.getJoinRequests(teamId, currentUserId, isOwner),
|
||||
queryFn: async () => {
|
||||
const result = await teamJoinService.getJoinRequests(teamId, currentUserId, isOwner);
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
enabled: !!teamId && !!currentUserId,
|
||||
});
|
||||
|
||||
return enhanceQueryResult(queryResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { TEAM_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||
import type { GetTeamMembershipOutputDTO } from '@/lib/types/generated/GetTeamMembershipOutputDTO';
|
||||
|
||||
export function useTeamMembership(teamId: string, driverId: string) {
|
||||
const teamService = useInject(TEAM_SERVICE_TOKEN);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { TEAM_SERVICE_TOKEN, DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { DRIVER_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||
|
||||
type TeamMemberRole = 'owner' | 'manager' | 'member';
|
||||
|
||||
interface TeamRosterMember {
|
||||
driver: any;
|
||||
driver: unknown;
|
||||
role: TeamMemberRole;
|
||||
joinedAt: string;
|
||||
rating: number | null;
|
||||
@@ -18,7 +18,6 @@ export function useTeamRoster(memberships: Array<{
|
||||
role: string;
|
||||
joinedAt: string;
|
||||
}>) {
|
||||
const teamService = useInject(TEAM_SERVICE_TOKEN);
|
||||
const driverService = useInject(DRIVER_SERVICE_TOKEN);
|
||||
|
||||
const queryResult = useQuery<TeamRosterMember[]>({
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useInject } from '@/lib/di/hooks/useInject';
|
||||
import { LEAGUE_SERVICE_TOKEN } from '@/lib/di/tokens';
|
||||
import { enhanceQueryResult } from '@/lib/di/hooks/useReactQueryWithApiError';
|
||||
|
||||
export function useTeamStandings(teamId: string, leagues: string[]) {
|
||||
const leagueService = useInject(LEAGUE_SERVICE_TOKEN);
|
||||
|
||||
export function useTeamStandings(_teamId: string, leagues: string[]) {
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['teamStandings', teamId, leagues],
|
||||
queryKey: ['teamStandings', _teamId, leagues],
|
||||
queryFn: async () => {
|
||||
// For demo purposes, create mock standings
|
||||
return leagues.map(leagueId => ({
|
||||
|
||||
@@ -13,7 +13,14 @@ export function useCapability(
|
||||
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['policySnapshot', capabilityKey],
|
||||
queryFn: () => policyService.getSnapshot(),
|
||||
queryFn: async () => {
|
||||
const result = await policyService.getSnapshot();
|
||||
if (result.isErr()) {
|
||||
const error = result.getError();
|
||||
throw new ApiError(error.message, 'SERVER_ERROR', { timestamp: new Date().toISOString() });
|
||||
}
|
||||
return result.unwrap();
|
||||
},
|
||||
staleTime: 60_000,
|
||||
gcTime: 5 * 60_000,
|
||||
...options,
|
||||
@@ -32,4 +39,4 @@ export function useCapability(
|
||||
isCapabilityEnabled: capabilityState === 'enabled',
|
||||
isCapabilityComingSoon: capabilityState === 'coming_soon',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
*/
|
||||
|
||||
import { useState, useCallback, useEffect, FormEvent, ChangeEvent, Dispatch, SetStateAction } from 'react';
|
||||
import { parseApiError, formatValidationErrorsForForm, logErrorWithContext, createErrorContext } from '@/lib/utils/errorUtils';
|
||||
import { ApiError } from '@/lib/api/base/ApiError';
|
||||
import { parseApiError, formatValidationErrorsForForm, logErrorWithContext } from '@/lib/utils/errorUtils';
|
||||
|
||||
export interface FormField<T> {
|
||||
value: T;
|
||||
@@ -16,7 +15,7 @@ export interface FormField<T> {
|
||||
validating: boolean;
|
||||
}
|
||||
|
||||
export interface FormState<T extends Record<string, any>> {
|
||||
export interface FormState<T extends Record<string, unknown>> {
|
||||
fields: { [K in keyof T]: FormField<T[K]> };
|
||||
isValid: boolean;
|
||||
isSubmitting: boolean;
|
||||
@@ -24,7 +23,7 @@ export interface FormState<T extends Record<string, any>> {
|
||||
submitCount: number;
|
||||
}
|
||||
|
||||
export interface FormOptions<T extends Record<string, any>> {
|
||||
export interface FormOptions<T extends Record<string, unknown>> {
|
||||
initialValues: T;
|
||||
validate?: (values: T) => Record<string, string> | Promise<Record<string, string>>;
|
||||
onSubmit: (values: T) => Promise<void>;
|
||||
@@ -33,7 +32,7 @@ export interface FormOptions<T extends Record<string, any>> {
|
||||
component?: string;
|
||||
}
|
||||
|
||||
export interface UseEnhancedFormReturn<T extends Record<string, any>> {
|
||||
export interface UseEnhancedFormReturn<T extends Record<string, unknown>> {
|
||||
formState: FormState<T>;
|
||||
setFormState: Dispatch<SetStateAction<FormState<T>>>;
|
||||
handleChange: (e: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => void;
|
||||
@@ -49,7 +48,7 @@ export interface UseEnhancedFormReturn<T extends Record<string, any>> {
|
||||
/**
|
||||
* Enhanced form hook with comprehensive error handling
|
||||
*/
|
||||
export function useEnhancedForm<T extends Record<string, any>>(
|
||||
export function useEnhancedForm<T extends Record<string, unknown>>(
|
||||
options: FormOptions<T>
|
||||
): UseEnhancedFormReturn<T> {
|
||||
const [formState, setFormState] = useState<FormState<T>>(() => ({
|
||||
@@ -68,6 +67,13 @@ export function useEnhancedForm<T extends Record<string, any>>(
|
||||
submitCount: 0,
|
||||
}));
|
||||
|
||||
const getValues = useCallback((): T => {
|
||||
return Object.keys(formState.fields).reduce((acc, key) => ({
|
||||
...acc,
|
||||
[key]: formState.fields[key as keyof T].value,
|
||||
}), {} as T);
|
||||
}, [formState.fields]);
|
||||
|
||||
// Validate form on change
|
||||
useEffect(() => {
|
||||
if (options.validate && formState.submitCount > 0) {
|
||||
@@ -91,18 +97,11 @@ export function useEnhancedForm<T extends Record<string, any>>(
|
||||
};
|
||||
validateAsync();
|
||||
}
|
||||
}, [formState.fields, formState.submitCount, options.validate]);
|
||||
|
||||
const getValues = useCallback((): T => {
|
||||
return Object.keys(formState.fields).reduce((acc, key) => ({
|
||||
...acc,
|
||||
[key]: formState.fields[key as keyof T].value,
|
||||
}), {} as T);
|
||||
}, [formState.fields]);
|
||||
}, [formState.fields, formState.submitCount, options.validate, getValues]);
|
||||
|
||||
const handleChange = useCallback((e: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
|
||||
const { name, value, type } = e.target;
|
||||
const checked = 'checked' in e.target ? e.target.checked : false;
|
||||
const checked = 'checked' in e.target ? (e.target as HTMLInputElement).checked : false;
|
||||
const fieldValue = type === 'checkbox' ? checked : value;
|
||||
|
||||
setFormState(prev => ({
|
||||
@@ -267,7 +266,7 @@ export function useEnhancedForm<T extends Record<string, any>>(
|
||||
}
|
||||
} catch (validationError) {
|
||||
logErrorWithContext(validationError, {
|
||||
timestamp: new Date().toISOString(),
|
||||
timestamp: new globalThis.Date().toISOString(),
|
||||
component: options.component || 'useEnhancedForm',
|
||||
action: 'validate',
|
||||
formData: values,
|
||||
@@ -298,7 +297,7 @@ export function useEnhancedForm<T extends Record<string, any>>(
|
||||
|
||||
// Log for developers
|
||||
logErrorWithContext(error, {
|
||||
timestamp: new Date().toISOString(),
|
||||
timestamp: new globalThis.Date().toISOString(),
|
||||
component: options.component || 'useEnhancedForm',
|
||||
action: 'submit',
|
||||
formData: values,
|
||||
|
||||
@@ -9,9 +9,12 @@ export function useLeagueScoringPresets() {
|
||||
|
||||
const queryResult = useQuery({
|
||||
queryKey: ['leagueScoringPresets'],
|
||||
queryFn: async () => {
|
||||
queryFn: async (): Promise<LeagueScoringPresetDTO[]> => {
|
||||
const result = await leagueService.getScoringPresets();
|
||||
return result as LeagueScoringPresetDTO[];
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.getError().message);
|
||||
}
|
||||
return result.unwrap() as unknown as LeagueScoringPresetDTO[];
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -77,7 +77,11 @@ export function useCreateLeagueWizard() {
|
||||
// Use the league service to create the league
|
||||
const result = await leagueService.createLeague(input);
|
||||
|
||||
return result;
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.getError().message);
|
||||
}
|
||||
|
||||
return result.unwrap();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user