diff --git a/com.twin.app.shoptime/src/actions/playActions.js b/com.twin.app.shoptime/src/actions/playActions.js index fecf1154..fef433c7 100644 --- a/com.twin.app.shoptime/src/actions/playActions.js +++ b/com.twin.app.shoptime/src/actions/playActions.js @@ -161,11 +161,18 @@ export const startVideoPlayerNew = panelWorkingAction = updatePanel; } - // 중복 실행 방지: 현재 PlayerPanel이 같은 배너를 재생 중이면 skip - const currentPlayerState = topPanel?.panelInfo?.playerState || {}; - if (currentPlayerState?.currentBannerId === bannerId) { - console.log('[playActions] startVideoPlayerNew: 동일 배너 재생 중이라 중복 실행 SKIP', { + // 중복 실행 방지: 같은 배너 + 같은 modal 상태/컨테이너면 skip + const currentPanelInfo = topPanel?.panelInfo || {}; + const currentPlayerState = currentPanelInfo.playerState || {}; + const isSameBanner = currentPlayerState.currentBannerId === bannerId; + const isSameModalType = currentPanelInfo.modal === modal; + const isSameContainer = currentPanelInfo.modalContainerId === modalContainerId; + + if (isSameBanner && isSameModalType && isSameContainer) { + console.log('[playActions] startVideoPlayerNew: 동일한 요청이므로 스킵', { bannerId, + modal, + modalContainerId, }); return; } @@ -397,7 +404,13 @@ export const shrinkVideoTo1px = () => (dispatch, getState) => { }) ); } else { - console.log('[HomePanel] shrinkVideoTo1px: No modal PlayerPanel found'); + console.log('[HomePanel] shrinkVideoTo1px: No modal PlayerPanel found', { + panels: panels.map((p) => ({ + name: p.name, + modal: p.panelInfo?.modal, + shouldShrinkTo1px: p.panelInfo?.shouldShrinkTo1px, + })), + }); } }; @@ -445,7 +458,13 @@ export const expandVideoFrom1px = () => (dispatch, getState) => { }) ); } else { - console.log('[HomePanel] expandVideoFrom1px: No shrunk modal PlayerPanel found'); + console.log('[HomePanel] expandVideoFrom1px: No shrunk modal PlayerPanel found', { + panels: panels.map((p) => ({ + name: p.name, + modal: p.panelInfo?.modal, + shouldShrinkTo1px: p.panelInfo?.shouldShrinkTo1px, + })), + }); } }; diff --git a/com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js b/com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js index 0a235f91..7157402b 100644 --- a/com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js +++ b/com.twin.app.shoptime/src/hooks/useVideoPlay/useVideoPlay.js @@ -3,7 +3,7 @@ import { useCallback, useRef, useState, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { - startBannerVideo, + startVideoPlayerNew, stopBannerVideo, stopAndHideVideo, hidePlayerVideo, @@ -143,7 +143,14 @@ export const useVideoPlay = (options = {}) => { videoState.setCurrentPlaying(bannerId); // Redux 액션 dispatch - bannerId를 modalContainerId로 사용 - dispatch(startBannerVideo(bannerId, { modalContainerId: bannerId, force })); + dispatch( + startVideoPlayerNew({ + bannerId, + modal: true, + modalContainerId: bannerId, + force, + }) + ); // 성공 상태 업데이트 setErrorCount(0); // 성공 시 오류 카운트 초기화 diff --git a/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js b/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js index 0e0b261b..81ca099f 100644 --- a/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js +++ b/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js @@ -22,10 +22,11 @@ const DEBUG_MODE = true; */ export const panelHistoryMiddleware = (store) => (next) => (action) => { // 모든 PANEL 관련 액션 로깅 - if (DEBUG_MODE && action.type && ( - action.type.includes('PANEL') || - action.type === 'CLEAR_PANEL_HISTORY' - )) { + if ( + DEBUG_MODE && + action.type && + (action.type.includes('PANEL') || action.type === 'CLEAR_PANEL_HISTORY') + ) { const caller = new Error().stack.split('\n')[1]?.trim(); console.log(`[PANEL DEBUG] ${action.type} from: ${caller}`); console.log(' Payload:', action.payload); @@ -38,8 +39,7 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { const stackLines = stack.split('\n'); for (const line of stackLines) { - if (line.includes('TabLayout.jsx') || - line.includes('TIconButton.jsx')) { + if (line.includes('TabLayout.jsx') || line.includes('TIconButton.jsx')) { return true; } } @@ -75,15 +75,36 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { if (panelName) { const isGNB = isGNBCall(); const isOnTop = calculateIsOnTop(panelName); // 🎯 isOnTop 계산 - if (DEBUG_MODE) console.log('[PANEL] PUSH_PANEL:', { panelName, panelInfo, isGNB, isOnTop, timestamp: new Date().toISOString() }); - store.dispatch(enqueuePanelHistory(panelName, panelInfo, 'PUSH', new Date().toISOString(), isGNB, false, isOnTop)); + if (DEBUG_MODE) + console.log('[PANEL] PUSH_PANEL:', { + panelName, + panelInfo, + isGNB, + isOnTop, + timestamp: new Date().toISOString(), + }); + store.dispatch( + enqueuePanelHistory( + panelName, + panelInfo, + 'PUSH', + new Date().toISOString(), + isGNB, + false, + isOnTop + ) + ); // PanelHistory 상태 로그 (state 업데이트 후) const logPanelHistoryAfter = () => { if (DEBUG_MODE) { const stateAfter = store.getState(); const panelHistoryAfter = stateAfter.panelHistory; - console.log('[PANEL_HISTORY] After PUSH_PANEL:', panelHistoryAfter); + const panelsAfter = stateAfter.panels.panels; + console.log('[PANEL_HISTORY] After PUSH_PANEL:', { + panelHistory: panelHistoryAfter, + panels: panelsAfter, + }); } }; @@ -102,15 +123,36 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { if (topPanel && topPanel.name) { const isGNB = isGNBCall(); const isOnTop = calculateIsOnTop(topPanel.name); // 🎯 isOnTop 계산 - if (DEBUG_MODE) console.log('[PANEL] POP_PANEL:', { panelName: topPanel.name, panelInfo: topPanel.panelInfo || {}, isGNB, isOnTop, timestamp: new Date().toISOString() }); - store.dispatch(enqueuePanelHistory(topPanel.name, topPanel.panelInfo || {}, 'POP', new Date().toISOString(), isGNB, false, isOnTop)); + if (DEBUG_MODE) + console.log('[PANEL] POP_PANEL:', { + panelName: topPanel.name, + panelInfo: topPanel.panelInfo || {}, + isGNB, + isOnTop, + timestamp: new Date().toISOString(), + }); + store.dispatch( + enqueuePanelHistory( + topPanel.name, + topPanel.panelInfo || {}, + 'POP', + new Date().toISOString(), + isGNB, + false, + isOnTop + ) + ); // PanelHistory 상태 로그 (state 업데이트 후) const logPanelHistoryAfter = () => { if (DEBUG_MODE) { const stateAfter = store.getState(); const panelHistoryAfter = stateAfter.panelHistory; - console.log('[PANEL_HISTORY] After POP_PANEL:', panelHistoryAfter); + const panelsAfter = stateAfter.panels.panels; + console.log('[PANEL_HISTORY] After POP_PANEL:', { + panelHistory: panelHistoryAfter, + panels: panelsAfter, + }); } }; @@ -129,15 +171,36 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { if (panelName) { const isGNB = isGNBCall(); const isOnTop = calculateIsOnTop(panelName); // 🎯 isOnTop 계산 - if (DEBUG_MODE) console.log('[PANEL] UPDATE_PANEL:', { panelName, panelInfo, isGNB, isOnTop, timestamp: new Date().toISOString() }); - store.dispatch(enqueuePanelHistory(panelName, panelInfo, 'UPDATE', new Date().toISOString(), isGNB, false, isOnTop)); + if (DEBUG_MODE) + console.log('[PANEL] UPDATE_PANEL:', { + panelName, + panelInfo, + isGNB, + isOnTop, + timestamp: new Date().toISOString(), + }); + store.dispatch( + enqueuePanelHistory( + panelName, + panelInfo, + 'UPDATE', + new Date().toISOString(), + isGNB, + false, + isOnTop + ) + ); // PanelHistory 상태 로그 (state 업데이트 후) const logPanelHistoryAfter = () => { if (DEBUG_MODE) { const stateAfter = store.getState(); const panelHistoryAfter = stateAfter.panelHistory; - console.log('[PANEL_HISTORY] After UPDATE_PANEL:', panelHistoryAfter); + const panelsAfter = stateAfter.panels.panels; + console.log('[PANEL_HISTORY] After UPDATE_PANEL:', { + panelHistory: panelHistoryAfter, + panels: panelsAfter, + }); } }; @@ -150,11 +213,13 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { // RESET_PANELS: GNB 네비게이션 또는 완전 초기화 case types.RESET_PANELS: { - if (DEBUG_MODE) console.log('[PANEL] RESET_PANELS:', { - payload: action.payload, - timestamp: new Date().toISOString() - }); - if (DEBUG_MODE) console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory); + if (DEBUG_MODE) + console.log('[PANEL] RESET_PANELS:', { + payload: action.payload, + timestamp: new Date().toISOString(), + }); + if (DEBUG_MODE) + console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory); // 모든 RESET_PANELS를 기록 const isGNB = isGNBCall(); @@ -164,35 +229,48 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { const firstPanel = action.payload[0]; if (firstPanel && firstPanel.name) { const isOnTop = calculateIsOnTop(firstPanel.name); // 🎯 isOnTop 계산 - if (DEBUG_MODE) console.log('[PANEL_DEBUG] RESET_PANELS to:', firstPanel.name, { isGNB, isOnTop, fromResetPanel: true }); + if (DEBUG_MODE) + console.log('[PANEL_DEBUG] RESET_PANELS to:', firstPanel.name, { + isGNB, + isOnTop, + fromResetPanel: true, + }); // RESET 이동을 히스토리에 기록 - store.dispatch(enqueuePanelHistory( - firstPanel.name, - firstPanel.panelInfo || {}, - 'RESET', - new Date().toISOString(), - isGNB, // TabLayout/TIconButton이면 true - true, // fromResetPanel: 항상 true - isOnTop // 🎯 isOnTop 정보 추가 - )); + store.dispatch( + enqueuePanelHistory( + firstPanel.name, + firstPanel.panelInfo || {}, + 'RESET', + new Date().toISOString(), + isGNB, // TabLayout/TIconButton이면 true + true, // fromResetPanel: 항상 true + isOnTop // 🎯 isOnTop 정보 추가 + ) + ); } } else { // 완전 초기화 (payload가 없는 경우 - HomePanel, 앱 초기화 등) - if (DEBUG_MODE) console.log('[PANEL_DEBUG] Complete panel history reset (payload empty)', { isGNB, fromResetPanel: true }); + if (DEBUG_MODE) + console.log('[PANEL_DEBUG] Complete panel history reset (payload empty)', { + isGNB, + fromResetPanel: true, + }); store.dispatch(clearPanelHistory()); // HomePanel 초기화 기록 (앱 시작 시) if (DEBUG_MODE) console.log('[PANEL_DEBUG] Recording initial HomePanel'); const isOnTop = calculateIsOnTop('homepanel'); // 🎯 isOnTop 계산 - store.dispatch(enqueuePanelHistory( - 'homepanel', - {}, - 'APP_INITIALIZE', - new Date().toISOString(), - isGNB, // TIconButton Home 버튼이면 true - true, // fromResetPanel: true - isOnTop // 🎯 isOnTop 정보 추가 - )); + store.dispatch( + enqueuePanelHistory( + 'homepanel', + {}, + 'APP_INITIALIZE', + new Date().toISOString(), + isGNB, // TIconButton Home 버튼이면 true + true, // fromResetPanel: true + isOnTop // 🎯 isOnTop 정보 추가 + ) + ); } // PanelHistory 상태 로그 (초기화 후) @@ -200,7 +278,11 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { if (DEBUG_MODE) { const stateAfter = store.getState(); const panelHistoryAfter = stateAfter.panelHistory; - console.log('[PANEL_HISTORY] After RESET_PANELS:', panelHistoryAfter); + const panelsAfter = stateAfter.panels.panels; + console.log('[PANEL_HISTORY] After RESET_PANELS:', { + panelHistory: panelHistoryAfter, + panels: panelsAfter, + }); } }; diff --git a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx index f03becbc..5870f1be 100644 --- a/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx +++ b/com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx @@ -599,6 +599,13 @@ const HomePanel = ({ isOnTop }) => { if (isInitialRender.current) { isInitialRender.current = false; + // ✅ 마운트 시 banner0 자동 재생 설정 + console.log('[HomePanel] 마운트 - banner0 재생 시도', videoPlay); + videoPlayIntentRef.current = { bannerId: 'banner0' }; + console.log('[HomePanel] videoPlayIntentRef 설정:', videoPlayIntentRef.current); + videoPlay.playVideo('banner0', { reason: 'mount-init' }); + console.log('[HomePanel] playVideo 호출 완료'); + if (isDeepLink || (!panels.length && !panelInfo.focusedContainerId)) { dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } })); dispatch(getHomeMainContents()); @@ -684,6 +691,28 @@ const HomePanel = ({ isOnTop }) => { } }, [isOnTop]); + // ✅ HomePanel 활성화 조건: 최상단 패널 또는 PlayerPanel 아래의 두 번째 패널 + // 비디오가 재생이 아니면 videoPlayIntentRef의 bannerId로 비디오 재생 + useEffect(() => { + const isHomePanelActive = + panels[0]?.name === panel_names.HOME_PANEL || + (panels.length >= 2 && + panels[0]?.name === panel_names.PLAYER_PANEL && + panels[1]?.name === panel_names.HOME_PANEL); + + if (isHomePanelActive && videoPlayIntentRef.current?.bannerId) { + const bannerId = videoPlayIntentRef.current.bannerId; + const currentPlaying = videoPlay.getCurrentPlayingBanner(); + + // 이미 재생 중인 배너가 다르면 새로 재생 + if (currentPlaying !== bannerId) { + videoPlay.playVideo(bannerId, { + reason: 'homePanel-active', + }); + } + } + }, [panels]); + useEffect(() => { return () => { const c = Spotlight.getCurrent(); diff --git a/com.twin.app.shoptime/src/views/MainView/MainView.jsx b/com.twin.app.shoptime/src/views/MainView/MainView.jsx index fae595f7..1a34875a 100644 --- a/com.twin.app.shoptime/src/views/MainView/MainView.jsx +++ b/com.twin.app.shoptime/src/views/MainView/MainView.jsx @@ -6,11 +6,10 @@ import { useDispatch, useSelector } from 'react-redux'; import platform from '@enact/core/platform'; import Spotlight from '@enact/spotlight'; - import defaultWatchItem from '../../../assets/images/img-alert-banner-st@3x.png'; // 테스트용 - TODO: 메인 홈 화면에 나와야 하는 이미지들 추가 후 preloadImages에 추가 -import testImage from '../../../assets/images/img-banner-myinfo-login@3x.png'; -import defaultImageItem from '../../../assets/images/img-thumb-empty-product@3x.png'; +// import testImage from '../../../assets/images/img-banner-myinfo-login@3x.png'; +// import defaultImageItem from '../../../assets/images/img-thumb-empty-product@3x.png'; import LoadingPreloadImage from '../../../assets/images/intro/splash_02_stop.webp'; import LoadingAnimation from '../../../assets/images/intro/splash_03_end.webp'; import LoadingCompleteImage from '../../../assets/images/intro/splash_04_end.webp'; @@ -80,7 +79,7 @@ import WelcomeEventPanel from '../WelcomeEventPanel/WelcomeEventPanel'; import css from './MainView.module.less'; // DEBUG_MODE 상수 - true일 때만 console.log 출력 -const DEBUG_MODE = false; +const DEBUG_MODE = true; const preloadImages = [ LoadingPreloadImage, @@ -209,11 +208,14 @@ export default function MainView({ className, initService }) { // 단독 패널 체크 - CheckOutPanel, CartPanel 등 단독으로 렌더링되어야 하는 패널들 if (DEBUG_MODE) { - console.log(`[MainView] 🔍 Top panel name: ${topPanel?.name}`); - console.log(`[MainView] 🔍 isStandalonePanel check:`, isStandalonePanel(topPanel?.name)); - console.log(`[MainView] 🔍 STANDALONE_PANELS:`, STANDALONE_PANELS); + console.log(`[PANEL_MainView] 🔍 Top panel name: ${topPanel?.name}`); console.log( - `[MainView] 🔍 All panels:`, + `[PANEL_MainView] 🔍 isStandalonePanel check:`, + isStandalonePanel(topPanel?.name) + ); + console.log(`[PANEL_MainView] 🔍 STANDALONE_PANELS:`, STANDALONE_PANELS); + console.log( + `[PANEL_MainView] 🔍 All panels:`, panels.map((p) => ({ name: p.name, hasModal: !!p.panelInfo?.modal })) ); } @@ -258,6 +260,7 @@ export default function MainView({ className, initService }) { renderingPanels = panels.slice(-1); } } + return ( <> {(isHomeOnTop ||