[251114] fix: ProductAllSection ProductVideo.v3
🕐 커밋 시간: 2025. 11. 14. 15:36:07 📊 변경 통계: • 총 파일: 4개 • 추가: +27줄 • 삭제: -333줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/utils/helperMethods.js ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v3.jsx ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/utils/helperMethods.js (javascript): ✅ Added: getFormattingDate() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): 🔄 Modified: extractProductMeta() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v3.jsx (javascript): ✅ Added: Spottable() 📄 com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx (javascript): 🔄 Modified: normalizeModalStyle() ❌ Deleted: handleEvent() 🔧 주요 변경 내용: • 공통 유틸리티 함수 최적화 Performance: 코드 최적화로 성능 개선 기대
This commit is contained in:
@@ -397,6 +397,11 @@ export const getFormattingDate = (dateString) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const removeSpecificTags = (html) => {
|
export const removeSpecificTags = (html) => {
|
||||||
|
// null 또는 undefined 체크
|
||||||
|
if (!html) {
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
const tagPatterns = [
|
const tagPatterns = [
|
||||||
/<a\b[^>]*>(.*?)<\/a>/gi,
|
/<a\b[^>]*>(.*?)<\/a>/gi,
|
||||||
/<script\b[^>]*>(.*?)<\/script>/gi,
|
/<script\b[^>]*>(.*?)<\/script>/gi,
|
||||||
|
|||||||
@@ -151,6 +151,8 @@ export default function ProductAllSection({
|
|||||||
|
|
||||||
// ProductVideo 버전 관리 (1: 기존 modal 방식, 2: 내장 방식 , 3: 비디오 생략)
|
// ProductVideo 버전 관리 (1: 기존 modal 방식, 2: 내장 방식 , 3: 비디오 생략)
|
||||||
const [productVideoVersion, setProductVideoVersion] = useState(1);
|
const [productVideoVersion, setProductVideoVersion] = useState(1);
|
||||||
|
// 비디오 재생 여부 flag (재생 전에는 minimize/restore 로직 비활성화)
|
||||||
|
const [isVideoPlaying, setIsVideoPlaying] = useState(false);
|
||||||
|
|
||||||
// const [currentHeight, setCurrentHeight] = useState(0);
|
// const [currentHeight, setCurrentHeight] = useState(0);
|
||||||
//하단부분까지 갔을때 체크용
|
//하단부분까지 갔을때 체크용
|
||||||
@@ -666,7 +668,8 @@ export default function ProductAllSection({
|
|||||||
|
|
||||||
// 🔽 ProductVideo (v3.jsx)에만 HomePanel 스타일 즉각 스크롤 로직 적용
|
// 🔽 ProductVideo (v3.jsx)에만 HomePanel 스타일 즉각 스크롤 로직 적용
|
||||||
// ProductVideo.v3.jsx는 ProductVideo로 import되어 productVideoVersion === 1일 때 사용됨
|
// ProductVideo.v3.jsx는 ProductVideo로 import되어 productVideoVersion === 1일 때 사용됨
|
||||||
if (productVideoVersion === 1) {
|
// ⚠️ 비디오가 재생되었을 때만 minimize/restore 로직 실행
|
||||||
|
if (productVideoVersion === 1 && isVideoPlaying) {
|
||||||
const isScrollingDown = currentScrollTop > prevScrollTop;
|
const isScrollingDown = currentScrollTop > prevScrollTop;
|
||||||
|
|
||||||
prevScrollTopRef.current = currentScrollTop;
|
prevScrollTopRef.current = currentScrollTop;
|
||||||
@@ -710,7 +713,7 @@ export default function ProductAllSection({
|
|||||||
}
|
}
|
||||||
// v2: onScrollStop에서 처리 (기존 로직 유지)
|
// v2: onScrollStop에서 처리 (기존 로직 유지)
|
||||||
},
|
},
|
||||||
[documentHeight, isBottom, productVideoVersion, dispatch]
|
[documentHeight, isBottom, productVideoVersion, isVideoPlaying, dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
// 스크롤 멈추었을 때만 호출 (성능 최적화)
|
// 스크롤 멈추었을 때만 호출 (성능 최적화)
|
||||||
@@ -1112,6 +1115,7 @@ export default function ProductAllSection({
|
|||||||
thumbnailUrl={renderItems[0].thumbnail}
|
thumbnailUrl={renderItems[0].thumbnail}
|
||||||
autoPlay={true}
|
autoPlay={true}
|
||||||
continuousPlay={true}
|
continuousPlay={true}
|
||||||
|
onVideoPlaying={() => setIsVideoPlaying(true)}
|
||||||
onScrollToImages={handleScrollToImagesV1}
|
onScrollToImages={handleScrollToImagesV1}
|
||||||
onFocus={() => console.log('[ProductVideo V1] Focused')}
|
onFocus={() => console.log('[ProductVideo V1] Focused')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export default function ProductVideo({
|
|||||||
videoUrl,
|
videoUrl,
|
||||||
thumbnailUrl,
|
thumbnailUrl,
|
||||||
onScrollToImages,
|
onScrollToImages,
|
||||||
|
onVideoPlaying = null, // 비디오 재생 시 호출되는 콜백
|
||||||
autoPlay = false, // 자동 재생 여부
|
autoPlay = false, // 자동 재생 여부
|
||||||
continuousPlay = false, // 반복 재생 여부
|
continuousPlay = false, // 반복 재생 여부
|
||||||
onFocus = null, // 외부에서 전달된 포커스 핸들러
|
onFocus = null, // 외부에서 전달된 포커스 핸들러
|
||||||
@@ -32,6 +33,7 @@ export default function ProductVideo({
|
|||||||
const [focused, setFocused] = useState(false);
|
const [focused, setFocused] = useState(false);
|
||||||
const [modalState, setModalState] = useState(true); // 모달 상태 관리 추가
|
const [modalState, setModalState] = useState(true); // 모달 상태 관리 추가
|
||||||
const [hasAutoPlayed, setHasAutoPlayed] = useState(false); // 자동 재생 완료 여부
|
const [hasAutoPlayed, setHasAutoPlayed] = useState(false); // 자동 재생 완료 여부
|
||||||
|
const [isVideoPlaying, setIsVideoPlaying] = useState(false); // 비디오 재생 여부 flag
|
||||||
|
|
||||||
const topPanel = panels[panels.length - 1];
|
const topPanel = panels[panels.length - 1];
|
||||||
|
|
||||||
@@ -59,6 +61,10 @@ export default function ProductVideo({
|
|||||||
|
|
||||||
// 짧은 딜레이 후 재생 시작 (컴포넌트 마운트 완료 후)
|
// 짧은 딜레이 후 재생 시작 (컴포넌트 마운트 완료 후)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
setIsVideoPlaying(true); // 비디오 재생 flag 설정
|
||||||
|
if (onVideoPlaying) {
|
||||||
|
onVideoPlaying(); // 부모 컴포넌트에 알림
|
||||||
|
}
|
||||||
dispatch(
|
dispatch(
|
||||||
startMediaPlayer({
|
startMediaPlayer({
|
||||||
qrCurrentItem: productInfo,
|
qrCurrentItem: productInfo,
|
||||||
@@ -178,6 +184,10 @@ export default function ProductVideo({
|
|||||||
console.log('[ProductVideo] *** Starting modal MediaPanel ***');
|
console.log('[ProductVideo] *** Starting modal MediaPanel ***');
|
||||||
console.log('[ProductVideo] productInfo:', JSON.stringify(productInfo, null, 2));
|
console.log('[ProductVideo] productInfo:', JSON.stringify(productInfo, null, 2));
|
||||||
// 처음 재생 시작 - modal=true로 시작
|
// 처음 재생 시작 - modal=true로 시작
|
||||||
|
setIsVideoPlaying(true); // 비디오 재생 flag 설정
|
||||||
|
if (onVideoPlaying) {
|
||||||
|
onVideoPlaying(); // 부모 컴포넌트에 알림
|
||||||
|
}
|
||||||
dispatch(
|
dispatch(
|
||||||
startMediaPlayer({
|
startMediaPlayer({
|
||||||
qrCurrentItem: productInfo,
|
qrCurrentItem: productInfo,
|
||||||
|
|||||||
@@ -67,16 +67,7 @@ import * as Config from '../../utils/Config';
|
|||||||
import { ACTIVE_POPUP, panel_names } from '../../utils/Config';
|
import { ACTIVE_POPUP, panel_names } from '../../utils/Config';
|
||||||
import { $L, formatGMTString } from '../../utils/helperMethods';
|
import { $L, formatGMTString } from '../../utils/helperMethods';
|
||||||
import { SpotlightIds } from '../../utils/SpotlightIds';
|
import { SpotlightIds } from '../../utils/SpotlightIds';
|
||||||
import { removeDotAndColon } from '../PlayerPanel/PlayerItemCard/PlayerItemCard';
|
|
||||||
import PlayerOverlayChat from '../PlayerPanel/PlayerOverlay/PlayerOverlayChat';
|
|
||||||
import PlayerOverlayQRCode from '../PlayerPanel/PlayerOverlay/PlayerOverlayQRCode';
|
|
||||||
import css from './MediaPanel.v3.module.less';
|
import css from './MediaPanel.v3.module.less';
|
||||||
import PlayerTabButton from '../PlayerPanel/PlayerTabContents/TabButton/PlayerTabButton';
|
|
||||||
import TabContainer from '../PlayerPanel/PlayerTabContents/TabContainer';
|
|
||||||
import TabContainerV2 from '../PlayerPanel/PlayerTabContents/v2/TabContainer.v2';
|
|
||||||
// import LiveShowContainer from './PlayerTabContents/v2/LiveShowContainer';
|
|
||||||
// import ShopNowContainer from './PlayerTabContents/v2/ShopNowContainer';
|
|
||||||
// import ShopNowButton from './PlayerTabContents/v2/ShopNowButton';
|
|
||||||
|
|
||||||
const Container = SpotlightContainerDecorator(
|
const Container = SpotlightContainerDecorator(
|
||||||
{ enterTo: 'default-element', preserveld: true },
|
{ enterTo: 'default-element', preserveld: true },
|
||||||
@@ -168,12 +159,6 @@ const YOUTUBECONFIG = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const INITIAL_TIMEOUT = 30000;
|
|
||||||
const REGULAR_TIMEOUT = 30000;
|
|
||||||
const TAB_CONTAINER_SPOTLIGHT_ID = 'tab-container-spotlight-id';
|
|
||||||
const TAB_CONTAINER_V2_SPOTLIGHT_ID = 'tab-container-v2-spotlight-id';
|
|
||||||
const TARGET_EVENTS = ['mousemove', 'keydown', 'click'];
|
|
||||||
|
|
||||||
// last time error
|
// last time error
|
||||||
const VIDEO_END_ACTION_DELAY = 1500;
|
const VIDEO_END_ACTION_DELAY = 1500;
|
||||||
|
|
||||||
@@ -236,8 +221,6 @@ const MediaPanel = React.forwardRef(
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
const [prevChannelIndex, setPrevChannelIndex] = USE_STATE('prevChannelIndex', 0);
|
const [prevChannelIndex, setPrevChannelIndex] = USE_STATE('prevChannelIndex', 0);
|
||||||
const [sideContentsVisible, setSideContentsVisible] = USE_STATE('sideContentsVisible', true);
|
|
||||||
const [belowContentsVisible, setBelowContentsVisible] = USE_STATE('belowContentsVisible', true);
|
|
||||||
const [currentTime, setCurrentTime] = USE_STATE('currentTime', 0);
|
const [currentTime, setCurrentTime] = USE_STATE('currentTime', 0);
|
||||||
const [isInitialFocusOccurred, setIsInitialFocusOccurred] = USE_STATE(
|
const [isInitialFocusOccurred, setIsInitialFocusOccurred] = USE_STATE(
|
||||||
'isInitialFocusOccurred',
|
'isInitialFocusOccurred',
|
||||||
@@ -261,8 +244,6 @@ const MediaPanel = React.forwardRef(
|
|||||||
isDetailMediaReady: false,
|
isDetailMediaReady: false,
|
||||||
});
|
});
|
||||||
const [isVODPaused, setIsVODPaused] = USE_STATE('isVODPaused', false);
|
const [isVODPaused, setIsVODPaused] = USE_STATE('isVODPaused', false);
|
||||||
const [tabIndexV2, setTabIndexV2] = USE_STATE('tabIndexV2', 1); // 0: ShopNow, 1: LiveChannel, 2: ShopNowButton
|
|
||||||
const [tabContainerVersion, setTabContainerVersion] = USE_STATE('tabContainerVersion', 2); // 1: TabContainer (우측), 2: TabContainerV2 (하단)
|
|
||||||
|
|
||||||
const panels = USE_SELECTOR('panels', (state) => state.panels.panels);
|
const panels = USE_SELECTOR('panels', (state) => state.panels.panels);
|
||||||
const chatData = USE_SELECTOR('chatData', (state) => state.play.chatData);
|
const chatData = USE_SELECTOR('chatData', (state) => state.play.chatData);
|
||||||
@@ -890,30 +871,13 @@ const MediaPanel = React.forwardRef(
|
|||||||
const handleItemFocus = useCallback(
|
const handleItemFocus = useCallback(
|
||||||
(menu) => {
|
(menu) => {
|
||||||
dispatch(sendLogGNB(menu));
|
dispatch(sendLogGNB(menu));
|
||||||
|
|
||||||
if (!videoVerticalVisible) {
|
|
||||||
resetTimer(REGULAR_TIMEOUT);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[dispatch, resetTimer, videoVerticalVisible]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onClickBack = useCallback(
|
const onClickBack = useCallback(
|
||||||
(ev, isEnd) => {
|
(ev, isEnd) => {
|
||||||
//modal로부터 Full 전환된 경우 다시 preview 모드로 돌아감.
|
//modal로부터 Full 전환된 경우 다시 preview 모드로 돌아감.
|
||||||
|
|
||||||
// TabContainer(v1)만: Side Contents가 보이는 경우 먼저 숨기고 return
|
|
||||||
if (
|
|
||||||
tabContainerVersion === 1 &&
|
|
||||||
sideContentsVisible &&
|
|
||||||
!videoVerticalVisible &&
|
|
||||||
panelInfo.shptmBanrTpNm !== 'MEDIA'
|
|
||||||
) {
|
|
||||||
setSideContentsVisible(false);
|
|
||||||
ev?.stopPropagation();
|
|
||||||
// ev?.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (panelInfo.modalContainerId && !panelInfo.modal) {
|
if (panelInfo.modalContainerId && !panelInfo.modal) {
|
||||||
dispatch(
|
dispatch(
|
||||||
startMediaPlayer({
|
startMediaPlayer({
|
||||||
@@ -954,16 +918,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[dispatch, panelInfo, videoPlayer, videoVerticalVisible, backupInitialIndex, panels]
|
||||||
dispatch,
|
|
||||||
panelInfo,
|
|
||||||
videoPlayer,
|
|
||||||
sideContentsVisible,
|
|
||||||
videoVerticalVisible,
|
|
||||||
backupInitialIndex,
|
|
||||||
panels,
|
|
||||||
tabContainerVersion,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1043,11 +998,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!panelInfo.modal && !videoVerticalVisible && !hasProperSpot) {
|
if (!panelInfo.modal && !videoVerticalVisible && !hasProperSpot) {
|
||||||
if (tabContainerVersion === 1) {
|
Spotlight.focus('below-tab-live-channel-button');
|
||||||
Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON);
|
|
||||||
} else if (tabContainerVersion === 2) {
|
|
||||||
Spotlight.focus('below-tab-live-channel-button');
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//비디오 진입시 포커스
|
//비디오 진입시 포커스
|
||||||
@@ -1063,7 +1014,6 @@ const MediaPanel = React.forwardRef(
|
|||||||
panelInfo.isUpdatedByClick,
|
panelInfo.isUpdatedByClick,
|
||||||
panelInfo.isIndicatorByClick,
|
panelInfo.isIndicatorByClick,
|
||||||
panelInfo.shptmBanrTpNm,
|
panelInfo.shptmBanrTpNm,
|
||||||
tabContainerVersion,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 최상단 패널 정보 (여러 useMemo에서 공통으로 사용)
|
// 최상단 패널 정보 (여러 useMemo에서 공통으로 사용)
|
||||||
@@ -1326,7 +1276,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
if (playListInfo && playListInfo.length > 0) {
|
if (playListInfo && playListInfo.length > 0) {
|
||||||
videoInitialFocused();
|
videoInitialFocused();
|
||||||
}
|
}
|
||||||
}, [sideContentsVisible, panelInfo.modal]);
|
}, [panelInfo.modal]);
|
||||||
|
|
||||||
// liveChannel initial selectedIndex
|
// liveChannel initial selectedIndex
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -1796,11 +1746,8 @@ const MediaPanel = React.forwardRef(
|
|||||||
}, [currentSubtitleBlob, isSubtitleActive]);
|
}, [currentSubtitleBlob, isSubtitleActive]);
|
||||||
|
|
||||||
const currentSideButtonStatus = useMemo(() => {
|
const currentSideButtonStatus = useMemo(() => {
|
||||||
if (panelInfo?.shptmBanrTpNm !== 'MEDIA' && !panelInfo?.modal && sideContentsVisible) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}, [panelInfo, sideContentsVisible]);
|
}, []);
|
||||||
|
|
||||||
const videoType = useMemo(() => {
|
const videoType = useMemo(() => {
|
||||||
if (currentPlayingUrl) {
|
if (currentPlayingUrl) {
|
||||||
@@ -1920,11 +1867,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sideContentsVisible) {
|
}, [dispatch, playListInfo, selectedIndex, initialEnter]);
|
||||||
setPrevChannelIndex(selectedIndex);
|
|
||||||
}
|
|
||||||
setSideContentsVisible(true);
|
|
||||||
}, [dispatch, playListInfo, selectedIndex, sideContentsVisible, initialEnter]);
|
|
||||||
|
|
||||||
const handleIndicatorUpClick = useCallback(() => {
|
const handleIndicatorUpClick = useCallback(() => {
|
||||||
if (!initialEnter) {
|
if (!initialEnter) {
|
||||||
@@ -1967,11 +1910,7 @@ const MediaPanel = React.forwardRef(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sideContentsVisible) {
|
}, [dispatch, playListInfo, selectedIndex, initialEnter]);
|
||||||
setPrevChannelIndex(selectedIndex);
|
|
||||||
}
|
|
||||||
setSideContentsVisible(true);
|
|
||||||
}, [dispatch, playListInfo, selectedIndex, sideContentsVisible, initialEnter]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (panelInfo.shptmBanrTpNm === 'VOD' && panelInfo.patnrId && panelInfo.showId) {
|
if (panelInfo.shptmBanrTpNm === 'VOD' && panelInfo.patnrId && panelInfo.showId) {
|
||||||
@@ -2041,29 +1980,6 @@ const MediaPanel = React.forwardRef(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const [initialEnter, setInitialEnter] = USE_STATE('initialEnter', true);
|
const [initialEnter, setInitialEnter] = USE_STATE('initialEnter', true);
|
||||||
const [initialEnterV2, setInitialEnterV2] = USE_STATE('initialEnterV2', true);
|
|
||||||
const timerId = useRef(null);
|
|
||||||
const timerIdV2 = useRef(null);
|
|
||||||
|
|
||||||
const showSideContents = useMemo(() => {
|
|
||||||
return (
|
|
||||||
sideContentsVisible &&
|
|
||||||
playListInfo &&
|
|
||||||
panelInfo?.shptmBanrTpNm !== 'MEDIA' &&
|
|
||||||
!panelInfo?.modal &&
|
|
||||||
isOnTop
|
|
||||||
);
|
|
||||||
}, [sideContentsVisible, playListInfo, panelInfo, isOnTop]);
|
|
||||||
|
|
||||||
const showBelowContents = useMemo(() => {
|
|
||||||
return (
|
|
||||||
belowContentsVisible &&
|
|
||||||
playListInfo &&
|
|
||||||
panelInfo?.shptmBanrTpNm !== 'MEDIA' &&
|
|
||||||
!panelInfo?.modal &&
|
|
||||||
isOnTop
|
|
||||||
);
|
|
||||||
}, [belowContentsVisible, playListInfo, panelInfo, isOnTop]);
|
|
||||||
|
|
||||||
const qrCurrentItem = useMemo(() => {
|
const qrCurrentItem = useMemo(() => {
|
||||||
if (shopNowInfo?.length && panelInfo?.shptmBanrTpNm === 'LIVE') {
|
if (shopNowInfo?.length && panelInfo?.shptmBanrTpNm === 'LIVE') {
|
||||||
@@ -2096,61 +2012,11 @@ const MediaPanel = React.forwardRef(
|
|||||||
|
|
||||||
return panelInfo.shptmBanrTpNm;
|
return panelInfo.shptmBanrTpNm;
|
||||||
}, [panelInfo.shptmBanrTpNm, playListInfo, selectedIndex]);
|
}, [panelInfo.shptmBanrTpNm, playListInfo, selectedIndex]);
|
||||||
const clearTimer = useCallback(() => {
|
|
||||||
clearTimeout(timerId.current);
|
|
||||||
timerId.current = null;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const resetTimer = useCallback(
|
|
||||||
(timeout) => {
|
|
||||||
if (timerId.current) {
|
|
||||||
clearTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialEnter) {
|
|
||||||
setInitialEnter(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
timerId.current = setTimeout(() => {
|
|
||||||
setSideContentsVisible(false);
|
|
||||||
// setBelowContentsVisible(false);
|
|
||||||
}, timeout);
|
|
||||||
},
|
|
||||||
[clearTimer, initialEnter, setInitialEnter, setSideContentsVisible]
|
|
||||||
);
|
|
||||||
|
|
||||||
const clearTimerV2 = useCallback(() => {
|
|
||||||
clearTimeout(timerIdV2.current);
|
|
||||||
timerIdV2.current = null;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const resetTimerV2 = useCallback(
|
|
||||||
(timeout) => {
|
|
||||||
// console.log('[TabContainerV2] resetTimerV2 호출', timeout);
|
|
||||||
if (timerIdV2.current) {
|
|
||||||
// console.log('[TabContainerV2] 기존 타이머 클리어');
|
|
||||||
clearTimerV2();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initialEnterV2) {
|
|
||||||
// console.log('[TabContainerV2] initialEnterV2 false로 변경');
|
|
||||||
setInitialEnterV2(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
timerIdV2.current = setTimeout(() => {
|
|
||||||
// console.log('[TabContainerV2] 타이머 실행 - belowContentsVisible false로 변경');
|
|
||||||
setBelowContentsVisible(false);
|
|
||||||
}, timeout);
|
|
||||||
},
|
|
||||||
[clearTimerV2, initialEnterV2, setInitialEnterV2, setBelowContentsVisible]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Redux로 오버레이 숨김
|
// Redux로 오버레이 숨김
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (shouldHideOverlays) {
|
if (shouldHideOverlays) {
|
||||||
console.log('[MediaPanel] shouldHideOverlays true - 오버레이 숨김');
|
console.log('[MediaPanel] shouldHideOverlays true - 오버레이 숨김');
|
||||||
setSideContentsVisible(false);
|
|
||||||
setBelowContentsVisible(false);
|
|
||||||
|
|
||||||
if (videoPlayer.current?.hideControls) {
|
if (videoPlayer.current?.hideControls) {
|
||||||
videoPlayer.current.hideControls();
|
videoPlayer.current.hideControls();
|
||||||
@@ -2164,8 +2030,6 @@ const MediaPanel = React.forwardRef(
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (shouldShowOverlays) {
|
if (shouldShowOverlays) {
|
||||||
console.log('[MediaPanel] shouldShowOverlays true - 오버레이 표시');
|
console.log('[MediaPanel] shouldShowOverlays true - 오버레이 표시');
|
||||||
setSideContentsVisible(true);
|
|
||||||
setBelowContentsVisible(true);
|
|
||||||
|
|
||||||
if (videoPlayer.current?.showControls) {
|
if (videoPlayer.current?.showControls) {
|
||||||
videoPlayer.current.showControls();
|
videoPlayer.current.showControls();
|
||||||
@@ -2175,16 +2039,6 @@ const MediaPanel = React.forwardRef(
|
|||||||
}
|
}
|
||||||
}, [shouldShowOverlays, dispatch]);
|
}, [shouldShowOverlays, dispatch]);
|
||||||
|
|
||||||
// MediaPanel이 최상단이 될 때 오버레이 표시 (DetailPanel에서 복귀)
|
|
||||||
useEffect(() => {
|
|
||||||
if (isOnTop && !panelInfo.modal && !videoVerticalVisible) {
|
|
||||||
console.log('[MediaPanel] isOnTop true - 오버레이 표시');
|
|
||||||
setSideContentsVisible(true);
|
|
||||||
setBelowContentsVisible(true);
|
|
||||||
// VideoPlayer가 belowContentsVisible prop을 감지해서 자동으로 controls 표시함
|
|
||||||
}
|
|
||||||
}, [isOnTop, panelInfo.modal, videoVerticalVisible]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (panelInfoRef.current?.modal && !panelInfo.modal && isOnTop && !videoVerticalVisible) {
|
if (panelInfoRef.current?.modal && !panelInfo.modal && isOnTop && !videoVerticalVisible) {
|
||||||
const focusTimer = setTimeout(() => {
|
const focusTimer = setTimeout(() => {
|
||||||
@@ -2197,104 +2051,6 @@ const MediaPanel = React.forwardRef(
|
|||||||
}
|
}
|
||||||
}, [panelInfo.modal, isOnTop, videoVerticalVisible]);
|
}, [panelInfo.modal, isOnTop, videoVerticalVisible]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// tabContainerVersion === 1일 때만 실행
|
|
||||||
if (tabContainerVersion !== 1) return;
|
|
||||||
|
|
||||||
const node = document.querySelector(`[data-spotlight-id=${TAB_CONTAINER_SPOTLIGHT_ID}]`);
|
|
||||||
|
|
||||||
if (!showSideContents || !node || videoVerticalVisible) return;
|
|
||||||
|
|
||||||
// NOTE 첫 진입 시에는 10초 후 탭이 닫히도록 설정
|
|
||||||
if (initialEnter) {
|
|
||||||
resetTimer(INITIAL_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleEvent = () => resetTimer(REGULAR_TIMEOUT);
|
|
||||||
TARGET_EVENTS.forEach((event) => node.addEventListener(event, handleEvent));
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
TARGET_EVENTS.forEach((event) => node.removeEventListener(event, handleEvent));
|
|
||||||
|
|
||||||
if (timerId.current) {
|
|
||||||
clearTimer();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [
|
|
||||||
showSideContents,
|
|
||||||
videoVerticalVisible,
|
|
||||||
tabContainerVersion,
|
|
||||||
resetTimer,
|
|
||||||
initialEnter,
|
|
||||||
clearTimer,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (initialEnter || !sideContentsVisible || videoVerticalVisible) return;
|
|
||||||
|
|
||||||
// NOTE button을 통해 탭을 연 경우 5초 후 탭이 닫히도록 설정
|
|
||||||
if (sideContentsVisible) {
|
|
||||||
resetTimer(REGULAR_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (timerId.current) {
|
|
||||||
clearTimer();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [sideContentsVisible]);
|
|
||||||
|
|
||||||
// TabContainerV2 자동 닫기
|
|
||||||
useEffect(() => {
|
|
||||||
// tabContainerVersion === 2일 때만 실행
|
|
||||||
if (tabContainerVersion !== 2) return;
|
|
||||||
|
|
||||||
// console.log('[TabContainerV2] useEffect 시작', {
|
|
||||||
// showBelowContents,
|
|
||||||
// videoVerticalVisible,
|
|
||||||
// initialEnterV2,
|
|
||||||
// });
|
|
||||||
|
|
||||||
const node = document.querySelector(`[data-spotlight-id=${TAB_CONTAINER_V2_SPOTLIGHT_ID}]`);
|
|
||||||
// console.log('[TabContainerV2] DOM node:', node);
|
|
||||||
|
|
||||||
if (!showBelowContents || !node || videoVerticalVisible) {
|
|
||||||
// console.log('[TabContainerV2] early return');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE 첫 진입 시에는 30초 후 탭이 닫히도록 설정
|
|
||||||
if (initialEnterV2) {
|
|
||||||
// console.log('[TabContainerV2] 첫 진입 - 타이머 시작', INITIAL_TIMEOUT);
|
|
||||||
resetTimerV2(INITIAL_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleEvent = (e) => {
|
|
||||||
// console.log('[TabContainerV2] 이벤트 발생:', e.type);
|
|
||||||
resetTimerV2(REGULAR_TIMEOUT);
|
|
||||||
};
|
|
||||||
TARGET_EVENTS.forEach((event) => {
|
|
||||||
// console.log('[TabContainerV2] 이벤트 리스너 등록:', event);
|
|
||||||
node.addEventListener(event, handleEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// console.log('[TabContainerV2] cleanup');
|
|
||||||
TARGET_EVENTS.forEach((event) => node.removeEventListener(event, handleEvent));
|
|
||||||
|
|
||||||
if (timerIdV2.current) {
|
|
||||||
clearTimerV2();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [
|
|
||||||
showBelowContents,
|
|
||||||
videoVerticalVisible,
|
|
||||||
tabContainerVersion,
|
|
||||||
resetTimerV2,
|
|
||||||
initialEnterV2,
|
|
||||||
clearTimerV2,
|
|
||||||
]);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const videoContainer = document.querySelector(`.${css.videoContainer}`);
|
const videoContainer = document.querySelector(`.${css.videoContainer}`);
|
||||||
|
|
||||||
@@ -2466,16 +2222,10 @@ const MediaPanel = React.forwardRef(
|
|||||||
selectedIndex={selectedIndex}
|
selectedIndex={selectedIndex}
|
||||||
qrCurrentItem={qrCurrentItem}
|
qrCurrentItem={qrCurrentItem}
|
||||||
setIsSubtitleActive={setIsSubtitleActive}
|
setIsSubtitleActive={setIsSubtitleActive}
|
||||||
setSideContentsVisible={setSideContentsVisible}
|
|
||||||
sideContentsVisible={sideContentsVisible}
|
|
||||||
setBelowContentsVisible={setBelowContentsVisible}
|
|
||||||
belowContentsVisible={belowContentsVisible}
|
|
||||||
videoVerticalVisible={videoVerticalVisible}
|
videoVerticalVisible={videoVerticalVisible}
|
||||||
setCurrentTime={setCurrentTime}
|
setCurrentTime={setCurrentTime}
|
||||||
setIsVODPaused={setIsVODPaused}
|
setIsVODPaused={setIsVODPaused}
|
||||||
broadcast={broadcast}
|
broadcast={broadcast}
|
||||||
tabContainerVersion={tabContainerVersion}
|
|
||||||
tabIndexV2={tabIndexV2}
|
|
||||||
dispatch={dispatch}
|
dispatch={dispatch}
|
||||||
>
|
>
|
||||||
{typeof window === 'object' && window.PalmSystem && (
|
{typeof window === 'object' && window.PalmSystem && (
|
||||||
@@ -2501,91 +2251,6 @@ const MediaPanel = React.forwardRef(
|
|||||||
QRCodeUrl={playListInfo[selectedIndex]?.chatUrl}
|
QRCodeUrl={playListInfo[selectedIndex]?.chatUrl}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{tabContainerVersion === 1 &&
|
|
||||||
currentSideButtonStatus &&
|
|
||||||
!videoVerticalVisible &&
|
|
||||||
playListInfo && (
|
|
||||||
<PlayerTabButton
|
|
||||||
setSideContentsVisible={setSideContentsVisible}
|
|
||||||
sideContentsVisible={sideContentsVisible}
|
|
||||||
videoType={isShowType}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{tabContainerVersion === 1 && showSideContents && (
|
|
||||||
<TabContainer
|
|
||||||
spotlightId={TAB_CONTAINER_SPOTLIGHT_ID}
|
|
||||||
panelInfo={panelInfo}
|
|
||||||
shopNowInfo={shopNowInfo}
|
|
||||||
playListInfo={playListInfo}
|
|
||||||
selectedIndex={selectedIndex}
|
|
||||||
setSelectedIndex={setSelectedIndex}
|
|
||||||
liveChannelInfos={liveChannelInfos || liveShowInfos}
|
|
||||||
videoVerticalVisible={videoVerticalVisible}
|
|
||||||
handleItemFocus={handleItemFocus}
|
|
||||||
prevChannelIndex={prevChannelIndex}
|
|
||||||
currentTime={currentTime}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* {shouldShowBelowTab && (
|
|
||||||
<>
|
|
||||||
{belowTabMode === 'liveShow' && (
|
|
||||||
<LiveShowContainer
|
|
||||||
panelInfo={panelInfo}
|
|
||||||
liveInfos={playListInfo}
|
|
||||||
currentTime={currentTime}
|
|
||||||
setSelectedIndex={setSelectedIndex}
|
|
||||||
videoVerticalVisible={videoVerticalVisible}
|
|
||||||
currentVideoShowId={playListInfo && playListInfo[selectedIndex]?.showId}
|
|
||||||
handleItemFocus={handleItemFocus}
|
|
||||||
onLiveChannelButtonClick={() => setBelowTabMode('shopNowButton')}
|
|
||||||
tabTitle={[
|
|
||||||
$L('SHOP NOW'),
|
|
||||||
panelInfo?.shptmBanrTpNm === 'LIVE' ? $L('LIVE CHANNEL') : $L('FEATURED SHOWS'),
|
|
||||||
]}
|
|
||||||
selectedIndex={selectedIndex}
|
|
||||||
tabIndex={1}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{belowTabMode === 'shopNowButton' && (
|
|
||||||
<ShopNowButton onClick={() => setBelowTabMode('shopNow')} />
|
|
||||||
)}
|
|
||||||
{belowTabMode === 'shopNow' && (
|
|
||||||
<ShopNowContainer
|
|
||||||
panelInfo={panelInfo}
|
|
||||||
liveInfos={playListInfo}
|
|
||||||
currentTime={currentTime}
|
|
||||||
setSelectedIndex={setSelectedIndex}
|
|
||||||
videoVerticalVisible={videoVerticalVisible}
|
|
||||||
currentVideoShowId={playListInfo && playListInfo[selectedIndex]?.showId}
|
|
||||||
handleItemFocus={handleItemFocus}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)} */}
|
|
||||||
|
|
||||||
{tabContainerVersion === 2 && showBelowContents && (
|
|
||||||
<TabContainerV2
|
|
||||||
panelInfo={panelInfo}
|
|
||||||
playListInfo={playListInfo}
|
|
||||||
shopNowInfo={shopNowInfo}
|
|
||||||
selectedIndex={selectedIndex}
|
|
||||||
setSelectedIndex={setSelectedIndex}
|
|
||||||
liveChannelInfos={liveChannelInfos || liveShowInfos}
|
|
||||||
videoVerticalVisible={videoVerticalVisible}
|
|
||||||
handleItemFocus={handleItemFocus}
|
|
||||||
prevChannelIndex={prevChannelIndex}
|
|
||||||
currentTime={currentTime}
|
|
||||||
spotlightId={TAB_CONTAINER_V2_SPOTLIGHT_ID}
|
|
||||||
tabIndex={tabIndexV2}
|
|
||||||
onShopNowButtonClick={() => setTabIndexV2(0)}
|
|
||||||
onLiveChannelButtonClick={() => setTabIndexV2(2)}
|
|
||||||
onTabClose={(newTabIndex) => setTabIndexV2(newTabIndex)}
|
|
||||||
tabVisible={belowContentsVisible}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
{activePopup === ACTIVE_POPUP.alertPopup && (
|
{activePopup === ACTIVE_POPUP.alertPopup && (
|
||||||
|
|||||||
Reference in New Issue
Block a user