- shopnowIcon이미지 변경. qvc로 고정되어있었던부분 영상에 맞게 노출되도록 수정. - qvc영상일때 이미지는 border-radius먹지않도록 변경.
378 lines
12 KiB
JavaScript
378 lines
12 KiB
JavaScript
import React, { useCallback, useEffect, useMemo } from 'react';
|
||
|
||
import classNames from 'classnames';
|
||
import { useSelector } from 'react-redux';
|
||
|
||
import Spotlight from '@enact/spotlight';
|
||
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
|
||
import Spottable from '@enact/spotlight/Spottable';
|
||
|
||
// import icon_arrow_right from '../../../../../assets/images/icons';
|
||
import icon_arrow_dwon from '../../../../../assets/images/player/icon_tabcontainer_arrow_down.png';
|
||
import usePrevious from '../../../../hooks/usePrevious';
|
||
import { LOG_MENU } from '../../../../utils/Config';
|
||
import { createDebugHelpers } from '../../../../utils/debug';
|
||
import { $L } from '../../../../utils/helperMethods';
|
||
import { SpotlightIds } from '../../../../utils/SpotlightIds';
|
||
import FeaturedShowContents from '../TabContents/FeaturedShowContents';
|
||
import LiveChannelContents from '../TabContents/LiveChannelContents';
|
||
import ShopNowContents from '../TabContents/ShopNowContents';
|
||
import LiveChannelNext from './LiveChannelNext';
|
||
import ShopNowButton from './ShopNowButton';
|
||
import css from './TabContainer.v2.module.less';
|
||
|
||
// 디버그 헬퍼 설정
|
||
const DEBUG_MODE = false;
|
||
const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE);
|
||
|
||
const Container = SpotlightContainerDecorator(
|
||
{ enterTo: 'last-focused' },
|
||
'div'
|
||
);
|
||
|
||
const SpottableDiv = Spottable('div');
|
||
|
||
export default function TabContainerV2({
|
||
panelInfo,
|
||
playListInfo,
|
||
shopNowInfo,
|
||
selectedIndex,
|
||
setSelectedIndex,
|
||
liveChannelInfos,
|
||
videoVerticalVisible,
|
||
handleItemFocus,
|
||
prevChannelIndex,
|
||
currentTime,
|
||
spotlightId,
|
||
tabIndex = 1, // tabIndex prop으로 제어 (0: ShopNow, 1: LiveChannel, 2: ShopNowButton)
|
||
onShopNowButtonClick,
|
||
onLiveChannelButtonClick,
|
||
onLiveNext,
|
||
onTabClose, // 탭 닫기 콜백 함수
|
||
tabVisible,
|
||
}) {
|
||
const youmaylikeInfos = useSelector((state) => state.main.youmaylikeInfos);
|
||
|
||
// 다음 재생 가능한 쇼 찾기
|
||
const findNextPlayableShow = useCallback((currentPlayList, currentIndex) => {
|
||
if (!currentPlayList || currentPlayList.length === 0) return null;
|
||
|
||
let nextIndex =
|
||
currentIndex === currentPlayList.length - 1 ? 0 : currentIndex + 1;
|
||
let initialIndex = nextIndex;
|
||
let attempts = 0;
|
||
|
||
// 유효한 showId를 가진 다음 쇼 찾기
|
||
while (
|
||
!currentPlayList[nextIndex]?.showId &&
|
||
attempts < currentPlayList.length
|
||
) {
|
||
nextIndex = nextIndex === currentPlayList.length - 1 ? 0 : nextIndex + 1;
|
||
attempts++;
|
||
if (nextIndex === initialIndex) break;
|
||
}
|
||
|
||
if (currentPlayList[nextIndex]?.showId) {
|
||
return currentPlayList[nextIndex];
|
||
}
|
||
|
||
return null;
|
||
}, []);
|
||
|
||
// 다음 쇼 정보 계산
|
||
const nextShowInfo = useMemo(() => {
|
||
return findNextPlayableShow(playListInfo, selectedIndex);
|
||
}, [playListInfo, selectedIndex, findNextPlayableShow]);
|
||
|
||
// ✨ DEBUG: youmaylikeInfos 데이터 로그
|
||
useEffect(() => {
|
||
dlog('[DEBUG] TabContainerV2 - youmaylikeInfos:', {
|
||
exists: !!youmaylikeInfos,
|
||
length: youmaylikeInfos?.length,
|
||
data: youmaylikeInfos,
|
||
shopNowInfo_length: shopNowInfo?.length,
|
||
shouldShowYouMayAlso:
|
||
shopNowInfo &&
|
||
shopNowInfo.length < 3 &&
|
||
youmaylikeInfos &&
|
||
youmaylikeInfos.length > 0,
|
||
});
|
||
}, [youmaylikeInfos, shopNowInfo]);
|
||
|
||
const tabList = [
|
||
$L('SHOP NOW'),
|
||
panelInfo?.shptmBanrTpNm === 'LIVE'
|
||
? $L('LIVE CHANNEL')
|
||
: $L('FEATURED SHOWS'),
|
||
];
|
||
|
||
useEffect(() => {
|
||
let nowMenu;
|
||
|
||
if (tabIndex === 0) {
|
||
nowMenu = LOG_MENU.FULL_SHOP_NOW;
|
||
}
|
||
|
||
if (tabIndex === 1) {
|
||
const isLive = panelInfo?.shptmBanrTpNm === 'LIVE';
|
||
nowMenu = isLive
|
||
? LOG_MENU.FULL_LIVE_CHANNELS
|
||
: LOG_MENU.FULL_FEATURED_SHOWS;
|
||
}
|
||
|
||
if (nowMenu) {
|
||
handleItemFocus(nowMenu);
|
||
}
|
||
}, [handleItemFocus, panelInfo?.shptmBanrTpNm, tabIndex]);
|
||
|
||
const _handleItemFocus = useCallback(
|
||
(nowMenu) => {
|
||
if (handleItemFocus) {
|
||
handleItemFocus(nowMenu);
|
||
}
|
||
},
|
||
[handleItemFocus]
|
||
);
|
||
|
||
const onSpotlightIndicatorUpButton = useCallback(
|
||
(e) => {
|
||
if (videoVerticalVisible) {
|
||
e.stopPropagation();
|
||
e.preventDefault();
|
||
Spotlight.focus('spotlightId-video-contaienr');
|
||
}
|
||
},
|
||
[videoVerticalVisible]
|
||
);
|
||
|
||
const handleCloseButtonClick = useCallback(
|
||
(e) => {
|
||
e.stopPropagation();
|
||
e.preventDefault();
|
||
if (onTabClose) {
|
||
onTabClose(2); // tabIndex를 2로 설정
|
||
}
|
||
},
|
||
[onTabClose]
|
||
);
|
||
|
||
// 위 방향 포커스 이동 시 백 버튼으로 이동
|
||
const handleSpotlightUpToBackButton = useCallback((e) => {
|
||
e.stopPropagation();
|
||
e.preventDefault();
|
||
|
||
// VideoPlayer가 belowContentsVisible prop을 감지해서 이미 controls를 표시했으므로
|
||
// 바로 포커스 이동
|
||
Spotlight.focus(SpotlightIds.PLAYER_BACK_BUTTON);
|
||
}, []);
|
||
|
||
// 이전 tabIndex 값 추적
|
||
const prevTabIndexRef = usePrevious(tabIndex);
|
||
const prevTabIndex = prevTabIndexRef.current;
|
||
|
||
// 하나의 함수에서 모든 tabIndex 변화 처리
|
||
const handleTabIndexChange = useCallback((newTabIndex, oldTabIndex) => {
|
||
console.log(
|
||
`[TabIndexChange] Tab changed from ${oldTabIndex} to ${newTabIndex}`
|
||
);
|
||
|
||
if (newTabIndex === 0) {
|
||
// tabIndex = 0 (ShopNow)
|
||
const timeoutId = setTimeout(() => {
|
||
Spotlight.focus('shownow_close_button');
|
||
}, 100);
|
||
return () => clearTimeout(timeoutId);
|
||
}
|
||
|
||
if (newTabIndex === 1) {
|
||
// tabIndex = 1 (LiveChannel)
|
||
const timeoutId = setTimeout(() => {
|
||
Spotlight.focus('below-tab-live-channel-button');
|
||
}, 100);
|
||
return () => clearTimeout(timeoutId);
|
||
}
|
||
|
||
if (newTabIndex === 2) {
|
||
// tabIndex = 2 (ShopNowButton)
|
||
const timeoutId = setTimeout(() => {
|
||
Spotlight.focus('below-tab-shop-now-button');
|
||
}, 100);
|
||
return () => clearTimeout(timeoutId);
|
||
}
|
||
}, []);
|
||
|
||
// tabIndex 변화 감지 및 처리
|
||
useEffect(() => {
|
||
// 초기 렌더링이 아닐 때만 실행 (prevTabIndex가 정의되었을 때)
|
||
if (prevTabIndex !== undefined && prevTabIndex !== tabIndex) {
|
||
handleTabIndexChange(tabIndex, prevTabIndex);
|
||
}
|
||
}, [tabIndex, prevTabIndex, handleTabIndexChange]);
|
||
|
||
return (
|
||
<Container
|
||
className={classNames(
|
||
css.tabContainer,
|
||
videoVerticalVisible && css.vertical,
|
||
css[`tabIndex${tabIndex}`]
|
||
)}
|
||
spotlightId={spotlightId}
|
||
>
|
||
{tabVisible && tabIndex === 0 && (
|
||
<>
|
||
<div className={css.shopNowHeaderContainer}>
|
||
<div className={css.shopNowHeader}>
|
||
<SpottableDiv
|
||
className={css.shopNowHeaderLeft}
|
||
spotlightId="shownow_close_button"
|
||
onClick={handleCloseButtonClick}
|
||
onSpotlightUp={handleSpotlightUpToBackButton}
|
||
onSpotlightDown={(e) => {
|
||
// 첫 번째 ShopNow 아이템으로 포커스 이동
|
||
e.stopPropagation();
|
||
e.preventDefault();
|
||
Spotlight.focus('shop-now-item-0');
|
||
}}
|
||
>
|
||
<div
|
||
className={classNames(
|
||
css.shopNowIconWrapper,
|
||
playListInfo[selectedIndex]?.patncNm === 'QVC' &&
|
||
css.shopNowQvcIconWrapper
|
||
)}
|
||
>
|
||
<img
|
||
src={playListInfo[selectedIndex]?.patncLogoPath}
|
||
alt="shop now icon"
|
||
className={css.shopNowIcon}
|
||
/>
|
||
</div>
|
||
<div className={css.shopNowHeaderText}>SHOP NOW</div>
|
||
<div className={css.arrowIcon}>
|
||
<img src={icon_arrow_dwon} alt="arrow down" />
|
||
</div>
|
||
</SpottableDiv>
|
||
{/* <SpottableDiv
|
||
className={css.closeButton}
|
||
spotlightId="below-tab-close-button"
|
||
onClick={handleCloseButtonClick}
|
||
onSpotlightUp={handleSpotlightUpToBackButton}
|
||
onSpotlightDown={(e) => {
|
||
// 첫 번째 ShopNow 아이템으로 포커스 이동
|
||
e.stopPropagation();
|
||
e.preventDefault();
|
||
Spotlight.focus("shop-now-item-0");
|
||
}}
|
||
>
|
||
×
|
||
</SpottableDiv> */}
|
||
</div>
|
||
|
||
{/* YouMayAlso Like 헤더 (ShopNow 아이템 < 3 && YouMayLike 데이터 존재) */}
|
||
{shopNowInfo &&
|
||
shopNowInfo.length < 3 &&
|
||
youmaylikeInfos &&
|
||
youmaylikeInfos.length > 0 && (
|
||
<div className={css.youMayAlsoLikeHeader}>
|
||
<div className={css.youMayAlsoLikeText}>
|
||
You may also like
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
<ShopNowContents
|
||
tabTitle={tabList}
|
||
shopNowInfo={shopNowInfo}
|
||
playListInfo={playListInfo && playListInfo[selectedIndex]}
|
||
videoVerticalVisible={videoVerticalVisible}
|
||
panelInfo={panelInfo}
|
||
tabIndex={tabIndex}
|
||
handleItemFocus={_handleItemFocus}
|
||
version={2}
|
||
direction="horizontal"
|
||
/>
|
||
</>
|
||
)}
|
||
|
||
{tabVisible && tabIndex === 1 && (
|
||
<>
|
||
<SpottableDiv
|
||
className={css.liveChannelButton}
|
||
onClick={onLiveChannelButtonClick}
|
||
spotlightId={
|
||
panelInfo?.shptmBanrTpNm === 'LIVE'
|
||
? 'below-tab-live-channel-button'
|
||
: 'below-tab-featured-show-button'
|
||
}
|
||
onSpotlightUp={handleSpotlightUpToBackButton}
|
||
onSpotlightDown={(e) => {
|
||
// 첫 번째 PlayerItem으로 포커스 이동
|
||
Spotlight.focus('tabChannel-video-0');
|
||
}}
|
||
onSpotlightFocus={() => {
|
||
console.log('[TabContainerV2] below-tab button focused');
|
||
}}
|
||
>
|
||
<span className={css.buttonText}>{tabList[1]}</span>
|
||
<div className={css.arrowIcon}>
|
||
<img src={icon_arrow_dwon} alt="arrow down" />
|
||
</div>
|
||
</SpottableDiv>
|
||
|
||
{panelInfo?.shptmBanrTpNm === 'LIVE' && playListInfo && (
|
||
<LiveChannelContents
|
||
tabTitle={tabList}
|
||
selectedIndex={selectedIndex}
|
||
setSelectedIndex={setSelectedIndex}
|
||
videoVerticalVisible={videoVerticalVisible}
|
||
currentVideoShowId={playListInfo[selectedIndex]?.showId}
|
||
liveInfos={playListInfo}
|
||
tabIndex={tabIndex}
|
||
handleItemFocus={_handleItemFocus}
|
||
panelInfo={panelInfo}
|
||
currentTime={currentTime}
|
||
version={2}
|
||
direction="horizontal"
|
||
/>
|
||
)}
|
||
|
||
{panelInfo?.shptmBanrTpNm === 'VOD' && playListInfo && (
|
||
<FeaturedShowContents
|
||
tabTitle={tabList}
|
||
featuredShowsInfos={playListInfo}
|
||
currentVideoInfo={playListInfo[selectedIndex]}
|
||
setSelectedIndex={setSelectedIndex}
|
||
selectedIndex={selectedIndex}
|
||
videoVerticalVisible={videoVerticalVisible}
|
||
currentVideoShowId={playListInfo[selectedIndex]?.showId}
|
||
tabIndex={tabIndex}
|
||
handleItemFocus={_handleItemFocus}
|
||
panelInfo={panelInfo}
|
||
version={2}
|
||
direction="horizontal"
|
||
/>
|
||
)}
|
||
</>
|
||
)}
|
||
|
||
{tabVisible && tabIndex === 2 && (
|
||
<>
|
||
<LiveChannelNext
|
||
channelLogo={nextShowInfo?.patncLogoPath}
|
||
channelName={nextShowInfo?.patncNm || 'ShopLC'}
|
||
programName={nextShowInfo?.showNm || 'Live Channel'}
|
||
backgroundColor={
|
||
nextShowInfo?.dfltThumbnailImgPath ||
|
||
'linear-gradient(180deg, #284998 0%, #06B0EE 100%)'
|
||
}
|
||
onClick={onLiveNext}
|
||
spotlightId="live-channel-next-button"
|
||
onFocus={onLiveNext}
|
||
/>
|
||
<ShopNowButton onClick={onShopNowButtonClick} />
|
||
</>
|
||
)}
|
||
</Container>
|
||
);
|
||
}
|