[251012] fix: DetailPanel Background Video Play
🕐 커밋 시간: 2025. 10. 12. 15:20:05 📊 변경 통계: • 총 파일: 8개 • 추가: +142줄 • 삭제: -18줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/videoPlayActions.js ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js ~ com.twin.app.shoptime/src/reducers/videoPlayReducer.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/components/DetailPanelBackground/DetailPanelBackground.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/actions/videoPlayActions.js (javascript): ✅ Added: curry() 📄 com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js (javascript): 🔄 Modified: extends() 📄 com.twin.app.shoptime/src/reducers/videoPlayReducer.js (javascript): ✅ Added: curry(), videoPlayReducer() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): 🔄 Modified: extractProductMeta() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • UI 컴포넌트 아키텍처 개선
This commit is contained in:
@@ -9,6 +9,9 @@ export const VIDEO_PLAY_ACTIONS = {
|
|||||||
SET_VIDEO_BANNER: 'SET_VIDEO_BANNER',
|
SET_VIDEO_BANNER: 'SET_VIDEO_BANNER',
|
||||||
SET_VIDEO_FULLSCREEN: 'SET_VIDEO_FULLSCREEN',
|
SET_VIDEO_FULLSCREEN: 'SET_VIDEO_FULLSCREEN',
|
||||||
SET_VIDEO_MINIMIZED: 'SET_VIDEO_MINIMIZED',
|
SET_VIDEO_MINIMIZED: 'SET_VIDEO_MINIMIZED',
|
||||||
|
HIDE_PLAYER_OVERLAYS: 'HIDE_PLAYER_OVERLAYS',
|
||||||
|
SHOW_PLAYER_OVERLAYS: 'SHOW_PLAYER_OVERLAYS',
|
||||||
|
RESET_PLAYER_OVERLAYS: 'RESET_PLAYER_OVERLAYS',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Video Play States
|
// Video Play States
|
||||||
@@ -92,3 +95,24 @@ export const setVideoMinimized = curry((videoInfo) => ({
|
|||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PlayerPanel 오버레이를 숨김 (DetailPanel 진입 시)
|
||||||
|
*/
|
||||||
|
export const hidePlayerOverlays = () => ({
|
||||||
|
type: VIDEO_PLAY_ACTIONS.HIDE_PLAYER_OVERLAYS,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PlayerPanel 오버레이를 표시 (DetailPanel에서 복귀 시)
|
||||||
|
*/
|
||||||
|
export const showPlayerOverlays = () => ({
|
||||||
|
type: VIDEO_PLAY_ACTIONS.SHOW_PLAYER_OVERLAYS,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 오버레이 상태를 리셋
|
||||||
|
*/
|
||||||
|
export const resetPlayerOverlays = () => ({
|
||||||
|
type: VIDEO_PLAY_ACTIONS.RESET_PLAYER_OVERLAYS,
|
||||||
|
});
|
||||||
|
|||||||
@@ -2582,6 +2582,7 @@ const VideoPlayer = ApiDecorator(
|
|||||||
'showControls',
|
'showControls',
|
||||||
'showFeedback',
|
'showFeedback',
|
||||||
'toggleControls',
|
'toggleControls',
|
||||||
|
'onVideoClick',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
I18nContextDecorator(
|
I18nContextDecorator(
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ const initialState = {
|
|||||||
state: VIDEO_STATES.STOPPED, // 'stopped', 'banner', 'fullscreen', 'minimized'
|
state: VIDEO_STATES.STOPPED, // 'stopped', 'banner', 'fullscreen', 'minimized'
|
||||||
videoInfo: {}, // 비디오 관련 정보 (showUrl, thumbnail, modalContainerId 등)
|
videoInfo: {}, // 비디오 관련 정보 (showUrl, thumbnail, modalContainerId 등)
|
||||||
timestamp: null, // 마지막 상태 변경 시간
|
timestamp: null, // 마지막 상태 변경 시간
|
||||||
|
shouldHideOverlays: false, // 오버레이 숨김 플래그
|
||||||
|
shouldShowOverlays: false, // 오버레이 표시 플래그
|
||||||
};
|
};
|
||||||
|
|
||||||
// FP handlers (curried) with immutable updates only
|
// FP handlers (curried) with immutable updates only
|
||||||
@@ -53,15 +55,30 @@ const handleSetVideoMinimized = curry((state, action) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const handleHidePlayerOverlays = curry((state) => {
|
||||||
|
return set('shouldHideOverlays', true, set('shouldShowOverlays', false, state));
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleShowPlayerOverlays = curry((state) => {
|
||||||
|
return set('shouldShowOverlays', true, set('shouldHideOverlays', false, state));
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleResetPlayerOverlays = curry((state) => {
|
||||||
|
return set('shouldHideOverlays', false, set('shouldShowOverlays', false, state));
|
||||||
|
});
|
||||||
|
|
||||||
const handlers = {
|
const handlers = {
|
||||||
[VIDEO_PLAY_ACTIONS.UPDATE_VIDEO_STATE]: handleUpdateVideoState,
|
[VIDEO_PLAY_ACTIONS.UPDATE_VIDEO_STATE]: handleUpdateVideoState,
|
||||||
[VIDEO_PLAY_ACTIONS.SET_VIDEO_STOPPED]: handleSetVideoStopped,
|
[VIDEO_PLAY_ACTIONS.SET_VIDEO_STOPPED]: handleSetVideoStopped,
|
||||||
[VIDEO_PLAY_ACTIONS.SET_VIDEO_BANNER]: handleSetVideoBanner,
|
[VIDEO_PLAY_ACTIONS.SET_VIDEO_BANNER]: handleSetVideoBanner,
|
||||||
[VIDEO_PLAY_ACTIONS.SET_VIDEO_FULLSCREEN]: handleSetVideoFullscreen,
|
[VIDEO_PLAY_ACTIONS.SET_VIDEO_FULLSCREEN]: handleSetVideoFullscreen,
|
||||||
[VIDEO_PLAY_ACTIONS.SET_VIDEO_MINIMIZED]: handleSetVideoMinimized,
|
[VIDEO_PLAY_ACTIONS.SET_VIDEO_MINIMIZED]: handleSetVideoMinimized,
|
||||||
|
[VIDEO_PLAY_ACTIONS.HIDE_PLAYER_OVERLAYS]: handleHidePlayerOverlays,
|
||||||
|
[VIDEO_PLAY_ACTIONS.SHOW_PLAYER_OVERLAYS]: handleShowPlayerOverlays,
|
||||||
|
[VIDEO_PLAY_ACTIONS.RESET_PLAYER_OVERLAYS]: handleResetPlayerOverlays,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function videoPlayReducer(state = initialState, action = {}) {
|
export function videoPlayReducer(state = initialState, action = {}) {
|
||||||
const type = get('type', action);
|
const type = get('type', action);
|
||||||
const handler = handlers[type];
|
const handler = handlers[type];
|
||||||
return handler ? handler(state, action) : state;
|
return handler ? handler(state, action) : state;
|
||||||
|
|||||||
@@ -69,6 +69,11 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
[panelInfo]
|
[panelInfo]
|
||||||
);
|
);
|
||||||
const panelBgImgNo = useMemo(() => fp.pipe(() => panelInfo, fp.get('bgImgNo'))(), [panelInfo]);
|
const panelBgImgNo = useMemo(() => fp.pipe(() => panelInfo, fp.get('bgImgNo'))(), [panelInfo]);
|
||||||
|
// PlayerPanel에서 진입했는지 여부를 panelInfo에서 추출
|
||||||
|
const panelLaunchedFromPlayer = useMemo(
|
||||||
|
() => fp.pipe(() => panelInfo, fp.get('launchedFromPlayer'))(),
|
||||||
|
[panelInfo]
|
||||||
|
);
|
||||||
const productPmtSuptYn = useMemo(
|
const productPmtSuptYn = useMemo(
|
||||||
() => fp.pipe(() => productData, fp.get('pmtSuptYn'))(),
|
() => fp.pipe(() => productData, fp.get('pmtSuptYn'))(),
|
||||||
[productData]
|
[productData]
|
||||||
@@ -142,6 +147,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// PlayerPanel의 isOnTop useEffect가 자동으로 오버레이 표시
|
||||||
}
|
}
|
||||||
)();
|
)();
|
||||||
|
|
||||||
@@ -603,7 +609,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
}, [imageUrl]);
|
}, [imageUrl]);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
console.log('productDataSource :', productDataSource);
|
// console.log('productDataSource :', productDataSource);
|
||||||
|
|
||||||
// 언마운트 시 인덱스 초기화가 필요하면:
|
// 언마운트 시 인덱스 초기화가 필요하면:
|
||||||
// useEffect(() => () => setSelectedIndex(0), [])
|
// useEffect(() => () => setSelectedIndex(0), [])
|
||||||
@@ -620,7 +626,8 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
return (
|
return (
|
||||||
<div ref={containerRef}>
|
<div ref={containerRef}>
|
||||||
{/* 배경 이미지 및 그라데이션 컴포넌트 - 모든 콘텐츠 뒤에 렌더링 */}
|
{/* 배경 이미지 및 그라데이션 컴포넌트 - 모든 콘텐츠 뒤에 렌더링 */}
|
||||||
<DetailPanelBackground />
|
{/* launchedFromPlayer: PlayerPanel에서 진입 시 true, 다른 패널에서 진입 시 false/undefined */}
|
||||||
|
<DetailPanelBackground launchedFromPlayer={panelLaunchedFromPlayer} />
|
||||||
|
|
||||||
<TPanel
|
<TPanel
|
||||||
isTabActivated={false}
|
isTabActivated={false}
|
||||||
|
|||||||
@@ -462,7 +462,9 @@ export default function ProductAllSection({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleButtonFocus = useCallback((buttonType) => {
|
const handleButtonFocus = useCallback((buttonType) => {
|
||||||
setActiveButton(buttonType);
|
if (activeButton !== buttonType) {
|
||||||
|
setActiveButton(buttonType);
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleButtonBlur = useCallback(() => {
|
const handleButtonBlur = useCallback(() => {
|
||||||
|
|||||||
@@ -6,23 +6,31 @@ import detailPanelBg from '../../../../../assets/images/detailpanel/detailpanel-
|
|||||||
/**
|
/**
|
||||||
* DetailPanel의 배경 이미지와 그라데이션을 렌더링하는 컴포넌트
|
* DetailPanel의 배경 이미지와 그라데이션을 렌더링하는 컴포넌트
|
||||||
* CSS 변수 대신 실제 DOM 요소로 구현하여 webOS TV 호환성 확보
|
* CSS 변수 대신 실제 DOM 요소로 구현하여 webOS TV 호환성 확보
|
||||||
|
*
|
||||||
|
* @param {boolean} launchedFromPlayer - PlayerPanel에서 진입했는지 여부
|
||||||
|
* - true: PlayerPanel의 MEDIA 재생 완료 후 진입 (updatePanel로 전달됨)
|
||||||
|
* - false/undefined: 다른 패널(Shop Now, You May Like 등)에서 진입
|
||||||
|
* - 이 값에 따라 배경 UI를 다르게 표시할 수 있음
|
||||||
*/
|
*/
|
||||||
export default function DetailPanelBackground() {
|
export default function DetailPanelBackground({ launchedFromPlayer = false }) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('[DetailPanelBackground] 배경 이미지 경로:', detailPanelBg);
|
console.log('[DetailPanelBackground] 배경 이미지 경로:', detailPanelBg);
|
||||||
}, []);
|
console.log('[DetailPanelBackground] launchedFromPlayer:', launchedFromPlayer);
|
||||||
|
}, [launchedFromPlayer]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={css.backgroundContainer}>
|
<div className={css.backgroundContainer}>
|
||||||
{/* 실제 배경 이미지 */}
|
{/* 실제 배경 이미지 */}
|
||||||
{/* <img
|
{!launchedFromPlayer && (
|
||||||
src={detailPanelBg}
|
<img
|
||||||
alt=""
|
src={detailPanelBg}
|
||||||
className={css.backgroundImage}
|
alt=""
|
||||||
aria-hidden="true"
|
className={css.backgroundImage}
|
||||||
onLoad={() => console.log('[DetailPanelBackground] 이미지 로드 완료')}
|
aria-hidden="true"
|
||||||
onError={(e) => console.error('[DetailPanelBackground] 이미지 로드 실패:', e)}
|
onLoad={() => console.log('[DetailPanelBackground] 이미지 로드 완료')}
|
||||||
/> */}
|
onError={(e) => console.error('[DetailPanelBackground] 이미지 로드 실패:', e)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 그라데이션 레이어들 - CSS의 linear-gradient를 div로 구현 */}
|
{/* 그라데이션 레이어들 - CSS의 linear-gradient를 div로 구현 */}
|
||||||
{/* 1. 270도 방향 그라데이션 (왼쪽→오른쪽, 투명→불투명) */}
|
{/* 1. 270도 방향 그라데이션 (왼쪽→오른쪽, 투명→불투명) */}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {
|
|||||||
pauseModalVideo,
|
pauseModalVideo,
|
||||||
resumeModalVideo,
|
resumeModalVideo,
|
||||||
} from '../../actions/playActions';
|
} from '../../actions/playActions';
|
||||||
|
import { resetPlayerOverlays } from '../../actions/videoPlayActions';
|
||||||
import { convertUtcToLocal } from '../../components/MediaPlayer/util';
|
import { convertUtcToLocal } from '../../components/MediaPlayer/util';
|
||||||
import TPanel from '../../components/TPanel/TPanel';
|
import TPanel from '../../components/TPanel/TPanel';
|
||||||
import TPopUp from '../../components/TPopUp/TPopUp';
|
import TPopUp from '../../components/TPopUp/TPopUp';
|
||||||
@@ -212,6 +213,14 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
|||||||
|
|
||||||
const panels = USE_SELECTOR('panels', (state) => state.panels.panels);
|
const panels = USE_SELECTOR('panels', (state) => state.panels.panels);
|
||||||
const chatData = USE_SELECTOR('chatData', (state) => state.play.chatData);
|
const chatData = USE_SELECTOR('chatData', (state) => state.play.chatData);
|
||||||
|
const shouldHideOverlays = USE_SELECTOR(
|
||||||
|
'shouldHideOverlays',
|
||||||
|
(state) => state.videoPlay.shouldHideOverlays
|
||||||
|
);
|
||||||
|
const shouldShowOverlays = USE_SELECTOR(
|
||||||
|
'shouldShowOverlays',
|
||||||
|
(state) => state.videoPlay.shouldShowOverlays
|
||||||
|
);
|
||||||
|
|
||||||
const popupVisible = USE_SELECTOR('popupVisible', (state) => state.common.popup.popupVisible);
|
const popupVisible = USE_SELECTOR('popupVisible', (state) => state.common.popup.popupVisible);
|
||||||
const activePopup = USE_SELECTOR('activePopup', (state) => state.common.popup.activePopup);
|
const activePopup = USE_SELECTOR('activePopup', (state) => state.common.popup.activePopup);
|
||||||
@@ -981,10 +990,22 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
|||||||
panelInfo.shptmBanrTpNm,
|
panelInfo.shptmBanrTpNm,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// 최상단 패널 정보 (여러 useMemo에서 공통으로 사용)
|
||||||
|
const topPanel = useMemo(() => {
|
||||||
|
return panels[panels.length - 1];
|
||||||
|
}, [panels]);
|
||||||
|
|
||||||
|
// 최상단 패널이 DetailPanel이고 PlayerPanel에서 진입했는지 확인
|
||||||
|
const isTopPanelDetailFromPlayer = useMemo(() => {
|
||||||
|
return (
|
||||||
|
topPanel?.name === panel_names.DETAIL_PANEL &&
|
||||||
|
topPanel?.panelInfo?.launchedFromPlayer === true
|
||||||
|
);
|
||||||
|
}, [topPanel]);
|
||||||
|
|
||||||
const cannotPlay = useMemo(() => {
|
const cannotPlay = useMemo(() => {
|
||||||
const topPanel = panels[panels.length - 1];
|
|
||||||
return !isOnTop && topPanel?.name === panel_names.PLAYER_PANEL;
|
return !isOnTop && topPanel?.name === panel_names.PLAYER_PANEL;
|
||||||
}, [panels, isOnTop]);
|
}, [topPanel, isOnTop]);
|
||||||
|
|
||||||
const getPlayer = useCallback((ref) => {
|
const getPlayer = useCallback((ref) => {
|
||||||
videoPlayer.current = ref;
|
videoPlayer.current = ref;
|
||||||
@@ -1886,12 +1907,48 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
|||||||
}, timeout);
|
}, timeout);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Redux로 오버레이 숨김
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOnTop && !panelInfo.modal && !videoVerticalVisible) {
|
if (shouldHideOverlays) {
|
||||||
|
console.log('[PlayerPanel] shouldHideOverlays true - 오버레이 숨김');
|
||||||
|
setSideContentsVisible(false);
|
||||||
|
setBelowContentsVisible(false);
|
||||||
|
|
||||||
|
if (videoPlayer.current?.hideControls) {
|
||||||
|
videoPlayer.current.hideControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(resetPlayerOverlays());
|
||||||
|
}
|
||||||
|
}, [shouldHideOverlays, dispatch]);
|
||||||
|
|
||||||
|
// Redux로 오버레이 표시
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldShowOverlays) {
|
||||||
|
console.log('[PlayerPanel] shouldShowOverlays true - 오버레이 표시');
|
||||||
setSideContentsVisible(true);
|
setSideContentsVisible(true);
|
||||||
setBelowContentsVisible(true);
|
setBelowContentsVisible(true);
|
||||||
|
|
||||||
|
if (videoPlayer.current?.showControls) {
|
||||||
|
videoPlayer.current.showControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(resetPlayerOverlays());
|
||||||
}
|
}
|
||||||
}, [panelInfo.modal]);
|
}, [shouldShowOverlays, dispatch]);
|
||||||
|
|
||||||
|
// PlayerPanel이 최상단이 될 때 오버레이 표시 (DetailPanel에서 복귀)
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOnTop && !panelInfo.modal && !videoVerticalVisible) {
|
||||||
|
console.log('[PlayerPanel] isOnTop true - 오버레이 표시');
|
||||||
|
setSideContentsVisible(true);
|
||||||
|
setBelowContentsVisible(true);
|
||||||
|
|
||||||
|
if (videoPlayer.current?.showControls) {
|
||||||
|
videoPlayer.current.showControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [isOnTop, panelInfo.modal, videoVerticalVisible]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// tabContainerVersion === 1일 때만 실행
|
// tabContainerVersion === 1일 때만 실행
|
||||||
@@ -2081,7 +2138,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
|
|||||||
className={classNames(
|
className={classNames(
|
||||||
css.videoContainer,
|
css.videoContainer,
|
||||||
panelInfo.modal && css.modal,
|
panelInfo.modal && css.modal,
|
||||||
!isOnTop && css.background,
|
// PlayerPanel이 최상단 아니고, 최상단이 DetailPanel(from Player)이면 비디오 보이도록
|
||||||
|
!isOnTop && isTopPanelDetailFromPlayer && css['background-visible'],
|
||||||
|
// PlayerPanel이 최상단 아니고, 위 조건 아니면 1px로 숨김
|
||||||
|
!isOnTop && !isTopPanelDetailFromPlayer && css.background,
|
||||||
!captionEnable && css.hideSubtitle
|
!captionEnable && css.hideSubtitle
|
||||||
)}
|
)}
|
||||||
handleCancel={onClickBack}
|
handleCancel={onClickBack}
|
||||||
|
|||||||
@@ -1,59 +1,36 @@
|
|||||||
import React, {
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
|
|
||||||
import {
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
useDispatch,
|
|
||||||
useSelector,
|
|
||||||
} from 'react-redux';
|
|
||||||
|
|
||||||
import { Job } from '@enact/core/util';
|
import { Job } from '@enact/core/util';
|
||||||
import SpotlightContainerDecorator
|
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
|
||||||
from '@enact/spotlight/SpotlightContainerDecorator';
|
import { getContainerNode, setContainerLastFocusedElement } from '@enact/spotlight/src/container';
|
||||||
import {
|
|
||||||
getContainerNode,
|
|
||||||
setContainerLastFocusedElement,
|
|
||||||
} from '@enact/spotlight/src/container';
|
|
||||||
|
|
||||||
import { sendLogTotalRecommend } from '../../../../actions/logActions';
|
import { sendLogTotalRecommend } from '../../../../actions/logActions';
|
||||||
import { pushPanel } from '../../../../actions/panelActions';
|
import { pushPanel } from '../../../../actions/panelActions';
|
||||||
|
import { hidePlayerOverlays } from '../../../../actions/videoPlayActions';
|
||||||
import TItemCard, { TYPES } from '../../../../components/TItemCard/TItemCard';
|
import TItemCard, { TYPES } from '../../../../components/TItemCard/TItemCard';
|
||||||
import TVirtualGridList
|
import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList';
|
||||||
from '../../../../components/TVirtualGridList/TVirtualGridList';
|
|
||||||
import useScrollTo from '../../../../hooks/useScrollTo';
|
import useScrollTo from '../../../../hooks/useScrollTo';
|
||||||
import {
|
import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../../../utils/Config';
|
||||||
LOG_CONTEXT_NAME,
|
|
||||||
LOG_MENU,
|
|
||||||
LOG_MESSAGE_ID,
|
|
||||||
panel_names,
|
|
||||||
} from '../../../../utils/Config';
|
|
||||||
import { scaleH } from '../../../../utils/helperMethods';
|
import { scaleH } from '../../../../utils/helperMethods';
|
||||||
import ListEmptyContents
|
import ListEmptyContents from '../TabContents/ListEmptyContents/ListEmptyContents';
|
||||||
from '../TabContents/ListEmptyContents/ListEmptyContents';
|
|
||||||
import css1 from './ShopNowContents.module.less';
|
import css1 from './ShopNowContents.module.less';
|
||||||
import cssV2 from './ShopNowContents.v2.module.less';
|
import cssV2 from './ShopNowContents.v2.module.less';
|
||||||
|
|
||||||
const extractPriceInfo = (priceInfo) => {
|
const extractPriceInfo = (priceInfo) => {
|
||||||
if (!priceInfo)
|
if (!priceInfo) return { originalPrice: '', discountedPrice: '', discountRate: '' };
|
||||||
return { originalPrice: "", discountedPrice: "", discountRate: "" };
|
|
||||||
|
|
||||||
const parts = priceInfo.split("|").map((part) => part.trim());
|
const parts = priceInfo.split('|').map((part) => part.trim());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
originalPrice: parts[0] || "",
|
originalPrice: parts[0] || '',
|
||||||
discountedPrice: parts[1] || "",
|
discountedPrice: parts[1] || '',
|
||||||
discountRate: parts[4] || "",
|
discountRate: parts[4] || '',
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const Container = SpotlightContainerDecorator(
|
const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
||||||
{ enterTo: "last-focused" },
|
|
||||||
"div"
|
|
||||||
);
|
|
||||||
export default function ShopNowContents({
|
export default function ShopNowContents({
|
||||||
shopNowInfo,
|
shopNowInfo,
|
||||||
videoVerticalVisible,
|
videoVerticalVisible,
|
||||||
@@ -63,7 +40,7 @@ export default function ShopNowContents({
|
|||||||
panelInfo,
|
panelInfo,
|
||||||
tabTitle,
|
tabTitle,
|
||||||
version = 1,
|
version = 1,
|
||||||
direction = "vertical",
|
direction = 'vertical',
|
||||||
}) {
|
}) {
|
||||||
const css = version === 2 ? cssV2 : css1;
|
const css = version === 2 ? cssV2 : css1;
|
||||||
const { getScrollTo, scrollTop } = useScrollTo();
|
const { getScrollTo, scrollTop } = useScrollTo();
|
||||||
@@ -88,7 +65,7 @@ export default function ShopNowContents({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
const gridListId = "playVideoShopNowBox";
|
const gridListId = 'playVideoShopNowBox';
|
||||||
const girdList = getContainerNode(gridListId);
|
const girdList = getContainerNode(gridListId);
|
||||||
|
|
||||||
if (girdList) setContainerLastFocusedElement(null, [gridListId]);
|
if (girdList) setContainerLastFocusedElement(null, [gridListId]);
|
||||||
@@ -141,8 +118,7 @@ export default function ShopNowContents({
|
|||||||
} = shopNowInfo[index];
|
} = shopNowInfo[index];
|
||||||
|
|
||||||
// 미리 계산된 가격 정보를 사용
|
// 미리 계산된 가격 정보를 사용
|
||||||
const { originalPrice, discountedPrice, discountRate } =
|
const { originalPrice, discountedPrice, discountRate } = priceInfoMap[index] || {};
|
||||||
priceInfoMap[index] || {};
|
|
||||||
|
|
||||||
const handleItemClick = () => {
|
const handleItemClick = () => {
|
||||||
const params = {
|
const params = {
|
||||||
@@ -160,6 +136,9 @@ export default function ShopNowContents({
|
|||||||
};
|
};
|
||||||
dispatch(sendLogTotalRecommend(params));
|
dispatch(sendLogTotalRecommend(params));
|
||||||
|
|
||||||
|
// DetailPanel push 전에 VideoPlayer 오버레이 숨김
|
||||||
|
dispatch(hidePlayerOverlays());
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
pushPanel({
|
pushPanel({
|
||||||
name: panel_names.DETAIL_PANEL,
|
name: panel_names.DETAIL_PANEL,
|
||||||
@@ -168,7 +147,7 @@ export default function ShopNowContents({
|
|||||||
showId: playListInfo?.showId,
|
showId: playListInfo?.showId,
|
||||||
liveFlag: playListInfo?.liveFlag,
|
liveFlag: playListInfo?.liveFlag,
|
||||||
thumbnailUrl: playListInfo?.thumbnailUrl,
|
thumbnailUrl: playListInfo?.thumbnailUrl,
|
||||||
liveReqFlag: panelInfo?.shptmBanrTpNm === "LIVE" && "Y",
|
liveReqFlag: panelInfo?.shptmBanrTpNm === 'LIVE' && 'Y',
|
||||||
patnrId,
|
patnrId,
|
||||||
prdtId,
|
prdtId,
|
||||||
launchedFromPlayer: true,
|
launchedFromPlayer: true,
|
||||||
@@ -221,9 +200,7 @@ export default function ShopNowContents({
|
|||||||
itemWidth={version === 2 ? 310 : videoVerticalVisible ? 540 : 600}
|
itemWidth={version === 2 ? 310 : videoVerticalVisible ? 540 : 600}
|
||||||
itemHeight={version === 2 ? 445 : 236}
|
itemHeight={version === 2 ? 445 : 236}
|
||||||
spacing={version === 2 ? 30 : 12}
|
spacing={version === 2 ? 30 : 12}
|
||||||
className={
|
className={videoVerticalVisible ? css.verticalItemList : css.itemList}
|
||||||
videoVerticalVisible ? css.verticalItemList : css.itemList
|
|
||||||
}
|
|
||||||
noScrollByWheel={false}
|
noScrollByWheel={false}
|
||||||
spotlightId="playVideoShopNowBox"
|
spotlightId="playVideoShopNowBox"
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user