ERP-node/frontend/hooks/queries/useCodes.ts

154 lines
5.0 KiB
TypeScript

import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { commonCodeApi } from "@/lib/api/commonCode";
import { queryKeys } from "@/lib/queryKeys";
import type { CodeFilter, CreateCodeData, UpdateCodeData } from "@/lib/schemas/commonCode";
/**
* 코드 목록 조회 훅
*/
export function useCodes(categoryCode: string, filters?: CodeFilter) {
return useQuery({
queryKey: queryKeys.codes.list(categoryCode, filters),
queryFn: () => commonCodeApi.codes.getList(categoryCode, filters),
select: (data) => data.data || [],
enabled: !!categoryCode, // categoryCode가 있을 때만 실행
});
}
/**
* 코드 생성 뮤테이션 훅
*/
export function useCreateCode() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ categoryCode, data }: { categoryCode: string; data: CreateCodeData }) =>
commonCodeApi.codes.create(categoryCode, data),
onSuccess: (_, variables) => {
// 해당 카테고리의 모든 코드 쿼리 무효화
queryClient.invalidateQueries({
queryKey: queryKeys.codes.list(variables.categoryCode),
});
},
onError: (error) => {
console.error("코드 생성 실패:", error);
},
});
}
/**
* 코드 수정 뮤테이션 훅
*/
export function useUpdateCode() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({
categoryCode,
codeValue,
data,
}: {
categoryCode: string;
codeValue: string;
data: UpdateCodeData;
}) => commonCodeApi.codes.update(categoryCode, codeValue, data),
onSuccess: (_, variables) => {
// 해당 코드 상세 쿼리 무효화
queryClient.invalidateQueries({
queryKey: queryKeys.codes.detail(variables.categoryCode, variables.codeValue),
});
// 해당 카테고리의 코드 목록 쿼리 무효화
queryClient.invalidateQueries({
queryKey: queryKeys.codes.list(variables.categoryCode),
});
},
onError: (error) => {
console.error("코드 수정 실패:", error);
},
});
}
/**
* 코드 삭제 뮤테이션 훅
*/
export function useDeleteCode() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ categoryCode, codeValue }: { categoryCode: string; codeValue: string }) =>
commonCodeApi.codes.delete(categoryCode, codeValue),
onSuccess: (_, variables) => {
// 해당 코드 관련 쿼리 무효화 및 캐시 제거
queryClient.invalidateQueries({
queryKey: queryKeys.codes.list(variables.categoryCode),
});
queryClient.removeQueries({
queryKey: queryKeys.codes.detail(variables.categoryCode, variables.codeValue),
});
},
onError: (error) => {
console.error("코드 삭제 실패:", error);
},
});
}
/**
* 코드 순서 변경 뮤테이션 훅
*/
export function useReorderCodes() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({
categoryCode,
codes,
}: {
categoryCode: string;
codes: Array<{ codeValue: string; sortOrder: number }>;
}) => commonCodeApi.codes.reorder(categoryCode, codes),
onMutate: async ({ categoryCode, codes }) => {
// 진행 중인 쿼리들을 취소해서 optimistic update가 덮어쓰이지 않도록 함
await queryClient.cancelQueries({ queryKey: queryKeys.codes.list(categoryCode) });
// 이전 데이터를 백업
const previousCodes = queryClient.getQueryData(queryKeys.codes.list(categoryCode));
// Optimistic update: 새로운 순서로 즉시 업데이트
if (previousCodes && (previousCodes as any).data && Array.isArray((previousCodes as any).data)) {
const previousCodesArray = (previousCodes as any).data;
// 기존 데이터를 복사하고 sort_order만 업데이트
const updatedCodes = [...previousCodesArray].map((code: any) => {
const newCodeData = codes.find((c) => c.codeValue === code.code_value);
return newCodeData ? { ...code, sort_order: newCodeData.sortOrder } : code;
});
// sort_order로 정렬
updatedCodes.sort((a: any, b: any) => a.sort_order - b.sort_order);
// API 응답 형태로 캐시에 저장 (기존 구조 유지)
queryClient.setQueryData(queryKeys.codes.list(categoryCode), {
...(previousCodes as any),
data: updatedCodes,
});
}
// 롤백용 데이터 반환
return { previousCodes };
},
onError: (error, variables, context) => {
console.error("코드 순서 변경 실패:", error);
// 에러 시 이전 데이터로 롤백
if (context?.previousCodes) {
queryClient.setQueryData(queryKeys.codes.list(variables.categoryCode), context.previousCodes);
}
},
onSettled: (_, __, variables) => {
// 성공/실패와 관계없이 최종적으로 서버 데이터로 동기화
queryClient.invalidateQueries({
queryKey: queryKeys.codes.list(variables.categoryCode),
});
},
});
}