126 lines
3.7 KiB
TypeScript
126 lines
3.7 KiB
TypeScript
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||
import { ideasApi, type QueryIdeasParams } from '../services/ideas';
|
||
import type { CreateIdeaDto, UpdateIdeaDto } from '../types/idea';
|
||
import { useIdeasStore } from '../store/ideas';
|
||
|
||
const QUERY_KEY = 'ideas';
|
||
|
||
export function useIdeasQuery() {
|
||
const { filters, sorting, pagination } = useIdeasStore();
|
||
|
||
const params: QueryIdeasParams = {
|
||
...filters,
|
||
...sorting,
|
||
...pagination,
|
||
};
|
||
|
||
return useQuery({
|
||
queryKey: [QUERY_KEY, params],
|
||
queryFn: () => ideasApi.getAll(params),
|
||
});
|
||
}
|
||
|
||
export function useIdeaQuery(id: string) {
|
||
return useQuery({
|
||
queryKey: [QUERY_KEY, id],
|
||
queryFn: () => ideasApi.getOne(id),
|
||
enabled: !!id,
|
||
});
|
||
}
|
||
|
||
export function useModulesQuery() {
|
||
return useQuery({
|
||
queryKey: [QUERY_KEY, 'modules'],
|
||
queryFn: () => ideasApi.getModules(),
|
||
staleTime: 60000, // Cache for 1 minute
|
||
});
|
||
}
|
||
|
||
export function useCreateIdea() {
|
||
const queryClient = useQueryClient();
|
||
|
||
return useMutation({
|
||
mutationFn: (dto: CreateIdeaDto) => ideasApi.create(dto),
|
||
onSuccess: () => {
|
||
void queryClient.invalidateQueries({ queryKey: [QUERY_KEY] });
|
||
},
|
||
});
|
||
}
|
||
|
||
export function useUpdateIdea() {
|
||
const queryClient = useQueryClient();
|
||
|
||
return useMutation({
|
||
mutationFn: ({ id, dto }: { id: string; dto: UpdateIdeaDto }) =>
|
||
ideasApi.update(id, dto),
|
||
onSuccess: () => {
|
||
void queryClient.invalidateQueries({ queryKey: [QUERY_KEY] });
|
||
},
|
||
});
|
||
}
|
||
|
||
export function useDeleteIdea() {
|
||
const queryClient = useQueryClient();
|
||
|
||
return useMutation({
|
||
mutationFn: (id: string) => ideasApi.delete(id),
|
||
onSuccess: () => {
|
||
void queryClient.invalidateQueries({ queryKey: [QUERY_KEY] });
|
||
},
|
||
});
|
||
}
|
||
|
||
export function useReorderIdeas() {
|
||
const queryClient = useQueryClient();
|
||
|
||
return useMutation({
|
||
mutationFn: (items: { id: string; order: number }[]) =>
|
||
ideasApi.reorder(items),
|
||
onMutate: async (items) => {
|
||
// Получаем актуальное состояние store
|
||
const { filters, sorting, pagination } = useIdeasStore.getState();
|
||
|
||
// Отменяем исходящие запросы чтобы не перезаписать оптимистичное обновление
|
||
await queryClient.cancelQueries({ queryKey: [QUERY_KEY] });
|
||
|
||
// Сохраняем предыдущее состояние для отката
|
||
const queryKey = [QUERY_KEY, { ...filters, ...sorting, ...pagination }];
|
||
const previousData = queryClient.getQueryData(queryKey);
|
||
|
||
// Оптимистично обновляем кэш
|
||
queryClient.setQueryData(
|
||
queryKey,
|
||
(
|
||
old:
|
||
| { data: { id: string; order: number }[]; meta: unknown }
|
||
| undefined,
|
||
) => {
|
||
if (!old) return old;
|
||
|
||
// Создаём новый порядок на основе items
|
||
const orderMap = new Map(items.map((item) => [item.id, item.order]));
|
||
const newData = [...old.data].sort((a, b) => {
|
||
const orderA = orderMap.get(a.id) ?? a.order;
|
||
const orderB = orderMap.get(b.id) ?? b.order;
|
||
return orderA - orderB;
|
||
});
|
||
|
||
return { ...old, data: newData };
|
||
},
|
||
);
|
||
|
||
return { previousData, queryKey };
|
||
},
|
||
onError: (_err, _items, context) => {
|
||
// Откатываем к предыдущему состоянию при ошибке
|
||
if (context?.previousData) {
|
||
queryClient.setQueryData(context.queryKey, context.previousData);
|
||
}
|
||
},
|
||
onSettled: () => {
|
||
// Инвалидируем для синхронизации с сервером
|
||
void queryClient.invalidateQueries({ queryKey: [QUERY_KEY] });
|
||
},
|
||
});
|
||
}
|