import { useState, useCallback, useEffect, useMemo } from "react"; import { User, UserSearchFilter } from "@/types/user"; import { userAPI } from "@/lib/api/user"; // 백엔드 연동 활성화 import { PaginationInfo } from "@/components/common/Pagination"; import { useDebounce } from "./useDebounce"; // import { MOCK_USERS } from "@/constants/user"; // 목 데이터 비활성화 /** * 사용자 관리 비즈니스 로직을 담당하는 커스텀 훅 */ export const useUserManagement = () => { // 사용자 목록 상태 const [users, setUsers] = useState([]); // 검색 필터 상태 const [searchFilter, setSearchFilter] = useState({}); // 검색어만 디바운싱 (500ms 지연) - searchType은 즉시 반영 const debouncedSearchValue = useDebounce(searchFilter.searchValue || "", 500); // 디바운싱된 검색 필터 (useMemo로 최적화) const debouncedSearchFilter = useMemo( () => ({ searchValue: debouncedSearchValue, searchType: searchFilter.searchType || "all", }), [debouncedSearchValue, searchFilter.searchType], ); // 검색 중인지 확인 (검색어만 체크) const isSearching = (searchFilter.searchValue || "") !== debouncedSearchValue; // 로딩 및 에러 상태 const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); // 페이지네이션 상태 const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(20); const [totalItems, setTotalItems] = useState(0); // 사용자 목록 로드 (특정 검색 조건으로 호출) const loadUsers = useCallback( async (searchValue?: string, searchType?: string) => { setIsLoading(true); setError(null); try { // 백엔드 API 호출 // 검색 파라미터 구성 (단순 검색 방식) const searchParams: Record = { page: currentPage, countPerPage: pageSize, }; // 검색어가 있고 searchType이 'all'이 아닐 때만 검색 파라미터 추가 if (searchValue && searchValue.trim() && searchType && searchType !== "all") { const trimmedValue = searchValue.trim(); // 각 검색 타입별로 해당하는 백엔드 파라미터 매핑 (백엔드 MyBatis와 정확히 일치) switch (searchType) { case "sabun": searchParams.search_sabun = trimmedValue; break; case "company_name": searchParams.search_companyName = trimmedValue; // MyBatis: search_companyName break; case "dept_name": searchParams.search_deptName = trimmedValue; // MyBatis: search_deptName break; case "position_name": searchParams.search_positionName = trimmedValue; // MyBatis: search_positionName break; case "user_id": searchParams.search_userId = trimmedValue; // MyBatis: search_userId break; case "user_name": searchParams.search_userName = trimmedValue; // MyBatis: search_userName break; case "tel": searchParams.search_tel = trimmedValue; // MyBatis: search_tel break; case "email": searchParams.search_email = trimmedValue; // MyBatis: search_email break; default: searchParams.search_userName = trimmedValue; // 기본값 } } console.log("🔍 검색 파라미터:", searchParams); const response = await userAPI.getList(searchParams); // 백엔드 응답 구조에 맞게 처리 { success, data, total } if (response && response.success && response.data) { // 새로운 API 응답 구조: { success, data: { users, pagination } } if (response.data.users && Array.isArray(response.data.users)) { setUsers(response.data.users); setTotalItems(response.data.pagination?.totalCount || response.data.users.length); } else if (Array.isArray(response.data)) { // 기존 구조: { success, data: User[] } setUsers(response.data); setTotalItems(response.total || response.data.length); } else { setUsers([]); setTotalItems(0); } } else { setUsers([]); setTotalItems(0); } } catch (err) { setError(err instanceof Error ? err.message : "사용자 목록 조회에 실패했습니다."); setUsers([]); setTotalItems(0); } finally { setIsLoading(false); } }, [currentPage, pageSize], ); // 초기 로드 useEffect(() => { loadUsers(); }, [loadUsers]); // 검색어 변경 시에만 API 호출 (검색어가 있고 'all'이 아닐 때) useEffect(() => { if ( debouncedSearchFilter.searchValue && debouncedSearchFilter.searchValue.trim() && debouncedSearchFilter.searchType !== "all" ) { loadUsers(debouncedSearchFilter.searchValue, debouncedSearchFilter.searchType); } }, [debouncedSearchFilter.searchValue, loadUsers]); // '전체' 선택 시에만 즉시 반영 useEffect(() => { if (searchFilter.searchType === "all" && !searchFilter.searchValue) { loadUsers(); // 전체 목록 로드 (검색 조건 없음) } }, [searchFilter.searchType, loadUsers]); // 검색 필터 업데이트 const updateSearchFilter = useCallback((newFilter: Partial) => { setSearchFilter((prev) => ({ ...prev, ...newFilter })); // searchType이 변경되거나 searchValue가 변경될 때만 첫 페이지로 이동 if (newFilter.searchType !== undefined || newFilter.searchValue !== undefined) { setCurrentPage(1); } }, []); // 페이지 변경 핸들러 const handlePageChange = useCallback((page: number) => { setCurrentPage(page); }, []); // 페이지 크기 변경 핸들러 const handlePageSizeChange = useCallback((newPageSize: number) => { setPageSize(newPageSize); setCurrentPage(1); // 페이지 크기 변경 시 첫 페이지로 이동 }, []); // 페이지네이션 정보 계산 const paginationInfo: PaginationInfo = { currentPage, totalPages: Math.ceil(totalItems / pageSize), totalItems, itemsPerPage: pageSize, startItem: totalItems > 0 ? (currentPage - 1) * pageSize + 1 : 0, endItem: Math.min(currentPage * pageSize, totalItems), }; // 사용자 편집 기능 제거됨 // 사용자 삭제 기능 제거됨 // 사용자 상태 토글 핸들러 const handleStatusToggle = useCallback(async (user: User, newStatus: string) => { try { console.log(`🎛️ 상태 변경: ${user.user_name} (${user.user_id}) → ${newStatus}`); // 백엔드 API 호출 const response = await userAPI.updateStatus(user.user_id, newStatus); // 백엔드 응답 구조: { result: boolean, msg: string } if (response && typeof response === "object" && "result" in response) { const apiResponse = response as unknown as { result: boolean; msg: string }; if (apiResponse.result) { console.log("✅ 상태 변경 성공:", apiResponse.msg); // 전체 목록 새로고침 대신 개별 사용자 상태만 업데이트 setUsers((prevUsers) => prevUsers.map((u) => (u.user_id === user.user_id ? { ...u, status: newStatus } : u))); } else { console.error("❌ 상태 변경 실패:", apiResponse.msg); alert(apiResponse.msg || "상태 변경에 실패했습니다."); } } else { console.error("❌ 예상치 못한 응답 형식:", response); alert("상태 변경 중 오류가 발생했습니다."); } } catch (error) { console.error("상태 변경 오류:", error); alert("상태 변경 중 오류가 발생했습니다."); } }, []); // 데이터 새로고침 (비밀번호 초기화 후 목록 갱신용) const refreshData = useCallback(() => { loadUsers(debouncedSearchFilter.searchValue, debouncedSearchFilter.searchType); }, [loadUsers, debouncedSearchFilter.searchValue, debouncedSearchFilter.searchType]); // 사용자 등록 핸들러 const handleCreate = useCallback(() => { console.log("📝 사용자 등록"); alert("사용자 등록 기능은 추후 구현 예정입니다."); }, []); // 에러 상태 초기화 const clearError = useCallback(() => { setError(null); }, []); return { // 데이터 users, searchFilter, isLoading, isSearching, error, paginationInfo, // 검색 기능 updateSearchFilter, // 페이지네이션 handlePageChange, handlePageSizeChange, // 액션 핸들러 handleStatusToggle, handleCreate, // 유틸리티 loadUsers, refreshData, clearError, }; };