diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx index 5fa108b8..a21f3922 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/YouMayAlsoLike/YouMayAlsoLike.jsx @@ -141,32 +141,39 @@ export default function YouMayAlsoLike({ } = product; const handleItemClick = () => { - dispatch(finishVideoPreview()); - dispatch(finishModalMediaForce()); + // Promise 체이닝으로 순서 보장 (Chrome 68, 87 호환성) + Promise.resolve() + .then(() => { + // 1. 기존 비디오 강제 종료 + dispatch(finishVideoPreview()); + dispatch(finishModalMediaForce()); - if (themeProductInfos && themeProductInfos.length > 0) { - dispatch(clearThemeDetail()); - } - - // popPanel + pushPanel 대신 updatePanel 사용 - // DetailPanel을 언마운트하지 않고 상품 정보만 업데이트 - // 이렇게 하면 백그라운드 비디오 제어 상태가 유지됨 - dispatch( - updatePanel({ - name: panel_names.DETAIL_PANEL, - panelInfo: { - showNm: panelInfo?.showNm, - showId: panelInfo?.showId, - liveFlag: panelInfo?.liveFlag, - thumbnailUrl: panelInfo?.thumbnailUrl, - patnrId, - prdtId, - launchedFromPlayer: launchedFromPlayer, - bgVideoInfo: bgVideoInfo, // 백그라운드 비디오 정보 유지 - }, + if (themeProductInfos && themeProductInfos.length > 0) { + dispatch(clearThemeDetail()); + } }) - ); - cursorOpen.current.stop(); + .then(() => { + // 2. 비디오 종료 후 새로운 상품으로 업데이트 + // popPanel + pushPanel 대신 updatePanel 사용 + // DetailPanel을 언마운트하지 않고 상품 정보만 업데이트 + // 이렇게 하면 백그라운드 비디오 제어 상태가 유지됨 + dispatch( + updatePanel({ + name: panel_names.DETAIL_PANEL, + panelInfo: { + showNm: panelInfo?.showNm, + showId: panelInfo?.showId, + liveFlag: panelInfo?.liveFlag, + thumbnailUrl: panelInfo?.thumbnailUrl, + patnrId, + prdtId, + launchedFromPlayer: launchedFromPlayer, + bgVideoInfo: bgVideoInfo, // 백그라운드 비디오 정보 유지 + }, + }) + ); + cursorOpen.current.stop(); + }); }; // prdtId가 없는 경우를 대비한 안정적인 key 생성 const itemKey = prdtId ? `${patnrId}-${prdtId}` : `product-${index}`; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx b/com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx index 5af0ef1e..f1ff339a 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect } from 'react'; +import React, { useCallback, useRef } from 'react'; import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; @@ -30,8 +30,12 @@ export default function FavoriteBtn({ }) { const dispatch = useDispatch(); const { popupVisible, activePopup } = useSelector((state) => state.common.popup); + const clickLockRef = useRef(false); + + const handleFavoriteActivate = useCallback(() => { + if (clickLockRef.current) return; + clickLockRef.current = true; - const handleFavoriteClick = useCallback(() => { dispatch( sendLogTotalRecommend({ menu: logMenu, @@ -61,10 +65,34 @@ export default function FavoriteBtn({ } }, [dispatch, favoriteFlag, selectedPatnrId, selectedPrdtId, logMenu]); + const handleMouseUp = useCallback( + (event) => { + // 실제 마우스 클릭(detail > 0)만 처리하고 키보드에서 전달된 mouse 이벤트(detail === 0)는 무시 + if (event?.detail === 0) return; + if (event.button !== 0) return; + event.preventDefault(); + event.stopPropagation(); + handleFavoriteActivate(); + }, + [handleFavoriteActivate] + ); + + const handleClick = useCallback( + (event) => { + // 키보드(Enter)에서 발생하는 click(detail === 0)만 처리 + if (event?.detail !== 0) return; + event.preventDefault(); + event.stopPropagation(); + handleFavoriteActivate(); + }, + [handleFavoriteActivate] + ); + const PopUpOnClick = useCallback(() => { setTimeout(() => Spotlight.focus('favoriteBtn')); dispatch(setHidePopup()); onFavoriteFlagChanged(favoriteFlag === 'Y' ? 'N' : 'Y'); + clickLockRef.current = false; }, [dispatch, favoriteFlag, onFavoriteFlagChanged]); const handleSpotlightDown = useCallback( @@ -96,7 +124,8 @@ export default function FavoriteBtn({ role="button" aria-label="Register in Favorites" tabIndex={0} - onClick={handleFavoriteClick} + onMouseUp={handleMouseUp} + onClick={handleClick} onSpotlightDown={handleSpotlightDown} data-spotlight-next-down={ kind === 'item_detail' ? nextDownId || 'product-details-button' : undefined