2025-09-05 17:49:48 +02:00
|
|
|
/**
|
|
|
|
|
* Auth React Query hooks
|
2026-01-15 20:45:49 +01:00
|
|
|
* Updated for atomic registration architecture with 3DS support
|
2025-09-05 17:49:48 +02:00
|
|
|
*/
|
|
|
|
|
import { useMutation, useQuery, useQueryClient, UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
|
|
|
|
|
import { authService } from '../services/auth';
|
2025-10-06 15:27:01 +02:00
|
|
|
import {
|
|
|
|
|
UserRegistration,
|
|
|
|
|
UserLogin,
|
|
|
|
|
TokenResponse,
|
|
|
|
|
PasswordChange,
|
|
|
|
|
PasswordReset,
|
|
|
|
|
UserResponse,
|
|
|
|
|
UserUpdate,
|
2026-01-15 20:45:49 +01:00
|
|
|
TokenVerification,
|
|
|
|
|
RegistrationStartResponse,
|
|
|
|
|
RegistrationCompletionResponse,
|
|
|
|
|
RegistrationVerification,
|
2025-09-05 17:49:48 +02:00
|
|
|
} from '../types/auth';
|
|
|
|
|
import { ApiError } from '../client';
|
2025-09-24 21:54:49 +02:00
|
|
|
import { useAuthStore } from '../../stores/auth.store';
|
2025-09-05 17:49:48 +02:00
|
|
|
|
|
|
|
|
// Query Keys
|
|
|
|
|
export const authKeys = {
|
|
|
|
|
all: ['auth'] as const,
|
|
|
|
|
profile: () => [...authKeys.all, 'profile'] as const,
|
|
|
|
|
health: () => [...authKeys.all, 'health'] as const,
|
|
|
|
|
verify: (token?: string) => [...authKeys.all, 'verify', token] as const,
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
// Queries
|
|
|
|
|
export const useAuthProfile = (
|
|
|
|
|
options?: Omit<UseQueryOptions<UserResponse, ApiError>, 'queryKey' | 'queryFn'>
|
|
|
|
|
) => {
|
|
|
|
|
return useQuery<UserResponse, ApiError>({
|
|
|
|
|
queryKey: authKeys.profile(),
|
|
|
|
|
queryFn: () => authService.getProfile(),
|
|
|
|
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useAuthHealth = (
|
2025-10-06 15:27:01 +02:00
|
|
|
options?: Omit<UseQueryOptions<{ status: string; service: string }, ApiError>, 'queryKey' | 'queryFn'>
|
2025-09-05 17:49:48 +02:00
|
|
|
) => {
|
2025-10-06 15:27:01 +02:00
|
|
|
return useQuery<{ status: string; service: string }, ApiError>({
|
2025-09-05 17:49:48 +02:00
|
|
|
queryKey: authKeys.health(),
|
|
|
|
|
queryFn: () => authService.healthCheck(),
|
|
|
|
|
staleTime: 30 * 1000, // 30 seconds
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useVerifyToken = (
|
|
|
|
|
token?: string,
|
2025-10-06 15:27:01 +02:00
|
|
|
options?: Omit<UseQueryOptions<TokenVerification, ApiError>, 'queryKey' | 'queryFn'>
|
2025-09-05 17:49:48 +02:00
|
|
|
) => {
|
2025-10-06 15:27:01 +02:00
|
|
|
return useQuery<TokenVerification, ApiError>({
|
2025-09-05 17:49:48 +02:00
|
|
|
queryKey: authKeys.verify(token),
|
|
|
|
|
queryFn: () => authService.verifyToken(token),
|
|
|
|
|
enabled: !!token,
|
|
|
|
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Mutations
|
2026-01-15 20:45:49 +01:00
|
|
|
export const useStartRegistration = (
|
|
|
|
|
options?: UseMutationOptions<RegistrationStartResponse, ApiError, UserRegistration>
|
2025-09-05 17:49:48 +02:00
|
|
|
) => {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
2026-01-15 20:45:49 +01:00
|
|
|
return useMutation<RegistrationStartResponse, ApiError, UserRegistration>({
|
|
|
|
|
mutationFn: (userData: UserRegistration) => authService.startRegistration(userData),
|
|
|
|
|
onSuccess: (data) => {
|
|
|
|
|
// If no 3DS required, update profile query with new user data
|
|
|
|
|
if (data.user) {
|
|
|
|
|
queryClient.setQueryData(authKeys.profile(), data.user);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Hook for completing registration after 3DS verification
|
|
|
|
|
* This is the second step in the atomic registration flow
|
|
|
|
|
*/
|
|
|
|
|
export const useCompleteRegistration = (
|
|
|
|
|
options?: UseMutationOptions<RegistrationCompletionResponse, ApiError, RegistrationVerification>
|
|
|
|
|
) => {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation<RegistrationCompletionResponse, ApiError, RegistrationVerification>({
|
|
|
|
|
mutationFn: (verificationData: RegistrationVerification) => authService.completeRegistration(verificationData),
|
2025-09-05 17:49:48 +02:00
|
|
|
onSuccess: (data) => {
|
|
|
|
|
// Update profile query with new user data
|
|
|
|
|
if (data.user) {
|
|
|
|
|
queryClient.setQueryData(authKeys.profile(), data.user);
|
|
|
|
|
}
|
2026-01-15 20:45:49 +01:00
|
|
|
// Invalidate all queries to refresh data
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: ['auth'] });
|
2025-09-05 17:49:48 +02:00
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-15 20:45:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-05 17:49:48 +02:00
|
|
|
export const useLogin = (
|
|
|
|
|
options?: UseMutationOptions<TokenResponse, ApiError, UserLogin>
|
|
|
|
|
) => {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation<TokenResponse, ApiError, UserLogin>({
|
|
|
|
|
mutationFn: (loginData: UserLogin) => authService.login(loginData),
|
|
|
|
|
onSuccess: (data) => {
|
|
|
|
|
// Update profile query with new user data
|
|
|
|
|
if (data.user) {
|
|
|
|
|
queryClient.setQueryData(authKeys.profile(), data.user);
|
|
|
|
|
}
|
|
|
|
|
// Invalidate all queries to refresh data
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: ['auth'] });
|
|
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useRefreshToken = (
|
|
|
|
|
options?: UseMutationOptions<TokenResponse, ApiError, string>
|
|
|
|
|
) => {
|
|
|
|
|
return useMutation<TokenResponse, ApiError, string>({
|
|
|
|
|
mutationFn: (refreshToken: string) => authService.refreshToken(refreshToken),
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useLogout = (
|
|
|
|
|
options?: UseMutationOptions<{ message: string }, ApiError, string>
|
|
|
|
|
) => {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation<{ message: string }, ApiError, string>({
|
|
|
|
|
mutationFn: (refreshToken: string) => authService.logout(refreshToken),
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
// Clear all queries on logout
|
|
|
|
|
queryClient.clear();
|
|
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useChangePassword = (
|
|
|
|
|
options?: UseMutationOptions<{ message: string }, ApiError, PasswordChange>
|
|
|
|
|
) => {
|
|
|
|
|
return useMutation<{ message: string }, ApiError, PasswordChange>({
|
|
|
|
|
mutationFn: (passwordData: PasswordChange) => authService.changePassword(passwordData),
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2026-01-16 09:55:54 +01:00
|
|
|
export const useRequestPasswordReset = (
|
|
|
|
|
options?: UseMutationOptions<{ message: string }, ApiError, string>
|
|
|
|
|
) => {
|
|
|
|
|
return useMutation<{ message: string }, ApiError, string>({
|
|
|
|
|
mutationFn: (email: string) => authService.requestPasswordReset(email),
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useResetPasswordWithToken = (
|
|
|
|
|
options?: UseMutationOptions<{ message: string }, ApiError, { token: string; newPassword: string }>
|
2025-09-05 17:49:48 +02:00
|
|
|
) => {
|
2026-01-16 09:55:54 +01:00
|
|
|
return useMutation<{ message: string }, ApiError, { token: string; newPassword: string }>({
|
|
|
|
|
mutationFn: ({ token, newPassword }) => authService.resetPasswordWithToken(token, newPassword),
|
2025-09-05 17:49:48 +02:00
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useUpdateProfile = (
|
|
|
|
|
options?: UseMutationOptions<UserResponse, ApiError, UserUpdate>
|
|
|
|
|
) => {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation<UserResponse, ApiError, UserUpdate>({
|
|
|
|
|
mutationFn: (updateData: UserUpdate) => authService.updateProfile(updateData),
|
|
|
|
|
onSuccess: (data) => {
|
|
|
|
|
// Update the profile cache
|
|
|
|
|
queryClient.setQueryData(authKeys.profile(), data);
|
2025-09-24 21:54:49 +02:00
|
|
|
// Update the auth store user to maintain consistency
|
|
|
|
|
const authStore = useAuthStore.getState();
|
|
|
|
|
if (authStore.user) {
|
2025-10-06 15:27:01 +02:00
|
|
|
authStore.updateUser(data as any);
|
2025-09-24 21:54:49 +02:00
|
|
|
}
|
2025-09-05 17:49:48 +02:00
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const useVerifyEmail = (
|
|
|
|
|
options?: UseMutationOptions<{ message: string }, ApiError, { userId: string; verificationToken: string }>
|
|
|
|
|
) => {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
|
|
|
|
|
return useMutation<{ message: string }, ApiError, { userId: string; verificationToken: string }>({
|
|
|
|
|
mutationFn: ({ userId, verificationToken }) =>
|
|
|
|
|
authService.verifyEmail(userId, verificationToken),
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
// Invalidate profile to get updated verification status
|
|
|
|
|
queryClient.invalidateQueries({ queryKey: authKeys.profile() });
|
|
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
};
|