fix: DetailPanel above PlayerPanel , FeaturedBrandsPanel
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 계산
|
||||
|
||||
@@ -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 (
|
||||
<div ref={containerRef}>
|
||||
|
||||
@@ -206,7 +206,9 @@ export default function MainView({ className, initService }) {
|
||||
let renderingPanels = [];
|
||||
|
||||
const topPanel = panels[panels.length - 1];
|
||||
|
||||
const hasFeaturedBrandsPanel = panels.some(
|
||||
(panel) => panel?.name === Config.panel_names.FEATURED_BRANDS_PANEL
|
||||
);
|
||||
// 단독 패널 체크 - CheckOutPanel, CartPanel 등 단독으로 렌더링되어야 하는 패널들
|
||||
if (DEBUG_MODE) {
|
||||
console.log(`[PANEL_MainView] 🔍 Top panel name: ${topPanel?.name}`);
|
||||
@@ -248,7 +250,7 @@ export default function MainView({ className, initService }) {
|
||||
'[MainView] Rendering 3-layer structure: PlayerPanel + DetailPanel + MediaPanel'
|
||||
);
|
||||
}
|
||||
renderingPanels = panels.slice(-3);
|
||||
renderingPanels = hasFeaturedBrandsPanel ? panels.slice(-4) : panels.slice(-3);
|
||||
} else if (
|
||||
panels[panels.length - 1]?.name === Config.panel_names.PLAYER_PANEL ||
|
||||
panels[panels.length - 1]?.name === Config.panel_names.PLAYER_PANEL_NEW ||
|
||||
@@ -256,18 +258,17 @@ export default function MainView({ className, initService }) {
|
||||
panels[panels.length - 2]?.name === Config.panel_names.PLAYER_PANEL ||
|
||||
panels[panels.length - 2]?.name === Config.panel_names.MEDIA_PANEL
|
||||
) {
|
||||
renderingPanels = panels.slice(-2);
|
||||
// const hasFeaturedBrandsPanel = panels.some(p => p.name === Config.panel_names.FEATURED_BRANDS_PANEL);
|
||||
// if (hasFeaturedBrandsPanel) {
|
||||
// renderingPanels = panels.slice(-3); // 3개 다 렌더링
|
||||
// } else {
|
||||
// renderingPanels = panels.slice(-2); // 2개만
|
||||
// }
|
||||
renderingPanels = hasFeaturedBrandsPanel ? panels.slice(-3) : panels.slice(-2);
|
||||
} else {
|
||||
renderingPanels = panels.slice(-1);
|
||||
}
|
||||
}
|
||||
|
||||
// DetailPanel 위치 확인 (있으면 항상 onTop 처리)
|
||||
const detailPanelIndex = renderingPanels.findIndex(
|
||||
(panel) => panel.name === Config.panel_names.DETAIL_PANEL
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{(isHomeOnTop ||
|
||||
@@ -293,17 +294,12 @@ export default function MainView({ className, initService }) {
|
||||
console.log(`[MainView] Standalone panel ${panel.name} is always onTop`);
|
||||
}
|
||||
}
|
||||
// 3-layer 케이스: 중간 패널(DetailPanel)이 onTop
|
||||
else if (renderingPanels.length === 3) {
|
||||
if (index === 1) {
|
||||
// DetailPanel (중간)
|
||||
isPanelOnTop = true;
|
||||
if (DEBUG_MODE) {
|
||||
console.log('[MainView] 3-layer: DetailPanel is onTop');
|
||||
}
|
||||
// DetailPanel이 포함되어 있으면 항상 onTop
|
||||
else if (detailPanelIndex >= 0) {
|
||||
isPanelOnTop = index === detailPanelIndex;
|
||||
if (DEBUG_MODE && isPanelOnTop) {
|
||||
console.log('[MainView] DetailPanel set to onTop');
|
||||
}
|
||||
// PlayerPanel (index 0): isOnTop = false (백그라운드)
|
||||
// MediaPanel (index 2): isOnTop = false (modal overlay)
|
||||
}
|
||||
// 2-layer 케이스: modal이면 첫 번째가 onTop
|
||||
else if (
|
||||
|
||||
@@ -1192,14 +1192,27 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
||||
//todo if(modal)
|
||||
return () => {
|
||||
// 패널이 2개 존재할때만 popPanel 진행
|
||||
if (panelInfo.modal && !isOnTop) {
|
||||
console.log('[PlayerPanel] popPanel - useEffect cleanup');
|
||||
// 현재 스택의 top이 PlayerPanel일 때만 pop 수행 (다른 패널이 올라온 상태에서 오작동 방지)
|
||||
console.log('[PP-TRACE] cleanup start', {
|
||||
modal: panelInfo.modal,
|
||||
isOnTop,
|
||||
topPanel: panels[panels.length - 1]?.name,
|
||||
stack: panels.map((p) => p.name),
|
||||
});
|
||||
const topPanelName = panels[panels.length - 1]?.name;
|
||||
if (
|
||||
panelInfo.modal &&
|
||||
!isOnTop &&
|
||||
topPanelName === panel_names.PLAYER_PANEL &&
|
||||
panels.length === 1 // 다른 패널 존재 시 pop 금지 (DetailPanel 제거 방지)
|
||||
) {
|
||||
console.log('[PP-TRACE] popPanel - useEffect cleanup (top is PlayerPanel)');
|
||||
dispatch(PanelActions.popPanel());
|
||||
} else {
|
||||
Spotlight.focus('tbody');
|
||||
}
|
||||
};
|
||||
}, [panelInfo?.modal, isOnTop]);
|
||||
}, [panelInfo?.modal, isOnTop, panels]);
|
||||
|
||||
useEffect(() => {
|
||||
if (showNowInfos && panelInfo.shptmBanrTpNm === 'LIVE') {
|
||||
|
||||
Reference in New Issue
Block a user