[feat]: Item Master 데이터 관리 기능 구현 및 타입 에러 수정
- ItemMasterDataManagement 컴포넌트 구조화 (tabs, dialogs, components 분리) - HierarchyTab 타입 에러 수정 (BOMItem section_id, updated_at 추가) - API 클라이언트 구현 (item-master.ts, 13개 엔드포인트) - ItemMasterContext 구현 (상태 관리 및 데이터 흐름) - 백엔드 요구사항 문서 작성 (CORS 설정, API 스펙 등) - SSR 호환성 수정 (navigator API typeof window 체크) - 미사용 변수 ESLint 에러 해결 - Context 리팩토링 (AuthContext, RootProvider 추가) - API 유틸리티 추가 (error-handler, logger, transformers) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
'use client';
|
||||
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
|
||||
const INPUT_TYPE_OPTIONS = [
|
||||
{ value: 'textbox', label: '텍스트 입력' },
|
||||
{ value: 'number', label: '숫자 입력' },
|
||||
{ value: 'dropdown', label: '드롭다운' },
|
||||
{ value: 'checkbox', label: '체크박스' },
|
||||
{ value: 'date', label: '날짜' },
|
||||
{ value: 'textarea', label: '긴 텍스트' },
|
||||
];
|
||||
|
||||
interface TemplateFieldDialogProps {
|
||||
isTemplateFieldDialogOpen: boolean;
|
||||
setIsTemplateFieldDialogOpen: (open: boolean) => void;
|
||||
editingTemplateFieldId: number | null;
|
||||
setEditingTemplateFieldId: (id: number | null) => void;
|
||||
templateFieldName: string;
|
||||
setTemplateFieldName: (name: string) => void;
|
||||
templateFieldKey: string;
|
||||
setTemplateFieldKey: (key: string) => void;
|
||||
templateFieldInputType: 'textbox' | 'number' | 'dropdown' | 'checkbox' | 'date' | 'textarea';
|
||||
setTemplateFieldInputType: (type: any) => void;
|
||||
templateFieldRequired: boolean;
|
||||
setTemplateFieldRequired: (required: boolean) => void;
|
||||
templateFieldOptions: string;
|
||||
setTemplateFieldOptions: (options: string) => void;
|
||||
templateFieldDescription: string;
|
||||
setTemplateFieldDescription: (description: string) => void;
|
||||
templateFieldMultiColumn: boolean;
|
||||
setTemplateFieldMultiColumn: (multi: boolean) => void;
|
||||
templateFieldColumnCount: number;
|
||||
setTemplateFieldColumnCount: (count: number) => void;
|
||||
templateFieldColumnNames: string[];
|
||||
setTemplateFieldColumnNames: (names: string[]) => void;
|
||||
handleAddTemplateField: () => void;
|
||||
}
|
||||
|
||||
export function TemplateFieldDialog({
|
||||
isTemplateFieldDialogOpen,
|
||||
setIsTemplateFieldDialogOpen,
|
||||
editingTemplateFieldId,
|
||||
setEditingTemplateFieldId,
|
||||
templateFieldName,
|
||||
setTemplateFieldName,
|
||||
templateFieldKey,
|
||||
setTemplateFieldKey,
|
||||
templateFieldInputType,
|
||||
setTemplateFieldInputType,
|
||||
templateFieldRequired,
|
||||
setTemplateFieldRequired,
|
||||
templateFieldOptions,
|
||||
setTemplateFieldOptions,
|
||||
templateFieldDescription,
|
||||
setTemplateFieldDescription,
|
||||
templateFieldMultiColumn,
|
||||
setTemplateFieldMultiColumn,
|
||||
templateFieldColumnCount,
|
||||
setTemplateFieldColumnCount,
|
||||
templateFieldColumnNames,
|
||||
setTemplateFieldColumnNames,
|
||||
handleAddTemplateField,
|
||||
}: TemplateFieldDialogProps) {
|
||||
return (
|
||||
<Dialog open={isTemplateFieldDialogOpen} onOpenChange={(open) => {
|
||||
setIsTemplateFieldDialogOpen(open);
|
||||
if (!open) {
|
||||
setEditingTemplateFieldId(null);
|
||||
setTemplateFieldName('');
|
||||
setTemplateFieldKey('');
|
||||
setTemplateFieldInputType('textbox');
|
||||
setTemplateFieldRequired(false);
|
||||
setTemplateFieldOptions('');
|
||||
setTemplateFieldDescription('');
|
||||
setTemplateFieldMultiColumn(false);
|
||||
setTemplateFieldColumnCount(2);
|
||||
setTemplateFieldColumnNames(['컬럼1', '컬럼2']);
|
||||
}
|
||||
}}>
|
||||
<DialogContent className="max-w-[95vw] sm:max-w-2xl max-h-[90vh] overflow-y-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{editingTemplateFieldId ? '항목 수정' : '항목 추가'}</DialogTitle>
|
||||
<DialogDescription>
|
||||
섹션에 포함될 항목을 설정합니다
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label>항목명 *</Label>
|
||||
<Input
|
||||
value={templateFieldName}
|
||||
onChange={(e) => setTemplateFieldName(e.target.value)}
|
||||
placeholder="예: 품목명"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>필드 키 *</Label>
|
||||
<Input
|
||||
value={templateFieldKey}
|
||||
onChange={(e) => setTemplateFieldKey(e.target.value)}
|
||||
placeholder="예: itemName"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>입력방식 *</Label>
|
||||
<Select value={templateFieldInputType} onValueChange={(v: any) => setTemplateFieldInputType(v)}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{INPUT_TYPE_OPTIONS.map(opt => (
|
||||
<SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{templateFieldInputType === 'dropdown' && (
|
||||
<div>
|
||||
<Label>드롭다운 옵션</Label>
|
||||
<Input
|
||||
value={templateFieldOptions}
|
||||
onChange={(e) => setTemplateFieldOptions(e.target.value)}
|
||||
placeholder="옵션1, 옵션2, 옵션3 (쉼표로 구분)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(templateFieldInputType === 'textbox' || templateFieldInputType === 'textarea') && (
|
||||
<div className="space-y-3 border rounded-lg p-4 bg-muted/30">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch
|
||||
checked={templateFieldMultiColumn}
|
||||
onCheckedChange={setTemplateFieldMultiColumn}
|
||||
/>
|
||||
<Label>다중 컬럼 사용</Label>
|
||||
</div>
|
||||
|
||||
{templateFieldMultiColumn && (
|
||||
<>
|
||||
<div>
|
||||
<Label>컬럼 개수</Label>
|
||||
<Input
|
||||
type="number"
|
||||
min={2}
|
||||
max={10}
|
||||
value={templateFieldColumnCount}
|
||||
onChange={(e) => {
|
||||
const count = parseInt(e.target.value) || 2;
|
||||
setTemplateFieldColumnCount(count);
|
||||
const newNames = Array.from({ length: count }, (_, i) =>
|
||||
templateFieldColumnNames[i] || `컬럼${i + 1}`
|
||||
);
|
||||
setTemplateFieldColumnNames(newNames);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>컬럼명</Label>
|
||||
{Array.from({ length: templateFieldColumnCount }).map((_, idx) => (
|
||||
<Input
|
||||
key={idx}
|
||||
placeholder={`컬럼 ${idx + 1}`}
|
||||
value={templateFieldColumnNames[idx] || ''}
|
||||
onChange={(e) => {
|
||||
const newNames = [...templateFieldColumnNames];
|
||||
newNames[idx] = e.target.value;
|
||||
setTemplateFieldColumnNames(newNames);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Label>설명 (선택)</Label>
|
||||
<Textarea
|
||||
value={templateFieldDescription}
|
||||
onChange={(e) => setTemplateFieldDescription(e.target.value)}
|
||||
placeholder="항목에 대한 설명"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch checked={templateFieldRequired} onCheckedChange={setTemplateFieldRequired} />
|
||||
<Label>필수 항목</Label>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setIsTemplateFieldDialogOpen(false)}>취소</Button>
|
||||
<Button onClick={handleAddTemplateField}>
|
||||
{editingTemplateFieldId ? '수정' : '추가'}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user