[251121] fix: JustForYouTestPanel Top Click
🕐 커밋 시간: 2025. 11. 21. 12:49:09 📊 변경 통계: • 총 파일: 5개 • 추가: +115줄 • 삭제: -23줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx ~ com.twin.app.shoptime/src/views/JustForYouPanel/JustForYouPanel.jsx ~ com.twin.app.shoptime/src/views/JustForYouPanel/JustForYouPanel.module.less ~ com.twin.app.shoptime/src/views/JustForYouTestPanel/JustForYouTestPanel.jsx 🔧 주요 변경 내용: • UI 컴포넌트 아키텍처 개선 • 테스트 커버리지 및 안정성 향상 • 중간 규모 기능 개선
This commit is contained in:
@@ -910,6 +910,10 @@ export default function ProductAllSection({
|
|||||||
Spotlight.focus('spotlightId_backBtn');
|
Spotlight.focus('spotlightId_backBtn');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleSpotlightDown = useCallback((e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const onFavoriteFlagChanged = useCallback(
|
const onFavoriteFlagChanged = useCallback(
|
||||||
(newFavoriteFlag) => setFavoriteOverride(newFavoriteFlag),
|
(newFavoriteFlag) => setFavoriteOverride(newFavoriteFlag),
|
||||||
[]
|
[]
|
||||||
@@ -1265,7 +1269,7 @@ export default function ProductAllSection({
|
|||||||
|
|
||||||
{promotions.map((promotion, idx) => {
|
{promotions.map((promotion, idx) => {
|
||||||
return(
|
return(
|
||||||
<HorizontalContainer className={css.couponContainer} key={idx}>
|
<div className={css.couponContainer} key={idx}>
|
||||||
<div className={css.couponTitleText}>
|
<div className={css.couponTitleText}>
|
||||||
<div className={css.firstTitle}>SPECIAL PROMOTION</div>
|
<div className={css.firstTitle}>SPECIAL PROMOTION</div>
|
||||||
<div className={css.secondTitle}>Coupon only applicable to this product!</div>
|
<div className={css.secondTitle}>Coupon only applicable to this product!</div>
|
||||||
@@ -1277,6 +1281,7 @@ export default function ProductAllSection({
|
|||||||
handleCouponClick(idx, promotion);
|
handleCouponClick(idx, promotion);
|
||||||
}}
|
}}
|
||||||
onSpotlightUp={handleSpotlightUpFromCouponButtons}
|
onSpotlightUp={handleSpotlightUpFromCouponButtons}
|
||||||
|
onSpotlightDown={handleSpotlightDown}
|
||||||
size="detail_very_small"
|
size="detail_very_small"
|
||||||
>
|
>
|
||||||
<div className={css.couponText}>
|
<div className={css.couponText}>
|
||||||
@@ -1284,16 +1289,17 @@ export default function ProductAllSection({
|
|||||||
</div>
|
</div>
|
||||||
<img className={css.buttonImg} src={couponImg} />
|
<img className={css.buttonImg} src={couponImg} />
|
||||||
</TButton>
|
</TButton>
|
||||||
</HorizontalContainer>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
{isBillingProductVisible && (
|
{isBillingProductVisible && (
|
||||||
<HorizontalContainer className={css.buyNowCartContainer}>
|
<div className={css.buyNowCartContainer}>
|
||||||
<TButton
|
<TButton
|
||||||
spotlightId="detail-buy-now-button"
|
spotlightId="detail-buy-now-button"
|
||||||
className={css.buyNowButton}
|
className={css.buyNowButton}
|
||||||
onClick={handleBuyNowClick}
|
onClick={handleBuyNowClick}
|
||||||
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
||||||
|
onSpotlightDown={handleSpotlightDown}
|
||||||
type="detail_small"
|
type="detail_small"
|
||||||
>
|
>
|
||||||
<div className={css.buyNowText}>{$L('BUY NOW')}</div>
|
<div className={css.buyNowText}>{$L('BUY NOW')}</div>
|
||||||
@@ -1304,14 +1310,15 @@ export default function ProductAllSection({
|
|||||||
// onClick={handleAddToCartClick}
|
// onClick={handleAddToCartClick}
|
||||||
onClick={handleBuyNowClick}
|
onClick={handleBuyNowClick}
|
||||||
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
onSpotlightUp={handleSpotlightUpFromBuyButtons}
|
||||||
|
onSpotlightDown={handleSpotlightDown}
|
||||||
type="detail_small"
|
type="detail_small"
|
||||||
>
|
>
|
||||||
<div className={css.addToCartText}>{$L('ADD TO CART')}</div>
|
<div className={css.addToCartText}>{$L('ADD TO CART')}</div>
|
||||||
</TButton>
|
</TButton>
|
||||||
</HorizontalContainer>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<HorizontalContainer
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
css.buttonContainer,
|
css.buttonContainer,
|
||||||
isBillingProductVisible && css.buttonHasNoCart
|
isBillingProductVisible && css.buttonHasNoCart
|
||||||
@@ -1323,6 +1330,7 @@ export default function ProductAllSection({
|
|||||||
className={css.shopByMobileButton}
|
className={css.shopByMobileButton}
|
||||||
onClick={handleShopByMobileOpen}
|
onClick={handleShopByMobileOpen}
|
||||||
onSpotlightUp={handleSpotlightUpToBackButton}
|
onSpotlightUp={handleSpotlightUpToBackButton}
|
||||||
|
onSpotlightDown={handleSpotlightDown}
|
||||||
>
|
>
|
||||||
<div className={css.shopByMobileText}>{$L('SHOP BY MOBILE')}</div>
|
<div className={css.shopByMobileText}>{$L('SHOP BY MOBILE')}</div>
|
||||||
</TButton>
|
</TButton>
|
||||||
@@ -1338,7 +1346,7 @@ export default function ProductAllSection({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</HorizontalContainer>
|
</div>
|
||||||
|
|
||||||
<div className={css.callToOrderSection}>
|
<div className={css.callToOrderSection}>
|
||||||
{orderPhnNo && (
|
{orderPhnNo && (
|
||||||
|
|||||||
@@ -66,20 +66,33 @@ export default function FavoriteBtn({
|
|||||||
onFavoriteFlagChanged(favoriteFlag === 'Y' ? 'N' : 'Y');
|
onFavoriteFlagChanged(favoriteFlag === 'Y' ? 'N' : 'Y');
|
||||||
}, [dispatch, favoriteFlag, onFavoriteFlagChanged]);
|
}, [dispatch, favoriteFlag, onFavoriteFlagChanged]);
|
||||||
|
|
||||||
|
const handleFavoriteKeyDown = useCallback((e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
handleFavoriteClick();
|
||||||
|
}
|
||||||
|
}, [handleFavoriteClick]);
|
||||||
|
|
||||||
|
const handleSpotlightDown = useCallback((e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SpottableDiv
|
<SpottableDiv
|
||||||
className={classNames(css.favorBtnContainer, kind === 'item_detail' ? css.smallSize : '')}
|
|
||||||
spotlightId="favoriteBtn"
|
spotlightId="favoriteBtn"
|
||||||
onClick={handleFavoriteClick}
|
className={classNames(css.favorBtnContainer, kind === 'item_detail' ? css.smallSize : '')}
|
||||||
role="button"
|
role="button"
|
||||||
|
aria-label="Register in Favorites"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
onClick={handleFavoriteClick}
|
||||||
|
onKeyDown={handleFavoriteKeyDown}
|
||||||
|
onSpotlightDown={handleSpotlightDown}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
css.favoriteButton,
|
css.favoriteButton,
|
||||||
favoriteFlag === 'N' ? css.favorBtn : css.favorUnableBtn
|
favoriteFlag === 'N' ? css.favorBtn : css.favorUnableBtn
|
||||||
)}
|
)}
|
||||||
aria-label="Register in Favorites"
|
|
||||||
/>
|
/>
|
||||||
{activePopup === Config.ACTIVE_POPUP.favoritePopup && (
|
{activePopup === Config.ACTIVE_POPUP.favoritePopup && (
|
||||||
<TPopUp
|
<TPopUp
|
||||||
|
|||||||
@@ -73,6 +73,21 @@ const JustForYouPanel = ({ panelInfo, isOnTop, ...rest }) => {
|
|||||||
const currentSentMenuRef = useRef(null);
|
const currentSentMenuRef = useRef(null);
|
||||||
const focusedContainerIdRef = useRef(panelInfo?.focusedContainerId);
|
const focusedContainerIdRef = useRef(panelInfo?.focusedContainerId);
|
||||||
|
|
||||||
|
// 마운트 로그
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('[JustForYouPanel] 마운트됨', {
|
||||||
|
isOnTop,
|
||||||
|
recentItemsCount: recentItems?.length || 0,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
console.log('[JustForYouPanel] 언마운트됨', {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleScroll = useCallback((e) => {
|
const handleScroll = useCallback((e) => {
|
||||||
setShowButton(e.scrollTop === 0);
|
setShowButton(e.scrollTop === 0);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -120,7 +135,24 @@ const JustForYouPanel = ({ panelInfo, isOnTop, ...rest }) => {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleWrapClickCapture = useCallback(() => {
|
||||||
|
console.log("[JustForYouPanel] wrapper capture: 상위 div 통과");
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handlePanelClickCapture = useCallback(() => {
|
||||||
|
console.log("[JustForYouPanel] TPanel capture: panel 통과");
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleBodyClickCapture = useCallback(() => {
|
||||||
|
console.log("[JustForYouPanel] TBody capture: body 통과");
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleButtonWrapperClickCapture = useCallback(() => {
|
||||||
|
console.log("[JustForYouPanel] 버튼 감싸는 div capture: 버튼 바로 위");
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleTopButtonClick = useCallback(() => {
|
const handleTopButtonClick = useCallback(() => {
|
||||||
|
console.log("[JustForYouPanel] TButton onClick: TOP 버튼 클릭");
|
||||||
if (cbChangePageRef.current) {
|
if (cbChangePageRef.current) {
|
||||||
cbChangePageRef.current(0, true);
|
cbChangePageRef.current(0, true);
|
||||||
}
|
}
|
||||||
@@ -132,6 +164,10 @@ const JustForYouPanel = ({ panelInfo, isOnTop, ...rest }) => {
|
|||||||
}
|
}
|
||||||
}, [recentItems]);
|
}, [recentItems]);
|
||||||
|
|
||||||
|
const handleTopButtonSpotlightDown = useCallback((e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
(item) => {
|
(item) => {
|
||||||
const {
|
const {
|
||||||
@@ -234,9 +270,15 @@ const JustForYouPanel = ({ panelInfo, isOnTop, ...rest }) => {
|
|||||||
// </TBody>
|
// </TBody>
|
||||||
// </TPanel>
|
// </TPanel>
|
||||||
// </div>
|
// </div>
|
||||||
<div className={css.justForYouWrap}>
|
<div
|
||||||
<TPanel>
|
className={css.justForYouWrap}
|
||||||
<TBody className={css.justForYou}>
|
onClickCapture={handleWrapClickCapture}
|
||||||
|
>
|
||||||
|
<TPanel onClickCapture={handlePanelClickCapture}>
|
||||||
|
<TBody
|
||||||
|
className={css.justForYou}
|
||||||
|
onClickCapture={handleBodyClickCapture}
|
||||||
|
>
|
||||||
<div className={css.background}>
|
<div className={css.background}>
|
||||||
<CustomImage src={background} animationSpeed="none" />
|
<CustomImage src={background} animationSpeed="none" />
|
||||||
</div>
|
</div>
|
||||||
@@ -311,15 +353,23 @@ const JustForYouPanel = ({ panelInfo, isOnTop, ...rest }) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{recentItems && recentItems?.length > 10 && (
|
{recentItems && recentItems?.length > 10 && (
|
||||||
<RecentSawContainer>
|
<RecentSawContainer onClickCapture={handleButtonWrapperClickCapture}>
|
||||||
|
<div
|
||||||
|
onClick={(e) => {
|
||||||
|
console.log("[JustForYouPanel] DIV onClick: TOP 버튼 DIV 클릭");
|
||||||
|
handleTopButtonClick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<TButton
|
<TButton
|
||||||
onClick={handleTopButtonClick}
|
onClick={handleTopButtonClick}
|
||||||
|
onSpotlightDown={handleTopButtonSpotlightDown}
|
||||||
size={null}
|
size={null}
|
||||||
spotlightId={SpotlightIds.JUST_FOR_YOU_TOP_BUTTON}
|
spotlightId={SpotlightIds.JUST_FOR_YOU_TOP_BUTTON}
|
||||||
ariaLabel="Move to Top"
|
ariaLabel="Move to Top"
|
||||||
data-wheel-point
|
data-wheel-point
|
||||||
type={TYPES.topButton}
|
type={TYPES.topButton}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</RecentSawContainer>
|
</RecentSawContainer>
|
||||||
)}
|
)}
|
||||||
</TBody>
|
</TBody>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.itemsContainer {
|
.itemsContainer {
|
||||||
|
|||||||
@@ -60,8 +60,17 @@ const JustForYouTestPanel = ({ panelInfo, ...rest }) => {
|
|||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const handleTopButtonClick = useCallback(() => {
|
const handleTopButtonClick = useCallback(() => {
|
||||||
|
console.log("[JustForYouTestPanel] TOP 버튼 클릭됨", {
|
||||||
|
cbChangePageRefExists: !!cbChangePageRef.current,
|
||||||
|
shelfInfosLength: shelfInfos?.length || 0,
|
||||||
|
firstShelfProductCount: shelfInfos?.[0]?.productInfos?.length || 0,
|
||||||
|
});
|
||||||
|
|
||||||
if (cbChangePageRef.current) {
|
if (cbChangePageRef.current) {
|
||||||
|
console.log("[JustForYouTestPanel] cbChangePageRef 호출");
|
||||||
cbChangePageRef.current(0, true);
|
cbChangePageRef.current(0, true);
|
||||||
|
} else {
|
||||||
|
console.log("[JustForYouTestPanel] ⚠️ cbChangePageRef.current가 null");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -69,10 +78,18 @@ const JustForYouTestPanel = ({ panelInfo, ...rest }) => {
|
|||||||
shelfInfos.length > 0 &&
|
shelfInfos.length > 0 &&
|
||||||
shelfInfos[0].productInfos?.length > 0
|
shelfInfos[0].productInfos?.length > 0
|
||||||
) {
|
) {
|
||||||
|
console.log("[JustForYouTestPanel] Spotlight.focus('justForYouList_1') 호출");
|
||||||
Spotlight.focus("justForYouList_1");
|
Spotlight.focus("justForYouList_1");
|
||||||
|
} else {
|
||||||
|
console.log("[JustForYouTestPanel] ⚠️ shelfInfos 없음 또는 비어있음");
|
||||||
}
|
}
|
||||||
}, [shelfInfos]);
|
}, [shelfInfos]);
|
||||||
|
|
||||||
|
const handleTopButtonSpotlightDown = useCallback((e) => {
|
||||||
|
console.log("[JustForYouTestPanel] TOP 버튼 SpotlightDown");
|
||||||
|
e.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
(shelfId, shelfExpsOrd, productInfos) =>
|
(shelfId, shelfExpsOrd, productInfos) =>
|
||||||
({ index, ...rest }) => {
|
({ index, ...rest }) => {
|
||||||
@@ -138,6 +155,7 @@ const JustForYouTestPanel = ({ panelInfo, ...rest }) => {
|
|||||||
className={css.tVerticalPagenator}
|
className={css.tVerticalPagenator}
|
||||||
spotlightId={"justforyouspotlight"}
|
spotlightId={"justforyouspotlight"}
|
||||||
topMargin={470}
|
topMargin={470}
|
||||||
|
cbChangePageRef={cbChangePageRef}
|
||||||
>
|
>
|
||||||
<div className={css.background}>
|
<div className={css.background}>
|
||||||
<THeaderCustom
|
<THeaderCustom
|
||||||
@@ -204,6 +222,7 @@ const JustForYouTestPanel = ({ panelInfo, ...rest }) => {
|
|||||||
<ListContainer>
|
<ListContainer>
|
||||||
<TButton
|
<TButton
|
||||||
onClick={handleTopButtonClick}
|
onClick={handleTopButtonClick}
|
||||||
|
onSpotlightDown={handleTopButtonSpotlightDown}
|
||||||
size={null}
|
size={null}
|
||||||
spotlightId={SpotlightIds.JUST_FOR_YOU_TOP_BUTTON}
|
spotlightId={SpotlightIds.JUST_FOR_YOU_TOP_BUTTON}
|
||||||
ariaLabel="Move to Top"
|
ariaLabel="Move to Top"
|
||||||
|
|||||||
Reference in New Issue
Block a user