[251209] feat: NBCU-ShopByShow-2
🕐 커밋 시간: 2025. 12. 09. 15:48:17 📊 변경 통계: • 총 파일: 11개 • 추가: +25줄 • 삭제: -114줄 📁 추가된 파일: + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShow.figma.jsx + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowSection/ShopByShowImageCard/ShopByShowImageCard.jsx + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowSection/ShopByShowImageCard/ShopByShowImageCard.module.less + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowSection/ShopByShowProductList/ShopByShowProductList.jsx + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowSection/ShopByShowProductList/ShopByShowProductList.module.less + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowSection/ShopByShowSection.jsx + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowSection/ShopByShowSection.module.less 📝 수정된 파일: ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowContents/ShopByShowContents.module.less ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowList.jsx ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowList.module.less ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/ShopByShow/ShopByShowList/ShopByShowNav/ShopByShowNav.jsx 🔧 주요 변경 내용: • 소규모 기능 개선 • 코드 정리 및 최적화 • 모듈 구조 개선 Performance: 코드 최적화로 성능 개선 기대
This commit is contained in:
@@ -0,0 +1,79 @@
|
|||||||
|
<div style={{width: '100%', height: '100%', paddingTop: 63, paddingLeft: 60, flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'flex-start', gap: 10, display: 'inline-flex'}}>
|
||||||
|
<div style={{width: 1800, height: 42, justifyContent: 'flex-start', alignItems: 'center', gap: 12, display: 'inline-flex'}}>
|
||||||
|
<div style={{width: 6, height: 36, background: '#C70850'}} />
|
||||||
|
<div style={{textAlign: 'center', color: 'black', fontSize: 42, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 42, wordWrap: 'break-word'}}>Chef Gadget's</div>
|
||||||
|
</div>
|
||||||
|
<div style={{alignSelf: 'stretch', paddingTop: 20, paddingBottom: 20, justifyContent: 'flex-start', alignItems: 'flex-start', gap: 19, display: 'inline-flex'}}>
|
||||||
|
<div style={{width: 665, alignSelf: 'stretch', padding: 18, background: 'white', overflow: 'hidden', borderRadius: 12, outline: '1px #DADADA solid', outlineOffset: '-1px', justifyContent: 'flex-start', alignItems: 'flex-start', display: 'flex'}}>
|
||||||
|
<img style={{flex: '1 1 0', alignSelf: 'stretch', padding: 18, background: 'linear-gradient(180deg, #EC79B8 0%, #CD4F93 100%)', border: '1px rgba(218, 218, 218, 0.54) solid'}} src="https://placehold.co/629x402" alt="Chef Gadget's featured product" />
|
||||||
|
</div>
|
||||||
|
<div style={{width: 323, padding: 18, background: 'white', borderRadius: 12, outline: '1px #DADADA solid', outlineOffset: '-1px', flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'flex-start', display: 'inline-flex'}}>
|
||||||
|
<div style={{alignSelf: 'stretch', height: 287, position: 'relative'}}>
|
||||||
|
<img style={{width: 287, height: 287, left: 0, top: 0, position: 'absolute'}} src="https://placehold.co/287x287" alt="Bravo's Top Chef product" />
|
||||||
|
<div style={{width: 71, height: 72, left: 216, top: 215, position: 'absolute', background: '#EFEEF0'}} />
|
||||||
|
</div>
|
||||||
|
<div style={{alignSelf: 'stretch', height: 82, paddingTop: 8, paddingBottom: 10, justifyContent: 'flex-start', alignItems: 'flex-start', gap: 10, display: 'inline-flex'}}>
|
||||||
|
<div style={{flex: '1 1 0', color: 'black', fontSize: 24, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 32, wordWrap: 'break-word'}}>Bravo's Top Chef</div>
|
||||||
|
</div>
|
||||||
|
<div style={{paddingBottom: 3, justifyContent: 'center', alignItems: 'center', gap: 4, display: 'inline-flex'}}>
|
||||||
|
<div style={{color: '#C70850', fontSize: 30, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 30, wordWrap: 'break-word'}}>$32.98</div>
|
||||||
|
<div style={{color: '#808080', fontSize: 18, fontFamily: 'LG Smart UI', fontWeight: '400', textDecoration: 'line-through', lineHeight: 18, wordWrap: 'break-word'}}>$150.00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{width: 323, padding: 18, background: 'white', boxShadow: '0px 0px 30px rgba(0, 0, 0, 0.45)', borderRadius: 12, outline: '2px #C70850 solid', outlineOffset: '-2px', flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'flex-start', display: 'inline-flex'}}>
|
||||||
|
<img style={{alignSelf: 'stretch', height: 287}} src="https://placehold.co/287x287" alt="Top Chef Knife Tote Bag" />
|
||||||
|
<div style={{alignSelf: 'stretch', height: 82, paddingTop: 8, paddingBottom: 10, justifyContent: 'flex-start', alignItems: 'flex-start', gap: 10, display: 'inline-flex'}}>
|
||||||
|
<div style={{flex: '1 1 0', color: 'black', fontSize: 24, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 32, wordWrap: 'break-word'}}>Top Chef Knife Tote Bag</div>
|
||||||
|
</div>
|
||||||
|
<div style={{paddingBottom: 3, justifyContent: 'center', alignItems: 'center', gap: 4, display: 'inline-flex'}}>
|
||||||
|
<div style={{color: '#C70850', fontSize: 30, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 30, wordWrap: 'break-word'}}>$32.98</div>
|
||||||
|
<div style={{color: '#808080', fontSize: 18, fontFamily: 'LG Smart UI', fontWeight: '400', textDecoration: 'line-through', lineHeight: 18, wordWrap: 'break-word'}}>$150.00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{width: 323, padding: 18, background: 'white', borderRadius: 12, outline: '1px #DADADA solid', outlineOffset: '-1px', flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'flex-start', display: 'inline-flex'}}>
|
||||||
|
<div style={{alignSelf: 'stretch', height: 287, position: 'relative'}}>
|
||||||
|
<img style={{width: 287, height: 287, left: 0, top: 0, position: 'absolute'}} src="https://placehold.co/287x287" alt="Salt, Maldon Traditional product on sale 17%" />
|
||||||
|
<div style={{width: 60, height: 60, left: 219, top: 219, position: 'absolute', background: '#C70850', borderRadius: 1000, justifyContent: 'center', alignItems: 'center', display: 'inline-flex'}}>
|
||||||
|
<div style={{justifyContent: 'center', display: 'flex', flexDirection: 'column', color: 'white', fontSize: 24, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 26, wordWrap: 'break-word'}}>17%</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{alignSelf: 'stretch', height: 82, paddingTop: 8, paddingBottom: 10, justifyContent: 'flex-start', alignItems: 'flex-start', gap: 10, display: 'inline-flex'}}>
|
||||||
|
<div style={{flex: '1 1 0', color: 'black', fontSize: 24, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 32, wordWrap: 'break-word'}}>Salt, Maldon Traditional</div>
|
||||||
|
</div>
|
||||||
|
<div style={{paddingBottom: 3, justifyContent: 'center', alignItems: 'center', gap: 4, display: 'inline-flex'}}>
|
||||||
|
<div style={{color: '#C70850', fontSize: 30, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 30, wordWrap: 'break-word'}}>$32.98</div>
|
||||||
|
<div style={{color: '#808080', fontSize: 18, fontFamily: 'LG Smart UI', fontWeight: '400', textDecoration: 'line-through', lineHeight: 18, wordWrap: 'break-word'}}>$150.00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{width: 323, padding: 18, background: 'white', borderRadius: 12, outline: '1px #DADADA solid', outlineOffset: '-1px', flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'flex-start', display: 'inline-flex'}}>
|
||||||
|
<img style={{alignSelf: 'stretch', height: 287}} src="https://placehold.co/287x287" alt="Fish Grill Pan" />
|
||||||
|
<div style={{alignSelf: 'stretch', height: 82, paddingTop: 8, paddingBottom: 10, justifyContent: 'flex-start', alignItems: 'flex-start', gap: 10, display: 'inline-flex'}}>
|
||||||
|
<div style={{flex: '1 1 0', color: 'black', fontSize: 24, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 32, wordWrap: 'break-word'}}>Fish Grill Pan</div>
|
||||||
|
</div>
|
||||||
|
<div style={{paddingBottom: 3, justifyContent: 'center', alignItems: 'center', gap: 4, display: 'inline-flex'}}>
|
||||||
|
<div style={{color: '#C70850', fontSize: 30, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 30, wordWrap: 'break-word'}}>$32.98</div>
|
||||||
|
<div style={{color: '#808080', fontSize: 18, fontFamily: 'LG Smart UI', fontWeight: '400', textDecoration: 'line-through', lineHeight: 18, wordWrap: 'break-word'}}>$150.00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{width: 323, padding: 18, background: 'white', borderRadius: 12, outline: '1px #DADADA solid', outlineOffset: '-1px', flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'flex-start', display: 'inline-flex'}}>
|
||||||
|
<img style={{alignSelf: 'stretch', height: 287}} src="https://placehold.co/287x287" alt="Product" />
|
||||||
|
<div style={{alignSelf: 'stretch', paddingTop: 8, paddingBottom: 10, justifyContent: 'flex-start', alignItems: 'flex-start', gap: 10, display: 'inline-flex'}}>
|
||||||
|
<div style={{flex: '1 1 0', color: 'black', fontSize: 24, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 32, wordWrap: 'break-word'}}>Productl Nameytg Product
Name Producthlyg()...</div>
|
||||||
|
</div>
|
||||||
|
<div style={{paddingBottom: 3, justifyContent: 'center', alignItems: 'center', gap: 4, display: 'inline-flex'}}>
|
||||||
|
<div style={{color: '#C70850', fontSize: 30, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 30, wordWrap: 'break-word'}}>$32.98</div>
|
||||||
|
<div style={{color: '#808080', fontSize: 18, fontFamily: 'LG Smart UI', fontWeight: '400', textDecoration: 'line-through', lineHeight: 18, wordWrap: 'break-word'}}>$150.00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style={{width: 323, padding: 18, background: 'white', borderRadius: 12, outline: '1px #DADADA solid', outlineOffset: '-1px', flexDirection: 'column', justifyContent: 'flex-start', alignItems: 'flex-start', display: 'inline-flex'}}>
|
||||||
|
<img style={{alignSelf: 'stretch', height: 287}} src="https://placehold.co/287x287" alt="Product" />
|
||||||
|
<div style={{alignSelf: 'stretch', paddingTop: 8, paddingBottom: 10, justifyContent: 'flex-start', alignItems: 'flex-start', gap: 10, display: 'inline-flex'}}>
|
||||||
|
<div style={{flex: '1 1 0', color: 'black', fontSize: 24, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 32, wordWrap: 'break-word'}}>Productl Nameytg Product
Name Producthlyg()...</div>
|
||||||
|
</div>
|
||||||
|
<div style={{paddingBottom: 3, justifyContent: 'center', alignItems: 'center', gap: 4, display: 'inline-flex'}}>
|
||||||
|
<div style={{color: '#C70850', fontSize: 30, fontFamily: 'LG Smart UI', fontWeight: '700', lineHeight: 30, wordWrap: 'break-word'}}>$32.98</div>
|
||||||
|
<div style={{color: '#808080', fontSize: 18, fontFamily: 'LG Smart UI', fontWeight: '400', textDecoration: 'line-through', lineHeight: 18, wordWrap: 'break-word'}}>$150.00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
.container {
|
.container {
|
||||||
padding-left: 60px;
|
padding-left: 60px;
|
||||||
margin-bottom: 12px;
|
|
||||||
|
|
||||||
> h3 {
|
> h3 {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -18,10 +17,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.container:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tVirtualGridList {
|
.tVirtualGridList {
|
||||||
padding-right: 18px;
|
padding-right: 18px;
|
||||||
.size(@h: 438px);
|
.size(@h: 438px);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import { getBrandShopByShow } from '../../../../actions/brandActions';
|
|||||||
import useScrollTo from '../../../../hooks/useScrollTo';
|
import useScrollTo from '../../../../hooks/useScrollTo';
|
||||||
import css from './ShopByShowList.module.less';
|
import css from './ShopByShowList.module.less';
|
||||||
import ShopByShowNav from './ShopByShowNav/ShopByShowNav';
|
import ShopByShowNav from './ShopByShowNav/ShopByShowNav';
|
||||||
import ShopByShowContents from './ShopByShowContents/ShopByShowContents';
|
import ShopByShowSection from './ShopByShowSection/ShopByShowSection';
|
||||||
|
|
||||||
const Container = SpotlightContainerDecorator(
|
const Container = SpotlightContainerDecorator(
|
||||||
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||||
@@ -42,14 +42,9 @@ export default function ShopByShowList({
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
|
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
|
||||||
const scrollLeftJob = useRef(new Job((func) => func(), 0));
|
const scrollLeftJob = useRef(new Job((func) => func(), 0));
|
||||||
const [selectedClctId, setSelectedClctId] = useState(null);
|
|
||||||
|
|
||||||
const brandShopByShowClctInfos = brandShopByShowContsInfo?.brandShopByShowClctInfos || [];
|
const brandShopByShowClctInfos = brandShopByShowContsInfo?.brandShopByShowClctInfos || [];
|
||||||
|
|
||||||
const filteredCollections = selectedClctId
|
|
||||||
? brandShopByShowClctInfos.filter(({ clctId }) => clctId === selectedClctId)
|
|
||||||
: brandShopByShowClctInfos;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (panelInfo?.section !== "shop-by-show" || !panelInfo?.x) {
|
if (panelInfo?.section !== "shop-by-show" || !panelInfo?.x) {
|
||||||
return;
|
return;
|
||||||
@@ -78,7 +73,7 @@ export default function ShopByShowList({
|
|||||||
scrollLeft();
|
scrollLeft();
|
||||||
}, [scrollLeft, selectedPatnrId]);
|
}, [scrollLeft, selectedPatnrId]);
|
||||||
|
|
||||||
const handleTabClick = useCallback((contsId) => {
|
const handleContsIdChange = useCallback((contsId) => {
|
||||||
dispatch(getBrandShopByShow({ patnrId: selectedPatnrId, contsId }));
|
dispatch(getBrandShopByShow({ patnrId: selectedPatnrId, contsId }));
|
||||||
}, [selectedPatnrId, dispatch]);
|
}, [selectedPatnrId, dispatch]);
|
||||||
|
|
||||||
@@ -94,30 +89,16 @@ export default function ShopByShowList({
|
|||||||
id={"shop-by-show-list-id"}
|
id={"shop-by-show-list-id"}
|
||||||
spotlightId={"shop-by-show-list-id"}
|
spotlightId={"shop-by-show-list-id"}
|
||||||
>
|
>
|
||||||
<div className={css.tabsContainer}>
|
|
||||||
{brandShopByShowContsList && brandShopByShowContsList.map((item) => (
|
|
||||||
<button
|
|
||||||
key={item.contsId}
|
|
||||||
className={`${css.tabButton} ${brandShopByShowContsInfo?.contsId === item.contsId ? css.active : ''}`}
|
|
||||||
onClick={() => handleTabClick(item.contsId)}
|
|
||||||
onMouseDown={(e) => e.preventDefault()}
|
|
||||||
>
|
|
||||||
{item.contsNm}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ShopByShowNav
|
<ShopByShowNav
|
||||||
brandShopByShowClctInfos={brandShopByShowClctInfos}
|
brandShopByShowContsList={brandShopByShowContsList}
|
||||||
|
brandShopByShowContsInfo={brandShopByShowContsInfo}
|
||||||
handleItemFocus={_handleItemFocus}
|
handleItemFocus={_handleItemFocus}
|
||||||
selectedClctId={selectedClctId}
|
onContsIdChange={handleContsIdChange}
|
||||||
setSelectedClctId={setSelectedClctId}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{filteredCollections.map((collection, collIdx) => (
|
{brandShopByShowClctInfos.map((collection, collIdx) => (
|
||||||
<ShopByShowContents
|
<ShopByShowSection
|
||||||
key={`${spotlightId}-${collIdx}`}
|
key={`${spotlightId}-${collIdx}`}
|
||||||
clctId={collection.clctId}
|
|
||||||
clctNm={collection.clctNm}
|
clctNm={collection.clctNm}
|
||||||
brandProductInfos={collection.brandProductInfos}
|
brandProductInfos={collection.brandProductInfos}
|
||||||
contentsIndex={collIdx}
|
contentsIndex={collIdx}
|
||||||
@@ -126,7 +107,6 @@ export default function ShopByShowList({
|
|||||||
spotlightId={spotlightId}
|
spotlightId={spotlightId}
|
||||||
shelfOrder={shelfOrder}
|
shelfOrder={shelfOrder}
|
||||||
shelfTitle={shelfTitle}
|
shelfTitle={shelfTitle}
|
||||||
getScrollTo={getScrollTo}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -6,54 +6,8 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
.tabsContainer {
|
> nav {
|
||||||
display: flex;
|
margin-bottom: 30px;
|
||||||
gap: 12px;
|
|
||||||
padding: 0 60px 24px 60px;
|
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: hidden;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
height: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background: #ccc;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tabButton {
|
|
||||||
flex-shrink: 0;
|
|
||||||
padding: 8px 16px;
|
|
||||||
background-color: transparent;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
color: #666;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: #000;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background-color: #000;
|
|
||||||
border-color: #000;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,23 +12,20 @@ const Container = SpotlightContainerDecorator(
|
|||||||
"nav"
|
"nav"
|
||||||
);
|
);
|
||||||
|
|
||||||
const STRING_CONF = {
|
|
||||||
ALL: "ALL",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(function ShopByShowNav({
|
export default memo(function ShopByShowNav({
|
||||||
brandShopByShowClctInfos,
|
brandShopByShowContsList,
|
||||||
|
brandShopByShowContsInfo,
|
||||||
handleItemFocus,
|
handleItemFocus,
|
||||||
selectedClctId,
|
onContsIdChange,
|
||||||
setSelectedClctId,
|
|
||||||
}) {
|
}) {
|
||||||
const { getScrollTo, scrollLeft } = useScrollTo();
|
const { getScrollTo, scrollLeft } = useScrollTo();
|
||||||
|
|
||||||
const handleClick = useCallback(
|
const handleClick = useCallback(
|
||||||
(clctId, clctNm) => () => {
|
(contsId) => () => {
|
||||||
setSelectedClctId(clctId);
|
onContsIdChange(contsId);
|
||||||
},
|
},
|
||||||
[setSelectedClctId]
|
[onContsIdChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleFocus = useCallback(() => {
|
const handleFocus = useCallback(() => {
|
||||||
@@ -37,41 +34,26 @@ export default memo(function ShopByShowNav({
|
|||||||
}
|
}
|
||||||
}, [handleItemFocus]);
|
}, [handleItemFocus]);
|
||||||
|
|
||||||
const selectedText = !selectedClctId ? "Selected " : "";
|
|
||||||
const allLabelText = selectedText + "ALL 1 of " + (brandShopByShowClctInfos?.length + 1 || 1);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className={css.nav} id="shop-by-show-nav-id" spotlightId="shop-by-show-nav-id">
|
<Container className={css.nav} id="shop-by-show-nav-id" spotlightId="shop-by-show-nav-id">
|
||||||
<TScroller cbScrollTo={getScrollTo} direction="horizontal" noScrollByWheel>
|
<TScroller cbScrollTo={getScrollTo} direction="horizontal" noScrollByWheel>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
{brandShopByShowContsList &&
|
||||||
<TButton
|
brandShopByShowContsList.map(({ contsId, contsNm }, index) => (
|
||||||
className={!selectedClctId && css.selected}
|
<li key={"shop-by-show-conts-" + index}>
|
||||||
onClick={handleClick(null, null)}
|
|
||||||
onFocus={handleFocus}
|
|
||||||
selected={!selectedClctId}
|
|
||||||
type={TYPES.oneDepthCategory}
|
|
||||||
ariaLabel={allLabelText}
|
|
||||||
>
|
|
||||||
ALL
|
|
||||||
</TButton>
|
|
||||||
</li>
|
|
||||||
{brandShopByShowClctInfos &&
|
|
||||||
brandShopByShowClctInfos.map(({ clctId, clctNm }, index) => (
|
|
||||||
<li key={"shop-by-show-clct-" + index}>
|
|
||||||
<TButton
|
<TButton
|
||||||
className={selectedClctId && selectedClctId === clctId && css.selected}
|
className={brandShopByShowContsInfo?.contsId === contsId && css.selected}
|
||||||
onClick={handleClick(clctId, clctNm)}
|
onClick={handleClick(contsId)}
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
selected={selectedClctId && selectedClctId === clctId}
|
selected={brandShopByShowContsInfo?.contsId === contsId}
|
||||||
type={TYPES.oneDepthCategory}
|
type={TYPES.oneDepthCategory}
|
||||||
ariaLabel={
|
ariaLabel={
|
||||||
selectedClctId && selectedClctId === clctId
|
brandShopByShowContsInfo?.contsId === contsId
|
||||||
? "Selected " + clctNm + " " + (index * 1 + 2) + " of " + (brandShopByShowClctInfos.length + 1)
|
? "Selected " + contsNm + " " + (index * 1 + 1) + " of " + brandShopByShowContsList.length
|
||||||
: "" + clctNm + " " + (index * 1 + 2) + " of " + (brandShopByShowClctInfos.length + 1)
|
: "" + contsNm + " " + (index * 1 + 1) + " of " + brandShopByShowContsList.length
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{clctNm}
|
{contsNm}
|
||||||
</TButton>
|
</TButton>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import React, { memo } from "react";
|
||||||
|
|
||||||
|
import Spottable from "@enact/spotlight/Spottable";
|
||||||
|
|
||||||
|
import CustomImage from "../../../../../../../components/CustomImage/CustomImage";
|
||||||
|
import css from "./ShopByShowImageCard.module.less";
|
||||||
|
|
||||||
|
const SpottableComponent = Spottable("figure");
|
||||||
|
|
||||||
|
export default memo(function ShopByShowImageCard({
|
||||||
|
imageAlt,
|
||||||
|
imageSource,
|
||||||
|
ariaLabel,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
|
delete rest.clctNm;
|
||||||
|
return (
|
||||||
|
<SpottableComponent className={css.card} aria-label={ariaLabel} {...rest}>
|
||||||
|
<CustomImage src={imageSource} alt={imageAlt} />
|
||||||
|
</SpottableComponent>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
@import "../../../../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.card {
|
||||||
|
position: relative;
|
||||||
|
.size(@w: 665px, @h:438px);
|
||||||
|
padding: 18px;
|
||||||
|
background-color: @COLOR_WHITE;
|
||||||
|
border: solid 1px @COLOR_GRAY02;
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
.size(@w: 629px, @h:402px);
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
&::after {
|
||||||
|
.focused(@boxShadow: 22px, @borderRadius: 12px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
import React, { useCallback, useRef, useEffect } from "react";
|
||||||
|
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
|
||||||
|
import { Job } from "@enact/core/util";
|
||||||
|
import Spotlight from "@enact/spotlight";
|
||||||
|
|
||||||
|
import { pushPanel, updatePanel } from "../../../../../../../actions/panelActions";
|
||||||
|
import TItemCardNew, { removeDotAndColon } from "../../../../../../../components/TItemCard/TItemCard.new";
|
||||||
|
import TVirtualGridList from "../../../../../../../components/TVirtualGridList/TVirtualGridList";
|
||||||
|
import useScrollTo from "../../../../../../../hooks/useScrollTo";
|
||||||
|
import {
|
||||||
|
LOG_CONTEXT_NAME,
|
||||||
|
LOG_MESSAGE_ID,
|
||||||
|
panel_names,
|
||||||
|
} from "../../../../../../../utils/Config";
|
||||||
|
import { getTranslate3dValueByDirection } from "../../../../../../../utils/helperMethods";
|
||||||
|
import css from "./ShopByShowProductList.module.less";
|
||||||
|
|
||||||
|
export default function ShopByShowProductList({
|
||||||
|
brandProductInfos,
|
||||||
|
contentsIndex,
|
||||||
|
handleFocus,
|
||||||
|
selectedPatnrId,
|
||||||
|
spotlightId,
|
||||||
|
shelfOrder,
|
||||||
|
shelfTitle,
|
||||||
|
clctNm,
|
||||||
|
}) {
|
||||||
|
const { getScrollTo, scrollLeft } = useScrollTo();
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const panelInfo = useSelector((state) => state.panels.panels[0]?.panelInfo);
|
||||||
|
|
||||||
|
const scrollLeftJob = useRef(new Job((func) => func(), 0));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
panelInfo?.section !== "shop-by-show" ||
|
||||||
|
!panelInfo?.x ||
|
||||||
|
panelInfo?.exprOrd !== contentsIndex + 1
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrollLeftJobValue = scrollLeftJob.current;
|
||||||
|
const { x } = panelInfo;
|
||||||
|
|
||||||
|
scrollLeftJobValue.start(() => scrollLeft({ x }));
|
||||||
|
|
||||||
|
return () => scrollLeftJobValue.stop();
|
||||||
|
}, [panelInfo, scrollLeft, contentsIndex]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
scrollLeft();
|
||||||
|
}, [scrollLeft, selectedPatnrId]);
|
||||||
|
|
||||||
|
const handleClick = useCallback(
|
||||||
|
(patnrId, prdtId) => (e) => {
|
||||||
|
const tItemCard = e.currentTarget;
|
||||||
|
|
||||||
|
const lastFocusedTarget = Spotlight.getCurrent();
|
||||||
|
const lastFocusedTargetId = lastFocusedTarget?.getAttribute("data-spotlight-id");
|
||||||
|
const exprOrd = parseInt(
|
||||||
|
lastFocusedTarget?.getAttribute("data-exposure-order")
|
||||||
|
);
|
||||||
|
|
||||||
|
const xContainer = tItemCard?.parentNode?.parentNode;
|
||||||
|
|
||||||
|
if (exprOrd && lastFocusedTargetId && xContainer) {
|
||||||
|
const section = "shop-by-show";
|
||||||
|
const x = getTranslate3dValueByDirection(xContainer);
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
updatePanel({
|
||||||
|
name: panel_names.FEATURED_BRANDS_PANEL,
|
||||||
|
panelInfo: {
|
||||||
|
exprOrd,
|
||||||
|
lastFocusedTargetId,
|
||||||
|
patnrId,
|
||||||
|
section,
|
||||||
|
x,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
pushPanel({
|
||||||
|
name: panel_names.DETAIL_PANEL,
|
||||||
|
panelInfo: { patnrId, prdtId },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ index, ...rest }) => {
|
||||||
|
if (!brandProductInfos || !brandProductInfos[index]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const product = brandProductInfos[index];
|
||||||
|
const {
|
||||||
|
prdtImgUrl,
|
||||||
|
prdtOfferId,
|
||||||
|
patnrId = "21",
|
||||||
|
prdtNm,
|
||||||
|
prdtId,
|
||||||
|
prdtPrice,
|
||||||
|
patncNm,
|
||||||
|
brndNm,
|
||||||
|
lgCatNm,
|
||||||
|
euEnrgLblInfos,
|
||||||
|
} = product;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TItemCardNew
|
||||||
|
catNm={lgCatNm}
|
||||||
|
contextName={LOG_CONTEXT_NAME.FEATURED_BRANDS}
|
||||||
|
messageId={LOG_MESSAGE_ID.SHELF_CLICK}
|
||||||
|
patnerName={patncNm || "Peacock | Shop The Moment"}
|
||||||
|
brandName={brndNm}
|
||||||
|
shelfId={spotlightId}
|
||||||
|
shelfLocation={shelfOrder}
|
||||||
|
shelfTitle={shelfTitle}
|
||||||
|
imageAlt={prdtNm}
|
||||||
|
imageSource={prdtImgUrl}
|
||||||
|
onClick={handleClick(patnrId, prdtId)}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
offerInfo={prdtOfferId}
|
||||||
|
priceInfo={prdtPrice}
|
||||||
|
productId={prdtId}
|
||||||
|
productName={prdtNm}
|
||||||
|
spotlightId={"shop-by-show-product-list-" + removeDotAndColon(prdtId)}
|
||||||
|
data-exposure-order={contentsIndex + 1}
|
||||||
|
label={index + 1 + " of " + brandProductInfos.length}
|
||||||
|
lastLabel=" go to detail, button"
|
||||||
|
euEnrgLblInfos={euEnrgLblInfos}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[brandProductInfos, contentsIndex, handleClick, handleFocus]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={css.container}>
|
||||||
|
{brandProductInfos && (
|
||||||
|
<TVirtualGridList
|
||||||
|
cbScrollTo={getScrollTo}
|
||||||
|
className={css.tVirtualGridList}
|
||||||
|
dataSize={brandProductInfos.length}
|
||||||
|
direction="horizontal"
|
||||||
|
itemHeight={438}
|
||||||
|
itemWidth={323}
|
||||||
|
spacing={19}
|
||||||
|
renderItem={renderItem}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
@import "../../../../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
.flex();
|
||||||
|
overflow: hidden;
|
||||||
|
.size(@w: calc(100% - 665px), @h: 482px);
|
||||||
|
padding: 0 18px;
|
||||||
|
|
||||||
|
// tVirtualGridListContainer
|
||||||
|
> div:nth-child(1) {
|
||||||
|
.size(@w: 100%, @h: inherit);
|
||||||
|
|
||||||
|
> div:nth-child(1) {
|
||||||
|
padding: 22px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> div:nth-child(3) {
|
||||||
|
right: -18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tVirtualGridList {
|
||||||
|
padding-right: 18px;
|
||||||
|
.size(@h: 438px);
|
||||||
|
|
||||||
|
> div:nth-child(3) {
|
||||||
|
right: -18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
import React, { memo, useCallback } from "react";
|
||||||
|
|
||||||
|
import Spotlight from "@enact/spotlight";
|
||||||
|
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||||
|
|
||||||
|
import TItemCardNew, { removeDotAndColon } from "../../../../../components/TItemCard/TItemCard.new";
|
||||||
|
import TVirtualGridList from "../../../../../components/TVirtualGridList/TVirtualGridList";
|
||||||
|
import useScrollTo from "../../../../../hooks/useScrollTo";
|
||||||
|
import {
|
||||||
|
LOG_CONTEXT_NAME,
|
||||||
|
LOG_MESSAGE_ID,
|
||||||
|
panel_names,
|
||||||
|
} from "../../../../../utils/Config";
|
||||||
|
import { getTranslate3dValueByDirection } from "../../../../../utils/helperMethods";
|
||||||
|
import { pushPanel, updatePanel } from "../../../../../actions/panelActions";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import css from "./ShopByShowSection.module.less";
|
||||||
|
|
||||||
|
const Container = SpotlightContainerDecorator(
|
||||||
|
{ leaveFor: { right: "" }, enterTo: null },
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
const ShopByShowSection = memo(({
|
||||||
|
clctNm,
|
||||||
|
brandProductInfos,
|
||||||
|
contentsIndex,
|
||||||
|
handleItemFocus,
|
||||||
|
selectedPatnrId,
|
||||||
|
spotlightId,
|
||||||
|
shelfOrder,
|
||||||
|
shelfTitle,
|
||||||
|
}) => {
|
||||||
|
const { getScrollTo } = useScrollTo();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const handleClick = useCallback(
|
||||||
|
(patnrId, prdtId) => (e) => {
|
||||||
|
const tItemCard = e.currentTarget;
|
||||||
|
const lastFocusedTarget = Spotlight.getCurrent();
|
||||||
|
const lastFocusedTargetId = lastFocusedTarget?.getAttribute("data-spotlight-id");
|
||||||
|
const xContainer = tItemCard?.parentNode?.parentNode;
|
||||||
|
|
||||||
|
if (lastFocusedTargetId && xContainer) {
|
||||||
|
const section = "shop-by-show";
|
||||||
|
const x = getTranslate3dValueByDirection(xContainer);
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
updatePanel({
|
||||||
|
name: panel_names.FEATURED_BRANDS_PANEL,
|
||||||
|
panelInfo: {
|
||||||
|
lastFocusedTargetId,
|
||||||
|
patnrId,
|
||||||
|
section,
|
||||||
|
x,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
pushPanel({
|
||||||
|
name: panel_names.DETAIL_PANEL,
|
||||||
|
panelInfo: { patnrId, prdtId },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleFocus = useCallback(() => {
|
||||||
|
if (handleItemFocus) {
|
||||||
|
handleItemFocus();
|
||||||
|
}
|
||||||
|
}, [handleItemFocus]);
|
||||||
|
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ index, ...rest }) => {
|
||||||
|
if (!brandProductInfos || !brandProductInfos[index]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const product = brandProductInfos[index];
|
||||||
|
const {
|
||||||
|
prdtImgUrl,
|
||||||
|
prdtOfferId,
|
||||||
|
patnrId = "21",
|
||||||
|
prdtNm,
|
||||||
|
prdtId,
|
||||||
|
prdtPrice,
|
||||||
|
patncNm,
|
||||||
|
brndNm,
|
||||||
|
lgCatNm,
|
||||||
|
euEnrgLblInfos,
|
||||||
|
} = product;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TItemCardNew
|
||||||
|
catNm={lgCatNm}
|
||||||
|
contextName={LOG_CONTEXT_NAME.FEATURED_BRANDS}
|
||||||
|
messageId={LOG_MESSAGE_ID.SHELF_CLICK}
|
||||||
|
patnerName={patncNm || "Peacock | Shop The Moment"}
|
||||||
|
brandName={brndNm}
|
||||||
|
shelfId={spotlightId}
|
||||||
|
shelfLocation={shelfOrder}
|
||||||
|
shelfTitle={shelfTitle}
|
||||||
|
imageAlt={prdtNm}
|
||||||
|
imageSource={prdtImgUrl}
|
||||||
|
onClick={handleClick(patnrId, prdtId)}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
offerInfo={prdtOfferId}
|
||||||
|
priceInfo={prdtPrice}
|
||||||
|
productId={prdtId}
|
||||||
|
productName={prdtNm}
|
||||||
|
spotlightId={"shop-by-show-section-" + removeDotAndColon(prdtId)}
|
||||||
|
label={index * 1 + 1 + " of " + brandProductInfos.length}
|
||||||
|
lastLabel=" go to detail, button"
|
||||||
|
euEnrgLblInfos={euEnrgLblInfos}
|
||||||
|
{...rest}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[brandProductInfos, handleClick, handleFocus]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!brandProductInfos || brandProductInfos.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
className={css.container}
|
||||||
|
data-wheel-point
|
||||||
|
spotlightId={`${spotlightId}-section-${contentsIndex}`}
|
||||||
|
>
|
||||||
|
<h3 className={css.sectionTitle}>{clctNm}</h3>
|
||||||
|
|
||||||
|
<TVirtualGridList
|
||||||
|
cbScrollTo={getScrollTo}
|
||||||
|
className={css.tVirtualGridList}
|
||||||
|
dataSize={brandProductInfos.length}
|
||||||
|
direction="horizontal"
|
||||||
|
itemHeight={438}
|
||||||
|
itemWidth={323}
|
||||||
|
spacing={19}
|
||||||
|
renderItem={renderItem}
|
||||||
|
/>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default ShopByShowSection;
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
@import "../../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
padding-left: 60px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionTitle {
|
||||||
|
position: relative;
|
||||||
|
.font(@fontFamily: @arialFontBold, @fontSize: 42px);
|
||||||
|
color: @COLOR_GRAY08;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
width: 6px;
|
||||||
|
height: 36px;
|
||||||
|
background-color: #C70850;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tVirtualGridList {
|
||||||
|
padding-right: 18px;
|
||||||
|
.size(@h: 438px);
|
||||||
|
|
||||||
|
> div:nth-child(3) {
|
||||||
|
right: -18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user