ERP-node/frontend/hooks/useCommonCode.ts

321 lines
9.7 KiB
TypeScript

import { useState, useEffect, useCallback } from "react";
import { commonCodeApi } from "@/lib/api/commonCode";
import {
CodeCategory,
CodeInfo,
CreateCategoryRequest,
UpdateCategoryRequest,
CreateCodeRequest,
UpdateCodeRequest,
GetCategoriesQuery,
GetCodesQuery,
} from "@/types/commonCode";
/**
* 공통코드 관리를 위한 커스텀 훅
*/
export function useCommonCode() {
// 카테고리 관련 상태
const [categories, setCategories] = useState<CodeCategory[]>([]);
const [categoriesLoading, setCategoriesLoading] = useState(false);
const [categoriesError, setCategoriesError] = useState<string | null>(null);
const [totalCategories, setTotalCategories] = useState(0);
// 코드 관련 상태
const [codes, setCodes] = useState<CodeInfo[]>([]);
const [codesLoading, setCodesLoading] = useState(false);
const [codesError, setCodesError] = useState<string | null>(null);
// 선택된 카테고리
const [selectedCategoryCode, setSelectedCategoryCode] = useState<string>("");
/**
* 카테고리 목록 조회
*/
const fetchCategories = useCallback(async (params?: GetCategoriesQuery) => {
setCategoriesLoading(true);
setCategoriesError(null);
try {
const response = await commonCodeApi.categories.getList(params);
if (response.success) {
setCategories(response.data || []);
setTotalCategories(response.total || 0);
setCategoriesError(null); // 에러 상태 초기화
} else {
throw new Error(response.message || "카테고리 조회에 실패했습니다.");
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.";
setCategoriesError(errorMessage);
console.error("카테고리 조회 오류:", error);
} finally {
setCategoriesLoading(false);
}
}, []);
/**
* 코드 목록 조회
*/
const fetchCodes = useCallback(async (categoryCode: string, params?: GetCodesQuery) => {
if (!categoryCode) {
setCodes([]);
return;
}
setCodesLoading(true);
setCodesError(null);
try {
const response = await commonCodeApi.codes.getList(categoryCode, params);
if (response.success && response.data) {
setCodes(response.data);
} else {
throw new Error(response.message || "코드 조회에 실패했습니다.");
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.";
setCodesError(errorMessage);
console.error("코드 조회 오류:", error);
} finally {
setCodesLoading(false);
}
}, []);
/**
* 카테고리 생성
*/
const createCategory = useCallback(
async (data: CreateCategoryRequest) => {
try {
const response = await commonCodeApi.categories.create(data);
if (response.success) {
// 🔥 즉시 UI 업데이트: 새로운 카테고리를 현재 목록에 추가
const newCategory = response.data;
setCategories((prevCategories) => [...prevCategories, newCategory]);
// 🔄 동시에 서버에서 최신 데이터 가져오기 (백그라운드)
fetchCategories();
return response;
} else {
throw new Error(response.message || "카테고리 생성에 실패했습니다.");
}
} catch (error) {
console.error("카테고리 생성 오류:", error);
throw error;
}
},
[fetchCategories],
);
/**
* 카테고리 수정
*/
const updateCategory = useCallback(
async (categoryCode: string, data: UpdateCategoryRequest) => {
try {
const response = await commonCodeApi.categories.update(categoryCode, data);
if (response.success) {
// 🔥 즉시 UI 업데이트: 수정된 카테고리를 현재 목록에서 업데이트
const updatedCategory = response.data;
setCategories((prevCategories) =>
prevCategories.map((category) => (category.category_code === categoryCode ? updatedCategory : category)),
);
// 🔄 동시에 서버에서 최신 데이터 가져오기 (백그라운드)
fetchCategories();
return response;
} else {
throw new Error(response.message || "카테고리 수정에 실패했습니다.");
}
} catch (error) {
console.error("카테고리 수정 오류:", error);
throw error;
}
},
[fetchCategories],
);
/**
* 카테고리 삭제
*/
const deleteCategory = useCallback(
async (categoryCode: string) => {
try {
const response = await commonCodeApi.categories.delete(categoryCode);
if (response.success) {
// 🔥 즉시 UI 업데이트: 삭제된 카테고리를 현재 목록에서 제거
setCategories((prevCategories) =>
prevCategories.filter((category) => category.category_code !== categoryCode),
);
// 선택된 카테고리가 삭제된 경우 선택 해제
if (selectedCategoryCode === categoryCode) {
setSelectedCategoryCode(""); // 선택 해제
setCodes([]); // 코드 목록 초기화
}
// 🔄 동시에 서버에서 최신 데이터 가져오기 (백그라운드)
fetchCategories();
return response;
} else {
throw new Error(response.message || "카테고리 삭제에 실패했습니다.");
}
} catch (error) {
console.error("카테고리 삭제 오류:", error);
throw error;
}
},
[fetchCategories, selectedCategoryCode],
);
/**
* 코드 생성
*/
const createCode = useCallback(
async (categoryCode: string, data: CreateCodeRequest) => {
try {
const response = await commonCodeApi.codes.create(categoryCode, data);
if (response.success) {
// 🔥 즉시 UI 업데이트: 새로운 코드를 현재 목록에 추가
const newCode = response.data;
setCodes((prevCodes) => [...prevCodes, newCode]);
// 🔄 동시에 서버에서 최신 데이터 가져오기 (백그라운드)
fetchCodes(categoryCode);
return response;
} else {
throw new Error(response.message || "코드 생성에 실패했습니다.");
}
} catch (error) {
console.error("코드 생성 오류:", error);
throw error;
}
},
[fetchCodes],
);
/**
* 코드 수정
*/
const updateCode = useCallback(
async (categoryCode: string, codeValue: string, data: UpdateCodeRequest) => {
try {
const response = await commonCodeApi.codes.update(categoryCode, codeValue, data);
if (response.success) {
// 🔥 즉시 UI 업데이트: 수정된 코드를 현재 목록에서 업데이트
const updatedCode = response.data;
setCodes((prevCodes) => prevCodes.map((code) => (code.code_value === codeValue ? updatedCode : code)));
// 🔄 동시에 서버에서 최신 데이터 가져오기 (백그라운드)
fetchCodes(categoryCode);
return response;
} else {
throw new Error(response.message || "코드 수정에 실패했습니다.");
}
} catch (error) {
console.error("코드 수정 오류:", error);
throw error;
}
},
[fetchCodes],
);
/**
* 코드 삭제
*/
const deleteCode = useCallback(
async (categoryCode: string, codeValue: string) => {
try {
const response = await commonCodeApi.codes.delete(categoryCode, codeValue);
if (response.success) {
// 🔥 즉시 UI 업데이트: 삭제된 코드를 현재 목록에서 제거
setCodes((prevCodes) => prevCodes.filter((code) => code.code_value !== codeValue));
// 🔄 동시에 서버에서 최신 데이터 가져오기 (백그라운드)
fetchCodes(categoryCode);
return response;
} else {
throw new Error(response.message || "코드 삭제에 실패했습니다.");
}
} catch (error) {
console.error("코드 삭제 오류:", error);
throw error;
}
},
[fetchCodes],
);
const reorderCodes = useCallback(
async (categoryCode: string, codes: Array<{ codeValue: string; sortOrder: number }>) => {
try {
const response = await commonCodeApi.codes.reorder(categoryCode, { codes });
if (response.success) {
console.log("✅ 코드 순서 변경 성공");
} else {
throw new Error(response.message || "코드 순서 변경에 실패했습니다.");
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.";
console.error("코드 순서 변경 오류:", error);
throw error;
}
},
[],
);
/**
* 초기 데이터 로드
*/
useEffect(() => {
fetchCategories();
}, [fetchCategories]);
/**
* 선택된 카테고리 변경 시 코드 목록 로드
*/
useEffect(() => {
if (selectedCategoryCode) {
fetchCodes(selectedCategoryCode);
} else {
setCodes([]);
}
}, [selectedCategoryCode, fetchCodes]);
return {
// 카테고리 관련
categories,
categoriesLoading,
categoriesError,
totalCategories,
fetchCategories,
createCategory,
updateCategory,
deleteCategory,
// 코드 관련
codes,
setCodes,
codesLoading,
codesError,
fetchCodes,
createCode,
updateCode,
deleteCode,
reorderCodes,
// 선택된 카테고리
selectedCategoryCode,
setSelectedCategoryCode,
};
}