562 lines
17 KiB
JavaScript
562 lines
17 KiB
JavaScript
import React, {
|
|
useCallback,
|
|
useEffect,
|
|
useMemo,
|
|
useRef,
|
|
useState,
|
|
} from 'react';
|
|
|
|
import classNames from 'classnames';
|
|
import {
|
|
useDispatch,
|
|
useSelector,
|
|
} from 'react-redux';
|
|
|
|
import SpotlightContainerDecorator
|
|
from '@enact/spotlight/SpotlightContainerDecorator';
|
|
import Spottable from '@enact/spotlight/Spottable';
|
|
|
|
import btnPlay from '../../../../assets/images/btn/btn-play-thumb-nor.png';
|
|
import defaultLogoImg
|
|
from '../../../../assets/images/ic-tab-partners-default@3x.png';
|
|
import emptyHorImage
|
|
from '../../../../assets/images/img-home-banner-empty-hor.png';
|
|
import emptyVerImage
|
|
from '../../../../assets/images/img-home-banner-empty-ver.png';
|
|
import defaultImageItem
|
|
from '../../../../assets/images/img-thumb-empty-product@3x.png';
|
|
import liveShow from '../../../../assets/images/tag-liveshow.png';
|
|
//import { sendBroadCast } from "../../../actions/commonActions";
|
|
import { pushPanel } from '../../../actions/panelActions';
|
|
import {
|
|
finishVideoPreview,
|
|
startVideoPlayer,
|
|
} from '../../../actions/playActions';
|
|
import CustomImage from '../../../components/CustomImage/CustomImage';
|
|
import useLogService from '../../../hooks/useLogService';
|
|
import usePriceInfo from '../../../hooks/usePriceInfo';
|
|
import {
|
|
LOG_MENU,
|
|
LOG_TP_NO,
|
|
panel_names,
|
|
} from '../../../utils/Config';
|
|
import {
|
|
$L,
|
|
formatGMTString,
|
|
} from '../../../utils/helperMethods';
|
|
import css from './RandomUnit.module.less';
|
|
|
|
const SpottableComponent = Spottable("div");
|
|
|
|
const Container = SpotlightContainerDecorator(
|
|
{ enterTo: "last-focused" },
|
|
"div"
|
|
);
|
|
|
|
export default function RandomUnit({
|
|
bannerData,
|
|
spotlightId,
|
|
isHorizontal,
|
|
handleItemFocus,
|
|
randomNumber,
|
|
}) {
|
|
const bannerDetailInfos = bannerData.bannerDetailInfos;
|
|
|
|
const { sendLogTopContents } = useLogService();
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
const curationId = useSelector((state) => state.home?.bannerData?.curationId);
|
|
const curtNm = useSelector((state) => state.home?.bannerData?.curtNm);
|
|
const shptmTmplCd = useSelector(
|
|
(state) => state.home?.bannerData?.shptmTmplCd
|
|
);
|
|
const nowMenu = useSelector((state) => state.common.menu.nowMenu);
|
|
const homeCategory = useSelector(
|
|
(state) => state.home.menuData?.data?.homeCategory
|
|
);
|
|
|
|
const [randomData, setRandomData] = useState("");
|
|
const [priceInfos, setpriceInfos] = useState("");
|
|
const [isFocused, setIsFocused] = useState(false);
|
|
|
|
const timerRef = useRef();
|
|
const bannerDataRef = useRef(bannerData);
|
|
const randomDataRef = useRef(bannerDetailInfos[randomNumber]);
|
|
|
|
const [videoError, setVideoError] = useState(false);
|
|
|
|
const [liveIndicies, setLiveIndicies] = useState([]);
|
|
|
|
// 정상적으로 로딩되면 빈객체로 넘어가고 , 에러가 나면 객체안에 타입이 담겨옵니다.
|
|
const broadcast = useSelector((state) => state.common.broadcast);
|
|
|
|
// 1. 비디오(live) 에러 감지
|
|
// 2. 라이브 영상이 2개 이상이면, 그 다음 영상으로 전환
|
|
// 3. 라이브 영상이 1개면 그 다음 영상으로 전환을 할 수 없으므로 에러 로고 화면을 보여준다.
|
|
// 라이브 영상이 1개 라도 순간적인 네트워크 오류나, 일시적인 오류 일수 있으므로, 일정 시간을 주고, 비디오를 다시 호출 한다.
|
|
|
|
useEffect(() => {
|
|
if (bannerDetailInfos && randomNumber) {
|
|
const indices = bannerDetailInfos
|
|
.map((info, index) => (info.shptmBanrTpNm === "LIVE" ? index : null))
|
|
.filter((index) => index !== null && index !== randomNumber);
|
|
|
|
setLiveIndicies(indices);
|
|
}
|
|
}, [bannerDetailInfos, randomNumber]);
|
|
|
|
// 비디오 에러일시, 클릭 이동
|
|
const videoErrorClick = useCallback(() => {
|
|
return dispatch(
|
|
pushPanel({
|
|
name: panel_names.FEATURED_BRANDS_PANEL,
|
|
panelInfo: { patnrId: randomData.patnrId },
|
|
})
|
|
);
|
|
}, [randomData, dispatch]);
|
|
|
|
// 포커스 인
|
|
const onFocus = useCallback(() => {
|
|
if (handleItemFocus) {
|
|
handleItemFocus();
|
|
}
|
|
setIsFocused(true);
|
|
}, [handleItemFocus]);
|
|
|
|
// 포커스 아웃
|
|
const onBlur = useCallback(() => {
|
|
setIsFocused(false);
|
|
clearTimeout(timerRef.current);
|
|
}, [isFocused]);
|
|
|
|
// DSP00501 : Featured Brands
|
|
// DSP00502 : Trending now
|
|
// DSP00503 : HOT PICKS
|
|
// DSP00504 : ON SALE
|
|
// DSP00505 : CATEGORY
|
|
// DSP00506 : Product Detail
|
|
// DSP00507 : VOD
|
|
// DSP00508 : Show Detail
|
|
// DSP00509 : Theme
|
|
|
|
const categoryData = useMemo(() => {
|
|
if (randomData && randomData.shptmLnkTpCd === "DSP00505") {
|
|
if (homeCategory && homeCategory.length > 0) {
|
|
const foundCategory = homeCategory.find(
|
|
(data) => data.lgCatCd === randomData.lgCatCd
|
|
);
|
|
if (foundCategory) {
|
|
return {
|
|
lgCatNm: foundCategory.lgCatNm,
|
|
COUNT: foundCategory.COUNT,
|
|
};
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}, [homeCategory, randomData.shptmLnkTpCd]);
|
|
|
|
// 이미지 배너 클릭
|
|
const imageBannerClick = () => {
|
|
let panelName = "";
|
|
|
|
if (randomData.shptmLnkTpCd === "DSP00501") {
|
|
return dispatch(
|
|
pushPanel({
|
|
name: panel_names.FEATURED_BRANDS_PANEL,
|
|
panelInfo: { patnrId: randomData.patnrId },
|
|
})
|
|
);
|
|
} else if (randomData.shptmLnkTpCd === "DSP00502") {
|
|
panelName = panel_names.TRENDING_NOW_PANEL;
|
|
} else if (randomData.shptmLnkTpCd === "DSP00503") {
|
|
return dispatch(
|
|
pushPanel({
|
|
name: panel_names.HOT_PICKS_PANEL,
|
|
panelInfo: {
|
|
patnrId: randomData.patnrId,
|
|
curationId: randomData.lnkCurationId,
|
|
},
|
|
})
|
|
);
|
|
} else if (randomData.shptmLnkTpCd === "DSP00504") {
|
|
return dispatch(
|
|
pushPanel({
|
|
name: panel_names.ON_SALE_PANEL,
|
|
panelInfo: {
|
|
lgCatCd: randomData.lgCatCd,
|
|
},
|
|
})
|
|
);
|
|
} else if (randomData.shptmLnkTpCd === "DSP00505") {
|
|
if (Object.keys(categoryData).length > 0) {
|
|
return dispatch(
|
|
pushPanel({
|
|
name: panel_names.CATEGORY_PANEL,
|
|
panelInfo: {
|
|
lgCatCd: randomData.lgCatCd,
|
|
lgCatNm: categoryData.lgCatNm,
|
|
COUNT: categoryData.COUNT,
|
|
currentSpot: null,
|
|
dropDownTab: 0,
|
|
tab: 0,
|
|
focusedContainerId: null,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
} else if (randomData.shptmLnkTpCd === "DSP00506") {
|
|
return dispatch(
|
|
pushPanel({
|
|
name: panel_names.DETAIL_PANEL,
|
|
panelInfo: {
|
|
patnrId: randomData.patnrId,
|
|
prdtId: randomData.prdtId,
|
|
curationId: randomData.lnkCurationId,
|
|
},
|
|
})
|
|
);
|
|
} else if (randomData.shptmLnkTpCd === "DSP00507") {
|
|
return dispatch(
|
|
startVideoPlayer({
|
|
patnrId: randomData.patnrId,
|
|
showId: randomData.showId,
|
|
shptmBanrTpNm: "VOD",
|
|
lgCatCd: randomData.lgCatCd,
|
|
modal: false,
|
|
})
|
|
);
|
|
} else if (randomData.shptmLnkTpCd === "DSP00508") {
|
|
return dispatch(
|
|
pushPanel({
|
|
name: panel_names.DETAIL_PANEL,
|
|
panelInfo: {
|
|
patnrId: randomData.patnrId,
|
|
curationId: randomData.lnkCurationId,
|
|
prdtId: randomData.prdtId,
|
|
type: "theme",
|
|
},
|
|
})
|
|
);
|
|
} else if (randomData.shptmLnkTpCd === "DSP00509") {
|
|
return dispatch(
|
|
pushPanel({
|
|
name: panel_names.THEME_CURATION_PANEL,
|
|
panelInfo: {
|
|
curationId: randomData.lnkCurationId,
|
|
},
|
|
})
|
|
);
|
|
} else {
|
|
panelName = panel_names.HOME_PANEL;
|
|
}
|
|
|
|
dispatch(
|
|
pushPanel({
|
|
name: panelName,
|
|
panelInfo: {
|
|
patnrId: randomData.patnrId,
|
|
prdtId: randomData.prdtId,
|
|
},
|
|
})
|
|
);
|
|
};
|
|
|
|
// 투데이즈딜 클릭
|
|
const todayDealClick = useCallback(() => {
|
|
dispatch(
|
|
pushPanel({
|
|
name: panel_names.DETAIL_PANEL,
|
|
panelInfo: {
|
|
patnrId: randomData.patnrId,
|
|
prdtId: randomData.prdtId,
|
|
},
|
|
})
|
|
);
|
|
}, [dispatch, randomData?.patnrId, randomData?.prdtId]);
|
|
|
|
// 비디오 클릭
|
|
const videoClick = useCallback(() => {
|
|
dispatch(
|
|
startVideoPlayer({
|
|
showUrl: randomData.showUrl,
|
|
patnrId: randomData.patnrId,
|
|
showId: randomData.showId,
|
|
shptmBanrTpNm: randomData.showId ? randomData.shptmBanrTpNm : "MEDIA",
|
|
lgCatCd: randomData.lgCatCd,
|
|
chanId: randomData.brdcChnlId,
|
|
modal: false,
|
|
modalContainerId: spotlightId,
|
|
modalClassName: css.videoModal,
|
|
})
|
|
);
|
|
}, [randomData, spotlightId]);
|
|
|
|
// 투데이즈 딜 가격 정보
|
|
const { originalPrice, discountedPrice, discountRate, offerInfo } =
|
|
usePriceInfo(priceInfos) || {};
|
|
|
|
// 로그
|
|
useEffect(() => {
|
|
if (
|
|
bannerDataRef.current &&
|
|
randomDataRef.current &&
|
|
nowMenu &&
|
|
nowMenu === LOG_MENU.HOME_TOP
|
|
) {
|
|
const params = {
|
|
banrNo: `${randomDataRef.current?.banrDpOrd}`,
|
|
banrTpNm: randomDataRef.current?.vtctpYn
|
|
? randomDataRef.current.vtctpYn === "Y"
|
|
? "Vertical"
|
|
: "Horizontal"
|
|
: "",
|
|
contId: curationId ?? "",
|
|
contNm: curtNm ?? "",
|
|
contTpNm: randomDataRef.current?.shptmBanrTpNm ?? "",
|
|
dspyTpNm: bannerDataRef.current?.shptmDspyTpNm ?? "",
|
|
expsOrd: bannerDataRef.current?.banrLctnNo ?? "",
|
|
inDt: formatGMTString(new Date()),
|
|
linkTpCd: "",
|
|
logTpNo: LOG_TP_NO.TOP_CONTENTS,
|
|
patncNm: randomDataRef.current?.patncNm ?? "",
|
|
patnrId: randomDataRef.current?.patnrId ?? "",
|
|
tmplCd: shptmTmplCd,
|
|
};
|
|
|
|
return () => sendLogTopContents(params);
|
|
}
|
|
}, [curationId, curtNm, nowMenu, sendLogTopContents, shptmTmplCd]);
|
|
|
|
useEffect(() => {
|
|
if (bannerData) {
|
|
setRandomData(bannerDetailInfos[randomNumber]);
|
|
}
|
|
}, [bannerData]);
|
|
|
|
useEffect(() => {
|
|
if (randomData && randomData.priceInfo !== null) {
|
|
return setpriceInfos(randomData.priceInfo);
|
|
}
|
|
}, [randomData]);
|
|
|
|
useEffect(() => {
|
|
if (isFocused) {
|
|
// 비디오 정상
|
|
if (broadcast && Object.keys(broadcast).length === 0) {
|
|
setVideoError(false);
|
|
timerRef.current = setTimeout(
|
|
() =>
|
|
dispatch(
|
|
startVideoPlayer({
|
|
showUrl: randomData.showUrl,
|
|
patnrId: randomData.patnrId,
|
|
showId: randomData.showId,
|
|
shptmBanrTpNm: randomData.showId
|
|
? randomData.shptmBanrTpNm
|
|
: "MEDIA",
|
|
lgCatCd: randomData.lgCatCd,
|
|
chanId: randomData.brdcChnlId,
|
|
modal: true,
|
|
modalContainerId: spotlightId,
|
|
modalClassName: css.videoModal,
|
|
})
|
|
),
|
|
1000
|
|
);
|
|
// 비디오 오류
|
|
} else if (broadcast && Object.keys(broadcast).length !== 0) {
|
|
dispatch(finishVideoPreview());
|
|
if (liveIndicies.length > 0) {
|
|
const nextIndex = liveIndicies[0];
|
|
|
|
setLiveIndicies((prev) => prev.slice(1));
|
|
setRandomData(bannerDetailInfos[nextIndex]);
|
|
|
|
setTimeout(() => {
|
|
setVideoError(false);
|
|
}, 0);
|
|
} else {
|
|
setVideoError(true);
|
|
}
|
|
}
|
|
} else {
|
|
dispatch(finishVideoPreview());
|
|
}
|
|
return () => {
|
|
clearTimeout(timerRef.current);
|
|
};
|
|
}, [isFocused, dispatch, broadcast, videoError]);
|
|
|
|
return (
|
|
<>
|
|
<Container
|
|
className={classNames(
|
|
css.rollingWrap,
|
|
isHorizontal && css.isHorizontalWrap
|
|
)}
|
|
>
|
|
{randomData?.shptmBanrTpNm == "Image Banner" ? (
|
|
<SpottableComponent
|
|
className={classNames(
|
|
css.itemBox,
|
|
isHorizontal && css.isHorizontal
|
|
)}
|
|
onClick={imageBannerClick}
|
|
spotlightId={spotlightId}
|
|
aria-label={
|
|
randomData.prdtNm ? randomData.prdtNm : randomData.tmnlImgNm
|
|
}
|
|
>
|
|
<div className={css.imgBanner}>
|
|
<CustomImage
|
|
delay={0}
|
|
src={randomData.tmnlImgPath}
|
|
animationSpeed="fast"
|
|
ariaLabel={randomData.tmnImgNm}
|
|
/>
|
|
</div>
|
|
</SpottableComponent>
|
|
) : randomData?.shptmBanrTpNm == "LIVE" ||
|
|
randomData?.shptmBanrTpNm == "VOD" ? (
|
|
<SpottableComponent
|
|
className={classNames(
|
|
css.itemBox,
|
|
isHorizontal && css.isHorizontal
|
|
)}
|
|
onClick={videoError === true ? videoErrorClick : videoClick}
|
|
onFocus={onFocus}
|
|
onBlur={onBlur}
|
|
spotlightId={spotlightId}
|
|
aria-label={
|
|
randomData.shptmBanrTpNm == "LIVE"
|
|
? "LIVE " + randomData.showNm
|
|
: randomData.showNm
|
|
}
|
|
alt={"LIVE"}
|
|
>
|
|
{randomData.shptmBanrTpNm == "LIVE" && videoError === false && (
|
|
<p className={css.liveIcon}>
|
|
<CustomImage
|
|
delay={0}
|
|
src={liveShow}
|
|
animationSpeed="fast"
|
|
ariaLabel="LIVE icon"
|
|
/>
|
|
</p>
|
|
)}
|
|
|
|
{/* 비디오 에러 발생 */}
|
|
{videoError === true && (
|
|
<div className={css.errorContents}>
|
|
<div>
|
|
{randomData.patncLogoPath && (
|
|
<img
|
|
className={css.errorlogo}
|
|
src={randomData.patncLogoPath}
|
|
/>
|
|
)}
|
|
<p className={css.errorText}>
|
|
Click the screen to see more products!
|
|
</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 배너 메인 이미지 */}
|
|
{videoError === false && (
|
|
<div
|
|
className={classNames(
|
|
css.itemBox,
|
|
isHorizontal && css.isHorizontal
|
|
)}
|
|
>
|
|
{randomData.tmnlImgPath ? (
|
|
<CustomImage
|
|
delay={0}
|
|
src={randomData.tmnlImgPath}
|
|
ariaLabel={randomData.tmnImgNm}
|
|
animationSpeed="fast"
|
|
/>
|
|
) : (
|
|
<CustomImage
|
|
delay={0}
|
|
src={
|
|
randomData.vtctpYn === "Y" ? emptyVerImage : emptyHorImage
|
|
}
|
|
animationSpeed="fast"
|
|
ariaLabel={randomData.tmnImgNm}
|
|
/>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
{/* 플레이 버튼 [>] */}
|
|
{videoError === false && (
|
|
<div className={css.btnPlay}>
|
|
{randomData.tmnlImgPath == null ? "" : <img src={btnPlay} />}
|
|
</div>
|
|
)}
|
|
|
|
{/* 배너 하단 로고 */}
|
|
{videoError === false && (
|
|
<p className={css.brandIcon}>
|
|
{randomData.showId && (
|
|
<CustomImage
|
|
delay={0}
|
|
src={randomData.showId ? randomData.patncLogoPath : null}
|
|
fallbackSrc={defaultLogoImg}
|
|
animationSpeed="fast"
|
|
ariaLabel={randomData.brdcChnlId}
|
|
/>
|
|
)}
|
|
</p>
|
|
)}
|
|
</SpottableComponent>
|
|
) : randomData?.shptmBanrTpNm == "Today's Deals" ? (
|
|
<SpottableComponent
|
|
className={classNames(
|
|
css.itemBox,
|
|
css.todaysDeals,
|
|
isHorizontal && css.isHorizontal
|
|
)}
|
|
onClick={todayDealClick}
|
|
spotlightId={spotlightId}
|
|
aria-label={
|
|
randomData.prdtNm ? randomData.prdtNm : randomData.tmnlImgNm
|
|
}
|
|
>
|
|
<div className={css.productInfo}>
|
|
<div className={css.todaysDealTitle}>{$L("TODAY's DEALS")}</div>
|
|
<div className={css.textBox}>{randomData.prdtNm}</div>
|
|
<div className={css.accBox}>
|
|
{parseFloat(originalPrice?.replace("$", "")) === 0 ? (
|
|
<strong>{randomData.offerInfo}</strong>
|
|
) : discountRate ? (
|
|
discountedPrice
|
|
) : (
|
|
originalPrice
|
|
)}
|
|
</div>
|
|
{discountRate && (
|
|
<span className={css.saleAccBox}>{originalPrice}</span>
|
|
)}
|
|
</div>
|
|
|
|
<div className={css.itemImgBox}>
|
|
<CustomImage
|
|
delay={0}
|
|
src={randomData.tmnlImgPath}
|
|
animationSpeed="fast"
|
|
fallbackSrc={defaultImageItem}
|
|
ariaLabel={randomData.tmnlImgNm}
|
|
/>
|
|
</div>
|
|
</SpottableComponent>
|
|
) : null}
|
|
</Container>
|
|
</>
|
|
);
|
|
}
|