[For You] 부분 처리건
1. 홈배너 노출부분. 2. 롤링배너에 노출시에 아이템 갯수별로 노출시 스타일 피그마랑 맞춤. 3. 저스트포유패널생성및 연결 - 피그마에는 따로 사이드바가 보이지않아 이부분은 월요일에 물어보고 처리해야할것같습니다. - 디자인만 우선 넣어둠.(좌우 스크롤이 정상작동하지않음) - 상품 컴포넌트 분리 필요 - 첫번째 타이틀이 흰색으로 처리되어있는데 이부분 스크롤시에 어떤식으로 생각하고 한부분인지 물어보고 처리필요.
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 3.8 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
BIN
com.twin.app.shoptime/assets/images/homebanner/items/coffee.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
com.twin.app.shoptime/assets/images/homebanner/items/cream.jpg
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
com.twin.app.shoptime/assets/images/homebanner/items/pizza.jpg
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
com.twin.app.shoptime/assets/images/homebanner/items/salmon.jpg
Normal file
|
After Width: | Height: | Size: 55 KiB |
9
com.twin.app.shoptime/src/components/TItemCard/Tag.jsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
import styles from './Tag.module.less';
|
||||
|
||||
const Tag = ({ text }) => {
|
||||
return <span className={styles.tag}>{text}</span>;
|
||||
};
|
||||
|
||||
export default Tag;
|
||||
@@ -0,0 +1,17 @@
|
||||
@import "../../style/CommonStyle.module.less";
|
||||
@import "../../style/utils.module.less";
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
background: @PRIMARY_COLOR_RED;
|
||||
color: #fff;
|
||||
border-radius: 5px;
|
||||
font-size: 21px;
|
||||
font-weight: 700;
|
||||
padding: 2px 6px;
|
||||
margin-bottom: 6px;
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
top: 30px;
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -4,41 +4,50 @@ import React, {
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
} from 'react';
|
||||
|
||||
import classNames from "classnames";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
|
||||
//아이콘
|
||||
import { Job } from "@enact/core/util";
|
||||
import { Job } from '@enact/core/util';
|
||||
//enact
|
||||
import Skinnable from "@enact/sandstone/Skinnable";
|
||||
import Spotlight from "@enact/spotlight";
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
import { Cancelable } from "@enact/ui/Cancelable";
|
||||
import Skinnable from '@enact/sandstone/Skinnable';
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import SpotlightContainerDecorator
|
||||
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import { Cancelable } from '@enact/ui/Cancelable';
|
||||
|
||||
import shoptimeFullIconRuc from "../../../assets/images/icons/ic-lnb-logo-shoptime-ruc-white.png";
|
||||
import shoptimeFullIconRuc
|
||||
from '../../../assets/images/icons/ic-lnb-logo-shoptime-ruc-white.png';
|
||||
//이미지
|
||||
import shoptimeFullIcon from "../../../assets/images/icons/ic-lnb-logo-shoptime@3x.png";
|
||||
import { gnbOpened } from "../../actions/commonActions";
|
||||
import { checkEnterThroughGNB, resetHomeInfo } from "../../actions/homeActions";
|
||||
import { resetPanels } from "../../actions/panelActions";
|
||||
import usePrevious from "../../hooks/usePrevious";
|
||||
import useScrollTo from "../../hooks/useScrollTo";
|
||||
import { panel_names } from "../../utils/Config";
|
||||
import { SpotlightIds } from "../../utils/SpotlightIds";
|
||||
import TScroller from "../TScroller/TScroller";
|
||||
import CategoryIcon from "./iconComponents/CategoryIcon";
|
||||
import FeaturedBrandIcon from "./iconComponents/FeaturedBrandIcon";
|
||||
import HomeIcon from "./iconComponents/HomeIcon";
|
||||
import HotPicksIcon from "./iconComponents/HotPicksIcon";
|
||||
import MyPageIcon from "./iconComponents/MyPageIcon";
|
||||
import OnSaleIcon from "./iconComponents/OnSaleIcon";
|
||||
import SearchIcon from "./iconComponents/SearchIcon";
|
||||
import TrendingNowIcon from "./iconComponents/TrendingNowIcon";
|
||||
import TabItem from "./TabItem";
|
||||
import TabItemSub from "./TabItemSub";
|
||||
import css from "./TabLayout.module.less";
|
||||
import shoptimeFullIcon
|
||||
from '../../../assets/images/icons/ic-lnb-logo-shoptime@3x.png';
|
||||
import { gnbOpened } from '../../actions/commonActions';
|
||||
import {
|
||||
checkEnterThroughGNB,
|
||||
resetHomeInfo,
|
||||
} from '../../actions/homeActions';
|
||||
import { resetPanels } from '../../actions/panelActions';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import useScrollTo from '../../hooks/useScrollTo';
|
||||
import { panel_names } from '../../utils/Config';
|
||||
import { SpotlightIds } from '../../utils/SpotlightIds';
|
||||
import TScroller from '../TScroller/TScroller';
|
||||
import CategoryIcon from './iconComponents/CategoryIcon';
|
||||
import FeaturedBrandIcon from './iconComponents/FeaturedBrandIcon';
|
||||
import HomeIcon from './iconComponents/HomeIcon';
|
||||
import HotPicksIcon from './iconComponents/HotPicksIcon';
|
||||
import MyPageIcon from './iconComponents/MyPageIcon';
|
||||
import OnSaleIcon from './iconComponents/OnSaleIcon';
|
||||
import SearchIcon from './iconComponents/SearchIcon';
|
||||
import TrendingNowIcon from './iconComponents/TrendingNowIcon';
|
||||
import TabItem from './TabItem';
|
||||
import TabItemSub from './TabItemSub';
|
||||
import css from './TabLayout.module.less';
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ enterTo: "default-element" },
|
||||
@@ -122,6 +131,7 @@ const PANELS_HAS_TAB = [
|
||||
panel_names.ON_SALE_PANEL,
|
||||
panel_names.SEARCH_PANEL,
|
||||
panel_names.TRENDING_NOW_PANEL,
|
||||
panel_names.JUST_FOR_YOU_PANEL,
|
||||
];
|
||||
|
||||
export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
|
||||
@@ -31,6 +31,7 @@ export const panel_names = {
|
||||
IMAGE_PANEL: "imagepanel",
|
||||
SERVICE_UNAVAILABLE: "servicepanel",
|
||||
OPTIONAL_TERMS_PANEL: "optionaltermspanel", // 선택약관 Intro Panel
|
||||
JUST_FOR_YOU_PANEL: "justforyoupanel", //justforyou
|
||||
// error
|
||||
ERROR_PANEL: "errorpanel",
|
||||
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
//temperary module less file
|
||||
//done API, this file will be deleted or moved to other file
|
||||
|
||||
@import "../../../style/CommonStyle.module.less";
|
||||
@import "../../../style/utils.module.less";
|
||||
|
||||
.JustForYouBanner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
.imageContainer {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent 60%,
|
||||
rgba(0, 0, 0, 0.7) 100%
|
||||
);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.contentOverlay {
|
||||
position: absolute;
|
||||
top: 20%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
|
||||
.todaysDealTitle {
|
||||
position: relative;
|
||||
font-size: 58px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
color: #d13b3b;
|
||||
font-family: "LG Smart UI";
|
||||
text-align: center;
|
||||
}
|
||||
.todaysDealTitle::before {
|
||||
z-index: -1;
|
||||
content: attr(data-content);
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
-webkit-text-stroke: 10px @COLOR_WHITE;
|
||||
}
|
||||
|
||||
.accBox {
|
||||
background-color: fade(@COLOR_WHITE, 30%);
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
margin: 20px auto;
|
||||
|
||||
.textBox {
|
||||
font-size: 24px;
|
||||
color: @COLOR_GRAY06;
|
||||
font-family: "LG Smart UI";
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.itemImgBox {
|
||||
position: absolute;
|
||||
bottom: 50px;
|
||||
left: 90px;
|
||||
width: 305px;
|
||||
height: 307px;
|
||||
z-index: 1;
|
||||
.imageLayout {
|
||||
.imageItemBox {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
.imageItem10 {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
&.imageLayout2 {
|
||||
display: flex;
|
||||
.imageItemBox {
|
||||
max-width: 147.5px;
|
||||
height: 307px;
|
||||
margin-right: 10px;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.imageLayout3 {
|
||||
display: flex;
|
||||
flex-wrap: wrap; /* 줄 바꿈 허용 */
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
width: 305px;
|
||||
height: 307px;
|
||||
.imageItemBox {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.imageItemBox:nth-child(3n + 1) {
|
||||
width: 305px;
|
||||
height: 148.5px;
|
||||
flex: 0 0 auto;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.imageItemBox:nth-child(3n + 2),
|
||||
.imageItemBox:nth-child(3n + 3) {
|
||||
width: 147.5px;
|
||||
height: 148.5px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.imageItemBox:nth-child(3n + 2) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
&.imageLayout4 {
|
||||
display: flex;
|
||||
flex-wrap: wrap; /* 줄 바꿈 허용 */
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
width: 305px;
|
||||
height: 307px;
|
||||
.imageItemBox {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 147.5px;
|
||||
height: 148.5px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.imageItemBox:nth-child(4n + 1),
|
||||
.imageItemBox:nth-child(4n + 2) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.imageItemBox:nth-child(4n + 1),
|
||||
.imageItemBox:nth-child(4n + 3) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,60 @@
|
||||
// src/views/HomePanel/HomeBanner/HomeBanner.jsx
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
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 { $L } from "../../../utils/helperMethods";
|
||||
import {
|
||||
setDefaultFocus,
|
||||
// setShowPopup,
|
||||
fetchCurrentUserHomeTerms,
|
||||
} from "../../../actions/homeActions";
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import {
|
||||
SpotlightContainerDecorator,
|
||||
} from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
|
||||
import {
|
||||
changeAppStatus,
|
||||
setOptionalTermsPopupShown,
|
||||
setOptionalTermsUserDecision,
|
||||
handleOptionalTermsAgree as handleOptionalTermsAgreeAction,
|
||||
handleOptionalTermsDecline,
|
||||
setOptionalTermsPopupShown,
|
||||
setOptionalTermsUserDecision,
|
||||
updateOptionalTermsAgreement,
|
||||
} from "../../../actions/commonActions";
|
||||
import { setMyPageTermsAgree } from "../../../actions/myPageActions";
|
||||
import { pushPanel, popPanel } from "../../../actions/panelActions";
|
||||
import { panel_names } from "../../../utils/Config";
|
||||
} from '../../../actions/commonActions';
|
||||
import {
|
||||
fetchCurrentUserHomeTerms,
|
||||
setDefaultFocus,
|
||||
} from '../../../actions/homeActions';
|
||||
import { setMyPageTermsAgree } from '../../../actions/myPageActions';
|
||||
import {
|
||||
popPanel,
|
||||
pushPanel,
|
||||
} from '../../../actions/panelActions';
|
||||
import {
|
||||
startVideoPlayer,
|
||||
requestPlayControl,
|
||||
releasePlayControl,
|
||||
} from "../../../actions/playActions";
|
||||
import CustomImage from "../../../components/CustomImage/CustomImage";
|
||||
import css from "./HomeBanner.module.less";
|
||||
import Random from "./RandomUnit";
|
||||
import Rolling from "./RollingUnit";
|
||||
import TNewPopUp from "../../../components/TPopUp/TNewPopUp";
|
||||
requestPlayControl,
|
||||
startVideoPlayer,
|
||||
} from '../../../actions/playActions';
|
||||
import CustomImage from '../../../components/CustomImage/CustomImage';
|
||||
// import TButtonScroller from "../../../components/TButtonScroller/TButtonScroller";
|
||||
import OptionalConfirm from "../../../components/Optional/OptionalConfirm";
|
||||
import OptionalConfirm from '../../../components/Optional/OptionalConfirm';
|
||||
import TNewPopUp from '../../../components/TPopUp/TNewPopUp';
|
||||
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 RandomUnitNew from "./RandomUnit.new";
|
||||
import SimpleVideoContainer from "./SimpleVideoContainer";
|
||||
import PersistentVideoUnit from './PersistentVideoUnit';
|
||||
import JustForSwitchBanner from './RandomBannerType/JustForYouBanner';
|
||||
import Random from './RandomUnit';
|
||||
import RandomUnitNew from './RandomUnit.new';
|
||||
import Rolling from './RollingUnit';
|
||||
import SimpleVideoContainer from './SimpleVideoContainer';
|
||||
|
||||
const SpottableComponent = Spottable("div");
|
||||
const Container = SpotlightContainerDecorator(
|
||||
@@ -647,7 +661,20 @@ export default function HomeBanner({
|
||||
{renderItem(1, true)}
|
||||
</ContainerBasic>
|
||||
{renderItem(2, false)}
|
||||
{renderItem(3, false)}
|
||||
{/* //NOTE - 약관 동의 여부 & 추후 API 따라 팝업 표시 여부 결정 */}
|
||||
{introTermsAgree ? (
|
||||
<div className={css.imgBox}>
|
||||
<JustForSwitchBanner
|
||||
renderItem={renderItem}
|
||||
handleShelfFocus={_handleShelfFocus}
|
||||
handleItemFocus={_handleItemFocus}
|
||||
isHorizontal={false}
|
||||
spotlightId={"banner3"}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
renderItem(3, false)
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
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 justforyou
|
||||
from '../../../../../assets/images/homebanner/img-home-banner-jfy-4x.png';
|
||||
import coffeeImage
|
||||
from '../../../../../assets/images/homebanner/items/coffee.jpg';
|
||||
import creamImage
|
||||
from '../../../../../assets/images/homebanner/items/cream.jpg';
|
||||
import pizzaImage
|
||||
from '../../../../../assets/images/homebanner/items/pizza.jpg';
|
||||
import salmonImage
|
||||
from '../../../../../assets/images/homebanner/items/salmon.jpg';
|
||||
import { pushPanel } from '../../../../actions/panelActions';
|
||||
import CustomImage from '../../../../components/CustomImage/CustomImage';
|
||||
import { panel_names } from '../../../../utils/Config';
|
||||
import cssBannerUnit from '../BannerUnit.module.less';
|
||||
import css from '../RollingUnit.module.less';
|
||||
|
||||
const SpottableComponent = Spottable("div");
|
||||
|
||||
// JustForYou 배너 컴포넌트
|
||||
function JustForYouBanner({
|
||||
onClick,
|
||||
spotlightId,
|
||||
onFocus,
|
||||
isHorizontal,
|
||||
popupVisible,
|
||||
activePopup,
|
||||
}) {
|
||||
const [imagesLoaded, setImagesLoaded] = useState(false);
|
||||
const loadedImages = useRef(new Set());
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
//NOTE - 임시 데이터 추후 API 연동 필요
|
||||
const recentlyProductsData = useMemo(
|
||||
() => [
|
||||
{
|
||||
src: creamImage,
|
||||
alt: "Product 1",
|
||||
},
|
||||
{
|
||||
src: pizzaImage,
|
||||
alt: "Product 4",
|
||||
},
|
||||
{
|
||||
src: coffeeImage,
|
||||
alt: "Product 2",
|
||||
},
|
||||
{
|
||||
src: salmonImage,
|
||||
alt: "Product 3",
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const handleImageLoad = useCallback(
|
||||
(src) => {
|
||||
loadedImages.current.add(src);
|
||||
if (loadedImages.current.size === recentlyProductsData.length) {
|
||||
setImagesLoaded(true);
|
||||
}
|
||||
},
|
||||
[recentlyProductsData.length]
|
||||
);
|
||||
|
||||
const preloadImages = recentlyProductsData.map((imageData) => (
|
||||
<CustomImage
|
||||
key={imageData.src}
|
||||
src={imageData.src}
|
||||
style={{ display: "none" }}
|
||||
onLoad={() => handleImageLoad(imageData.src)}
|
||||
/>
|
||||
));
|
||||
|
||||
return (
|
||||
<Container
|
||||
className={classNames(
|
||||
css.rollingWrap,
|
||||
isHorizontal && css.isHorizontalWrap
|
||||
)}
|
||||
>
|
||||
<SpottableComponent
|
||||
className={css.itemBox}
|
||||
onClick={onClick}
|
||||
spotlightId={spotlightId}
|
||||
onFocus={onFocus}
|
||||
popupVisible={popupVisible}
|
||||
activePopup={activePopup}
|
||||
>
|
||||
{!imagesLoaded && preloadImages}
|
||||
|
||||
<div
|
||||
className={classNames(
|
||||
cssBannerUnit.JustForYouBanner,
|
||||
isHorizontal && cssBannerUnit.isHorizontal
|
||||
)}
|
||||
>
|
||||
<div className={cssBannerUnit.imageContainer}>
|
||||
<CustomImage src={justforyou} animationSpeed="none" />
|
||||
</div>
|
||||
|
||||
<div className={cssBannerUnit.itemImgBox}>
|
||||
{/* {imagesLoaded && <TImageGrid images={recentlyProductsData} />} */}
|
||||
|
||||
<div
|
||||
className={classNames(
|
||||
cssBannerUnit.imageLayout,
|
||||
cssBannerUnit.imageLayout + recentlyProductsData.length
|
||||
)}
|
||||
>
|
||||
{recentlyProductsData.map((img, index) => (
|
||||
<div className={cssBannerUnit.imageItemBox}>
|
||||
<img
|
||||
key={index}
|
||||
src={img.src}
|
||||
alt={`item-${index}`}
|
||||
className={classNames(
|
||||
cssBannerUnit.imageItem,
|
||||
cssBannerUnit.imageItem +
|
||||
recentlyProductsData.legnth +
|
||||
index
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SpottableComponent>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default function JustForSwitchBanner({
|
||||
renderItem,
|
||||
handleShelfFocus,
|
||||
handleItemFocus,
|
||||
isHorizontal,
|
||||
spotlightId,
|
||||
}) {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const bannerCount = 2;
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { popupVisible, activePopup } = useSelector(
|
||||
(state) => state.common.popup
|
||||
);
|
||||
|
||||
const handlePrev = useCallback(() => {
|
||||
setCurrentIndex((prevIndex) =>
|
||||
prevIndex === 0 ? bannerCount - 1 : prevIndex - 1
|
||||
);
|
||||
}, []);
|
||||
|
||||
const handleNext = useCallback(() => {
|
||||
setCurrentIndex((prevIndex) =>
|
||||
prevIndex === bannerCount - 1 ? 0 : prevIndex + 1
|
||||
);
|
||||
}, []);
|
||||
|
||||
const onFocus = useCallback(() => {
|
||||
if (handleItemFocus) {
|
||||
handleItemFocus();
|
||||
}
|
||||
}, [handleItemFocus]);
|
||||
|
||||
const shelfFocus = useCallback(() => {
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: panel_names.JUST_FOR_YOU_PANEL,
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
css.rollingWrap,
|
||||
isHorizontal && css.isHorizontalWrap
|
||||
)}
|
||||
>
|
||||
<SpottableComponent
|
||||
className={classNames(css.arrow, css.leftBtn)}
|
||||
onClick={handlePrev}
|
||||
spotlightId={spotlightId + "Prev"}
|
||||
aria-label="Move to left Button"
|
||||
/>
|
||||
|
||||
{currentIndex === 0 ? (
|
||||
<JustForYouBanner
|
||||
spotlightId={spotlightId}
|
||||
onFocus={onFocus}
|
||||
isHorizontal={isHorizontal}
|
||||
popupVisible={popupVisible}
|
||||
activePopup={activePopup}
|
||||
onClick={shelfFocus}
|
||||
/>
|
||||
) : (
|
||||
renderItem(3, false)
|
||||
)}
|
||||
|
||||
<SpottableComponent
|
||||
className={classNames(css.arrow, css.rightBtn)}
|
||||
onClick={handleNext}
|
||||
spotlightId={spotlightId + "Next"}
|
||||
aria-label="Move to right Button"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
@import "../../../style/CommonStyle.module.less";
|
||||
@import "../../../style/utils.module.less";
|
||||
|
||||
.forYouItemWrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 438px;
|
||||
margin-right: 18px;
|
||||
flex: none;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
.recommendBadge {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
z-index: 1;
|
||||
width: 120px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.forYouCardWrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
|
||||
import TForYouCard from '../../../components/TForYouCard/TForYouCard';
|
||||
import TItemCard from '../../../components/TItemCard/TItemCard';
|
||||
import {
|
||||
LOG_CONTEXT_NAME,
|
||||
LOG_MESSAGE_ID,
|
||||
} from '../../../utils/Config';
|
||||
import css from './ForYouItems.module.less';
|
||||
|
||||
const ForYouWrapper = ({
|
||||
bestSellerData,
|
||||
spotlightId,
|
||||
shelfLocation,
|
||||
shelfTitle,
|
||||
handleFocus,
|
||||
handleBlur,
|
||||
handleCardClick,
|
||||
}) => {
|
||||
const lastItem = bestSellerData[bestSellerData.length - 1];
|
||||
|
||||
return (
|
||||
<div className={css.forYouItemWrapper}>
|
||||
<div className={css.recommendBadge}>
|
||||
<TForYouCard />
|
||||
</div>
|
||||
<TItemCard
|
||||
key={"lastItem"}
|
||||
contextName={LOG_CONTEXT_NAME.HOME}
|
||||
messageId={LOG_MESSAGE_ID.SHELF_CLICK}
|
||||
order={bestSellerData.length}
|
||||
shelfId={spotlightId}
|
||||
shelfLocation={shelfLocation}
|
||||
shelfTitle={shelfTitle}
|
||||
patnerName={lastItem.patncNm}
|
||||
brandName={lastItem.brndNm}
|
||||
catNm={lastItem.catNm}
|
||||
imageAlt={lastItem.prdtId}
|
||||
imageSource={lastItem.imgUrl}
|
||||
priceInfo={lastItem.priceInfo}
|
||||
productName={lastItem.prdtNm}
|
||||
isBestSeller={true}
|
||||
productId={lastItem.prdtId}
|
||||
onFocus={handleFocus(bestSellerData.length - 1)}
|
||||
onBlur={handleBlur(bestSellerData.length - 1)}
|
||||
onClick={handleCardClick(lastItem.patnrId, lastItem.prdtId)}
|
||||
offerInfo={lastItem.offerInfo}
|
||||
spotlightId={"bestsellerLastItem"}
|
||||
firstLabel={lastItem.rankOrd + "th"}
|
||||
label={"Last item"}
|
||||
lastLabel=" go to detail, button"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ForYouWrapper;
|
||||
@@ -0,0 +1,258 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
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 {
|
||||
pushPanel,
|
||||
updatePanel,
|
||||
} from '../../../actions/panelActions';
|
||||
import SectionTitle from '../../../components/SectionTitle/SectionTitle';
|
||||
import TItemCard from '../../../components/TItemCard/TItemCard';
|
||||
import TScroller from '../../../components/TScroller/TScroller';
|
||||
import useScrollReset from '../../../hooks/useScrollReset';
|
||||
import useScrollTo from '../../../hooks/useScrollTo';
|
||||
import {
|
||||
LOG_CONTEXT_NAME,
|
||||
LOG_MESSAGE_ID,
|
||||
panel_names,
|
||||
} from '../../../utils/Config';
|
||||
import {
|
||||
$L,
|
||||
scaleW,
|
||||
} from '../../../utils/helperMethods';
|
||||
import { SpotlightIds } from '../../../utils/SpotlightIds';
|
||||
import css from './PickedForYou.module.less';
|
||||
|
||||
const SpottableComponent = Spottable("div");
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
const PickedForYou = ({
|
||||
order,
|
||||
scrollTopBody,
|
||||
spotlightId,
|
||||
handleItemFocus,
|
||||
handleShelfFocus,
|
||||
shelfLocation,
|
||||
shelfTitle,
|
||||
}) => {
|
||||
console.log("###Test pjh 여기지 ?");
|
||||
const { getScrollTo, scrollLeft } = useScrollTo();
|
||||
const { handleScrollReset, handleStopScrolling } = useScrollReset(
|
||||
scrollLeft,
|
||||
true
|
||||
);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { cursorVisible } = useSelector((state) => state.common.appStatus);
|
||||
|
||||
const justForYouDatas = useSelector(
|
||||
(state) => state.product.bestSellerData?.bestSeller
|
||||
);
|
||||
|
||||
const [drawChk, setDrawChk] = useState(false);
|
||||
const [firstChk, setFirstChk] = useState(0);
|
||||
|
||||
const orderStyle = useMemo(() => ({ order: order }), [order]);
|
||||
|
||||
useEffect(() => {
|
||||
setDrawChk(true);
|
||||
}, [justForYouDatas]);
|
||||
|
||||
const handleCardClick = useCallback(
|
||||
(patnrId, prdtId) => () => {
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: panel_names.DETAIL_PANEL,
|
||||
panelInfo: {
|
||||
patnrId: patnrId,
|
||||
prdtId: prdtId,
|
||||
nowShelf: spotlightId,
|
||||
},
|
||||
})
|
||||
);
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const handleMoreCardClick = useCallback(() => {
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: panel_names.TRENDING_NOW_PANEL,
|
||||
panelInfo: {
|
||||
pageName: "BS",
|
||||
focusedContainerId: SpotlightIds.TRENDING_NOW_BEST_SELLER,
|
||||
},
|
||||
})
|
||||
);
|
||||
}, [dispatch]);
|
||||
|
||||
const handleBlur = useCallback(
|
||||
(itemIndex) => () => {
|
||||
if (itemIndex === 0) {
|
||||
handleStopScrolling();
|
||||
}
|
||||
},
|
||||
[handleStopScrolling]
|
||||
);
|
||||
|
||||
const handleFocus = useCallback(
|
||||
(itemIndex) => () => {
|
||||
_handleItemFocus();
|
||||
|
||||
if (itemIndex === 0) {
|
||||
handleScrollReset();
|
||||
}
|
||||
|
||||
if (firstChk === 0 && itemIndex === 0) {
|
||||
const c = Spotlight.getCurrent();
|
||||
if (c) {
|
||||
let cAriaLabel = c.getAttribute("aria-label");
|
||||
cAriaLabel = "Best Seller, Heading 1," + cAriaLabel;
|
||||
c.setAttribute("aria-label", cAriaLabel);
|
||||
}
|
||||
setFirstChk(1);
|
||||
} else if (firstChk === 1 && itemIndex === 0) {
|
||||
const c = Spotlight.getCurrent();
|
||||
if (c) {
|
||||
let cAriaLabel = c.getAttribute("aria-label");
|
||||
if (cAriaLabel) {
|
||||
const newcAriaLabel = cAriaLabel.replace(
|
||||
"Best Seller, Heading 1,",
|
||||
""
|
||||
);
|
||||
c.setAttribute("aria-label", newcAriaLabel);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cursorVisible) {
|
||||
return;
|
||||
}
|
||||
},
|
||||
[cursorVisible, _handleItemFocus, handleScrollReset, scrollTopBody]
|
||||
);
|
||||
|
||||
const handleScrollRight = (e) => {
|
||||
const container = e.currentTarget?.parentNode;
|
||||
const x = container.scrollWidth - container.clientWidth + 60;
|
||||
|
||||
setTimeout(() => {
|
||||
scrollLeft({ x, animate: true });
|
||||
});
|
||||
};
|
||||
|
||||
const _handleItemFocus = useCallback(() => {
|
||||
if (handleItemFocus) {
|
||||
handleItemFocus();
|
||||
}
|
||||
}, [handleItemFocus]);
|
||||
|
||||
const _handleShelfFocus = useCallback(() => {
|
||||
if (handleShelfFocus) {
|
||||
handleShelfFocus();
|
||||
}
|
||||
}, [handleShelfFocus]);
|
||||
|
||||
return (
|
||||
<Container
|
||||
className={css.bestSellerWrap}
|
||||
style={orderStyle}
|
||||
spotlightId={spotlightId}
|
||||
data-wheel-point={true}
|
||||
onFocus={_handleShelfFocus}
|
||||
>
|
||||
<SectionTitle
|
||||
title={$L("PICKED FOR YOU")}
|
||||
data-title-index="homeBestSellerTitle"
|
||||
label="PICKED FOR YOU"
|
||||
/>
|
||||
|
||||
<TScroller
|
||||
className={css.homeBestSeller}
|
||||
direction="horizontal"
|
||||
cbScrollTo={getScrollTo}
|
||||
noScrollByWheel
|
||||
>
|
||||
{justForYouDatas &&
|
||||
justForYouDatas.map(
|
||||
(
|
||||
{
|
||||
prdtId,
|
||||
imgUrl,
|
||||
priceInfo,
|
||||
prdtNm,
|
||||
rankOrd,
|
||||
patnrId,
|
||||
offerInfo,
|
||||
brndNm,
|
||||
patncNm,
|
||||
catNm,
|
||||
},
|
||||
itemIndex
|
||||
) => {
|
||||
return (
|
||||
<TItemCard
|
||||
key={"subItem" + itemIndex}
|
||||
contextName={LOG_CONTEXT_NAME.HOME}
|
||||
messageId={LOG_MESSAGE_ID.SHELF_CLICK}
|
||||
order={itemIndex + 1}
|
||||
shelfId={spotlightId}
|
||||
shelfLocation={shelfLocation}
|
||||
shelfTitle={shelfTitle}
|
||||
patnerName={patncNm}
|
||||
brandName={brndNm}
|
||||
catNm={catNm}
|
||||
imageAlt={prdtId}
|
||||
imageSource={imgUrl}
|
||||
priceInfo={priceInfo}
|
||||
productName={prdtNm}
|
||||
isBestSeller={true}
|
||||
productId={prdtId}
|
||||
onFocus={handleFocus(itemIndex)}
|
||||
onBlur={handleBlur(itemIndex)}
|
||||
onClick={handleCardClick(patnrId, prdtId)}
|
||||
offerInfo={offerInfo}
|
||||
spotlightId={"bestsellerItem" + itemIndex}
|
||||
label={itemIndex * 1 + 1 + " of " + justForYouDatas.length}
|
||||
lastLabel=" go to detail, button"
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
|
||||
{drawChk && (
|
||||
<div className={css.addItem} onFocus={handleScrollRight}>
|
||||
<SpottableComponent
|
||||
className={css.displayBox}
|
||||
onClick={handleMoreCardClick}
|
||||
spotlightId={"bestseller-item-more-btn"}
|
||||
aria-label="See more button"
|
||||
></SpottableComponent>
|
||||
</div>
|
||||
)}
|
||||
</TScroller>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default PickedForYou;
|
||||
@@ -0,0 +1,51 @@
|
||||
@import "../../../style/CommonStyle.module.less";
|
||||
@import "../../../style/utils.module.less";
|
||||
|
||||
.bestSellerWrap {
|
||||
height: 512px;
|
||||
> h2 {
|
||||
margin-left: 60px;
|
||||
font-size: 42px;
|
||||
}
|
||||
> ul {
|
||||
height: 438px;
|
||||
}
|
||||
|
||||
.homeBestSeller {
|
||||
height: 482px;
|
||||
width: 100%;
|
||||
> div {
|
||||
> div {
|
||||
padding: 20px 0px 30px 60px;
|
||||
display: flex;
|
||||
> div {
|
||||
flex: none;
|
||||
margin-right: 18px;
|
||||
&:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.addItem {
|
||||
flex: none;
|
||||
.size(@w:258px, @h:438px);
|
||||
> .displayBox {
|
||||
.size(@w: 198px, @h: 438px);
|
||||
background-color: @COLOR_WHITE;
|
||||
.border-solid(@size:1px, @color:#e4e4e4);
|
||||
border-radius: 12px;
|
||||
background-image: url("../../../../assets/images/btn/ic-more-nor@3x.png");
|
||||
background-size: 66px 66px;
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
&:focus {
|
||||
border: 4px solid @PRIMARY_COLOR_RED;
|
||||
box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5);
|
||||
border-radius: 12px;
|
||||
background-image: url("../../../../assets/images/btn/ic-more-sel@3x.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
|
||||
import { sendLogCuration } from '../../../actions/logActions';
|
||||
import { getSubCategory } from '../../../actions/mainActions';
|
||||
import { pushPanel } from '../../../actions/panelActions';
|
||||
import Tag from '../../../components/TItemCard/Tag';
|
||||
import TItemCardNew from '../../../components/TItemCard/TitemCard.new';
|
||||
import TScroller from '../../../components/TScroller/TScroller';
|
||||
import usePrevious from '../../../hooks/usePrevious';
|
||||
@@ -286,7 +287,11 @@ export default memo(function SubCategory({
|
||||
categoryItemInfos?.subCatItemList.length
|
||||
}
|
||||
lastLabel=" go to detail, button"
|
||||
/>
|
||||
>
|
||||
{/* 조건수식 필요함. */}
|
||||
<Tag text={"For You"} />
|
||||
{/* //조건수식 필요함. */}
|
||||
</TItemCardNew>
|
||||
);
|
||||
}
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import SpotlightContainerDecorator
|
||||
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||
import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
|
||||
|
||||
import background
|
||||
from '../../../assets/images/JustForYouPanel/background_new.png';
|
||||
import {
|
||||
sendLogGNB,
|
||||
sendLogTotalRecommend,
|
||||
} from '../../actions/logActions';
|
||||
import {
|
||||
pushPanel,
|
||||
updatePanel,
|
||||
} from '../../actions/panelActions';
|
||||
// import { getBestSeller } from '../../actions/productActions';
|
||||
import CustomImage from '../../components/CustomImage/CustomImage';
|
||||
import SectionTitle from '../../components/SectionTitle/SectionTitle';
|
||||
import TBody from '../../components/TBody/TBody';
|
||||
import TButton, { TYPES } from '../../components/TButton/TButton';
|
||||
import TItemCard, {
|
||||
removeDotAndColon,
|
||||
} from '../../components/TItemCard/TItemCard';
|
||||
import TPanel from '../../components/TPanel/TPanel';
|
||||
import TVirtualGridList
|
||||
from '../../components/TVirtualGridList/TVirtualGridList';
|
||||
import useWhyDidYouUpdate from '../../hooks/useWhyDidYouUpdate';
|
||||
import {
|
||||
LOG_CONTEXT_NAME,
|
||||
LOG_MENU,
|
||||
LOG_MESSAGE_ID,
|
||||
panel_names,
|
||||
} from '../../utils/Config';
|
||||
import { $L } from '../../utils/helperMethods';
|
||||
import { SpotlightIds } from '../../utils/SpotlightIds';
|
||||
import css from './JustForYouPanel.module.less';
|
||||
|
||||
const RecentSawContainer = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
const STRING_CONF = {
|
||||
LIKE_ITEMS: "Like items you recently saw",
|
||||
LIKE_BRANDS: "Liked Brand Products",
|
||||
MORE_PRICE: "More to Consider at This Price",
|
||||
};
|
||||
|
||||
const JustForYouPanel = ({ panelInfo, isOnTop, ...rest }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const recentItems = useSelector(
|
||||
(state) => state.product?.bestSellerData?.bestSeller
|
||||
);
|
||||
|
||||
const [showButton, setShowButton] = useState("showButton", true);
|
||||
|
||||
const cbChangePageRef = useRef(null);
|
||||
const isInitialRef = useRef(true);
|
||||
const currentSentMenuRef = useRef(null);
|
||||
const focusedContainerIdRef = useRef(panelInfo?.focusedContainerId);
|
||||
|
||||
const handleScroll = useCallback((e) => {
|
||||
setShowButton(e.scrollTop === 0);
|
||||
}, []);
|
||||
|
||||
const handleItemClick = useCallback(
|
||||
({ patnrId, prdtId }) =>
|
||||
() => {
|
||||
const currentSpot =
|
||||
Spotlight.getCurrent()?.getAttribute("data-spotlight-id") || null;
|
||||
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.JUST_FOR_YOU_PANEL,
|
||||
panelInfo: {
|
||||
currentSpot,
|
||||
focusedContainerId: focusedContainerIdRef.current,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(
|
||||
pushPanel({
|
||||
name: panel_names.DETAIL_PANEL,
|
||||
panelInfo: { patnrId, prdtId },
|
||||
})
|
||||
);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleItemFocus = useCallback(() => {
|
||||
setTimeout(() => dispatch(sendLogGNB(LOG_MENU.JUST_FOR_YOU)));
|
||||
|
||||
if (LOG_MENU.JUST_FOR_YOU !== currentSentMenuRef.current) {
|
||||
const params = {
|
||||
contextName: LOG_CONTEXT_NAME.JUST_FOR_YOU,
|
||||
messageId: LOG_MESSAGE_ID.SHELF,
|
||||
shelfLocation: 1,
|
||||
shelfId: SpotlightIds.JUST_FOR_YOU_ITEMS,
|
||||
shelfTitle: STRING_CONF.LIKE_ITEMS,
|
||||
};
|
||||
dispatch(sendLogTotalRecommend(params));
|
||||
|
||||
currentSentMenuRef.current = LOG_MENU.JUST_FOR_YOU;
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleTopButtonClick = useCallback(() => {
|
||||
if (cbChangePageRef.current) {
|
||||
cbChangePageRef.current(0, true);
|
||||
}
|
||||
|
||||
if (recentItems && recentItems.length > 0) {
|
||||
const target = `spotlightId-recentItem-${recentItems[0]?.prdtId}`;
|
||||
Spotlight.focus(target);
|
||||
setContainerLastFocusedElement(null, [SpotlightIds.JUST_FOR_YOU_ITEMS]);
|
||||
}
|
||||
}, [recentItems]);
|
||||
|
||||
const renderItem = useCallback(
|
||||
(item) => {
|
||||
const {
|
||||
imgUrl,
|
||||
offerInfo,
|
||||
prdtId,
|
||||
lgCatNm,
|
||||
patncNm,
|
||||
brndNm,
|
||||
prdtNm,
|
||||
priceInfo,
|
||||
} = recentItems[item.index];
|
||||
|
||||
return (
|
||||
<TItemCard
|
||||
contextName={LOG_CONTEXT_NAME.JUST_FOR_YOU}
|
||||
messageId={LOG_MESSAGE_ID.SHELF_CLICK}
|
||||
shelfLocation={1}
|
||||
shelfTitle={STRING_CONF.LIKE_ITEMS}
|
||||
shelfId={SpotlightIds.JUST_FOR_YOU_ITEMS}
|
||||
catNm={lgCatNm}
|
||||
patnerName={patncNm}
|
||||
brandName={brndNm}
|
||||
data-wheel-point={item.index >= 5}
|
||||
imageAlt={prdtId}
|
||||
imageSource={imgUrl}
|
||||
key={prdtId}
|
||||
label={item.index * 1 + 1 + " of " + recentItems.length}
|
||||
lastLabel=" go to detail, button"
|
||||
offerInfo={offerInfo}
|
||||
onFocus={handleItemFocus}
|
||||
onClick={handleItemClick(item)}
|
||||
priceInfo={priceInfo}
|
||||
productName={prdtNm}
|
||||
productId={prdtId}
|
||||
spotlightId={
|
||||
"spotlightId-" + "recentItem- " + removeDotAndColon(prdtId)
|
||||
}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[handleItemFocus, handleItemClick]
|
||||
);
|
||||
|
||||
return (
|
||||
// <div className={css.justForYouWrap}>
|
||||
// <TPanel>
|
||||
// <TBody
|
||||
// className={css.justForYou}
|
||||
// scrollable={false}
|
||||
// spotlightDisabled={!isOnTop}
|
||||
// >
|
||||
// <TVerticalPagenator
|
||||
// className={css.tVerticalPagenator}
|
||||
// spotlightId={SpotlightIds.JUST_FOR_YOU_VERTICAL_PAGINATOR}
|
||||
// defaultContainerId={panelInfo?.focusedContainerId}
|
||||
// onScroll={handleScroll}
|
||||
// onFocusedContainerId={onFocusedContainerId}
|
||||
// cbChangePageRef={cbChangePageRef}
|
||||
// topMargin={470}
|
||||
// >
|
||||
// <div className={css.background}>
|
||||
// <CustomImage src={background} animationSpeed="none" />
|
||||
// </div>
|
||||
// {recentItems && recentItems?.length > 0 && (
|
||||
// <RecentSawContainer
|
||||
// className={css.itemsContainer}
|
||||
// spotlightId={SpotlightIds.JUST_FOR_YOU_ITEMS}
|
||||
// data-wheel-point
|
||||
// >
|
||||
// <SectionTitle
|
||||
// title={`${$L(STRING_CONF.LIKE_ITEMS)} (${recentItems.length})`}
|
||||
// data-title-index="JFYTitle"
|
||||
// />
|
||||
|
||||
// <div className={css.itemList}>
|
||||
// <TVirtualGridList
|
||||
// dataSize={recentItems.length}
|
||||
// itemWidth={324}
|
||||
// itemHeight={438}
|
||||
// spacing={18}
|
||||
// renderItem={renderItem}
|
||||
// />
|
||||
// </div>
|
||||
// </RecentSawContainer>
|
||||
// )}
|
||||
// {recentItems && recentItems?.length > 10 && (
|
||||
// <RecentSawContainer>
|
||||
// <TButton
|
||||
// onClick={handleTopButtonClick}
|
||||
// size={null}
|
||||
// spotlightId={SpotlightIds.JUST_FOR_YOU_TOP_BUTTON}
|
||||
// ariaLabel="Move to Top"
|
||||
// data-wheel-point
|
||||
// type={TYPES.topButton}
|
||||
// />
|
||||
// </RecentSawContainer>
|
||||
// )}
|
||||
// </TVerticalPagenator>
|
||||
// </TBody>
|
||||
// </TPanel>
|
||||
// </div>
|
||||
<div className={css.justForYouWrap}>
|
||||
<TPanel>
|
||||
<TBody className={css.justForYou}>
|
||||
<div className={css.background}>
|
||||
<CustomImage src={background} animationSpeed="none" />
|
||||
</div>
|
||||
{recentItems && recentItems?.length > 0 && (
|
||||
<RecentSawContainer
|
||||
className={classNames(css.itemsContainer, css.itemsContinerFirst)}
|
||||
spotlightId={SpotlightIds.JUST_FOR_YOU_ITEMS}
|
||||
data-wheel-point
|
||||
>
|
||||
<SectionTitle
|
||||
title={`${$L(STRING_CONF.LIKE_ITEMS)} (${recentItems.length})`}
|
||||
data-title-index="JFYTitle"
|
||||
/>
|
||||
|
||||
<div className={css.itemList}>
|
||||
<TVirtualGridList
|
||||
dataSize={recentItems.length}
|
||||
itemWidth={324}
|
||||
itemHeight={438}
|
||||
spacing={18}
|
||||
renderItem={renderItem}
|
||||
direction={"horizontal"}
|
||||
/>
|
||||
</div>
|
||||
</RecentSawContainer>
|
||||
)}
|
||||
{recentItems && recentItems?.length > 0 && (
|
||||
<RecentSawContainer
|
||||
className={css.itemsContainer}
|
||||
spotlightId={SpotlightIds.JUST_FOR_YOU_ITEMS}
|
||||
data-wheel-point
|
||||
>
|
||||
<SectionTitle
|
||||
title={`${$L(STRING_CONF.LIKE_BRANDS)} (${recentItems.length})`}
|
||||
data-title-index="JFYTitle"
|
||||
/>
|
||||
|
||||
<div className={css.itemList}>
|
||||
<TVirtualGridList
|
||||
dataSize={recentItems.length}
|
||||
itemWidth={324}
|
||||
itemHeight={438}
|
||||
spacing={18}
|
||||
renderItem={renderItem}
|
||||
direction={"horizontal"}
|
||||
/>
|
||||
</div>
|
||||
</RecentSawContainer>
|
||||
)}
|
||||
{recentItems && recentItems?.length > 0 && (
|
||||
<RecentSawContainer
|
||||
className={css.itemsContainer}
|
||||
spotlightId={SpotlightIds.JUST_FOR_YOU_ITEMS}
|
||||
data-wheel-point
|
||||
>
|
||||
<SectionTitle
|
||||
title={`${$L(STRING_CONF.MORE_PRICE)} (${recentItems.length})`}
|
||||
data-title-index="JFYTitle"
|
||||
/>
|
||||
|
||||
<div className={css.itemList}>
|
||||
<TVirtualGridList
|
||||
dataSize={recentItems.length}
|
||||
itemWidth={324}
|
||||
itemHeight={438}
|
||||
spacing={18}
|
||||
renderItem={renderItem}
|
||||
direction={"horizontal"}
|
||||
/>
|
||||
</div>
|
||||
</RecentSawContainer>
|
||||
)}
|
||||
|
||||
{recentItems && recentItems?.length > 10 && (
|
||||
<RecentSawContainer>
|
||||
<TButton
|
||||
onClick={handleTopButtonClick}
|
||||
size={null}
|
||||
spotlightId={SpotlightIds.JUST_FOR_YOU_TOP_BUTTON}
|
||||
ariaLabel="Move to Top"
|
||||
data-wheel-point
|
||||
type={TYPES.topButton}
|
||||
/>
|
||||
</RecentSawContainer>
|
||||
)}
|
||||
</TBody>
|
||||
</TPanel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const propsAreEqual = (prev, next) => {
|
||||
const keys = Object.keys(prev);
|
||||
const nextKeys = Object.keys(next);
|
||||
if (keys.length !== nextKeys.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (prev[keys[i]] !== next[keys[i]]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export default React.memo(JustForYouPanel, propsAreEqual);
|
||||
@@ -0,0 +1,67 @@
|
||||
@import "../../style/CommonStyle.module.less";
|
||||
@import "../../style/utils.module.less";
|
||||
|
||||
.justForYouWrap {
|
||||
.justForYou {
|
||||
position: relative;
|
||||
background: @COLOR_WHITE;
|
||||
overflow: auto;
|
||||
height: @globalHeight;
|
||||
.tVerticalPagenator {
|
||||
height: 100% !important;
|
||||
}
|
||||
.background {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.itemsContainer {
|
||||
width: 100%;
|
||||
padding: 0 0 0 60px;
|
||||
margin-top: 30px;
|
||||
&.itemsContinerFirst {
|
||||
margin-top: 470px;
|
||||
}
|
||||
|
||||
.itemList {
|
||||
position: relative;
|
||||
margin-top: 24px;
|
||||
.size(@w: 100%, @h: 438px);
|
||||
padding-right: 18px;
|
||||
> div:nth-child(1) {
|
||||
.size(@w: 100%, @h: inherit);
|
||||
&.tVirtualGridList {
|
||||
padding-left: 60px;
|
||||
> div:nth-child(1) {
|
||||
.tItemCard {
|
||||
> div:nth-child(1) {
|
||||
> img {
|
||||
will-change: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> div:nth-child(3) {
|
||||
right: -18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
max-width: 1800px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import React, { memo, useCallback } from "react";
|
||||
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { sendLogTotalRecommend } from "../../../actions/logActions";
|
||||
import { LOG_CONTEXT_NAME, LOG_MESSAGE_ID } from "../../../utils/Config";
|
||||
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
|
||||
import css from "./JustForYouContents.module.less";
|
||||
import JustForYouProductList from "./JustForYouProductList/JustForYouProductList";
|
||||
import { $L } from "../../../utils/helperMethods";
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
|
||||
export default memo(function JustForYouContents({
|
||||
contentsData,
|
||||
contentsTitle,
|
||||
contentsIndex,
|
||||
}) {
|
||||
|
||||
|
||||
const {
|
||||
saleNm,
|
||||
selectedLgCatNm,
|
||||
shelfOrder,
|
||||
selectedLgCatCd,
|
||||
} = contentsData;
|
||||
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const onFocus = useCallback(() => {
|
||||
//NOTE - 추후 아래 로직 필요한지 확인하고 params 추가 필요
|
||||
// dispatch(sendLogTotalRecommend(params));
|
||||
console.log("onFocus");
|
||||
}, [selectedLgCatNm, shelfOrder, selectedLgCatCd, saleNm]);
|
||||
|
||||
|
||||
//NOTE - onSale 패널 참고해서 추가 작업 필요 현재 작업중
|
||||
|
||||
return (
|
||||
<Container
|
||||
className={css.container}
|
||||
spotlightId={spotlightId}
|
||||
data-wheel-point
|
||||
onFocus={onFocus}
|
||||
>
|
||||
<SectionTitle
|
||||
data-title-index={contentsIndex}
|
||||
title={`${$L(contentsTitle)} (${contentsData.length})`} label={contentsTitle}
|
||||
/>
|
||||
<JustForYouProductList
|
||||
spotlightId={spotlightId}
|
||||
data-wheel-point
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"main": "JustForYouPanel.jsx",
|
||||
"styles": [
|
||||
"JustForYouPanel.module.less"
|
||||
]
|
||||
}
|
||||
@@ -1,26 +1,34 @@
|
||||
import React, {
|
||||
use,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
} from 'react';
|
||||
|
||||
import classNames from "classnames";
|
||||
import { indexOf } from "ilib/lib/JSUtils";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import classNames from 'classnames';
|
||||
import { indexOf } from 'ilib/lib/JSUtils';
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
|
||||
import platform from "@enact/core/platform";
|
||||
import Spotlight from "@enact/spotlight";
|
||||
import platform from '@enact/core/platform';
|
||||
import Spotlight from '@enact/spotlight';
|
||||
|
||||
import defaultWatchItem from "../../../assets/images/img-alert-banner-st@3x.png";
|
||||
import defaultWatchItem
|
||||
from '../../../assets/images/img-alert-banner-st@3x.png';
|
||||
// 테스트용 - TODO: 메인 홈 화면에 나와야 하는 이미지들 추가 후 preloadImages에 추가
|
||||
import testImage from "../../../assets/images/img-banner-myinfo-login@3x.png";
|
||||
import defaultImageItem from "../../../assets/images/img-thumb-empty-product@3x.png";
|
||||
import LoadingPreloadImage from "../../../assets/images/intro/splash_02_stop.webp";
|
||||
import LoadingAnimation from "../../../assets/images/intro/splash_03_end.webp";
|
||||
import LoadingCompleteImage from "../../../assets/images/intro/splash_04_end.webp";
|
||||
import LoadingShopOnTvImage from "../../../assets/images/intro/splash_end.jpg";
|
||||
import testImage from '../../../assets/images/img-banner-myinfo-login@3x.png';
|
||||
import defaultImageItem
|
||||
from '../../../assets/images/img-thumb-empty-product@3x.png';
|
||||
import LoadingPreloadImage
|
||||
from '../../../assets/images/intro/splash_02_stop.webp';
|
||||
import LoadingAnimation from '../../../assets/images/intro/splash_03_end.webp';
|
||||
import LoadingCompleteImage
|
||||
from '../../../assets/images/intro/splash_04_end.webp';
|
||||
import LoadingShopOnTvImage from '../../../assets/images/intro/splash_end.jpg';
|
||||
import {
|
||||
alertToast,
|
||||
changeAppStatus,
|
||||
@@ -29,70 +37,77 @@ import {
|
||||
setExitApp,
|
||||
setHidePopup,
|
||||
setShowPopup,
|
||||
} from "../../actions/commonActions";
|
||||
import { getHomeMenu, getHomeTerms } from "../../actions/homeActions";
|
||||
} from '../../actions/commonActions';
|
||||
import {
|
||||
getHomeMenu,
|
||||
getHomeTerms,
|
||||
updateHomeInfo,
|
||||
} from '../../actions/homeActions';
|
||||
import {
|
||||
sendLogAlarmClick,
|
||||
sendLogAlarmPop,
|
||||
sendLogLive,
|
||||
sendLogVOD,
|
||||
} from "../../actions/logActions";
|
||||
} from '../../actions/logActions';
|
||||
import {
|
||||
getMyUpcomingAlertShow,
|
||||
setMyTermsWithdraw,
|
||||
} from "../../actions/myPageActions";
|
||||
} from '../../actions/myPageActions';
|
||||
import {
|
||||
popPanel,
|
||||
pushPanel,
|
||||
resetPanels,
|
||||
updatePanel,
|
||||
} from "../../actions/panelActions";
|
||||
import { updateHomeInfo } from "../../actions/homeActions";
|
||||
import EndOfServicePopUp from "../../components/EndOfServicePopUp/EndOfServicePopUp";
|
||||
import Loader from "../../components/Loader/Loader";
|
||||
import { convertUtcToLocal } from "../../components/MediaPlayer/util";
|
||||
import PreloadImage from "../../components/PreloadImage/PreloadImage";
|
||||
import SystemNotification from "../../components/SystemNotification/SystemNotification";
|
||||
import TabLayout from "../../components/TabLayout/TabLayout";
|
||||
import TButton from "../../components/TButton/TButton";
|
||||
import TPopUp from "../../components/TPopUp/TPopUp";
|
||||
import TNewPopUp from "../../components/TPopUp/TNewPopUp";
|
||||
import usePrevious from "../../hooks/usePrevious";
|
||||
import * as Config from "../../utils/Config";
|
||||
import { panel_names } from "../../utils/Config";
|
||||
} from '../../actions/panelActions';
|
||||
import EndOfServicePopUp
|
||||
from '../../components/EndOfServicePopUp/EndOfServicePopUp';
|
||||
import Loader from '../../components/Loader/Loader';
|
||||
import { convertUtcToLocal } from '../../components/MediaPlayer/util';
|
||||
import OptionalTermsConfirm
|
||||
from '../../components/Optional/OptionalTermsConfirm';
|
||||
import OptionalTermsConfirmBottom
|
||||
from '../../components/Optional/OptionalTermsConfirmBottom';
|
||||
import PreloadImage from '../../components/PreloadImage/PreloadImage';
|
||||
import SystemNotification
|
||||
from '../../components/SystemNotification/SystemNotification';
|
||||
import TabLayout from '../../components/TabLayout/TabLayout';
|
||||
import TButton from '../../components/TButton/TButton';
|
||||
import TNewPopUp from '../../components/TPopUp/TNewPopUp';
|
||||
import TPopUp from '../../components/TPopUp/TPopUp';
|
||||
import usePrevious from '../../hooks/usePrevious';
|
||||
import * as Config from '../../utils/Config';
|
||||
import { panel_names } from '../../utils/Config';
|
||||
import {
|
||||
$L,
|
||||
getErrorMessage,
|
||||
getSpottableDescendants,
|
||||
} from "../../utils/helperMethods";
|
||||
import { SpotlightIds } from "../../utils/SpotlightIds";
|
||||
import CartPanel from "../CartPanel/CartPanel";
|
||||
import CategoryPanel from "../CategoryPanel/CategoryPanel";
|
||||
import CheckOutPanel from "../CheckOutPanel/CheckOutPanel";
|
||||
import ConfirmPanel from "../ConfirmPanel/ConfirmPanel";
|
||||
import DebugPanel from "../DebugPanel/DebugPanel";
|
||||
import DetailPanel from "../DetailPanel/DetailPanel";
|
||||
import ErrorPanel from "../ErrorPanel/ErrorPanel";
|
||||
import FeaturedBrandsPanel from "../FeaturedBrandsPanel/FeaturedBrandsPanel";
|
||||
import HomePanel from "../HomePanel/HomePanel";
|
||||
import HotPicksPanel from "../HotPicksPanel/HotPicksPanel";
|
||||
import ImagePanel from "../ImagePanel/ImagePanel";
|
||||
import IntroPanel from "../IntroPanel/IntroPanel.new";
|
||||
import LoadingPanel from "../LoadingPanel/LoadingPanel";
|
||||
import MyPagePanel from "../MyPagePanel/MyPagePanel";
|
||||
import OnSalePanel from "../OnSalePanel/OnSalePanel";
|
||||
import PlayerPanel from "../PlayerPanel/PlayerPanel";
|
||||
import PlayerPanelNew from "../PlayerPanel/PlayerPanel.new";
|
||||
import SearchPanel from "../SearchPanel/SearchPanel";
|
||||
import ThemeCurationPanel from "../ThemeCurationPanel/ThemeCurationPanel";
|
||||
import TrendingNowPanel from "../TrendingNowPanel/TrendingNowPanel";
|
||||
import VideoTestPanel from "../VideoTestPanel/VideoTestPanel";
|
||||
import WelcomeEventPanel from "../WelcomeEventPanel/WelcomeEventPanel";
|
||||
import UserReviewPanel from "../UserReview/UserReviewPanel";
|
||||
import OptionalTermsConfirm from "../../components/Optional/OptionalTermsConfirm";
|
||||
import OptionalTermsConfirmBottom from "../../components/Optional/OptionalTermsConfirmBottom";
|
||||
import css from "./MainView.module.less";
|
||||
import { use } from "react";
|
||||
} from '../../utils/helperMethods';
|
||||
import { SpotlightIds } from '../../utils/SpotlightIds';
|
||||
import CartPanel from '../CartPanel/CartPanel';
|
||||
import CategoryPanel from '../CategoryPanel/CategoryPanel';
|
||||
import CheckOutPanel from '../CheckOutPanel/CheckOutPanel';
|
||||
import ConfirmPanel from '../ConfirmPanel/ConfirmPanel';
|
||||
import DebugPanel from '../DebugPanel/DebugPanel';
|
||||
import DetailPanel from '../DetailPanel/DetailPanel';
|
||||
import ErrorPanel from '../ErrorPanel/ErrorPanel';
|
||||
import FeaturedBrandsPanel from '../FeaturedBrandsPanel/FeaturedBrandsPanel';
|
||||
import HomePanel from '../HomePanel/HomePanel';
|
||||
import HotPicksPanel from '../HotPicksPanel/HotPicksPanel';
|
||||
import ImagePanel from '../ImagePanel/ImagePanel';
|
||||
import IntroPanel from '../IntroPanel/IntroPanel.new';
|
||||
import JustForYouPanel from '../JustForYouPanel/JustForYouPanel';
|
||||
import LoadingPanel from '../LoadingPanel/LoadingPanel';
|
||||
import MyPagePanel from '../MyPagePanel/MyPagePanel';
|
||||
import OnSalePanel from '../OnSalePanel/OnSalePanel';
|
||||
import PlayerPanel from '../PlayerPanel/PlayerPanel';
|
||||
import PlayerPanelNew from '../PlayerPanel/PlayerPanel.new';
|
||||
import SearchPanel from '../SearchPanel/SearchPanel';
|
||||
import ThemeCurationPanel from '../ThemeCurationPanel/ThemeCurationPanel';
|
||||
import TrendingNowPanel from '../TrendingNowPanel/TrendingNowPanel';
|
||||
import UserReviewPanel from '../UserReview/UserReviewPanel';
|
||||
import VideoTestPanel from '../VideoTestPanel/VideoTestPanel';
|
||||
import WelcomeEventPanel from '../WelcomeEventPanel/WelcomeEventPanel';
|
||||
import css from './MainView.module.less';
|
||||
|
||||
const preloadImages = [
|
||||
LoadingPreloadImage,
|
||||
@@ -124,6 +139,7 @@ const panelMap = {
|
||||
[Config.panel_names.IMAGE_PANEL]: ImagePanel,
|
||||
[Config.panel_names.CONFIRM_PANEL]: ConfirmPanel,
|
||||
[Config.panel_names.USER_REVIEW_PANEL]: UserReviewPanel,
|
||||
[Config.panel_names.JUST_FOR_YOU_PANEL]: JustForYouPanel,
|
||||
// [Config.panel_names.OPTIONAL_TERMS_PANEL]: TermsOfOptional,
|
||||
};
|
||||
|
||||
|
||||