[FeaturedBrandsPanel] logic 수정 및 TodaysDeals 추가

Detail Notes :

1. FeaturedBrandsPanel.jsx, brandTsvInfo 추가, 함수 변경 및 추가 (findItemByPatnrId, isNotEmptyObject)
2. QuickMenu.jsx, props 변경
3. TodaysDeals.jsx / TodaysDealsCard.jsx 추가 및 적용
This commit is contained in:
younghoon100.park
2024-02-13 16:33:13 +09:00
parent 85f6ccff0b
commit f5f3385c5b
8 changed files with 353 additions and 19 deletions

View File

@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
@@ -8,6 +8,7 @@ import {
getBrandLayoutInfo, getBrandLayoutInfo,
getBrandList, getBrandList,
getBrandLiveChannelInfo, getBrandLiveChannelInfo,
getBrandTSVInfo,
} from "../../actions/brandActions"; } from "../../actions/brandActions";
import TBody from "../../components/TBody/TBody"; import TBody from "../../components/TBody/TBody";
import TPanel from "../../components/TPanel/TPanel"; import TPanel from "../../components/TPanel/TPanel";
@@ -15,10 +16,15 @@ import Banner from "./Banner/Banner";
import css from "./FeaturedBrandsPanel.module.less"; import css from "./FeaturedBrandsPanel.module.less";
import LiveChannels from "./LiveChannels/LiveChannels"; import LiveChannels from "./LiveChannels/LiveChannels";
import QuickMenu from "./QuickMenu/QuickMenu"; import QuickMenu from "./QuickMenu/QuickMenu";
import TodaysDeals from "./TodaysDeals/TodaysDeals";
import UpComing from "./UpComing/UpComing"; import UpComing from "./UpComing/UpComing";
const getSelectedBrandInfo = (brandInfo, selectedPatnrId) => { const findItemByPatnrId = (array, patnrId) => {
return brandInfo.find((brand) => brand?.patnrId === selectedPatnrId); return array.find((item) => item.patnrId === patnrId);
};
const isNotEmptyObject = (object) => {
return Object.keys(object).length > 0;
}; };
export default function FeaturedBrandsPanel() { export default function FeaturedBrandsPanel() {
@@ -38,21 +44,13 @@ export default function FeaturedBrandsPanel() {
const brandLiveChannelUpcoming = useSelector( const brandLiveChannelUpcoming = useSelector(
(state) => state.brand.brandLiveChannelInfoData.brandLiveChannelUpcoming (state) => state.brand.brandLiveChannelInfoData.brandLiveChannelUpcoming
); );
const brandTsvInfo = useSelector(
(state) => state.brand.brandTsvInfoData.brandTsvInfo
);
const [selectedPatnrId, setSelectedPatnrId] = useState(String(panelInfo)); const [selectedPatnrId, setSelectedPatnrId] = useState(String(panelInfo));
const [selectedBrandInfo, setSelectedBrandInfo] = useState(); const [selectedBrandInfo, setSelectedBrandInfo] = useState();
const handleQuickMenuClick = useCallback(
(patnrId) => {
if (selectedPatnrId === patnrId) {
return;
}
setSelectedPatnrId(patnrId);
},
[selectedPatnrId]
);
useEffect(() => { useEffect(() => {
if (!brandInfo) { if (!brandInfo) {
dispatch(getBrandList()); dispatch(getBrandList());
@@ -61,9 +59,10 @@ export default function FeaturedBrandsPanel() {
useEffect(() => { useEffect(() => {
if (brandInfo && selectedPatnrId) { if (brandInfo && selectedPatnrId) {
setSelectedBrandInfo(getSelectedBrandInfo(brandInfo, selectedPatnrId)); setSelectedBrandInfo(findItemByPatnrId(brandInfo, selectedPatnrId));
dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId })); dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId })); dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandTSVInfo({ patnrId: selectedPatnrId }));
} }
}, [brandInfo, dispatch, selectedPatnrId]); }, [brandInfo, dispatch, selectedPatnrId]);
@@ -81,8 +80,8 @@ export default function FeaturedBrandsPanel() {
{brandInfo && brandInfo.length > 1 && ( {brandInfo && brandInfo.length > 1 && (
<QuickMenu <QuickMenu
brandInfo={brandInfo} brandInfo={brandInfo}
onQuickMenuClick={handleQuickMenuClick}
selectedPatnrId={selectedPatnrId} selectedPatnrId={selectedPatnrId}
setSelectedPatnrId={setSelectedPatnrId}
/> />
)} )}
@@ -104,6 +103,10 @@ export default function FeaturedBrandsPanel() {
{brandLiveChannelUpcoming && brandLiveChannelUpcoming.length > 0 && ( {brandLiveChannelUpcoming && brandLiveChannelUpcoming.length > 0 && (
<UpComing brandLiveChannelUpcoming={brandLiveChannelUpcoming} /> <UpComing brandLiveChannelUpcoming={brandLiveChannelUpcoming} />
)} )}
{brandTsvInfo && isNotEmptyObject(brandTsvInfo) && (
<TodaysDeals brandTsvInfo={brandTsvInfo} />
)}
</div> </div>
</TBody> </TBody>
</TPanel> </TPanel>

View File

@@ -20,9 +20,20 @@ const Container = SpotlightContainerDecorator(
export default function QuickMenu({ export default function QuickMenu({
brandInfo, brandInfo,
selectedPatnrId, selectedPatnrId,
onQuickMenuClick, setSelectedPatnrId,
...rest ...rest
}) { }) {
const handleQuickMenuClick = useCallback(
(patnrId) => {
if (selectedPatnrId === patnrId) {
return;
}
setSelectedPatnrId(patnrId);
},
[selectedPatnrId]
);
const renderItem = useCallback( const renderItem = useCallback(
({ index, ...rest }) => { ({ index, ...rest }) => {
return ( return (
@@ -30,12 +41,12 @@ export default function QuickMenu({
brandInfo={brandInfo} brandInfo={brandInfo}
index={index} index={index}
selectedPatnrId={selectedPatnrId} selectedPatnrId={selectedPatnrId}
onQuickMenuClick={onQuickMenuClick} onQuickMenuClick={handleQuickMenuClick}
{...rest} {...rest}
/> />
); );
}, },
[brandInfo, selectedPatnrId, onQuickMenuClick] [brandInfo, selectedPatnrId, handleQuickMenuClick]
); );
return ( return (

View File

@@ -0,0 +1,58 @@
import React, { memo } from "react";
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
import { $L } from "../../../utils/helperMethods";
import css from "./TodaysDeals.module.less";
import TodaysDealsCard from "./TodaysDealsCard/TodaysDealsCard";
const STRING_CONF = {
TODAYS_DEALS: $L("TODAY'S DEALS"),
};
// cpnFlag, // 쿠폰 여부 (Y or N)
// freeShippingFlag, // 무료 배송 여부 (Y or N)
// logoImgAlt, // 로고 이미지 alt 값
// logoImgNm, // 로고 이미지 이름
// logoImgPath, // 로고 이미지 경로
// offerInfo, // 제공 정보
// patncLogoPath, // 파트너사 로고 이미지 경로
// patncNm, // 파트너 이름
// patnrId, // 파트너 아이디
// prdtId, // 상품 아이디
// prdtNm, // 상품 이름
// priceInfo, // 상품 금액 정보, 할인전 금액, 할인 후(최종) 금액, 리워드 여부, save 금액, off(할인 %)
// showId, // 방송 아이디
// showNm, // 방송 이름
// showUrl, // 방송 url
// thumbnailImg, // 썸네일 이미지
// tmpltCd, // 템플릿 코드
// tmpltNm, // 템플릿 명칭
// todaySpclFlag, // Today Sepcial Value 여부 (Y or N)
export default memo(function TodaysDeals({ brandTsvInfo }) {
console.log("@@brandTsvInfo", brandTsvInfo);
const {
cpnFlag: couponFlag,
freeShippingFlag,
prdtNm: productName,
priceInfo,
thumbnailImg,
todaySpclFlag: todaySpecialFlag,
} = brandTsvInfo;
return (
<div className={css.container}>
<SectionTitle title={STRING_CONF.TODAYS_DEALS} />
<TodaysDealsCard
couponFlag={couponFlag}
freeShippingFlag={freeShippingFlag}
imageSource={thumbnailImg}
imageAlt={productName}
priceInfo={priceInfo}
productName={productName}
todaySpecialFlag={todaySpecialFlag}
/>
</div>
);
});

View File

@@ -0,0 +1,10 @@
@import "../../../style/CommonStyle.module.less";
@import "../../../style/utils.module.less";
.container {
margin-bottom: 58px;
h2 {
margin-bottom: 24px;
}
}

View File

@@ -0,0 +1,69 @@
import React, { memo } from "react";
import Spottable from "@enact/spotlight/Spottable";
import usePriceInfo from "../../../../hooks/usePriceInfo";
import css from "./TodaysDealsCard.module.less";
const SpottableComponent = Spottable("div");
export default memo(function TodaysDealsCard({
couponFlag,
freeShippingFlag,
imageAlt,
imageSource,
priceInfo,
productName,
todaySpecialFlag,
...rest
}) {
const { originalPrice, discountedPrice, discountRate, discountNumeric } =
usePriceInfo(priceInfo);
return (
<SpottableComponent className={css.item} {...rest}>
<div>
<img src={imageSource} alt={imageAlt} />
</div>
<div>
<div>
<div className={css.todaysDealsTag}>
{todaySpecialFlag === "N" && <span className={css.specialValue} />}
{freeShippingFlag === "N" && <span className={css.freeShipping} />}
</div>
<div className={css.specialPriceType}>
{true && <span className={css.tsv} />}
{true && <span className={css.frees} />}
{true && <span className={css.bigSale} />}
{true && <span className={css.shopTimePrice} />}
{couponFlag === "N" && (
// @@pyh Todo, COUPON, image resource 유무에 따라 추후 수정 (언어)
<span className={css.coupon}>{"COUPON"}</span>
)}
</div>
</div>
<div>
<h3>{productName}</h3>
<p>
{discountRate ? discountedPrice : originalPrice}
{/* {discountRate && <span>{originalPrice}</span>} */}
<span>{"$ 22.33"}</span>
</p>
</div>
</div>
{/* {discountRate && (
<div>
<span>{"18%"}</span>
<span>{"SAVE"}</span>
</div>
)} */}
<div>
<span>{"18%"}</span>
<span>{"SAVE"}</span>
</div>
</SpottableComponent>
);
});

View File

@@ -0,0 +1,171 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.item {
/* normal */
position: relative;
.flex(@justifyCenter: flex-start);
.size(@w: 1680px, @h: 372px);
padding: 30px 60px;
background-image: url("../../../../../assets/images/partners/img-partners-banner-td-hor@3x.png");
background-position: center;
background-size: contain;
// image area (left)
> div:nth-child(1) {
overflow: hidden;
margin-right: 30px;
border-radius: 16px;
img {
.size(@w: 558px, @h: 312px);
}
}
// product infomation (center)
> div:nth-child(2) {
.flex(@direction: column, @justifyCenter: space-between, @alignCenter: flex-start);
.size(@w: 648px, @h: 100%);
padding: 12px 0;
// product badge icon area (top)
> div:nth-child(1) {
.size(@w: inherit, @h: 156px);
.todaysDealsTag {
.size(@w: inherit, @h: 112px);
.specialValue {
display: block;
.size(@w: 240px, @h: 48px);
margin-bottom: 6px;
background-image: url("../../../../../assets/icon/badge/badge-td-specialvalue@3x.png");
background-position: center;
background-size: contain;
}
.freeShipping {
display: block;
.size(@w: 240px, @h: 48px);
margin-bottom: 6px;
background-image: url("../../../../../assets/icon/badge/badge-td-freesh@3x.png");
background-position: center;
background-size: contain;
}
}
.specialPriceType {
.flex(@justifyCenter: flex-start);
overflow: hidden;
.size(@w: inherit, @h: 42px);
margin-bottom: 6px;
.tsv {
display: inline-block;
.size(@w: 80px, @h: 42px);
margin-right: 6px;
background-image: url("../../../../../assets/icon/badge/badge-tsv@3x.png");
background-position: center;
background-size: contain;
}
.frees {
display: inline-block;
.size(@w: 130px, @h: 42px);
margin-right: 6px;
background-image: url("../../../../../assets/icon/badge/badge-frees-h@3x.png");
background-position: center;
background-size: contain;
}
.bigSale {
display: inline-block;
.size(@w: 120px, @h: 42px);
margin-right: 6px;
background-image: url("../../../../../assets/icon/badge/badge-bigsale@3x.png");
background-position: center;
background-size: contain;
}
.shopTimePrice {
display: inline-block;
.size(@w: 200px, @h: 42px);
margin-right: 6px;
background-image: url("../../../../../assets/icon/badge/badge-shoptimeprice@3x.png");
background-position: center;
background-size: contain;
}
.coupon {
display: inline-block;
.size(@w: 120px, @h: 42px);
border-radius: 4px;
background-color: #7a808d;
.font(@fontFamily: @baseFontBold, @fontSize: 24px);
text-align: center;
line-height: 42px;
color: @COLOR_WHITE;
}
}
}
// product contents area (bottom)
> div:nth-child(2) {
h3 {
overflow: hidden;
width: 540px;
min-height: 80px;
margin-bottom: 4px;
.font(@fontFamily: @baseFontBold, @fontSize: 30px);
.elip(@clamp:2);
word-break: break-all;
color: @COLOR_GRAY06;
}
p {
.flex(@justifyCenter: flex-start);
.font(@fontFamily: @baseFontBold, @fontSize: 46px);
color: @PRIMARY_COLOR_RED;
span {
margin-left: 6px;
.font(@fontFamily: @baseFont, @fontSize: 24px);
color: #7f7f7f;
text-decoration: line-through;
}
}
}
}
// sale percentage area (right)
> div:nth-child(3) {
.flex(@direction: column, @alignCenter: flex-end);
flex-grow: 1;
padding-right: 48px;
> span:nth-child(1) {
.flex();
.size(@w: 174px, @h: 90px);
margin-bottom: 6px;
background-color: #f40000;
border-radius: 44px;
.font(@fontFamily: @baseFontBold, @fontSize: 54px);
color: @COLOR_WHITE;
}
> span:nth-child(2) {
.flex();
.size(@w: 174px, @h: 72px);
.font(@fontFamily: @baseFontBold, @fontSize: 60px);
}
}
/* focused */
&:focus-within {
&::after {
.focused(@boxShadow:50px, @borderRadius:12px);
}
}
/* selected */
}

View File

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

View File

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