308 lines
8.4 KiB
TypeScript
308 lines
8.4 KiB
TypeScript
import { useState, useCallback, useMemo, useEffect } from "react";
|
|
import {
|
|
Company,
|
|
CompanyFormData,
|
|
CompanyModalState,
|
|
CompanyDeleteState,
|
|
CompanySearchFilter,
|
|
AllDiskUsageInfo,
|
|
} 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 [diskUsageInfo, setDiskUsageInfo] = useState<AllDiskUsageInfo | null>(null);
|
|
const [isDiskUsageLoading, setIsDiskUsageLoading] = useState(false);
|
|
|
|
// 회사 목록 로드
|
|
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]);
|
|
|
|
// 디스크 사용량 로드
|
|
const loadDiskUsage = useCallback(async () => {
|
|
setIsDiskUsageLoading(true);
|
|
try {
|
|
const data = await companyAPI.getAllDiskUsage();
|
|
setDiskUsageInfo(data);
|
|
console.log("✅ 디스크 사용량 조회 성공:", data.summary);
|
|
} catch (err) {
|
|
console.error("❌ 디스크 사용량 조회 실패:", err);
|
|
// 디스크 사용량 조회 실패는 에러로 처리하지 않음 (선택적 기능)
|
|
} finally {
|
|
setIsDiskUsageLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
// 초기 로드 및 검색 필터 변경 시 재로드
|
|
useEffect(() => {
|
|
loadCompanies();
|
|
loadDiskUsage(); // 디스크 사용량도 함께 로드
|
|
}, [loadCompanies, loadDiskUsage]);
|
|
|
|
// 디스크 사용량 정보가 포함된 회사 목록
|
|
const companiesWithDiskUsage = useMemo(() => {
|
|
if (!diskUsageInfo) return companies;
|
|
|
|
return companies.map((company) => {
|
|
const diskUsage = diskUsageInfo.companies.find((usage) => usage.companyCode === company.company_code);
|
|
|
|
return {
|
|
...company,
|
|
diskUsage: diskUsage
|
|
? {
|
|
fileCount: diskUsage.fileCount,
|
|
totalSize: diskUsage.totalSize,
|
|
totalSizeMB: diskUsage.totalSizeMB,
|
|
lastChecked: diskUsage.lastChecked,
|
|
}
|
|
: undefined,
|
|
};
|
|
});
|
|
}, [companies, diskUsageInfo]);
|
|
|
|
// 필터링된 회사 목록 (디스크 사용량 정보 포함)
|
|
const filteredCompanies = useMemo(() => {
|
|
return companiesWithDiskUsage;
|
|
}, [companiesWithDiskUsage]);
|
|
|
|
// 검색 필터 업데이트
|
|
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,
|
|
|
|
// 디스크 사용량 관련
|
|
diskUsageInfo,
|
|
isDiskUsageLoading,
|
|
loadDiskUsage,
|
|
|
|
// 모달 상태
|
|
modalState,
|
|
deleteState,
|
|
|
|
// 검색 기능
|
|
updateSearchFilter,
|
|
clearSearchFilter,
|
|
|
|
// 모달 제어
|
|
openCreateModal,
|
|
openEditModal,
|
|
closeModal,
|
|
updateFormData,
|
|
|
|
// 삭제 다이얼로그 제어
|
|
openDeleteDialog,
|
|
closeDeleteDialog,
|
|
|
|
// CRUD 작업
|
|
saveCompany,
|
|
deleteCompany,
|
|
loadCompanies, // 외부에서 수동으로 새로고침할 때 사용
|
|
|
|
// 에러 처리
|
|
clearError: () => setError(null),
|
|
};
|
|
};
|