From 95bb25a13554946a07b5c4d13d8894172854e2d7 Mon Sep 17 00:00:00 2001 From: optrader Date: Sun, 19 Oct 2025 21:45:44 +0900 Subject: [PATCH] [251019] fix: PlayerPanel Optimization-1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 10. 19. 21:45:39 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 11๊ฐœ โ€ข ์ถ”๊ฐ€: +119์ค„ โ€ข ์‚ญ์ œ: -101์ค„ ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/actions/productActions.js ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js ~ com.twin.app.shoptime/src/hooks/useReviews/useReviews.js ~ com.twin.app.shoptime/src/reducers/productReducer.js ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviews.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabButton/PlayerTabButton.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx ๐Ÿ”ง ํ•จ์ˆ˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ: ๐Ÿ“„ com.twin.app.shoptime/src/actions/productActions.js (javascript): ๐Ÿ”„ Modified: resetShowAllReviews() ๐Ÿ“„ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviews.jsx (javascript): ๐Ÿ”„ Modified: SpotlightContainerDecorator() ๐Ÿ“„ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabButton/PlayerTabButton.jsx (javascript): โŒ Deleted: handleTabOnClick() ๐Ÿ“„ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx (javascript): ๐Ÿ”„ Modified: Spottable() ๐Ÿ”ง ์ฃผ์š” ๋ณ€๊ฒฝ ๋‚ด์šฉ: โ€ข ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฐœ์„  โ€ข UI ์ปดํฌ๋„ŒํŠธ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„  --- .../src/actions/productActions.js | 38 +++++----- .../components/VideoPlayer/MediaPlayer.jsx | 6 -- .../src/components/VideoPlayer/VideoPlayer.js | 19 ----- .../src/hooks/useReviews/useReviews.js | 44 +++++------ .../src/reducers/productReducer.js | 65 ++++++++--------- .../UserReviews/UserReviews.jsx | 12 +-- .../src/views/PlayerPanel/PlayerPanel.jsx | 36 ++++----- .../TabButton/PlayerTabButton.jsx | 73 ++++++++++--------- .../TabContents/FeaturedShowContents.jsx | 66 ++++++++++------- .../TabContents/LiveChannelContents.jsx | 20 ++++- .../PlayerTabContents/v2/TabContainer.v2.jsx | 4 +- 11 files changed, 195 insertions(+), 188 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/productActions.js b/com.twin.app.shoptime/src/actions/productActions.js index d5fbf1ef..7b9e602e 100644 --- a/com.twin.app.shoptime/src/actions/productActions.js +++ b/com.twin.app.shoptime/src/actions/productActions.js @@ -280,15 +280,15 @@ export const getUserReviews = (requestParams) => (dispatch, getState) => { // }); const onSuccess = (response) => { - console.log('[UserReviews]-API โœ… API ์„ฑ๊ณต ์‘๋‹ต:', { - status: response.status, - statusText: response.statusText, - headers: response.headers, - retCode: response.data && response.data.retCode, - retMsg: response.data && response.data.retMsg, - hasData: !!(response.data && response.data.data), - fullResponse: response.data, - }); + // console.log('[UserReviews]-API โœ… API ์„ฑ๊ณต ์‘๋‹ต:', { + // status: response.status, + // statusText: response.statusText, + // headers: response.headers, + // retCode: response.data && response.data.retCode, + // retMsg: response.data && response.data.retMsg, + // hasData: !!(response.data && response.data.data), + // fullResponse: response.data, + // }); // ==================== [์ž„์‹œ ํ…Œ์ŠคํŠธ] ๋นˆ ๋ฆฌ๋ทฐ ์‘๋‹ต ์‹œ๋ฎฌ๋ ˆ์ด์…˜ - ์ฝ”๋ฉ˜ํŠธ ์ฒ˜๋ฆฌ ==================== // 30% ํ™•๋ฅ ๋กœ ๋ฆฌ๋ทฐ ์—†๋Š” ์ƒํ’ˆ ์‘๋‹ต ๋ฐ˜ํ™˜ (ํ…Œ์ŠคํŠธ์šฉ) @@ -311,16 +311,16 @@ export const getUserReviews = (requestParams) => (dispatch, getState) => { } */ // ==================== [์ž„์‹œ ํ…Œ์ŠคํŠธ] ๋ - ์ฝ”๋ฉ˜ํŠธ ์ฒ˜๋ฆฌ ==================== - if (response.data && response.data.data) { - console.log('[UserReviews] ๐Ÿ“Š API ๋ฐ์ดํ„ฐ ์ƒ์„ธ:', { - reviewListLength: response.data.data.reviewList ? response.data.data.reviewList.length : 0, - reviewDetail: response.data.data.reviewDetail, - reviewList_sample: - (response.data.data.reviewList && response.data.data.reviewList[0]) || 'empty', - totRvwCnt: response.data.data.reviewDetail && response.data.data.reviewDetail.totRvwCnt, - totRvwAvg: response.data.data.reviewDetail && response.data.data.reviewDetail.totRvwAvg, - }); - } + // if (response.data && response.data.data) { + // console.log('[UserReviews] ๐Ÿ“Š API ๋ฐ์ดํ„ฐ ์ƒ์„ธ:', { + // reviewListLength: response.data.data.reviewList ? response.data.data.reviewList.length : 0, + // reviewDetail: response.data.data.reviewDetail, + // reviewList_sample: + // (response.data.data.reviewList && response.data.data.reviewList[0]) || 'empty', + // totRvwCnt: response.data.data.reviewDetail && response.data.data.reviewDetail.totRvwCnt, + // totRvwAvg: response.data.data.reviewDetail && response.data.data.reviewDetail.totRvwAvg, + // }); + // } // ์‹ค์ œ API ์‘๋‹ต์—์„œ data ๋ถ€๋ถ„ ์ถ”์ถœ const apiData = extractReviewApiData(response.data); diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx index 4f2c8e84..639ad47e 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx @@ -1064,9 +1064,7 @@ const VideoPlayerBase = class extends React.Component { * @public */ showControls = () => { - console.log('[VideoPlayer] showControls ํ˜ธ์ถœ'); if (this.props.disabled) { - console.log('[VideoPlayer] disabled true - return'); return; } @@ -1138,10 +1136,6 @@ const VideoPlayerBase = class extends React.Component { * @public */ toggleControls = () => { - console.log( - '[VideoPlayer] toggleControls ํ˜ธ์ถœ, mediaControlsVisible:', - this.state.mediaControlsVisible - ); if (this.state.mediaControlsVisible) { this.hideControls(); } else { diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js index 11124a30..a2e7a70b 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js +++ b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js @@ -867,19 +867,11 @@ const VideoPlayerBase = class extends React.Component { this.props.belowContentsVisible !== undefined && prevProps.belowContentsVisible !== this.props.belowContentsVisible ) { - console.log('[VideoPlayer] belowContentsVisible ๋ณ€๊ฒฝ ๊ฐ์ง€:', { - prev: prevProps.belowContentsVisible, - current: this.props.belowContentsVisible, - mediaControlsVisible: this.state.mediaControlsVisible, - }); - if (this.props.belowContentsVisible && !this.state.mediaControlsVisible) { // TabContainerV2๊ฐ€ ํ‘œ์‹œ๋  ๋•Œ controls๋„ ํ‘œ์‹œ - console.log('[VideoPlayer] TabContainerV2 ํ‘œ์‹œ - controls ๊ฐ•์ œ ํ‘œ์‹œ'); this.showControls(); } else if (!this.props.belowContentsVisible && this.state.mediaControlsVisible) { // TabContainerV2๊ฐ€ ์ˆจ๊ฒจ์งˆ ๋•Œ controls๋„ ์ˆจ๊น€ - console.log('[VideoPlayer] TabContainerV2 ์ˆจ๊น€ - controls ์ˆจ๊น€'); this.hideControls(); } } @@ -1049,7 +1041,6 @@ const VideoPlayerBase = class extends React.Component { // TabContainerV2๊ฐ€ ํ‘œ์‹œ ์ค‘์ด๋ฉด ์ž๋™์œผ๋กœ ๋‹ซ์ง€ ์•Š์Œ if (this.props.tabContainerVersion === 2 && this.props.belowContentsVisible) { - console.log('[VideoPlayer] TabContainerV2 ํ‘œ์‹œ ์ค‘ - autoClose ๋น„ํ™œ์„ฑํ™”'); return; } @@ -1116,9 +1107,7 @@ const VideoPlayerBase = class extends React.Component { * @public */ showControls = () => { - console.log('[VideoPlayer] showControls ํ˜ธ์ถœ'); if (this.props.disabled) { - console.log('[VideoPlayer] disabled true - return'); return; } @@ -1190,10 +1179,6 @@ const VideoPlayerBase = class extends React.Component { * @public */ toggleControls = () => { - console.log( - '[VideoPlayer] toggleControls ํ˜ธ์ถœ, mediaControlsVisible:', - this.state.mediaControlsVisible - ); if (this.state.mediaControlsVisible) { this.hideControls(); } else { @@ -1988,12 +1973,9 @@ const VideoPlayerBase = class extends React.Component { // Player Interaction events // onVideoClick = () => { - console.log('[VideoPlayer] onVideoClick ํ˜ธ์ถœ'); - // tabContainerVersion === 2์ผ ๋•Œ belowContentsVisible๋„ ํ•จ๊ป˜ ํ† ๊ธ€ if (this.props.tabContainerVersion === 2 && this.props.setBelowContentsVisible) { const willShowControls = !this.state.mediaControlsVisible; - console.log('[VideoPlayer] ํด๋ฆญ - ์ƒํƒœ ๋™๊ธฐํ™” ํ† ๊ธ€:', willShowControls); // belowContentsVisible์„ ๋จผ์ € ๋ณ€๊ฒฝ (componentDidUpdate์—์„œ mediaControls ๋™๊ธฐํ™”๋จ) this.props.setBelowContentsVisible(willShowControls); @@ -2002,7 +1984,6 @@ const VideoPlayerBase = class extends React.Component { // ์™ธ๋ถ€ onClick ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์žˆ์œผ๋ฉด ํ˜ธ์ถœ if (this.props.onClick) { - console.log('[VideoPlayer] onClick ํ˜ธ์ถœ'); this.props.onClick(); return; } diff --git a/com.twin.app.shoptime/src/hooks/useReviews/useReviews.js b/com.twin.app.shoptime/src/hooks/useReviews/useReviews.js index 83706b21..75dd08fe 100644 --- a/com.twin.app.shoptime/src/hooks/useReviews/useReviews.js +++ b/com.twin.app.shoptime/src/hooks/useReviews/useReviews.js @@ -239,20 +239,20 @@ const useReviews = (prdtId, patnrId) => { }); // ๋ณ„์ ์ด ์—†๋Š” ๋ฆฌ๋ทฐ๋“ค ๋กœ๊ทธ ์ถœ๋ ฅ - if (noStarReviews.length > 0) { - console.log('[UserReviews]-NoStar ๋ณ„์  ์—†๋Š” ๋ฆฌ๋ทฐ๋“ค:', { - totalReviews: allReviews.length, - noStarCount: noStarReviews.length, - noStarReviews: noStarReviews.map((review) => ({ - rvwId: review.rvwId, - rvwScr: review.rvwScr, - rvwRtng: review.rvwRtng, - rating: review.rating, - rvwCtnt: review.rvwCtnt?.substring(0, 50) + '...', - wrtrNknm: review.wrtrNknm, - })), - }); - } + // if (noStarReviews.length > 0) { + // console.log('[UserReviews]-NoStar ๋ณ„์  ์—†๋Š” ๋ฆฌ๋ทฐ๋“ค:', { + // totalReviews: allReviews.length, + // noStarCount: noStarReviews.length, + // noStarReviews: noStarReviews.map((review) => ({ + // rvwId: review.rvwId, + // rvwScr: review.rvwScr, + // rvwRtng: review.rvwRtng, + // rating: review.rating, + // rvwCtnt: review.rvwCtnt?.substring(0, 50) + '...', + // wrtrNknm: review.wrtrNknm, + // })), + // }); + // } // ๋ณ„์ ์ด ์žˆ๋Š” ๋ฆฌ๋ทฐ๋งŒ ์นด์šดํŠธ (1~5์ ) let ratingSum = 0; @@ -538,14 +538,14 @@ const useReviews = (prdtId, patnrId) => { const apiTotalCount = reviewDetail && reviewDetail.totRvwCnt ? reviewDetail.totRvwCnt : 0; const actualReviewCount = allReviews.length; - if (apiTotalCount > actualReviewCount && actualReviewCount > 0) { - console.log('[UserReviews]-API Mismatch API ๊ฐœ์ˆ˜์™€ ์‹ค์ œ ๊ฐœ์ˆ˜ ๋ถˆ์ผ์น˜:', { - apiTotalCount, - actualReviewCount, - difference: apiTotalCount - actualReviewCount, - reason: 'API๊ฐ€ ์ตœ๋Œ€ 100๊ฐœ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ํŽ˜์ด์ง• ์ œํ•œ', - }); - } + // if (apiTotalCount > actualReviewCount && actualReviewCount > 0) { + // console.log('[UserReviews]-API Mismatch API ๊ฐœ์ˆ˜์™€ ์‹ค์ œ ๊ฐœ์ˆ˜ ๋ถˆ์ผ์น˜:', { + // apiTotalCount, + // actualReviewCount, + // difference: apiTotalCount - actualReviewCount, + // reason: 'API๊ฐ€ ์ตœ๋Œ€ 100๊ฐœ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” ํŽ˜์ด์ง• ์ œํ•œ', + // }); + // } return { totalReviews: actualReviewCount, // ์‹ค์ œ๋กœ ๋ฐ›์€ ๋ฆฌ๋ทฐ ๊ฐœ์ˆ˜ ์‚ฌ์šฉ (API ์ œํ•œ ๋ฐ˜์˜) diff --git a/com.twin.app.shoptime/src/reducers/productReducer.js b/com.twin.app.shoptime/src/reducers/productReducer.js index a3df2238..ddab2d16 100644 --- a/com.twin.app.shoptime/src/reducers/productReducer.js +++ b/com.twin.app.shoptime/src/reducers/productReducer.js @@ -1,73 +1,68 @@ -import { types } from "../actions/actionTypes"; -import { curry, get, set } from "../utils/fp"; +import { types } from '../actions/actionTypes'; +import { curry, get, set } from '../utils/fp'; const initialState = { bestSellerData: {}, productImageLength: 0, prdtOptInfo: {}, - reviewData: null, // ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ - showAllReviews: false, // ์ „์ฒด ๋ฆฌ๋ทฐ ๋ณด๊ธฐ ์ƒํƒœ - loadedPrdtId: null, // ํ˜„์žฌ ๋กœ๋“œ๋œ ์ƒํ’ˆ ID + reviewData: null, // ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ + showAllReviews: false, // ์ „์ฒด ๋ฆฌ๋ทฐ ๋ณด๊ธฐ ์ƒํƒœ + loadedPrdtId: null, // ํ˜„์žฌ ๋กœ๋“œ๋œ ์ƒํ’ˆ ID }; // FP: handlers map (curried), pure and immutable updates only const handleBestSeller = curry((state, action) => - set("bestSellerData", get("payload", action), state) + set('bestSellerData', get('payload', action), state) ); const handleProductOption = curry((state, action) => - set("prdtOptInfo", get(["payload", "prdtOptInfo"], action), state) + set('prdtOptInfo', get(['payload', 'prdtOptInfo'], action), state) ); const handleProductGroup = curry((state, action) => - set("groupInfo", get(["payload", "groupInfo"], action), state) + set('groupInfo', get(['payload', 'groupInfo'], action), state) ); const handleProductImageLength = curry((state, action) => - set( - "productImageLength", - (get("payload", action) ? get("payload", action) : 0) + 1, - state - ) + set('productImageLength', (get('payload', action) ? get('payload', action) : 0) + 1, state) ); const handleVideoIndicatorFocus = curry((state, action) => - set("videoIndicatorFocus", get("payload", action), state) + set('videoIndicatorFocus', get('payload', action), state) ); -const handleClearProductDetail = curry((state) => set("prdtOptInfo", null, state)); +const handleClearProductDetail = curry((state) => set('prdtOptInfo', null, state)); const handleProductOptionId = curry((state, action) => - set("prodOptCdCval", get("payload", action), state) + set('prodOptCdCval', get('payload', action), state) ); // ์œ ์ € ๋ฆฌ๋ทฐ ๋ฐ์ดํ„ฐ ํ•ธ๋“ค๋Ÿฌ ์ถ”๊ฐ€ const handleUserReview = curry((state, action) => { - const reviewData = get("payload", action); - const prdtId = get(["payload", "prdtId"], action); - - console.log("[UserReviews] Reducer - Storing review data:", { - prdtId: prdtId, - hasData: !!reviewData, - reviewListLength: reviewData && reviewData.reviewList ? reviewData.reviewList.length : 0, - totalCount: reviewData && reviewData.reviewDetail ? reviewData.reviewDetail.totRvwCnt : 0 - }); - - return set("reviewData", reviewData, - set("loadedPrdtId", prdtId, state)); + const reviewData = get('payload', action); + const prdtId = get(['payload', 'prdtId'], action); + + // console.log("[UserReviews] Reducer - Storing review data:", { + // prdtId: prdtId, + // hasData: !!reviewData, + // reviewListLength: reviewData && reviewData.reviewList ? reviewData.reviewList.length : 0, + // totalCount: reviewData && reviewData.reviewDetail ? reviewData.reviewDetail.totRvwCnt : 0 + // }); + + return set('reviewData', reviewData, set('loadedPrdtId', prdtId, state)); }); // showAllReviews ํ† ๊ธ€ ํ•ธ๋“ค๋Ÿฌ const handleToggleShowAllReviews = curry((state, action) => { - const currentValue = get("showAllReviews", state); + const currentValue = get('showAllReviews', state); // console.log("[UserReviews] Toggle showAllReviews:", !currentValue); - return set("showAllReviews", !currentValue, state); + return set('showAllReviews', !currentValue, state); }); // showAllReviews ์ดˆ๊ธฐํ™” ํ•ธ๋“ค๋Ÿฌ const handleResetShowAllReviews = curry((state, action) => { // console.log("[UserReviews] Reset showAllReviews to false"); - return set("showAllReviews", false, state); + return set('showAllReviews', false, state); }); const handlers = { @@ -78,13 +73,13 @@ const handlers = { [types.GET_VIDEO_INDECATOR_FOCUS]: handleVideoIndicatorFocus, [types.CLEAR_PRODUCT_DETAIL]: handleClearProductDetail, [types.GET_PRODUCT_OPTION_ID]: handleProductOptionId, - [types.GET_USER_REVIEW]: handleUserReview, // GET_USER_REVIEW ํ•ธ๋“ค๋Ÿฌ ์ถ”๊ฐ€ - [types.TOGGLE_SHOW_ALL_REVIEWS]: handleToggleShowAllReviews, // showAllReviews ํ† ๊ธ€ ํ•ธ๋“ค๋Ÿฌ - [types.RESET_SHOW_ALL_REVIEWS]: handleResetShowAllReviews, // showAllReviews ์ดˆ๊ธฐํ™” ํ•ธ๋“ค๋Ÿฌ + [types.GET_USER_REVIEW]: handleUserReview, // GET_USER_REVIEW ํ•ธ๋“ค๋Ÿฌ ์ถ”๊ฐ€ + [types.TOGGLE_SHOW_ALL_REVIEWS]: handleToggleShowAllReviews, // showAllReviews ํ† ๊ธ€ ํ•ธ๋“ค๋Ÿฌ + [types.RESET_SHOW_ALL_REVIEWS]: handleResetShowAllReviews, // showAllReviews ์ดˆ๊ธฐํ™” ํ•ธ๋“ค๋Ÿฌ }; export const productReducer = (state = initialState, action = {}) => { - const type = get("type", action); + const type = get('type', action); const handler = handlers[type]; return handler ? handler(state, action) : state; }; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviews.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviews.jsx index 935088c9..d50aa851 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviews.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/UserReviews/UserReviews.jsx @@ -169,12 +169,12 @@ export default function UserReviews({ productInfo, panelInfo, reviewsData }) { }, []); // ์ด๋ฏธ์ง€ ํด๋ฆญ์œผ๋กœ All-Images ๋ชจ๋“œ ํŒ์—… ์—ด๊ธฐ - const handleOpenAllImagesPopup = useCallback((imageIndex = 0) => { - console.log('[UserReviews] Opening popup in All-Images mode, image index:', imageIndex); - setSelectedImageIndex(imageIndex); - setPopupMode('all-images'); - setIsPopupOpen(true); - }, []); + // const handleOpenAllImagesPopup = useCallback((imageIndex = 0) => { + // console.log('[UserReviews] Opening popup in All-Images mode, image index:', imageIndex); + // setSelectedImageIndex(imageIndex); + // setPopupMode('all-images'); + // setIsPopupOpen(true); + // }, []); const handleClosePopup = useCallback(() => { // console.log("[UserReviews] Closing popup and resetting mode"); diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index 1bdc3b7a..8ce27256 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -269,7 +269,9 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props const vodLogParamsRef = useRef(null); const mediaLogParamsRef = useRef(null); const prevNowMenuRef = useRef(null); - const watchInterval = useRef(null); + const watchIntervalLive = useRef(null); + const watchIntervalVod = useRef(null); + const watchIntervalMedia = useRef(null); // useEffect(() => { // console.log("###videoLoaded", videoLoaded); // if (nowMenu) { @@ -443,7 +445,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ) { let watchStrtDt = formatGMTString(new Date()); - watchInterval.current = setInterval(() => { + watchIntervalLive.current = setInterval(() => { let watchEndDt = formatGMTString(new Date()); let watchRecord = { ...liveLogParamsRef.current, @@ -458,7 +460,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ...status, isModalLiveLogReady: false, })); - clearInterval(watchInterval.current); + clearInterval(watchIntervalLive.current); dispatch( sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} })) @@ -476,7 +478,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ) { let watchStrtDt = formatGMTString(new Date()); - watchInterval.current = setInterval(() => { + watchIntervalLive.current = setInterval(() => { let watchEndDt = formatGMTString(new Date()); let watchRecord = { ...liveLogParamsRef.current, @@ -491,7 +493,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ...status, isFullLiveLogReady: false, })); - clearInterval(watchInterval.current); + clearInterval(watchIntervalLive.current); dispatch( sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} })) @@ -509,7 +511,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ) { let watchStrtDt = formatGMTString(new Date()); - watchInterval.current = setInterval(() => { + watchIntervalLive.current = setInterval(() => { let watchEndDt = formatGMTString(new Date()); let watchRecord = { ...liveLogParamsRef.current, @@ -524,7 +526,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ...status, isDetailLiveLogReady: false, })); - clearInterval(watchInterval.current); + clearInterval(watchIntervalLive.current); dispatch( sendLogLive({ ...liveLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} })) @@ -596,7 +598,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ) { let watchStrtDt = formatGMTString(new Date()); - watchInterval.current = setInterval(() => { + watchIntervalVod.current = setInterval(() => { let watchEndDt = formatGMTString(new Date()); let watchRecord = { ...vodLogParamsRef.current, @@ -611,7 +613,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ...status, isModalVodLogReady: false, })); - clearInterval(watchInterval.current); + clearInterval(watchIntervalVod.current); dispatch( sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} })) @@ -629,7 +631,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ) { let watchStrtDt = formatGMTString(new Date()); - watchInterval.current = setInterval(() => { + watchIntervalVod.current = setInterval(() => { let watchEndDt = formatGMTString(new Date()); let watchRecord = { ...vodLogParamsRef.current, @@ -644,7 +646,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ...status, isFullVodLogReady: false, })); - clearInterval(watchInterval.current); + clearInterval(watchIntervalVod.current); dispatch( sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} })) @@ -662,7 +664,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ) { let watchStrtDt = formatGMTString(new Date()); - watchInterval.current = setInterval(() => { + watchIntervalVod.current = setInterval(() => { let watchEndDt = formatGMTString(new Date()); let watchRecord = { ...vodLogParamsRef.current, @@ -677,7 +679,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ...status, isDetailVodLogReady: false, })); - clearInterval(watchInterval.current); + clearInterval(watchIntervalVod.current); dispatch( sendLogVOD({ ...vodLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} })) @@ -752,7 +754,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props if (logStatus.isModalMediaLogReady && panelInfo?.modal) { let watchStrtDt = formatGMTString(new Date()); - watchInterval.current = setInterval(() => { + watchIntervalMedia.current = setInterval(() => { let watchEndDt = formatGMTString(new Date()); let watchRecord = { ...mediaLogParamsRef.current, @@ -767,7 +769,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ...status, isModalMediaLogReady: false, })); - clearInterval(watchInterval.current); + clearInterval(watchIntervalMedia.current); dispatch( sendLogVOD({ ...mediaLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} })) @@ -781,7 +783,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props if (logStatus.isFullMediaLogReady && !panelInfo?.modal) { let watchStrtDt = formatGMTString(new Date()); - watchInterval.current = setInterval(() => { + watchIntervalMedia.current = setInterval(() => { let watchEndDt = formatGMTString(new Date()); let watchRecord = { ...mediaLogParamsRef.current, @@ -796,7 +798,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ...status, isFullMediaLogReady: false, })); - clearInterval(watchInterval.current); + clearInterval(watchIntervalMedia.current); dispatch( sendLogVOD({ ...mediaLogParamsRef.current, watchStrtDt }, () => dispatch(changeLocalSettings({ watchRecord: {} })) diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabButton/PlayerTabButton.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabButton/PlayerTabButton.jsx index c6dd21de..516811e6 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabButton/PlayerTabButton.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabButton/PlayerTabButton.jsx @@ -1,21 +1,21 @@ -import React, { useCallback, useEffect } from "react"; +import React, { useCallback, useEffect } from 'react'; -import classNames from "classnames"; -import { useDispatch, useSelector } from "react-redux"; +import classNames from 'classnames'; +import { useDispatch, useSelector } from 'react-redux'; -import Spotlight from "@enact/spotlight"; -import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; -import Spottable from "@enact/spotlight/Spottable"; +import Spotlight from '@enact/spotlight'; +import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; +import Spottable from '@enact/spotlight/Spottable'; -import { updatePanel } from "../../../../actions/panelActions"; -import { panel_names } from "../../../../utils/Config"; -import { SpotlightIds } from "../../../../utils/SpotlightIds"; -import css from "./PlayerTabButton.module.less"; +import { updatePanel } from '../../../../actions/panelActions'; +import { panel_names } from '../../../../utils/Config'; +import { SpotlightIds } from '../../../../utils/SpotlightIds'; +import css from './PlayerTabButton.module.less'; -const SpottableComponent = Spottable("button"); +const SpottableComponent = Spottable('button'); const Container = SpotlightContainerDecorator( - { enterTo: "default-element", preserveld: true }, - "div" + { enterTo: 'default-element', preserveld: true }, + 'div' ); export default function PlayerTabButton({ sideContentsVisible, @@ -26,22 +26,27 @@ export default function PlayerTabButton({ const dispatch = useDispatch(); const countryCode = useSelector((state) => state.common.httpHeader.cntry_cd); - const handleTabOnClick = (e) => { - dispatch( - updatePanel({ - name: panel_names.PLAYER_PANEL, - panelInfo: { - isUpdatedByClick: false, - }, - }) - ); - setSideContentsVisible((prev) => !prev); - setTimeout(() => { - Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON); - }, 0); + const handleTabOnClick = useCallback( + (e) => { + dispatch( + updatePanel({ + name: panel_names.PLAYER_PANEL, + panelInfo: { + isUpdatedByClick: false, + }, + }) + ); + setSideContentsVisible((prev) => !prev); - e.stopPropagation(); - }; + // microtask ํ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ ์ดํ›„ ํฌ์ปค์Šค ์ด๋™ + Promise.resolve().then(() => { + Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON); + }); + + e.stopPropagation(); + }, + [dispatch, setSideContentsVisible] + ); const _onSpotlightLeft = useCallback( (e) => { @@ -52,7 +57,7 @@ export default function PlayerTabButton({ } if (!sideContentsVisible) { e.stopPropagation(); - Spotlight.focus("videoIndicator-up-button"); + Spotlight.focus('videoIndicator-up-button'); } }, [sideContentsVisible] @@ -60,10 +65,10 @@ export default function PlayerTabButton({ const onSpotlightDown = useCallback( (e) => { - if (countryCode !== "US") { - if (videoType === "VOD") { - Spotlight.focus("videoIndicator-up-button"); - } else if (videoType === "LIVE") { + if (countryCode !== 'US') { + if (videoType === 'VOD') { + Spotlight.focus('videoIndicator-up-button'); + } else if (videoType === 'LIVE') { Spotlight.focus(SpotlightIds.PLAYER_SLIDER); } return; @@ -80,7 +85,7 @@ export default function PlayerTabButton({ (e) => { if (!sideContentsVisible) { e.stopPropagation(); - Spotlight.focus("videoIndicator-up-button"); + Spotlight.focus('videoIndicator-up-button'); } }, [sideContentsVisible] diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx index e246dce9..0538c7b9 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/FeaturedShowContents.jsx @@ -1,19 +1,19 @@ -import React, { useCallback, useEffect, useMemo, useRef } from "react"; +import React, { useCallback, useEffect, useMemo, useRef } from 'react'; -import { useDispatch } from "react-redux"; +import { useDispatch } from 'react-redux'; -import Spotlight from "@enact/spotlight"; +import Spotlight from '@enact/spotlight'; -import defaultImage from "../../../../../assets/images/img-thumb-empty-144@3x.png"; -import { updatePanel } from "../../../../actions/panelActions"; -import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList"; -import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from "../../../../utils/Config"; -import { $L, removeSpecificTags } from "../../../../utils/helperMethods"; -import PlayerItemCard, { TYPES } from "../../PlayerItemCard/PlayerItemCard"; -import ListEmptyContents from "../TabContents/ListEmptyContents/ListEmptyContents"; -import css from "./LiveChannelContents.module.less"; -import { getMainCategoryShowDetail } from "../../../../actions/mainActions"; -import { sendLogTotalRecommend } from "../../../../actions/logActions"; +import defaultImage from '../../../../../assets/images/img-thumb-empty-144@3x.png'; +import { updatePanel } from '../../../../actions/panelActions'; +import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList'; +import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../../../utils/Config'; +import { $L, removeSpecificTags } from '../../../../utils/helperMethods'; +import PlayerItemCard, { TYPES } from '../../PlayerItemCard/PlayerItemCard'; +import ListEmptyContents from '../TabContents/ListEmptyContents/ListEmptyContents'; +import css from './LiveChannelContents.module.less'; +import { getMainCategoryShowDetail } from '../../../../actions/mainActions'; +import { sendLogTotalRecommend } from '../../../../actions/logActions'; export default function FeaturedShowContents({ featuredShowsInfos, @@ -25,10 +25,12 @@ export default function FeaturedShowContents({ tabIndex, handleItemFocus, tabTitle, - panelInfo + panelInfo, }) { const dispatch = useDispatch(); const isClickBlocked = useRef(false); + const blockTimeoutRef = useRef(null); + const handleFocus = useCallback( () => () => { if (handleItemFocus) { @@ -61,8 +63,8 @@ export default function FeaturedShowContents({ category: catNm, partner: patncNm, contextName: LOG_CONTEXT_NAME.SHOW, - messageId: LOG_MESSAGE_ID.CONTENTCLICK - } + messageId: LOG_MESSAGE_ID.CONTENTCLICK, + }; dispatch(sendLogTotalRecommend(params)); //์ค‘๋ณตํด๋ฆญ๋ฐฉ์ง€ if (isClickBlocked.current) { @@ -70,8 +72,15 @@ export default function FeaturedShowContents({ } isClickBlocked.current = true; - setTimeout(() => { + + // ์ด์ „ ํƒ€์ด๋จธ๊ฐ€ ์žˆ์œผ๋ฉด ์ •๋ฆฌ + if (blockTimeoutRef.current) { + clearTimeout(blockTimeoutRef.current); + } + + blockTimeoutRef.current = setTimeout(() => { isClickBlocked.current = false; + blockTimeoutRef.current = null; }, 600); if (currentVideoShowId && currentVideoShowId === showId) { @@ -107,29 +116,30 @@ export default function FeaturedShowContents({ spotlightId={`tabChannel-video-${index}`} videoVerticalVisible={videoVerticalVisible} selectedIndex={index} - currentVideoVisible={ - currentVideoShowId === featuredShowsInfos[index].showId - } + currentVideoVisible={currentVideoShowId === featuredShowsInfos[index].showId} /> ); }, - [ - featuredShowsInfos, - currentVideoInfo, - currentVideoShowId, - videoVerticalVisible, - isClickBlocked, - ] + [featuredShowsInfos, currentVideoInfo, currentVideoShowId, videoVerticalVisible, isClickBlocked] ); useEffect(() => { const timer = setTimeout(() => { - Spotlight.focus("tabChannel-video-" + selectedIndex); + Spotlight.focus('tabChannel-video-' + selectedIndex); }); return () => clearTimeout(timer); }, [featuredShowsInfos]); + // cleanup useEffect + useEffect(() => { + return () => { + if (blockTimeoutRef.current) { + clearTimeout(blockTimeoutRef.current); + } + }; + }, []); + return ( <>
diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx index 41615161..009f4341 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/LiveChannelContents.jsx @@ -29,6 +29,8 @@ export default function LiveChannelContents({ }) { const dispatch = useDispatch(); const isClickBlocked = useRef(false); + const blockTimeoutRef = useRef(null); + const handleFocus = useCallback( () => () => { if (handleItemFocus) { @@ -75,8 +77,15 @@ export default function LiveChannelContents({ } isClickBlocked.current = true; - setTimeout(() => { + + // ์ด์ „ ํƒ€์ด๋จธ๊ฐ€ ์žˆ์œผ๋ฉด ์ •๋ฆฌ + if (blockTimeoutRef.current) { + clearTimeout(blockTimeoutRef.current); + } + + blockTimeoutRef.current = setTimeout(() => { isClickBlocked.current = false; + blockTimeoutRef.current = null; }, 600); if (!showId) return; @@ -144,6 +153,15 @@ export default function LiveChannelContents({ const containerClass = version === 2 ? cssV2.container : css.container; + // cleanup useEffect + useEffect(() => { + return () => { + if (blockTimeoutRef.current) { + clearTimeout(blockTimeoutRef.current); + } + }; + }, []); + return ( <>
diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx index 90aaa21f..8316920d 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx @@ -120,9 +120,11 @@ export default function TabContainerV2({ // tabIndex๊ฐ€ 2(ShopNowButton)๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด ์ž๋™์œผ๋กœ ํฌ์ปค์Šค ์ด๋™ useEffect(() => { if (tabIndex === 2) { - setTimeout(() => { + const timeoutId = setTimeout(() => { Spotlight.focus('below-tab-shop-now-button'); }, 100); + + return () => clearTimeout(timeoutId); } }, [tabIndex]);