[FeaturedBrandsPanel] RecommendedShows 추가, TVirtualGridList 변경 반영

Detail Notes :
This commit is contained in:
younghoon100.park
2024-02-22 19:14:26 +09:00
parent 9ab8a812d4
commit b896d148a5
15 changed files with 328 additions and 88 deletions

View File

@@ -1,44 +1,60 @@
import React, { memo, useCallback } from "react";
import React, { useCallback } from "react";
import { useDispatch } from "react-redux";
import { pushPanel } from "../../../../actions/panelActions";
import TItemCard from "../../../../components/TItemCard/TItemCard";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import { panel_names } from "../../../../utils/Config";
import css from "./FeaturedBestSellerList.module.less";
export default memo(function FeaturedBestSellerList({ brandBestSellerInfo }) {
export default function FeaturedBestSellerList({ brandBestSellerInfo }) {
const dispatch = useDispatch();
const handleClick = useCallback(
(brandBestSellerInfo) => {
const { patnrId, prdtId } = brandBestSellerInfo;
const renderItem = useCallback(
({ index, ...rest }) => {
const { imgUrl, patnrId, prdtNm, prdtId, priceInfo, rankOrd } =
brandBestSellerInfo[index];
dispatch(
pushPanel({
name: panel_names.DETAIL_PANEL,
panelInfo: { patnrId, prdtId },
})
const handleClick = () => {
dispatch(
pushPanel({
name: panel_names.DETAIL_PANEL,
panelInfo: { patnrId, prdtId },
})
);
};
return (
<TItemCard
imageAlt={prdtNm}
imageSource={imgUrl}
isBestSeller
rank={rankOrd}
onClick={handleClick}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
{...rest}
/>
);
},
[dispatch, brandBestSellerInfo]
[brandBestSellerInfo, dispatch]
);
return (
<div className={css.container}>
{brandBestSellerInfo && (
<></>
// <TVirtualGridList
// className={css.tVirtualGridList}
// dataSize={brandBestSellerInfo.length}
// direction="horizontal"
// items={brandBestSellerInfo}
// itemHeight={438}
// itemWidth={324}
// onClick={handleClick}
// spacing={18}
// />
<TVirtualGridList
className={css.tVirtualGridList}
dataSize={brandBestSellerInfo.length}
direction="horizontal"
itemHeight={438}
itemWidth={324}
spacing={18}
renderItem={renderItem}
/>
)}
</div>
);
});
}

View File

@@ -2,8 +2,6 @@ import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import Spotlight from "@enact/spotlight";
import {
getBrandBestSeller,
getBrandLayoutInfo,
@@ -62,31 +60,39 @@ export default function FeaturedBrandsPanel() {
(state) => state.brand.brandRecommendedShowInfoData.brandRecommendedShowInfo
);
const [selectedPatnrId, setSelectedPatnrId] = useState(String(panelInfo));
const [selectedPatnrId, setSelectedPatnrId] = useState(panelInfo.toString());
const [selectedBrandInfo, setSelectedBrandInfo] = useState();
const [selectedCatCd, setSelectedCatCd] = useState();
useEffect(() => {
if (!brandInfo) {
console.log("@@ [initial sideEffect]");
dispatch(getBrandList());
}
}, [brandInfo, dispatch]);
useEffect(() => {
console.log("@@ [patnrId sideEffect]");
if (brandInfo && selectedPatnrId) {
console.log("@@ [patnrId sideEffect]");
setSelectedBrandInfo(findItemByPatnrId(brandInfo, selectedPatnrId));
setSelectedCatCd();
dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandTSVInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandBestSeller({ patnrId: selectedPatnrId }));
dispatch(getBrandRecommendedShowInfo({ patnrId: selectedPatnrId }));
dispatch(
getBrandRecommendedShowInfo({ patnrId: selectedPatnrId, catCd: "" })
);
}
}, [brandInfo, dispatch, selectedPatnrId]);
useEffect(() => {
console.log("@@ [catCd sideEffect]");
if (selectedCatCd) {
console.log("@@ [catCd sideEffect]");
dispatch(
getBrandRecommendedShowInfo({
catCd: selectedCatCd,

View File

@@ -62,7 +62,10 @@ export default function LiveChannels({ brandChanInfo, brandChannelCnt }) {
/>
{brandProductInfo && (
<LiveProductList brandProductInfo={brandProductInfo} />
<LiveProductList
brandProductInfo={brandProductInfo}
patnrId={patnrId}
/>
)}
</div>
)}

View File

@@ -1,23 +1,58 @@
import React from "react";
import React, { useCallback } from "react";
import { TYPES } from "../../../../components/TItemCard/TItemCard";
import { useDispatch } from "react-redux";
import { pushPanel } from "../../../../actions/panelActions";
import TItemCard, { TYPES } from "../../../../components/TItemCard/TItemCard";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import { panel_names } from "../../../../utils/Config";
import css from "./LiveProductList.module.less";
export default function LiveProductList({ brandProductInfo }) {
export default function LiveProductList({ brandProductInfo, patnrId }) {
const dispatch = useDispatch();
const renderItem = useCallback(
({ index, ...rest }) => {
const { prdtId, prdtImgUrl, prdtNm, priceInfo, soldoutFlag } =
brandProductInfo[index];
const handleClick = () => {
dispatch(
pushPanel({
name: panel_names.DETAIL_PANEL,
panelInfo: { patnrId, prdtId },
})
);
};
return (
<TItemCard
imageAlt={prdtNm}
imageSource={prdtImgUrl}
onClick={handleClick}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
soldoutFlag={soldoutFlag}
type={TYPES.horizontal}
{...rest}
/>
);
},
[brandProductInfo, dispatch, patnrId]
);
return (
<div className={css.container}>
{brandProductInfo && (
<></>
// <TVirtualGridList
// className={css.tVirtualGridList}
// dataSize={brandProductInfo.length}
// items={brandProductInfo}
// itemHeight={236}
// itemType={TYPES.horizontal}
// itemWidth={660}
// spacing={12}
// />
<TVirtualGridList
className={css.tVirtualGridList}
dataSize={brandProductInfo.length}
itemHeight={236}
itemWidth={660}
spacing={12}
renderItem={renderItem}
/>
)}
</div>
);

View File

@@ -1,48 +1,39 @@
import React, { memo } from "react";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
import { $L } from "../../../utils/helperMethods";
import css from "./RecommendedShows.module.less";
import RecommendedShowsContents from "./RecommendedShowsContents/RecommendedShowsContents";
import RecommendedShowsNav from "./RecommendedShowsNav/RecommendedShowsNav";
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
const STRING_CONF = {
RECOMMENDED_SHOWS: $L("RECOMMENDED SHOWS"),
};
{
/* <TButton
onClick={() => handleClick(catCd)}
selected={selectedCatCd === String(catCd)}
type={TYPES.oneDepthCategory}
>
{catNm}
</TButton>
<TButton
selected={selectedCatCd === String(catCd)}
size={null}
color={null}
type={TYPES.twoDepthCategory}
withMarquee
>
{catNm}
</TButton> */
}
export default function RecommendedShows({
export default memo(function RecommendedShows({
brandRecommendedShowCategoryInfo,
brandRecommendedShowInfo,
selectedCatCd,
setSelectedCatCd,
}) {
return (
<div className={css.container}>
<Container className={css.container}>
<SectionTitle title={STRING_CONF.RECOMMENDED_SHOWS} />
<RecommendedShowsNav
brandRecommendedShowCategoryInfo={brandRecommendedShowCategoryInfo}
selectedCatCd={selectedCatCd}
setSelectedCatCd={setSelectedCatCd}
/>
</div>
<RecommendedShowsContents
brandRecommendedShowInfo={brandRecommendedShowInfo}
/>
</Container>
);
}
});

View File

@@ -0,0 +1,45 @@
import React from "react";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import TItemCard, { TYPES } from "../../../../components/TItemCard/TItemCard";
import css from "./RecommendedShowsContents.module.less";
import RecommendedShowsProductList from "./RecommendedShowsProductList/RecommendedShowsProductList";
const ContentsWrap = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
export default function RecommendedShowsContents({ brandRecommendedShowInfo }) {
return (
<div className={css.container}>
{brandRecommendedShowInfo &&
brandRecommendedShowInfo.map(
(
{ brandRecommendedShowProductInfo, patnrId, showNm, thumbnailUrl },
index
) => (
<ContentsWrap
className={css.contentsWrap}
key={"brandRecommendedShowInfo-" + index}
>
<TItemCard
imageAlt={showNm}
imageSource={thumbnailUrl}
nonPosition
productName={showNm}
type={TYPES.videoShow}
/>
<RecommendedShowsProductList
brandRecommendedShowProductInfo={
brandRecommendedShowProductInfo
}
patnrId={patnrId}
/>
</ContentsWrap>
)
)}
</div>
);
}

View File

@@ -0,0 +1,14 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
.flex(@direction: column, @justifyCenter: flex-start);
width: 100%;
padding-left: 60px;
.contentsWrap {
display: flex;
.size(@w: 100%, @h:438px);
margin-bottom: 36px;
}
}

View File

@@ -0,0 +1,62 @@
import React, { useCallback } from "react";
import { useDispatch } from "react-redux";
import { pushPanel } from "../../../../../actions/panelActions";
import TItemCard from "../../../../../components/TItemCard/TItemCard";
import TVirtualGridList from "../../../../../components/TVirtualGridList/TVirtualGridList";
import { panel_names } from "../../../../../utils/Config";
import css from "./RecommendedShowsProductList.module.less";
export default function RecommendedShowsProductList({
brandRecommendedShowProductInfo,
patnrId,
}) {
const dispatch = useDispatch();
const renderItem = useCallback(
({ index, ...rest }) => {
const { imgUrl, prdtId, prdtNm, priceInfo, soldoutFlag } =
brandRecommendedShowProductInfo[index];
const handleClick = () => {
dispatch(
pushPanel({
name: panel_names.DETAIL_PANEL,
panelInfo: { patnrId, prdtId },
})
);
};
return (
<TItemCard
imageAlt={prdtNm}
imageSource={imgUrl}
onClick={handleClick}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
soldoutFlag={soldoutFlag}
{...rest}
/>
);
},
[brandRecommendedShowProductInfo, dispatch, patnrId]
);
return (
<div className={css.container}>
{brandRecommendedShowProductInfo && (
<TVirtualGridList
className={css.tVirtualGridList}
dataSize={brandRecommendedShowProductInfo.length}
direction="horizontal"
itemHeight={438}
itemWidth={324}
spacing={18}
renderItem={renderItem}
/>
)}
</div>
);
}

View File

@@ -0,0 +1,8 @@
@import "../../../../../style/utils.module.less";
.container {
.flex();
overflow: hidden;
width: calc(100% - 546px);
padding-left: 18px;
}

View File

@@ -0,0 +1,6 @@
{
"main": "RecommendedShowsProductList.jsx",
"styles": [
"RecommendedShowsProductList.module.less"
]
}

View File

@@ -0,0 +1,6 @@
{
"main": "RecommendedShowsProductContents.jsx",
"styles": [
"RecommendedShowsProductContents.module.less"
]
}

View File

@@ -1,12 +1,18 @@
import React, { useCallback } from "react";
import Scroller from "@enact/sandstone/Scroller";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import TButton, { TYPES } from "../../../../components/TButton/TButton";
import useScrollReset from "../../../../hooks/useScrollReset";
import useScrollTo from "../../../../hooks/useScrollTo";
import css from "./RecommendedShowsNav.module.less";
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"nav"
);
export default function RecommendedShowsNav({
brandRecommendedShowCategoryInfo,
selectedCatCd,
@@ -22,11 +28,12 @@ export default function RecommendedShowsNav({
if (index !== 0) {
return;
}
handleStopScrolling();
}, []);
const handleClick = useCallback((catCd) => {
setSelectedCatCd(String(catCd));
setSelectedCatCd(catCd);
}, []);
const handleFocus = useCallback((index) => {
@@ -38,7 +45,7 @@ export default function RecommendedShowsNav({
}, []);
return (
<nav className={css.nav}>
<Container className={css.nav}>
<Scroller
cbScrollTo={getScrollTo}
direction="horizontal"
@@ -51,10 +58,15 @@ export default function RecommendedShowsNav({
brandRecommendedShowCategoryInfo.map(({ catNm, catCd }, index) => (
<li key={"brandRecommendedShowCategoryInfo-" + index}>
<TButton
className={selectedCatCd === catCd.toString() && css.selected}
onBlur={() => handleBlur(index)}
onClick={() => handleClick(catCd)}
onClick={() => handleClick(catCd.toString())}
onFocus={() => handleFocus(index)}
selected={selectedCatCd === String(catCd)}
selected={
selectedCatCd
? selectedCatCd === catCd.toString()
: index === 0
}
type={TYPES.oneDepthCategory}
>
{catNm}
@@ -63,6 +75,6 @@ export default function RecommendedShowsNav({
))}
</ul>
</Scroller>
</nav>
</Container>
);
}

View File

@@ -2,17 +2,47 @@
@import "../../../../style/utils.module.less";
.nav {
.size(@w: 100%, @h: 144px);
background-color: #dddddd;
.size(@w: 100%, @h: 162px);
margin-bottom: 12px;
background-color: #ddd;
ul {
display: flex;
align-items: center;
height: inherit;
padding-left: 60px;
border-bottom: 18px solid @BG_COLOR_01;
&::before {
position: absolute;
right: -100%;
bottom: 0;
.size(@w: 100%, @h: 18px);
background-color: @BG_COLOR_01;
content: "";
}
li {
margin-right: 12px;
> div {
position: relative;
&.selected {
&::before {
position: absolute;
bottom: -62px;
left: 50%;
transform: translateX(-50%);
.size(@w: 0, @h: 0);
border-top: 18px solid #ddd;
border-right: 18px solid transparent;
border-bottom: 18px solid transparent;
border-left: 18px solid transparent;
content: "";
}
}
}
}
}
}

View File

@@ -19,8 +19,6 @@ const STRING_CONF = {
const SpottableComponent = Spottable("div");
export default memo(function UpComingCard({ hstNm, showNm, strtDt, ...rest }) {
for (let key in rest) delete rest[key];
const [isFocused, setIsFocused] = useState(false);
const [isSelected, setIsSelected] = useState(false);

View File

@@ -1,24 +1,32 @@
import React from "react";
import React, { useCallback } from "react";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import UpComingCard from "./UpComingCard/UpComingCard";
import css from "./UpComingList.module.less";
export default function UpComingList({ brandLiveChannelUpcoming }) {
const renderItem = useCallback(
({ index, ...rest }) => {
const { hstNm, showNm, strtDt } = brandLiveChannelUpcoming[index];
return (
<UpComingCard hstNm={hstNm} showNm={showNm} strtDt={strtDt} {...rest} />
);
},
[brandLiveChannelUpcoming]
);
return (
<div className={css.container}>
{brandLiveChannelUpcoming && (
<></>
// <TVirtualGridList
// className={css.tVirtualGridList}
// dataSize={brandLiveChannelUpcoming.length}
// direction="horizontal"
// items={brandLiveChannelUpcoming}
// itemCard={UpComingCard}
// itemHeight={344}
// itemWidth={480}
// spacing={18}
// />
<TVirtualGridList
className={css.tVirtualGridList}
dataSize={brandLiveChannelUpcoming.length}
direction="horizontal"
itemHeight={344}
itemWidth={480}
spacing={18}
renderItem={renderItem}
/>
)}
</div>
);