'use client'; import { useState, useCallback } from 'react'; import { useMachines } from '@/lib/hooks'; import type { InspectionTemplate, InspectionTemplateItem } from '@/lib/types'; const SCHEDULE_LABELS: Record = { daily: '일일', weekly: '주간', monthly: '월간', yearly: '연간', ad_hoc: '수시', }; const MODE_LABELS: Record = { checklist: '체크리스트', measurement: '측정', monitoring: '모니터링', }; const DATA_TYPE_LABELS: Record = { numeric: '숫자', boolean: '예/아니오', text: '텍스트', select: '선택', }; interface ItemDraft { id?: string; name: string; category: string; data_type: string; unit: string; spec_min: string; spec_max: string; select_options_text: string; equipment_part_id: string; is_required: boolean; } interface TemplateDraft { name: string; subject_type: string; machine_id: string; product_code: string; schedule_type: string; inspection_mode: string; } interface Props { tenantId: string; initialData?: InspectionTemplate | null; onSave: (meta: TemplateDraft, items: ItemDraft[]) => Promise; isEdit?: boolean; } function itemToItemDraft(item: InspectionTemplateItem): ItemDraft { return { id: item.id, name: item.name, category: item.category || '', data_type: item.data_type, unit: item.unit || '', spec_min: item.spec_min !== null ? String(item.spec_min) : '', spec_max: item.spec_max !== null ? String(item.spec_max) : '', select_options_text: item.select_options ? item.select_options.join(', ') : '', equipment_part_id: item.equipment_part_id || '', is_required: item.is_required, }; } const EMPTY_ITEM: ItemDraft = { name: '', category: '', data_type: 'numeric', unit: '', spec_min: '', spec_max: '', select_options_text: '', equipment_part_id: '', is_required: true, }; export function TemplateEditor({ tenantId, initialData, onSave, isEdit }: Props) { const [meta, setMeta] = useState({ name: initialData?.name || '', subject_type: initialData?.subject_type || 'equipment', machine_id: initialData?.machine_id || '', product_code: initialData?.product_code || '', schedule_type: initialData?.schedule_type || 'daily', inspection_mode: initialData?.inspection_mode || 'measurement', }); const [items, setItems] = useState( initialData?.items?.map(itemToItemDraft) || [] ); const [submitting, setSubmitting] = useState(false); const [showAddItem, setShowAddItem] = useState(false); const [newItem, setNewItem] = useState({ ...EMPTY_ITEM }); const { machines } = useMachines(tenantId); const handleMetaChange = useCallback((field: string, value: string) => { setMeta(prev => ({ ...prev, [field]: value })); }, []); const addItem = useCallback(() => { if (!newItem.name.trim()) return; setItems(prev => [...prev, { ...newItem }]); setNewItem({ ...EMPTY_ITEM }); setShowAddItem(false); }, [newItem]); const removeItem = useCallback((idx: number) => { if (!confirm('이 검사 항목을 삭제하시겠습니까?')) return; setItems(prev => prev.filter((_, i) => i !== idx)); }, []); const moveItem = useCallback((idx: number, direction: -1 | 1) => { setItems(prev => { const next = [...prev]; const target = idx + direction; if (target < 0 || target >= next.length) return prev; [next[idx], next[target]] = [next[target], next[idx]]; return next; }); }, []); const updateItem = useCallback((idx: number, field: string, value: string | boolean) => { setItems(prev => prev.map((item, i) => i === idx ? { ...item, [field]: value } : item )); }, []); const handleSubmit = useCallback(async (e: React.FormEvent) => { e.preventDefault(); if (!meta.name.trim()) return; setSubmitting(true); try { await onSave(meta, items); } finally { setSubmitting(false); } }, [meta, items, onSave]); return (

기본 정보

handleMetaChange('name', e.target.value)} disabled={submitting} autoFocus />
{meta.subject_type === 'equipment' && (
)}

검사 항목 ({items.length}개)

{items.length === 0 ? (
playlist_add

검사 항목이 없습니다. 항목을 추가하세요.

) : (
{items.map((item, idx) => (
{idx + 1}
updateItem(idx, 'name', e.target.value)} disabled={submitting} />
{item.data_type === 'numeric' && (
updateItem(idx, 'unit', e.target.value)} disabled={submitting} />
updateItem(idx, 'spec_min', e.target.value)} disabled={submitting} step="any" />
updateItem(idx, 'spec_max', e.target.value)} disabled={submitting} step="any" />
)} {item.data_type === 'select' && (
updateItem(idx, 'select_options_text', e.target.value)} disabled={submitting} />
)}
))}
)}
{showAddItem && (
setShowAddItem(false)}>
e.stopPropagation()}>

검사 항목 추가

setNewItem(prev => ({ ...prev, name: e.target.value }))} autoFocus />
setNewItem(prev => ({ ...prev, category: e.target.value }))} />
{newItem.data_type === 'numeric' && (
setNewItem(prev => ({ ...prev, unit: e.target.value }))} />
setNewItem(prev => ({ ...prev, spec_min: e.target.value }))} step="any" />
setNewItem(prev => ({ ...prev, spec_max: e.target.value }))} step="any" />
)} {newItem.data_type === 'select' && (
setNewItem(prev => ({ ...prev, select_options_text: e.target.value }))} />
)}
)}
); } export { SCHEDULE_LABELS, MODE_LABELS, DATA_TYPE_LABELS }; export type { TemplateDraft, ItemDraft };