'use client'; import { useState, useEffect, useCallback } from 'react'; import { getItemList, type ItemOption } from './actions'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { Switch } from '@/components/ui/switch'; import { Checkbox } from '@/components/ui/checkbox'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Search, Package } from 'lucide-react'; import type { ClassificationRule, RuleRegistrationType, RuleType, MatchingType, } from '@/types/process'; import { RULE_TYPE_OPTIONS, MATCHING_TYPE_OPTIONS } from '@/types/process'; // 품목 유형 옵션 const ITEM_TYPE_OPTIONS = [ { value: 'all', label: '전체' }, { value: '제품', label: '제품' }, { value: '반제품', label: '반제품' }, { value: '원자재', label: '원자재' }, { value: '부자재', label: '부자재' }, ]; interface RuleModalProps { open: boolean; onOpenChange: (open: boolean) => void; onAdd: (rule: Omit) => void; editRule?: ClassificationRule; } export function RuleModal({ open, onOpenChange, onAdd, editRule }: RuleModalProps) { // 공통 상태 const [registrationType, setRegistrationType] = useState( editRule?.registrationType || 'pattern' ); const [description, setDescription] = useState(editRule?.description || ''); // 패턴 규칙용 상태 const [ruleType, setRuleType] = useState(editRule?.ruleType || '품목코드'); const [matchingType, setMatchingType] = useState( editRule?.matchingType || 'startsWith' ); const [conditionValue, setConditionValue] = useState(editRule?.conditionValue || ''); const [priority, setPriority] = useState(editRule?.priority || 10); const [isActive, setIsActive] = useState(editRule?.isActive ?? true); // 개별 품목용 상태 const [searchKeyword, setSearchKeyword] = useState(''); const [selectedItemType, setSelectedItemType] = useState('all'); const [selectedItemCodes, setSelectedItemCodes] = useState>(new Set()); // 품목 목록 API 상태 const [itemList, setItemList] = useState([]); const [isItemsLoading, setIsItemsLoading] = useState(false); // 품목 목록 로드 (debounced) const loadItems = useCallback(async (q?: string, itemType?: string) => { setIsItemsLoading(true); const result = await getItemList({ q: q || undefined, itemType: itemType === 'all' ? undefined : itemType, size: 100, }); if (result.success && result.data) { setItemList(result.data); } setIsItemsLoading(false); }, []); // 검색어/품목유형 변경 시 API 호출 (debounce) useEffect(() => { if (registrationType !== 'individual') return; const timer = setTimeout(() => { loadItems(searchKeyword, selectedItemType); }, 300); return () => clearTimeout(timer); }, [searchKeyword, selectedItemType, registrationType, loadItems]); // 모달 열릴 때 품목 목록 초기 로드 useEffect(() => { if (open && registrationType === 'individual') { loadItems('', 'all'); } }, [open, registrationType, loadItems]); // 체크박스 토글 const handleToggleItem = (code: string) => { setSelectedItemCodes((prev) => { const newSet = new Set(prev); if (newSet.has(code)) { newSet.delete(code); } else { newSet.add(code); } return newSet; }); }; // 전체 선택 const handleSelectAll = () => { const allCodes = itemList.map((item) => item.code); setSelectedItemCodes(new Set(allCodes)); }; // 초기화 const handleResetSelection = () => { setSelectedItemCodes(new Set()); }; // 모달 열릴 때 초기화 또는 수정 데이터 로드 useEffect(() => { if (open) { if (editRule) { // 수정 모드: 기존 데이터 로드 setRegistrationType(editRule.registrationType); setDescription(editRule.description || ''); setRuleType(editRule.ruleType); setMatchingType(editRule.matchingType); setConditionValue(editRule.conditionValue); setPriority(editRule.priority); setIsActive(editRule.isActive); setSearchKeyword(''); setSelectedItemType('all'); // 개별 품목인 경우 선택된 품목 코드 설정 if (editRule.registrationType === 'individual') { const codes = editRule.conditionValue.split(',').filter(Boolean); setSelectedItemCodes(new Set(codes)); } else { setSelectedItemCodes(new Set()); } } else { // 추가 모드: 초기화 setRegistrationType('pattern'); setDescription(''); setRuleType('품목코드'); setMatchingType('startsWith'); setConditionValue(''); setPriority(10); setIsActive(true); setSearchKeyword(''); setSelectedItemType('all'); setSelectedItemCodes(new Set()); } } }, [open, editRule]); const handleSubmit = () => { if (registrationType === 'pattern') { if (!conditionValue.trim()) { alert('조건 값을 입력해주세요.'); return; } } else { if (selectedItemCodes.size === 0) { alert('품목을 최소 1개 이상 선택해주세요.'); return; } } // 개별 품목의 경우 conditionValue에 품목코드들을 저장 const finalConditionValue = registrationType === 'individual' ? Array.from(selectedItemCodes).join(',') : conditionValue.trim(); onAdd({ registrationType, ruleType: registrationType === 'individual' ? '품목코드' : ruleType, matchingType: registrationType === 'individual' ? 'equals' : matchingType, conditionValue: finalConditionValue, priority: registrationType === 'individual' ? 10 : priority, description: description.trim() || undefined, isActive: registrationType === 'individual' ? true : isActive, }); // Reset form setRegistrationType('pattern'); setDescription(''); setRuleType('품목코드'); setMatchingType('startsWith'); setConditionValue(''); setPriority(10); setIsActive(true); setSearchKeyword(''); setSelectedItemType('all'); setSelectedItemCodes(new Set()); onOpenChange(false); }; return ( {editRule ? '규칙 수정' : '규칙 추가'}
{/* 등록 방식 */}
setRegistrationType(v as RuleRegistrationType)} >
{/* 패턴 규칙 UI */} {registrationType === 'pattern' && ( <> {/* 규칙 유형 */}
{/* 매칭 방식 */}
{/* 조건 값 */}
setConditionValue(e.target.value)} placeholder="예: SCR-, E-, STEEL-" className="flex-1" />

Enter 키를 누르거나 검색 버튼을 클릭하세요

{/* 우선순위 - 패턴 규칙에서만 표시 */}
setPriority(Number(e.target.value))} min={1} max={100} className="w-24" />

낮을수록 먼저 적용됩니다

{/* 설명 - 패턴 규칙 */}
setDescription(e.target.value)} placeholder="규칙에 대한 설명" />
{/* 활성 상태 - 패턴 규칙에서만 표시 */}
)} {/* 개별 품목 UI - 기획서 기준 */} {registrationType === 'individual' && ( <> {/* 설명 (선택) */}
setDescription(e.target.value)} placeholder="이 품목 그룹에 대한 설명" />
{/* 품목 검색 + 품목 유형 필터 */}
setSearchKeyword(e.target.value)} placeholder="품목코드 또는 품목명으로 검색..." className="pl-9" />
{/* 품목 목록 헤더 */}
{isItemsLoading ? ( '로딩 중...' ) : ( <>품목 목록 ({itemList.length}개) | 선택됨 ({selectedItemCodes.size}개) )}
|
{/* 품목 테이블 */}
품목코드 품목명 품목유형 {isItemsLoading ? ( 품목 목록을 불러오는 중... ) : itemList.length === 0 ? ( 검색 결과가 없습니다 ) : ( itemList.map((item) => ( handleToggleItem(item.code)} > handleToggleItem(item.code)} onClick={(e) => e.stopPropagation()} /> {item.code} {item.fullName} {item.type} )) )}
{/* 안내 문구 */}

이 공정에 배정할 품목을 선택하세요. 다른 공정에 이미 배정된 품목은 표시되지 않습니다.

)}
); }