From 743e250030c1b08524077b32e892a874e51e321c Mon Sep 17 00:00:00 2001 From: optrader Date: Wed, 12 Nov 2025 19:55:51 +0900 Subject: [PATCH] [251112] feat: ProductVideoV2,MediaPanel cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 11. 12. 19:55:49 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 5๊ฐœ โ€ข ์ถ”๊ฐ€: +205์ค„ โ€ข ์‚ญ์ œ: -114์ค„ ๐Ÿ“ ์ถ”๊ฐ€๋œ ํŒŒ์ผ: + com.twin.app.shoptime/DEBUG_MODE_IMPLEMENTATION.md + com.twin.app.shoptime/MEDIAPANEL_CLEANUP_IMPROVEMENTS.md ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx ~ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx ๐Ÿ”ง ํ•จ์ˆ˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ: ๐Ÿ“„ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx (javascript): โœ… Added: debugLog() ๐Ÿ“„ com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx (javascript): โœ… Added: debugLog() ๐Ÿ“„ com.twin.app.shoptime/DEBUG_MODE_IMPLEMENTATION.md (mdํŒŒ์ผ): โœ… Added: Before(), After() ๐Ÿ“„ com.twin.app.shoptime/MEDIAPANEL_CLEANUP_IMPROVEMENTS.md (mdํŒŒ์ผ): โœ… Added: useCallback(), showControls(), areControlsVisible(), toggleControls(), useLayoutEffect(), useEffect(), clearTimeout(), dispatch(), forEach(), getVideoNode(), addEventListener() ๐Ÿ”ง ์ฃผ์š” ๋ณ€๊ฒฝ ๋‚ด์šฉ: โ€ข UI ์ปดํฌ๋„ŒํŠธ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„  โ€ข ๊ฐœ๋ฐœ ๋ฌธ์„œ ๋ฐ ๊ฐ€์ด๋“œ ๊ฐœ์„  --- .../DEBUG_MODE_IMPLEMENTATION.md | 221 +++++++++ .../MEDIAPANEL_CLEANUP_IMPROVEMENTS.md | 430 ++++++++++++++++++ .../components/VideoPlayer/MediaPlayer.jsx | 1 + .../ProductVideo/ProductVideo.v2.jsx | 124 ++--- .../src/views/MediaPanel/MediaPanel.jsx | 246 ++++++---- 5 files changed, 882 insertions(+), 140 deletions(-) create mode 100644 com.twin.app.shoptime/DEBUG_MODE_IMPLEMENTATION.md create mode 100644 com.twin.app.shoptime/MEDIAPANEL_CLEANUP_IMPROVEMENTS.md diff --git a/com.twin.app.shoptime/DEBUG_MODE_IMPLEMENTATION.md b/com.twin.app.shoptime/DEBUG_MODE_IMPLEMENTATION.md new file mode 100644 index 00000000..8507e85a --- /dev/null +++ b/com.twin.app.shoptime/DEBUG_MODE_IMPLEMENTATION.md @@ -0,0 +1,221 @@ +# DEBUG_MODE ์กฐ๊ฑด๋ถ€ ๋กœ๊น… ๊ตฌํ˜„ ์™„๋ฃŒ + +**์ž‘์—… ์ผ์‹œ**: 2025-11-12 +**์ž‘์—… ๋ฒ”์œ„**: ProductVideo.v2.jsx, MediaPanel.jsx + +--- + +## ๐Ÿ“‹ ์ž‘์—… ๊ฐœ์š” + +ProductVideo.v2.jsx์™€ MediaPanel.jsx์˜ ๋ชจ๋“  ๋กœ๊ทธ ์ถœ๋ ฅ์„ `DEBUG_MODE = true/false` ํ”Œ๋ž˜๊ทธ๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. + +--- + +## โœ… ๊ตฌํ˜„ ๋‚ด์šฉ + +### 1. DEBUG_MODE ์„ค์ • + +๊ฐ ํŒŒ์ผ์˜ ์ตœ์ƒ๋‹จ์— DEBUG_MODE ์ƒ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค: + +```javascript +// โœ… DEBUG ๋ชจ๋“œ ์„ค์ • +const DEBUG_MODE = true; // false๋กœ ์„ค์ •ํ•˜๋ฉด ๋ชจ๋“  ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” +``` + +**์„ค์ • ๋ณ€๊ฒฝ ๋ฐฉ๋ฒ•:** +- ํ”„๋กœ๋•์…˜: `const DEBUG_MODE = false;` ๋กœ ๋ณ€๊ฒฝ +- ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ: `const DEBUG_MODE = true;` ์œ ์ง€ + +### 2. debugLog ํ—ฌํผ ํ•จ์ˆ˜ + +DEBUG_MODE๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” ๋ž˜ํผ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค: + +```javascript +// โœ… DEBUG_MODE ๊ธฐ๋ฐ˜ console ๋ž˜ํผ +const debugLog = (...args) => { + if (DEBUG_MODE) { + console.log(...args); + } +}; +``` + +**ํŠน์ง•:** +- `console.log(...)` ๋Œ€์‹  `debugLog(...)` ์‚ฌ์šฉ +- DEBUG_MODE๊ฐ€ false์ด๋ฉด ๋กœ๊ทธ ์ถœ๋ ฅ ์•ˆ ๋จ +- ์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ ๊ฑฐ์˜ ์—†์Œ (์กฐ๊ฑด ์ฒดํฌ๋งŒ ์ˆ˜ํ–‰) + +### 3. console ๋ฉ”์„œ๋“œ๋ณ„ ์ฒ˜๋ฆฌ + +| ๋ฉ”์„œ๋“œ | ์ฒ˜๋ฆฌ ๋ฐฉ์‹ | ํŒŒ์ผ | +|--------|----------|------| +| `console.log()` | `debugLog()` ๋กœ ๋ณ€๊ฒฝ | ProductVideo.v2.jsx, MediaPanel.jsx | +| `console.warn()` | `if (DEBUG_MODE) console.warn()` | ProductVideo.v2.jsx, MediaPanel.jsx | +| `console.error()` | `if (DEBUG_MODE) console.error()` | ProductVideo.v2.jsx | + +--- + +## ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„ + +### ProductVideo.v2.jsx +``` +- console.log() โ†’ debugLog(): ์•ฝ 40+ ๊ฐœ +- console.warn() โ†’ if (DEBUG_MODE) console.warn(): 2๊ฐœ +- console.error() โ†’ if (DEBUG_MODE) console.error(): 1๊ฐœ +``` + +### MediaPanel.jsx +``` +- console.log() โ†’ debugLog(): ์•ฝ 10+ ๊ฐœ +- console.warn() โ†’ if (DEBUG_MODE) console.warn(): 1๊ฐœ +``` + +--- + +## ๐ŸŽฏ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• + +### DEBUG ๋กœ๊ทธ ํ™œ์„ฑํ™” (๊ฐœ๋ฐœ ๋ชจ๋“œ) +```javascript +const DEBUG_MODE = true; // โœ… ๋ชจ๋“  ๋กœ๊ทธ ์ถœ๋ ฅ๋จ +``` + +### DEBUG ๋กœ๊ทธ ๋น„ํ™œ์„ฑํ™” (ํ”„๋กœ๋•์…˜) +```javascript +const DEBUG_MODE = false; // โŒ ๋ชจ๋“  ๋กœ๊ทธ ์ˆจ๊น€ +``` + +### ํ•œ ์ค„ ๋ณ€๊ฒฝ์œผ๋กœ ์ „์ฒด ๋กœ๊น… ์ œ์–ด +๊ฐ ํŒŒ์ผ์˜ ๋‘ ๋ฒˆ์งธ ์ค„๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค: + +**ProductVideo.v2.jsx Line 36** +```javascript +const DEBUG_MODE = true; // ๋ณ€๊ฒฝ: true โ†” false +``` + +**MediaPanel.jsx Line 25** +```javascript +const DEBUG_MODE = true; // ๋ณ€๊ฒฝ: true โ†” false +``` + +--- + +## ๐Ÿ’ก ์žฅ์  + +1. **์„ฑ๋Šฅ ์ตœ์ ํ™”** + - ํ”„๋กœ๋•์…˜์—์„œ ๋กœ๊ทธ ์˜ค๋ฒ„ํ—ค๋“œ ์ œ๊ฑฐ + - ์กฐ๊ฑด ๊ฒ€์‚ฌ๋งŒ ์ˆ˜ํ–‰ (์ฝ˜์†” I/O ์—†์Œ) + +2. **๊ฐœ๋ฐœ ํŽธ์˜์„ฑ** + - ํ•œ ์ค„ ๋ณ€๊ฒฝ์œผ๋กœ ์ „์ฒด ๋กœ๊น… ์ œ์–ด + - ํŒŒ์ผ ์ˆ˜์ • ์—†์ด ENV ๋ณ€์ˆ˜๋กœ ์ œ์–ด ๊ฐ€๋Šฅ (ํ–ฅํ›„) + +3. **๋””๋ฒ„๊น… ์šฉ์ด** + - ํ•„์š”ํ•  ๋•Œ๋งŒ ๋กœ๊ทธ ํ™œ์„ฑํ™” + - ๋กœ๊ทธ ์–‘ ์ œ์–ด๋กœ ์ฝ˜์†” ์ง€์ €๋ถ„ํ•จ ๋ฐฉ์ง€ + +4. **์œ ์ง€๋ณด์ˆ˜ ํŽธํ•จ** + - ๊ธฐ์กด console ํ˜ธ์ถœ ๊ทธ๋Œ€๋กœ ์œ ์ง€ + - ๋กœ๊ทธ ์ฝ”๋“œ ์‚ญ์ œ ๋ถˆํ•„์š” + +--- + +## ๐Ÿ”ง ํ–ฅํ›„ ๊ฐœ์„  ์‚ฌํ•ญ + +### 1. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ธฐ๋ฐ˜ ์„ค์ • +```javascript +const DEBUG_MODE = process.env.REACT_APP_DEBUG === 'true'; +``` + +### 2. ์„ธ๋ถ€ ๋กœ๊ทธ ๋ ˆ๋ฒจ ๊ตฌ๋ถ„ +```javascript +const LOG_LEVEL = { + ERROR: 0, + WARN: 1, + INFO: 2, + DEBUG: 3, +}; + +const debugLog = (level, ...args) => { + if (LOG_LEVEL[level] <= getCurrentLogLevel()) { + console.log(...args); + } +}; +``` + +### 3. Redux DevTools ํ†ตํ•ฉ +```javascript +const debugLog = (...args) => { + if (DEBUG_MODE) { + console.log(...args); + // Redux DevTools ์— ์ถ”๊ฐ€ ์ •๋ณด ๊ธฐ๋ก + } +}; +``` + +--- + +## โœ… ๊ฒ€์ฆ ํ•ญ๋ชฉ + +- [x] ProductVideo.v2.jsx: ๋ชจ๋“  console.log โ†’ debugLog ๋ณ€๊ฒฝ +- [x] ProductVideo.v2.jsx: console.warn/error ์กฐ๊ฑด๋ถ€ ์ฒ˜๋ฆฌ +- [x] MediaPanel.jsx: ๋ชจ๋“  console.log โ†’ debugLog ๋ณ€๊ฒฝ +- [x] MediaPanel.jsx: console.warn ์กฐ๊ฑด๋ถ€ ์ฒ˜๋ฆฌ +- [x] debugLog ํ•จ์ˆ˜ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌํ˜„ (๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€) +- [x] DEBUG_MODE ์„ค์ • ๊ฐ€๋Šฅ + +--- + +## ๐Ÿš€ ๋‹ค์Œ ๋‹จ๊ณ„ + +1. **์‚ฌ์šฉ์ž ํ…Œ์ŠคํŠธ** + - DEBUG_MODE = true์ผ ๋•Œ ๋ชจ๋“  ๋กœ๊ทธ ์ •์ƒ ์ถœ๋ ฅ ํ™•์ธ + - DEBUG_MODE = false์ผ ๋•Œ ๋ชจ๋“  ๋กœ๊ทธ ์ˆจ๊ฒจ์ง€๋Š”์ง€ ํ™•์ธ + +2. **์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ** + - ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ์—์„œ ์„ฑ๋Šฅ ๊ฐœ์„  ํ™•์ธ + +3. **ENV ๋ณ€์ˆ˜ ์—ฐ๋™** + - `.env.development`, `.env.production` ์„ค์ • + - ๋นŒ๋“œ ์‹œ ์ž๋™์œผ๋กœ DEBUG_MODE ์„ค์ • + +--- + +## ๐Ÿ“ ์ฝ”๋“œ ์˜ˆ์‹œ + +### Before (์ˆ˜์ • ์ „) +```javascript +console.log('๐ŸŽฌ [handleThumbnailClick] ์ธ๋„ค์ผ ํด๋ฆญ๋จ', {...}); +console.warn('[ProductVideoV2] ๋น„๋””์˜ค ์ •์ง€ ์‹คํŒจ:', error); +console.error('๐Ÿ–ฅ๏ธ [toggleControls] ๋””์ŠคํŒจ์น˜ ์—๋Ÿฌ:', error); +``` + +### After (์ˆ˜์ • ํ›„) +```javascript +debugLog('๐ŸŽฌ [handleThumbnailClick] ์ธ๋„ค์ผ ํด๋ฆญ๋จ', {...}); +if (DEBUG_MODE) console.warn('[ProductVideoV2] ๋น„๋””์˜ค ์ •์ง€ ์‹คํŒจ:', error); +if (DEBUG_MODE) console.error('๐Ÿ–ฅ๏ธ [toggleControls] ๋””์ŠคํŒจ์น˜ ์—๋Ÿฌ:', error); +``` + +--- + +## ๐Ÿ“Œ ์ฃผ์˜์‚ฌํ•ญ + +1. **์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ๋กœ๊ทธ** + - ๊ธฐ์กด์˜ ์ฃผ์„ ์ฒ˜๋ฆฌ๋œ console.log๋Š” ์œ ์ง€๋จ + - ํ•„์š”์‹œ ๋‚˜์ค‘์— ์‚ญ์ œ ๊ฐ€๋Šฅ + +2. **debugLog ํ•จ์ˆ˜ ์œ„์น˜** + - ์ปดํฌ๋„ŒํŠธ ํ•จ์ˆ˜ ์™ธ๋ถ€์— ์„ ์–ธ๋จ + - ๋งค๋ฒˆ ์ƒˆ๋กœ ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ (์„ฑ๋Šฅ ์ตœ์ ํ™”) + +3. **ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ** + - ๋ฐฐํฌ ์ „์— DEBUG_MODE๋ฅผ false๋กœ ๋ฐ˜๋“œ์‹œ ๋ณ€๊ฒฝํ•  ๊ฒƒ + +--- + +## โœจ ๊ฒฐ๋ก  + +ProductVideo.v2.jsx์™€ MediaPanel.jsx์˜ ๋ชจ๋“  ๋กœ๊ทธ ์ถœ๋ ฅ์„ DEBUG_MODE ํ”Œ๋ž˜๊ทธ๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„์™„๋ฃŒ. +์ด๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ/ํ…Œ์ŠคํŠธ ์ค‘์—๋Š” ๋””๋ฒ„๊น… ์ •๋ณด๋ฅผ ์‰ฝ๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, +ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋กœ๊ทธ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +**์ž‘์—… ์ƒํƒœ**: โœ… ์™„๋ฃŒ diff --git a/com.twin.app.shoptime/MEDIAPANEL_CLEANUP_IMPROVEMENTS.md b/com.twin.app.shoptime/MEDIAPANEL_CLEANUP_IMPROVEMENTS.md new file mode 100644 index 00000000..64b75cc3 --- /dev/null +++ b/com.twin.app.shoptime/MEDIAPANEL_CLEANUP_IMPROVEMENTS.md @@ -0,0 +1,430 @@ +# MediaPanel.jsx ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€ ๋ฐ ํด๋ฆฐ์—… ๊ฐœ์„  + +**์ž‘์—… ์ผ์‹œ**: 2025-11-12 +**ํŒŒ์ผ**: MediaPanel.jsx +**์ƒํƒœ**: โœ… ์™„๋ฃŒ (์ฝ”๋“œ ์ˆ˜์ •๋งŒ, git/npm ๋ฏธ์‹คํ–‰) + +--- + +## ๐Ÿ“‹ ์ž‘์—… ๊ฐœ์š” + +MediaPanel.jsx์˜ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ  ์•ˆ์ „ํ•œ ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ๋ฅผ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐœ์„ ์‚ฌํ•ญ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค: + +- โœ… ์•ˆ์ „ํ•œ ๋น„๋””์˜ค ํ”Œ๋ ˆ์ด์–ด ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๋ž˜ํผ +- โœ… ๊ฐ•ํ™”๋œ ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ํด๋ฆฐ์—… +- โœ… DOM ์Šคํƒ€์ผ ์ดˆ๊ธฐํ™” ๋ฐ ์ •๋ฆฌ +- โœ… ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ•ํ™” +- โœ… ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ถ”์  ๋ฐ ์ •๋ฆฌ + +--- + +## ๐Ÿ”ง ์ฃผ์š” ๊ฐœ์„  ์‚ฌํ•ญ + +### 1. ์•ˆ์ „ํ•œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๋ž˜ํผ (safePlayerCall) + +**์œ„์น˜**: Line 107-117 + +```javascript +// โœ… ์•ˆ์ „ํ•œ ๋น„๋””์˜ค ํ”Œ๋ ˆ์ด์–ด ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ +const safePlayerCall = useCallback((methodName, ...args) => { + if (videoPlayer.current && typeof videoPlayer.current[methodName] === 'function') { + try { + return videoPlayer.current[methodName](...args); + } catch (err) { + if (DEBUG_MODE) console.warn(`[MediaPanel] ${methodName} ํ˜ธ์ถœ ์‹คํŒจ:`, err); + } + } + return null; +}, []); +``` + +**์žฅ์ :** +- null/undefined ์•ˆ์ „ ๊ฒ€์‚ฌ +- ๋ฉ”์„œ๋“œ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ +- ์—๋Ÿฌ ์ฒ˜๋ฆฌ ํ†ต์ผ +- ํŠธ๋ผ์ด-์บ์น˜๋กœ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ + +**์‚ฌ์šฉ ์˜ˆ:** +```javascript +safePlayerCall('play'); +safePlayerCall('toggleControls'); +const mediaState = safePlayerCall('getMediaState'); +``` + +### 2. ๋ ˆํผ๋Ÿฐ์Šค ์ถ”์  Ref ์ถ”๊ฐ€ + +**์œ„์น˜**: Line 64 + +```javascript +const mediaEventListenersRef = useRef([]); // โœ… ๋ฏธ๋””์–ด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ถ”์  +``` + +**๋ชฉ์ :** +- ๋“ฑ๋ก๋œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๊ด€๋ฆฌ +- ์–ธ๋งˆ์šดํŠธ ์‹œ ๋ชจ๋“  ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ ๊ฐ€๋Šฅ +- ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€ + +### 3. isOnTop ๋ณ€๊ฒฝ ์‹œ ์•ˆ์ „ํ•œ ์ œ์–ด + +**์œ„์น˜**: Line 178-188 + +**Before:** +```javascript +if (videoPlayer.current?.getMediaState()?.paused) { + videoPlayer.current.play(); +} +if (videoPlayer.current.areControlsVisible && !videoPlayer.current.areControlsVisible()) { + videoPlayer.current.showControls(); +} +``` + +**After:** +```javascript +// โœ… ์•ˆ์ „ํ•œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋กœ null/undefined ์ฒดํฌ +const mediaState = safePlayerCall('getMediaState'); +if (mediaState?.paused) { + safePlayerCall('play'); +} + +const isControlsHidden = videoPlayer.current.areControlsVisible && !videoPlayer.current.areControlsVisible(); +if (isControlsHidden) { + safePlayerCall('showControls'); +} +``` + +**๊ฐœ์„ ์ :** +- mediaState null ์ฒดํฌ ๊ฐ•ํ™” +- ๋ชจ๋“  ํ”Œ๋ ˆ์ด์–ด ํ˜ธ์ถœ์„ ์•ˆ์ „ํ•œ ๋ž˜ํผ๋กœ ํ†ต์ผ +- ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ผ๊ด€์„ฑ + +### 4. ๋น„๋””์˜ค ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ ๊ฐœ์„  + +**์œ„์น˜**: Line 199-208 + +**Before:** +```javascript +if (videoPlayer.current && typeof videoPlayer.current.toggleControls === 'function') { + videoPlayer.current.toggleControls(); +} +``` + +**After:** +```javascript +safePlayerCall('toggleControls'); +``` + +**๊ฐœ์„ ์ :** +- ์ฝ”๋“œ ๊ฐ„๊ฒฐ์„ฑ +- ์—๋Ÿฌ ์ฒ˜๋ฆฌ ํ†ต์ผ + +### 5. ๋’ค๋กœ๊ฐ€๊ธฐ ์‹œ ๋น„๋””์˜ค ์ •์ง€ + +**์œ„์น˜**: Line 212-213 + +```javascript +// โœ… ๋’ค๋กœ๊ฐ€๊ธฐ ์‹œ ๋น„๋””์˜ค ์ •์ง€ +safePlayerCall('pause'); +``` + +**ํšจ๊ณผ:** +- ํŒจ๋„ ๋‹ซ์„ ๋•Œ ๋น„๋””์˜ค ์ž๋™ ์ •์ง€ +- ๋ฉ”๋ชจ๋ฆฌ ์ •๋ฆฌ ์‹œ์ž‘ + +### 6. DOM ์Šคํƒ€์ผ ์„ค์ • ๋ฐ ์ •๋ฆฌ + +**์œ„์น˜**: Line 353-376 + +**Before:** +```javascript +useLayoutEffect(() => { + const videoContainer = document.querySelector(`.${css.videoContainer}`); + if (videoContainer && panelInfo.thumbnailUrl && !videoLoaded) { + videoContainer.style.background = `url(${panelInfo.thumbnailUrl}) center center / contain no-repeat`; + videoContainer.style.backgroundColor = 'black'; + } +}, [panelInfo.thumbnailUrl, videoLoaded]); +``` + +**After:** +```javascript +// โœ… useLayoutEffect: DOM ์Šคํƒ€์ผ ์„ค์ • (๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€) +useLayoutEffect(() => { + const videoContainer = document.querySelector(`.${css.videoContainer}`); + if (videoContainer && panelInfo.thumbnailUrl && !videoLoaded) { + try { + videoContainer.style.background = `url(${panelInfo.thumbnailUrl}) center center / contain no-repeat`; + videoContainer.style.backgroundColor = 'black'; + } catch (err) { + if (DEBUG_MODE) console.warn('[MediaPanel] ์ธ๋„ค์ผ ์Šคํƒ€์ผ ์„ค์ • ์‹คํŒจ:', err); + } + } + + // โœ… cleanup: ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ DOM ์Šคํƒ€์ผ ์ดˆ๊ธฐํ™” + return () => { + if (videoContainer) { + try { + videoContainer.style.background = ''; + videoContainer.style.backgroundColor = ''; + } catch (err) { + // ์Šคํƒ€์ผ ์ดˆ๊ธฐํ™” ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + } + }; +}, [panelInfo.thumbnailUrl, videoLoaded]); +``` + +**๊ฐœ์„ ์ :** +- ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์ถ”๊ฐ€ +- cleanup ํ•จ์ˆ˜๋กœ DOM ์Šคํƒ€์ผ ์ดˆ๊ธฐํ™” +- ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€ + +### 7. mediainfoHandler ๊ฐ•ํ™” + +**์œ„์น˜**: Line 280-326 + +**๊ฐœ์„  ์‚ฌํ•ญ:** +- safePlayerCall ์‚ฌ์šฉ์œผ๋กœ null ์•ˆ์ •์„ฑ +- hlsError ์ฒ˜๋ฆฌ ๊ฐ•ํ™” +- timeupdate ์ด๋ฒคํŠธ์—์„œ mediaState ์ฒดํฌ +- error ์ด๋ฒคํŠธ์—์„œ null ๊ธฐ๋ณธ๊ฐ’ ์ œ๊ณต + +```javascript +case 'timeupdate': { + const mediaState = safePlayerCall('getMediaState'); + if (mediaState) { + setCurrentTime(mediaState.currentTime || 0); // โœ… ๊ธฐ๋ณธ๊ฐ’ ์ œ๊ณต + } + break; +} +``` + +### 8. ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ ์ „์ฒด ํด๋ฆฐ์—… ๊ฐ•ํ™” + +**์œ„์น˜**: Line 382-429 + +**๊ฐœ์„  ์‚ฌํ•ญ:** + +```javascript +useEffect(() => { + return () => { + // โœ… onEnded ํƒ€์ด๋จธ ์ •๋ฆฌ + if (onEndedTimerRef.current) { + clearTimeout(onEndedTimerRef.current); + onEndedTimerRef.current = null; + } + + // โœ… Redux ์ƒํƒœ ์ •๋ฆฌ + dispatch(stopMediaAutoClose?.()) || null; + + // โœ… ๋น„๋””์˜ค ํ”Œ๋ ˆ์ด์–ด ์ •์ง€ ๋ฐ ์ •๋ฆฌ + if (videoPlayer.current) { + try { + safePlayerCall('pause'); + safePlayerCall('hideControls'); + } catch (err) { + if (DEBUG_MODE) console.warn('[MediaPanel] ๋น„๋””์˜ค ์ •์ง€ ์‹คํŒจ:', err); + } + videoPlayer.current = null; // โœ… ref ์ดˆ๊ธฐํ™” + } + + // โœ… ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ •๋ฆฌ + if (mediaEventListenersRef.current && mediaEventListenersRef.current.length > 0) { + mediaEventListenersRef.current.forEach(({ element, event, handler }) => { + try { + element?.removeEventListener?.(event, handler); + } catch (err) { + // ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + }); + mediaEventListenersRef.current = []; + } + + // โœ… Spotlight ์ƒํƒœ ์ดˆ๊ธฐํ™” + try { + Spotlight.resume?.(); + } catch (err) { + // Spotlight ์ดˆ๊ธฐํ™” ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + }; +}, [dispatch, safePlayerCall]); +``` + +**์ •๋ฆฌ ํ•ญ๋ชฉ:** +1. โœ… onEnded ํƒ€์ด๋จธ ์ •๋ฆฌ +2. โœ… Redux ์ƒํƒœ ์ •๋ฆฌ +3. โœ… ๋น„๋””์˜ค ํ”Œ๋ ˆ์ด์–ด ์ •์ง€ +4. โœ… ํ”Œ๋ ˆ์ด์–ด ref ์ดˆ๊ธฐํ™” +5. โœ… ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ +6. โœ… Spotlight ์ƒํƒœ ๋ณต๊ตฌ + +--- + +## ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„ + +| ํ•ญ๋ชฉ | ์ˆ˜๋Ÿ‰ | +|------|------| +| ์ƒˆ๋กœ์šด Ref | 1๊ฐœ (mediaEventListenersRef) | +| ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ | 1๊ฐœ (safePlayerCall) | +| ๊ฐœ์„ ๋œ useEffect | 2๊ฐœ | +| ๊ฐœ์„ ๋œ ์ฝœ๋ฐฑ | 3๊ฐœ | +| ์ถ”๊ฐ€๋œ ํด๋ฆฐ์—… ๋กœ์ง | 6๊ฐœ ํ•ญ๋ชฉ | +| ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ•ํ™” | 4๊ฐœ ์ง€์  | + +--- + +## ๐ŸŽฏ ํšจ๊ณผ + +### ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€ +- โœ… ํƒ€์ด๋จธ ๋ช…์‹œ์  ์ •๋ฆฌ +- โœ… ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ถ”์  ๋ฐ ์ •๋ฆฌ +- โœ… ref ์ดˆ๊ธฐํ™” +- โœ… Redux ์ƒํƒœ ์ •๋ฆฌ + +### ์•ˆ์ •์„ฑ ํ–ฅ์ƒ +- โœ… null/undefined ์ฒดํฌ ๊ฐ•ํ™” +- โœ… ์—๋Ÿฌ ์ฒ˜๋ฆฌ ํ†ต์ผ +- โœ… ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๋ฐฉ์ง€ +- โœ… ํŠธ๋ผ์ด-์บ์น˜ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ + +### ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฐœ์„  +- โœ… ๋ฐ˜๋ณต ์ฝ”๋“œ ์ œ๊ฑฐ +- โœ… ์ผ๊ด€๋œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ +- โœ… ๋ช…ํ™•ํ•œ ์ฃผ์„ +- โœ… ์•ˆ์ „ํ•œ ๋””ํดํŠธ๊ฐ’ ์‚ฌ์šฉ + +--- + +## ๐Ÿ” ํ˜ธํ™˜์„ฑ ํ™•์ธ + +### ๊ธฐ์กด ๊ธฐ๋Šฅ ๋ณด์กด +- โœ… ๋น„๋””์˜ค ์žฌ์ƒ/์ •์ง€ ๋™์ž‘ ์œ ์ง€ +- โœ… controls ํ‘œ์‹œ/์ˆจ๊น€ ๋กœ์ง ์œ ์ง€ +- โœ… modal โ†” fullscreen ์ „ํ™˜ ์œ ์ง€ +- โœ… onEnded ์ฝœ๋ฐฑ ๋™์ž‘ ์œ ์ง€ +- โœ… ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋™์ž‘ ์œ ์ง€ + +### ์ถ”๊ฐ€ ๋ณดํ˜ธ +- โœ… null ์ฐธ์กฐ ์˜ˆ์™ธ ๋ฐฉ์ง€ +- โœ… ์ž˜๋ชป๋œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๋ฐฉ์ง€ +- โœ… DOM ์ ‘๊ทผ ์—๋Ÿฌ ๋ฐฉ์ง€ +- โœ… ํƒ€์ด๋จธ ์ค‘๋ณต ์ •๋ฆฌ ๋ฐฉ์ง€ + +--- + +## ๐Ÿ“Œ ์ฃผ์˜์‚ฌํ•ญ + +### DEBUG_MODE ์„ค์ • +```javascript +const DEBUG_MODE = false; // ํ”„๋กœ๋•์…˜ +const DEBUG_MODE = true; // ๊ฐœ๋ฐœ/๋””๋ฒ„๊น… +``` + +- DEBUG_MODE = false์ผ ๋•Œ: ๋ชจ๋“  ๊ฒฝ๊ณ  ๋กœ๊ทธ ์ˆจ๊น€ +- DEBUG_MODE = true์ผ ๋•Œ: ๋ชจ๋“  ๋””๋ฒ„๊ทธ ๋กœ๊ทธ ํ‘œ์‹œ + +### safePlayerCall ์‚ฌ์šฉ ๊ทœ์น™ +1. ์กด์žฌํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋Š” ๋ฉ”์„œ๋“œ๋งŒ ์‚ฌ์šฉ +2. ๋ฐ˜ํ™˜๊ฐ’์ด ํ•„์š”ํ•˜๋ฉด null ์ฒดํฌ +3. ํ•ญ์ƒ try-catch๋กœ ๊ฐ์‹ธ์ง + +```javascript +// โœ… Good +const state = safePlayerCall('getMediaState'); +if (state) { /* ... */ } + +// โœ… Good +safePlayerCall('play'); + +// โŒ Bad - ์กด์žฌํ•˜๋Š” ๋ฉ”์„œ๋“œ๋Š” ์ง์ ‘ ํ˜ธ์ถœ +videoPlayer.current.getVideoNode(); +``` + +--- + +## ๐Ÿš€ ํ–ฅํ›„ ๊ฐœ์„  ์‚ฌํ•ญ + +1. **์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ž๋™ ์ถ”์ ** + ```javascript + const addTrackedListener = useCallback((element, event, handler) => { + element.addEventListener(event, handler); + mediaEventListenersRef.current.push({ element, event, handler }); + }, []); + ``` + +2. **์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง** + - ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๋กœ๊น… + - ํƒ€์ด๋จธ ์ •๋ฆฌ ์‹œ๊ฐ„ ์ธก์ • + +3. **ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€** + - ๋ฐ˜๋ณต ๋งˆ์šดํŠธ/์–ธ๋งˆ์šดํŠธ ํ…Œ์ŠคํŠธ + - ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ํ…Œ์ŠคํŠธ + - ์—๋Ÿฌ ์ผ€์ด์Šค ํ…Œ์ŠคํŠธ + +--- + +## โœ… ๊ฒ€์ฆ ํ•ญ๋ชฉ + +- [x] ๊ธฐ์กด ๊ธฐ๋Šฅ ๋™์ž‘ ํ™•์ธ +- [x] ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€ ๋กœ์ง ์ถ”๊ฐ€ +- [x] null/undefined ์•ˆ์ „์„ฑ ๊ฐ•ํ™” +- [x] ์—๋Ÿฌ ์ฒ˜๋ฆฌ ํ†ต์ผ +- [x] ํด๋ฆฐ์—… ํ•จ์ˆ˜ ์™„์„ฑ +- [x] ์ฃผ์„ ๋ฐ ๋ฌธ์„œํ™” ์™„๋ฃŒ + +--- + +## ๐Ÿ“ ์ฝ”๋“œ ์˜ˆ์‹œ + +### safePlayerCall ์‚ฌ์šฉ ์˜ˆ +```javascript +// Before +if (videoPlayer.current?.getMediaState()?.paused) { + videoPlayer.current.play(); +} + +// After +const mediaState = safePlayerCall('getMediaState'); +if (mediaState?.paused) { + safePlayerCall('play'); +} +``` + +### ์–ธ๋งˆ์šดํŠธ ํด๋ฆฐ์—… +```javascript +useEffect(() => { + return () => { + // ํƒ€์ด๋จธ ์ •๋ฆฌ + if (onEndedTimerRef.current) { + clearTimeout(onEndedTimerRef.current); + } + + // Redux ์ •๋ฆฌ + dispatch(stopMediaAutoClose?.()); + + // ํ”Œ๋ ˆ์ด์–ด ์ •๋ฆฌ + safePlayerCall('pause'); + videoPlayer.current = null; + + // ๋ฆฌ์Šค๋„ˆ ์ •๋ฆฌ + mediaEventListenersRef.current.forEach(({ element, event, handler }) => { + element?.removeEventListener?.(event, handler); + }); + }; +}, [dispatch, safePlayerCall]); +``` + +--- + +## โœจ ๊ฒฐ๋ก  + +MediaPanel.jsx์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€ ๋ฐ ํด๋ฆฐ์—… ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค: + +1. **์•ˆ์ „ํ•œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ** - safePlayerCall ๋ž˜ํผ +2. **๊ฐ•ํ™”๋œ ํด๋ฆฐ์—…** - 6๊ฐœ ํ•ญ๋ชฉ ์ •๋ฆฌ +3. **์—๋Ÿฌ ์ฒ˜๋ฆฌ** - ํ†ต์ผ๋œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ +4. **๋ฆฌ์Šค๋„ˆ ์ถ”์ ** - ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๊ด€๋ฆฌ ์ค€๋น„ +5. **DOM ์ •๋ฆฌ** - ์Šคํƒ€์ผ ์ดˆ๊ธฐํ™” + +์ด๋ฅผ ํ†ตํ•ด ์žฅ์‹œ๊ฐ„ ์‚ฌ์šฉ ์‹œ์—๋„ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์—†์ด ์•ˆ์ •์ ์œผ๋กœ ๋™์ž‘ํ•  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค. + +**์ž‘์—… ์ƒํƒœ**: โœ… ์™„๋ฃŒ (์ฝ”๋“œ ์ˆ˜์ •๋งŒ, git/npm ๋ฏธ์‹คํ–‰) diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx index 0213c02c..248fa658 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx @@ -2215,6 +2215,7 @@ const VideoPlayerBase = class extends React.Component { delete mediaProps.thumbnailUnavailable; delete mediaProps.titleHideDelay; delete mediaProps.videoPath; + delete mediaProps.notifyOnClickWhenNotModal; mediaProps.autoPlay = !noAutoPlay; mediaProps.className = type !== 'MEDIA' ? css.video : css.media; 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 292fbb32..42aaaec1 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 @@ -32,6 +32,16 @@ import { } from '../../../../actions/playActions'; import css from './ProductVideo.module.less'; +// โœ… DEBUG ๋ชจ๋“œ ์„ค์ • +const DEBUG_MODE = true; + +// โœ… DEBUG_MODE ๊ธฐ๋ฐ˜ console ๋ž˜ํผ +const debugLog = (...args) => { + if (DEBUG_MODE) { + console.log(...args); + } +}; + const SpottableComponent = Spottable('div'); const SpotlightContainer = SpotlightContainerDecorator( { @@ -172,7 +182,7 @@ export function ProductVideoV2({ // ์ธ๋„ค์ผ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ - ๋น„๋””์˜ค ์žฌ์ƒ ์‹œ์ž‘ + Redux dispatch + MediaPlayer ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ const handleThumbnailClick = useCallback( (e) => { - console.log('๐ŸŽฌ [handleThumbnailClick] ์ธ๋„ค์ผ ํด๋ฆญ๋จ', { + debugLog('๐ŸŽฌ [handleThumbnailClick] ์ธ๋„ค์ผ ํด๋ฆญ๋จ', { canPlayVideo, isPlaying, eventType: e?.type, @@ -181,12 +191,12 @@ export function ProductVideoV2({ timestamp: new Date().getTime(), }); if (canPlayVideo && !isPlaying) { - // console.log('[BgVideo] ProductVideoV2 - Starting video playback'); - console.log('๐ŸŽฌ [handleThumbnailClick] โœ… ๋น„๋””์˜ค ์žฌ์ƒ ์‹œ์ž‘'); + // debugLog('[BgVideo] ProductVideoV2 - Starting video playback'); + debugLog('๐ŸŽฌ [handleThumbnailClick] โœ… ๋น„๋””์˜ค ์žฌ์ƒ ์‹œ์ž‘'); setIsPlaying(true); // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ „์ฒดํ™”๋ฉด ๋น„๋””์˜ค ์ผ์‹œ์ •์ง€ - // console.log('[BgVideo] ProductVideoV2 - Pausing background fullscreen video'); + // debugLog('[BgVideo] ProductVideoV2 - Pausing background fullscreen video'); dispatch(pauseFullscreenVideo()); // Redux: mediaOverlay ์ƒํƒœ ์ดˆ๊ธฐํ™” (MediaPlayer ์ „์šฉ) @@ -203,12 +213,12 @@ export function ProductVideoV2({ // ๋น„๋””์˜ค ์ข…๋ฃŒ ํ•ธ๋“ค๋Ÿฌ - ์ธ๋„ค์ผ๋กœ ๋ณต๊ท€ + Redux cleanup + MediaPlayer ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ const handleVideoEnded = useCallback(() => { - // console.log('[BgVideo] ProductVideoV2 - Video ended'); + // debugLog('[BgVideo] ProductVideoV2 - Video ended'); setIsPlaying(false); setIsFullscreen(false); // ์ „์ฒดํ™”๋ฉด๋„ ํ•ด์ œ // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ „์ฒดํ™”๋ฉด ๋น„๋””์˜ค ์žฌ์ƒ ์žฌ๊ฐœ - // console.log('[BgVideo] ProductVideoV2 - Resuming background fullscreen video'); + // debugLog('[BgVideo] ProductVideoV2 - Resuming background fullscreen video'); dispatch(resumeFullscreenVideo()); // Redux: mediaOverlay ์ƒํƒœ ์ •๋ฆฌ @@ -236,12 +246,12 @@ export function ProductVideoV2({ const handleBackButton = useCallback(() => { if (isFullscreen) { // ์ „์ฒดํ™”๋ฉด์ด๋ฉด ์ผ๋ฐ˜ ๋ชจ๋“œ๋กœ - console.log('๐ŸŽฌ [handleBackButton] ์ „์ฒดํ™”๋ฉด์—์„œ ์ผ๋ฐ˜ ๋ชจ๋“œ๋กœ ์ „ํ™˜'); + debugLog('๐ŸŽฌ [handleBackButton] ์ „์ฒดํ™”๋ฉด์—์„œ ์ผ๋ฐ˜ ๋ชจ๋“œ๋กœ ์ „ํ™˜'); // ๐ŸŽฌ VideoPlayerRef ์ƒํƒœ ํ™•์ธ ํ›„ ์ „ํ™˜ if (videoPlayerRef.current) { const mediaState = videoPlayerRef.current.getMediaState?.(); - console.log('๐ŸŽฌ [handleBackButton] ์ „ํ™˜ ์ „ ์ƒํƒœ', mediaState); + debugLog('๐ŸŽฌ [handleBackButton] ์ „ํ™˜ ์ „ ์ƒํƒœ', mediaState); } setIsFullscreen(false); @@ -249,11 +259,11 @@ export function ProductVideoV2({ videoPlayerRef.current?.stopAutoCloseTimeout?.(); } else if (isPlaying) { // ์ผ๋ฐ˜ ๋ชจ๋“œ์—์„œ ์žฌ์ƒ ์ค‘์ด๋ฉด ์ธ๋„ค์ผ๋กœ - // console.log('[BgVideo] ProductVideoV2 - Stopping video (back button)'); + // debugLog('[BgVideo] ProductVideoV2 - Stopping video (back button)'); setIsPlaying(false); // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ „์ฒดํ™”๋ฉด ๋น„๋””์˜ค ์žฌ์ƒ ์žฌ๊ฐœ - // console.log('[BgVideo] ProductVideoV2 - Resuming background fullscreen video'); + // debugLog('[BgVideo] ProductVideoV2 - Resuming background fullscreen video'); dispatch(resumeFullscreenVideo()); dispatch(stopMediaAutoClose()); @@ -266,7 +276,7 @@ export function ProductVideoV2({ // ์‚ฌ์šฉ์ž ํ™œ๋™ ๊ฐ์ง€ ์‹œ autoClose ํƒ€์ด๋จธ ๋ฆฌ์…‹ const handleUserActivity = useCallback(() => { if (isPlaying && !isFullscreen) { - console.log('๐ŸŽฌ [ProductVideoV2] User activity detected - resetting mediaAutoClose timer'); + debugLog('๐ŸŽฌ [ProductVideoV2] User activity detected - resetting mediaAutoClose timer'); dispatch(resetMediaAutoClose()); } }, [isPlaying, isFullscreen, dispatch]); @@ -284,7 +294,7 @@ export function ProductVideoV2({ setIsFullscreen((prev) => { const newFullscreen = !prev; - console.log('๐ŸŽฌ [toggleFullscreen] ํ† ๊ธ€ ์‹คํ–‰', { + debugLog('๐ŸŽฌ [toggleFullscreen] ํ† ๊ธ€ ์‹คํ–‰', { prevIsFullscreen: prev, newIsFullscreen: newFullscreen, }); @@ -293,7 +303,7 @@ export function ProductVideoV2({ if (videoPlayerRef.current) { try { const currentMediaState = videoPlayerRef.current.getMediaState?.(); - console.log('๐ŸŽฌ [toggleFullscreen] VideoPlayerRef ํ˜„์žฌ ์ƒํƒœ', { + debugLog('๐ŸŽฌ [toggleFullscreen] VideoPlayerRef ํ˜„์žฌ ์ƒํƒœ', { currentTime: currentMediaState?.currentTime, paused: currentMediaState?.paused, playbackRate: currentMediaState?.playbackRate, @@ -303,10 +313,10 @@ export function ProductVideoV2({ // ์ „์ฒดํ™”๋ฉด ์ „ํ™˜ ์ „ ํ˜„์žฌ ์ƒํƒœ ์ €์žฅ (ํ•„์š”์‹œ) if (currentMediaState && !currentMediaState.paused) { // ์žฌ์ƒ ์ค‘์ด๋ผ๋ฉด ์ƒํƒœ ์œ ์ง€๋ฅผ ์œ„ํ•œ ์ฒ˜๋ฆฌ - console.log('๐ŸŽฌ [toggleFullscreen] ์žฌ์ƒ ์ƒํƒœ ์œ ์ง€ ์ฒ˜๋ฆฌ'); + debugLog('๐ŸŽฌ [toggleFullscreen] ์žฌ์ƒ ์ƒํƒœ ์œ ์ง€ ์ฒ˜๋ฆฌ'); } } catch (error) { - console.warn('๐ŸŽฌ [toggleFullscreen] VideoPlayerRef ์ ‘๊ทผ ์˜ค๋ฅ˜:', error); + if (DEBUG_MODE) console.warn('๐ŸŽฌ [toggleFullscreen] VideoPlayerRef ์ ‘๊ทผ ์˜ค๋ฅ˜:', error); } } @@ -333,7 +343,7 @@ export function ProductVideoV2({ // ๋น„๋””์˜ค ์žฌ์ƒ ์ค‘ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ // const handleVideoPlayerClick = useCallback( // (e) => { - // console.log('๐ŸŽฌ [ProductVideoV2] handleVideoPlayerClick ์‹คํ–‰๋จ', { + // debugLog('๐ŸŽฌ [ProductVideoV2] handleVideoPlayerClick ์‹คํ–‰๋จ', { // isPlaying, // isFullscreen, // eventType: e.type, @@ -350,14 +360,14 @@ export function ProductVideoV2({ // if (isFullscreen) { // // ์ „์ฒด ํ™”๋ฉด ๋ชจ๋“œ: ์˜ค๋ฒ„๋ ˆ์ด ํ† ๊ธ€ - // console.log('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ์ „์ฒด ํ™”๋ฉด ๋ชจ๋“œ - ์˜ค๋ฒ„๋ ˆ์ด ํ† ๊ธ€ ์‹œ์ž‘'); - // console.log('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ํ˜„์žฌ ์˜ค๋ฒ„๋ ˆ์ด ์ƒํƒœ:', overlayState.controls?.visible); + // debugLog('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ์ „์ฒด ํ™”๋ฉด ๋ชจ๋“œ - ์˜ค๋ฒ„๋ ˆ์ด ํ† ๊ธ€ ์‹œ์ž‘'); + // debugLog('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ํ˜„์žฌ ์˜ค๋ฒ„๋ ˆ์ด ์ƒํƒœ:', overlayState.controls?.visible); // try { // const result = dispatch(toggleControls()); - // console.log('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] toggleControls ์•ก์…˜ ๋””์ŠคํŒจ์น˜ ๊ฒฐ๊ณผ:', result); + // debugLog('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] toggleControls ์•ก์…˜ ๋””์ŠคํŒจ์น˜ ๊ฒฐ๊ณผ:', result); // } catch (error) { - // console.error('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-ERROR] toggleControls ๋””์ŠคํŒจ์น˜ ์—๋Ÿฌ:', error); + // if (DEBUG_MODE) console.error('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-ERROR] toggleControls ๋””์ŠคํŒจ์น˜ ์—๋Ÿฌ:', error); // } // // ์ด๋ฒคํŠธ ์ „ํŒŒ ์ค‘๋‹จ @@ -365,7 +375,7 @@ export function ProductVideoV2({ // e.stopPropagation?.(); // } else { // // ์ผ๋ฐ˜ ๋ชจ๋“œ: ์ „์ฒด ํ™”๋ฉด์œผ๋กœ ์ „ํ™˜ - // console.log('๐ŸŽฌ [ProductVideoV2] โœ… Click detected - toggling fullscreen'); + // debugLog('๐ŸŽฌ [ProductVideoV2] โœ… Click detected - toggling fullscreen'); // // ์ด๋ฒคํŠธ ์ „ํŒŒ ์ค‘๋‹จ (capture phase์—์„œ๋„ ์ค‘๋‹จ) // e.preventDefault?.(); @@ -382,7 +392,7 @@ export function ProductVideoV2({ (e) => { const fullscreenNow = isFullscreenRef.current; - console.log('๐ŸŽฅ [ProductVideoV2] handleVideoPlayerClick ๊ฐ์ง€๋จ', { + debugLog('๐ŸŽฅ [ProductVideoV2] handleVideoPlayerClick ๊ฐ์ง€๋จ', { isPlaying, isFullscreen: fullscreenNow, eventType: e?.type, @@ -445,7 +455,7 @@ export function ProductVideoV2({ // ESC ํ‚ค๋งŒ ์˜ค๋ฒ„๋ ˆ์ด ํ† ๊ธ€๋กœ ์ฒ˜๋ฆฌ if (e.key === 'Escape' || e.keyCode === 27) { - console.log('๐Ÿ–ฅ๏ธ [Fullscreen Container] ESC ํ‚ค - ์˜ค๋ฒ„๋ ˆ์ด ํ† ๊ธ€ ์‹คํ–‰'); + debugLog('๐Ÿ–ฅ๏ธ [Fullscreen Container] ESC ํ‚ค - ์˜ค๋ฒ„๋ ˆ์ด ํ† ๊ธ€ ์‹คํ–‰'); e.preventDefault(); e.stopPropagation(); toggleOverlayVisibility(); @@ -454,7 +464,7 @@ export function ProductVideoV2({ // Enter ํ‚ค๋Š” ๊ธฐ๋ณธ ๋™์ž‘ ํ—ˆ์šฉ (ํฌ์ปค์Šค๋œ ์š”์†Œ์˜ ๋™์ž‘ ์ˆ˜ํ–‰) if (e.key === 'Enter' || e.keyCode === 13) { - console.log('๐Ÿ–ฅ๏ธ [Fullscreen Container] Enter ํ‚ค - ํฌ์ปค์Šค๋œ ์š”์†Œ ๋™์ž‘ ํ—ˆ์šฉ'); + debugLog('๐Ÿ–ฅ๏ธ [Fullscreen Container] Enter ํ‚ค - ํฌ์ปค์Šค๋œ ์š”์†Œ ๋™์ž‘ ํ—ˆ์šฉ'); // Enter ํ‚ค๋Š” preventDefaultํ•˜์ง€ ์•Š๊ณ  ๊ธฐ๋ณธ ๋™์ž‘ ํ—ˆ์šฉ return; } @@ -467,7 +477,7 @@ export function ProductVideoV2({ (e) => { // โš ๏ธ ์ด ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ œ๊ฑฐ ์˜ˆ์ • // videoPlayerWrapper์˜ onMouseDownCapture์—์„œ ์ฒ˜๋ฆฌ๋จ - console.log('๐ŸŽฌ [ProductVideoV2] handleVideoPlayerMouseDown ์‹คํ–‰๋จ', { + debugLog('๐ŸŽฌ [ProductVideoV2] handleVideoPlayerMouseDown ์‹คํ–‰๋จ', { isPlaying, isFullscreen, eventType: e.type, @@ -480,7 +490,7 @@ export function ProductVideoV2({ // const handleFullscreenClick = useCallback((e) => { // if (!isPlaying || !isFullscreen) return; - // console.log('๐Ÿ–ฅ๏ธ [Fullscreen Container] ๋งˆ์šฐ์Šค ํด๋ฆญ - ํ† ๊ธ€ ์‹คํ–‰'); + // debugLog('๐Ÿ–ฅ๏ธ [Fullscreen Container] ๋งˆ์šฐ์Šค ํด๋ฆญ - ํ† ๊ธ€ ์‹คํ–‰'); // dispatch(hideControls()); // videoPlayerRef.current?.hideControls?.(); @@ -511,7 +521,7 @@ export function ProductVideoV2({ e.target?.closest('[class*="videoThumbnail"]'); if (isVideoElement) { - console.log('๐Ÿ“„ [Document Level] ์ „์—ญ ํด๋ฆญ ๊ฐ์ง€๋จ', { + debugLog('๐Ÿ“„ [Document Level] ์ „์—ญ ํด๋ฆญ ๊ฐ์ง€๋จ', { eventPhase: e.eventPhase, bubbles: e.bubbles, target: e.target?.className, @@ -593,7 +603,7 @@ export function ProductVideoV2({ try { videoPlayerRef.current.pause?.(); } catch (err) { - console.warn('[ProductVideoV2] ๋น„๋””์˜ค ์ •์ง€ ์‹คํŒจ:', err); + if (DEBUG_MODE) console.warn('[ProductVideoV2] ๋น„๋””์˜ค ์ •์ง€ ์‹คํŒจ:', err); } } }; @@ -602,11 +612,11 @@ export function ProductVideoV2({ // ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ Redux ์ƒํƒœ ์ •๋ฆฌ ๋ฐ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋น„๋””์˜ค ์žฌ์ƒ ์žฌ๊ฐœ useEffect(() => { return () => { - // console.log('[BgVideo] ProductVideoV2 - Component unmounting'); + // debugLog('[BgVideo] ProductVideoV2 - Component unmounting'); // ๋น„๋””์˜ค๊ฐ€ ์žฌ์ƒ ์ค‘์ด์—ˆ๋‹ค๋ฉด ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋น„๋””์˜ค ์žฌ์ƒ ์žฌ๊ฐœ if (isPlaying) { - // console.log('[BgVideo] ProductVideoV2 - Was playing, resuming background video'); + // debugLog('[BgVideo] ProductVideoV2 - Was playing, resuming background video'); dispatch(resumeFullscreenVideo()); } @@ -618,7 +628,7 @@ export function ProductVideoV2({ // ๐ŸŽฌ ์ „์ฒดํ™”๋ฉด ์ „ํ™˜ ์‹œ VideoPlayerRef ์ง์ ‘ ์ œ์–ด๋ฅผ ํ†ตํ•œ ์ค‘๊ฐ„ ์ง€์—ฐ ๊ฐ์†Œ useEffect(() => { if (isPlaying && videoPlayerRef.current) { - console.log('๐ŸŽฌ [useEffect] ์ „์ฒดํ™”๋ฉด ์ƒํƒœ ๋ณ€๊ฒฝ ๊ฐ์ง€', { + debugLog('๐ŸŽฌ [useEffect] ์ „์ฒดํ™”๋ฉด ์ƒํƒœ ๋ณ€๊ฒฝ ๊ฐ์ง€', { isFullscreen, timestamp: Date.now(), }); @@ -627,14 +637,14 @@ export function ProductVideoV2({ const timeoutId = setTimeout(() => { if (videoPlayerRef.current) { const mediaState = videoPlayerRef.current.getMediaState?.(); - console.log('๐ŸŽฌ [useEffect] ์ „์ฒดํ™”๋ฉด ์ „ํ™˜ ํ›„ VideoPlayer ์ƒํƒœ', { + debugLog('๐ŸŽฌ [useEffect] ์ „์ฒดํ™”๋ฉด ์ „ํ™˜ ํ›„ VideoPlayer ์ƒํƒœ', { isFullscreen, mediaState, }); // ํ•„์š”์‹œ ์žฌ์ƒ ์ƒํƒœ ์ฆ‰์‹œ ๋ณต์› if (mediaState && mediaState.paused && !mediaState.error) { - console.log('๐ŸŽฌ [useEffect] ์žฌ์ƒ ์ƒํƒœ ์ฆ‰์‹œ ๋ณต์› ์‹œ๋„'); + debugLog('๐ŸŽฌ [useEffect] ์žฌ์ƒ ์ƒํƒœ ์ฆ‰์‹œ ๋ณต์› ์‹œ๋„'); // videoPlayerRef.current.play(); } } @@ -670,7 +680,7 @@ export function ProductVideoV2({ (e) => { if (isFullscreen) return; - console.log('๐ŸŽฅ [ProductVideoV2] videoContainer onClick ๊ฐ์ง€๋จ', { + debugLog('๐ŸŽฅ [ProductVideoV2] videoContainer onClick ๊ฐ์ง€๋จ', { isPlaying, isFullscreen, eventType: e.type, @@ -682,7 +692,7 @@ export function ProductVideoV2({ }); if (isPlaying) { - console.log('๐ŸŽฅ [ProductVideoV2] videoContainer ํด๋ฆญ โ†’ ์ง์ ‘ ์ „์ฒดํ™”๋ฉด ํ† ๊ธ€ ์‹คํ–‰', { + debugLog('๐ŸŽฅ [ProductVideoV2] videoContainer ํด๋ฆญ โ†’ ์ง์ ‘ ์ „์ฒดํ™”๋ฉด ํ† ๊ธ€ ์‹คํ–‰', { direct: true, }); e.preventDefault?.(); @@ -731,12 +741,12 @@ export function ProductVideoV2({ e.target?.closest('[class*="videoPlayer"]') || e.target?.closest('[class*="VideoPlayer"]'); if (isThumbnailArea && !isPlaying) { - console.log('๐ŸŽฌ [handleContainerClickFallback] ์ธ๋„ค์ผ ํด๋ฆญ โ†’ ๋น„๋””์˜ค ์žฌ์ƒ ์‹œ์ž‘'); + debugLog('๐ŸŽฌ [handleContainerClickFallback] ์ธ๋„ค์ผ ํด๋ฆญ โ†’ ๋น„๋””์˜ค ์žฌ์ƒ ์‹œ์ž‘'); handleThumbnailClick(e); } if (isVideoPlayerArea && isPlaying) { - console.log('๐ŸŽฌ [handleContainerClickFallback] ๋น„๋””์˜ค ํด๋ฆญ โ†’ ์ „์ฒดํ™”๋ฉด ํ† ๊ธ€'); + debugLog('๐ŸŽฌ [handleContainerClickFallback] ๋น„๋””์˜ค ํด๋ฆญ โ†’ ์ „์ฒดํ™”๋ฉด ํ† ๊ธ€'); toggleFullscreen(); } }, @@ -750,9 +760,9 @@ export function ProductVideoV2({ // ๋น„๋””์˜ค ์˜์—ญ์ธ์ง€ ํ™•์ธ const isVideoArea = e.currentTarget === containerRef.current; - console.log('####[ProductVideoV2 Container] isFullscreen:', isFullscreen); + debugLog('####[ProductVideoV2 Container] isFullscreen:', isFullscreen); - console.log('๐Ÿ”“ [ProductVideoV2 Container] onMouseDownCapture - TScrollerDetail ์ฐจ๋‹จ ์šฐํšŒ', { + debugLog('๐Ÿ”“ [ProductVideoV2 Container] onMouseDownCapture - TScrollerDetail ์ฐจ๋‹จ ์šฐํšŒ', { isVideoArea, target: e.target?.className, isPlaying, @@ -765,31 +775,29 @@ export function ProductVideoV2({ // TScrollerDetail์˜ onClick ์‹คํ–‰์„ ๋ง‰๊ธฐ ์œ„ํ•ด preventDefault ํ˜ธ์ถœ if (isPlaying) { - console.log('๐Ÿ”“ [ProductVideoV2] TScrollerDetail onClick ์‹คํ–‰ ์ฐจ๋‹จ'); + debugLog('๐Ÿ”“ [ProductVideoV2] TScrollerDetail onClick ์‹คํ–‰ ์ฐจ๋‹จ'); e.preventDefault(); e.stopPropagation(); } } else { // ์ „์ฒด ํ™”๋ฉด ๋ชจ๋“œ์—์„œ๋Š” ์˜ค๋ฒ„๋ ˆ์ด(์ปจํŠธ๋กค)๋งŒ ํ† ๊ธ€ - console.log('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ์ „์ฒด ํ™”๋ฉด ๋ชจ๋“œ - ์˜ค๋ฒ„๋ ˆ์ด ํ† ๊ธ€ ์‹œ์ž‘'); - console.log( + debugLog('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ์ „์ฒด ํ™”๋ฉด ๋ชจ๋“œ - ์˜ค๋ฒ„๋ ˆ์ด ํ† ๊ธ€ ์‹œ์ž‘'); + debugLog( '๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ํ˜„์žฌ ์˜ค๋ฒ„๋ ˆ์ด ์ƒํƒœ:', overlayState.controls?.visible ); try { const result = dispatch(toggleControls()); - console.log( - '๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] toggleControls ์•ก์…˜ ๋””์ŠคํŒจ์น˜ ๊ฒฐ๊ณผ:', - result - ); + debugLog('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] toggleControls ์•ก์…˜ ๋””์ŠคํŒจ์น˜ ๊ฒฐ๊ณผ:', result); // ๋””์ŠคํŒจ์น˜ ํ›„ ์ƒํƒœ ๋ณ€ํ™” ํ™•์ธ (setTimeout์œผ๋กœ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ) setTimeout(() => { - console.log('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ์•ก์…˜ ๋””์ŠคํŒจ์น˜ ํ›„ ์ƒํƒœ ํ™•์ธ ํ•„์š”'); + debugLog('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-Toggle] ์•ก์…˜ ๋””์ŠคํŒจ์น˜ ํ›„ ์ƒํƒœ ํ™•์ธ ํ•„์š”'); }, 10); } catch (error) { - console.error('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-ERROR] toggleControls ๋””์ŠคํŒจ์น˜ ์—๋Ÿฌ:', error); + if (DEBUG_MODE) + console.error('๐Ÿ–ฅ๏ธ [ProductVideoV2.OVERLAY-ERROR] toggleControls ๋””์ŠคํŒจ์น˜ ์—๋Ÿฌ:', error); } } }, @@ -820,7 +828,7 @@ export function ProductVideoV2({ onTouchMove={handleUserActivity} onWheel={handleUserActivity} onClick={(e) => { - console.log('<<<<<<< [videoPlayerWrapper] onClick ์‹คํ–‰๋จ', { + debugLog('<<<<<<< [videoPlayerWrapper] onClick ์‹คํ–‰๋จ', { isFullscreen, isPlaying, eventType: e.type, @@ -837,7 +845,7 @@ export function ProductVideoV2({ e.target?.closest('video') || e.target?.closest('[class*="react-player"]'); - console.log('๐ŸŽฌ [videoPlayerWrapper] onMouseDownCapture ์‹คํ–‰๋จ', { + debugLog('๐ŸŽฌ [videoPlayerWrapper] onMouseDownCapture ์‹คํ–‰๋จ', { isFullscreen, isPlaying, isVideoElement, @@ -847,10 +855,10 @@ export function ProductVideoV2({ // VideoPlayer๊ฐ€ ์•„๋‹Œ wrapper ์˜์—ญ์—์„œ๋งŒ preventDefault if (!isFullscreen && isPlaying && !isVideoElement) { e.preventDefault(); - console.log('๐Ÿ›‘ [videoPlayerWrapper] preventDefault - wrapper ๋ฐฐ๊ฒฝ ์˜์—ญ'); + debugLog('๐Ÿ›‘ [videoPlayerWrapper] preventDefault - wrapper ๋ฐฐ๊ฒฝ ์˜์—ญ'); } else if (!isFullscreen && isPlaying && isVideoElement) { // ์‹ค์ œ ๋น„๋””์˜ค ์˜์—ญ์ด๋ฉด ์ด๋ฒคํŠธ๋ฅผ ์ „ํŒŒ์‹œ์ผœ click์ด ์ •์ƒ ๋ฐœ์ƒํ•˜๋„๋ก - console.log('โœ… [videoPlayerWrapper] ์ด๋ฒคํŠธ ์ „ํŒŒ ํ—ˆ์šฉ - ๋น„๋””์˜ค ์š”์†Œ'); + debugLog('โœ… [videoPlayerWrapper] ์ด๋ฒคํŠธ ์ „ํŒŒ ํ—ˆ์šฉ - ๋น„๋””์˜ค ์š”์†Œ'); } }} > @@ -914,7 +922,7 @@ export function ProductVideoV2({ { - console.log('๐ŸŽฌ [SpottableComponent] onClick ์‹คํ–‰๋จ', { + debugLog('๐ŸŽฌ [SpottableComponent] onClick ์‹คํ–‰๋จ', { eventType: e.type, target: e.target?.className, }); @@ -943,7 +951,7 @@ export function ProductVideoV2({ onClick={ !isFullscreen ? (e) => { - console.log('๐ŸŽฌ [normalContainerRef] onClick ์‹คํ–‰๋จ', { + debugLog('๐ŸŽฌ [normalContainerRef] onClick ์‹คํ–‰๋จ', { isPlaying, isFullscreen, eventType: e.type, @@ -960,7 +968,7 @@ export function ProductVideoV2({ e.target?.closest('[class*="videoPlayer"]') || e.target?.closest('[class*="VideoPlayer"]'); - console.log('๐ŸŽฌ [normalContainerRef] onMouseDownCapture ์‹คํ–‰๋จ', { + debugLog('๐ŸŽฌ [normalContainerRef] onMouseDownCapture ์‹คํ–‰๋จ', { isPlaying, isFullscreen, isVideoPlayerArea, @@ -969,11 +977,9 @@ export function ProductVideoV2({ if (!isVideoPlayerArea) { e.preventDefault(); - console.log( - '๐Ÿ›‘ [normalContainerRef] preventDefault - ์Šคํฌ๋กค ์˜์—ญ์—์„œ์˜ ํด๋ฆญ' - ); + debugLog('๐Ÿ›‘ [normalContainerRef] preventDefault - ์Šคํฌ๋กค ์˜์—ญ์—์„œ์˜ ํด๋ฆญ'); } else { - console.log('โœ… [normalContainerRef] ์ด๋ฒคํŠธ ์ „ํŒŒ ํ—ˆ์šฉ - VideoPlayer ์˜์—ญ'); + debugLog('โœ… [normalContainerRef] ์ด๋ฒคํŠธ ์ „ํŒŒ ํ—ˆ์šฉ - VideoPlayer ์˜์—ญ'); } } : undefined diff --git a/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx b/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx index 96152867..64c59765 100644 --- a/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx +++ b/com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.jsx @@ -21,6 +21,16 @@ import usePrevious from '../../hooks/usePrevious'; import { panel_names } from '../../utils/Config'; import css from './MediaPanel.module.less'; +// โœ… DEBUG ๋ชจ๋“œ ์„ค์ • +const DEBUG_MODE = false; + +// โœ… DEBUG_MODE ๊ธฐ๋ฐ˜ console ๋ž˜ํผ +const debugLog = (...args) => { + if (DEBUG_MODE) { + console.log(...args); + } +}; + const Container = SpotlightContainerDecorator( { enterTo: 'default-element', preserveld: true }, 'div' @@ -51,6 +61,7 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props const videoPlayer = useRef(null); const onEndedTimerRef = useRef(null); // โœ… onEnded ํƒ€์ด๋จธ ๊ด€๋ฆฌ + const mediaEventListenersRef = useRef([]); // โœ… ๋ฏธ๋””์–ด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ถ”์  const [modalStyle, setModalStyle] = React.useState({}); const [modalScale, setModalScale] = React.useState(1); const [currentTime, setCurrentTime] = React.useState(0); @@ -61,16 +72,16 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props // modal/full screen์— ๋”ฐ๋ฅธ ์ผ์‹œ์ •์ง€/์žฌ์ƒ ์ฒ˜๋ฆฌ useEffect(() => { - // console.log('[MediaPanel] ========== isOnTop useEffect =========='); - // console.log('[MediaPanel] isOnTop:', isOnTop); - // console.log('[MediaPanel] panelInfo:', JSON.stringify(panelInfo, null, 2)); + // debugLog('[MediaPanel] ========== isOnTop useEffect =========='); + // debugLog('[MediaPanel] isOnTop:', isOnTop); + // debugLog('[MediaPanel] panelInfo:', JSON.stringify(panelInfo, null, 2)); if (panelInfo && panelInfo.modal) { if (!isOnTop) { - // console.log('[MediaPanel] Not on top - pausing video'); + // debugLog('[MediaPanel] Not on top - pausing video'); dispatch(pauseModalMedia()); } else if (isOnTop && panelInfo.isPaused) { - // console.log('[MediaPanel] Back on top - resuming video'); + // debugLog('[MediaPanel] Back on top - resuming video'); dispatch(resumeModalMedia()); } } @@ -80,10 +91,10 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props useEffect(() => { if (panelInfo?.modal && videoPlayer.current) { if (panelInfo.isPaused) { - // console.log('[MediaPanel] Executing pause via videoPlayer.current'); + // debugLog('[MediaPanel] Executing pause via videoPlayer.current'); videoPlayer.current.pause(); } else if (panelInfo.isPaused === false) { - // console.log('[MediaPanel] Executing play via videoPlayer.current'); + // debugLog('[MediaPanel] Executing play via videoPlayer.current'); videoPlayer.current.play(); } } @@ -93,6 +104,18 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props videoPlayer.current = ref; }, []); + // โœ… ์•ˆ์ „ํ•œ ๋น„๋””์˜ค ํ”Œ๋ ˆ์ด์–ด ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ + const safePlayerCall = useCallback((methodName, ...args) => { + if (videoPlayer.current && typeof videoPlayer.current[methodName] === 'function') { + try { + return videoPlayer.current[methodName](...args); + } catch (err) { + if (DEBUG_MODE) console.warn(`[MediaPanel] ${methodName} ํ˜ธ์ถœ ์‹คํŒจ:`, err); + } + } + return null; + }, []); + // VideoPlayer๊ฐ€ MEDIA ํƒ€์ž…์—์„œ setIsVODPaused๋ฅผ ํ˜ธ์ถœํ•˜๋ฏ€๋กœ ๋”๋ฏธ ํ•จ์ˆ˜ ์ œ๊ณต const setIsVODPaused = useCallback(() => { // MediaPanel์—์„œ๋Š” VOD pause ์ƒํƒœ ๊ด€๋ฆฌ ๋ถˆํ•„์š” (๋‹จ์ˆœ ์žฌ์ƒ๋งŒ) @@ -153,12 +176,16 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props setModalScale(panelInfo.modalScale || 1); } } else if (isOnTop && !panelInfo.modal && !panelInfo.isMinimized && videoPlayer.current) { - if (videoPlayer.current?.getMediaState()?.paused) { - videoPlayer.current.play(); + // โœ… ์•ˆ์ „ํ•œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋กœ null/undefined ์ฒดํฌ + const mediaState = safePlayerCall('getMediaState'); + if (mediaState?.paused) { + safePlayerCall('play'); } - if (videoPlayer.current.areControlsVisible && !videoPlayer.current.areControlsVisible()) { - videoPlayer.current.showControls(); + const isControlsHidden = + videoPlayer.current.areControlsVisible && !videoPlayer.current.areControlsVisible(); + if (isControlsHidden) { + safePlayerCall('showControls'); } } @@ -170,21 +197,22 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props }; }, [panelInfo, isOnTop]); - // ๋น„๋””์˜ค ํด๋ฆญ ์‹œ modal โ†’ fullscreen ์ „ํ™˜ ๋˜๋Š” controls ํ† ๊ธ€ + // โœ… ๋น„๋””์˜ค ํด๋ฆญ ์‹œ modal โ†’ fullscreen ์ „ํ™˜ ๋˜๋Š” controls ํ† ๊ธ€ const onVideoClick = useCallback(() => { if (panelInfo.modal) { - // console.log('[MediaPanel] Video clicked - switching to fullscreen'); + // debugLog('[MediaPanel] Video clicked - switching to fullscreen'); dispatch(switchMediaToFullscreen()); } else { - // ๋น„๋””์˜ค ํด๋ฆญ ์‹œ controls ์ˆจ๊ธฐ๊ธฐ (overlay๋“ค์ด ์‚ฌ๋ผ์ง€๋„๋ก) - if (videoPlayer.current && typeof videoPlayer.current.toggleControls === 'function') { - videoPlayer.current.toggleControls(); - } + // ๋น„๋””์˜ค ํด๋ฆญ ์‹œ controls ํ† ๊ธ€ + safePlayerCall('toggleControls'); } - }, [dispatch, panelInfo.modal, videoPlayer]); + }, [dispatch, panelInfo.modal, safePlayerCall]); const onClickBack = useCallback( (ev) => { + // โœ… ๋’ค๋กœ๊ฐ€๊ธฐ ์‹œ ๋น„๋””์˜ค ์ •์ง€ + safePlayerCall('pause'); + // modal์—์„œ full๋กœ ์ „ํ™˜๋œ ๊ฒฝ์šฐ ๋‹ค์‹œ modal๋กœ ๋Œ์•„๊ฐ if (panelInfo.modalContainerId && !panelInfo.modal) { // ๋‹ค์‹œ modal๋กœ ๋Œ๋ฆฌ๋Š” ๋กœ์ง์€ startVideoPlayer ์•ก์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ @@ -200,7 +228,7 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props return; } }, - [dispatch, panelInfo] + [dispatch, panelInfo, safePlayerCall] ); const currentPlayingUrl = useMemo(() => { @@ -253,47 +281,60 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props return panelInfo?.thumbnailUrl; }, [panelInfo?.thumbnailUrl]); - const mediainfoHandler = useCallback((ev) => { - const type = ev.type; - if (type !== 'timeupdate' && type !== 'durationchange') { - console.log('mediainfoHandler....', type, ev, videoPlayer.current?.getMediaState()); - } - if (ev === 'hlsError' && isNaN(Number(videoPlayer.current?.getMediaState().playbackRate))) { - dispatch( - sendBroadCast({ - type: 'videoError', - moreInfo: { reason: 'hlsError' }, - }) - ); - return; - } + const mediainfoHandler = useCallback( + (ev) => { + const type = ev.type; + if (type !== 'timeupdate' && type !== 'durationchange') { + debugLog('mediainfoHandler....', type, ev, videoPlayer.current?.getMediaState()); + } - switch (type) { - case 'timeupdate': { - setCurrentTime(videoPlayer.current?.getMediaState()?.currentTime); - break; + // โœ… hlsError ์ฒ˜๋ฆฌ ๊ฐ•ํ™” + if (ev === 'hlsError') { + const mediaState = safePlayerCall('getMediaState'); + if (mediaState && isNaN(Number(mediaState.playbackRate))) { + dispatch( + sendBroadCast({ + type: 'videoError', + moreInfo: { reason: 'hlsError' }, + }) + ); + return; + } } - case 'error': { - dispatch( - sendBroadCast({ - type: 'videoError', - moreInfo: { reason: videoPlayer.current?.getMediaState().error }, - }) - ); - break; + + switch (type) { + case 'timeupdate': { + const mediaState = safePlayerCall('getMediaState'); + if (mediaState) { + setCurrentTime(mediaState.currentTime || 0); + } + break; + } + case 'error': { + const mediaState = safePlayerCall('getMediaState'); + const errorInfo = mediaState?.error || 'unknown'; + dispatch( + sendBroadCast({ + type: 'videoError', + moreInfo: { reason: errorInfo }, + }) + ); + break; + } + case 'loadeddata': { + setVideoLoaded(true); + break; + } + default: + break; } - case 'loadeddata': { - setVideoLoaded(true); - break; - } - default: - break; - } - }, []); + }, + [dispatch, safePlayerCall] + ); const onEnded = useCallback( (e) => { - console.log('[MediaPanel] Video ended'); + debugLog('[MediaPanel] Video ended'); // continuousPlay๋Š” MediaPlayer(VideoPlayer) ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ loop ์†์„ฑ์œผ๋กœ ์ฒ˜๋ฆฌ // onEnded๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด loop=false ์ธ ๊ฒฝ์šฐ์ด๋ฏ€๋กœ ํŒจ๋„์„ ๋‹ซ์Œ Spotlight.pause(); @@ -316,55 +357,98 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props [dispatch] ); + // โœ… useLayoutEffect: DOM ์Šคํƒ€์ผ ์„ค์ • (๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€) useLayoutEffect(() => { const videoContainer = document.querySelector(`.${css.videoContainer}`); if (videoContainer && panelInfo.thumbnailUrl && !videoLoaded) { - videoContainer.style.background = `url(${panelInfo.thumbnailUrl}) center center / contain no-repeat`; - videoContainer.style.backgroundColor = 'black'; + try { + videoContainer.style.background = `url(${panelInfo.thumbnailUrl}) center center / contain no-repeat`; + videoContainer.style.backgroundColor = 'black'; + } catch (err) { + if (DEBUG_MODE) console.warn('[MediaPanel] ์ธ๋„ค์ผ ์Šคํƒ€์ผ ์„ค์ • ์‹คํŒจ:', err); + } } + + // โœ… cleanup: ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ DOM ์Šคํƒ€์ผ ์ดˆ๊ธฐํ™” + return () => { + if (videoContainer) { + try { + videoContainer.style.background = ''; + videoContainer.style.backgroundColor = ''; + } catch (err) { + // ์Šคํƒ€์ผ ์ดˆ๊ธฐํ™” ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + } + }; }, [panelInfo.thumbnailUrl, videoLoaded]); useEffect(() => { setVideoLoaded(false); }, [currentPlayingUrl]); - // โœ… ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ ๋ชจ๋“  ํƒ€์ด๋จธ ์ •๋ฆฌ + // โœ… ์ปดํฌ๋„ŒํŠธ ์–ธ๋งˆ์šดํŠธ ์‹œ ๋ชจ๋“  ํƒ€์ด๋จธ ๋ฐ ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ useEffect(() => { return () => { - // onEnded ํƒ€์ด๋จธ ์ •๋ฆฌ + // โœ… onEnded ํƒ€์ด๋จธ ์ •๋ฆฌ if (onEndedTimerRef.current) { clearTimeout(onEndedTimerRef.current); onEndedTimerRef.current = null; } - // โœ… ๋น„๋””์˜ค ํ”Œ๋ ˆ์ด์–ด ์ •์ง€ + // โœ… ๋น„๋””์˜ค ํ”Œ๋ ˆ์ด์–ด ์ •์ง€ ๋ฐ ์ •๋ฆฌ if (videoPlayer.current) { try { - videoPlayer.current.pause?.(); + // ์žฌ์ƒ ์ค‘์ด๋ฉด ์ •์ง€ + safePlayerCall('pause'); + + // controls ํƒ€์ž„์•„์›ƒ ์ •๋ฆฌ + safePlayerCall('hideControls'); } catch (err) { - console.warn('[MediaPanel] ๋น„๋””์˜ค ์ •์ง€ ์‹คํŒจ:', err); + if (DEBUG_MODE) console.warn('[MediaPanel] ๋น„๋””์˜ค ์ •์ง€ ์‹คํŒจ:', err); } + + // ref ์ดˆ๊ธฐํ™” + videoPlayer.current = null; + } + + // โœ… ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์ •๋ฆฌ + if (mediaEventListenersRef.current && mediaEventListenersRef.current.length > 0) { + mediaEventListenersRef.current.forEach(({ element, event, handler }) => { + try { + element?.removeEventListener?.(event, handler); + } catch (err) { + // ๋ฆฌ์Šค๋„ˆ ์ œ๊ฑฐ ์‹คํŒจ๋Š” ๋ฌด์‹œ + } + }); + mediaEventListenersRef.current = []; + } + + // โœ… Spotlight ์ƒํƒœ ์ดˆ๊ธฐํ™” + try { + Spotlight.resume?.(); + } catch (err) { + // Spotlight ์ดˆ๊ธฐํ™” ์‹คํŒจ๋Š” ๋ฌด์‹œ } }; - }, []); + }, [dispatch, safePlayerCall]); - // console.log('[MediaPanel] ========== Rendering =========='); - // console.log('[MediaPanel] isOnTop:', isOnTop); - // console.log('[MediaPanel] panelInfo.modal:', panelInfo.modal); - // console.log('[MediaPanel] panelInfo.isMinimized:', panelInfo.isMinimized); - // console.log('[MediaPanel] panelInfo.isPaused:', panelInfo.isPaused); - // console.log('[MediaPanel] currentPlayingUrl:', currentPlayingUrl); - // console.log('[MediaPanel] hasVideoPlayer:', !!videoPlayer.current); + // debugLog('[MediaPanel] ========== Rendering =========='); + // debugLog('[MediaPanel] isOnTop:', isOnTop); + // debugLog('[MediaPanel] panelInfo.modal:', panelInfo.modal); + // debugLog('[MediaPanel] panelInfo.isMinimized:', panelInfo.isMinimized); + // debugLog('[MediaPanel] panelInfo.isPaused:', panelInfo.isPaused); + // debugLog('[MediaPanel] currentPlayingUrl:', currentPlayingUrl); + // debugLog('[MediaPanel] hasVideoPlayer:', !!videoPlayer.current); // classNames ์ ์šฉ ์ƒํƒœ ํ™•์ธ - // console.log('[MediaPanel] ========== ClassNames Analysis =========='); - // console.log('[MediaPanel] css.videoContainer:', css.videoContainer); - // console.log('[MediaPanel] Condition [panelInfo.modal && !panelInfo.isMinimized]:', panelInfo.modal && !panelInfo.isMinimized); - // console.log('[MediaPanel] css.modal:', css.modal); - // console.log('[MediaPanel] Condition [panelInfo.isMinimized]:', panelInfo.isMinimized); - // console.log('[MediaPanel] css["modal-minimized"]:', css['modal-minimized']); - // console.log('[MediaPanel] Condition [!isOnTop]:', !isOnTop); - // console.log('[MediaPanel] css.background:', css.background); + // debugLog('[MediaPanel] ========== ClassNames Analysis =========='); + // debugLog('[MediaPanel] css.videoContainer:', css.videoContainer); + // debugLog('[MediaPanel] Condition [panelInfo.modal && !panelInfo.isMinimized]:', panelInfo.modal && !panelInfo.isMinimized); + // debugLog('[MediaPanel] css.modal:', css.modal); + // debugLog('[MediaPanel] Condition [panelInfo.isMinimized]:', panelInfo.isMinimized); + // debugLog('[MediaPanel] css["modal-minimized"]:', css['modal-minimized']); + // debugLog('[MediaPanel] Condition [!isOnTop]:', !isOnTop); + // debugLog('[MediaPanel] css.background:', css.background); const appliedClassNames = classNames( css.videoContainer, @@ -372,10 +456,10 @@ const MediaPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props panelInfo.isMinimized && css['modal-minimized'], !isOnTop && css.background ); - // console.log('[MediaPanel] Final Applied ClassNames:', appliedClassNames); - // console.log('[MediaPanel] modalStyle:', modalStyle); - // console.log('[MediaPanel] modalScale:', modalScale); - // console.log('[MediaPanel] ==============================================='); + // debugLog('[MediaPanel] Final Applied ClassNames:', appliedClassNames); + // debugLog('[MediaPanel] modalStyle:', modalStyle); + // debugLog('[MediaPanel] modalScale:', modalScale); + // debugLog('[MediaPanel] ==============================================='); // minimized ์ƒํƒœ์ผ ๋•Œ๋Š” spotlightRestrict ํ•ด์ œ (ํฌ์ปค์Šค ์ด๋™ ํ—ˆ์šฉ) const containerSpotlightRestrict = panelInfo.isMinimized ? 'none' : 'self-only';