[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:
2025-11-22 17:43:05 +09:00
parent 77e1dc56a2
commit 11bfdc0825
2 changed files with 127 additions and 93 deletions

View File

@@ -134,6 +134,15 @@ const BuyNowContainer = SpotlightContainerDecorator(
'div'
);
const ButtonStackContainer = SpotlightContainerDecorator(
{
spotlightDirection: 'vertical',
enterTo: 'last-focused',
restrict: 'self-only',
},
'div'
);
const SpottableComponent = Spottable('div');
const getProductData = curry((productType, themeProductInfo, productInfo) =>
@@ -948,6 +957,11 @@ export default function ProductAllSection({
[]
);
const stackDefaultElement = useMemo(
() => shopByMobileId || firstStackElementId,
[shopByMobileId, firstStackElementId]
);
// 버튼 스택(위→아래) 구성: 실제 렌더링 순서에 맞춰 행(row) 단위로 설정
const { focusDownMap, focusUpMap, focusOrder, focusRows } = useMemo(() => {
const rows = [];
@@ -1166,6 +1180,7 @@ export default function ProductAllSection({
});
}
}, [focusRows]);
const firstStackElementId = focusRows[0]?.[0];
const scrollPositionRef = useRef(0);
const prevScrollPositionRef = useRef(0); // 이전 스크롤 위치 추적
const prevScrollTopRef = useRef(0); // HomePanel 스타일 스크롤 위치 추적
@@ -1491,100 +1506,106 @@ export default function ProductAllSection({
</div>
</ProductOverview>
{userNumber &&
promotions.map((promotion, idx) => {
const couponButtonId = `detail-coupon-button-${idx}`;
return (
<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}
<ButtonStackContainer
className={css.buttonStackContainer}
spotlightId="detail-button-stack"
defaultElement={stackDefaultElement}
>
{/* 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>
{userNumber &&
promotions.map((promotion, idx) => {
const couponButtonId = `detail-coupon-button-${idx}`;
return (
<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>
<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}>
{orderPhnNo && (

View File

@@ -605,6 +605,19 @@
}
}
.buttonStackContainer {
width: 100%;
display: flex;
flex-direction: column;
> * {
margin-bottom: 5px;
&:last-child {
margin-bottom: 0;
}
}
}
.favoriteBtnWrapper {
width: 60px;
height: 60px;
@@ -825,4 +838,4 @@
}
}
}
}
}