diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx index adb6e497..bf264351 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx @@ -33,6 +33,11 @@ import { setHidePopup, setShowPopup, } from '../../../actions/commonActions.js'; +import { + sendLogGNB, +} from '../../../actions/logActions'; +import { updatePanel } from '../../../actions/panelActions'; +import { panel_names } from '../../../utils/Config'; import { getProductCouponDownload, getProductCouponSearch, @@ -59,7 +64,6 @@ import TVirtualGridList import useReviews from '../../../hooks/useReviews/useReviews'; import useScrollTo from '../../../hooks/useScrollTo'; import { BUYNOW_CONFIG } from '../../../utils/BuyNowConfig'; -import { panel_names } from '../../../utils/Config'; import * as Config from '../../../utils/Config.js'; import { andThen, @@ -242,6 +246,7 @@ export default function ProductAllSection({ // Redux 상태 const webOSVersion = useSelector((state) => state.common.appStatus.webOSVersion); const groupInfos = useSelector((state) => state.product.groupInfo); + const nowMenu = useSelector((state) => state.common.menu.nowMenu); // YouMayLike 데이터는 API 응답 시간이 걸리므로 직접 구독 const youmaylikeData = useSelector((state) => state.main.youmaylikeData); @@ -263,6 +268,18 @@ export default function ProductAllSection({ const [isShowQRCode, setIsShowQRCode] = useState(true); const timerRef = useRef(null); + // sendLogGNB용 entryMenu + const entryMenuRef = useRef(null); + + // 출처 정보 통합 (향후 확장성 대비) + // YouMayLike 상품이 아닐 경우 fromPanel을 초기화하여 오기 방지 + const fromPanel = useMemo(() => ({ + fromYouMayLike: panelInfo?.fromPanel?.fromYouMayLike || false, + // 향후 다른 출처 플래그들 추가 가능 + // fromRecommendation: panelInfo?.fromPanel?.fromRecommendation || false, + // fromSearch: panelInfo?.fromPanel?.fromSearch || false, + }), [panelInfo?.fromPanel?.fromYouMayLike]); + //구매 하단 토스트 노출 확인을 위한 용도 const [openToast, setOpenToast] = useState(false); @@ -652,6 +669,45 @@ export default function ProductAllSection({ dispatch(resetShowAllReviews()); }, []); // 빈 dependency array = 마운트 시에만 실행 + // sendLogGNB 로깅 - Source의 DetailPanel 컴포넌트들과 동일한 패턴 + useEffect(() => { + if (!entryMenuRef.current) entryMenuRef.current = nowMenu; + + // BUY NOW 버튼 활성화 상태에 따른 메뉴 결정 (Source SingleProduct vs UnableProduct 패턴) + let baseMenu; + if (isTravelProductVisible) { + baseMenu = Config.LOG_MENU.DETAIL_PAGE_TRAVEL_THEME_DETAIL; + } else if (isGroupProductVisible) { + baseMenu = Config.LOG_MENU.DETAIL_PAGE_GROUP_DETAIL; + } else if (isBillingProductVisible) { + // BUY NOW 버튼 활성화 = SingleProduct + baseMenu = Config.LOG_MENU.DETAIL_PAGE_BILLING_PRODUCT_DETAIL; + } else { + // BUY NOW 버튼 비활성화 = UnableProduct + baseMenu = Config.LOG_MENU.DETAIL_PAGE_PRODUCT_DETAIL; + } + + // YouMayLike에서 상품 선택 시 메뉴 변경 (Source의 isYouMayLikeOpened와 동일 패턴) + const menu = (fromPanel?.fromYouMayLike !== undefined && fromPanel?.fromYouMayLike === true) + ? `${baseMenu}/${Config.LOG_MENU.DETAIL_PAGE_YOU_MAY_LIKE}` + : baseMenu; + + dispatch(sendLogGNB(menu)); + + // sendLogGNB 전송 후 플래그 초기화 (1회 사용 후 비활성화) + if (fromPanel?.fromYouMayLike === true) { + dispatch(updatePanel({ + name: panel_names.DETAIL_PANEL, + panelInfo: { + ...panelInfo, + fromPanel: { + fromYouMayLike: false // 플래그 초기화 + } + } + })); + } +}, [fromPanel?.fromYouMayLike, isBillingProductVisible, isUnavailableProductVisible, isGroupProductVisible, isTravelProductVisible]); // BUY NOW 상태 변경 시 재실행 + // [251115] 주석 처리: MediaPanel에서 이미 포커스 이동을 처리하므로 // ProductAllSection의 자동 포커스는 포커스 탈취를 일으킬 수 있음 // useEffect(() => { diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx index a21f3922..90eb3116 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx @@ -169,6 +169,9 @@ export default function YouMayAlsoLike({ prdtId, launchedFromPlayer: launchedFromPlayer, bgVideoInfo: bgVideoInfo, // 백그라운드 비디오 정보 유지 + fromPanel: { + fromYouMayLike: true, // YouMayLike에서 선택된 상품임을 표시 +}, // 출처 정보 통합 객체 }, }) ); diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index 23952d3f..512d3247 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -718,6 +718,13 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props panelInfo?.modal && liveLogParamsRef.current?.showId === panelInfo?.showId ) { + dlog('[PlayerPanel] 📡 LIVE Modal Log Ready and Conditions Met:', { + isModalLiveLogReady: logStatus.isModalLiveLogReady, + isOnTop, + isModal: panelInfo?.modal, + showIdMatch: liveLogParamsRef.current?.showId === panelInfo?.showId, + logParams: liveLogParamsRef.current, + }); let watchStrtDt = formatGMTString(new Date()); watchIntervalLive.current = setInterval(() => { @@ -736,6 +743,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props isModalLiveLogReady: false, })); clearInterval(watchIntervalLive.current); + dlog('[PlayerPanel] 🚀 Dispatching LIVE Modal Log:', { + logParams: liveLogParamsRef.current, + watchStrtDt, + }); dispatch( sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} }))