[저스트포유] 랜덤 배너에도 추가

- 현재 데이터가 롤링유닛에만 내려와서 확인이 불가능한 상황이라 우선 실제 노출소스는 주석처리.
 - 추후 확인후 주석해제하여 사용하겠습니다.
This commit is contained in:
junghoon86.park
2025-12-12 10:39:29 +09:00
parent 4a70f321ed
commit b3b1151a1d
2 changed files with 302 additions and 17 deletions

View File

@@ -1,31 +1,52 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import React, {
useCallback,
// 디버그 모드 설정 - true일 때만 console.log 출력 useEffect,
const DEBUG_MODE = false; useMemo,
useRef,
useState,
} from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux'; import {
useDispatch,
useSelector,
} from 'react-redux';
import Spotlight from '@enact/spotlight'; import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable'; import Spottable from '@enact/spotlight/Spottable';
import { getContainerId } from '@enact/spotlight/src/container'; import { getContainerId } from '@enact/spotlight/src/container';
import btnPlay from '../../../../assets/images/btn/btn-play-thumb-nor.png'; import btnPlay from '../../../../assets/images/btn/btn-play-thumb-nor.png';
import defaultLogoImg from '../../../../assets/images/ic-tab-partners-default@3x.png'; import defaultLogoImg
import emptyHorImage from '../../../../assets/images/img-home-banner-empty-hor.png'; from '../../../../assets/images/ic-tab-partners-default@3x.png';
import emptyVerImage from '../../../../assets/images/img-home-banner-empty-ver.png'; import emptyHorImage
import defaultImageItem from '../../../../assets/images/img-thumb-empty-product@3x.png'; 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 liveShow from '../../../../assets/images/tag-liveshow.png';
import { changeAppStatus } from '../../../actions/commonActions'; import { changeAppStatus } from '../../../actions/commonActions';
import { updateHomeInfo, setVideoTransitionLock } from '../../../actions/homeActions'; import {
import { sendLogTopContents, sendLogTotalRecommend } from '../../../actions/logActions'; setVideoTransitionLock,
import { pushPanel, navigateFromRandomUnit, SOURCE_MENUS } from '../../../actions/panelActions'; updateHomeInfo,
} from '../../../actions/homeActions';
import {
sendLogTopContents,
sendLogTotalRecommend,
} from '../../../actions/logActions';
import {
navigateFromRandomUnit,
pushPanel,
SOURCE_MENUS,
} from '../../../actions/panelActions';
import { import {
finishVideoPreview, finishVideoPreview,
hideModalVideo,
startVideoPlayer, startVideoPlayer,
startVideoPlayerNew, startVideoPlayerNew,
hideModalVideo,
} from '../../../actions/playActions'; } from '../../../actions/playActions';
import CustomImage from '../../../components/CustomImage/CustomImage'; import CustomImage from '../../../components/CustomImage/CustomImage';
import usePriceInfo from '../../../hooks/usePriceInfo'; import usePriceInfo from '../../../hooks/usePriceInfo';
@@ -36,11 +57,19 @@ import {
LOG_TP_NO, LOG_TP_NO,
panel_names, panel_names,
} from '../../../utils/Config'; } from '../../../utils/Config';
import { selectIsPlaying } from '../../../utils/playerState/playerStateSelectors'; import {
import { $L, formatGMTString } from '../../../utils/helperMethods'; $L,
formatGMTString,
} from '../../../utils/helperMethods';
import {
selectIsPlaying,
} from '../../../utils/playerState/playerStateSelectors';
import { TEMPLATE_CODE_CONF } from '../HomePanel'; import { TEMPLATE_CODE_CONF } from '../HomePanel';
import css from './RandomUnit.module.less'; import css from './RandomUnit.module.less';
// 디버그 모드 설정 - true일 때만 console.log 출력
const DEBUG_MODE = false;
const SpottableComponent = Spottable('div'); const SpottableComponent = Spottable('div');
const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div'); const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
@@ -66,6 +95,7 @@ export default function RandomUnit({
const homeCategory = useSelector((state) => state.home.menuData?.data?.homeCategory); const homeCategory = useSelector((state) => state.home.menuData?.data?.homeCategory);
const countryCode = useSelector((state) => state.common.httpHeader.cntry_cd); const countryCode = useSelector((state) => state.common.httpHeader.cntry_cd);
const foryouInfos = useSelector((state) => state.foryou.recommendInfo.recommendProduct);
// 현재 재생 중인 비디오 배너 ID 가져오기 // 현재 재생 중인 비디오 배너 ID 가져오기
const currentVideoBannerId = useSelector((state) => { const currentVideoBannerId = useSelector((state) => {
@@ -490,6 +520,14 @@ export default function RandomUnit({
}; };
break; break;
case 'DSP00510':
linkInfo = {
name: panel_names.JUST_FOR_YOU_TEST_PANEL,
panelInfo: {
},
};
break;
default: default:
linkInfo = { linkInfo = {
name: panel_names.HOME_PANEL, name: panel_names.HOME_PANEL,
@@ -644,6 +682,29 @@ export default function RandomUnit({
const { originalPrice, discountedPrice, discountRate, offerInfo } = const { originalPrice, discountedPrice, discountRate, offerInfo } =
usePriceInfo(priceInfos) || {}; usePriceInfo(priceInfos) || {};
// Just For You 데이터에서 첫 번째 상품 추출
const justForYouProduct = useMemo(() => {
if (foryouInfos && foryouInfos.length > 0) {
const justForYouShelf = foryouInfos.find(
(shelf) => shelf.recommendTpCd === 'JUSTFORYOU'
);
if (justForYouShelf && justForYouShelf.productInfos && justForYouShelf.productInfos.length > 0) {
return justForYouShelf.productInfos[0];
}
}
return null;
}, [foryouInfos]);
// Just For You 상품의 가격 정보
const justForYouPriceInfo = usePriceInfo(
justForYouProduct && justForYouProduct.priceInfo ? justForYouProduct.priceInfo : ''
) || {
originalPrice: '',
discountedPrice: '',
discountRate: null,
offerInfo: '',
};
// 로그 // 로그
useEffect(() => { useEffect(() => {
let _nowMenu = nowMenu; let _nowMenu = nowMenu;
@@ -999,7 +1060,72 @@ export default function RandomUnit({
/> />
</div> </div>
</SpottableComponent> </SpottableComponent>
) : null} )
: randomData?.shptmBanrTpNm == "Just For You" ? (
{/* <SpottableComponent
className={classNames(
css.itemBox,
css.justforyou,
countryCode === 'RU' ? css.ru : '',
countryCode === 'DE' ? css.de : '',
isHorizontal && css.isHorizontal
)}
onClick={todayDealClick}
spotlightId={spotlightId}
aria-label={justForYouProduct?.prdtNm ? justForYouProduct?.prdtNm : randomData.tmnlImgNm}
>
<div className={css.productInfo}>
<div className={css.justforyouTitle}>{$L("Just For You")}</div>
<div
className={css.textBox}
dangerouslySetInnerHTML={{
__html: `${justForYouProduct?.prdtNm || randomData.prdtNm}`,
}}
/>
<div className={css.accBox}>
{justForYouProduct ? (
<>
{parseFloat(justForYouPriceInfo.originalPrice?.replace('$', '') || '0') === 0
? justForYouProduct.offerInfo
: justForYouPriceInfo.discountRate
? justForYouPriceInfo.discountedPrice
: justForYouPriceInfo.originalPrice}
{justForYouPriceInfo.discountRate && !isHorizontal && (
<span className={css.saleAccBox}>{justForYouPriceInfo.originalPrice}</span>
)}
</>
) : (
<>
{parseFloat(originalPrice?.replace('$', '') || '0') === 0
? randomData?.offerInfo
: discountRate
? discountedPrice
: originalPrice}
{discountRate && !isHorizontal && (
<span className={css.saleAccBox}>{originalPrice}</span>
)}
</>
)}
</div>
{isHorizontal && justForYouProduct && parseFloat(justForYouPriceInfo.originalPrice?.replace('$', '') || '0') !== 0 && (
<span className={css.saleAccBox}>{justForYouPriceInfo.originalPrice}</span>
)}
</div>
<div className={css.itemImgBox}>
<CustomImage
delay={0}
src={justForYouProduct?.imgUrl || randomData.tmnlImgPath}
animationSpeed="fast"
fallbackSrc={defaultImageItem}
ariaLabel={justForYouProduct?.prdtNm || randomData.tmnlImgNm}
/>
</div>
</SpottableComponent> */}
)
: null}
</Container> </Container>
</> </>
); );

View File

@@ -233,6 +233,165 @@
left: -4px; left: -4px;
} }
} }
&.justforyou {
background-image: url(../../../../assets/images/img-home-banner-jfy-ver@3x.png);
background-size: 486px 858px;
background-position: left top;
border-radius: 10px;
padding: 75px 51px 0;
&.ru {
.productInfo {
.justforyouTitle {
font-size: 58px;
line-height: 60px;
font-family: @arialFontBold;
}
}
}
&.de {
.productInfo {
.justforyouTitle {
font-size: 74px !important;
line-height: 63px !important;
letter-spacing: -1px !important;
}
}
}
.productInfo {
margin-bottom: 31px;
.justforyouTitle {
.size(@w:100%,@h:132px);
font-family: Arial;
font-weight: bold;
font-size: 80px;
word-break: break-word;
font-stretch: normal;
color: #151515;
text-align: center;
line-height: 76px;
font-family: @arialFontBold;
}
.textBox {
.size(@w: 100%, @h: 80px);
margin-top: 71px;
.elip(@clamp:2);
font-weight: bold;
font-size: 30px;
color: @COLOR_GRAY06;
line-height: 1.27;
margin-bottom: 6px;
}
.accBox {
width: 100%;
text-align: center;
font-weight: bold;
font-size: 42px;
color: @PRIMARY_COLOR_RED;
line-height: 1.14;
display: inline-block;
.elip(@clamp:1);
> strong {
width: 260px;
font-size: 30px;
line-height: 1.27;
display: block;
.elip(@clamp:2);
}
.saleAccBox {
font-weight: normal;
font-size: 24px;
color: @COLOR_GRAY04;
vertical-align: middle;
text-decoration: line-through;
margin-left: 9px;
display: inline-block;
}
}
}
.itemImgBox {
> img {
.size(@w: 356px, @h: 356px);
border-radius: 12px;
border:6px solid #DCB9A1;
box-sizing: content-box;
}
}
&.isHorizontal {
background-image: url(../../../../assets/images/img-home-banner-jfy-hor@3x.png);
background-size: 744px 420px;
background-position: center center;
display: flex;
padding: 0 30px 0 0;
border-radius: 10px;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
-o-border-radius: 10px;
> div {
flex: none;
}
&.ru {
.productInfo {
.justforyouTitle {
font-size: 58px;
line-height: 60px;
font-family: @arialFontBold;
}
}
}
&.de {
.productInfo {
.justforyouTitle {
font-size: 59px !important;
line-height: 63px !important;
letter-spacing: -2px !important;
}
}
}
.productInfo {
margin-bottom: 0;
.justforyouTitle {
.size(@w:305px,@h:114px);
margin-top: 53px;
margin-left: 49px;
font-size: 66px;
word-break: break-word;
color: #151515;
text-align: left;
line-height: 57px;
font-family: @arialBlack;
}
.textBox {
.size(@w: 294px, @h: 80px);
margin: 67px 0 5px 50px;
text-align: left;
}
.accBox {
.size(@w: 320px, @h: 50px);
margin-left: 50px;
text-align: left;
display: block;
.elip(@clamp:1);
}
.saleAccBox {
color: #767676;
display: block;
text-align: left;
margin: 5px 0 0 55px;
text-decoration: line-through;
}
}
.itemImgBox {
.position(@position: absolute, @top: 47px, @left: 389px);
.size(@w: 326px, @h: 326px);
> img {
.size(@w: inherit, @h: inherit);
border-radius: 12px;
border:6px solid #DCB9A1;
box-sizing: content-box;
}
}
}
}
} }
.arrow { .arrow {