import { useQuery, useMutation, useQueryClient, UseQueryOptions, UseMutationOptions } from '@tanstack/react-query'; import { toast } from 'react-hot-toast'; import api from '@/lib/api'; import { cacheKeys } from '@/lib/api-cache'; /** * Хук для выполнения GET-запросов с использованием react-query * @param key Ключ кэша * @param url URL для запроса * @param params Параметры запроса * @param options Дополнительные опции для useQuery * @returns Результат выполнения useQuery */ export function useAdminQuery( key: string | string[], url: string, params: Record = {}, options: Omit, 'queryKey' | 'queryFn'> = {} ) { const queryKey = Array.isArray(key) ? key : [key]; return useQuery({ queryKey, queryFn: async () => { try { const response = await api.get(url, { params }); return response; } catch (error) { console.error(`Error fetching data from ${url}:`, error); throw error; } }, // Оптимизированные настройки кэширования staleTime: 5 * 60 * 1000, // 5 минут - данные считаются свежими gcTime: 10 * 60 * 1000, // 10 минут - данные хранятся в кэше ...options }); } /** * Хук для выполнения мутаций (POST, PUT, DELETE) с использованием react-query * @param method Метод запроса * @param url URL для запроса или функция, возвращающая URL * @param options Дополнительные опции для useMutation * @returns Результат выполнения useMutation */ export function useAdminMutation( method: 'post' | 'put' | 'delete', url: string | ((variables: TVariables) => string), options: { onSuccessMessage?: string; onErrorMessage?: string; invalidateQueries?: (string | string[])[]; mutationOptions?: Omit, 'mutationFn'>; } = {} ) { const queryClient = useQueryClient(); const { onSuccessMessage = 'Операция выполнена успешно', onErrorMessage = 'Произошла ошибка при выполнении операции', invalidateQueries = [], mutationOptions = {} } = options; return useMutation({ mutationFn: async (variables) => { try { const resolvedUrl = typeof url === 'function' ? url(variables) : url; if (method === 'delete') { return await api.delete(resolvedUrl); } else { return await api[method](resolvedUrl, variables); } } catch (error) { console.error(`Error in ${method.toUpperCase()} request to ${typeof url === 'string' ? url : 'dynamic URL'}:`, error); throw error; } }, onSuccess: (data, variables, context) => { // Показываем сообщение об успехе if (onSuccessMessage) { toast.success(onSuccessMessage); } // Инвалидируем кэш для указанных запросов if (invalidateQueries.length > 0) { invalidateQueries.forEach(queryKey => { if (Array.isArray(queryKey)) { queryClient.invalidateQueries({ queryKey }); } else { queryClient.invalidateQueries({ queryKey: [queryKey] }); } }); } // Вызываем пользовательский обработчик успеха if (mutationOptions.onSuccess) { mutationOptions.onSuccess(data, variables, context); } }, onError: (error, variables, context) => { // Показываем сообщение об ошибке if (onErrorMessage) { toast.error(onErrorMessage); } // Вызываем пользовательский обработчик ошибки if (mutationOptions.onError) { mutationOptions.onError(error, variables, context); } }, ...mutationOptions }); } export function useProducts(params: Record = {}, options = {}) { return useAdminQuery( [cacheKeys.products, JSON.stringify(params)], '/catalog/products', params, options ); } export function useProduct(id: number | string, options = {}) { return useAdminQuery( cacheKeys.product(id), `/catalog/products/${id}`, {}, options ); } export function useCategories(params: Record = {}, options = {}) { return useAdminQuery( [cacheKeys.categories, JSON.stringify(params)], '/catalog/categories', params, options ); } export function useCollections(params: Record = {}, options = {}) { return useAdminQuery( [cacheKeys.collections, JSON.stringify(params)], '/catalog/collections', params, options ); } export function useSizes(params: Record = {}, options = {}) { return useAdminQuery( [cacheKeys.sizes, JSON.stringify(params)], '/catalog/sizes', params, options ); } export function useOrders(params: Record = {}, options = {}) { return useAdminQuery( [cacheKeys.orders, JSON.stringify(params)], '/orders', params, options ); } export function useOrder(id: number | string, options = {}) { return useAdminQuery( cacheKeys.order(id), `/orders/${id}`, {}, options ); } export function useDashboardStats(options = {}) { return useAdminQuery( cacheKeys.dashboardStats, '/dashboard/stats', {}, options ); } export function useRecentOrders(limit = 5, options = {}) { return useAdminQuery( cacheKeys.recentOrders, '/orders/recent', { limit }, options ); } export function usePopularProducts(limit = 5, options = {}) { return useAdminQuery( cacheKeys.popularProducts, '/catalog/products/popular', { limit }, options ); } export default { useAdminQuery, useAdminMutation, useProducts, useProduct, useCategories, useCollections, useSizes, useOrders, useOrder, useDashboardStats, useRecentOrders, usePopularProducts };