"use client"; import React, { useState, useEffect } from "react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { ScreenGroup, createScreenGroup, updateScreenGroup } from "@/lib/api/screenGroup"; import { toast } from "sonner"; import { apiClient } from "@/lib/api/client"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Check, ChevronsUpDown, Folder } from "lucide-react"; import { cn } from "@/lib/utils"; interface ScreenGroupModalProps { isOpen: boolean; onClose: () => void; onSuccess: () => void; group?: ScreenGroup | null; // 수정 모드일 때 기존 그룹 데이터 } export function ScreenGroupModal({ isOpen, onClose, onSuccess, group, }: ScreenGroupModalProps) { const [currentCompanyCode, setCurrentCompanyCode] = useState(""); const [isSuperAdmin, setIsSuperAdmin] = useState(false); const [formData, setFormData] = useState({ group_name: "", group_code: "", description: "", display_order: 0, target_company_code: "", parent_group_id: null as number | null, }); const [loading, setLoading] = useState(false); const [companies, setCompanies] = useState<{ code: string; name: string }[]>([]); const [availableParentGroups, setAvailableParentGroups] = useState([]); const [isParentGroupSelectOpen, setIsParentGroupSelectOpen] = useState(false); // 그룹 경로 가져오기 (계층 구조 표시용) const getGroupPath = (groupId: number): string => { const grp = availableParentGroups.find((g) => g.id === groupId); if (!grp) return ""; const path: string[] = [grp.group_name]; let currentGroup = grp; while ((currentGroup as any).parent_group_id) { const parent = availableParentGroups.find((g) => g.id === (currentGroup as any).parent_group_id); if (parent) { path.unshift(parent.group_name); currentGroup = parent; } else { break; } } return path.join(" > "); }; // 그룹을 계층 구조로 정렬 const getSortedGroups = (): typeof availableParentGroups => { const result: typeof availableParentGroups = []; const addChildren = (parentId: number | null, level: number) => { const children = availableParentGroups .filter((g) => (g as any).parent_group_id === parentId) .sort((a, b) => (a.display_order || 0) - (b.display_order || 0)); for (const child of children) { result.push({ ...child, group_level: level } as any); addChildren(child.id, level + 1); } }; addChildren(null, 1); return result; }; // 현재 사용자 정보 로드 useEffect(() => { const loadUserInfo = async () => { try { const response = await apiClient.get("/auth/me"); const result = response.data; if (result.success && result.data) { const companyCode = result.data.companyCode || result.data.company_code || ""; setCurrentCompanyCode(companyCode); setIsSuperAdmin(companyCode === "*"); } } catch (error) { console.error("사용자 정보 로드 실패:", error); } }; if (isOpen) { loadUserInfo(); } }, [isOpen]); // 회사 목록 로드 (최고 관리자만) useEffect(() => { if (isSuperAdmin && isOpen) { const loadCompanies = async () => { try { const response = await apiClient.get("/admin/companies"); const result = response.data; if (result.success && result.data) { const companyList = result.data.map((c: any) => ({ code: c.company_code, name: c.company_name, })); setCompanies(companyList); } } catch (error) { console.error("회사 목록 로드 실패:", error); } }; loadCompanies(); } }, [isSuperAdmin, isOpen]); // 부모 그룹 목록 로드 (현재 회사의 대분류/중분류 그룹만) useEffect(() => { if (isOpen && currentCompanyCode) { const loadParentGroups = async () => { try { const response = await apiClient.get(`/screen-groups/groups?size=1000`); const result = response.data; if (result.success && result.data) { // 모든 그룹을 상위 그룹으로 선택 가능 (무한 중첩 지원) setAvailableParentGroups(result.data); } } catch (error) { console.error("부모 그룹 목록 로드 실패:", error); } }; loadParentGroups(); } }, [isOpen, currentCompanyCode]); // 그룹 데이터가 변경되면 폼 초기화 useEffect(() => { if (currentCompanyCode) { if (group) { setFormData({ group_name: group.group_name || "", group_code: group.group_code || "", description: group.description || "", display_order: group.display_order || 0, target_company_code: group.company_code || currentCompanyCode, parent_group_id: (group as any).parent_group_id || null, }); } else { setFormData({ group_name: "", group_code: "", description: "", display_order: 0, target_company_code: currentCompanyCode, parent_group_id: null, }); } } }, [group, isOpen, currentCompanyCode]); const handleSubmit = async () => { // 필수 필드 검증 if (!formData.group_name.trim()) { toast.error("그룹명을 입력하세요"); return; } if (!formData.group_code.trim()) { toast.error("그룹 코드를 입력하세요"); return; } setLoading(true); try { let response; if (group) { // 수정 모드 response = await updateScreenGroup(group.id, formData); } else { // 추가 모드 response = await createScreenGroup({ ...formData, is_active: "Y", }); } if (response.success) { toast.success(group ? "그룹이 수정되었습니다" : "그룹이 추가되었습니다"); onSuccess(); onClose(); } else { toast.error(response.message || "작업에 실패했습니다"); } } catch (error: any) { console.error("그룹 저장 실패:", error); toast.error("그룹 저장에 실패했습니다"); } finally { setLoading(false); } }; return ( {group ? "그룹 수정" : "그룹 추가"} 화면 그룹 정보를 입력하세요
{/* 회사 선택 (최고 관리자만) */} {isSuperAdmin && (

선택한 회사에 그룹이 생성됩니다

)} {/* 부모 그룹 선택 (하위 그룹 만들기) - 트리 구조 + 검색 */}
그룹을 찾을 수 없습니다 {/* 대분류로 생성 옵션 */} { setFormData({ ...formData, parent_group_id: null, // 대분류 선택 시 현재 회사 코드 유지 }); setIsParentGroupSelectOpen(false); }} className="text-xs sm:text-sm" > 대분류로 생성 {/* 계층 구조로 그룹 표시 */} {getSortedGroups().map((parentGroup) => ( { // 상위 그룹의 company_code로 자동 설정 const parentCompanyCode = parentGroup.company_code || formData.target_company_code; setFormData({ ...formData, parent_group_id: parentGroup.id, target_company_code: parentCompanyCode, }); setIsParentGroupSelectOpen(false); }} className="text-xs sm:text-sm" > {/* 들여쓰기로 계층 표시 */} {parentGroup.group_name} ))}

부모 그룹을 선택하면 하위 그룹으로 생성됩니다

{/* 그룹명 */}
setFormData({ ...formData, group_name: e.target.value }) } placeholder="그룹명을 입력하세요" className="h-8 text-xs sm:h-10 sm:text-sm" />
{/* 그룹 코드 */}
setFormData({ ...formData, group_code: e.target.value }) } placeholder="영문 대문자와 언더스코어로 입력" className="h-8 text-xs sm:h-10 sm:text-sm" disabled={!!group} // 수정 모드일 때는 코드 변경 불가 /> {group && (

그룹 코드는 수정할 수 없습니다

)}
{/* 설명 */}