refactor: 품목기준관리 unused 코드 정리 및 import 최적화
- unused 변수 제거: _handleAddColumn, _handleDeleteColumn, _handleDeleteSectionWithTracking, _currentTemplateId, _itemSections - unused import 제거: ItemMasterDialogs, Badge, toast - unused helper 함수 제거: getInputTypeLabel - 코드 감소: 968줄 → 954줄 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import { MasterFieldTab, HierarchyTab, SectionsTab } from './ItemMasterDataManag
|
||||
import { LoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import { ServerErrorPage } from '@/components/common/ServerErrorPage';
|
||||
// 2025-12-24: Phase 2 UI 컴포넌트 분리
|
||||
import { AttributeTabContent, ItemMasterDialogs } from './ItemMasterDataManagement/components';
|
||||
import { AttributeTabContent } from './ItemMasterDataManagement/components';
|
||||
import {
|
||||
Database,
|
||||
FileText,
|
||||
@@ -17,8 +17,6 @@ import {
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
// 커스텀 훅 import
|
||||
import {
|
||||
@@ -53,19 +51,6 @@ const INPUT_TYPE_OPTIONS = [
|
||||
{ value: 'textarea', label: '텍스트영역' }
|
||||
];
|
||||
|
||||
// 입력 타입 라벨 변환 헬퍼 함수 (중복 코드 제거)
|
||||
const getInputTypeLabel = (inputType: string | undefined): string => {
|
||||
const labels: Record<string, string> = {
|
||||
textbox: '텍스트박스',
|
||||
number: '숫자',
|
||||
dropdown: '드롭다운',
|
||||
checkbox: '체크박스',
|
||||
date: '날짜',
|
||||
textarea: '텍스트영역',
|
||||
};
|
||||
return labels[inputType || ''] || '텍스트박스';
|
||||
};
|
||||
|
||||
export function ItemMasterDataManagement() {
|
||||
const {
|
||||
itemPages,
|
||||
@@ -158,7 +143,6 @@ export function ItemMasterDataManagement() {
|
||||
newColumnType, setNewColumnType,
|
||||
newColumnRequired, setNewColumnRequired,
|
||||
handleAddOption, handleDeleteOption,
|
||||
handleAddColumn: _handleAddColumn, handleDeleteColumn: _handleDeleteColumn,
|
||||
} = attributeManagement;
|
||||
|
||||
// 2025-12-24: 신규 훅 초기화
|
||||
@@ -185,7 +169,6 @@ export function ItemMasterDataManagement() {
|
||||
const deleteManagement = useDeleteManagement({ itemPages });
|
||||
const {
|
||||
handleDeletePage: handleDeletePageWithTracking,
|
||||
handleDeleteSection: _handleDeleteSectionWithTracking,
|
||||
handleUnlinkField: handleUnlinkFieldWithTracking,
|
||||
handleResetAllData: handleResetAllDataFromHook,
|
||||
} = deleteManagement;
|
||||
@@ -268,7 +251,7 @@ export function ItemMasterDataManagement() {
|
||||
isLoadTemplateDialogOpen, setIsLoadTemplateDialogOpen,
|
||||
selectedTemplateId, setSelectedTemplateId,
|
||||
isTemplateFieldDialogOpen, setIsTemplateFieldDialogOpen,
|
||||
currentTemplateId: _currentTemplateId, setCurrentTemplateId,
|
||||
setCurrentTemplateId,
|
||||
editingTemplateFieldId, setEditingTemplateFieldId,
|
||||
templateFieldName, setTemplateFieldName,
|
||||
templateFieldKey, setTemplateFieldKey,
|
||||
@@ -290,14 +273,6 @@ export function ItemMasterDataManagement() {
|
||||
handleDeleteBOMItemFromTemplate,
|
||||
} = templateManagement;
|
||||
|
||||
// 모든 페이지의 섹션을 하나의 배열로 평탄화
|
||||
const _itemSections = itemPages.flatMap(page =>
|
||||
page.sections.map(section => ({
|
||||
...section,
|
||||
parentPageId: page.id
|
||||
}))
|
||||
);
|
||||
|
||||
// 2025-11-26: itemPages의 모든 섹션 + 독립 섹션(independentSections)을 SectionTemplate 형식으로 변환
|
||||
// 이렇게 하면 계층구조 탭과 섹션 탭이 같은 데이터 소스를 사용하여 자동 동기화됨
|
||||
// 독립 섹션: 페이지에서 연결 해제된 섹션 (page_id = null)
|
||||
@@ -481,531 +456,32 @@ export function ItemMasterDataManagement() {
|
||||
</Button> */}
|
||||
</div>
|
||||
|
||||
{/* 속성 탭 (단위/재질/표면처리 통합) */}
|
||||
{/* 속성 탭 (단위/재질/표면처리 통합) - 2025-12-24: AttributeTabContent로 분리 */}
|
||||
<TabsContent value="attributes" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>속성 관리</CardTitle>
|
||||
<CardDescription>단위, 재질, 표면처리 등의 속성을 관리합니다</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{/* 속성 하위 탭 (칩 형태) */}
|
||||
<div className="flex items-center gap-2 mb-6 border-b pb-2">
|
||||
<div className="flex gap-2 flex-1 flex-wrap">
|
||||
{attributeSubTabs.sort((a, b) => a.order - b.order).map(tab => (
|
||||
<Button
|
||||
key={tab.id}
|
||||
variant={activeAttributeTab === tab.key ? 'default' : 'outline'}
|
||||
size="sm"
|
||||
onClick={() => setActiveAttributeTab(tab.key)}
|
||||
className="rounded-full"
|
||||
>
|
||||
{tab.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setIsManageAttributeTabsDialogOpen(true)}
|
||||
className="shrink-0"
|
||||
>
|
||||
<Settings className="w-4 h-4 mr-1" />
|
||||
항목 관리
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 단위 관리 */}
|
||||
{activeAttributeTab === 'units' && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="font-medium">단위 목록</h3>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm" onClick={() => {
|
||||
setManagingColumnType('units');
|
||||
setNewColumnName('');
|
||||
setNewColumnKey('');
|
||||
setNewColumnType('text');
|
||||
setNewColumnRequired(false);
|
||||
setIsColumnManageDialogOpen(true);
|
||||
}}>
|
||||
<Settings className="w-4 h-4 mr-2" />칼럼 관리
|
||||
</Button>
|
||||
<Button size="sm" onClick={() => { setEditingOptionType('unit'); setIsOptionDialogOpen(true); }}>
|
||||
<Plus className="w-4 h-4 mr-2" />추가
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{unitOptions.map((option) => {
|
||||
const columns = attributeColumns['units'] || [];
|
||||
const hasColumns = columns.length > 0 && option.columnValues;
|
||||
|
||||
return (
|
||||
<div key={option.id} className="p-4 border rounded hover:bg-gray-50 transition-colors">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-base">{option.label}</span>
|
||||
{option.inputType && (
|
||||
<Badge variant="outline" className="text-xs">{getInputTypeLabel(option.inputType)}</Badge>
|
||||
)}
|
||||
{option.required && (
|
||||
<Badge variant="destructive" className="text-xs">필수</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">값(Value):</span>
|
||||
<span>{option.value}</span>
|
||||
</div>
|
||||
{option.placeholder && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">플레이스홀더:</span>
|
||||
<span>{option.placeholder}</span>
|
||||
</div>
|
||||
)}
|
||||
{option.defaultValue && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">기본값:</span>
|
||||
<span>{option.defaultValue}</span>
|
||||
</div>
|
||||
)}
|
||||
{option.inputType === 'dropdown' && option.options && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">옵션:</span>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{option.options.map((opt, idx) => (
|
||||
<Badge key={idx} variant="secondary" className="text-xs">{opt}</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasColumns && (
|
||||
<div className="mt-3 pt-3 border-t">
|
||||
<p className="text-xs font-medium text-muted-foreground mb-2">추가 칼럼</p>
|
||||
<div className="grid grid-cols-2 gap-2 text-sm">
|
||||
{columns.map((column) => (
|
||||
<div key={column.id} className="flex gap-2">
|
||||
<span className="text-muted-foreground">{column.name}:</span>
|
||||
<span>{option.columnValues?.[column.key] || '-'}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" onClick={() => handleDeleteOption('unit', option.id)}>
|
||||
<Trash2 className="w-4 h-4 text-red-500" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 재질 관리 */}
|
||||
{activeAttributeTab === 'materials' && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="font-medium">재질 목록</h3>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm" onClick={() => {
|
||||
setManagingColumnType('materials');
|
||||
setNewColumnName('');
|
||||
setNewColumnKey('');
|
||||
setNewColumnType('text');
|
||||
setNewColumnRequired(false);
|
||||
setIsColumnManageDialogOpen(true);
|
||||
}}>
|
||||
<Settings className="w-4 h-4 mr-2" />칼럼 관리
|
||||
</Button>
|
||||
<Button size="sm" onClick={() => { setEditingOptionType('material'); setIsOptionDialogOpen(true); }}>
|
||||
<Plus className="w-4 h-4 mr-2" />추가
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{materialOptions.map((option) => {
|
||||
const columns = attributeColumns['materials'] || [];
|
||||
const hasColumns = columns.length > 0 && option.columnValues;
|
||||
|
||||
return (
|
||||
<div key={option.id} className="p-4 border rounded hover:bg-gray-50 transition-colors">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-base">{option.label}</span>
|
||||
{option.inputType && (
|
||||
<Badge variant="outline" className="text-xs">{getInputTypeLabel(option.inputType)}</Badge>
|
||||
)}
|
||||
{option.required && (
|
||||
<Badge variant="destructive" className="text-xs">필수</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">값(Value):</span>
|
||||
<span>{option.value}</span>
|
||||
</div>
|
||||
{option.placeholder && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">플레이스홀더:</span>
|
||||
<span>{option.placeholder}</span>
|
||||
</div>
|
||||
)}
|
||||
{option.defaultValue && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">기본값:</span>
|
||||
<span>{option.defaultValue}</span>
|
||||
</div>
|
||||
)}
|
||||
{option.inputType === 'dropdown' && option.options && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">옵션:</span>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{option.options.map((opt, idx) => (
|
||||
<Badge key={idx} variant="secondary" className="text-xs">{opt}</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasColumns && (
|
||||
<div className="mt-3 pt-3 border-t">
|
||||
<p className="text-xs font-medium text-muted-foreground mb-2">추가 칼럼</p>
|
||||
<div className="grid grid-cols-2 gap-2 text-sm">
|
||||
{columns.map((column) => (
|
||||
<div key={column.id} className="flex gap-2">
|
||||
<span className="text-muted-foreground">{column.name}:</span>
|
||||
<span>{option.columnValues?.[column.key] || '-'}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" onClick={() => handleDeleteOption('material', option.id)}>
|
||||
<Trash2 className="w-4 h-4 text-red-500" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 표면처리 관리 */}
|
||||
{activeAttributeTab === 'surface' && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="font-medium">표면처리 목록</h3>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm" onClick={() => {
|
||||
setManagingColumnType('surface');
|
||||
setNewColumnName('');
|
||||
setNewColumnKey('');
|
||||
setNewColumnType('text');
|
||||
setNewColumnRequired(false);
|
||||
setIsColumnManageDialogOpen(true);
|
||||
}}>
|
||||
<Settings className="w-4 h-4 mr-2" />칼럼 관리
|
||||
</Button>
|
||||
<Button size="sm" onClick={() => { setEditingOptionType('surface'); setIsOptionDialogOpen(true); }}>
|
||||
<Plus className="w-4 h-4 mr-2" />추가
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{surfaceTreatmentOptions.map((option) => {
|
||||
const columns = attributeColumns['surface'] || [];
|
||||
const hasColumns = columns.length > 0 && option.columnValues;
|
||||
const inputTypeLabel = getInputTypeLabel(option.inputType);
|
||||
|
||||
return (
|
||||
<div key={option.id} className="p-4 border rounded hover:bg-gray-50 transition-colors">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-base">{option.label}</span>
|
||||
{option.inputType && (
|
||||
<Badge variant="outline" className="text-xs">{inputTypeLabel}</Badge>
|
||||
)}
|
||||
{option.required && (
|
||||
<Badge variant="destructive" className="text-xs">필수</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">값(Value):</span>
|
||||
<span>{option.value}</span>
|
||||
</div>
|
||||
{option.placeholder && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">플레이스홀더:</span>
|
||||
<span>{option.placeholder}</span>
|
||||
</div>
|
||||
)}
|
||||
{option.defaultValue && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">기본값:</span>
|
||||
<span>{option.defaultValue}</span>
|
||||
</div>
|
||||
)}
|
||||
{option.inputType === 'dropdown' && option.options && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">옵션:</span>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{option.options.map((opt, idx) => (
|
||||
<Badge key={idx} variant="secondary" className="text-xs">{opt}</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasColumns && (
|
||||
<div className="mt-3 pt-3 border-t">
|
||||
<p className="text-xs font-medium text-muted-foreground mb-2">추가 칼럼</p>
|
||||
<div className="grid grid-cols-2 gap-2 text-sm">
|
||||
{columns.map((column) => (
|
||||
<div key={column.id} className="flex gap-2">
|
||||
<span className="text-muted-foreground">{column.name}:</span>
|
||||
<span>{option.columnValues?.[column.key] || '-'}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" onClick={() => handleDeleteOption('surface', option.id)}>
|
||||
<Trash2 className="w-4 h-4 text-red-500" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 사용자 정의 속성 탭 및 마스터 항목 탭 */}
|
||||
{!['units', 'materials', 'surface'].includes(activeAttributeTab) && (() => {
|
||||
const currentTabKey = activeAttributeTab;
|
||||
|
||||
// 마스터 항목인지 확인
|
||||
const masterField = itemMasterFields.find(f => f.id.toString() === currentTabKey);
|
||||
|
||||
// 마스터 항목이면 해당 항목의 속성값들을 표시
|
||||
// Note: properties is Record<string, any> | null, convert to array for display
|
||||
const propertiesArray = masterField?.properties
|
||||
? Object.entries(masterField.properties).map(([key, value]) => ({ key, ...value as object }))
|
||||
: [];
|
||||
|
||||
if (masterField && propertiesArray.length > 0) {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div>
|
||||
<h3 className="font-medium">{masterField.field_name} 속성 목록</h3>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
항목 탭에서 추가한 "{masterField.field_name}" 항목의 속성값들입니다
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */}
|
||||
{propertiesArray.map((property: any) => {
|
||||
const inputTypeLabel = getInputTypeLabel(property.type);
|
||||
|
||||
return (
|
||||
<div key={property.id} className="p-4 border rounded hover:bg-gray-50 transition-colors">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-base">{property.label}</span>
|
||||
<Badge variant="outline" className="text-xs">{inputTypeLabel}</Badge>
|
||||
{property.required && (
|
||||
<Badge variant="destructive" className="text-xs">필수</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-24">키(Key):</span>
|
||||
<code className="bg-gray-100 px-2 py-0.5 rounded text-xs">{property.key}</code>
|
||||
</div>
|
||||
{property.placeholder && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-24">플레이스홀더:</span>
|
||||
<span>{property.placeholder}</span>
|
||||
</div>
|
||||
)}
|
||||
{property.defaultValue && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-24">기본값:</span>
|
||||
<span>{property.defaultValue}</span>
|
||||
</div>
|
||||
)}
|
||||
{property.type === 'dropdown' && property.options && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-24">옵션:</span>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{property.options.map((opt: string, idx: number) => (
|
||||
<Badge key={idx} variant="secondary" className="text-xs">{opt}</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="mt-4 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
||||
<div className="flex items-start gap-2">
|
||||
<Package className="w-5 h-5 text-blue-600 mt-0.5" />
|
||||
<div className="flex-1">
|
||||
<p className="text-sm font-medium text-blue-900">
|
||||
마스터 항목 속성 관리
|
||||
</p>
|
||||
<p className="text-xs text-blue-700 mt-1">
|
||||
이 속성들은 <strong>항목 탭</strong>에서 "{masterField.field_name}" 항목을 편집하여 추가/수정/삭제할 수 있습니다.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 사용자 정의 속성 탭 (기존 로직)
|
||||
const currentOptions = customAttributeOptions[currentTabKey] || [];
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="font-medium">
|
||||
{attributeSubTabs.find(t => t.key === activeAttributeTab)?.label || '사용자 정의'} 목록
|
||||
</h3>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm" onClick={() => {
|
||||
setManagingColumnType(currentTabKey);
|
||||
setNewColumnName('');
|
||||
setNewColumnKey('');
|
||||
setNewColumnType('text');
|
||||
setNewColumnRequired(false);
|
||||
setIsColumnManageDialogOpen(true);
|
||||
}}>
|
||||
<Settings className="w-4 h-4 mr-2" />칼럼 관리
|
||||
</Button>
|
||||
<Button size="sm" onClick={() => {
|
||||
setEditingOptionType(activeAttributeTab);
|
||||
setNewOptionValue('');
|
||||
setNewOptionLabel('');
|
||||
setNewOptionColumnValues({});
|
||||
setIsOptionDialogOpen(true);
|
||||
}}>
|
||||
<Plus className="w-4 h-4 mr-2" />추가
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{currentOptions.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
{currentOptions.map((option) => {
|
||||
const columns = attributeColumns[currentTabKey] || [];
|
||||
const hasColumns = columns.length > 0 && option.columnValues;
|
||||
const inputTypeLabel = getInputTypeLabel(option.inputType);
|
||||
|
||||
return (
|
||||
<div key={option.id} className="p-4 border rounded hover:bg-gray-50 transition-colors">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-base">{option.label}</span>
|
||||
<Badge variant="outline" className="text-xs">{inputTypeLabel}</Badge>
|
||||
{option.required && (
|
||||
<Badge variant="destructive" className="text-xs">필수</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-muted-foreground space-y-1">
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">값(Value):</span>
|
||||
<span>{option.value}</span>
|
||||
</div>
|
||||
{option.placeholder && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">플레이스홀더:</span>
|
||||
<span>{option.placeholder}</span>
|
||||
</div>
|
||||
)}
|
||||
{option.defaultValue && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">기본값:</span>
|
||||
<span>{option.defaultValue}</span>
|
||||
</div>
|
||||
)}
|
||||
{option.inputType === 'dropdown' && option.options && (
|
||||
<div className="flex gap-2">
|
||||
<span className="font-medium min-w-16">옵션:</span>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{option.options.map((opt, idx) => (
|
||||
<Badge key={idx} variant="secondary" className="text-xs">{opt}</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{hasColumns && (
|
||||
<div className="mt-3 pt-3 border-t">
|
||||
<p className="text-xs font-medium text-muted-foreground mb-2">추가 칼럼</p>
|
||||
<div className="grid grid-cols-2 gap-2 text-sm">
|
||||
{columns.map((column) => (
|
||||
<div key={column.id} className="flex gap-2">
|
||||
<span className="text-muted-foreground">{column.name}:</span>
|
||||
<span>{option.columnValues?.[column.key] || '-'}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" onClick={() => handleDeleteOption(currentTabKey, option.id)}>
|
||||
<Trash2 className="w-4 h-4 text-red-500" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="border-2 border-dashed rounded-lg p-8 text-center text-gray-500">
|
||||
<Settings className="w-12 h-12 mx-auto mb-4 text-gray-400" />
|
||||
<p className="mb-2">아직 추가된 항목이 없습니다</p>
|
||||
<p className="text-sm">위 "추가" 버튼을 클릭하여 새로운 속성을 추가할 수 있습니다</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</CardContent>
|
||||
</Card>
|
||||
<AttributeTabContent
|
||||
activeAttributeTab={activeAttributeTab}
|
||||
setActiveAttributeTab={setActiveAttributeTab}
|
||||
attributeSubTabs={attributeSubTabs}
|
||||
unitOptions={unitOptions}
|
||||
materialOptions={materialOptions}
|
||||
surfaceTreatmentOptions={surfaceTreatmentOptions}
|
||||
customAttributeOptions={customAttributeOptions}
|
||||
attributeColumns={attributeColumns}
|
||||
itemMasterFields={itemMasterFields}
|
||||
setIsManageAttributeTabsDialogOpen={setIsManageAttributeTabsDialogOpen}
|
||||
setIsOptionDialogOpen={setIsOptionDialogOpen}
|
||||
setEditingOptionType={setEditingOptionType}
|
||||
setNewOptionValue={setNewOptionValue}
|
||||
setNewOptionLabel={setNewOptionLabel}
|
||||
setNewOptionColumnValues={setNewOptionColumnValues}
|
||||
setIsColumnManageDialogOpen={setIsColumnManageDialogOpen}
|
||||
setManagingColumnType={setManagingColumnType}
|
||||
setNewColumnName={setNewColumnName}
|
||||
setNewColumnKey={setNewColumnKey}
|
||||
setNewColumnType={setNewColumnType}
|
||||
setNewColumnRequired={setNewColumnRequired}
|
||||
handleDeleteOption={handleDeleteOption}
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
{/* 항목 탭 */}
|
||||
|
||||
Reference in New Issue
Block a user