diff --git a/com.twin.app.shoptime/src/actions/panelActions.js b/com.twin.app.shoptime/src/actions/panelActions.js index cfe19ad7..6706a6f8 100644 --- a/com.twin.app.shoptime/src/actions/panelActions.js +++ b/com.twin.app.shoptime/src/actions/panelActions.js @@ -6,7 +6,7 @@ import { updateHomeInfo } from './homeActions'; import { createDebugHelpers } from '../utils/debug'; // 디버그 헬퍼 설정 -const DEBUG_MODE = false; +const DEBUG_MODE = true; const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE); // 시작 메뉴 추적을 위한 상수 @@ -39,10 +39,19 @@ export const pushPanel = (panel, duplicatable = false) => ({ duplicatable: duplicatable, }); -export const popPanel = (panelName) => ({ - type: types.POP_PANEL, - payload: panelName, -}); +export const popPanel = (panelName) => { + if (DEBUG_MODE) { + console.log('[PANEL-TRACE] popPanel action creator', { + panelName, + caller: new Error().stack?.split('\n')[2]?.trim(), + }); + console.trace('[PANEL-TRACE] popPanel stack trace'); + } + return { + type: types.POP_PANEL, + payload: panelName, + }; +}; export const updatePanel = (panelInfo) => ({ type: types.UPDATE_PANEL, @@ -289,10 +298,25 @@ export const navigateToDetail = ({ case SOURCE_MENUS.PLAYER_MEDIA: { // PlayerPanel에서 온 경우 const { hidePlayerOverlays } = require('./videoPlayActions'); + const statePanels = panels || getState().panels.panels; + const playerPanelEntry = statePanels.find((p) => p.name === panel_names.PLAYER_PANEL); // DetailPanel push 전에 VideoPlayer 오버레이 숨김 dispatch(hidePlayerOverlays()); + // PlayerPanel이 modal=true라면 풀스크린 백그라운드로 전환 + if (playerPanelEntry?.panelInfo?.modal) { + dispatch( + updatePanel({ + name: panel_names.PLAYER_PANEL, + panelInfo: { + ...playerPanelEntry.panelInfo, + modal: false, + }, + }) + ); + } + // 현재 포커스된 요소 저장 if (Object.keys(focusSnapshot).length > 0) { panelInfo.lastFocusedTargetId = focusSnapshot.lastFocusedTargetId; diff --git a/com.twin.app.shoptime/src/actions/playActions.js b/com.twin.app.shoptime/src/actions/playActions.js index 6a7d005c..5a377615 100644 --- a/com.twin.app.shoptime/src/actions/playActions.js +++ b/com.twin.app.shoptime/src/actions/playActions.js @@ -325,6 +325,12 @@ export const finishVideoPreview = () => (dispatch, getState) => { const panels = getState().panels.panels; const topPanel = panels[panels.length - 1]; if (topPanel && topPanel.name === panel_names.PLAYER_PANEL && topPanel.panelInfo.modal) { + console.log('[PANEL-TRACE] finishVideoPreview: popping modal player', { + topPanelName: topPanel.name, + modal: topPanel.panelInfo.modal, + stack: panels.map((p) => p.name), + panelInfo: topPanel.panelInfo, + }); if (startVideoFocusTimer) { clearTimeout(startVideoFocusTimer); startVideoFocusTimer = null; diff --git a/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js b/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js index d7c05ea8..29c1ff65 100644 --- a/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js +++ b/com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js @@ -125,6 +125,14 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => { // POP 후 top panel을 기록 (이전 패널로 돌아감) if (panels.length > 0) { const topPanel = panels[panels.length - 1]; + if (DEBUG_MODE) { + console.log('[PANEL-TRACE] POP_PANEL middleware stack', { + stack: panels.map((p) => p.name), + topPanel: topPanel?.name, + payload: action.payload, + caller: new Error().stack?.split('\n')[2]?.trim(), + }); + } if (topPanel && topPanel.name) { const isGNB = isGNBCall(); const isOnTop = calculateIsOnTop(topPanel.name); // 🎯 isOnTop 계산 diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx index 7923c89f..78034238 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx @@ -303,6 +303,12 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { const sourcePanel = panelInfo?.sourcePanel; const sourceMenu = panelInfo?.sourceMenu; + console.log('[DP-TRACE] Detail unmount start', { + sourcePanel, + sourceMenu, + panelsSnapshot: panels.map((p) => p.name), + }); + console.log('[Detail-BG] 306-line sourcePanel:', sourcePanel, 'sourceMenu:', sourceMenu); // DetailPanel이 unmount되는 시점 @@ -1051,11 +1057,11 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { } else { console.log('[Detail-BG] ⏭️ DetailPanel - Skipping pause (no playerPanel or no productVideo)', { hasPlayerPanel, - hasProductVideo, - reason: !hasPlayerPanel ? 'no playerPanel' : 'no productVideo', - timestamp: Date.now(), - }); - } + hasProductVideo, + reason: !hasPlayerPanel ? 'no playerPanel' : 'no productVideo', + timestamp: Date.now(), + }); + } return () => { // DetailPanel 언마운트 시: 비디오가 있었고 멈췄던 경우만 재생 재개 @@ -1104,12 +1110,15 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { const hasPlayerPanel = panels.some( (panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal === true ); + const launchedFromPlayer = panelInfo?.fromPlayer || panelInfo?.sourcePanel === panel_names.PLAYER_PANEL; - if (hasPlayerPanel) { - console.log('[DetailPanel] PlayerPanel modal=true detected - stopping video preview'); + if (hasPlayerPanel && !launchedFromPlayer) { + console.log('[DetailPanel] PlayerPanel modal=true detected - stopping video preview (non-player source)'); dispatch(finishVideoPreview()); + } else if (hasPlayerPanel && launchedFromPlayer) { + console.log('[DetailPanel] PlayerPanel modal=true detected - launched from Player, skip finishVideoPreview'); } - }, [panels, dispatch]); + }, [panels, dispatch, panelInfo?.fromPlayer, panelInfo?.sourcePanel]); return (