'use client'; import { useState, useEffect, useRef } from 'react'; import { toast } from 'sonner'; import { useItemMaster } from '@/contexts/ItemMasterContext'; import type { MasterOption, OptionColumn } from '../types'; import { attributeService } from '../services'; export interface UseAttributeManagementReturn { // 속성 옵션 상태 unitOptions: MasterOption[]; setUnitOptions: React.Dispatch>; materialOptions: MasterOption[]; setMaterialOptions: React.Dispatch>; surfaceTreatmentOptions: MasterOption[]; setSurfaceTreatmentOptions: React.Dispatch>; customAttributeOptions: Record; setCustomAttributeOptions: React.Dispatch>>; // 옵션 다이얼로그 상태 isOptionDialogOpen: boolean; setIsOptionDialogOpen: (open: boolean) => void; editingOptionType: string | null; setEditingOptionType: (type: string | null) => void; // 옵션 폼 상태 newOptionValue: string; setNewOptionValue: (value: string) => void; newOptionLabel: string; setNewOptionLabel: (label: string) => void; newOptionColumnValues: Record; setNewOptionColumnValues: React.Dispatch>>; newOptionInputType: 'textbox' | 'dropdown' | 'checkbox' | 'number' | 'date' | 'textarea'; setNewOptionInputType: (type: 'textbox' | 'dropdown' | 'checkbox' | 'number' | 'date' | 'textarea') => void; newOptionRequired: boolean; setNewOptionRequired: (required: boolean) => void; newOptionOptions: string; setNewOptionOptions: (options: string) => void; newOptionPlaceholder: string; setNewOptionPlaceholder: (placeholder: string) => void; newOptionDefaultValue: string; setNewOptionDefaultValue: (value: string) => void; // 칼럼 관리 상태 isColumnManageDialogOpen: boolean; setIsColumnManageDialogOpen: (open: boolean) => void; managingColumnType: string | null; setManagingColumnType: (type: string | null) => void; attributeColumns: Record; setAttributeColumns: React.Dispatch>>; // 칼럼 폼 상태 newColumnName: string; setNewColumnName: (name: string) => void; newColumnKey: string; setNewColumnKey: (key: string) => void; newColumnType: 'text' | 'number'; setNewColumnType: (type: 'text' | 'number') => void; newColumnRequired: boolean; setNewColumnRequired: (required: boolean) => void; // 핸들러 handleAddOption: () => void; handleDeleteOption: (type: string, id: string) => void; handleAddColumn: () => void; handleDeleteColumn: (columnKey: string) => void; resetOptionForm: () => void; resetColumnForm: () => void; } export function useAttributeManagement(): UseAttributeManagementReturn { const { itemMasterFields, updateItemMasterField } = useItemMaster(); // 속성 옵션 상태 (기본값 하드코딩 - TODO: 나중에 백엔드 API로 대체) const [unitOptions, setUnitOptions] = useState([ { id: 'unit-1', value: 'EA', label: 'EA (개)', isActive: true }, { id: 'unit-2', value: 'KG', label: 'KG (킬로그램)', isActive: true }, { id: 'unit-3', value: 'M', label: 'M (미터)', isActive: true }, { id: 'unit-4', value: 'MM', label: 'MM (밀리미터)', isActive: true }, { id: 'unit-5', value: 'L', label: 'L (리터)', isActive: true }, { id: 'unit-6', value: 'SET', label: 'SET (세트)', isActive: true }, { id: 'unit-7', value: 'BOX', label: 'BOX (박스)', isActive: true }, { id: 'unit-8', value: 'ROLL', label: 'ROLL (롤)', isActive: true }, ]); const [materialOptions, setMaterialOptions] = useState([ { id: 'mat-1', value: 'SUS304', label: 'SUS304 (스테인리스)', isActive: true }, { id: 'mat-2', value: 'SUS316', label: 'SUS316 (스테인리스)', isActive: true }, { id: 'mat-3', value: 'AL6061', label: 'AL6061 (알루미늄)', isActive: true }, { id: 'mat-4', value: 'AL5052', label: 'AL5052 (알루미늄)', isActive: true }, { id: 'mat-5', value: 'SS400', label: 'SS400 (일반강)', isActive: true }, { id: 'mat-6', value: 'S45C', label: 'S45C (탄소강)', isActive: true }, { id: 'mat-7', value: 'POM', label: 'POM (폴리아세탈)', isActive: true }, { id: 'mat-8', value: 'PEEK', label: 'PEEK (폴리에테르에테르케톤)', isActive: true }, ]); const [surfaceTreatmentOptions, setSurfaceTreatmentOptions] = useState([ { id: 'surf-1', value: 'NONE', label: '없음', isActive: true }, { id: 'surf-2', value: 'ANODIZE', label: '아노다이징', isActive: true }, { id: 'surf-3', value: 'PLATING', label: '도금', isActive: true }, { id: 'surf-4', value: 'PAINTING', label: '도장', isActive: true }, { id: 'surf-5', value: 'PASSIVATION', label: '부동태처리', isActive: true }, { id: 'surf-6', value: 'SANDBLAST', label: '샌드블라스트', isActive: true }, { id: 'surf-7', value: 'POLISHING', label: '폴리싱', isActive: true }, ]); const [customAttributeOptions, setCustomAttributeOptions] = useState>({}); // 옵션 다이얼로그 상태 const [isOptionDialogOpen, setIsOptionDialogOpen] = useState(false); const [editingOptionType, setEditingOptionType] = useState(null); // 옵션 폼 상태 const [newOptionValue, setNewOptionValue] = useState(''); const [newOptionLabel, setNewOptionLabel] = useState(''); const [newOptionColumnValues, setNewOptionColumnValues] = useState>({}); const [newOptionInputType, setNewOptionInputType] = useState<'textbox' | 'dropdown' | 'checkbox' | 'number' | 'date' | 'textarea'>('textbox'); const [newOptionRequired, setNewOptionRequired] = useState(false); const [newOptionOptions, setNewOptionOptions] = useState(''); const [newOptionPlaceholder, setNewOptionPlaceholder] = useState(''); const [newOptionDefaultValue, setNewOptionDefaultValue] = useState(''); // 칼럼 관리 상태 const [isColumnManageDialogOpen, setIsColumnManageDialogOpen] = useState(false); const [managingColumnType, setManagingColumnType] = useState(null); const [attributeColumns, setAttributeColumns] = useState>({}); // 칼럼 폼 상태 const [newColumnName, setNewColumnName] = useState(''); const [newColumnKey, setNewColumnKey] = useState(''); const [newColumnType, setNewColumnType] = useState<'text' | 'number'>('text'); const [newColumnRequired, setNewColumnRequired] = useState(false); // 이전 옵션 값 추적용 ref (무한 루프 방지) const prevOptionsRef = useRef(''); // 속성 변경 시 연동된 마스터 항목의 옵션 자동 업데이트 // 주의: itemMasterFields를 의존성에서 제거하여 무한 루프 방지 useEffect(() => { // 현재 옵션 상태를 문자열로 직렬화 const currentOptionsState = JSON.stringify({ unit: unitOptions.map(o => o.label).sort(), material: materialOptions.map(o => o.label).sort(), surface: surfaceTreatmentOptions.map(o => o.label).sort(), custom: Object.keys(customAttributeOptions).reduce((acc, key) => { acc[key] = (customAttributeOptions[key] || []).map(o => o.label).sort(); return acc; }, {} as Record) }); // 이전 상태와 동일하면 업데이트 스킵 if (prevOptionsRef.current === currentOptionsState) { return; } prevOptionsRef.current = currentOptionsState; // 실제 업데이트가 필요한 경우만 처리 itemMasterFields.forEach(field => { // properties가 null/undefined인 경우 스킵 if (!field.properties) return; const attributeType = (field.properties as any).attributeType; if (attributeType && attributeType !== 'custom' && (field.properties as any)?.inputType === 'dropdown') { let newOptions: string[] = []; if (attributeType === 'unit') { newOptions = unitOptions.map(opt => opt.label); } else if (attributeType === 'material') { newOptions = materialOptions.map(opt => opt.label); } else if (attributeType === 'surface') { newOptions = surfaceTreatmentOptions.map(opt => opt.label); } else { const customOpts = customAttributeOptions[attributeType] || []; newOptions = customOpts.map(opt => opt.label); } const currentOptions = (field.properties as any)?.options || []; const optionsChanged = JSON.stringify([...currentOptions].sort()) !== JSON.stringify([...newOptions].sort()); if (optionsChanged && newOptions.length > 0) { updateItemMasterField(field.id, { properties: { ...(field.properties || {}), options: newOptions } }); } } }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [unitOptions, materialOptions, surfaceTreatmentOptions, customAttributeOptions]); // 옵션 추가 const handleAddOption = () => { if (!editingOptionType || !newOptionValue.trim() || !newOptionLabel.trim()) { toast.error('모든 항목을 입력해주세요'); return; } // dropdown일 경우 옵션 필수 체크 if (newOptionInputType === 'dropdown' && !newOptionOptions.trim()) { toast.error('드롭다운 옵션을 입력해주세요'); return; } // 칼럼 필수 값 체크 const currentColumns = attributeColumns[editingOptionType] || []; for (const column of currentColumns) { if (column.required && !newOptionColumnValues[column.key]?.trim()) { toast.error(`${column.name}은(는) 필수 입력 항목입니다`); return; } } const newOption: MasterOption = { id: `${editingOptionType}-${Date.now()}`, value: newOptionValue, label: newOptionLabel, isActive: true, inputType: newOptionInputType, required: newOptionRequired, options: newOptionInputType === 'dropdown' ? newOptionOptions.split(',').map(o => o.trim()).filter(o => o) : undefined, placeholder: newOptionPlaceholder || undefined, defaultValue: newOptionDefaultValue || undefined, columnValues: Object.keys(newOptionColumnValues).length > 0 ? { ...newOptionColumnValues } : undefined }; if (editingOptionType === 'unit') { setUnitOptions(prev => [...prev, newOption]); } else if (editingOptionType === 'material') { setMaterialOptions(prev => [...prev, newOption]); } else if (editingOptionType === 'surface') { setSurfaceTreatmentOptions(prev => [...prev, newOption]); } else { setCustomAttributeOptions(prev => ({ ...prev, [editingOptionType]: [...(prev[editingOptionType] || []), newOption] })); } resetOptionForm(); toast.success('속성이 추가되었습니다 (저장 필요)'); }; // 옵션 삭제 const handleDeleteOption = (type: string, id: string) => { if (type === 'unit') { setUnitOptions(prev => prev.filter(o => o.id !== id)); } else if (type === 'material') { setMaterialOptions(prev => prev.filter(o => o.id !== id)); } else if (type === 'surface') { setSurfaceTreatmentOptions(prev => prev.filter(o => o.id !== id)); } else { setCustomAttributeOptions(prev => ({ ...prev, [type]: (prev[type] || []).filter(o => o.id !== id) })); } toast.success('삭제되었습니다'); }; // 칼럼 추가 const handleAddColumn = () => { if (!managingColumnType || !newColumnName.trim() || !newColumnKey.trim()) { toast.error('칼럼명과 키를 입력해주세요'); return; } const newColumn: OptionColumn = { id: `col-${Date.now()}`, key: newColumnKey, name: newColumnName, type: newColumnType, required: newColumnRequired }; setAttributeColumns(prev => ({ ...prev, [managingColumnType]: [...(prev[managingColumnType] || []), newColumn] })); resetColumnForm(); toast.success('칼럼이 추가되었습니다'); }; // 칼럼 삭제 const handleDeleteColumn = (columnKey: string) => { if (!managingColumnType) return; setAttributeColumns(prev => ({ ...prev, [managingColumnType]: (prev[managingColumnType] || []).filter(c => c.key !== columnKey) })); toast.success('칼럼이 삭제되었습니다'); }; // 옵션 폼 초기화 const resetOptionForm = () => { setNewOptionValue(''); setNewOptionLabel(''); setNewOptionColumnValues({}); setNewOptionInputType('textbox'); setNewOptionRequired(false); setNewOptionOptions(''); setNewOptionPlaceholder(''); setNewOptionDefaultValue(''); setIsOptionDialogOpen(false); }; // 칼럼 폼 초기화 const resetColumnForm = () => { setNewColumnName(''); setNewColumnKey(''); setNewColumnType('text'); setNewColumnRequired(false); }; return { // 속성 옵션 상태 unitOptions, setUnitOptions, materialOptions, setMaterialOptions, surfaceTreatmentOptions, setSurfaceTreatmentOptions, customAttributeOptions, setCustomAttributeOptions, // 옵션 다이얼로그 상태 isOptionDialogOpen, setIsOptionDialogOpen, editingOptionType, setEditingOptionType, // 옵션 폼 상태 newOptionValue, setNewOptionValue, newOptionLabel, setNewOptionLabel, newOptionColumnValues, setNewOptionColumnValues, newOptionInputType, setNewOptionInputType, newOptionRequired, setNewOptionRequired, newOptionOptions, setNewOptionOptions, newOptionPlaceholder, setNewOptionPlaceholder, newOptionDefaultValue, setNewOptionDefaultValue, // 칼럼 관리 상태 isColumnManageDialogOpen, setIsColumnManageDialogOpen, managingColumnType, setManagingColumnType, attributeColumns, setAttributeColumns, // 칼럼 폼 상태 newColumnName, setNewColumnName, newColumnKey, setNewColumnKey, newColumnType, setNewColumnType, newColumnRequired, setNewColumnRequired, // 핸들러 handleAddOption, handleDeleteOption, handleAddColumn, handleDeleteColumn, resetOptionForm, resetColumnForm, }; }