/** * 품목 등록/수정 폼 컴포넌트 * * react-hook-form + Zod 검증 */ 'use client'; import { useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import type { ItemType } from '@/types/item'; import { createItemFormSchema, type CreateItemFormData } from '@/lib/utils/validation'; import { Card, CardContent, CardHeader, CardTitle, } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Alert, AlertDescription } from '@/components/ui/alert'; import ItemTypeSelect from '../ItemTypeSelect'; import { DrawingCanvas } from '../DrawingCanvas'; // Local imports import { PART_TYPE_CATEGORIES, PART_ITEM_NAMES } from './constants'; import type { ItemFormProps } from './types'; import ValidationAlert from './ValidationAlert'; import FormHeader from './FormHeader'; import BendingDiagramSection from './BendingDiagramSection'; import BOMSection from './BOMSection'; import { MaterialForm, ProductForm, ProductCertificationSection, PartForm } from './forms'; import { useItemFormState } from './hooks'; import { toast } from 'sonner'; export default function ItemForm({ mode, initialData, onSubmit }: ItemFormProps) { const router = useRouter(); // 커스텀 훅으로 상태 관리 통합 const { // 기본 상태 isSubmitting, setIsSubmitting, selectedItemType, setSelectedItemType, // BOM 상태 bomLines, setBomLines, bomSearchStates, setBomSearchStates, // 파일 상태 specificationFile, setSpecificationFile, certificationFile, setCertificationFile, setBendingDiagramFile, bendingDiagram, setBendingDiagram, bendingDiagramInputMethod, setBendingDiagramInputMethod, isDrawingOpen, setIsDrawingOpen, // FG(제품) 상태 productName, setProductName, productStatus, setProductStatus, // PT(부품) 상태 selectedPartType, setSelectedPartType, partStatus, setPartStatus, // SM/RM/CS 상태 itemName, setItemName, selectedCategory1, setSelectedCategory1, selectedInstallationType, setSelectedInstallationType, materialStatus, setMaterialStatus, selectedSpecification, setSelectedSpecification, selectedUnit, setSelectedUnit, // ASSEMBLY 부품 상태 sideSpecWidth, setSideSpecWidth, sideSpecHeight, setSideSpecHeight, assemblyLength, setAssemblyLength, assemblyUnit, setAssemblyUnit, // 전동개폐기 상태 electricOpenerPower, setElectricOpenerPower, electricOpenerCapacity, setElectricOpenerCapacity, // 모터/체인 상태 motorVoltage, setMotorVoltage, chainSpec, setChainSpec, // BENDING 부품 상태 selectedBendingItemType, setSelectedBendingItemType, material, setMaterial, bendingLength, setBendingLength, widthSum, setWidthSum, partUnit, setPartUnit, bendingDetails, setBendingDetails, // BOM 필요 여부 needsBOM, setNeedsBOM, // 비고 remarks, setRemarks, // 헬퍼 함수 resetAllStates, } = useItemFormState({ mode, initialData }); const { register, handleSubmit, formState: { errors }, setValue, getValues, clearErrors, } = useForm({ // eslint-disable-next-line @typescript-eslint/no-explicit-any resolver: zodResolver(createItemFormSchema) as any, defaultValues: initialData || { itemType: 'FG', unit: 'EA', isActive: true, currentRevision: 0, isFinal: false, }, }); // 전개도 상세 입력 변경 시 폭 합계 자동 업데이트 useEffect(() => { if (bendingDetails.length > 0) { const totalSum = bendingDetails.reduce((acc, d) => { const calc = d.input + d.elongation; return acc + calc; }, 0); setWidthSum(totalSum.toFixed(1)); setValue('length', totalSum.toFixed(1)); } }, [bendingDetails, setValue, setWidthSum]); // 품목코드 자동 생성 함수 const generateItemCode = () => { if (selectedPartType === "BENDING" && selectedCategory1 && selectedBendingItemType) { const categoryData = PART_TYPE_CATEGORIES.BENDING.categories.find( cat => cat.value === selectedCategory1 ); const categoryCode = categoryData?.code || ''; const itemTypeData = PART_ITEM_NAMES[selectedCategory1]?.find( item => item.label === selectedBendingItemType ); const itemTypeCode = itemTypeData?.code || ''; let lengthCode = ""; if (bendingLength) { if (bendingLength.startsWith("W")) { if (bendingLength === "W50x3000") lengthCode = "53"; else if (bendingLength === "W50x4000") lengthCode = "54"; else if (bendingLength === "W80x3000") lengthCode = "83"; else if (bendingLength === "W80x4000") lengthCode = "84"; else { const match = bendingLength.match(/W(\d+)x(\d+)/); if (match) { const width = parseInt(match[1]); const length = parseInt(match[2]); lengthCode = `${Math.floor(width / 10)}${Math.floor(length / 1000)}`; } } } else { const lengthNum = parseInt(bendingLength); const lengthMap: Record = { 1219: "12", 2438: "24", 3000: "30", 3500: "35", 4000: "40", 4150: "41", 4200: "42", 4300: "43" }; lengthCode = lengthMap[lengthNum] || Math.floor(lengthNum / 100).toString().padStart(2, '0'); } } return `${categoryCode}${itemTypeCode}${lengthCode}`; } return ""; }; const handleFormSubmit = async (data: CreateItemFormData) => { setIsSubmitting(true); try { const finalData = { ...data, bom: bomLines.length > 0 ? bomLines : undefined, bendingDetails: bendingDetails.length > 0 ? bendingDetails : undefined, specificationFileName: specificationFile?.name, certificationFileName: certificationFile?.name, }; await onSubmit(finalData); router.push('/production/screen-production'); router.refresh(); } catch { toast.error('품목 저장에 실패했습니다.'); } finally { setIsSubmitting(false); } }; const handleItemTypeChange = (type: ItemType) => { setSelectedItemType(type); setValue('itemType', type); resetAllStates(setValue, clearErrors, type); }; return (
{/* Validation 에러 Alert */} {/* 헤더 */} router.back()} /> {/* 기본 정보 */} 기본 정보
{/* 1단계: 품목 유형 먼저 선택 */}
{errors.itemType && (

{errors.itemType.message}

)}

* 품목 유형에 따라 입력 항목이 다릅니다

{/* 2단계: 품목 유형이 선택된 경우에만 표시 */} {selectedItemType && ( <> {/* 제품(FG)인 경우 */} {selectedItemType === 'FG' && ( )} {/* 부품(PT)인 경우 */} {selectedItemType === 'PT' && ( )} {/* SM/RM/CS 공통 섹션 */} {(selectedItemType === 'RM' || selectedItemType === 'SM' || selectedItemType === 'CS') && ( )} )}
{/* 비고 필드 (PT를 제외한 모든 품목 유형) */} {selectedItemType && selectedItemType !== 'PT' && (
)} {/* 인정 정보 (FG only) */} {selectedItemType === 'FG' && ( )}
{/* 품목 유형 선택 안내 경고 */} {!selectedItemType && ( ⚠️ 품목 유형을 먼저 선택해주세요 )} {/* 절곡품 전개도 - PT ASSEMBLY(category1 선택 시) 또는 PT BENDING */} {selectedItemType === 'PT' && ( (selectedPartType === 'ASSEMBLY' && selectedCategory1) || selectedPartType === 'BENDING' ) && ( )} {/* 부품 구성 (BOM) - 제품 또는 부품(needsBOM 체크 시) */} {( selectedItemType === 'FG' || (selectedItemType === 'PT' && selectedPartType === 'ASSEMBLY' && selectedCategory1) || (selectedItemType === 'PT' && selectedPartType === 'PURCHASED') ) && needsBOM && ( )} {/* 전개도 그리기 캔버스 */} { setBendingDiagram(imageData); setIsDrawingOpen(false); }} initialImage={bendingDiagram} title={selectedPartType === 'ASSEMBLY' ? '조립품 전개도 그리기' : '절곡품 전개도 그리기'} description="전개도를 직접 그리거나 편집합니다." /> ); }