@dbs-portal/core-api
Version:
HTTP client and API utilities for DBS Portal
197 lines • 6.01 kB
JavaScript
/**
* React Query hooks for common API operations
*/
import { useQuery, useMutation, useInfiniteQuery, useQueryClient, } from '@tanstack/react-query';
import { useCallback } from 'react';
import { queryKeys, queryOptions, mutationOptions } from './query-client';
/**
* Hook to get the API client instance
* This should be provided via context in a real application
*/
let globalApiClient = null;
export function setGlobalApiClient(client) {
globalApiClient = client;
}
function useApiClient() {
if (!globalApiClient) {
throw new Error('API client not configured. Call setGlobalApiClient() first.');
}
return globalApiClient;
}
/**
* Generic fetch hook
*/
export function useApiFetch(key, url, config, options) {
const apiClient = useApiClient();
return useQuery({
...queryOptions.standard(key, () => apiClient.get(url, config).then(response => response.data)),
...options,
});
}
/**
* Generic mutation hook
*/
export function useApiMutation(mutationFn, options) {
return useMutation({
...mutationOptions.standard(mutationFn),
...options,
});
}
/**
* GET request hook
*/
export function useGet(key, url, config, options) {
return useApiFetch(key, url, config, options);
}
/**
* POST request hook
*/
export function usePost(url, options) {
const apiClient = useApiClient();
return useApiMutation(variables => apiClient.post(url, variables), options);
}
/**
* PUT request hook
*/
export function usePut(url, options) {
const apiClient = useApiClient();
return useApiMutation(variables => apiClient.put(url, variables), options);
}
/**
* PATCH request hook
*/
export function usePatch(url, options) {
const apiClient = useApiClient();
return useApiMutation(variables => apiClient.patch(url, variables), options);
}
/**
* DELETE request hook
*/
export function useDelete(url, options) {
const apiClient = useApiClient();
return useApiMutation(() => apiClient.delete(url), options);
}
/**
* Paginated query hook
*/
export function usePaginatedQuery(key, url, page = 1, limit = 10, config, options) {
const apiClient = useApiClient();
return useQuery({
...queryOptions.standard([...key, 'paginated', { page, limit }], () => apiClient
.get(url, {
...config,
params: { ...config?.params, page, limit },
})
.then(response => response.data)),
...options,
});
}
/**
* Infinite query hook for pagination
*/
export function useInfiniteApiQuery(key, url, config, options) {
const apiClient = useApiClient();
return useInfiniteQuery({
queryKey: [...key, 'infinite'],
queryFn: ({ pageParam = 1 }) => apiClient
.get(url, {
...config,
params: { ...config?.params, page: pageParam },
})
.then(response => response.data),
getNextPageParam: lastPage => {
if (lastPage.pagination.hasNext) {
return lastPage.pagination.page + 1;
}
return undefined;
},
initialPageParam: 1,
...options,
});
}
/**
* Search query hook with debouncing
*/
export function useSearchQuery(query, url, config, options) {
const apiClient = useApiClient();
return useQuery({
queryKey: queryKeys.search(query),
queryFn: () => apiClient
.get(url, {
...config,
params: { ...config?.params, q: query },
})
.then(response => response.data),
enabled: query.length > 0,
staleTime: 30 * 1000, // 30 seconds
...options,
});
}
/**
* Cache management hooks
*/
export function useCacheUtils() {
const queryClient = useQueryClient();
const invalidateQueries = useCallback((key) => {
return queryClient.invalidateQueries({ queryKey: key });
}, [queryClient]);
const refetchQueries = useCallback((key) => {
return queryClient.refetchQueries({ queryKey: key });
}, [queryClient]);
const removeQueries = useCallback((key) => {
return queryClient.removeQueries({ queryKey: key });
}, [queryClient]);
const setQueryData = useCallback((key, data) => {
return queryClient.setQueryData(key, data);
}, [queryClient]);
const getQueryData = useCallback((key) => {
return queryClient.getQueryData(key);
}, [queryClient]);
const prefetchQuery = useCallback((key, fetcher, staleTime) => {
return queryClient.prefetchQuery({
queryKey: key,
queryFn: fetcher,
...(staleTime !== undefined && { staleTime }),
});
}, [queryClient]);
return {
invalidateQueries,
refetchQueries,
removeQueries,
setQueryData,
getQueryData,
prefetchQuery,
};
}
/**
* Optimistic update hook
*/
export function useOptimisticMutation(mutationFn, queryKey, optimisticUpdate, options) {
const queryClient = useQueryClient();
return useMutation({
mutationFn,
onMutate: async (variables) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey });
// Snapshot previous value
const previousData = queryClient.getQueryData(queryKey);
// Optimistically update
queryClient.setQueryData(queryKey, old => optimisticUpdate(old, variables));
// Return context with previous data
return { previousData };
},
onError: (error, variables, context) => {
// Rollback on error
if (context?.previousData) {
queryClient.setQueryData(queryKey, context.previousData);
}
options?.onError?.(error, variables, context);
},
onSettled: () => {
// Refetch after mutation
queryClient.invalidateQueries({ queryKey });
},
...options,
});
}
//# sourceMappingURL=hooks.js.map