328 lines
11 KiB
JavaScript
328 lines
11 KiB
JavaScript
// src/views/HomePanel/HomeBanner/HomeBanner.jsx
|
|
|
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
|
|
import Spotlight from '@enact/spotlight';
|
|
import { SpotlightContainerDecorator } from '@enact/spotlight/SpotlightContainerDecorator';
|
|
import Spottable from '@enact/spotlight/Spottable';
|
|
|
|
import { changeAppStatus } from '../../../actions/commonActions';
|
|
import { justForYou } from '../../../actions/forYouActions';
|
|
import {
|
|
clearAllVideoTimers,
|
|
releasePlayControl,
|
|
requestPlayControl,
|
|
startVideoPlayer,
|
|
startVideoPlayerNew,
|
|
} from '../../../actions/playActions';
|
|
import CustomImage from '../../../components/CustomImage/CustomImage';
|
|
import { useFocusHistory } from '../../../hooks/useFocusHistory/useFocusHistory';
|
|
// [COMMENTED OUT] useVideoMove 관련 코드 주석 처리 - 향후 사용 검토 필요
|
|
// import { useVideoMove } from '../../../hooks/useVideoTransition/useVideoMove';
|
|
import { panel_names } from '../../../utils/Config';
|
|
import { $L } from '../../../utils/helperMethods';
|
|
import css from './HomeBanner.module.less';
|
|
// import * as Config from "../../../utils/Config";
|
|
// 새로운 비디오 유닛 컴포넌트 임포트
|
|
import PersistentVideoUnit from './PersistentVideoUnit';
|
|
import JustForSwitchBanner from './RandomBannerType/JustForYouBanner';
|
|
import Random from './RandomUnit';
|
|
// import RandomUnitNew from './RandomUnit';
|
|
import Rolling from './RollingUnit';
|
|
import SimpleVideoContainer from './SimpleVideoContainer';
|
|
|
|
const SpottableComponent = Spottable('div');
|
|
const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
|
const ContainerBasic = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
|
|
|
|
export default function HomeBanner({
|
|
firstSpot,
|
|
spotlightId,
|
|
handleItemFocus,
|
|
handleShelfFocus,
|
|
videoPlayIntentRef,
|
|
}) {
|
|
const dispatch = useDispatch();
|
|
useEffect(() => {
|
|
dispatch(justForYou());
|
|
}, [dispatch]);
|
|
const homeTopDisplayInfo = useSelector((state) => state.home.homeTopDisplayInfo);
|
|
|
|
const bannerDataList = useSelector((state) => state.home.bannerData?.bannerInfos);
|
|
|
|
const popupVisible = useSelector((state) => state.common.popup.popupVisible);
|
|
const panels = useSelector((state) => state.panels.panels);
|
|
// 🔽 useFocusHistory - 경량화된 범용 포커스 히스토리
|
|
const focusHistory = useFocusHistory({
|
|
enableLogging: true,
|
|
useGlobalState: true,
|
|
logPrefix: '[HomeBanner-Focus]',
|
|
});
|
|
|
|
// 🔽 useVideoMove - 포커스 전환 기반 동영상 제어
|
|
// [COMMENTED OUT] useVideoMove 미사용 - playByTransition() 호출되지 않음
|
|
// const { playByTransition, cleanup } = useVideoMove({
|
|
// enableLogging: true,
|
|
// logPrefix: "[HomeBanner-VideoMove]",
|
|
// });
|
|
|
|
// 🔽 컴포넌트 언마운트 시 비디오 리소스 정리
|
|
useEffect(() => {
|
|
return () => {
|
|
// console.log('[HomeBanner] 컴포넌트 언마운트 - 비디오 리소스 정리');
|
|
// [COMMENTED OUT] useVideoMove cleanup 미사용
|
|
// cleanup();
|
|
|
|
// 전역 비디오 타이머 정리 (메모리 누수 방지)
|
|
clearAllVideoTimers();
|
|
|
|
// 백그라운드 비디오 정지
|
|
if (window.mediaPlayer && window.mediaPlayer._controller) {
|
|
try {
|
|
window.mediaPlayer._controller.pause();
|
|
console.log('[HomeBanner] 백그라운드 비디오 정지 완료');
|
|
} catch (error) {
|
|
console.warn('[HomeBanner] 백그라운드 비디오 정지 실패:', error);
|
|
}
|
|
}
|
|
};
|
|
}, []); // [COMMENTED OUT] cleanup 변수 제거 - useVideoMove 미사용으로 인한 의존성 제거
|
|
|
|
const selectTemplate = useMemo(() => {
|
|
return homeTopDisplayInfo.shptmTmplCd;
|
|
}, [homeTopDisplayInfo.shptmTmplCd]);
|
|
|
|
const _handleItemFocus = useCallback(() => {
|
|
if (handleItemFocus) {
|
|
handleItemFocus();
|
|
}
|
|
}, [handleItemFocus]);
|
|
|
|
// 🔽 초기 비디오 재생 플래그 (1회만 실행되도록)
|
|
const isInitialVideoPlayRef = useRef(false);
|
|
|
|
//------------------------------------------------------------------------------
|
|
const _handleShelfFocus = useCallback(() => {
|
|
if (handleShelfFocus) {
|
|
handleShelfFocus();
|
|
}
|
|
}, [handleShelfFocus]);
|
|
|
|
const defaultFocus = useMemo(() => {
|
|
if (bannerDataList) {
|
|
let targetIndex = 0;
|
|
for (let i = 0; i < bannerDataList.length; i++) {
|
|
const data = bannerDataList[i];
|
|
let bannerDetailInfos = data.bannerDetailInfos;
|
|
|
|
if (data.shptmDspyTpNm === 'Random') {
|
|
if (
|
|
bannerDetailInfos[data.randomIndex].shptmBanrTpNm === 'LIVE' ||
|
|
bannerDetailInfos[data.randomIndex].shptmBanrTpNm === 'VOD'
|
|
) {
|
|
targetIndex = i;
|
|
break;
|
|
}
|
|
} else if (
|
|
bannerDetailInfos.find((el) => el.shptmBanrTpNm === 'LIVE' || el.shptmBanrTpNm === 'VOD')
|
|
) {
|
|
targetIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
return 'banner' + targetIndex;
|
|
}
|
|
|
|
return null;
|
|
}, [bannerDataList]);
|
|
|
|
// 🔽 초기 비디오 자동 재생 (렌더링 완료 후)
|
|
useEffect(() => {
|
|
// 조건 체크
|
|
if (!bannerDataList || isInitialVideoPlayRef.current || !defaultFocus) {
|
|
return;
|
|
}
|
|
|
|
// 한 번만 실행
|
|
isInitialVideoPlayRef.current = true;
|
|
|
|
// defaultFocus에서 배너 인덱스 추출 (예: "banner0" -> 0)
|
|
const bannerIndex = parseInt(defaultFocus.replace('banner', ''));
|
|
const targetBannerData = bannerDataList[bannerIndex];
|
|
|
|
if (!targetBannerData) {
|
|
return;
|
|
}
|
|
|
|
// 비디오 재생 가능한 배너 찾기
|
|
let videoData = null;
|
|
if (targetBannerData.shptmDspyTpNm === 'Random') {
|
|
videoData = targetBannerData.bannerDetailInfos?.[targetBannerData.randomIndex];
|
|
} else {
|
|
videoData = targetBannerData.bannerDetailInfos?.[0];
|
|
}
|
|
|
|
// DetailPanel이 떠 있는 동안에는 배너 자동 재생을 스킵 (PlayerPanel 모달 재설정 방지)
|
|
const hasDetailPanel = panels.some((p) => p.name === panel_names.DETAIL_PANEL);
|
|
|
|
if (!hasDetailPanel && videoData && (videoData.shptmBanrTpNm === 'LIVE' || videoData.shptmBanrTpNm === 'VOD')) {
|
|
console.log('[HomeBanner] 초기 비디오 자동 재생:', defaultFocus);
|
|
|
|
dispatch(
|
|
startVideoPlayerNew({
|
|
bannerId: defaultFocus,
|
|
showUrl: videoData.showUrl,
|
|
patnrId: videoData.patnrId,
|
|
showId: videoData.showId,
|
|
shptmBanrTpNm: videoData.shptmBanrTpNm,
|
|
lgCatCd: videoData.lgCatCd,
|
|
chanId: videoData.brdcChnlId,
|
|
// 기본: 배너는 modal=true로 재생
|
|
modal: true,
|
|
modalContainerId: defaultFocus,
|
|
})
|
|
);
|
|
}
|
|
}, [bannerDataList, defaultFocus, dispatch, panels]);
|
|
|
|
const renderItem = useCallback(
|
|
(index, isHorizontal) => {
|
|
const data = bannerDataList?.[index] ?? {};
|
|
|
|
// videoPlayable을 동적으로 계산
|
|
// Random이나 Rolling 배너에서 LIVE 또는 VOD 타입의 비디오가 있는지 확인
|
|
const videoPlayerable =
|
|
(data.shptmDspyTpNm === 'Random' || data.shptmDspyTpNm === 'Rolling') &&
|
|
data.bannerDetailInfos?.some(
|
|
(item) => item.shptmBanrTpNm === 'LIVE' || item.shptmBanrTpNm === 'VOD'
|
|
);
|
|
|
|
return (
|
|
<div className={!isHorizontal ? css.imgBox : undefined}>
|
|
{data.shptmDspyTpNm === 'Rolling' ? (
|
|
<Rolling
|
|
bannerData={data}
|
|
isHorizontal={isHorizontal}
|
|
key={'banner' + index}
|
|
spotlightId={'banner' + index}
|
|
handleShelfFocus={_handleShelfFocus}
|
|
handleItemFocus={_handleItemFocus}
|
|
videoPlayerable={videoPlayerable}
|
|
/>
|
|
) : data.shptmDspyTpNm === 'Random' ? (
|
|
<Random
|
|
bannerData={data}
|
|
isHorizontal={isHorizontal}
|
|
key={'banner' + index}
|
|
spotlightId={'banner' + index}
|
|
handleShelfFocus={_handleShelfFocus}
|
|
handleItemFocus={_handleItemFocus}
|
|
randomNumber={data.randomIndex}
|
|
videoPlayerable={videoPlayerable}
|
|
videoPlayIntentRef={videoPlayIntentRef}
|
|
/>
|
|
) : (
|
|
<SpottableComponent spotlightId={'banner' + index}>
|
|
<CustomImage
|
|
delay={0}
|
|
src={
|
|
isHorizontal
|
|
? homeTopDisplayInfo.wdthtpImgPath1
|
|
: homeTopDisplayInfo.vtctpImgPath1
|
|
}
|
|
aria-label={
|
|
isHorizontal ? homeTopDisplayInfo.wdthtpImgNm1 : homeTopDisplayInfo.vtctpImgNm1
|
|
}
|
|
/>
|
|
</SpottableComponent>
|
|
)}
|
|
</div>
|
|
);
|
|
},
|
|
[_handleItemFocus, _handleShelfFocus, bannerDataList, videoPlayIntentRef]
|
|
);
|
|
|
|
// 0번째 배너(영구 재생)를 위한 렌더링 함수
|
|
const renderItemPersistentVideo = useCallback(
|
|
(index, isHorizontal) => {
|
|
return (
|
|
<div className={!isHorizontal ? css.imgBox : undefined}>
|
|
<SimpleVideoContainer
|
|
spotlightId={'banner' + index} // "banner0"
|
|
isHorizontal={isHorizontal}
|
|
handleShelfFocus={_handleShelfFocus}
|
|
/>
|
|
</div>
|
|
);
|
|
},
|
|
[_handleShelfFocus]
|
|
);
|
|
|
|
const renderSimpleVideoContainer = useCallback(
|
|
(index, isHorizontal) => {
|
|
return (
|
|
<div className={!isHorizontal ? css.imgBox : undefined}>
|
|
<SimpleVideoContainer
|
|
spotlightId={'banner' + index}
|
|
isHorizontal={isHorizontal}
|
|
handleShelfFocus={_handleShelfFocus}
|
|
/>
|
|
</div>
|
|
);
|
|
},
|
|
[_handleShelfFocus]
|
|
);
|
|
|
|
const renderLayout = useCallback(() => {
|
|
switch (selectTemplate) {
|
|
case 'DSP00201': {
|
|
return (
|
|
<>
|
|
<ContainerBasic className={css.smallBox}>
|
|
{renderItem(0, true)}
|
|
{renderItem(1, true)}
|
|
</ContainerBasic>
|
|
{renderItem(2, false)}
|
|
{renderItem(3, false)}
|
|
</>
|
|
);
|
|
}
|
|
case 'DSP00202': {
|
|
return (
|
|
<>
|
|
{renderItem(0, false)}
|
|
<ContainerBasic className={css.smallBox}>
|
|
{renderItem(1, true)}
|
|
{renderItem(2, true)}
|
|
</ContainerBasic>
|
|
{renderItem(3, false)}
|
|
</>
|
|
);
|
|
}
|
|
case 'DSP00203': {
|
|
return (
|
|
<>
|
|
{renderItem(0, false)}
|
|
{renderItem(1, false)}
|
|
<ContainerBasic className={css.smallBox}>
|
|
{renderItem(2, true)}
|
|
{renderItem(3, true)}
|
|
</ContainerBasic>
|
|
</>
|
|
);
|
|
}
|
|
}
|
|
return null;
|
|
}, [selectTemplate, renderItem, renderSimpleVideoContainer]);
|
|
|
|
return (
|
|
<>
|
|
<Container className={css.container} spotlightId={spotlightId} data-wheel-point={true}>
|
|
<div className={css.homeTemplateBox}>{renderLayout()}</div>
|
|
</Container>
|
|
</>
|
|
);
|
|
}
|