[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"; import css from "./Banner.module.less";
export default function Banner({ selectedBrandInfo, brandTopImgInfo }) { export default function Banner({ brandTopImgInfo, selectedBrandInfo }) {
const { logoImgAlt, logoImgPath, patncNm } = selectedBrandInfo;
const { topImgAlt, topImgPath } = brandTopImgInfo; const { topImgAlt, topImgPath } = brandTopImgInfo;
const { logoImgAlt, logoImgPath, patncNm } = selectedBrandInfo;
return ( return (
<div className={css.container}> <div className={css.container}>

View File

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

View File

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

View File

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

View File

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

View File

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