🕐 커밋 시간: 2025. 11. 15. 12:22:59 📊 변경 통계: • 총 파일: 12개 • 추가: +246줄 • 삭제: -27줄 📁 추가된 파일: + com.twin.app.shoptime/src/utils/focusPanelGuide.js 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/actionTypes.js ~ 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/utils/SpotlightIds.js ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v3.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/actions/panelActions.js (javascript): ✅ Added: resetPanels() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): 🔄 Modified: extractProductMeta() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v3.jsx (javascript): 🔄 Modified: Spottable() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx (javascript): 🔄 Modified: SpotlightContainerDecorator() 📄 com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx (javascript): 🔄 Modified: normalizeModalStyle() 📄 com.twin.app.shoptime/src/utils/focusPanelGuide.js (javascript): ✅ Added: DetailPanel(), handleProductSelect() 🔧 주요 변경 내용: • 타입 시스템 안정성 강화 • 핵심 비즈니스 로직 개선 • 공통 유틸리티 함수 최적화
113 lines
3.3 KiB
JavaScript
113 lines
3.3 KiB
JavaScript
import { types } from './actionTypes';
|
|
import Spotlight from '@enact/spotlight';
|
|
|
|
/*
|
|
name: panel_names.PLAYER_PANEL,
|
|
panelInfo: {
|
|
modal: true //only for video player
|
|
etc...
|
|
},
|
|
*/
|
|
export const pushPanel = (panel, duplicatable = false) => ({
|
|
type: types.PUSH_PANEL,
|
|
payload: panel,
|
|
duplicatable: duplicatable,
|
|
});
|
|
|
|
export const popPanel = (panelName) => ({
|
|
type: types.POP_PANEL,
|
|
payload: panelName,
|
|
});
|
|
|
|
export const updatePanel = (panelInfo) => ({
|
|
type: types.UPDATE_PANEL,
|
|
payload: panelInfo,
|
|
});
|
|
|
|
export const resetPanels = (panels) => ({
|
|
type: types.RESET_PANELS,
|
|
payload: panels,
|
|
});
|
|
|
|
/**
|
|
* [251114] 명시적 포커스 이동
|
|
* Panel의 비동기 작업(useEffect, 타이머 등)이 포커스를 탈취하는 것을 방지
|
|
* @param {string} panelName - 대상 Panel 이름
|
|
* @param {string} focusTarget - 포커스할 요소 ID
|
|
* @returns {Function} Redux thunk
|
|
*/
|
|
export const focusPanel = (panelName, focusTarget) => {
|
|
return (dispatch, getState) => {
|
|
const state = getState();
|
|
const panels = state.panels.panels;
|
|
|
|
console.log('[focusPanel] 포커스 이동 시도', {
|
|
panelName,
|
|
focusTarget,
|
|
currentPanels: panels.map((p) => p.name),
|
|
timestamp: Date.now(),
|
|
});
|
|
|
|
// 안전성 체크 1: Panel이 존재하고 최상단 또는 그 아래에 있는가?
|
|
const targetPanelIndex = panels.findIndex((p) => p.name === panelName);
|
|
const targetPanel = panels[targetPanelIndex];
|
|
const topPanel = panels[panels.length - 1];
|
|
|
|
if (!targetPanel) {
|
|
console.warn(`[focusPanel] ❌ Panel을 찾을 수 없음: ${panelName}`);
|
|
return;
|
|
}
|
|
|
|
// Panel이 최상단 또는 그 아래 레이어에 있는지 확인
|
|
// MediaPanel(최상단) 위에 다른 Modal이 있는 경우는 허용하지 않음
|
|
const panelsAboveTarget = panels.slice(targetPanelIndex + 1);
|
|
const hasBlockingModalAbove = panelsAboveTarget.some(
|
|
(panel) => panel?.panelInfo?.modal === true && panel.name !== panelName
|
|
);
|
|
|
|
if (hasBlockingModalAbove) {
|
|
const blockingModal = panelsAboveTarget.find((panel) => panel?.panelInfo?.modal === true);
|
|
console.warn(
|
|
`[focusPanel] ⚠️ 상위에 Modal이 있음. ` +
|
|
`${panelName}(${targetPanelIndex}층)에 포커스할 수 없음. ` +
|
|
`상단 Modal: ${blockingModal?.name}(${panelsAboveTarget.indexOf(blockingModal) + targetPanelIndex + 1}층)`
|
|
);
|
|
return;
|
|
}
|
|
|
|
console.log(
|
|
`[focusPanel] ✅ Panel 위치 확인: ${panelName}(${targetPanelIndex}층), ` +
|
|
`전체 Panel: ${panels.length}층`
|
|
);
|
|
|
|
// 포커스 이동
|
|
setTimeout(() => {
|
|
const element = document.getElementById(focusTarget);
|
|
|
|
if (!element) {
|
|
console.warn(`[focusPanel] ❌ 요소를 찾을 수 없음: ${focusTarget}`);
|
|
return;
|
|
}
|
|
|
|
if (element.offsetParent === null) {
|
|
console.warn(`[focusPanel] ⚠️ 요소가 숨겨져있음: ${focusTarget}`);
|
|
return;
|
|
}
|
|
|
|
// ✅ 포커스 이동
|
|
Spotlight.focus(focusTarget);
|
|
console.log(`[focusPanel] ✅ 포커스 이동 성공: ${panelName} → ${focusTarget}`);
|
|
|
|
// Reducer에 반영
|
|
dispatch({
|
|
type: types.FOCUS_PANEL,
|
|
payload: {
|
|
panelName,
|
|
focusTarget,
|
|
timestamp: Date.now(),
|
|
},
|
|
});
|
|
}, 0);
|
|
};
|
|
};
|