[251216] fix: TrendingNowPanel DetailPanel MediaPanel popPanel fix
🕐 커밋 시간: 2025. 12. 16. 15:21:13 📊 변경 통계: • 총 파일: 6개 • 추가: +62줄 • 삭제: -14줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/mediaActions.js ~ com.twin.app.shoptime/src/actions/panelActions.js ~ com.twin.app.shoptime/src/reducers/panelReducer.js ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • 소규모 기능 개선 • 모듈 구조 개선
This commit is contained in:
@@ -99,17 +99,25 @@ export const finishMediaPreview = () => (dispatch, getState) => {
|
|||||||
export const finishModalMediaForce = () => (dispatch, getState) => {
|
export const finishModalMediaForce = () => (dispatch, getState) => {
|
||||||
const panels = getState().panels.panels;
|
const panels = getState().panels.panels;
|
||||||
|
|
||||||
|
console.log('[🟡UNIQUE_DETAIL_CLEANUP🟡] finishModalMediaForce called', {
|
||||||
|
panelCount: panels.length,
|
||||||
|
panelNames: panels.map((p) => p.name),
|
||||||
|
});
|
||||||
|
|
||||||
const hasProductVideoPanel = panels.some(
|
const hasProductVideoPanel = panels.some(
|
||||||
(panel) =>
|
(panel) =>
|
||||||
panel.name === panel_names.MEDIA_PANEL &&
|
panel.name === panel_names.MEDIA_PANEL &&
|
||||||
(panel.panelInfo?.modal || panel.panelInfo?.modalContainerId === 'product-video-player')
|
(panel.panelInfo?.modal || panel.panelInfo?.modalContainerId === 'product-video-player')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log('[🟡UNIQUE_DETAIL_CLEANUP🟡] hasProductVideoPanel:', hasProductVideoPanel);
|
||||||
|
|
||||||
if (hasProductVideoPanel) {
|
if (hasProductVideoPanel) {
|
||||||
if (startMediaFocusTimer) {
|
if (startMediaFocusTimer) {
|
||||||
clearTimeout(startMediaFocusTimer);
|
clearTimeout(startMediaFocusTimer);
|
||||||
startMediaFocusTimer = null;
|
startMediaFocusTimer = null;
|
||||||
}
|
}
|
||||||
|
console.log('[🟡UNIQUE_DETAIL_CLEANUP🟡] Calling popPanel(panel_names.MEDIA_PANEL)');
|
||||||
dispatch(popPanel(panel_names.MEDIA_PANEL));
|
dispatch(popPanel(panel_names.MEDIA_PANEL));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,12 +40,20 @@ export const pushPanel = (panel, duplicatable = false) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const popPanel = (panelName) => {
|
export const popPanel = (panelName) => {
|
||||||
|
const stack = new Error().stack;
|
||||||
|
const stackLines = stack?.split('\n') || [];
|
||||||
|
|
||||||
|
console.log('[💜UNIQUE_PANEL_STACK💜] popPanel action dispatcher - REMOVING PANEL:', {
|
||||||
|
panelName,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
fullStack: stackLines.slice(1, 6).map((line) => line.trim()),
|
||||||
|
});
|
||||||
|
|
||||||
if (DEBUG_MODE) {
|
if (DEBUG_MODE) {
|
||||||
console.log('[PANEL-TRACE] popPanel action creator', {
|
console.log('[💜UNIQUE_PANEL_STACK💜] popPanel action creator stack:', {
|
||||||
panelName,
|
panelName,
|
||||||
caller: new Error().stack?.split('\n')[2]?.trim(),
|
caller: stackLines[2]?.trim(),
|
||||||
});
|
});
|
||||||
console.trace('[PANEL-TRACE] popPanel stack trace');
|
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
type: types.POP_PANEL,
|
type: types.POP_PANEL,
|
||||||
|
|||||||
@@ -94,6 +94,12 @@ export const panelsReducer = (state = initialState, action) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case types.POP_PANEL: {
|
case types.POP_PANEL: {
|
||||||
|
console.log('[💜UNIQUE_PANEL_STACK💜] POP_PANEL reducer START', {
|
||||||
|
targetPanel: action.payload || 'last_panel',
|
||||||
|
currentPanels: state.panels.map((p) => p.name),
|
||||||
|
timestamp: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
dlog('[panelReducer] 🔴 POP_PANEL START', {
|
dlog('[panelReducer] 🔴 POP_PANEL START', {
|
||||||
targetPanel: action.payload || 'last_panel',
|
targetPanel: action.payload || 'last_panel',
|
||||||
currentPanels: state.panels.map((p) => p.name),
|
currentPanels: state.panels.map((p) => p.name),
|
||||||
@@ -118,6 +124,13 @@ export const panelsReducer = (state = initialState, action) => {
|
|||||||
resultPanels = state.panels.slice(0, state.panels.length - 1);
|
resultPanels = state.panels.slice(0, state.panels.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[💜UNIQUE_PANEL_STACK💜] POP_PANEL reducer END', {
|
||||||
|
resultPanels: resultPanels.map((p) => p.name),
|
||||||
|
panelCount: resultPanels.length,
|
||||||
|
lastAction,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
dlog('[panelReducer] 🔴 POP_PANEL END', {
|
dlog('[panelReducer] 🔴 POP_PANEL END', {
|
||||||
resultPanels: resultPanels.map((p) => p.name),
|
resultPanels: resultPanels.map((p) => p.name),
|
||||||
lastAction,
|
lastAction,
|
||||||
|
|||||||
@@ -280,6 +280,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
console.log('[🟡UNIQUE_DETAIL_CLEANUP🟡] DetailPanel cleanup - calling finishModalMediaForce');
|
||||||
dispatch(finishModalMediaForce());
|
dispatch(finishModalMediaForce());
|
||||||
};
|
};
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
@@ -303,16 +304,15 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
const sourcePanel = panelInfo?.sourcePanel;
|
const sourcePanel = panelInfo?.sourcePanel;
|
||||||
const sourceMenu = panelInfo?.sourceMenu;
|
const sourceMenu = panelInfo?.sourceMenu;
|
||||||
|
|
||||||
console.log('[DP-TRACE] Detail unmount start', {
|
console.log('[🔴UNIQUE_DETAIL_UNMOUNT🔴] DetailPanel cleanup/unmount triggered', {
|
||||||
sourcePanel,
|
sourcePanel,
|
||||||
sourceMenu,
|
sourceMenu,
|
||||||
panelsSnapshot: panels.map((p) => p.name),
|
panelsSnapshot: panels.map((p) => p.name),
|
||||||
|
timestamp: Date.now(),
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('[Detail-BG] 306-line sourcePanel:', sourcePanel, 'sourceMenu:', sourceMenu);
|
|
||||||
|
|
||||||
// DetailPanel이 unmount되는 시점
|
// DetailPanel이 unmount되는 시점
|
||||||
console.log('[DetailPanel] unmount:', {
|
console.log('[🔴UNIQUE_DETAIL_UNMOUNT🔴] DetailPanel unmount details:', {
|
||||||
sourcePanel,
|
sourcePanel,
|
||||||
sourceMenu,
|
sourceMenu,
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
@@ -385,6 +385,14 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
const sourcePanel = panelInfo?.sourcePanel;
|
const sourcePanel = panelInfo?.sourcePanel;
|
||||||
const sourceMenu = panelInfo?.sourceMenu;
|
const sourceMenu = panelInfo?.sourceMenu;
|
||||||
|
|
||||||
|
console.log('[🟠UNIQUE_DETAIL_BACK🟠] onBackClick triggered', {
|
||||||
|
sourcePanel,
|
||||||
|
sourceMenu,
|
||||||
|
isCancelClick,
|
||||||
|
currentPanels: panels.map((p) => p.name),
|
||||||
|
timestamp: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
fp.pipe(
|
fp.pipe(
|
||||||
() => {
|
() => {
|
||||||
dispatch(clearAllToasts()); // BuyOption Toast 포함 모든 토스트 제거
|
dispatch(clearAllToasts()); // BuyOption Toast 포함 모든 토스트 제거
|
||||||
@@ -393,7 +401,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
switch (sourcePanel) {
|
switch (sourcePanel) {
|
||||||
case panel_names.PLAYER_PANEL:
|
case panel_names.PLAYER_PANEL:
|
||||||
// PlayerPanel에서 온 경우: 플레이어 비디오는 그대로 두고 모달만 정리
|
// PlayerPanel에서 온 경우: 플레이어 비디오는 그대로 두고 모달만 정리
|
||||||
console.log('[DetailPanel] onBackClick - PlayerPanel 출신: 모달 정리만 수행');
|
console.log('[🟠UNIQUE_DETAIL_BACK🟠] PlayerPanel 출신: 모달 정리만 수행');
|
||||||
dispatch(finishModalMediaForce()); // MEDIA_PANEL(ProductVideo) 강제 종료
|
dispatch(finishModalMediaForce()); // MEDIA_PANEL(ProductVideo) 강제 종료
|
||||||
dispatch(finishVideoPreview());
|
dispatch(finishVideoPreview());
|
||||||
break;
|
break;
|
||||||
@@ -403,7 +411,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
default:
|
default:
|
||||||
// HomePanel, SearchPanel 등에서 온 경우: 백그라운드 비디오 일시 중지
|
// HomePanel, SearchPanel 등에서 온 경우: 백그라운드 비디오 일시 중지
|
||||||
console.log(
|
console.log(
|
||||||
'[DetailPanel] onBackClick - source panel:',
|
'[🟠UNIQUE_DETAIL_BACK🟠] source panel:',
|
||||||
sourcePanel,
|
sourcePanel,
|
||||||
'백그라운드 비디오 일시 중지'
|
'백그라운드 비디오 일시 중지'
|
||||||
);
|
);
|
||||||
@@ -413,6 +421,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[🟠UNIQUE_DETAIL_BACK🟠] Calling popPanel(DETAIL_PANEL)');
|
||||||
dispatch(popPanel(panel_names.DETAIL_PANEL));
|
dispatch(popPanel(panel_names.DETAIL_PANEL));
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
|||||||
@@ -391,6 +391,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
const onEnded = useCallback(
|
const onEnded = useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
debugLog('[MediaPanel] Video ended');
|
debugLog('[MediaPanel] Video ended');
|
||||||
|
console.log('[🔥UNIQUE_MEDIA_ENDED🔥] MediaPanel onEnded triggered - will pop after 1500ms');
|
||||||
// continuousPlay는 MediaPlayer(VideoPlayer) 컴포넌트 내부에서 loop 속성으로 처리
|
// continuousPlay는 MediaPlayer(VideoPlayer) 컴포넌트 내부에서 loop 속성으로 처리
|
||||||
// onEnded가 호출되면 loop=false 인 경우이므로 패널을 닫음
|
// onEnded가 호출되면 loop=false 인 경우이므로 패널을 닫음
|
||||||
Spotlight.pause();
|
Spotlight.pause();
|
||||||
@@ -402,6 +403,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
|
|
||||||
// ✅ 새로운 타이머 저장 (cleanup 시 정리용)
|
// ✅ 새로운 타이머 저장 (cleanup 시 정리용)
|
||||||
onEndedTimerRef.current = setTimeout(() => {
|
onEndedTimerRef.current = setTimeout(() => {
|
||||||
|
console.log('[🔥UNIQUE_MEDIA_ENDED🔥] Executing popPanel(MEDIA_PANEL) after 1500ms');
|
||||||
Spotlight.resume();
|
Spotlight.resume();
|
||||||
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL));
|
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL));
|
||||||
onEndedTimerRef.current = null;
|
onEndedTimerRef.current = null;
|
||||||
|
|||||||
@@ -912,7 +912,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!panelInfo.modal) {
|
if (!panelInfo.modal) {
|
||||||
dispatch(PanelActions.popPanel());
|
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL));
|
||||||
dispatch(changeAppStatus({ cursorVisible: false }));
|
dispatch(changeAppStatus({ cursorVisible: false }));
|
||||||
document?.dispatchEvent?.(new CustomEvent('detailpanel-scroll-reset'));
|
document?.dispatchEvent?.(new CustomEvent('detailpanel-scroll-reset'));
|
||||||
|
|
||||||
@@ -937,7 +937,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
// 패널이 2개 존재할때만 popPanel 진행
|
// 패널이 2개 존재할때만 popPanel 진행
|
||||||
// fullscreen 전환 중이면 popPanel하지 않음
|
// fullscreen 전환 중이면 popPanel하지 않음
|
||||||
if (panelInfo.modal && !isOnTop && !isTransitioningToFullscreen.current) {
|
if (panelInfo.modal && !isOnTop && !isTransitioningToFullscreen.current) {
|
||||||
dispatch(PanelActions.popPanel());
|
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL));
|
||||||
} else {
|
} else {
|
||||||
Spotlight.focus('tbody');
|
Spotlight.focus('tbody');
|
||||||
}
|
}
|
||||||
@@ -1576,7 +1576,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
) {
|
) {
|
||||||
// case: Featured Brands
|
// case: Featured Brands
|
||||||
if (panelInfo?.sourcePanel === panel_names.FEATURED_BRANDS_PANEL) {
|
if (panelInfo?.sourcePanel === panel_names.FEATURED_BRANDS_PANEL) {
|
||||||
dispatch(PanelActions.popPanel());
|
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
@@ -2043,19 +2043,25 @@ const MediaPanel = React.forwardRef(
|
|||||||
(e) => {
|
(e) => {
|
||||||
const currentInfo = panelInfoRef.current;
|
const currentInfo = panelInfoRef.current;
|
||||||
|
|
||||||
|
console.log('[🔥UNIQUE_MEDIA_ENDED🔥] onEnded triggered - shptmBanrTpNm:', currentInfo?.shptmBanrTpNm);
|
||||||
|
|
||||||
// MEDIA: 기존 동작 유지 (배경 복원 없이 즉시 pop)
|
// MEDIA: 기존 동작 유지 (배경 복원 없이 즉시 pop)
|
||||||
if (currentInfo.shptmBanrTpNm === 'MEDIA') {
|
if (currentInfo.shptmBanrTpNm === 'MEDIA') {
|
||||||
console.log('[MediaPanel] 🚫 Skipping background restoration for ended media');
|
console.log('[🔥UNIQUE_MEDIA_ENDED🔥] MEDIA type - popPanel will be called');
|
||||||
Spotlight.pause();
|
Spotlight.pause();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
console.log('[🔥UNIQUE_MEDIA_ENDED🔥] setTimeout fired - dispatching popPanel(MEDIA_PANEL)');
|
||||||
Spotlight.resume();
|
Spotlight.resume();
|
||||||
dispatch(PanelActions.popPanel());
|
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL));
|
||||||
}, VIDEO_END_ACTION_DELAY);
|
}, VIDEO_END_ACTION_DELAY);
|
||||||
|
e?.stopPropagation();
|
||||||
|
e?.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// VOD: modal 여부에 따라 동작 분리
|
// VOD: modal 여부에 따라 동작 분리
|
||||||
if (currentInfo.shptmBanrTpNm === 'VOD') {
|
if (currentInfo.shptmBanrTpNm === 'VOD') {
|
||||||
|
console.log('[🔥UNIQUE_MEDIA_ENDED🔥] VOD type - popPanel will be called');
|
||||||
Spotlight.pause();
|
Spotlight.pause();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
stopExternalPlayer();
|
stopExternalPlayer();
|
||||||
@@ -2074,6 +2080,8 @@ const MediaPanel = React.forwardRef(
|
|||||||
e?.preventDefault();
|
e?.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[🔥UNIQUE_MEDIA_ENDED🔥] Unknown shptmBanrTpNm - no action taken');
|
||||||
},
|
},
|
||||||
[dispatch, focusBackButtonOrFallback, stopExternalPlayer]
|
[dispatch, focusBackButtonOrFallback, stopExternalPlayer]
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user