[251122] fix: DetailPaneel->ProductAllSection Focus-6
🕐 커밋 시간: 2025. 11. 22. 17:43:05 📊 변경 통계: • 총 파일: 2개 • 추가: +123줄 • 삭제: -89줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): ✅ Added: SpotlightContainerDecorator() 🔄 Modified: extractProductMeta()
This commit is contained in:
@@ -134,6 +134,15 @@ const BuyNowContainer = SpotlightContainerDecorator(
|
|||||||
'div'
|
'div'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const ButtonStackContainer = SpotlightContainerDecorator(
|
||||||
|
{
|
||||||
|
spotlightDirection: 'vertical',
|
||||||
|
enterTo: 'last-focused',
|
||||||
|
restrict: 'self-only',
|
||||||
|
},
|
||||||
|
'div'
|
||||||
|
);
|
||||||
|
|
||||||
const SpottableComponent = Spottable('div');
|
const SpottableComponent = Spottable('div');
|
||||||
|
|
||||||
const getProductData = curry((productType, themeProductInfo, productInfo) =>
|
const getProductData = curry((productType, themeProductInfo, productInfo) =>
|
||||||
@@ -948,6 +957,11 @@ export default function ProductAllSection({
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const stackDefaultElement = useMemo(
|
||||||
|
() => shopByMobileId || firstStackElementId,
|
||||||
|
[shopByMobileId, firstStackElementId]
|
||||||
|
);
|
||||||
|
|
||||||
// 버튼 스택(위→아래) 구성: 실제 렌더링 순서에 맞춰 행(row) 단위로 설정
|
// 버튼 스택(위→아래) 구성: 실제 렌더링 순서에 맞춰 행(row) 단위로 설정
|
||||||
const { focusDownMap, focusUpMap, focusOrder, focusRows } = useMemo(() => {
|
const { focusDownMap, focusUpMap, focusOrder, focusRows } = useMemo(() => {
|
||||||
const rows = [];
|
const rows = [];
|
||||||
@@ -1166,6 +1180,7 @@ export default function ProductAllSection({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [focusRows]);
|
}, [focusRows]);
|
||||||
|
const firstStackElementId = focusRows[0]?.[0];
|
||||||
const scrollPositionRef = useRef(0);
|
const scrollPositionRef = useRef(0);
|
||||||
const prevScrollPositionRef = useRef(0); // 이전 스크롤 위치 추적
|
const prevScrollPositionRef = useRef(0); // 이전 스크롤 위치 추적
|
||||||
const prevScrollTopRef = useRef(0); // HomePanel 스타일 스크롤 위치 추적
|
const prevScrollTopRef = useRef(0); // HomePanel 스타일 스크롤 위치 추적
|
||||||
@@ -1491,100 +1506,106 @@ export default function ProductAllSection({
|
|||||||
</div>
|
</div>
|
||||||
</ProductOverview>
|
</ProductOverview>
|
||||||
|
|
||||||
{userNumber &&
|
<ButtonStackContainer
|
||||||
promotions.map((promotion, idx) => {
|
className={css.buttonStackContainer}
|
||||||
const couponButtonId = `detail-coupon-button-${idx}`;
|
spotlightId="detail-button-stack"
|
||||||
return (
|
defaultElement={stackDefaultElement}
|
||||||
<div className={css.couponContainer} key={idx}>
|
|
||||||
<div className={css.couponTitleText}>
|
|
||||||
<div className={css.firstTitle}>SPECIAL PROMOTION</div>
|
|
||||||
<div className={css.secondTitle}>
|
|
||||||
Coupon only applicable to this product!
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<TButton
|
|
||||||
spotlightId={couponButtonId}
|
|
||||||
className={css.couponButton}
|
|
||||||
onClick={() => {
|
|
||||||
handleCouponClick(idx, promotion);
|
|
||||||
}}
|
|
||||||
onSpotlightUp={handleSpotlightUpFromCouponButtons}
|
|
||||||
onSpotlightDown={(e) => handleSpotlightDownFromCoupon(e, couponButtonId)}
|
|
||||||
data-spotlight-next-down={focusDownMap[couponButtonId]}
|
|
||||||
size="detail_very_small"
|
|
||||||
>
|
|
||||||
<div className={css.couponText}>COUPON</div>
|
|
||||||
<img className={css.buttonImg} src={couponImg} />
|
|
||||||
</TButton>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{isBillingProductVisible && (
|
|
||||||
<BuyNowContainer
|
|
||||||
className={css.buyNowCartContainer}
|
|
||||||
spotlightId="detail-buy-container"
|
|
||||||
defaultElement="detail-buy-now-button"
|
|
||||||
>
|
|
||||||
<TButton
|
|
||||||
spotlightId="detail-buy-now-button"
|
|
||||||
className={css.buyNowButton}
|
|
||||||
onClick={handleBuyNowClick}
|
|
||||||
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
|
||||||
onSpotlightDown={handleSpotlightDownFromBuyNow}
|
|
||||||
data-spotlight-next-down={focusDownMap['detail-buy-now-button']}
|
|
||||||
type="detail_small"
|
|
||||||
>
|
|
||||||
<div className={css.buyNowText}>{$L('BUY NOW')}</div>
|
|
||||||
</TButton>
|
|
||||||
<TButton
|
|
||||||
spotlightId="detail-add-to-cart-button"
|
|
||||||
className={css.addToCartButton}
|
|
||||||
// onClick={handleAddToCartClick}
|
|
||||||
onClick={handleBuyNowClick}
|
|
||||||
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
|
||||||
onSpotlightDown={handleSpotlightDownFromAddToCart}
|
|
||||||
data-spotlight-next-down={focusDownMap['detail-add-to-cart-button']}
|
|
||||||
type="detail_small"
|
|
||||||
>
|
|
||||||
<div className={css.addToCartText}>{$L('ADD TO CART')}</div>
|
|
||||||
</TButton>
|
|
||||||
</BuyNowContainer>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ShopByMobileContainer
|
|
||||||
className={classNames(
|
|
||||||
css.buttonContainer,
|
|
||||||
isBillingProductVisible && css.buttonHasNoCart
|
|
||||||
)}
|
|
||||||
spotlightId="detail-shop-by-mobile-container"
|
|
||||||
defaultElement={SpotlightIds.DETAIL_SHOPBYMOBILE}
|
|
||||||
>
|
>
|
||||||
{/* BUY NOW + ADD TO CART 버튼들 (결제 가능 상품일 때만 렌더링) */}
|
{userNumber &&
|
||||||
<TButton
|
promotions.map((promotion, idx) => {
|
||||||
spotlightId={SpotlightIds.DETAIL_SHOPBYMOBILE}
|
const couponButtonId = `detail-coupon-button-${idx}`;
|
||||||
className={css.shopByMobileButton}
|
return (
|
||||||
onClick={handleShopByMobileOpen}
|
<div className={css.couponContainer} key={idx}>
|
||||||
onSpotlightUp={handleSpotlightUpToBackButton}
|
<div className={css.couponTitleText}>
|
||||||
onSpotlightDown={handleSpotlightDownFromShopByMobile}
|
<div className={css.firstTitle}>SPECIAL PROMOTION</div>
|
||||||
data-spotlight-next-down={focusDownMap[shopByMobileId]}
|
<div className={css.secondTitle}>
|
||||||
data-spotlight-next-up={shopByMobileUpTarget}
|
Coupon only applicable to this product!
|
||||||
>
|
</div>
|
||||||
<div className={css.shopByMobileText}>{$L('SHOP BY MOBILE')}</div>
|
</div>
|
||||||
</TButton>
|
<TButton
|
||||||
{panelInfo && (
|
spotlightId={couponButtonId}
|
||||||
<div className={css.favoriteBtnWrapper}>
|
className={css.couponButton}
|
||||||
<FavoriteBtn
|
onClick={() => {
|
||||||
className={css.favoriteBtn}
|
handleCouponClick(idx, promotion);
|
||||||
selectedPatnrId={panelInfo.patnrId}
|
}}
|
||||||
selectedPrdtId={panelInfo.prdtId}
|
onSpotlightUp={handleSpotlightUpFromCouponButtons}
|
||||||
favoriteFlag={favoriteFlag}
|
onSpotlightDown={(e) => handleSpotlightDownFromCoupon(e, couponButtonId)}
|
||||||
onFavoriteFlagChanged={onFavoriteFlagChanged}
|
data-spotlight-next-down={focusDownMap[couponButtonId]}
|
||||||
kind={'item_detail'}
|
size="detail_very_small"
|
||||||
nextDownId={focusDownMap['favoriteBtn']}
|
>
|
||||||
/>
|
<div className={css.couponText}>COUPON</div>
|
||||||
</div>
|
<img className={css.buttonImg} src={couponImg} />
|
||||||
|
</TButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{isBillingProductVisible && (
|
||||||
|
<BuyNowContainer
|
||||||
|
className={css.buyNowCartContainer}
|
||||||
|
spotlightId="detail-buy-container"
|
||||||
|
defaultElement="detail-buy-now-button"
|
||||||
|
>
|
||||||
|
<TButton
|
||||||
|
spotlightId="detail-buy-now-button"
|
||||||
|
className={css.buyNowButton}
|
||||||
|
onClick={handleBuyNowClick}
|
||||||
|
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
||||||
|
onSpotlightDown={handleSpotlightDownFromBuyNow}
|
||||||
|
data-spotlight-next-down={focusDownMap['detail-buy-now-button']}
|
||||||
|
type="detail_small"
|
||||||
|
>
|
||||||
|
<div className={css.buyNowText}>{$L('BUY NOW')}</div>
|
||||||
|
</TButton>
|
||||||
|
<TButton
|
||||||
|
spotlightId="detail-add-to-cart-button"
|
||||||
|
className={css.addToCartButton}
|
||||||
|
// onClick={handleAddToCartClick}
|
||||||
|
onClick={handleBuyNowClick}
|
||||||
|
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
||||||
|
onSpotlightDown={handleSpotlightDownFromAddToCart}
|
||||||
|
data-spotlight-next-down={focusDownMap['detail-add-to-cart-button']}
|
||||||
|
type="detail_small"
|
||||||
|
>
|
||||||
|
<div className={css.addToCartText}>{$L('ADD TO CART')}</div>
|
||||||
|
</TButton>
|
||||||
|
</BuyNowContainer>
|
||||||
)}
|
)}
|
||||||
</ShopByMobileContainer>
|
|
||||||
|
<ShopByMobileContainer
|
||||||
|
className={classNames(
|
||||||
|
css.buttonContainer,
|
||||||
|
isBillingProductVisible && css.buttonHasNoCart
|
||||||
|
)}
|
||||||
|
spotlightId="detail-shop-by-mobile-container"
|
||||||
|
defaultElement={SpotlightIds.DETAIL_SHOPBYMOBILE}
|
||||||
|
>
|
||||||
|
{/* BUY NOW + ADD TO CART 버튼들 (결제 가능 상품일 때만 렌더링) */}
|
||||||
|
<TButton
|
||||||
|
spotlightId={SpotlightIds.DETAIL_SHOPBYMOBILE}
|
||||||
|
className={css.shopByMobileButton}
|
||||||
|
onClick={handleShopByMobileOpen}
|
||||||
|
onSpotlightUp={handleSpotlightUpToBackButton}
|
||||||
|
onSpotlightDown={handleSpotlightDownFromShopByMobile}
|
||||||
|
data-spotlight-next-down={focusDownMap[shopByMobileId]}
|
||||||
|
data-spotlight-next-up={shopByMobileUpTarget}
|
||||||
|
>
|
||||||
|
<div className={css.shopByMobileText}>{$L('SHOP BY MOBILE')}</div>
|
||||||
|
</TButton>
|
||||||
|
{panelInfo && (
|
||||||
|
<div className={css.favoriteBtnWrapper}>
|
||||||
|
<FavoriteBtn
|
||||||
|
className={css.favoriteBtn}
|
||||||
|
selectedPatnrId={panelInfo.patnrId}
|
||||||
|
selectedPrdtId={panelInfo.prdtId}
|
||||||
|
favoriteFlag={favoriteFlag}
|
||||||
|
onFavoriteFlagChanged={onFavoriteFlagChanged}
|
||||||
|
kind={'item_detail'}
|
||||||
|
nextDownId={focusDownMap['favoriteBtn']}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</ShopByMobileContainer>
|
||||||
|
</ButtonStackContainer>
|
||||||
|
|
||||||
<div className={css.callToOrderSection}>
|
<div className={css.callToOrderSection}>
|
||||||
{orderPhnNo && (
|
{orderPhnNo && (
|
||||||
|
|||||||
@@ -605,6 +605,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.buttonStackContainer {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.favoriteBtnWrapper {
|
.favoriteBtnWrapper {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
|
|||||||
Reference in New Issue
Block a user