From c3872210438c9d61d82183306f88957c970d8ff7 Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Wed, 26 Nov 2025 10:07:38 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=92=88=EB=AA=A9=20=EB=82=A9=EA=B8=B0?= =?UTF-8?q?=EC=9D=BC=20=EC=9D=BC=EA=B4=84=20=EC=A0=81=EC=9A=A9=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ModalRepeaterTableComponent에 납기일 자동 일괄 적용 로직 구현 - 첫 납기일 선택 시 빈 행에 자동으로 동일 날짜 적용 - isDeliveryDateApplied 플래그로 중복 실행 방지 - ScreenModal 환경에서 onFormDataChange 경로 지원 --- .../order/OrderRegistrationModal.tsx | 44 ++++++++++++++++- .../ModalRepeaterTableComponent.tsx | 49 +++++++++++++++++-- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/frontend/components/order/OrderRegistrationModal.tsx b/frontend/components/order/OrderRegistrationModal.tsx index bd780038..615f0426 100644 --- a/frontend/components/order/OrderRegistrationModal.tsx +++ b/frontend/components/order/OrderRegistrationModal.tsx @@ -64,6 +64,9 @@ export function OrderRegistrationModal({ // 선택된 품목 목록 const [selectedItems, setSelectedItems] = useState([]); + // 납기일 일괄 적용 플래그 (딱 한 번만 실행) + const [isDeliveryDateApplied, setIsDeliveryDateApplied] = useState(false); + // 저장 중 const [isSaving, setIsSaving] = useState(false); @@ -158,6 +161,45 @@ export function OrderRegistrationModal({ hsCode: "", }); setSelectedItems([]); + setIsDeliveryDateApplied(false); // 플래그 초기화 + }; + + // 품목 목록 변경 핸들러 (납기일 일괄 적용 로직 포함) + const handleItemsChange = (newItems: any[]) => { + // 1️⃣ 플래그가 이미 true면 그냥 업데이트만 (일괄 적용 완료 상태) + if (isDeliveryDateApplied) { + setSelectedItems(newItems); + return; + } + + // 2️⃣ 품목이 없으면 그냥 업데이트 + if (newItems.length === 0) { + setSelectedItems(newItems); + return; + } + + // 3️⃣ 현재 상태: 납기일이 있는 행과 없는 행 개수 체크 + const itemsWithDate = newItems.filter((item) => item.delivery_date); + const itemsWithoutDate = newItems.filter((item) => !item.delivery_date); + + // 4️⃣ 조건: 정확히 1개만 날짜가 있고, 나머지는 모두 비어있을 때 일괄 적용 + if (itemsWithDate.length === 1 && itemsWithoutDate.length > 0) { + // 5️⃣ 전체 일괄 적용 + const selectedDate = itemsWithDate[0].delivery_date; + const updatedItems = newItems.map((item) => ({ + ...item, + delivery_date: selectedDate, // 모든 행에 동일한 납기일 적용 + })); + + setSelectedItems(updatedItems); + setIsDeliveryDateApplied(true); // 플래그 활성화 (다음부터는 일괄 적용 안 함) + + console.log("✅ 납기일 일괄 적용 완료:", selectedDate); + console.log(` - 대상: ${itemsWithoutDate.length}개 행에 ${selectedDate} 적용`); + } else { + // 그냥 업데이트 + setSelectedItems(newItems); + } }; // 전체 금액 계산 @@ -338,7 +380,7 @@ export function OrderRegistrationModal({ diff --git a/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx b/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx index 91d7b36f..109c5c56 100644 --- a/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx +++ b/frontend/lib/registry/components/modal-repeater-table/ModalRepeaterTableComponent.tsx @@ -195,17 +195,57 @@ export function ModalRepeaterTableComponent({ const columnName = component?.columnName; const value = (columnName && formData?.[columnName]) || componentConfig?.value || propValue || []; - // ✅ onChange 래퍼 (기존 onChange 콜백 + onFormDataChange 호출) + // ✅ onChange 래퍼 (기존 onChange 콜백 + onFormDataChange 호출 + 납기일 일괄 적용) const handleChange = (newData: any[]) => { + console.log("🔄 ModalRepeaterTableComponent.handleChange 호출:", { + dataLength: newData.length, + columnName, + hasExternalOnChange: !!(componentConfig?.onChange || propOnChange), + hasOnFormDataChange: !!(onFormDataChange && columnName), + }); + + // 🆕 납기일 일괄 적용 로직 (납기일 필드가 있는 경우만) + let processedData = newData; + + // 납기일 필드 찾기 (item_due_date, delivery_date, due_date 등) + const dateField = columns.find( + (col) => + col.field === "item_due_date" || + col.field === "delivery_date" || + col.field === "due_date" + ); + + if (dateField && !isDeliveryDateApplied && newData.length > 0) { + // 현재 상태: 납기일이 있는 행과 없는 행 개수 체크 + const itemsWithDate = newData.filter((item) => item[dateField.field]); + const itemsWithoutDate = newData.filter((item) => !item[dateField.field]); + + // 정확히 1개만 날짜가 있고, 나머지는 모두 비어있을 때 일괄 적용 + if (itemsWithDate.length === 1 && itemsWithoutDate.length > 0) { + const selectedDate = itemsWithDate[0][dateField.field]; + processedData = newData.map((item) => ({ + ...item, + [dateField.field]: selectedDate, // 모든 행에 동일한 납기일 적용 + })); + + setIsDeliveryDateApplied(true); // 플래그 활성화 + + console.log("✅ 납기일 일괄 적용 완료:", selectedDate); + console.log(` - 대상: ${itemsWithoutDate.length}개 행에 ${selectedDate} 적용`); + } + } + // 기존 onChange 콜백 호출 (호환성) const externalOnChange = componentConfig?.onChange || propOnChange; if (externalOnChange) { - externalOnChange(newData); + console.log("📤 외부 onChange 호출"); + externalOnChange(processedData); } // 🆕 onFormDataChange 호출하여 EditModal의 groupData 업데이트 if (onFormDataChange && columnName) { - onFormDataChange(columnName, newData); + console.log("📤 onFormDataChange 호출:", columnName); + onFormDataChange(columnName, processedData); } }; @@ -219,6 +259,9 @@ export function ModalRepeaterTableComponent({ const companyCode = componentConfig?.companyCode || propCompanyCode; const [modalOpen, setModalOpen] = useState(false); + // 🆕 납기일 일괄 적용 플래그 (딱 한 번만 실행) + const [isDeliveryDateApplied, setIsDeliveryDateApplied] = useState(false); + // columns가 비어있으면 sourceColumns로부터 자동 생성 const columns = React.useMemo((): RepeaterColumnConfig[] => { const configuredColumns = componentConfig?.columns || propColumns || [];