287 lines
7.8 KiB
TypeScript
287 lines
7.8 KiB
TypeScript
import { useState, useCallback, useEffect } from 'react';
|
||
import { useRouter, useSearchParams } from 'next/navigation';
|
||
import { toast } from 'react-hot-toast';
|
||
import { useAdminQuery, useAdminMutation } from '@/hooks/useAdminApi';
|
||
import { cacheKeys } from '@/lib/api-cache';
|
||
import { Order } from '@/lib/orders';
|
||
|
||
interface OrdersState {
|
||
orders: Order[];
|
||
loading: {
|
||
fetch: boolean;
|
||
update: boolean;
|
||
};
|
||
error: Error | null;
|
||
selectedOrders: number[];
|
||
pagination: {
|
||
page: number;
|
||
pageSize: number;
|
||
total: number;
|
||
};
|
||
filters: {
|
||
search: string;
|
||
status: string;
|
||
dateRange: string;
|
||
};
|
||
}
|
||
|
||
export function useOrders() {
|
||
const router = useRouter();
|
||
const searchParams = useSearchParams();
|
||
|
||
// Состояние
|
||
const [state, setState] = useState<OrdersState>({
|
||
orders: [],
|
||
loading: {
|
||
fetch: true,
|
||
update: false,
|
||
},
|
||
error: null,
|
||
selectedOrders: [],
|
||
pagination: {
|
||
page: 1,
|
||
pageSize: 10,
|
||
total: 0,
|
||
},
|
||
filters: {
|
||
search: '',
|
||
status: '',
|
||
dateRange: '',
|
||
},
|
||
});
|
||
|
||
// Получаем параметры из URL при первой загрузке
|
||
useEffect(() => {
|
||
const page = searchParams.get('page') ? parseInt(searchParams.get('page') as string, 10) : 1;
|
||
const search = searchParams.get('search') || '';
|
||
const status = searchParams.get('status') || '';
|
||
const dateRange = searchParams.get('dateRange') || '';
|
||
|
||
setState(prev => ({
|
||
...prev,
|
||
pagination: {
|
||
...prev.pagination,
|
||
page,
|
||
},
|
||
filters: {
|
||
search,
|
||
status,
|
||
dateRange,
|
||
},
|
||
}));
|
||
}, [searchParams]);
|
||
|
||
// Формируем параметры запроса
|
||
const queryParams = {
|
||
skip: (state.pagination.page - 1) * state.pagination.pageSize,
|
||
limit: state.pagination.pageSize,
|
||
search: state.filters.search,
|
||
status: state.filters.status || undefined,
|
||
date_range: state.filters.dateRange || undefined,
|
||
};
|
||
|
||
// Запрос на получение заказов
|
||
const { data, isLoading, error, refetch } = useAdminQuery<Order[]>(
|
||
[cacheKeys.orders, JSON.stringify(queryParams)],
|
||
'/orders',
|
||
queryParams,
|
||
{
|
||
onSuccess: (data) => {
|
||
if (data) {
|
||
// API возвращает массив заказов, а не объект с полями orders и total
|
||
const orders = Array.isArray(data) ? data : [];
|
||
setState(prev => ({
|
||
...prev,
|
||
orders: orders,
|
||
pagination: {
|
||
...prev.pagination,
|
||
total: orders.length, // Используем длину массива как общее количество
|
||
},
|
||
loading: {
|
||
...prev.loading,
|
||
fetch: false,
|
||
},
|
||
}));
|
||
}
|
||
},
|
||
onError: (err) => {
|
||
setState(prev => ({
|
||
...prev,
|
||
error: err as Error,
|
||
loading: {
|
||
...prev.loading,
|
||
fetch: false,
|
||
},
|
||
}));
|
||
},
|
||
}
|
||
);
|
||
|
||
// Мутация для обновления статуса заказа
|
||
const updateStatusMutation = useAdminMutation<any, Error, { id: number, status: string }>(
|
||
'put',
|
||
({ id }) => `/orders/${id}`,
|
||
{
|
||
onSuccessMessage: 'Статус заказа успешно обновлен',
|
||
onErrorMessage: 'Не удалось обновить статус заказа',
|
||
invalidateQueries: [cacheKeys.orders],
|
||
mutationOptions: {
|
||
onMutate: () => {
|
||
setState(prev => ({
|
||
...prev,
|
||
loading: {
|
||
...prev.loading,
|
||
update: true,
|
||
},
|
||
}));
|
||
},
|
||
onSettled: () => {
|
||
setState(prev => ({
|
||
...prev,
|
||
loading: {
|
||
...prev.loading,
|
||
update: false,
|
||
},
|
||
}));
|
||
},
|
||
},
|
||
}
|
||
);
|
||
|
||
// Обработчик обновления статуса заказа
|
||
const updateOrderStatus = useCallback(async (id: number, status: string) => {
|
||
try {
|
||
// Передаем только статус в теле запроса, как требуется API
|
||
await updateStatusMutation.mutateAsync({
|
||
id,
|
||
status
|
||
});
|
||
} catch (error) {
|
||
console.error('Error updating order status:', error);
|
||
}
|
||
}, [updateStatusMutation]);
|
||
|
||
// Обработчик изменения фильтров
|
||
const setFilter = useCallback((key: keyof OrdersState['filters'], value: any) => {
|
||
setState(prev => ({
|
||
...prev,
|
||
filters: {
|
||
...prev.filters,
|
||
[key]: value,
|
||
},
|
||
pagination: {
|
||
...prev.pagination,
|
||
page: 1, // Сбрасываем страницу при изменении фильтров
|
||
},
|
||
}));
|
||
|
||
// Обновляем URL с новыми параметрами
|
||
const params = new URLSearchParams(searchParams.toString());
|
||
params.set('page', '1');
|
||
if (value !== null && value !== '') {
|
||
params.set(key, value.toString());
|
||
} else {
|
||
params.delete(key);
|
||
}
|
||
|
||
// Обновляем URL
|
||
router.push(`/admin/orders?${params.toString()}`);
|
||
}, [router, searchParams]);
|
||
|
||
// Обработчик изменения страницы
|
||
const setPage = useCallback((page: number) => {
|
||
setState(prev => ({
|
||
...prev,
|
||
pagination: {
|
||
...prev.pagination,
|
||
page,
|
||
},
|
||
}));
|
||
|
||
// Обновляем URL с новой страницей
|
||
const params = new URLSearchParams(searchParams.toString());
|
||
params.set('page', page.toString());
|
||
router.push(`/admin/orders?${params.toString()}`);
|
||
}, [router, searchParams]);
|
||
|
||
// Обработчик изменения размера страницы
|
||
const setPageSize = useCallback((pageSize: number) => {
|
||
setState(prev => ({
|
||
...prev,
|
||
pagination: {
|
||
...prev.pagination,
|
||
pageSize,
|
||
page: 1, // Сбрасываем страницу при изменении размера
|
||
},
|
||
}));
|
||
|
||
// Обновляем URL с новым размером страницы
|
||
const params = new URLSearchParams(searchParams.toString());
|
||
params.set('page', '1');
|
||
params.set('pageSize', pageSize.toString());
|
||
router.push(`/admin/orders?${params.toString()}`);
|
||
}, [router, searchParams]);
|
||
|
||
// Обработчик выбора заказов
|
||
const selectOrders = useCallback((selectedIds: number[]) => {
|
||
setState(prev => ({
|
||
...prev,
|
||
selectedOrders: selectedIds,
|
||
}));
|
||
}, []);
|
||
|
||
// Обновляем состояние при изменении данных
|
||
useEffect(() => {
|
||
if (data) {
|
||
// API возвращает массив заказов, а не объект с полями orders и total
|
||
const orders = Array.isArray(data) ? data : [];
|
||
setState(prev => ({
|
||
...prev,
|
||
orders: orders,
|
||
pagination: {
|
||
...prev.pagination,
|
||
total: orders.length, // Используем длину массива как общее количество
|
||
},
|
||
loading: {
|
||
...prev.loading,
|
||
fetch: false,
|
||
},
|
||
}));
|
||
}
|
||
}, [data]);
|
||
|
||
// Обновляем состояние при ошибке
|
||
useEffect(() => {
|
||
if (error) {
|
||
setState(prev => ({
|
||
...prev,
|
||
error: error as Error,
|
||
loading: {
|
||
...prev.loading,
|
||
fetch: false,
|
||
},
|
||
}));
|
||
}
|
||
}, [error]);
|
||
|
||
return {
|
||
orders: state.orders,
|
||
loading: {
|
||
fetch: isLoading || state.loading.fetch,
|
||
update: state.loading.update
|
||
},
|
||
error: state.error,
|
||
selectedOrders: state.selectedOrders,
|
||
pagination: state.pagination,
|
||
filters: state.filters,
|
||
updateOrderStatus,
|
||
setFilter,
|
||
setPage,
|
||
setPageSize,
|
||
selectOrders,
|
||
refetch,
|
||
};
|
||
}
|
||
|
||
export default useOrders;
|