255 lines
6.9 KiB
TypeScript
255 lines
6.9 KiB
TypeScript
import { useState, useCallback, useMemo, useEffect } from "react";
|
|
import { Company, CompanyFormData, CompanyModalState, CompanyDeleteState, CompanySearchFilter } from "@/types/company";
|
|
import { DEFAULT_COMPANY_FORM_DATA, COMPANY_STATUS } from "@/constants/company";
|
|
import { companyAPI } from "@/lib/api/company";
|
|
|
|
/**
|
|
* 회사 관리 비즈니스 로직을 담당하는 커스텀 훅
|
|
* CRUD 기능과 모달/다이얼로그 상태 관리
|
|
*/
|
|
export const useCompanyManagement = () => {
|
|
// 회사 목록 상태
|
|
const [companies, setCompanies] = useState<Company[]>([]);
|
|
|
|
// 검색 필터 상태
|
|
const [searchFilter, setSearchFilter] = useState<CompanySearchFilter>({});
|
|
|
|
// 로딩 및 에러 상태
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
// 모달 상태 (등록/수정)
|
|
const [modalState, setModalState] = useState<CompanyModalState>({
|
|
isOpen: false,
|
|
mode: "create",
|
|
selectedCompany: null,
|
|
formData: { ...DEFAULT_COMPANY_FORM_DATA },
|
|
});
|
|
|
|
// 삭제 다이얼로그 상태
|
|
const [deleteState, setDeleteState] = useState<CompanyDeleteState>({
|
|
isOpen: false,
|
|
targetCompany: null,
|
|
});
|
|
|
|
// 회사 목록 로드
|
|
const loadCompanies = useCallback(async () => {
|
|
setIsLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
// 실제 데이터베이스에서 회사 목록 조회
|
|
const searchParams = {
|
|
company_name: searchFilter.company_name,
|
|
status: searchFilter.status === "all" ? undefined : searchFilter.status,
|
|
};
|
|
|
|
// 더미 데이터 대신 실제 API 호출
|
|
const data = await companyAPI.getList(searchParams);
|
|
setCompanies(data);
|
|
|
|
console.log("✅ 실제 DB에서 회사 목록 조회 성공:", data.length, "개");
|
|
} catch (err) {
|
|
console.error("❌ 회사 목록 조회 실패:", err);
|
|
setError(err instanceof Error ? err.message : "회사 목록 조회에 실패했습니다.");
|
|
setCompanies([]);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, [searchFilter]);
|
|
|
|
// 초기 로드 및 검색 필터 변경 시 재로드
|
|
useEffect(() => {
|
|
loadCompanies();
|
|
}, [loadCompanies]);
|
|
|
|
// 필터링된 회사 목록 (이제 서버에서 필터링되므로 그대로 반환)
|
|
const filteredCompanies = useMemo(() => {
|
|
return companies;
|
|
}, [companies]);
|
|
|
|
// 검색 필터 업데이트
|
|
const updateSearchFilter = useCallback((filter: Partial<CompanySearchFilter>) => {
|
|
setSearchFilter((prev) => ({ ...prev, ...filter }));
|
|
}, []);
|
|
|
|
// 검색 필터 초기화
|
|
const clearSearchFilter = useCallback(() => {
|
|
setSearchFilter({});
|
|
}, []);
|
|
|
|
// 모달 열기 - 새 회사 등록
|
|
const openCreateModal = useCallback(() => {
|
|
setModalState({
|
|
isOpen: true,
|
|
mode: "create",
|
|
selectedCompany: null,
|
|
formData: { ...DEFAULT_COMPANY_FORM_DATA },
|
|
});
|
|
}, []);
|
|
|
|
// 모달 열기 - 회사 수정
|
|
const openEditModal = useCallback((company: Company) => {
|
|
setModalState({
|
|
isOpen: true,
|
|
mode: "edit",
|
|
selectedCompany: company,
|
|
formData: {
|
|
company_name: company.company_name,
|
|
},
|
|
});
|
|
}, []);
|
|
|
|
// 모달 닫기
|
|
const closeModal = useCallback(() => {
|
|
setModalState((prev) => ({
|
|
...prev,
|
|
isOpen: false,
|
|
selectedCompany: null,
|
|
formData: { ...DEFAULT_COMPANY_FORM_DATA },
|
|
}));
|
|
}, []);
|
|
|
|
// 폼 데이터 변경
|
|
const updateFormData = useCallback((field: keyof CompanyFormData, value: string) => {
|
|
setModalState((prev) => ({
|
|
...prev,
|
|
formData: {
|
|
...prev.formData,
|
|
[field]: value,
|
|
},
|
|
}));
|
|
}, []);
|
|
|
|
// 회사 생성
|
|
const createCompany = useCallback(async () => {
|
|
if (!modalState.formData.company_name.trim()) {
|
|
setError("회사명을 입력해주세요.");
|
|
return false;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
await companyAPI.create(modalState.formData);
|
|
closeModal();
|
|
// 목록 다시 로드
|
|
await loadCompanies();
|
|
return true;
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : "회사 등록에 실패했습니다.");
|
|
return false;
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, [modalState.formData, closeModal, loadCompanies]);
|
|
|
|
// 회사 수정
|
|
const updateCompany = useCallback(async () => {
|
|
if (!modalState.selectedCompany || !modalState.formData.company_name.trim()) {
|
|
setError("올바른 데이터를 입력해주세요.");
|
|
return false;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
await companyAPI.update(modalState.selectedCompany.company_code, {
|
|
company_name: modalState.formData.company_name,
|
|
status: modalState.selectedCompany.status,
|
|
});
|
|
closeModal();
|
|
// 목록 다시 로드
|
|
await loadCompanies();
|
|
return true;
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : "회사 수정에 실패했습니다.");
|
|
return false;
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, [modalState.selectedCompany, modalState.formData, closeModal, loadCompanies]);
|
|
|
|
// 삭제 다이얼로그 열기
|
|
const openDeleteDialog = useCallback((company: Company) => {
|
|
setDeleteState({
|
|
isOpen: true,
|
|
targetCompany: company,
|
|
});
|
|
}, []);
|
|
|
|
// 삭제 다이얼로그 닫기
|
|
const closeDeleteDialog = useCallback(() => {
|
|
setDeleteState({
|
|
isOpen: false,
|
|
targetCompany: null,
|
|
});
|
|
}, []);
|
|
|
|
// 회사 삭제
|
|
const deleteCompany = useCallback(async () => {
|
|
if (!deleteState.targetCompany) return false;
|
|
|
|
setIsLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
await companyAPI.delete(deleteState.targetCompany.company_code);
|
|
closeDeleteDialog();
|
|
// 목록 다시 로드
|
|
await loadCompanies();
|
|
return true;
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : "회사 삭제에 실패했습니다.");
|
|
return false;
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, [deleteState.targetCompany, closeDeleteDialog, loadCompanies]);
|
|
|
|
// 폼 저장 (등록 또는 수정)
|
|
const saveCompany = useCallback(async () => {
|
|
if (modalState.mode === "create") {
|
|
return await createCompany();
|
|
} else {
|
|
return await updateCompany();
|
|
}
|
|
}, [modalState.mode, createCompany, updateCompany]);
|
|
|
|
return {
|
|
// 데이터
|
|
companies: filteredCompanies,
|
|
searchFilter,
|
|
isLoading,
|
|
error,
|
|
|
|
// 모달 상태
|
|
modalState,
|
|
deleteState,
|
|
|
|
// 검색 기능
|
|
updateSearchFilter,
|
|
clearSearchFilter,
|
|
|
|
// 모달 제어
|
|
openCreateModal,
|
|
openEditModal,
|
|
closeModal,
|
|
updateFormData,
|
|
|
|
// 삭제 다이얼로그 제어
|
|
openDeleteDialog,
|
|
closeDeleteDialog,
|
|
|
|
// CRUD 작업
|
|
saveCompany,
|
|
deleteCompany,
|
|
loadCompanies, // 외부에서 수동으로 새로고침할 때 사용
|
|
|
|
// 에러 처리
|
|
clearError: () => setError(null),
|
|
};
|
|
};
|