[251126] feat: Featured Brands - NBCU Page Rendering using BestSeller

🕐 커밋 시간: 2025. 11. 26. 20:56:09

📊 변경 통계:
  • 총 파일: 7개
  • 추가: +145줄
  • 삭제: -64줄

📁 추가된 파일:
  + com.twin.app.shoptime/assets/images/featuredBrands/image-bg.png

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/Banner/Banner.jsx
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUContent.jsx
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUContent.module.less
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUList/NBCUList.jsx
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/QuickMenu/QuickMenu.jsx

🔧 주요 변경 내용:
  • 중간 규모 기능 개선
  • 모듈 구조 개선
This commit is contained in:
2025-11-26 20:56:10 +09:00
parent 57cc6dbf20
commit a5fbb21d43
7 changed files with 145 additions and 64 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -1,6 +1,7 @@
import React, { memo } from "react"; import React, { memo } from "react";
import IcPartnersDefault from "../../../../assets/images/ic-tab-partners-default@3x.png"; import IcPartnersDefault from "../../../../assets/images/ic-tab-partners-default@3x.png";
import NBCULogoImage from "../../../../assets/images/featuredBrands/image-nbcu.png";
import CustomImage from "../../../components/CustomImage/CustomImage"; import CustomImage from "../../../components/CustomImage/CustomImage";
import css from "./Banner.module.less"; import css from "./Banner.module.less";
@@ -15,16 +16,20 @@ export default memo(function Banner({
const { patncLogoPath, patncNm } = selectedBrandInfo; const { patncLogoPath, patncNm } = selectedBrandInfo;
const { topImgAlt, topImgPath } = brandTopImgInfo; const { topImgAlt, topImgPath } = brandTopImgInfo;
// NBCU 로고 이미지 처리
const logoSrc = panelPatnrId === 'NBCU' ? NBCULogoImage : patncLogoPath;
const logoName = panelPatnrId === 'NBCU' ? 'Peacock' : patncNm;
return ( return (
<div className={css.container}> <div className={css.container}>
<figure> <figure>
<CustomImage <CustomImage
src={patncLogoPath} src={logoSrc}
alt={patncNm} alt={logoName}
fallbackSrc={IcPartnersDefault} fallbackSrc={IcPartnersDefault}
ariaLabel={patncNm} ariaLabel={logoName}
/> />
<figcaption>{patncNm}</figcaption> <figcaption>{logoName}</figcaption>
</figure> </figure>
<CustomImage src={topImgPath} alt={topImgAlt} ariaLabel={topImgAlt} /> <CustomImage src={topImgPath} alt={topImgAlt} ariaLabel={topImgAlt} />
</div> </div>

View File

@@ -69,6 +69,7 @@ import TodaysDeals from "./TodaysDeals/TodaysDeals";
import UpComing from "./UpComing/UpComing"; import UpComing from "./UpComing/UpComing";
import { setContainerLastFocusedElement } from "@enact/spotlight/src/container"; import { setContainerLastFocusedElement } from "@enact/spotlight/src/container";
import { sortedIndexOf } from "lodash"; import { sortedIndexOf } from "lodash";
import NBCUBgImage from "../../../assets/images/featuredBrands/image-bg.png";
const STRING_CONF = { const STRING_CONF = {
CANCEL: "CANCEL", CANCEL: "CANCEL",
@@ -326,6 +327,24 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
[brandLayoutInfo, panelInfo?.patnrId] [brandLayoutInfo, panelInfo?.patnrId]
); );
const processedBrandTopImgInfo = useMemo(
() => {
// NBCU 특별 처리
if (panelInfo?.patnrId === 'NBCU') {
return {
topImgPath: NBCUBgImage,
topImgAlt: 'NBCU Background Image',
};
}
// 다른 브랜드: brandTopImgInfo가 유효한 객체여야 함
if (brandTopImgInfo && brandTopImgInfo.topImgPath) {
return brandTopImgInfo;
}
return null;
},
[brandTopImgInfo, panelInfo?.patnrId]
);
const doSendLogGNB = useCallback( const doSendLogGNB = useCallback(
(containerId, shelfOrder) => { (containerId, shelfOrder) => {
if ( if (
@@ -440,6 +459,9 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
handleItemFocus={handleItemFocus} handleItemFocus={handleItemFocus}
spotlightId={TEMPLATE_CODE_CONF.NBCU} spotlightId={TEMPLATE_CODE_CONF.NBCU}
shelfOrder={el.expsOrd} shelfOrder={el.expsOrd}
shelfTitle={el.shptmBrndOptTpNm}
selectedPatnrId={selectedPatnrId}
order={idx + 1}
/> />
</React.Fragment> </React.Fragment>
); );
@@ -995,10 +1017,10 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
/> />
)} )}
{brandInfo && brandTopImgInfo && ( {((brandInfo && processedBrandTopImgInfo) || panelInfo?.patnrId === 'NBCU') && processedBrandTopImgInfo && (
<Banner <Banner
brandInfo={brandInfo} brandInfo={brandInfo}
brandTopImgInfo={brandTopImgInfo} brandTopImgInfo={processedBrandTopImgInfo}
panelPatnrId={panelInfo?.patnrId} panelPatnrId={panelInfo?.patnrId}
/> />
)} )}

View File

@@ -1,14 +1,78 @@
import React, { memo } from 'react'; import React, { memo, useCallback, useState } from "react";
import css from './NBCUContent.module.less';
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
import { $L } from "../../../utils/helperMethods";
import css from "./NBCUContent.module.less";
import NBCUList from "./NBCUList/NBCUList";
const STRING_CONF = {
NBCU: "NBCU",
};
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
const NBCUContent = ({
handleItemFocus,
spotlightId,
shelfOrder,
selectedPatnrId,
shelfTitle,
order,
}) => {
const [firstChk, setFirstChk] = useState(0);
const _handleItemFocus = useCallback(() => {
if (handleItemFocus) handleItemFocus(spotlightId, shelfOrder);
const c = Spotlight.getCurrent();
if (firstChk === 0) {
if (c) {
let cAriaLabel = c.getAttribute("aria-label");
if (cAriaLabel) {
cAriaLabel = "NBCU, Heading1," + cAriaLabel;
c.setAttribute("aria-label", cAriaLabel);
}
}
setFirstChk(1);
} else if (firstChk === 1) {
if (c) {
let cAriaLabel = c.getAttribute("aria-label");
if (cAriaLabel) {
const newcAriaLabel = cAriaLabel.replace("NBCU, Heading1,", "");
c.setAttribute("aria-label", newcAriaLabel);
}
}
} else {
return;
}
}, [handleItemFocus, firstChk, spotlightId, shelfOrder]);
const NBCUContent = ({ handleItemFocus, spotlightId, shelfOrder = 1 }) => {
return ( return (
<div className={css.container} data-wheel-point> <Container
<div className={css.content}> className={css.container}
<h2 className={css.title}>NBCU</h2> data-shelf-order={order}
<p className={css.message}>Content Coming Soon</p> data-wheel-point
</div> spotlightId={spotlightId}
</div> >
<SectionTitle
title={$L(STRING_CONF.NBCU)}
data-title="nbcu"
label="NBCU Heading 1"
/>
<NBCUList
handleItemFocus={_handleItemFocus}
spotlightId={spotlightId}
shelfOrder={shelfOrder}
shelfTitle={shelfTitle}
selectedPatnrId={selectedPatnrId}
/>
</Container>
); );
}; };

View File

@@ -1,28 +1 @@
@import "../../../style/CommonStyle.module.less"; @import "../../../style/CommonStyle.module.less";
.container {
width: 100%;
padding: 40px 60px;
margin-bottom: 58px;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 400px;
}
.title {
font-size: 32px;
font-weight: bold;
margin-bottom: 20px;
color: #333;
}
.message {
font-size: 18px;
color: #666;
margin: 0;
}

View File

@@ -49,7 +49,7 @@ const NBCUList = ({ handleItemFocus, spotlightId, shelfTitle, shelfOrder }) => {
); );
return ( return (
<Container className={css.container} spotlightId={spotlightId}> <Container className={css.container} spotlightId="nbcu-list-id">
<TVirtualGridList <TVirtualGridList
dataSize={DUMMY_DATA.length} dataSize={DUMMY_DATA.length}
direction="horizontal" direction="horizontal"

View File

@@ -77,27 +77,44 @@ const QuickMenu = ({
noScrollByWheel noScrollByWheel
> >
<ul ref={ulRef}> <ul ref={ulRef}>
<QuickMenuItemNBCU {panelPatnrId === 'NBCU' ? (
itemIndex={0} <>
handleItemFocus={_handleItemFocus} <QuickMenuItemNBCU
key="nbcu-item" itemIndex={0}
resetStates={resetStates} handleItemFocus={_handleItemFocus}
scrollLeft={scrollLeft} key="nbcu-item"
selectedPatnrId={selectedPatnrId} resetStates={resetStates}
label={"1 of " + (brandInfo.length + 1)} scrollLeft={scrollLeft}
/> selectedPatnrId={selectedPatnrId}
{brandInfo.map((brandInfoItem, itemIndex) => ( label={"1 of " + (brandInfo.length + 1)}
<QuickMenuItem />
brandInfoItem={brandInfoItem} {brandInfo.map((brandInfoItem, itemIndex) => (
itemIndex={itemIndex + 1} <QuickMenuItem
handleItemFocus={_handleItemFocus} brandInfoItem={brandInfoItem}
key={"brand-info" + itemIndex} itemIndex={itemIndex + 1}
resetStates={resetStates} handleItemFocus={_handleItemFocus}
scrollLeft={scrollLeft} key={"brand-info" + itemIndex}
selectedPatnrId={selectedPatnrId} resetStates={resetStates}
label={(itemIndex + 2) + " of " + (brandInfo.length + 1)} scrollLeft={scrollLeft}
/> selectedPatnrId={selectedPatnrId}
))} label={(itemIndex + 2) + " of " + (brandInfo.length + 1)}
/>
))}
</>
) : (
brandInfo.map((brandInfoItem, itemIndex) => (
<QuickMenuItem
brandInfoItem={brandInfoItem}
itemIndex={itemIndex}
handleItemFocus={_handleItemFocus}
key={"brand-info" + itemIndex}
resetStates={resetStates}
scrollLeft={scrollLeft}
selectedPatnrId={selectedPatnrId}
label={(itemIndex + 1) + " of " + brandInfo.length}
/>
))
)}
</ul> </ul>
</TScroller> </TScroller>
</Container> </Container>