diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index c2ec759d..ec7e7134 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -91,6 +91,51 @@ const findSelector = (selector, maxAttempts = 5, currentAttempts = 0) => { } }; +// 배너 위치 수집 함수 (top, left만 저장) +const collectBannerPositions = () => { + const positions = []; + + // banner0, banner1 등의 배너 위치 수집 + for (let i = 0; i < 10; i++) { + const bannerId = `banner${i}`; + const node = document.querySelector(`[data-spotlight-id="${bannerId}"]`); + + if (node) { + const { top, left } = node.getBoundingClientRect(); + positions.push({ + bannerId, + position: { top: Math.round(top), left: Math.round(left) } + }); + dlog(`[PlayerPanel] 배너 위치 수집: ${bannerId}`, { top: Math.round(top), left: Math.round(left) }); + } + } + + return positions; +}; + +// 위치 검증 함수 (오차 범위: 1px) +const isPositionMatching = (bannerPositions, bannerId, currentPosition) => { + const validPosition = bannerPositions.find(p => p.bannerId === bannerId); + + if (!validPosition) { + dlog(`[PlayerPanel] 배너 위치 검증 실패: ${bannerId} 배너를 찾을 수 없음`); + return false; + } + + const tolerance = 1; // 1px 오차 범위 + const isMatching = + Math.abs(currentPosition.top - validPosition.position.top) <= tolerance && + Math.abs(currentPosition.left - validPosition.position.left) <= tolerance; + + dlog(`[PlayerPanel] 배너 위치 검증: ${bannerId}`, { + expected: validPosition.position, + current: currentPosition, + matching: isMatching + }); + + return isMatching; +}; + const getLogTpNo = (type, nowMenu) => { if (type === 'LIVE') { switch (nowMenu) { @@ -219,6 +264,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props const [tabIndexV2, setTabIndexV2] = USE_STATE('tabIndexV2', 1); // 0: ShopNow, 1: LiveChannel, 2: ShopNowButton const [tabContainerVersion, setTabContainerVersion] = USE_STATE('tabContainerVersion', 2); // 1: TabContainer (우측), 2: TabContainerV2 (하단) const [isModalClosed, setIsModalClosed] = USE_STATE('isModalClosed', true); // 모달이 false 상태인지 나타내는 플래그 + const [validBannerPositions, setValidBannerPositions] = USE_STATE('validBannerPositions', []); // 유효한 배너 위치 (top, left) const panels = USE_SELECTOR('panels', (state) => state.panels.panels); const chatData = USE_SELECTOR('chatData', (state) => state.play.chatData); @@ -1937,6 +1983,30 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props panelInfo: { modalStyle: modalStyle, modalScale: scale }, }) ); + + // 🔽 배너 위치 수집 (초기 로드 시에만 실행) + if (validBannerPositions.length === 0) { + const positions = collectBannerPositions(); + if (positions.length > 0) { + setValidBannerPositions(positions); + dlog('[PlayerPanel] ✅ 배너 위치 초기 수집 완료:', positions); + } + } + + // 🔽 배너 위치 검증 (위치가 맞지 않으면 비디오 재생 중단) + if (validBannerPositions.length > 0) { + const currentPosition = { top: Math.round(top), left: Math.round(left) }; + const isValidPosition = isPositionMatching(validBannerPositions, panelInfo.modalContainerId, currentPosition); + + if (!isValidPosition) { + dlog('[PlayerPanel] ⚠️ 배너 위치 검증 실패 - 비디오 재생 중단', { + bannerId: panelInfo.modalContainerId, + currentPosition, + validBannerPositions + }); + return; // 비디오 재생 중단 + } + } } else { dlog('[PlayerPanel] Condition 1: Node not found, using saved modalStyle'); setModalStyle(panelInfo.modalStyle);