[FeaturedBrandsPaenl] 로직 및 component 변경

Detail Notes :

1. GNB로 진입시 panelInfo값을 통한 api params 변경으로 로직 수정
2. LiveChannels.jsx, Scroller → VirtualGridList 변경
3. LiveVideoCard, css border 변경
This commit is contained in:
younghoon100.park
2024-02-06 20:44:05 +09:00
parent 2cda870806
commit e3232e2563
7 changed files with 116 additions and 127 deletions

View File

@@ -2,9 +2,9 @@ import React from "react";
import css from "./Banner.module.less";
export default function Banner({ selectedBrandInfo, brandTopImgInfo }) {
const { logoImgAlt, logoImgPath, patncNm } = selectedBrandInfo;
export default function Banner({ brandTopImgInfo, selectedBrandInfo }) {
const { topImgAlt, topImgPath } = brandTopImgInfo;
const { logoImgAlt, logoImgPath, patncNm } = selectedBrandInfo;
return (
<div className={css.container}>

View File

@@ -6,6 +6,7 @@ import Spotlight from "@enact/spotlight";
import {
getBrandLayoutInfo,
getBrandList,
getBrandLiveChannelInfo,
} from "../../actions/brandActions";
import TBody from "../../components/TBody/TBody";
@@ -22,12 +23,11 @@ const getSelectedBrandInfo = (brandInfo, selectedPatnrId) => {
export default function FeaturedBrandsPanel() {
const dispatch = useDispatch();
const panelInfo = useSelector((state) => state.panels.panels[0].panelInfo);
const brandInfo = useSelector((state) => state.brand.brandInfoData.brandInfo);
const brandTopImgInfo = useSelector(
(state) => state.brand.brandLayoutInfoData.brandTopImgInfo
);
const brandChanInfo = useSelector(
(state) => state.brand.brandLiveChannelInfoData.brandChanInfo
);
@@ -35,11 +35,9 @@ export default function FeaturedBrandsPanel() {
(state) => state.brand.brandLiveChannelInfoData.brandChannelCnt
);
const [selectedPatnrId, setSelectedPatnrId] = useState(String(panelInfo));
const [selectedBrandInfo, setSelectedBrandInfo] = useState();
// @@pyh Todo, provided by GNB as props or global state
const [selectedPatnrId, setSelectedPatnrId] = useState("1");
const handleQuickMenuClick = useCallback(
(patnrId) => {
if (selectedPatnrId === patnrId) {
@@ -52,15 +50,21 @@ export default function FeaturedBrandsPanel() {
);
useEffect(() => {
if (brandInfo) {
setSelectedBrandInfo(getSelectedBrandInfo(brandInfo, selectedPatnrId));
if (!brandInfo) {
dispatch(getBrandList());
}
dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId }));
}, [selectedPatnrId]);
}, [brandInfo, dispatch]);
useEffect(() => {
if (brandInfo && selectedPatnrId) {
setSelectedBrandInfo(getSelectedBrandInfo(brandInfo, selectedPatnrId));
dispatch(getBrandLayoutInfo({ patnrId: selectedPatnrId }));
dispatch(getBrandLiveChannelInfo({ patnrId: selectedPatnrId }));
}
}, [brandInfo, dispatch, selectedPatnrId]);
useEffect(() => {
// @@pyh Todo, loading 적용 이후 loading으로 조건 추가
if (selectedPatnrId) {
Spotlight.focus("spotlight" + selectedPatnrId);
}
@@ -78,10 +82,10 @@ export default function FeaturedBrandsPanel() {
/>
)}
{selectedBrandInfo && brandTopImgInfo && (
{brandTopImgInfo && selectedBrandInfo && (
<Banner
selectedBrandInfo={selectedBrandInfo}
brandTopImgInfo={brandTopImgInfo}
selectedBrandInfo={selectedBrandInfo}
/>
)}

View File

@@ -1,4 +1,7 @@
.container {
.tBody {
height: 1080px;
}
.sectionContainer {
padding-left: 60px;
}

View File

@@ -1,6 +1,7 @@
import React from "react";
import React, { useEffect } from "react";
import Scroller from "@enact/sandstone/Scroller";
import { VirtualGridList } from "@enact/sandstone/VirtualList";
import ri from "@enact/ui/resolution";
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
import TItemCard from "../../../components/TItemCard/TItemCard";
@@ -8,8 +9,39 @@ import { $L } from "../../../utils/helperMethods";
import LiveVideoCard from "../LiveVideoCard/LiveVideoCard";
import css from "./LiveChannels.module.less";
// getBrandLiveChannelInfo → brandChanInfo → brandProductInfo
// brandProductInfo = {
// freeShippingFlag = null, // 무료배송 여부
// offerInfo = "", // 제공 정보
// prdtId,
// prdtImgUrl,
// prdtNm,
// priceInfo, // 할인 전 금액, 할인 후(최종) 금액, 리워드여부, save금액, off(할인 %)
// revwGrd = null, 리뷰 등급 (별점)
// soldoutFlag,
// }
/*
<TItemCard
key={prdtId}
imageAlt={prdtNm}
imageSource={prdtImgUrl}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
soldoutFlag={soldoutFlag}
type="horizontal"
/>
*/
const LIVE_CHANNELS_STRING = "LIVE CHANNELS";
const LIST_ITEM_CONF = {
ITEM_WIDTH: 660 * 2,
ITEM_HEIGHT: 236 * 2,
SAPCING: 12 * 2,
};
export default function LiveChannels({ brandChanInfo, brandChannelCnt }) {
const {
alamDispFlag,
@@ -33,30 +65,27 @@ export default function LiveChannels({ brandChanInfo, brandChannelCnt }) {
vtctpYn, // 영상 세로 여부
} = brandChanInfo;
// getOnSaleInfos → saleInfos → saleProductInfos
// saleProductInfos = {
// imgUrl,
// lgCatCd,
// lgCatNm,
// OfferInfo = null,
// patncNm,
// patnrId,
// prdtNm,
// priceInfo
// }
// 현재 OnSalePanel 실사용 = imgUrl, prdtId, prdtNm, priceInfo
console.log();
// getBrandLiveChannelInfo → brandChanInfo → brandProductInfo
// brandProductInfo = {
// freeShippingFlag = null, // 무료배송 여부
// offerInfo = "", // 제공 정보
// prdtId,
// prdtImgUrl,
// prdtNm,
// priceInfo, // 할인 전 금액, 할인 후(최종) 금액, 리워드여부, save금액, off(할인 %)
// revwGrd = null, 리뷰 등급 (별점)
// soldoutFlag,
// }
const renderItem = ({ index, ...rest }) => {
const { prdtImgUrl, prdtId, prdtNm, priceInfo, soldoutFlag } =
brandProductInfo[index];
return (
<>
<TItemCard
key={prdtId}
imageAlt={prdtNm}
imageSource={prdtImgUrl}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
{...rest}
soldoutFlag={soldoutFlag}
type="horizontal"
/>
</>
);
};
return (
<>
@@ -73,69 +102,31 @@ export default function LiveChannels({ brandChanInfo, brandChannelCnt }) {
thumbnailSource={thumbnailImgPath}
title={showNm}
/>
<Scroller
className={css.scroller}
<div className={css.tempContainer}>
{brandProductInfo && (
<VirtualGridList
className={css.virtualGridList}
dataSize={brandProductInfo.length}
direction="vertical"
noScrollByWheel={true}
itemRenderer={renderItem}
itemSize={{
minWidth: ri.scale(LIST_ITEM_CONF.ITEM_WIDTH),
minHeight: ri.scale(LIST_ITEM_CONF.ITEM_HEIGHT),
}}
noScrollByWheel
scrollMode="translate"
spacing={ri.scale(LIST_ITEM_CONF.SAPCING)}
verticalScrollbar="hidden"
>
<ul>
{brandProductInfo &&
brandProductInfo.map(
({
prdtId,
prdtImgUrl,
prdtNm,
priceInfo,
soldoutFlag,
}) => {
return (
<TItemCard
key={prdtId}
imageAlt={prdtNm}
imageSource={prdtImgUrl}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
soldoutFlag={soldoutFlag}
type="horizontal"
/>
);
}
)}
</ul>
</Scroller>
</div>
</div>
)}
{brandChannelCnt > 1 && (
<div>
{"brandChannelCnt(영상의 수)가 1보다 클 경우, type = vertical"}
<ul>
{brandProductInfo &&
brandProductInfo.map(
({
prdtId,
prdtImgUrl,
prdtNm,
priceInfo,
soldoutFlag,
}) => {
return (
<TItemCard
key={prdtId}
imageAlt={prdtNm}
imageSource={prdtImgUrl}
priceInfo={priceInfo}
productId={prdtId}
productName={prdtNm}
soldoutFlag={soldoutFlag}
/>
);
}
)}
</ul>
</div>
)}
</div>

View File

@@ -2,25 +2,25 @@
@import "../../../style/utils.module.less";
.container {
margin-bottom: 58px;
h2 {
margin: 60px 0 24px;
margin: 58px 0 24px;
}
/* normal */
> div {
position: relative;
display: flex;
width: @globalWidth;
.flex(@justifyCenter: flex-start);
width: 100%;
// product scroll container
> .scroller {
width: 720px;
.tempContainer {
.size(@w: 660px, @h: 564px);
.virtualGridList {
// overflow: unset;
ul {
display: flex;
flex-direction: column;
gap: 12px;
height: 564px;
> div {
// overflow: unset !important;
}
}
}
}

View File

@@ -54,13 +54,7 @@ export default memo(function LiveVideoCard({
<div>
<div>
<img
src={IcLiveShow}
alt={
// @@pyh Todo, alt 값 언어처리 유무
LIVE_SHOW_STRING
}
/>
<img src={IcLiveShow} alt={$L(LIVE_SHOW_STRING)} />
<div>
<h3>{title}</h3>
<time>
@@ -68,15 +62,11 @@ export default memo(function LiveVideoCard({
</time>
</div>
</div>
{liveChannelCount && liveChannelCount === 1 && (
// @@pyh, live 방송이라는 조건으로 변경
<div>
<img
src={IcWarning}
alt={
// @@pyh Todo, alt 값 언어처리 유무
WARNING_STRING
}
/>
<img src={IcWarning} alt={$L(WARNING_STRING)} />
<span>{$L(WARNING_MESSAGE)}</span>
</div>
)}

View File

@@ -7,7 +7,6 @@
z-index: 10;
.size(@w: 1002px, @h: 564px);
margin-right: 18px;
border: 4px solid transparent;
border-radius: 12px;
overflow: hidden;
@@ -23,7 +22,7 @@
.size(@w: 100%, @h: 100%);
background-image: linear-gradient(to top, transparent 55%, @COLOR_BLACK);
// top part of video
// top part (live info)
> div:nth-child(1) {
.flex(@justifyCenter: flex-start);
gap: 12px;
@@ -48,7 +47,7 @@
}
}
// bottom part of video
// bottom part (warning message)
> div:nth-child(2) {
.flex(@justifyCenter: flex-start);
gap: 12px;
@@ -66,7 +65,9 @@
/* focused */
&:focus-within {
border: 4px solid @PRIMARY_COLOR_RED;
&::after {
.focused(@borderRadius: 12px);
}
.focusDropShadow();
}
}