211 lines
4.9 KiB
TypeScript
211 lines
4.9 KiB
TypeScript
import { useState, useCallback } from 'react';
|
||
import { toast } from 'react-hot-toast';
|
||
import api from '@/lib/api';
|
||
|
||
/**
|
||
* Типы состояний запроса
|
||
*/
|
||
export type ApiStatus = 'idle' | 'loading' | 'success' | 'error';
|
||
|
||
/**
|
||
* Интерфейс для опций хука
|
||
*/
|
||
interface UseAdminApiOptions {
|
||
onSuccess?: (data: any) => void;
|
||
onError?: (error: any) => void;
|
||
showSuccessToast?: boolean;
|
||
showErrorToast?: boolean;
|
||
successMessage?: string;
|
||
errorMessage?: string;
|
||
}
|
||
|
||
/**
|
||
* Хук для работы с API в админке
|
||
* @param options Опции хука
|
||
* @returns Объект с функциями и состоянием
|
||
*/
|
||
export function useAdminApi(options: UseAdminApiOptions = {}) {
|
||
const [status, setStatus] = useState<ApiStatus>('idle');
|
||
const [data, setData] = useState<any>(null);
|
||
const [error, setError] = useState<any>(null);
|
||
|
||
const {
|
||
onSuccess,
|
||
onError,
|
||
showSuccessToast = false,
|
||
showErrorToast = true,
|
||
successMessage = 'Операция выполнена успешно',
|
||
errorMessage = 'Произошла ошибка при выполнении операции'
|
||
} = options;
|
||
|
||
/**
|
||
* Обработка ошибки API
|
||
*/
|
||
const handleError = useCallback((err: any, customMessage?: string) => {
|
||
console.error('API Error:', err);
|
||
|
||
// Формируем сообщение об ошибке
|
||
let message = customMessage || errorMessage;
|
||
|
||
if (err?.response?.data?.detail) {
|
||
message = err.response.data.detail;
|
||
} else if (err?.message) {
|
||
message = err.message;
|
||
}
|
||
|
||
// Устанавливаем состояние ошибки
|
||
setError(message);
|
||
setStatus('error');
|
||
|
||
// Показываем уведомление об ошибке
|
||
if (showErrorToast) {
|
||
toast.error(message);
|
||
}
|
||
|
||
// Вызываем пользовательский обработчик ошибки
|
||
if (onError) {
|
||
onError(err);
|
||
}
|
||
}, [errorMessage, showErrorToast, onError]);
|
||
|
||
/**
|
||
* Выполнение GET запроса
|
||
*/
|
||
const get = useCallback(async <T>(url: string, params = {}) => {
|
||
try {
|
||
setStatus('loading');
|
||
setError(null);
|
||
|
||
const response = await api.get<T>(url, { params });
|
||
|
||
setData(response);
|
||
setStatus('success');
|
||
|
||
if (showSuccessToast) {
|
||
toast.success(successMessage);
|
||
}
|
||
|
||
if (onSuccess) {
|
||
onSuccess(response);
|
||
}
|
||
|
||
return response;
|
||
} catch (err) {
|
||
handleError(err);
|
||
return null;
|
||
}
|
||
}, [handleError, onSuccess, showSuccessToast, successMessage]);
|
||
|
||
/**
|
||
* Выполнение POST запроса
|
||
*/
|
||
const post = useCallback(async <T>(url: string, data = {}, config = {}) => {
|
||
try {
|
||
setStatus('loading');
|
||
setError(null);
|
||
|
||
const response = await api.post<T>(url, data, config);
|
||
|
||
setData(response);
|
||
setStatus('success');
|
||
|
||
if (showSuccessToast) {
|
||
toast.success(successMessage);
|
||
}
|
||
|
||
if (onSuccess) {
|
||
onSuccess(response);
|
||
}
|
||
|
||
return response;
|
||
} catch (err) {
|
||
handleError(err);
|
||
return null;
|
||
}
|
||
}, [handleError, onSuccess, showSuccessToast, successMessage]);
|
||
|
||
/**
|
||
* Выполнение PUT запроса
|
||
*/
|
||
const put = useCallback(async <T>(url: string, data = {}, config = {}) => {
|
||
try {
|
||
setStatus('loading');
|
||
setError(null);
|
||
|
||
const response = await api.put<T>(url, data, config);
|
||
|
||
setData(response);
|
||
setStatus('success');
|
||
|
||
if (showSuccessToast) {
|
||
toast.success(successMessage);
|
||
}
|
||
|
||
if (onSuccess) {
|
||
onSuccess(response);
|
||
}
|
||
|
||
return response;
|
||
} catch (err) {
|
||
handleError(err);
|
||
return null;
|
||
}
|
||
}, [handleError, onSuccess, showSuccessToast, successMessage]);
|
||
|
||
/**
|
||
* Выполнение DELETE запроса
|
||
*/
|
||
const del = useCallback(async <T>(url: string, config = {}) => {
|
||
try {
|
||
setStatus('loading');
|
||
setError(null);
|
||
|
||
const response = await api.delete<T>(url, config);
|
||
|
||
setData(response);
|
||
setStatus('success');
|
||
|
||
if (showSuccessToast) {
|
||
toast.success(successMessage);
|
||
}
|
||
|
||
if (onSuccess) {
|
||
onSuccess(response);
|
||
}
|
||
|
||
return response;
|
||
} catch (err) {
|
||
handleError(err);
|
||
return null;
|
||
}
|
||
}, [handleError, onSuccess, showSuccessToast, successMessage]);
|
||
|
||
/**
|
||
* Сброс состояния
|
||
*/
|
||
const reset = useCallback(() => {
|
||
setStatus('idle');
|
||
setData(null);
|
||
setError(null);
|
||
}, []);
|
||
|
||
return {
|
||
status,
|
||
isLoading: status === 'loading',
|
||
isSuccess: status === 'success',
|
||
isError: status === 'error',
|
||
data,
|
||
error,
|
||
get,
|
||
post,
|
||
put,
|
||
delete: del,
|
||
reset,
|
||
setData,
|
||
setError,
|
||
setStatus
|
||
};
|
||
}
|
||
|
||
export default useAdminApi;
|