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.all, }); // 무한 스크롤 쿼리도 명시적으로 무효화 queryClient.invalidateQueries({ queryKey: queryKeys.codes.infiniteList(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.all, }); // 무한 스크롤 쿼리도 명시적으로 무효화 queryClient.invalidateQueries({ queryKey: queryKeys.codes.infiniteList(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.all, }); // 무한 스크롤 쿼리도 명시적으로 무효화 queryClient.invalidateQueries({ queryKey: queryKeys.codes.infiniteList(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.all, }); // 무한 스크롤 쿼리도 명시적으로 무효화 queryClient.invalidateQueries({ queryKey: queryKeys.codes.infiniteList(variables.categoryCode), }); }, }); }