dressed_for_succes_store/frontend/hooks/useOrders.ts
ilya_zahvatkin 41c1385546 for deploy
2025-05-01 18:29:38 +07:00

287 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;