[251118] fix: DetailPanel노출 시 modal 비디오 제거

🕐 커밋 시간: 2025. 11. 18. 12:02:18

📊 변경 통계:
  • 총 파일: 6개
  • 추가: +82줄
  • 삭제: -4줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/App/App.js
  ~ com.twin.app.shoptime/src/actions/panelActions.js
  ~ com.twin.app.shoptime/src/actions/playActions.js
  ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx
  ~ com.twin.app.shoptime/src/views/HomePanel/HomeBanner/RandomUnit.jsx
  ~ com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx

🔧 주요 변경 내용:
  • 핵심 비즈니스 로직 개선
  • 소규모 기능 개선
  • 모듈 구조 개선
This commit is contained in:
2025-11-18 12:02:19 +09:00
parent 4778805dbf
commit 187043d9e7
6 changed files with 82 additions and 4 deletions

View File

@@ -456,6 +456,7 @@ function AppBase(props) {
// const termsFlag = useSelector((state) => state.common.termsFlag); // const termsFlag = useSelector((state) => state.common.termsFlag);
const termsData = useSelector((state) => state.home.termsData); const termsData = useSelector((state) => state.home.termsData);
// 🔽 Spotlight focus/blur 로그 (옵션)
useEffect(() => { useEffect(() => {
if (!Config.FOCUS_DEBUG) { if (!Config.FOCUS_DEBUG) {
return undefined; return undefined;

View File

@@ -1,6 +1,8 @@
import { types } from './actionTypes'; import { types } from './actionTypes';
import Spotlight from '@enact/spotlight'; import Spotlight from '@enact/spotlight';
import { getContainerId } from '@enact/spotlight/src/container';
import { panel_names } from '../utils/Config'; import { panel_names } from '../utils/Config';
import { updateHomeInfo } from './homeActions';
// 시작 메뉴 추적을 위한 상수 // 시작 메뉴 추적을 위한 상수
export const SOURCE_MENUS = { export const SOURCE_MENUS = {
@@ -67,6 +69,17 @@ export const navigateToDetail = ({
additionalInfo = {}, additionalInfo = {},
}) => { }) => {
return (dispatch, getState) => { return (dispatch, getState) => {
// 🔽 현재 포커스 정보 저장 (HomePanel 복귀 시 포커스 복원용)
const currentSpotNode = Spotlight.getCurrent();
const currentSpotId = currentSpotNode?.getAttribute('data-spotlight-id');
const currentContainerId = currentSpotNode ? getContainerId(currentSpotNode) : null;
const focusSnapshot = currentSpotId
? {
lastFocusedTargetId: currentContainerId || currentSpotId,
currentSpot: currentSpotId,
}
: {};
const panelInfo = { const panelInfo = {
patnrId, patnrId,
prdtId, prdtId,
@@ -100,6 +113,18 @@ export const navigateToDetail = ({
case SOURCE_MENUS.HOME_RANDOM_UNIT: case SOURCE_MENUS.HOME_RANDOM_UNIT:
case SOURCE_MENUS.HOME_ROLLING_UNIT: case SOURCE_MENUS.HOME_ROLLING_UNIT:
case SOURCE_MENUS.HOME_GENERAL: { case SOURCE_MENUS.HOME_GENERAL: {
// HomePanel Redux 상태에 포커스 스냅샷 저장 (Detail→Home 복귀 시 사용)
if (Object.keys(focusSnapshot).length > 0) {
dispatch(
updateHomeInfo({
name: panel_names.HOME_PANEL,
panelInfo: {
...focusSnapshot,
},
})
);
}
// 🔽 모든 HomePanel에서 DetailPanel로 이동 시 HomeBanner modal 비디오 정지 // 🔽 모든 HomePanel에서 DetailPanel로 이동 시 HomeBanner modal 비디오 정지
const state = getState(); const state = getState();
const playerPanelInfo = state.panels.panels.find( const playerPanelInfo = state.panels.panels.find(
@@ -115,6 +140,7 @@ export const navigateToDetail = ({
panelInfo: { panelInfo: {
lastSelectedProduct: { patnrId, prdtId }, lastSelectedProduct: { patnrId, prdtId },
lastActionSource: sourceMenu, lastActionSource: sourceMenu,
...focusSnapshot,
...additionalInfo, ...additionalInfo,
}, },
}) })
@@ -147,6 +173,7 @@ export const navigateToDetail = ({
videoStateToRestore, videoStateToRestore,
lastSelectedProduct: { patnrId, prdtId }, lastSelectedProduct: { patnrId, prdtId },
lastActionSource: sourceMenu, lastActionSource: sourceMenu,
...focusSnapshot,
...additionalInfo, ...additionalInfo,
}, },
}) })
@@ -163,6 +190,7 @@ export const navigateToDetail = ({
panelInfo: { panelInfo: {
lastSelectedProduct: { patnrId, prdtId }, lastSelectedProduct: { patnrId, prdtId },
lastActionSource: sourceMenu, lastActionSource: sourceMenu,
...focusSnapshot,
...additionalInfo, ...additionalInfo,
}, },
}) })
@@ -176,6 +204,7 @@ export const navigateToDetail = ({
panelInfo: { panelInfo: {
lastSelectedProduct: { patnrId, prdtId }, lastSelectedProduct: { patnrId, prdtId },
lastActionSource: sourceMenu, lastActionSource: sourceMenu,
...focusSnapshot,
...additionalInfo, ...additionalInfo,
}, },
}) })

View File

@@ -244,7 +244,7 @@ export const startVideoPlayerNew =
}; };
export const finishVideoPreview = () => (dispatch, getState) => { export const finishVideoPreview = () => (dispatch, getState) => {
console.log('@@@@@@@@@@@@@@@@@-finishVideoPreview'); console.log('###-finishVideoPreview');
const panels = getState().panels.panels; const panels = getState().panels.panels;
const topPanel = panels[panels.length - 1]; const topPanel = panels[panels.length - 1];
if (topPanel && topPanel.name === panel_names.PLAYER_PANEL && topPanel.panelInfo.modal) { if (topPanel && topPanel.name === panel_names.PLAYER_PANEL && topPanel.panelInfo.modal) {
@@ -258,7 +258,7 @@ export const finishVideoPreview = () => (dispatch, getState) => {
export const finishModalVideoForce = () => (dispatch, getState) => { export const finishModalVideoForce = () => (dispatch, getState) => {
const panels = getState().panels.panels; const panels = getState().panels.panels;
console.log('###-finishModalVideoForce');
// modal PlayerPanel이 존재하는지 확인 (스택 어디에 있든) // modal PlayerPanel이 존재하는지 확인 (스택 어디에 있든)
const hasModalPlayerPanel = panels.some( const hasModalPlayerPanel = panels.some(
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal (panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal
@@ -277,7 +277,7 @@ export const finishModalVideoForce = () => (dispatch, getState) => {
// 모든 PlayerPanel을 강제 제거 (modal과 fullscreen 모두) // 모든 PlayerPanel을 강제 제거 (modal과 fullscreen 모두)
export const finishAllVideoForce = () => (dispatch, getState) => { export const finishAllVideoForce = () => (dispatch, getState) => {
const panels = getState().panels.panels; const panels = getState().panels.panels;
console.log('###-finishAllVideoForce');
// 모든 PlayerPanel이 존재하는지 확인 (스택 어디에 있든) // 모든 PlayerPanel이 존재하는지 확인 (스택 어디에 있든)
const hasPlayerPanel = panels.some((panel) => panel.name === panel_names.PLAYER_PANEL); const hasPlayerPanel = panels.some((panel) => panel.name === panel_names.PLAYER_PANEL);
@@ -294,6 +294,7 @@ export const finishAllVideoForce = () => (dispatch, getState) => {
// 모달 비디오를 일시정지 (패널은 유지) // 모달 비디오를 일시정지 (패널은 유지)
export const pauseModalVideo = () => (dispatch, getState) => { export const pauseModalVideo = () => (dispatch, getState) => {
const panels = getState().panels.panels; const panels = getState().panels.panels;
console.log('###-pauseModalVideo');
// modal PlayerPanel 찾기 // modal PlayerPanel 찾기
const modalPlayerPanel = panels.find( const modalPlayerPanel = panels.find(

View File

@@ -768,6 +768,18 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
} }
}, [panels]); }, [panels]);
// PlayerPanel이 modal=true인 경우 비디오 미리보기 중지
useEffect(() => {
const hasPlayerPanel = panels.some(
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal === true
);
if (hasPlayerPanel) {
console.log('[DetailPanel] PlayerPanel modal=true detected - stopping video preview');
dispatch(finishVideoPreview());
}
}, [panels, dispatch]);
return ( return (
<div ref={containerRef}> <div ref={containerRef}>
<DetailPanelBackground launchedFromPlayer={panelLaunchedFromPlayer} patnrId={panelPatnrId}/> <DetailPanelBackground launchedFromPlayer={panelLaunchedFromPlayer} patnrId={panelPatnrId}/>

View File

@@ -490,6 +490,24 @@ export default function RandomUnit({
finishAndUnlock(); finishAndUnlock();
} }
// 🔖 DetailPanel로 이동하기 전에 현재 포커스 대상 저장 (HomePanel 복귀 시 복원)
if (isNavigatingToDetail) {
const currentSpot = Spotlight.getCurrent();
const lastFocusedTargetId = getContainerId(currentSpot);
if (lastFocusedTargetId) {
dispatch(
updateHomeInfo({
name: panel_names.HOME_PANEL,
panelInfo: {
lastFocusedTargetId,
currentSpot: currentSpot?.getAttribute('data-spotlight-id'),
focusedContainerId: TEMPLATE_CODE_CONF.TOP,
},
})
);
}
}
dispatch(action(linkInfo)); dispatch(action(linkInfo));
sendBannerLog(true); sendBannerLog(true);
dispatch( dispatch(

View File

@@ -139,6 +139,8 @@ const HomePanel = ({ isOnTop }) => {
const [cateNm, setCateNm] = useState(panelInfo.currentCateName ?? null); const [cateNm, setCateNm] = useState(panelInfo.currentCateName ?? null);
const { entryMenu, nowMenu } = useSelector((state) => state.common.menu); const { entryMenu, nowMenu } = useSelector((state) => state.common.menu);
const [focusedContainerId, setFocusedContainerId] = useState(panelInfo.focusedContainerId); const [focusedContainerId, setFocusedContainerId] = useState(panelInfo.focusedContainerId);
// DetailPanel 진입 시 포커스 대상 저장
const lastFocusedTargetRef = useRef(panelInfo.lastFocusedTargetId || null);
const isInitialRender = useRef(true); const isInitialRender = useRef(true);
const verticalPagenatorRef = useRef(null); const verticalPagenatorRef = useRef(null);
@@ -790,6 +792,20 @@ const HomePanel = ({ isOnTop }) => {
}) })
); );
// 🔽 DetailPanel에서 돌아온 뒤 포커스를 마지막 포커스 대상에 복원
console.log('[HomePanel] *** 🎯 Focus 복원 준비');
const targetFocusId = panelInfo.lastFocusedTargetId || lastFocusedTargetRef.current;
console.log('[HomePanel] *** 📍 targetFocusId:', targetFocusId, '(panelInfo.lastFocusedTargetId:', panelInfo.lastFocusedTargetId, ', lastFocusedTargetRef:', lastFocusedTargetRef.current, ')');
if (targetFocusId) {
console.log('[HomePanel] *** ⏰ 300ms 후 Spotlight.focus 호출 예정');
setTimeout(() => {
console.log('[HomePanel] *** 🔍 Spotlight.focus 호출:', targetFocusId);
Spotlight.focus(targetFocusId);
}, 300);
} else {
console.log('[HomePanel] *** ⚠️ targetFocusId가 없음 - Focus 복원 스킵');
}
// refs 초기화 // refs 초기화
videoPlayIntentRef.current = null; videoPlayIntentRef.current = null;
lastPlayedBannerIdRef.current = null; lastPlayedBannerIdRef.current = null;
@@ -821,6 +837,7 @@ const HomePanel = ({ isOnTop }) => {
currentCatCd: targetSpotlightCatcd, currentCatCd: targetSpotlightCatcd,
currentCateName: targetSpotlightCateNm, currentCateName: targetSpotlightCateNm,
focusedContainerId: focusedContainerIdRef.current, focusedContainerId: focusedContainerIdRef.current,
lastFocusedTargetId: lastFocusedTargetRef.current || panelInfo.lastFocusedTargetId,
}, },
}) })
); );