"use client"; import { useState, useEffect } from "react"; import { Plus, X, Star } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { useToast } from "@/hooks/use-toast"; import type { Department, DepartmentMember } from "@/types/department"; import * as departmentAPI from "@/lib/api/department"; interface DepartmentMembersProps { companyCode: string; selectedDepartment: Department | null; onMemberChange?: () => void; } /** * 부서 인원 관리 컴포넌트 */ export function DepartmentMembers({ companyCode, selectedDepartment, onMemberChange, }: DepartmentMembersProps) { const { toast } = useToast(); const [members, setMembers] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isAddModalOpen, setIsAddModalOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const [searchResults, setSearchResults] = useState([]); const [isSearching, setIsSearching] = useState(false); const [hasSearched, setHasSearched] = useState(false); // 검색 버튼을 눌렀는지 여부 const [duplicateMessage, setDuplicateMessage] = useState(null); // 부서원 삭제 확인 모달 const [removeConfirmOpen, setRemoveConfirmOpen] = useState(false); const [memberToRemove, setMemberToRemove] = useState<{ userId: string; name: string } | null>(null); // 부서원 목록 로드 useEffect(() => { if (selectedDepartment) { loadMembers(); } }, [selectedDepartment]); const loadMembers = async () => { if (!selectedDepartment) return; setIsLoading(true); try { const response = await departmentAPI.getDepartmentMembers(selectedDepartment.dept_code); if (response.success && response.data) { setMembers(response.data); } else { console.error("부서원 목록 로드 실패:", response.error); setMembers([]); } } catch (error) { console.error("부서원 목록 로드 실패:", error); setMembers([]); } finally { setIsLoading(false); } }; // 사용자 검색 const handleSearch = async () => { if (!searchQuery.trim()) { setSearchResults([]); setHasSearched(false); return; } setIsSearching(true); setHasSearched(true); // 검색 버튼을 눌렀음을 표시 try { const response = await departmentAPI.searchUsers(companyCode, searchQuery); if (response.success && response.data) { setSearchResults(response.data); } else { setSearchResults([]); } } catch (error) { console.error("사용자 검색 실패:", error); setSearchResults([]); } finally { setIsSearching(false); } }; // 부서원 추가 const handleAddMember = async (userId: string) => { if (!selectedDepartment) return; try { const response = await departmentAPI.addDepartmentMember( selectedDepartment.dept_code, userId ); if (response.success) { setIsAddModalOpen(false); setSearchQuery(""); setSearchResults([]); setHasSearched(false); // 검색 상태 초기화 loadMembers(); onMemberChange?.(); // 부서 구조 새로고침 // 성공 Toast 표시 toast({ title: "부서원 추가 완료", description: "부서원이 추가되었습니다.", variant: "default", }); } else { if ((response as any).isDuplicate) { setDuplicateMessage(response.error || "이미 해당 부서의 부서원입니다."); } else { toast({ title: "부서원 추가 실패", description: response.error || "부서원 추가에 실패했습니다.", variant: "destructive", }); } } } catch (error) { console.error("부서원 추가 실패:", error); toast({ title: "부서원 추가 실패", description: "부서원 추가 중 오류가 발생했습니다.", variant: "destructive", }); } }; // 부서원 제거 확인 요청 const handleRemoveMemberRequest = (userId: string, userName: string) => { setMemberToRemove({ userId, name: userName }); setRemoveConfirmOpen(true); }; // 부서원 제거 실행 const handleRemoveMemberConfirm = async () => { if (!selectedDepartment || !memberToRemove) return; try { const response = await departmentAPI.removeDepartmentMember( selectedDepartment.dept_code, memberToRemove.userId ); if (response.success) { setRemoveConfirmOpen(false); setMemberToRemove(null); loadMembers(); onMemberChange?.(); // 부서 구조 새로고침 // 성공 Toast 표시 toast({ title: "부서원 제거 완료", description: `${memberToRemove.name} 님이 부서에서 제외되었습니다.`, variant: "default", }); } else { toast({ title: "부서원 제거 실패", description: response.error || "부서원 제거에 실패했습니다.", variant: "destructive", }); } } catch (error) { console.error("부서원 제거 실패:", error); toast({ title: "부서원 제거 실패", description: "부서원 제거 중 오류가 발생했습니다.", variant: "destructive", }); } }; // 주 부서 설정 const handleSetPrimaryDepartment = async (userId: string) => { if (!selectedDepartment) return; try { const response = await departmentAPI.setPrimaryDepartment( selectedDepartment.dept_code, userId ); if (response.success) { loadMembers(); // 성공 Toast 표시 toast({ title: "주 부서 설정 완료", description: "주 부서가 변경되었습니다.", variant: "default", }); } else { toast({ title: "주 부서 설정 실패", description: response.error || "주 부서 설정에 실패했습니다.", variant: "destructive", }); } } catch (error) { console.error("주 부서 설정 실패:", error); toast({ title: "주 부서 설정 실패", description: "주 부서 설정 중 오류가 발생했습니다.", variant: "destructive", }); } }; if (!selectedDepartment) { return (

좌측에서 부서를 선택하세요

); } return (
{/* 헤더 */}

{selectedDepartment.dept_name}

부서원 {members.length}명

{/* 부서원 목록 */}
{isLoading ? (
로딩 중...
) : members.length === 0 ? (
부서원이 없습니다. 부서원을 추가해주세요.
) : (
{members.map((member) => (
{member.user_name} ({member.user_id}) {member.is_primary && ( 주 부서 )}
{member.position_name && 직책: {member.position_name}} {member.email && 이메일: {member.email}} {member.phone && 전화: {member.phone}} {member.cell_phone && 휴대폰: {member.cell_phone}}
{!member.is_primary && ( )}
))}
)}
{/* 부서원 추가 모달 */} 부서원 추가
{/* 검색 입력 */}
setSearchQuery(e.target.value)} onKeyPress={(e) => e.key === "Enter" && handleSearch()} placeholder="이름 또는 ID로 검색" className="h-8 text-xs sm:h-10 sm:text-sm" autoFocus />

겸직이 가능합니다. 한 사용자를 여러 부서에 추가할 수 있습니다.

{/* 검색 결과 */} {isSearching ? (
검색 중...
) : hasSearched && searchResults.length > 0 ? (
{searchResults.map((user) => (
handleAddMember(user.user_id)} >
{user.user_name} ({user.user_id})
{user.position_name && {user.position_name}} {user.email && {user.email}}
))}
) : hasSearched && searchResults.length === 0 ? (
검색 결과가 없습니다.
) : null}
{/* 중복 알림 모달 */} setDuplicateMessage(null)}> 중복 알림

{duplicateMessage}

{/* 부서원 제거 확인 모달 */} 부서원 제거 확인

{memberToRemove?.name} 님을 이 부서에서 제외하시겠습니까?

다른 부서에는 영향을 주지 않습니다.

); }