From 7da55ea1ae6caa535fcc68505fdc14f81a456bf3 Mon Sep 17 00:00:00 2001 From: optrader Date: Mon, 24 Nov 2025 19:23:41 +0900 Subject: [PATCH] =?UTF-8?q?[251124]=20fix:=20PlayerPanel,VideoPlayer=20?= =?UTF-8?q?=EC=B5=9C=EC=A0=81=ED=99=94-6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 11. 24. 19:23:39 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 8๊ฐœ โ€ข ์ถ”๊ฐ€: +142์ค„ โ€ข ์‚ญ์ œ: -31์ค„ ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/actions/playActions.js ~ com.twin.app.shoptime/src/components/MediaItem/MediaItem.js ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaTitle.js ~ com.twin.app.shoptime/src/components/VideoPlayer/TReactPlayer.jsx ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js ~ com.twin.app.shoptime/src/hooks/useReviews/useReviews.js ~ com.twin.app.shoptime/src/utils/helperMethods.js ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx ๐Ÿ”ง ์ฃผ์š” ๋ณ€๊ฒฝ ๋‚ด์šฉ: โ€ข ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ฐœ์„  โ€ข UI ์ปดํฌ๋„ŒํŠธ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„  โ€ข ๊ณตํ†ต ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ์ตœ์ ํ™” โ€ข ์ค‘๊ฐ„ ๊ทœ๋ชจ ๊ธฐ๋Šฅ ๊ฐœ์„  โ€ข ๋ชจ๋“ˆ ๊ตฌ์กฐ ๊ฐœ์„  --- .../src/actions/playActions.js | 110 ++++++++++++++++++ .../src/components/MediaItem/MediaItem.js | 2 +- .../src/components/VideoPlayer/MediaTitle.js | 2 +- .../components/VideoPlayer/TReactPlayer.jsx | 4 +- .../src/components/VideoPlayer/VideoPlayer.js | 4 +- .../src/hooks/useReviews/useReviews.js | 38 +++--- .../src/utils/helperMethods.js | 7 ++ .../src/views/PlayerPanel/PlayerPanel.jsx | 4 +- 8 files changed, 141 insertions(+), 30 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/playActions.js b/com.twin.app.shoptime/src/actions/playActions.js index 2db5ac53..b432e9a9 100644 --- a/com.twin.app.shoptime/src/actions/playActions.js +++ b/com.twin.app.shoptime/src/actions/playActions.js @@ -1147,3 +1147,113 @@ export const setDisplayFullscreen = () => ({ lastUpdate: Date.now(), }, }); + +/** + * ๋ฐฐ๋„ˆ ๋น„๋””์˜ค๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. + * @param {Object} videoInfo - ๋น„๋””์˜ค ์ •๋ณด + * @param {string} videoInfo.bannerId - ๋ฐฐ๋„ˆ ID + * @param {string} videoInfo.videoId - ๋น„๋””์˜ค ID + * @param {string} videoInfo.showUrl - ๋น„๋””์˜ค URL + * @param {boolean} videoInfo.modal - ๋ชจ๋‹ฌ ์—ฌ๋ถ€ + * @param {string} videoInfo.modalContainerId - ๋ชจ๋‹ฌ ์ปจํ…Œ์ด๋„ˆ ID + * @param {string} videoInfo.modalClassName - ๋ชจ๋‹ฌ ํด๋ž˜์Šค ์ด๋ฆ„ + */ +export const startBannerVideo = (videoInfo) => (dispatch, getState) => { + dlog('[startBannerVideo] โœ… START - videoInfo:', videoInfo); + + const { + bannerId, + videoId, + showUrl, + modal = true, + modalContainerId, + modalClassName, + ...rest + } = videoInfo; + + // ๋น„๋””์˜ค ์‹๋ณ„์ž ์ƒ์„ฑ + const videoIdentifier = videoId || showUrl || bannerId; + if (videoIdentifier) { + const displayMode = modal ? DISPLAY_STATUS.VISIBLE : DISPLAY_STATUS.FULLSCREEN; + dlog( + '[startBannerVideo] ๐Ÿ“Œ Setting playback loading - identifier:', + videoIdentifier, + ', displayMode:', + displayMode + ); + dispatch(setPlaybackLoading(videoIdentifier, displayMode)); + } + + const panels = getState().panels.panels; + const existingPlayerPanel = panels.find((p) => p.name === panel_names.PLAYER_PANEL); + + // ๊ธฐ์กด PlayerPanel์ด ์žˆ์œผ๋ฉด ์ดˆ๊ธฐํ™” + if (existingPlayerPanel) { + dlog('[startBannerVideo] ๐Ÿ”„ Resetting existing PLAYER_PANEL before start'); + clearAllVideoTimers(); + dispatch(popPanel(panel_names.PLAYER_PANEL)); + } + + // ์ƒˆ๋กœ์šด PlayerPanel push + dispatch( + pushPanel( + { + name: panel_names.PLAYER_PANEL, + panelInfo: { + modal, + modalContainerId, + modalClassName, + playerState: { + currentBannerId: bannerId, + }, + videoId, + showUrl, + bannerId, + ...rest, + }, + }, + true + ) + ); + + dlog('[startBannerVideo] โœจ Panel action dispatched'); +}; + +/** + * ๋น„๋””์˜ค๋ฅผ ์ค‘์ง€ํ•˜๊ณ  ํ™”๋ฉด์—์„œ ์ˆจ๊น๋‹ˆ๋‹ค. + * ํŒจ๋„์„ ๋‹ซ์ง€ ์•Š๊ณ  ๋น„๋””์˜ค ์žฌ์ƒ๋งŒ ์ค‘์ง€ํ•ฉ๋‹ˆ๋‹ค. + */ +export const stopAndHideVideo = () => (dispatch, getState) => { + const panels = getState().panels.panels; + + // ๋ชจ๋“  PlayerPanel ์ฐพ๊ธฐ + const playerPanels = panels.filter((panel) => panel.name === panel_names.PLAYER_PANEL); + + if (playerPanels.length > 0) { + dlog('[stopAndHideVideo] Stopping all video playback and hiding'); + + // ํƒ€์ด๋จธ ์ •๋ฆฌ + if (startVideoFocusTimer) { + clearTimeout(startVideoFocusTimer); + startVideoFocusTimer = null; + } + + // ๋ชจ๋“  PlayerPanel์„ ์ค‘์ง€ ๋ฐ ์ˆจ๊น€ ์ƒํƒœ๋กœ ์—…๋ฐ์ดํŠธ + playerPanels.forEach((playerPanel) => { + dispatch( + updatePanel({ + name: panel_names.PLAYER_PANEL, + panelInfo: { + ...playerPanel.panelInfo, + shouldStop: true, + isPaused: true, + isHidden: true, + }, + }) + ); + }); + + // Redux ์ƒํƒœ๋„ ์ค‘์ง€๋กœ ์—…๋ฐ์ดํŠธ + dispatch(setVideoStopped()); + } +}; diff --git a/com.twin.app.shoptime/src/components/MediaItem/MediaItem.js b/com.twin.app.shoptime/src/components/MediaItem/MediaItem.js index 9f4dda2a..50e2a33b 100644 --- a/com.twin.app.shoptime/src/components/MediaItem/MediaItem.js +++ b/com.twin.app.shoptime/src/components/MediaItem/MediaItem.js @@ -20,7 +20,7 @@ import * as Config from "../../utils/Config"; import * as ContentType from "../../utils/Config"; import * as Utils from "../../utils/helperMethods"; import { $L } from "../../utils/helperMethods"; -import SpotlightIds from "../../utils/SpotlightIds"; +import { SpotlightIds } from "../../utils/SpotlightIds"; import css from "./MediaItem.module.less"; /** diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaTitle.js b/com.twin.app.shoptime/src/components/VideoPlayer/MediaTitle.js index 2f3c3035..b859e816 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/MediaTitle.js +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaTitle.js @@ -10,7 +10,7 @@ import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainer import ForwardRef from "@enact/ui/ForwardRef"; import { $L } from "../../utils/helperMethods"; -import SpotlightIds from "../../utils/SpotlightIds"; +import { SpotlightIds } from "../../utils/SpotlightIds"; import TButton from "../TButton/TButton"; import css from "./MediaTitle.module.less"; diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/TReactPlayer.jsx b/com.twin.app.shoptime/src/components/VideoPlayer/TReactPlayer.jsx index 5b730908..c35e839c 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/TReactPlayer.jsx +++ b/com.twin.app.shoptime/src/components/VideoPlayer/TReactPlayer.jsx @@ -158,7 +158,7 @@ export default function TReactPlayer({ // ๐Ÿ”ฝ [์ตœ์ ํ™”] URL ๋ณ€๊ฒฝ ๋˜๋Š” ์–ธ๋งˆ์šดํŠธ ์‹œ ์ด์ „ ๋น„๋””์˜ค ์ •๋ฆฌ (๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€) useEffect(() => { return () => { - console.log('[TReactPlayer] cleanup - start', { url }); + // console.log('[TReactPlayer] cleanup - start', { url }); const videoNode = playerRef.current?.getInternalPlayer(); if (videoNode) { try { @@ -179,7 +179,7 @@ export default function TReactPlayer({ console.warn('[TReactPlayer] cleanup warning:', err); } } - console.log('[TReactPlayer] cleanup - done', { url }); + // console.log('[TReactPlayer] cleanup - done', { url }); }; }, [url]); // โœ… URL ๋ณ€๊ฒฝ ์‹œ์—๋„ ์ •๋ฆฌ ๋กœ์ง ์‹คํ–‰ diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js index 35ab208c..7d0eacd1 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js +++ b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js @@ -1020,7 +1020,7 @@ const VideoPlayerBase = class extends React.Component { } componentWillUnmount() { - console.log('[VideoPlayer] componentWillUnmount - start cleanup', { src: this.props?.src }); + // console.log('[VideoPlayer] componentWillUnmount - start cleanup', { src: this.props?.src }); off('mousemove', this.activityDetected); if (platform.touch) { off('touchmove', this.activityDetected); @@ -1089,7 +1089,7 @@ const VideoPlayerBase = class extends React.Component { // ์ •๋ฆฌ ์ค‘ ์—๋Ÿฌ๋Š” ๋ฌด์‹œํ•˜๊ณ  ์–ธ๋งˆ์šดํŠธ ์ง„ํ–‰ // console.warn('[VideoPlayer] cleanup error', err); } - console.log('[VideoPlayer] componentWillUnmount - cleanup done', { src: this.props?.src }); + // console.log('[VideoPlayer] componentWillUnmount - cleanup done', { src: this.props?.src }); if (this.floatingLayerController) { this.floatingLayerController.unregister(); } diff --git a/com.twin.app.shoptime/src/hooks/useReviews/useReviews.js b/com.twin.app.shoptime/src/hooks/useReviews/useReviews.js index a93c2a99..415831f4 100644 --- a/com.twin.app.shoptime/src/hooks/useReviews/useReviews.js +++ b/com.twin.app.shoptime/src/hooks/useReviews/useReviews.js @@ -1,6 +1,6 @@ import { useState, useMemo, useEffect, useCallback } from 'react'; import { useSelector, useDispatch } from 'react-redux'; -import { getUserReviews, getUserReviewList, getReviewFilters, clearReviewFilter } from '../../actions/productActions'; +import { getUserReviewList, getReviewFilters, clearReviewFilter } from '../../actions/productActions'; import fp from '../../utils/fp'; const DISPLAY_SIZE = 3; // ํ™”๋ฉด์— ํ‘œ์‹œํ•  ๋ฆฌ๋ทฐ ๊ฐœ์ˆ˜ @@ -175,28 +175,22 @@ const useReviews = (prdtId, patnrId, _deprecatedReviewVersion) => { // }); try { - if (reviewVersion === 1) { - // ๊ธฐ์กด API ํ˜ธ์ถœ - // console.log('[useReviews] ๐Ÿ”„ getUserReviews ํ˜ธ์ถœ ์ค‘... (v1)'); - await dispatch(getUserReviews({ prdtId, patnrId })); - } else { - // ์‹  API ํ˜ธ์ถœ (v2) - // console.log('[useReviews] ๐Ÿ”„ getUserReviewList ํ˜ธ์ถœ ์ค‘... (v2)'); - await dispatch(getUserReviewList({ - prdtId, - patnrId, - filterTpCd: 'ALL', - pageSize: 100, - pageNo: 1 - })); + // ์‹  API ํ˜ธ์ถœ (v2) + // console.log('[useReviews] ๐Ÿ”„ getUserReviewList ํ˜ธ์ถœ ์ค‘... (v2)'); + await dispatch(getUserReviewList({ + prdtId, + patnrId, + filterTpCd: 'ALL', + pageSize: 100, + pageNo: 1 + })); - // IF-LGSP-100 ํ•„ํ„ฐ ๋ฐ์ดํ„ฐ ์กฐํšŒ - // console.log('[useReviews] ๐Ÿ”„ getReviewFilters ํ˜ธ์ถœ ์ค‘... (IF-LGSP-100)'); - await dispatch(getReviewFilters({ - prdtId, - patnrId - })); - } + // IF-LGSP-100 ํ•„ํ„ฐ ๋ฐ์ดํ„ฐ ์กฐํšŒ + // console.log('[useReviews] ๐Ÿ”„ getReviewFilters ํ˜ธ์ถœ ์ค‘... (IF-LGSP-100)'); + await dispatch(getReviewFilters({ + prdtId, + patnrId + })); setHasLoadedData(true); } catch (error) { console.error('[useReviews] loadReviews ์‹คํŒจ:', error); diff --git a/com.twin.app.shoptime/src/utils/helperMethods.js b/com.twin.app.shoptime/src/utils/helperMethods.js index c6996563..3b487997 100644 --- a/com.twin.app.shoptime/src/utils/helperMethods.js +++ b/com.twin.app.shoptime/src/utils/helperMethods.js @@ -572,3 +572,10 @@ export const getReservationErrorMessage = (error) => { return $L("Failed to set reminder. Please try again."); }; + +export const convertNewlinesToBr = (text) => { + if (typeof text !== 'string') { + return text; + } + return text.replace(/\n/g, '
'); +}; diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index fe07a672..4635a566 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -2222,13 +2222,13 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props useEffect(() => { return () => { - console.log('[PlayerPanel] unmount cleanup start'); + // console.log('[PlayerPanel] unmount cleanup start'); cleanupPlayerOnUnmount(); stopExternalPlayer(); dispatch(clearShopNowInfo()); dispatch(CLEAR_PLAYER_INFO()); setShopNowInfo([]); - console.log('[PlayerPanel] unmount cleanup done'); + // console.log('[PlayerPanel] unmount cleanup done'); }; }, [cleanupPlayerOnUnmount, stopExternalPlayer, dispatch]);