From cc1b813a9d6fe16431d3cac69a6694fcb9fcab46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=EB=B3=91=EC=B2=A0?= Date: Thu, 5 Feb 2026 09:17:31 +0900 Subject: [PATCH] =?UTF-8?q?fix(WEB):=20=EC=A3=BC=EB=AC=B8=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=86=B5=ED=95=A9?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=85=9C=ED=94=8C=EB=A6=BF=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=B3=B4=EA=B0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OrderRegistration 수정 - IntegratedListTemplateV2 기능 확장 (+42줄) Co-Authored-By: Claude Opus 4.5 --- src/components/orders/OrderRegistration.tsx | 2 +- .../templates/IntegratedListTemplateV2.tsx | 42 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/components/orders/OrderRegistration.tsx b/src/components/orders/OrderRegistration.tsx index 2afedb23..fe1add7b 100644 --- a/src/components/orders/OrderRegistration.tsx +++ b/src/components/orders/OrderRegistration.tsx @@ -378,7 +378,7 @@ export function OrderRegistration({ // 폼 콘텐츠 렌더링 const renderFormContent = useCallback( () => ( -
+
{/* Validation 에러 Alert */} {Object.keys(fieldErrors).length > 0 && ( diff --git a/src/components/templates/IntegratedListTemplateV2.tsx b/src/components/templates/IntegratedListTemplateV2.tsx index 4a369cbd..ab1859f2 100644 --- a/src/components/templates/IntegratedListTemplateV2.tsx +++ b/src/components/templates/IntegratedListTemplateV2.tsx @@ -296,6 +296,7 @@ export function IntegratedListTemplateV2({ const [accumulatedMobileData, setAccumulatedMobileData] = useState([]); const [lastAccumulatedPage, setLastAccumulatedPage] = useState(0); const mobileScrollSentinelRef = useRef(null); + const mobileCardAreaRef = useRef(null); // 클라이언트 사이드 인피니티용 (allData가 있는 경우) const [clientDisplayCount, setClientDisplayCount] = useState(mobileDisplayCount || 20); @@ -404,6 +405,45 @@ export function IntegratedListTemplateV2({ return () => observer.disconnect(); }, [isServerSidePagination, allData, clientDisplayCount, enableMobileInfinityScroll, isMobileLoading, pagination.currentPage, pagination.totalPages, handleLoadMoreClient, handleLoadMoreMobile]); + // ===== 모바일 카드 영역 내부 스크롤 컨테인먼트 ===== + // 카드 영역이 뷰포트 남은 높이만큼만 차지하고, 내부에서만 스크롤되도록 설정 + // → 헤더/검색/탭은 항상 보이고, 카드만 스크롤 + useEffect(() => { + const el = mobileCardAreaRef.current; + if (!el) return; + + const applyScrollContainment = () => { + // xl(1280px) 이상은 데스크톱 → 테이블+페이지네이션 사용, 컨테인먼트 해제 + if (window.innerWidth >= 1280) { + el.style.maxHeight = ''; + el.style.overflowY = ''; + el.style.overscrollBehavior = ''; + return; + } + + const rect = el.getBoundingClientRect(); + const available = window.innerHeight - rect.top - 16; // 16px 하단 여유 + + if (available > 200) { + el.style.maxHeight = `${available}px`; + el.style.overflowY = 'auto'; + el.style.overscrollBehavior = 'contain'; // 스크롤 누수 방지 + } + }; + + // 페이지 스크롤을 최상단으로 리셋 후 정확한 위치 측정 + window.scrollTo(0, 0); + el.scrollTop = 0; + + const raf = requestAnimationFrame(applyScrollContainment); + window.addEventListener('resize', applyScrollContainment); + + return () => { + cancelAnimationFrame(raf); + window.removeEventListener('resize', applyScrollContainment); + }; + }, [activeTab, isLoading]); + const startIndex = (pagination.currentPage - 1) * pagination.itemsPerPage; const allSelected = selectedItems.size === data.length && data.length > 0; @@ -773,7 +813,7 @@ export function IntegratedListTemplateV2({ )} {/* 모바일/태블릿/소형 노트북 (~1279px) 카드 뷰 */} -
+
{isLoading ? (