6 Commits

Author SHA1 Message Date
cdf0d3de04 [251201] feat: views - NBCUContent.jsx - 기능 개선
🕐 커밋 시간: 2025. 12. 01. 17:04:51

📊 변경 통계:
  • 총 파일: 1개
  • 추가: +1줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUContent.jsx
2025-12-01 17:04:51 +09:00
9ff6064bc9 [251127] feat: Featured Brands - NBCU Series Card Images
🕐 커밋 시간: 2025. 11. 27. 10:53:45

📊 변경 통계:
  • 총 파일: 4개
  • 추가: +6줄
  • 삭제: -3줄

📁 추가된 파일:
  + com.twin.app.shoptime/assets/images/featuredBrands/series-card-1.png
  + com.twin.app.shoptime/assets/images/featuredBrands/series-card-2.png
  + com.twin.app.shoptime/assets/images/featuredBrands/series-card-3.png

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUContent.jsx
2025-11-27 10:53:46 +09:00
cfee554bf6 [251127] feat: Featured Brands - NBCU Series
🕐 커밋 시간: 2025. 11. 27. 10:42:58

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

📁 추가된 파일:
  + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUSectionTitle/NBCUSectionTitle.jsx
  + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUSectionTitle/NBCUSectionTitle.module.less
  + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUSeries/NBCUSeries.jsx
  + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUSeries/NBCUSeries.module.less

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

🔧 주요 변경 내용:
  • 중간 규모 기능 개선
  • 모듈 구조 개선
2025-11-27 10:42:59 +09:00
a5fbb21d43 [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

🔧 주요 변경 내용:
  • 중간 규모 기능 개선
  • 모듈 구조 개선
2025-11-26 20:56:10 +09:00
57cc6dbf20 [251126] feat: Featured Brands - NBCU QuickItem Icon
🕐 커밋 시간: 2025. 11. 26. 20:26:07

📊 변경 통계:
  • 총 파일: 4개
  • 추가: +18줄
  • 삭제: -4줄

📁 추가된 파일:
  + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/QuickMenu/QuickMenuItemNBCU/QuickMenuItemNBCU.jsx
  + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/QuickMenu/QuickMenuItemNBCU/QuickMenuItemNBCU.module.less

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/QuickMenu/QuickMenu.jsx
2025-11-26 20:26:09 +09:00
74d2b827b0 [251126] feat: Featured Brands - NBCU Basic Page
🕐 커밋 시간: 2025. 11. 26. 20:11:39

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

📁 추가된 파일:
  + 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/NBCUContent/NBCUList/NBCUList.module.less

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/FeaturedBrandsPanel.jsx

🔧 주요 변경 내용:
  • 소규모 기능 개선
2025-11-26 20:11:40 +09:00
18 changed files with 778 additions and 27 deletions

View File

@@ -22,3 +22,5 @@ nul
OPTIMAL.md OPTIMAL.md
.docs .docs
GEMINI.md

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 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

@@ -60,6 +60,7 @@ import css from "./FeaturedBrandsPanel.module.less";
import FeaturedCategory from "./FeaturedCategory/FeaturedCategory"; import FeaturedCategory from "./FeaturedCategory/FeaturedCategory";
import FeaturedCreators from "./FeaturedCreators/FeaturedCreators"; import FeaturedCreators from "./FeaturedCreators/FeaturedCreators";
import LiveChannels from "./LiveChannels/LiveChannels"; import LiveChannels from "./LiveChannels/LiveChannels";
import NBCUContent from "./NBCUContent/NBCUContent";
import QuickMenu from "./QuickMenu/QuickMenu"; import QuickMenu from "./QuickMenu/QuickMenu";
import RecommendedShows from "./RecommendedShows/RecommendedShows"; import RecommendedShows from "./RecommendedShows/RecommendedShows";
import Series from "./Series/Series"; import Series from "./Series/Series";
@@ -68,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",
@@ -81,6 +83,7 @@ const STRING_CONF = {
}; };
const TEMPLATE_CODE_CONF = { const TEMPLATE_CODE_CONF = {
NBCU: "NBU00100",
LIVE_CHANNELS: "BRD00101", LIVE_CHANNELS: "BRD00101",
UP_COMING: "BRD00102", UP_COMING: "BRD00102",
TODAYS_DEALS: "BRD00103", TODAYS_DEALS: "BRD00103",
@@ -304,8 +307,42 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
); );
const sortedBrandLayoutInfo = useMemo( const sortedBrandLayoutInfo = useMemo(
() => brandLayoutInfo?.sort((a, b) => a.expsOrd - b.expsOrd) ?? [], () => {
[brandLayoutInfo] if (!panelInfo?.patnrId) {
return [];
}
// NBCU 특별 처리
if (panelInfo?.patnrId === 'NBCU') {
return [
{
shptmBrndOptTpCd: TEMPLATE_CODE_CONF.NBCU,
shptmBrndOptTpNm: 'NBCU',
expsOrd: 1,
},
];
}
return brandLayoutInfo?.sort((a, b) => a.expsOrd - b.expsOrd) ?? [];
},
[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(
@@ -415,6 +452,21 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
<> <>
{sortedBrandLayoutInfo.map((el, idx) => { {sortedBrandLayoutInfo.map((el, idx) => {
switch (el.shptmBrndOptTpCd) { switch (el.shptmBrndOptTpCd) {
case TEMPLATE_CODE_CONF.NBCU: {
return (
<React.Fragment key={el.shptmBrndOptTpCd}>
<NBCUContent
handleItemFocus={handleItemFocus}
spotlightId={TEMPLATE_CODE_CONF.NBCU}
shelfOrder={el.expsOrd}
shelfTitle={el.shptmBrndOptTpNm}
selectedPatnrId={selectedPatnrId}
order={idx + 1}
/>
</React.Fragment>
);
}
case TEMPLATE_CODE_CONF.LIVE_CHANNELS: { case TEMPLATE_CODE_CONF.LIVE_CHANNELS: {
return ( return (
<React.Fragment key={el.shptmBrndOptTpCd}> <React.Fragment key={el.shptmBrndOptTpCd}>
@@ -709,7 +761,7 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
// effect: layout information fetching due to partner id change // effect: layout information fetching due to partner id change
useEffect(() => { useEffect(() => {
if (!fromDetail) { if (!fromDetail && panelInfo?.patnrId) {
dispatch({ type: types.RESET_BRAND_LAYOUT_INFO }); dispatch({ type: types.RESET_BRAND_LAYOUT_INFO });
dispatch(getBrandLayoutInfo({ patnrId: panelInfo?.patnrId })); dispatch(getBrandLayoutInfo({ patnrId: panelInfo?.patnrId }));
setIsInitialFocusOccurred(false); setIsInitialFocusOccurred(false);
@@ -719,14 +771,21 @@ const FeaturedBrandsPanel = ({ isOnTop, panelInfo, spotlightId }) => {
// effect: set selectedPatnrId and selectedPatncNm // effect: set selectedPatnrId and selectedPatncNm
useEffect(() => { useEffect(() => {
if (brandInfo) { if (brandInfo || panelInfo?.patnrId) {
const patnrId = panelInfo?.patnrId; const patnrId = panelInfo?.patnrId;
const patncNm = brandInfo.find((b) => b?.patnrId === patnrId).patncNm;
setSelectedPatncNm(patncNm);
// NBCU 특별 처리
if (patnrId === 'NBCU') {
setSelectedPatncNm('NBCU');
if (!fromDetail) setSelectedPatnrId('NBCU');
} else if (brandInfo) {
const brandItem = brandInfo.find((b) => b?.patnrId === patnrId);
if (brandItem) {
setSelectedPatncNm(brandItem.patncNm);
if (!fromDetail) setSelectedPatnrId(patnrId); if (!fromDetail) setSelectedPatnrId(patnrId);
} }
}
}
}, [brandInfo, panelInfo?.patnrId]); }, [brandInfo, panelInfo?.patnrId]);
// effect: data fetching based on brandLayoutInfo and selectedPatnrId // effect: data fetching based on brandLayoutInfo and selectedPatnrId
@@ -958,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

@@ -0,0 +1,182 @@
import React, { memo, useCallback, useState, useEffect } from "react";
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
import NBCUSectionTitle from "./NBCUSectionTitle/NBCUSectionTitle";
import { $L } from "../../../utils/helperMethods";
import css from "./NBCUContent.module.less";
import NBCUList from "./NBCUList/NBCUList";
import NBCUSeries from "./NBCUSeries/NBCUSeries";
import seriesCard1 from "../../../../assets/images/featuredBrands/series-card-1.png";
import seriesCard2 from "../../../../assets/images/featuredBrands/series-card-2.png";
import seriesCard3 from "../../../../assets/images/featuredBrands/series-card-3.png";
const STRING_CONF = {
NBCU: "NBCU",
PICKED_FOR_YOU: "PICKED FOR YOU",
};
// Mock data for Series
const MOCK_BRAND_SERIES_GROUP_INFO = [
{
seriesId: "series-1",
seriesNm: "Drama Collection",
seriesImgUrl: seriesCard1,
patnrId: "nbcu-partner-1",
brandSeriesProductInfo: Array.from({ length: 6 }).map((_, i) => ({
productId: `drama-${i}`,
productNm: `Drama Show ${i + 1}`,
imageUrl: "assets/images/img-thumb-empty-product@3x.png",
priceInfo: "$15.00|$10.00|N|$5.00|33%|PROMO|2025-12-31",
})),
},
{
seriesId: "series-2",
seriesNm: "Comedy Series",
seriesImgUrl: seriesCard2,
patnrId: "nbcu-partner-1",
brandSeriesProductInfo: Array.from({ length: 6 }).map((_, i) => ({
productId: `comedy-${i}`,
productNm: `Comedy Show ${i + 1}`,
imageUrl: "assets/images/img-thumb-empty-product@3x.png",
priceInfo: "$12.00|$8.00|N|$4.00|33%|PROMO|2025-12-31",
})),
},
{
seriesId: "series-3",
seriesNm: "Sci-Fi Originals",
seriesImgUrl: seriesCard3,
patnrId: "nbcu-partner-1",
brandSeriesProductInfo: Array.from({ length: 6 }).map((_, i) => ({
productId: `scifi-${i}`,
productNm: `Sci-Fi Show ${i + 1}`,
imageUrl: "assets/images/img-thumb-empty-product@3x.png",
priceInfo: "$18.00|$12.00|N|$6.00|33%|PROMO|2025-12-31",
})),
},
];
const MOCK_BRAND_SERIES_INFO = [
{ seriesId: "series-1", seriesNm: "LOVE ISLAND" },
{ seriesId: "series-2", seriesNm: "TOP CHEF" },
{ seriesId: "series-3", seriesNm: "BELOW DECK" },
];
const SpottableDiv = Spottable('div');
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
const NBCUContent = ({
handleItemFocus,
spotlightId,
shelfOrder,
selectedPatnrId,
shelfTitle,
order,
}) => {
const [firstChk, setFirstChk] = useState(0);
const [selectedSeriesId, setSelectedSeriesId] = useState(null);
useEffect(() => {
console.log('[NBCUContent] Rendered. order:', order);
}, [order]);
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]);
return (
<Container
className={css.container}
data-shelf-order={order}
data-wheel-point
spotlightId={spotlightId}
>
<SectionTitle
title={$L(STRING_CONF.NBCU)}
data-title="nbcu"
label="NBCU Heading 1"
/>
<NBCUList
handleItemFocus={_handleItemFocus}
spotlightId={spotlightId}
shelfOrder={shelfOrder}
shelfTitle={shelfTitle}
selectedPatnrId={selectedPatnrId}
/>
{/* Keyword Bubble Section (Dummy) */}
{/* <div className={css.keywordContainer}>
{['Action', 'Comedy', 'Drama', 'Sci-Fi', 'Thriller', 'Romance', 'Documentary'].map((keyword, index) => (
<SpottableDiv
key={index}
className={css.keywordBubble}
onClick={() => console.log(`Clicked keyword: ${keyword}`)}
>
{keyword}
</SpottableDiv>
))}
</div> */}
{/* Picked For You Section Title */}
<NBCUSectionTitle
title={$L(STRING_CONF.PICKED_FOR_YOU)}
data-title="picked-for-you"
label="Picked For You Heading"
isBlack={true}
/>
{/* Series Component with Mock Data */}
<NBCUSeries
brandSeriesGroupInfo={MOCK_BRAND_SERIES_GROUP_INFO}
brandSeriesInfo={MOCK_BRAND_SERIES_INFO}
fromGNB={false}
fromQuickMenu={false}
handleItemFocus={_handleItemFocus}
order={order}
shelfOrder={shelfOrder}
shelfTitle={shelfTitle}
spotlightId={`${spotlightId}-series`}
selectedPatncNm="NBCU"
selectedPatnrId={selectedPatnrId}
selectedSeriesId={selectedSeriesId}
setSelectedSeriesId={setSelectedSeriesId}
/>
</Container>
);
};
export default memo(NBCUContent);

View File

@@ -0,0 +1,36 @@
@import "../../../style/CommonStyle.module.less";
.container {
display: flex;
flex-direction: column;
padding: 50px 0; // Adjust padding as needed
}
.keywordContainer {
display: flex;
flex-wrap: wrap;
gap: 12px;
padding: 0 60px; // Match side padding of other contents
margin-bottom: 30px;
}
.keywordBubble {
display: flex;
align-items: center;
justify-content: center;
padding: 10px 24px;
border-radius: 30px;
background-color: rgba(255, 255, 255, 0.1);
color: #ffffff;
font-size: 24px;
font-weight: 500;
cursor: pointer;
border: 2px solid transparent;
transition: all 0.2s ease-in-out;
&:focus, &:hover {
background-color: rgba(255, 255, 255, 0.2);
border-color: #ffffff;
transform: scale(1.05);
}
}

View File

@@ -0,0 +1,66 @@
import React, { useCallback, useMemo } from 'react';
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
import TItemCardNew from '../../../../components/TItemCard/TItemCard.new';
import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList';
import css from './NBCUList.module.less';
// 더미 데이터 생성
// priceInfo format: originalPrice|discountedPrice|rewardFlag|discountAmount|discountRate|promotionCode|promotionDate
const DUMMY_DATA = Array.from({ length: 10 }).map((_, index) => ({
id: `nbcu-item-${index}`,
title: `NBCU Content ${index + 1}`,
imgUrl: 'assets/images/img-thumb-empty-product@3x.png',
priceInfo: '$20.00|$10.00|N|$10.00|50%|PROMO|2025-12-31',
}));
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: '' }, enterTo: 'last-focused' },
'div'
);
const NBCUList = ({ handleItemFocus, spotlightId, shelfTitle, shelfOrder }) => {
const renderItem = useCallback(
({ index, ...rest }) => {
const item = DUMMY_DATA[index];
const labelText = `${index + 1} of ${DUMMY_DATA.length}`;
return (
<TItemCardNew
{...rest}
key={item.id}
imageSource={item.imgUrl}
productName={item.title}
priceInfo={item.priceInfo}
spotlightId={`nbcu-spotlightId-${index}`}
shelfId={spotlightId}
shelfLocation={shelfOrder}
shelfTitle={shelfTitle}
label={labelText}
onFocus={handleItemFocus}
onClick={() => {
console.log('Clicked NBCU item:', item.title);
}}
/>
);
},
[handleItemFocus, spotlightId, shelfOrder, shelfTitle]
);
return (
<Container className={css.container} spotlightId="nbcu-list-id">
<TVirtualGridList
dataSize={DUMMY_DATA.length}
direction="horizontal"
itemHeight={438}
itemWidth={324}
spacing={18}
renderItem={renderItem}
className={css.tVirtualGridList}
/>
</Container>
);
};
export default React.memo(NBCUList);

View File

@@ -0,0 +1,22 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
display: flex;
position: relative;
.size(@w: 100%, @h: 438px);
padding-right: 18px;
// tVirtualGridListContainer
> div:nth-child(1) {
.size(@w: 100%, @h: inherit);
&.tVirtualGridList {
padding-left: 60px;
> div:nth-child(3) {
right: -18px;
}
}
}
}

View File

@@ -0,0 +1,28 @@
import React, { memo } from "react";
import classNames from "classnames";
import css from "./NBCUSectionTitle.module.less";
export default memo(function NBCUSectionTitle({
className,
itemCount,
title,
label,
isBlack = false,
...rest
}) {
return (
<h2
className={classNames(css.sectionTitle, isBlack && css.blackTitle, className)}
aria-label={label ? label : title}
tabIndex={-1}
aria-live="polite"
aria-atomic="true"
{...rest}
>
{title}
{itemCount && <span>({itemCount})</span>}
</h2>
);
});

View File

@@ -0,0 +1,31 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.sectionTitle {
position: relative;
.flex(@justifyCenter: flex-start);
min-height: 50px;
font-weight: bold;
font-size: 42px;
color: #000000 !important;
&::before {
display: inline-block;
content: "";
.size(@w: 6px, @h: 36px);
margin-right: 12px;
background-color: #000000 !important;
}
span {
margin-left: 10px;
}
}
.blackTitle {
color: #000000;
&::before {
background-color: #000000;
}
}

View File

@@ -0,0 +1,131 @@
import React, { memo, useCallback, useEffect, useState } from "react";
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import NBCUSectionTitle from "../NBCUSectionTitle/NBCUSectionTitle";
import { $L } from "../../../../utils/helperMethods";
import css from "./NBCUSeries.module.less";
import SeriesContents from "../../Series/SeriesContents/SeriesContents";
import SeriesNav from "../../Series/SeriesNav/SeriesNav";
const STRING_CONF = {
SERIES: "SERIES",
};
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
const NBCUSeries = ({
brandSeriesGroupInfo,
brandSeriesInfo,
fromGNB,
fromQuickMenu,
handleItemFocus,
order,
shelfOrder,
shelfTitle,
spotlightId,
selectedPatncNm,
selectedPatnrId,
selectedSeriesId,
setSelectedSeriesId,
}) => {
const [filteredBrandSeriesGroupInfo, setFilteredSeriesGroupInfo] = useState();
const [firstChk, setFirstChk] = useState(0);
useEffect(() => {
if (!selectedSeriesId) {
return setFilteredSeriesGroupInfo(brandSeriesGroupInfo);
}
setFilteredSeriesGroupInfo(
brandSeriesGroupInfo.filter(
({ seriesId }) => seriesId === selectedSeriesId
)
);
}, [brandSeriesGroupInfo, selectedSeriesId]);
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 = "series, 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("series, Heading1,", "");
c.setAttribute("aria-label", newcAriaLabel);
}
}
} else {
return;
}
}, [handleItemFocus, firstChk]);
return (
<Container
className={css.container}
data-shelf-order={order}
data-wheel-point
spotlightId={spotlightId}
>
{/* <NBCUSectionTitle title={$L(STRING_CONF.SERIES)} data-title="series" isBlack={true} /> */}
<SeriesNav
brandSeriesInfo={brandSeriesInfo}
fromGNB={fromGNB}
fromQuickMenu={fromQuickMenu}
handleItemFocus={_handleItemFocus}
selectedPatncNm={selectedPatncNm}
selectedPatnrId={selectedPatnrId}
selectedSeriesId={selectedSeriesId}
setSelectedSeriesId={setSelectedSeriesId}
/>
{filteredBrandSeriesGroupInfo &&
filteredBrandSeriesGroupInfo.map(
(
{
brandSeriesProductInfo,
patnrId,
seriesId,
seriesImgUrl,
seriesNm,
},
contentsIndex
) => (
<SeriesContents
brandSeriesProductInfo={brandSeriesProductInfo}
filteredBrandLength={filteredBrandSeriesGroupInfo.length}
contentsIndex={contentsIndex}
handleItemFocus={_handleItemFocus}
isCarousel={!selectedSeriesId}
key={`${spotlightId}-${contentsIndex}`}
patnrId={patnrId}
selectedPatnrId={selectedPatnrId}
selectedSeriesId={selectedSeriesId}
seriesId={seriesId}
seriesImgUrl={seriesImgUrl}
seriesNm={seriesNm}
spotlightId={spotlightId}
shelfOrder={shelfOrder}
shelfTitle={shelfTitle}
selectedPatncNm={selectedPatncNm}
/>
)
)}
</Container>
);
};
export default memo(NBCUSeries);

View File

@@ -0,0 +1,12 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
width: 100%;
margin-bottom: 36px;
h2 {
margin-bottom: 24px;
padding-left: 60px;
}
}

View File

@@ -5,7 +5,8 @@ import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDeco
import TScroller from "../../../components/TScroller/TScroller"; import TScroller from "../../../components/TScroller/TScroller";
import useScrollTo from "../../../hooks/useScrollTo"; import useScrollTo from "../../../hooks/useScrollTo";
import { scaleW } from "../../../utils/helperMethods"; import { scaleW } from "../../../utils/helperMethods";
import QuickMenuItem from "../QuickMenu/QuickMenuItem/QuickMenuItem"; import QuickMenuItem from "./QuickMenuItem/QuickMenuItem";
import QuickMenuItemNBCU from "./QuickMenuItemNBCU/QuickMenuItemNBCU";
import css from "./QuickMenu.module.less"; import css from "./QuickMenu.module.less";
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
@@ -76,7 +77,32 @@ const QuickMenu = ({
noScrollByWheel noScrollByWheel
> >
<ul ref={ulRef}> <ul ref={ulRef}>
{panelPatnrId === 'NBCU' ? (
<>
<QuickMenuItemNBCU
itemIndex={0}
handleItemFocus={_handleItemFocus}
key="nbcu-item"
resetStates={resetStates}
scrollLeft={scrollLeft}
selectedPatnrId={selectedPatnrId}
label={"1 of " + (brandInfo.length + 1)}
/>
{brandInfo.map((brandInfoItem, itemIndex) => ( {brandInfo.map((brandInfoItem, itemIndex) => (
<QuickMenuItem
brandInfoItem={brandInfoItem}
itemIndex={itemIndex + 1}
handleItemFocus={_handleItemFocus}
key={"brand-info" + itemIndex}
resetStates={resetStates}
scrollLeft={scrollLeft}
selectedPatnrId={selectedPatnrId}
label={(itemIndex + 2) + " of " + (brandInfo.length + 1)}
/>
))}
</>
) : (
brandInfo.map((brandInfoItem, itemIndex) => (
<QuickMenuItem <QuickMenuItem
brandInfoItem={brandInfoItem} brandInfoItem={brandInfoItem}
itemIndex={itemIndex} itemIndex={itemIndex}
@@ -85,9 +111,10 @@ const QuickMenu = ({
resetStates={resetStates} resetStates={resetStates}
scrollLeft={scrollLeft} scrollLeft={scrollLeft}
selectedPatnrId={selectedPatnrId} selectedPatnrId={selectedPatnrId}
label={itemIndex * 1 + 1 + " of " + brandInfo.length} label={(itemIndex + 1) + " of " + brandInfo.length}
/> />
))} ))
)}
</ul> </ul>
</TScroller> </TScroller>
</Container> </Container>

View File

@@ -0,0 +1,96 @@
import React, { memo, useCallback } from "react";
import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";
import Spottable from "@enact/spotlight/Spottable";
import IcPartnersDefault from "../../../../../assets/images/ic-tab-partners-default@3x.png";
import { resetPanels, updatePanel } from "../../../../actions/panelActions";
import CustomImage from "../../../../components/CustomImage/CustomImage";
import useScrollReset from "../../../../hooks/useScrollReset";
import { panel_names } from "../../../../utils/Config";
import css from "./QuickMenuItemNBCU.module.less";
const SpottableComponent = Spottable("li");
const QuickMenuItemNBCU = ({
itemIndex,
handleItemFocus,
resetStates,
scrollLeft,
selectedPatnrId,
label,
...rest
}) => {
const { handleScrollReset, handleStopScrolling } = useScrollReset(
scrollLeft,
true
);
const dispatch = useDispatch();
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
const patnrId = "NBCU";
const handleBlur = useCallback(() => {
if (itemIndex !== 0) {
return;
}
handleStopScrolling();
}, [handleStopScrolling, itemIndex]);
const handleClick = useCallback(() => {
if (patnrId === (selectedPatnrId ?? panelInfo?.patnrId)) {
return;
}
const from = "menu";
const name = panel_names.FEATURED_BRANDS_PANEL;
dispatch(resetPanels([{ name }]));
dispatch(updatePanel({ name, panelInfo: { from, patnrId } }));
resetStates();
}, [dispatch, patnrId, resetStates, selectedPatnrId]);
const handleFocus = useCallback(() => {
if (handleItemFocus) handleItemFocus();
if (itemIndex !== 0) return;
handleScrollReset();
}, [handleScrollReset, handleItemFocus, itemIndex]);
const selected =
(selectedPatnrId ?? panelInfo?.patnrId) === patnrId ? "Selected, " : "";
const ariaLabel = selected + "Channel NBCU, Tap " + label;
return (
<SpottableComponent
className={classNames(
css.brand,
(selectedPatnrId ?? panelInfo?.patnrId) === patnrId && css.selected
)}
data-menu-index={itemIndex}
onBlur={handleBlur}
onClick={handleClick}
onFocus={handleFocus}
spotlightId={"spotlightId-NBCU"}
aria-label={ariaLabel}
{...rest}
>
<div>
<CustomImage
src="assets/images/featuredBrands/image-nbcu.png"
alt="NBCU"
fallbackSrc={IcPartnersDefault}
ariaLabel="NBCU"
/>
</div>
</SpottableComponent>
);
};
export default memo(QuickMenuItemNBCU);

View File

@@ -0,0 +1,54 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.brand {
position: relative;
.flex();
.size(@w: 144px, @h: 144px);
> div {
position: relative;
// NBCU image
> img {
.size(@w: 120px, @h: 120px);
border-radius: 50%;
}
}
&.selected {
// NBCU image
.size(@w: 144px, @h: 144px);
> div {
&:after {
.focused(@boxShadow: 0px, @borderRadius: 50%);
}
> img {
.size(@w: 144px, @h: 144px);
border-radius: 50%;
}
}
}
&:focus {
// NBCU image
&:after {
.size(@w:100%, @h:6px);
position: absolute;
left: 0;
bottom: -18px;
background: @PRIMARY_COLOR_RED;
content: "";
}
> div {
&:after {
.focused(@boxShadow: 0px, @borderRadius: 50%);
border-color: @PRIMARY_COLOR_RED;
}
> img {
.size(@w: 120px, @h: 120px);
border-radius: 50%;
}
}
}
}