From b17aa89c286f0be740e13f5bc5d358215ad13c49 Mon Sep 17 00:00:00 2001 From: optrader Date: Wed, 12 Nov 2025 17:35:24 +0900 Subject: [PATCH] [251112] feat: ProductVideoV2 fullScreen ovelay toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ• 컀밋 μ‹œκ°„: 2025. 11. 12. 17:35:22 πŸ“Š λ³€κ²½ 톡계: β€’ 총 파일: 2개 β€’ μΆ”κ°€: +57쀄 β€’ μ‚­μ œ: -28쀄 πŸ“ μˆ˜μ •λœ 파일: ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx πŸ”§ μ£Όμš” λ³€κ²½ λ‚΄μš©: β€’ UI μ»΄ν¬λ„ŒνŠΈ μ•„ν‚€ν…μ²˜ κ°œμ„  β€’ μ†Œκ·œλͺ¨ κΈ°λŠ₯ κ°œμ„  --- .../components/VideoPlayer/MediaPlayer.jsx | 30 +++-- .../ProductVideo/ProductVideo.v2.jsx | 119 +++++++++++------- 2 files changed, 97 insertions(+), 52 deletions(-) diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx index 834deef1..0213c02c 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx @@ -65,7 +65,7 @@ const isEnter = is('enter'); const isLeft = is('left'); const isRight = is('right'); -const jumpBackKeyCode = 3 +const jumpBackKeyCode = 3; const jumpForwardKeyCode = 39; const controlsHandleAboveSelectionKeys = [13, 16777221, jumpBackKeyCode, jumpForwardKeyCode]; const getControlsHandleAboveHoldConfig = ({ frequency, time }) => ({ @@ -706,6 +706,7 @@ const VideoPlayerBase = class extends React.Component { reactPlayerConfig: PropTypes.any, //for ReactPlayer qrCurrentItem: PropTypes.any, modalScale: PropTypes.number, + notifyOnClickWhenNotModal: PropTypes.bool, }; static contextType = FloatingLayerContext; @@ -718,6 +719,7 @@ const VideoPlayerBase = class extends React.Component { jumpDelay: 200, mediaControlsComponent: MediaControls, miniFeedbackHideDelay: 2000, + notifyOnClickWhenNotModal: false, playbackRateHash: { fastForward: ['2', '4', '8', '16'], rewind: ['-2', '-4', '-8', '-16'], @@ -1429,7 +1431,13 @@ const VideoPlayerBase = class extends React.Component { } // 🎬 μ‹€μ‹œκ°„ μž¬μƒμƒνƒœ λ‘œκΉ… - if (ev.type === 'onUpdate' || ev.type === 'onPlay' || ev.type === 'onPause' || ev.type === 'onStart' || ev.type === 'onLoadStart') { + if ( + ev.type === 'onUpdate' || + ev.type === 'onPlay' || + ev.type === 'onPause' || + ev.type === 'onStart' || + ev.type === 'onLoadStart' + ) { console.log('🎬 [MediaPlayer] μž¬μƒμƒνƒœ μ‹€μ‹œκ°„ λ‘œκΉ…', { eventType: ev.type, currentTime: el.currentTime, @@ -1933,14 +1941,20 @@ const VideoPlayerBase = class extends React.Component { // // Player Interaction events // - onVideoClick = () => { + onVideoClick = (ev) => { console.log('[MediaPlayer] onVideoClick 호좜'); - // modal μƒνƒœμΌ λ•Œ μ™ΈλΆ€ onClick ν•Έλ“€λŸ¬κ°€ 있으면 호좜 - if (this.props.panelInfo?.modal && this.props.onClick) { - console.log('[MediaPlayer] modalμ—μ„œ onClick 호좜'); - this.props.onClick(); - return; + const shouldNotify = + (this.props.panelInfo?.modal || this.props.notifyOnClickWhenNotModal) && + typeof this.props.onClick === 'function'; + + if (shouldNotify) { + console.log('[MediaPlayer] μ™ΈλΆ€ onClick 콜백 호좜'); + this.props.onClick(ev); + + if (this.props.panelInfo?.modal && !this.props.notifyOnClickWhenNotModal) { + return; + } } // MediaPanelμ—μ„œλŠ” controls ν† κΈ€λ§Œ diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx index 8fe246c3..14e49893 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx @@ -86,6 +86,11 @@ export function ProductVideoV2({ const fullscreenContainerRef = useRef(null); const videoPortalHostRef = useRef(null); + const isFullscreenRef = useRef(isFullscreen); + useEffect(() => { + isFullscreenRef.current = isFullscreen; + }, [isFullscreen]); + const ensurePortalHost = useCallback(() => { if (!videoPortalHostRef.current && typeof document !== 'undefined') { const host = document.createElement('div'); @@ -373,9 +378,18 @@ export function ProductVideoV2({ // FullScreen λͺ¨λ“œμ—μ„œμ˜ MediaPlayer Click ν•Έλ“€λŸ¬ const handleVideoPlayerClick = useCallback( (e) => { + const fullscreenNow = isFullscreenRef.current; + + console.log('πŸŽ₯ [ProductVideoV2] handleVideoPlayerClick 감지됨', { + isPlaying, + isFullscreen: fullscreenNow, + eventType: e?.type, + target: e?.target?.className, + }); + if (!isPlaying) return; - if (!isFullscreen) { + if (!fullscreenNow) { e.preventDefault?.(); e.stopPropagation?.(); toggleFullscreen(); @@ -627,6 +641,8 @@ export function ProductVideoV2({ // VideoContainer의 λͺ¨λ“  클릭 κ°μ‹œ (HooksλŠ” early return 전에 μ •μ˜λ˜μ–΄μ•Ό 함) const handleVideoContainerClick = useCallback( (e) => { + if (isFullscreen) return; + console.log('πŸŽ₯ [ProductVideoV2] videoContainer onClick 감지됨', { isPlaying, isFullscreen, @@ -638,7 +654,7 @@ export function ProductVideoV2({ timestamp: new Date().getTime(), }); - if (isPlaying && !isFullscreen) { + if (isPlaying) { console.log('πŸŽ₯ [ProductVideoV2] videoContainer 클릭 β†’ 직접 전체화면 ν† κΈ€ μ‹€ν–‰', { direct: true, }); @@ -651,20 +667,22 @@ export function ProductVideoV2({ ); const containerProps = useMemo(() => { - const baseProps = { - onClick: handleVideoContainerClick, - }; - - if (isPlaying) { + if (isPlaying && !isFullscreen) { return { - ...baseProps, + onClick: handleVideoContainerClick, spotlightId: 'product-video-v2-playing', - onKeyDown: handleContainerKeyDown, // 일반 λͺ¨λ“œ: μ»¨ν…Œμ΄λ„ˆμ—μ„œ 직접 처리 - onSpotlightDown: handleSpotlightDown, // 일반 μž¬μƒμ—μ„œλ„ Down ν‚€ λ™μž‘ + onKeyDown: handleContainerKeyDown, + onSpotlightDown: handleSpotlightDown, }; - } else { - return baseProps; } + + if (!isFullscreen) { + return { + onClick: handleVideoContainerClick, + }; + } + + return {}; }, [ isFullscreen, isPlaying, @@ -676,6 +694,8 @@ export function ProductVideoV2({ // ⚠️ κ°„λ‹¨ν•œ ν•΄κ²°μ±…: λΉ„λ””μ˜€ μ˜μ—­ 클릭 μ‹œ 직접 λ™μž‘ μ‹€ν–‰ const handleContainerClickFallback = useCallback( (e) => { + if (isFullscreen) return; + const isThumbnailArea = e.target?.closest('[class*="videoThumbnail"]') || e.target?.closest('[class*="playButton"]'); @@ -683,14 +703,12 @@ export function ProductVideoV2({ const isVideoPlayerArea = e.target?.closest('[class*="videoPlayer"]') || e.target?.closest('[class*="VideoPlayer"]'); - // 썸넀일 클릭: λΉ„λ””μ˜€ μž¬μƒ μ‹œμž‘ if (isThumbnailArea && !isPlaying) { console.log('🎬 [handleContainerClickFallback] 썸넀일 클릭 β†’ λΉ„λ””μ˜€ μž¬μƒ μ‹œμž‘'); handleThumbnailClick(e); } - // λΉ„λ””μ˜€ μž¬μƒ 쀑 클릭: 전체화면 ν† κΈ€ - if (isVideoPlayerArea && isPlaying && !isFullscreen) { + if (isVideoPlayerArea && isPlaying) { console.log('🎬 [handleContainerClickFallback] λΉ„λ””μ˜€ 클릭 β†’ 전체화면 ν† κΈ€'); toggleFullscreen(); } @@ -705,6 +723,8 @@ export function ProductVideoV2({ // λΉ„λ””μ˜€ μ˜μ—­μΈμ§€ 확인 const isVideoArea = e.currentTarget === containerRef.current; + console.log('####[ProductVideoV2 Container] isFullscreen:', isFullscreen); + console.log('πŸ”“ [ProductVideoV2 Container] onMouseDownCapture - TScrollerDetail 차단 우회', { isVideoArea, target: e.target?.className, @@ -773,7 +793,7 @@ export function ProductVideoV2({ onTouchMove={handleUserActivity} onWheel={handleUserActivity} onClick={(e) => { - console.log('🎬 [videoPlayerWrapper] onClick 싀행됨', { + console.log('<<<<<<< [videoPlayerWrapper] onClick 싀행됨', { isFullscreen, isPlaying, eventType: e.type, @@ -813,6 +833,7 @@ export function ProductVideoV2({ onEnded={handleVideoEnded} onBackButton={handleBackButton} onClick={handleVideoPlayerClick} + notifyOnClickWhenNotModal noAutoPlay={false} noAutoShowMediaControls={!isFullscreen} autoCloseTimeout={5000} @@ -858,8 +879,8 @@ export function ProductVideoV2({ {...containerProps} ref={containerRef} className={`${css.videoContainer} ${isFullscreen ? css.hideWhileFullscreen : ''}`} - onMouseDownCapture={handleContainerMouseDownCapture} - onClick={handleContainerClickFallback} + onMouseDownCapture={!isFullscreen ? handleContainerMouseDownCapture : undefined} + onClick={!isFullscreen ? handleContainerClickFallback : undefined} > {!isPlaying ? ( // 썸넀일 + μž¬μƒ λ²„νŠΌ ν‘œμ‹œ @@ -892,34 +913,44 @@ export function ProductVideoV2({
{ - console.log('🎬 [normalContainerRef] onClick 싀행됨', { - isPlaying, - isFullscreen, - eventType: e.type, - target: e.target?.className, - }); - handleVideoPlayerClick(e); - }} - onMouseDownCapture={(e) => { - const isVideoPlayerArea = - e.target?.closest('[class*="videoPlayer"]') || - e.target?.closest('[class*="VideoPlayer"]'); + onClick={ + !isFullscreen + ? (e) => { + console.log('🎬 [normalContainerRef] onClick 싀행됨', { + isPlaying, + isFullscreen, + eventType: e.type, + target: e.target?.className, + }); + handleVideoPlayerClick(e); + } + : undefined + } + onMouseDownCapture={ + !isFullscreen + ? (e) => { + const isVideoPlayerArea = + e.target?.closest('[class*="videoPlayer"]') || + e.target?.closest('[class*="VideoPlayer"]'); - console.log('🎬 [normalContainerRef] onMouseDownCapture 싀행됨', { - isPlaying, - isFullscreen, - isVideoPlayerArea, - target: e.target?.className, - }); + console.log('🎬 [normalContainerRef] onMouseDownCapture 싀행됨', { + isPlaying, + isFullscreen, + isVideoPlayerArea, + target: e.target?.className, + }); - if (!isVideoPlayerArea) { - e.preventDefault(); - console.log('πŸ›‘ [normalContainerRef] preventDefault - 슀크둀 μ˜μ—­μ—μ„œμ˜ 클릭'); - } else { - console.log('βœ… [normalContainerRef] 이벀트 μ „νŒŒ ν—ˆμš© - VideoPlayer μ˜μ—­'); - } - }} + if (!isVideoPlayerArea) { + e.preventDefault(); + console.log( + 'πŸ›‘ [normalContainerRef] preventDefault - 슀크둀 μ˜μ—­μ—μ„œμ˜ 클릭' + ); + } else { + console.log('βœ… [normalContainerRef] 이벀트 μ „νŒŒ ν—ˆμš© - VideoPlayer μ˜μ—­'); + } + } + : undefined + } /> )}