[251124] fix: Log정리-2

🕐 커밋 시간: 2025. 11. 24. 12:03:52

📊 변경 통계:
  • 총 파일: 5개
  • 추가: +306줄
  • 삭제: -256줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/actions/productActions.js
  ~ com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js
  ~ com.twin.app.shoptime/src/reducers/panelReducer.js
  ~ com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/TermsOfOptional.jsx
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx

🔧 함수 변경 내용:
  📄 com.twin.app.shoptime/src/actions/productActions.js (javascript):
     Added: dwarn(), derror(), onSuccess()
    🔄 Modified: pickParams(), createGetThunk(), async()
     Deleted: onSuccess()
  📄 com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js (javascript):
     Added: dwarn(), derror()
  📄 com.twin.app.shoptime/src/reducers/panelReducer.js (javascript):
     Added: dwarn(), derror()
  📄 com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/TermsOfOptional.jsx (javascript):
     Added: dwarn(), derror(), onSuccess(), onTestSuccess()
     Deleted: onSuccess(), onTestSuccess()
  📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx (javascript):
     Added: dwarn(), derror()

🔧 주요 변경 내용:
  • 핵심 비즈니스 로직 개선
  • UI 컴포넌트 아키텍처 개선
  • API 서비스 레이어 개선
This commit is contained in:
2025-11-24 12:03:52 +09:00
parent 8188901054
commit 8514e28866
5 changed files with 847 additions and 715 deletions

View File

@@ -10,6 +10,17 @@ import reviewSampleImage from '../../assets/images/image-review-sample-1.png';
// DEBUG_MODE - true인 경우에만 로그 출력 // DEBUG_MODE - true인 경우에만 로그 출력
const DEBUG_MODE = false; const DEBUG_MODE = false;
// Local debug helpers (matches src/lunaSend/common.js pattern)
const dlog = (...args) => {
if (DEBUG_MODE) console.log(...args);
};
const dwarn = (...args) => {
if (DEBUG_MODE) console.warn(...args);
};
const derror = (...args) => {
if (DEBUG_MODE) console.error(...args);
};
// Best Seller 상품 목록 조회 IF-LGSP-303 // Best Seller 상품 목록 조회 IF-LGSP-303
// FP helpers // FP helpers
const pickParams = (keys) => (src) => const pickParams = (keys) => (src) =>
@@ -39,36 +50,34 @@ const createRequestThunk =
const body = data(props); const body = data(props);
// 📡 REQUEST 로그: API 호출 전 (tag별로 다르게 표시) // 📡 REQUEST 로그: API 호출 전 (tag별로 다르게 표시)
if (DEBUG_MODE) dlog(
console.log( `%c[${tag}] 📤 REQUEST - ${method.toUpperCase()} ${url}`,
`%c[${tag}] 📤 REQUEST - ${method.toUpperCase()} ${url}`, 'background: #4CAF50; color: white; font-weight: bold; padding: 3px;',
'background: #4CAF50; color: white; font-weight: bold; padding: 3px;', {
{ method: method.toUpperCase(),
method: method.toUpperCase(), url: url,
url: url, params: query,
params: query, body: body,
body: body, timestamp: new Date().toISOString(),
timestamp: new Date().toISOString(), }
} );
);
const onSuccess = (response) => { const onSuccess = (response) => {
// ✅ RESPONSE 로그: API 호출 성공 (tag별로 다르게 표시) // ✅ RESPONSE 로그: API 호출 성공 (tag별로 다르게 표시)
if (DEBUG_MODE) dlog(
console.log( `%c[${tag}] ✅ RESPONSE SUCCESS - ${method.toUpperCase()} ${url}`,
`%c[${tag}] ✅ RESPONSE SUCCESS - ${method.toUpperCase()} ${url}`, 'background: #2196F3; color: white; font-weight: bold; padding: 3px;',
'background: #2196F3; color: white; font-weight: bold; padding: 3px;', {
{ method: method.toUpperCase(),
method: method.toUpperCase(), url: url,
url: url, httpStatus: response?.status,
httpStatus: response?.status, httpStatusText: response?.statusText,
httpStatusText: response?.statusText, retCode: response?.data?.retCode,
retCode: response?.data?.retCode, retMsg: response?.data?.retMsg,
retMsg: response?.data?.retMsg, responseData: response?.data,
responseData: response?.data, timestamp: new Date().toISOString(),
timestamp: new Date().toISOString(), }
} );
);
dispatch({ type, payload: selectPayload(response) }); dispatch({ type, payload: selectPayload(response) });
onSuccessExtra(props, dispatch, getState, response); onSuccessExtra(props, dispatch, getState, response);
@@ -76,23 +85,22 @@ const createRequestThunk =
const onFail = (error) => { const onFail = (error) => {
// ❌ ERROR 로그: API 호출 실패 (tag별로 다르게 표시) // ❌ ERROR 로그: API 호출 실패 (tag별로 다르게 표시)
if (DEBUG_MODE) derror(
console.error( `%c[${tag}] ❌ RESPONSE ERROR - ${method.toUpperCase()} ${url}`,
`%c[${tag}] ❌ RESPONSE ERROR - ${method.toUpperCase()} ${url}`, 'background: #F44336; color: white; font-weight: bold; padding: 3px;',
'background: #F44336; color: white; font-weight: bold; padding: 3px;', {
{ method: method.toUpperCase(),
method: method.toUpperCase(), url: url,
url: url, errorMessage: error?.message,
errorMessage: error?.message, errorType: error?.type,
errorType: error?.type, httpStatus: error?.response?.status,
httpStatus: error?.response?.status, httpStatusText: error?.response?.statusText,
httpStatusText: error?.response?.statusText, responseRetCode: error?.response?.data?.retCode,
responseRetCode: error?.response?.data?.retCode, responseRetMsg: error?.response?.data?.retMsg,
responseRetMsg: error?.response?.data?.retMsg, responseData: error?.response?.data,
responseData: error?.response?.data, timestamp: new Date().toISOString(),
timestamp: new Date().toISOString(), }
} );
);
onFailExtra(props, dispatch, getState, error); onFailExtra(props, dispatch, getState, error);
}; };
@@ -106,14 +114,14 @@ const createGetThunk = ({ url, type, params = () => ({}), tag }) =>
export const getBestSeller = (callback) => (dispatch, getState) => { export const getBestSeller = (callback) => (dispatch, getState) => {
const onSuccess = (response) => { const onSuccess = (response) => {
if (DEBUG_MODE) console.log('getBestSeller onSuccess', response.data); dlog('getBestSeller onSuccess', response.data);
dispatch({ type: types.GET_BEST_SELLER, payload: get('data.data', response) }); dispatch({ type: types.GET_BEST_SELLER, payload: get('data.data', response) });
dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
callback && callback(); callback && callback();
}; };
const onFail = (error) => { const onFail = (error) => {
if (DEBUG_MODE) console.error('getBestSeller onFail', error); derror('getBestSeller onFail', error);
dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
callback && callback(); callback && callback();
}; };
@@ -718,20 +726,20 @@ export const getUserReviewList = (requestParams) => async (dispatch, getState) =
// Review Filters 추출 함수 (IF-LGSP-100) // Review Filters 추출 함수 (IF-LGSP-100)
const extractReviewFiltersApiData = (apiResponse) => { const extractReviewFiltersApiData = (apiResponse) => {
try { try {
console.log('[ReviewFilters] 📥 extractReviewFiltersApiData 호출 - 원본 응답:', apiResponse); dlog('[ReviewFilters] 📥 extractReviewFiltersApiData 호출 - 원본 응답:', apiResponse);
let data = null; let data = null;
// ⭐ 핵심: retCode가 0인지 먼저 확인 (HTTP 200이어도 API 에러일 수 있음) // ⭐ 핵심: retCode가 0인지 먼저 확인 (HTTP 200이어도 API 에러일 수 있음)
// 응답 구조: { retCode: 0, retMsg: "Success", data: { reviewFilterInfos: {...} } } // 응답 구조: { retCode: 0, retMsg: "Success", data: { reviewFilterInfos: {...} } }
if (!apiResponse) { if (!apiResponse) {
console.warn('[ReviewFilters] ⚠️ apiResponse가 null/undefined'); dwarn('[ReviewFilters] ⚠️ apiResponse가 null/undefined');
return null; return null;
} }
const retCode = apiResponse.retCode; const retCode = apiResponse.retCode;
if (retCode !== 0) { if (retCode !== 0) {
console.error('[ReviewFilters] ❌ API 에러 - retCode !== 0:', { derror('[ReviewFilters] ❌ API 에러 - retCode !== 0:', {
retCode: retCode, retCode: retCode,
retMsg: apiResponse?.retMsg, retMsg: apiResponse?.retMsg,
fullResponse: apiResponse, fullResponse: apiResponse,
@@ -742,7 +750,7 @@ const extractReviewFiltersApiData = (apiResponse) => {
// reviewFilterInfos 추출: data.reviewFilterInfos // reviewFilterInfos 추출: data.reviewFilterInfos
const reviewFilterInfos = apiResponse.data?.reviewFilterInfos || {}; const reviewFilterInfos = apiResponse.data?.reviewFilterInfos || {};
console.log('[ReviewFilters] 🔍 reviewFilterInfos 분석:', { dlog('[ReviewFilters] 🔍 reviewFilterInfos 분석:', {
patnrId: reviewFilterInfos.patnrId, patnrId: reviewFilterInfos.patnrId,
prdtId: reviewFilterInfos.prdtId, prdtId: reviewFilterInfos.prdtId,
hasFilters: !!reviewFilterInfos.filters, hasFilters: !!reviewFilterInfos.filters,
@@ -753,11 +761,11 @@ const extractReviewFiltersApiData = (apiResponse) => {
data = reviewFilterInfos; data = reviewFilterInfos;
if (!data || !data.filters) { if (!data || !data.filters) {
console.warn('[ReviewFilters] ⚠️ filters가 없음:', apiResponse); dwarn('[ReviewFilters] ⚠️ filters가 없음:', apiResponse);
return null; return null;
} }
console.log('[ReviewFilters] ✅ 추출 완료:', { dlog('[ReviewFilters] ✅ 추출 완료:', {
patnrId: data.patnrId, patnrId: data.patnrId,
prdtId: data.prdtId, prdtId: data.prdtId,
filtersLength: data.filters.length, filtersLength: data.filters.length,
@@ -765,7 +773,7 @@ const extractReviewFiltersApiData = (apiResponse) => {
return data; return data;
} catch (error) { } catch (error) {
console.error('[ReviewFilters] ❌ extractReviewFiltersApiData 에러:', error); derror('[ReviewFilters] ❌ extractReviewFiltersApiData 에러:', error);
return null; return null;
} }
}; };
@@ -783,7 +791,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
const body = {}; const body = {};
console.log('[ReviewFilters] 🚀 API 요청 시작:', { dlog('[ReviewFilters] 🚀 API 요청 시작:', {
requestParams, requestParams,
params, params,
body, body,
@@ -796,7 +804,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
const retCode = response?.data?.retCode; const retCode = response?.data?.retCode;
const retMsg = response?.data?.retMsg; const retMsg = response?.data?.retMsg;
console.log('[ReviewFilters] ✅ API 응답 수신 (retCode 확인):', { dlog('[ReviewFilters] ✅ API 응답 수신 (retCode 확인):', {
httpStatus: response?.status, httpStatus: response?.status,
retCode: retCode, retCode: retCode,
retMsg: retMsg, retMsg: retMsg,
@@ -808,7 +816,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
const filtersData = extractReviewFiltersApiData(response.data); const filtersData = extractReviewFiltersApiData(response.data);
if (!filtersData) { if (!filtersData) {
console.warn('[ReviewFilters] ⚠️ 필터 데이터 추출 실패:', { dwarn('[ReviewFilters] ⚠️ 필터 데이터 추출 실패:', {
retCode: retCode, retCode: retCode,
retMsg: retMsg, retMsg: retMsg,
reason: retCode !== 0 ? 'retCode !== 0' : 'filters 데이터 없음', reason: retCode !== 0 ? 'retCode !== 0' : 'filters 데이터 없음',
@@ -816,7 +824,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
return; // 실패 시 dispatch하지 않음 return; // 실패 시 dispatch하지 않음
} }
console.log('[ReviewFilters] 📊 필터 데이터 추출 성공:', { dlog('[ReviewFilters] 📊 필터 데이터 추출 성공:', {
patnrId: filtersData.patnrId, patnrId: filtersData.patnrId,
prdtId: filtersData.prdtId, prdtId: filtersData.prdtId,
filtersLength: filtersData.filters ? filtersData.filters.length : 0, filtersLength: filtersData.filters ? filtersData.filters.length : 0,
@@ -831,7 +839,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
}, },
}; };
console.log('[ReviewFilters] 📦 Redux dispatch:', { dlog('[ReviewFilters] 📦 Redux dispatch:', {
actionType: types.GET_REVIEW_FILTERS, actionType: types.GET_REVIEW_FILTERS,
patnrId: patnrId, patnrId: patnrId,
prdtId: prdtId, prdtId: prdtId,
@@ -842,7 +850,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
}; };
const onFail = (error) => { const onFail = (error) => {
console.error('[ReviewFilters] ❌ API 실패:', { derror('[ReviewFilters] ❌ API 실패:', {
errorMessage: error?.message || '알 수 없는 에러', errorMessage: error?.message || '알 수 없는 에러',
errorType: typeof error, errorType: typeof error,
httpStatus: error?.response?.status, httpStatus: error?.response?.status,

View File

@@ -66,6 +66,21 @@ import Video from './Video';
import css from './VideoPlayer.module.less'; import css from './VideoPlayer.module.less';
import { updateVideoPlayState } from '../../actions/playActions'; import { updateVideoPlayState } from '../../actions/playActions';
// Toggle debug logging for this module
const DEBUG_MODE = false;
const dlog = (...args) => {
if (DEBUG_MODE) console.log(...args);
};
const dwarn = (...args) => {
if (DEBUG_MODE) console.warn(...args);
};
const derror = (...args) => {
console.error(...args);
};
const isEnter = is('enter'); const isEnter = is('enter');
const isLeft = is('left'); const isLeft = is('left');
const isRight = is('right'); const isRight = is('right');
@@ -1488,7 +1503,7 @@ const VideoPlayerBase = class extends React.Component {
sourceUnavailable: false, sourceUnavailable: false,
}; };
if (!el) { if (!el) {
console.log('yhcho VideoPlayer no el '); dlog('yhcho VideoPlayer no el ');
updatedState.error = true; updatedState.error = true;
this.setState(updatedState); this.setState(updatedState);
return; return;
@@ -1564,7 +1579,7 @@ const VideoPlayerBase = class extends React.Component {
// 가장 중요한 이벤트만 로그 // 가장 중요한 이벤트만 로그
const shouldLogEvent = ['play', 'pause', 'ended'].includes(ev.type); const shouldLogEvent = ['play', 'pause', 'ended'].includes(ev.type);
if (shouldLogEvent) { if (shouldLogEvent) {
console.log('🔄 [PlayerPanel][VideoPlayer] Event-driven Redux update', { dlog('🔄 [PlayerPanel][VideoPlayer] Event-driven Redux update', {
eventType: ev.type, eventType: ev.type,
videoState: updatedState, videoState: updatedState,
updateState, updateState,
@@ -1573,7 +1588,7 @@ const VideoPlayerBase = class extends React.Component {
} }
// 🔍 Redux dispatch 확인 // 🔍 Redux dispatch 확인
console.log('📤 [PlayerPanel][VideoPlayer] Dispatching Redux update', { dlog('📤 [PlayerPanel][VideoPlayer] Dispatching Redux update', {
eventType: ev.type, eventType: ev.type,
updateState, updateState,
hasDispatch: !!this.props.dispatch, hasDispatch: !!this.props.dispatch,
@@ -1583,7 +1598,7 @@ const VideoPlayerBase = class extends React.Component {
this.props.dispatch(updateVideoPlayState(updateState)); this.props.dispatch(updateVideoPlayState(updateState));
} }
} else { } else {
console.log('❌ [PlayerPanel][VideoPlayer] No dispatch prop available', { derror('❌ [PlayerPanel][VideoPlayer] No dispatch prop available', {
props: Object.keys(this.props), props: Object.keys(this.props),
hasDispatch: !!this.props.dispatch, hasDispatch: !!this.props.dispatch,
hasVideoPlayState: !!this.props.videoPlayState, hasVideoPlayState: !!this.props.videoPlayState,
@@ -1595,7 +1610,7 @@ const VideoPlayerBase = class extends React.Component {
if (this.props.videoPlayState && typeof this.props.videoPlayState === 'object') { if (this.props.videoPlayState && typeof this.props.videoPlayState === 'object') {
// Redux 상태 디버깅 (최소한의 중요 이벤트만) // Redux 상태 디버깅 (최소한의 중요 이벤트만)
if (ev.type === 'play' || ev.type === 'pause') { if (ev.type === 'play' || ev.type === 'pause') {
console.log('🔍 [PlayerPanel][VideoPlayer] Redux state debug', { dlog('🔍 [PlayerPanel][VideoPlayer] Redux state debug', {
videoPlayState: this.props.videoPlayState, videoPlayState: this.props.videoPlayState,
isPaused: this.props.videoPlayState?.isPaused, isPaused: this.props.videoPlayState?.isPaused,
isPlaying: this.props.videoPlayState?.isPlaying, isPlaying: this.props.videoPlayState?.isPlaying,
@@ -1624,7 +1639,7 @@ const VideoPlayerBase = class extends React.Component {
// 중요한 상태 변화가 있고 빈번한 이벤트가 아닐 때만 로그 // 중요한 상태 변화가 있고 빈번한 이벤트가 아닐 때만 로그
if (hasSignificantChange && !isFrequentEvent) { if (hasSignificantChange && !isFrequentEvent) {
console.log('🔄 [PlayerPanel][VideoPlayer] Syncing internal state with Redux', { dlog('🔄 [PlayerPanel][VideoPlayer] Syncing internal state with Redux', {
timeDiff, timeDiff,
shouldUpdateTime, shouldUpdateTime,
pausedDiff: paused !== this.state.paused, pausedDiff: paused !== this.state.paused,
@@ -1703,7 +1718,7 @@ const VideoPlayerBase = class extends React.Component {
* @public * @public
*/ */
play = () => { play = () => {
console.log('🟢 [PlayerPanel][VideoPlayer] play() called', { dlog('🟢 [PlayerPanel][VideoPlayer] play() called', {
currentTime: this.state.currentTime, currentTime: this.state.currentTime,
duration: this.state.duration, duration: this.state.duration,
paused: this.state.paused, paused: this.state.paused,
@@ -1712,7 +1727,7 @@ const VideoPlayerBase = class extends React.Component {
}); });
if (this.state.sourceUnavailable) { if (this.state.sourceUnavailable) {
console.log('⚠️ [PlayerPanel][VideoPlayer] play() aborted - source unavailable'); dwarn('⚠️ [PlayerPanel][VideoPlayer] play() aborted - source unavailable');
return; return;
} }
@@ -1747,7 +1762,7 @@ const VideoPlayerBase = class extends React.Component {
* @public * @public
*/ */
pause = () => { pause = () => {
console.log('🔴 [VideoPlayer] pause() called', { dlog('🔴 [VideoPlayer] pause() called', {
currentTime: this.state.currentTime, currentTime: this.state.currentTime,
duration: this.state.duration, duration: this.state.duration,
paused: this.state.paused, paused: this.state.paused,
@@ -1756,7 +1771,7 @@ const VideoPlayerBase = class extends React.Component {
}); });
if (this.state.sourceUnavailable) { if (this.state.sourceUnavailable) {
console.log('⚠️ [VideoPlayer] pause() aborted - source unavailable'); dwarn('⚠️ [VideoPlayer] pause() aborted - source unavailable');
return; return;
} }
@@ -1779,10 +1794,10 @@ const VideoPlayerBase = class extends React.Component {
playbackRate: 1, playbackRate: 1,
}; };
console.log('📤 [VideoPlayer] Dispatching pause state', pauseState); dlog('📤 [VideoPlayer] Dispatching pause state', pauseState);
this.props.dispatch(updateVideoPlayState(pauseState)); this.props.dispatch(updateVideoPlayState(pauseState));
} else { } else {
console.log('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated'); dwarn('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated');
} }
}; };
@@ -1795,7 +1810,7 @@ const VideoPlayerBase = class extends React.Component {
* @public * @public
*/ */
seek = (timeIndex) => { seek = (timeIndex) => {
console.log('⏩ [VideoPlayer] seek() called', { dlog('⏩ [VideoPlayer] seek() called', {
timeIndex, timeIndex,
currentTime: this.state.currentTime, currentTime: this.state.currentTime,
duration: this.state.duration, duration: this.state.duration,
@@ -1815,7 +1830,7 @@ const VideoPlayerBase = class extends React.Component {
timeIndex >= this.video.duration ? this.video.duration - 1 : timeIndex; timeIndex >= this.video.duration ? this.video.duration - 1 : timeIndex;
this.video.currentTime = actualSeekTime; this.video.currentTime = actualSeekTime;
console.log('⏩ [VideoPlayer] Video seek completed', { dlog('⏩ [VideoPlayer] Video seek completed', {
requestedTime: timeIndex, requestedTime: timeIndex,
actualTime: actualSeekTime, actualTime: actualSeekTime,
videoDuration: this.video.duration, videoDuration: this.video.duration,
@@ -1831,17 +1846,17 @@ const VideoPlayerBase = class extends React.Component {
playbackRate: this.state.playbackRate, playbackRate: this.state.playbackRate,
}; };
console.log('📤 [VideoPlayer] Dispatching seek state', seekState); dlog('📤 [VideoPlayer] Dispatching seek state', seekState);
this.props.dispatch(updateVideoPlayState(seekState)); this.props.dispatch(updateVideoPlayState(seekState));
} else { } else {
console.log('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated'); dwarn('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated');
} }
} else { } else {
console.log('❌ [VideoPlayer] seek failed - disabled or source unavailable'); derror('❌ [VideoPlayer] seek failed - disabled or source unavailable');
forward('onSeekFailed', {}, this.props); forward('onSeekFailed', {}, this.props);
} }
} else { } else {
console.log('❌ [VideoPlayer] seek failed - no video element'); derror('❌ [VideoPlayer] seek failed - no video element');
} }
}; };

View File

@@ -1,6 +1,21 @@
import { types } from '../actions/actionTypes'; import { types } from '../actions/actionTypes';
import { panel_names } from '../utils/Config'; import { panel_names } from '../utils/Config';
// Toggle debug logging for this reducer
const DEBUG_MODE = false;
const dlog = (...args) => {
if (DEBUG_MODE) console.log(...args);
};
const dwarn = (...args) => {
if (DEBUG_MODE) console.warn(...args);
};
const derror = (...args) => {
console.error(...args);
};
const initialState = { const initialState = {
// 기존 상태 - 완전히 호환됨 // 기존 상태 - 완전히 호환됨
panels: [], panels: [],
@@ -29,7 +44,7 @@ const forceTopPanels = [panel_names.ERROR_PANEL, panel_names.INTRO_PANEL, panel_
export const panelsReducer = (state = initialState, action) => { export const panelsReducer = (state = initialState, action) => {
switch (action.type) { switch (action.type) {
case types.PUSH_PANEL: { case types.PUSH_PANEL: {
console.log('[panelReducer] 🔵 PUSH_PANEL START', { dlog('[panelReducer] 🔵 PUSH_PANEL START', {
newPanelName: action.payload.name, newPanelName: action.payload.name,
currentPanels: state.panels.map((p) => p.name), currentPanels: state.panels.map((p) => p.name),
duplicatable: action.duplicatable, duplicatable: action.duplicatable,
@@ -76,7 +91,7 @@ export const panelsReducer = (state = initialState, action) => {
} }
} }
console.log('[panelReducer] 🔵 PUSH_PANEL END', { dlog('[panelReducer] 🔵 PUSH_PANEL END', {
resultPanels: newState.map((p) => p.name), resultPanels: newState.map((p) => p.name),
lastAction, lastAction,
}); });
@@ -89,7 +104,7 @@ export const panelsReducer = (state = initialState, action) => {
} }
case types.POP_PANEL: { case types.POP_PANEL: {
console.log('[panelReducer] 🔴 POP_PANEL START', { dlog('[panelReducer] 🔴 POP_PANEL START', {
targetPanel: action.payload || 'last_panel', targetPanel: action.payload || 'last_panel',
currentPanels: state.panels.map((p) => p.name), currentPanels: state.panels.map((p) => p.name),
}); });
@@ -113,7 +128,7 @@ export const panelsReducer = (state = initialState, action) => {
resultPanels = state.panels.slice(0, state.panels.length - 1); resultPanels = state.panels.slice(0, state.panels.length - 1);
} }
console.log('[panelReducer] 🔴 POP_PANEL END', { dlog('[panelReducer] 🔴 POP_PANEL END', {
resultPanels: resultPanels.map((p) => p.name), resultPanels: resultPanels.map((p) => p.name),
lastAction, lastAction,
}); });
@@ -159,7 +174,7 @@ export const panelsReducer = (state = initialState, action) => {
}; };
} }
case types.RESET_PANELS: { case types.RESET_PANELS: {
console.log('[panelReducer] 🟢 RESET_PANELS START', { dlog('[panelReducer] 🟢 RESET_PANELS START', {
currentPanels: state.panels.map((p) => p.name), currentPanels: state.panels.map((p) => p.name),
payloadProvided: !!action.payload, payloadProvided: !!action.payload,
}); });
@@ -171,7 +186,7 @@ export const panelsReducer = (state = initialState, action) => {
})) }))
: []; : [];
console.log('[panelReducer] 🟢 RESET_PANELS END', { dlog('[panelReducer] 🟢 RESET_PANELS END', {
resultPanels: updatedPanels.map((p) => p.name), resultPanels: updatedPanels.map((p) => p.name),
}); });
@@ -184,7 +199,7 @@ export const panelsReducer = (state = initialState, action) => {
// [251106] 패널 액션 큐 관련 reducer 케이스들 // [251106] 패널 액션 큐 관련 reducer 케이스들
case types.ENQUEUE_PANEL_ACTION: { case types.ENQUEUE_PANEL_ACTION: {
console.log('[panelReducer] 🟠 ENQUEUE_PANEL_ACTION', { dlog('[panelReducer] 🟠 ENQUEUE_PANEL_ACTION', {
action: action.payload.action, action: action.payload.action,
queueId: action.payload.id, queueId: action.payload.id,
currentQueueLength: state.panelActionQueue.length, currentQueueLength: state.panelActionQueue.length,
@@ -201,7 +216,7 @@ export const panelsReducer = (state = initialState, action) => {
} }
case types.PROCESS_PANEL_QUEUE: { case types.PROCESS_PANEL_QUEUE: {
console.log('[panelReducer] 🟡 PROCESS_PANEL_QUEUE', { dlog('[panelReducer] 🟡 PROCESS_PANEL_QUEUE', {
isProcessing: state.isProcessingQueue, isProcessing: state.isProcessingQueue,
queueLength: state.panelActionQueue.length, queueLength: state.panelActionQueue.length,
}); });
@@ -215,7 +230,7 @@ export const panelsReducer = (state = initialState, action) => {
const firstQueueItem = state.panelActionQueue[0]; const firstQueueItem = state.panelActionQueue[0];
const remainingQueue = state.panelActionQueue.slice(1); const remainingQueue = state.panelActionQueue.slice(1);
console.log('[panelReducer] 🟡 PROCESSING_QUEUE_ITEM', { dlog('[panelReducer] 🟡 PROCESSING_QUEUE_ITEM', {
action: firstQueueItem.action, action: firstQueueItem.action,
queueId: firstQueueItem.id, queueId: firstQueueItem.id,
remainingQueueLength: remainingQueue.length, remainingQueueLength: remainingQueue.length,
@@ -261,7 +276,7 @@ export const panelsReducer = (state = initialState, action) => {
break; break;
} }
default: default:
console.warn('[panelReducer] ⚠️ UNKNOWN_QUEUE_ACTION', firstQueueItem.action); dwarn('[panelReducer] ⚠️ UNKNOWN_QUEUE_ACTION', firstQueueItem.action);
newState = state; newState = state;
} }
@@ -272,7 +287,7 @@ export const panelsReducer = (state = initialState, action) => {
processingTime) / processingTime) /
newTotalProcessed; newTotalProcessed;
console.log('[panelReducer] ✅ QUEUE_ITEM_PROCESSED', { dlog('[panelReducer] ✅ QUEUE_ITEM_PROCESSED', {
action: firstQueueItem.action, action: firstQueueItem.action,
queueId: firstQueueItem.id, queueId: firstQueueItem.id,
processingTime, processingTime,
@@ -290,7 +305,7 @@ export const panelsReducer = (state = initialState, action) => {
}, },
}; };
} catch (error) { } catch (error) {
console.error('[panelReducer] ❌ QUEUE_PROCESSING_ERROR', { derror('[panelReducer] ❌ QUEUE_PROCESSING_ERROR', {
action: firstQueueItem.action, action: firstQueueItem.action,
queueId: firstQueueItem.id, queueId: firstQueueItem.id,
error: error.message, error: error.message,
@@ -315,7 +330,7 @@ export const panelsReducer = (state = initialState, action) => {
} }
case types.CLEAR_PANEL_QUEUE: { case types.CLEAR_PANEL_QUEUE: {
console.log('[panelReducer] 🔵 CLEAR_PANEL_QUEUE', { dlog('[panelReducer] 🔵 CLEAR_PANEL_QUEUE', {
currentQueueLength: state.panelActionQueue.length, currentQueueLength: state.panelActionQueue.length,
}); });
@@ -328,7 +343,7 @@ export const panelsReducer = (state = initialState, action) => {
} }
case types.SET_QUEUE_PROCESSING: { case types.SET_QUEUE_PROCESSING: {
console.log('[panelReducer] 🟣 SET_QUEUE_PROCESSING', { dlog('[panelReducer] 🟣 SET_QUEUE_PROCESSING', {
isProcessing: action.payload.isProcessing, isProcessing: action.payload.isProcessing,
queueLength: state.panelActionQueue.length, queueLength: state.panelActionQueue.length,
}); });
@@ -341,7 +356,7 @@ export const panelsReducer = (state = initialState, action) => {
// [251106] 비동기 패널 액션 관련 reducer 케이스들 // [251106] 비동기 패널 액션 관련 reducer 케이스들
case types.ENQUEUE_ASYNC_PANEL_ACTION: { case types.ENQUEUE_ASYNC_PANEL_ACTION: {
console.log('[panelReducer] 🟠 ENQUEUE_ASYNC_PANEL_ACTION', { dlog('[panelReducer] 🟠 ENQUEUE_ASYNC_PANEL_ACTION', {
actionId: action.payload.id, actionId: action.payload.id,
timestamp: action.payload.timestamp, timestamp: action.payload.timestamp,
}); });
@@ -361,7 +376,7 @@ export const panelsReducer = (state = initialState, action) => {
} }
case types.COMPLETE_ASYNC_PANEL_ACTION: { case types.COMPLETE_ASYNC_PANEL_ACTION: {
console.log('[panelReducer] ✅ COMPLETE_ASYNC_PANEL_ACTION', { dlog('[panelReducer] ✅ COMPLETE_ASYNC_PANEL_ACTION', {
actionId: action.payload.actionId, actionId: action.payload.actionId,
timestamp: action.payload.timestamp, timestamp: action.payload.timestamp,
}); });
@@ -401,7 +416,7 @@ export const panelsReducer = (state = initialState, action) => {
} }
case types.FAIL_ASYNC_PANEL_ACTION: { case types.FAIL_ASYNC_PANEL_ACTION: {
console.log('[panelReducer] ❌ FAIL_ASYNC_PANEL_ACTION', { derror('[panelReducer] ❌ FAIL_ASYNC_PANEL_ACTION', {
actionId: action.payload.actionId, actionId: action.payload.actionId,
error: action.payload.error?.message || 'Unknown error', error: action.payload.error?.message || 'Unknown error',
timestamp: action.payload.timestamp, timestamp: action.payload.timestamp,
@@ -440,7 +455,7 @@ export const panelsReducer = (state = initialState, action) => {
// [251114] 명시적 포커스 이동 // [251114] 명시적 포커스 이동
case types.FOCUS_PANEL: { case types.FOCUS_PANEL: {
console.log('[panelReducer] 🎯 FOCUS_PANEL', { dlog('[panelReducer] 🎯 FOCUS_PANEL', {
panelName: action.payload.panelName, panelName: action.payload.panelName,
focusTarget: action.payload.focusTarget, focusTarget: action.payload.focusTarget,
timestamp: action.payload.timestamp, timestamp: action.payload.timestamp,

View File

@@ -66,6 +66,21 @@ import TabContainerV2 from './PlayerTabContents/v2/TabContainer.v2';
const Container = SpotlightContainerDecorator({ enterTo: 'last-focused', preserveId: true }, 'div'); const Container = SpotlightContainerDecorator({ enterTo: 'last-focused', preserveId: true }, 'div');
// Toggle debug logging for this view
const DEBUG_MODE = false;
const dlog = (...args) => {
if (DEBUG_MODE) console.log(...args);
};
const dwarn = (...args) => {
if (DEBUG_MODE) console.warn(...args);
};
const derror = (...args) => {
console.error(...args);
};
const findSelector = (selector, maxAttempts = 5, currentAttempts = 0) => { const findSelector = (selector, maxAttempts = 5, currentAttempts = 0) => {
try { try {
if (currentAttempts >= maxAttempts) { if (currentAttempts >= maxAttempts) {
@@ -363,7 +378,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// PlayerPanel.jsx의 라인 313-327 useEffect 수정 - detailPanelClosed flag 감지 추가 // PlayerPanel.jsx의 라인 313-327 useEffect 수정 - detailPanelClosed flag 감지 추가
useEffect(() => { useEffect(() => {
console.log('[PlayerPanel] 🔍 isOnTop useEffect 호출:', { dlog('[PlayerPanel] 🔍 isOnTop useEffect 호출:', {
isOnTop, isOnTop,
modal: panelInfo?.modal, modal: panelInfo?.modal,
isPaused: panelInfo?.isPaused, isPaused: panelInfo?.isPaused,
@@ -374,18 +389,18 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 1. Resume Video if needed (isPaused or detailPanelClosed) // 1. Resume Video if needed (isPaused or detailPanelClosed)
if (panelInfo.isPaused || panelInfo.detailPanelClosed) { if (panelInfo.isPaused || panelInfo.detailPanelClosed) {
if (panelInfo.modal) { if (panelInfo.modal) {
console.log('[PlayerPanel] ▶️ Back on top (Modal) - resuming video'); dlog('[PlayerPanel] ▶️ Back on top (Modal) - resuming video');
dispatch(resumeModalVideo()); dispatch(resumeModalVideo());
} else { } else {
console.log('[PlayerPanel] ▶️ Back on top (Fullscreen) - resuming video'); dlog('[PlayerPanel] ▶️ Back on top (Fullscreen) - resuming video');
dispatch(resumeFullscreenVideo()); dispatch(resumeFullscreenVideo());
} }
} }
// 2. Reset detailPanelClosed flag // 2. Reset detailPanelClosed flag
if (panelInfo.detailPanelClosed) { if (panelInfo.detailPanelClosed) {
console.log('[PlayerPanel] 🔄 detailPanelClosed flag 초기화 시작'); dlog('[PlayerPanel] 🔄 detailPanelClosed flag 초기화 시작');
console.log('[PlayerPanel] 🔙 DetailPanel에서 복귀 정보:', { dlog('[PlayerPanel] 🔙 DetailPanel에서 복귀 정보:', {
detailPanelClosedAt: panelInfo.detailPanelClosedAt, detailPanelClosedAt: panelInfo.detailPanelClosedAt,
detailPanelClosedFromSource: panelInfo.detailPanelClosedFromSource, detailPanelClosedFromSource: panelInfo.detailPanelClosedFromSource,
lastFocusedTargetId: panelInfo.lastFocusedTargetId, lastFocusedTargetId: panelInfo.lastFocusedTargetId,
@@ -393,13 +408,13 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 포커스 복원 로직 추가 (1000ms 지연) // 포커스 복원 로직 추가 (1000ms 지연)
if (panelInfo.lastFocusedTargetId) { if (panelInfo.lastFocusedTargetId) {
console.log( dlog(
'[PlayerPanel] 🎯 DetailPanel 복귀 후 1000ms 지연 포커스 복원 예약:', '[PlayerPanel] 🎯 DetailPanel 복귀 후 1000ms 지연 포커스 복원 예약:',
panelInfo.lastFocusedTargetId panelInfo.lastFocusedTargetId
); );
const focusTimeoutId = setTimeout(() => { const focusTimeoutId = setTimeout(() => {
console.log( dlog(
'[PlayerPanel] 🔍 DetailPanel 복귀 후 포커스 복원 실행:', '[PlayerPanel] 🔍 DetailPanel 복귀 후 포커스 복원 실행:',
panelInfo.lastFocusedTargetId panelInfo.lastFocusedTargetId
); );
@@ -410,7 +425,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
return () => { return () => {
if (focusTimeoutId) { if (focusTimeoutId) {
clearTimeout(focusTimeoutId); clearTimeout(focusTimeoutId);
console.log('[PlayerPanel] 🧹 포커스 복원 타이머 정리됨'); dlog('[PlayerPanel] 🧹 포커스 복원 타이머 정리됨');
} }
}; };
} }
@@ -426,12 +441,12 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
}, },
}) })
); );
console.log('[PlayerPanel] 🏁 detailPanelClosed flag 초기화 완료'); dlog('[PlayerPanel] 🏁 detailPanelClosed flag 초기화 완료');
} }
} else { } else {
// Not on top // Not on top
if (panelInfo && panelInfo.modal) { if (panelInfo && panelInfo.modal) {
console.log('[PlayerPanel] ⏸️ Not on top (Modal) - pausing video logic commented out'); dlog('[PlayerPanel] ⏸️ Not on top (Modal) - pausing video logic commented out');
// dispatch(pauseModalVideo()); // dispatch(pauseModalVideo());
} }
} }
@@ -464,7 +479,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
(isOnTop && videoPlayState && hasSignificantChange) || (isOnTop && videoPlayState && hasSignificantChange) ||
(isDetailPanelOnTop && (isPlayingChanged || isPausedChanged)) (isDetailPanelOnTop && (isPlayingChanged || isPausedChanged))
) { ) {
console.log('📊 [PlayerPanel] Significant videoPlayState change', { dlog('📊 [PlayerPanel] Significant videoPlayState change', {
previousState: previousVideoPlayState.current, previousState: previousVideoPlayState.current,
currentState: videoPlayState, currentState: videoPlayState,
topPanelName: topPanel?.name, topPanelName: topPanel?.name,
@@ -492,7 +507,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (isOnTop && panelInfo?.isPaused !== undefined && isPausedChanged) { if (isOnTop && panelInfo?.isPaused !== undefined && isPausedChanged) {
// 상태 변경 시에만 디버깅 로그 출력 // 상태 변경 시에만 디버깅 로그 출력
console.log('🔍 [PlayerPanel] PanelInfo isPaused changed', { dlog('🔍 [PlayerPanel] PanelInfo isPaused changed', {
previousIsPaused: previousPanelInfo.current?.isPaused, previousIsPaused: previousPanelInfo.current?.isPaused,
currentIsPaused: panelInfo.isPaused, currentIsPaused: panelInfo.isPaused,
isOnTop, isOnTop,
@@ -500,7 +515,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
currentPlayingUrl, currentPlayingUrl,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}); });
console.log('🎮 [PlayerPanel] PanelInfo isPaused changed', { dlog('🎮 [PlayerPanel] PanelInfo isPaused changed', {
previousIsPaused: previousPanelInfo.current?.isPaused, previousIsPaused: previousPanelInfo.current?.isPaused,
currentIsPaused: panelInfo.isPaused, currentIsPaused: panelInfo.isPaused,
videoPlayerExists: !!videoPlayer.current, videoPlayerExists: !!videoPlayer.current,
@@ -513,10 +528,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (videoPlayer.current) { if (videoPlayer.current) {
if (panelInfo.isPaused === true) { if (panelInfo.isPaused === true) {
console.log('🔴 [PlayerPanel] Calling VideoPlayer.pause() due to PanelInfo change'); dlog('🔴 [PlayerPanel] Calling VideoPlayer.pause() due to PanelInfo change');
videoPlayer.current.pause(); videoPlayer.current.pause();
} else if (panelInfo.isPaused === false) { } else if (panelInfo.isPaused === false) {
console.log('🟢 [PlayerPanel] Calling VideoPlayer.play() due to PanelInfo change'); dlog('🟢 [PlayerPanel] Calling VideoPlayer.play() due to PanelInfo change');
videoPlayer.current.play(); videoPlayer.current.play();
} }
} }
@@ -550,7 +565,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
? 'Top panel changed' ? 'Top panel changed'
: 'VideoPlayer created'; : 'VideoPlayer created';
console.log('🎬 [PlayerPanel] VideoPlayer state change', { dlog('🎬 [PlayerPanel] VideoPlayer state change', {
hasVideoPlayer: !!videoPlayer.current, hasVideoPlayer: !!videoPlayer.current,
currentPlayingUrl, currentPlayingUrl,
previousVideoSource: previousVideoSource.current, previousVideoSource: previousVideoSource.current,
@@ -570,7 +585,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (isVideoSourceChanged || videoPlayerJustCreated || isDetailPanelOnTopChanged) { if (isVideoSourceChanged || videoPlayerJustCreated || isDetailPanelOnTopChanged) {
const mediaState = videoPlayer.current.getMediaState?.(); const mediaState = videoPlayer.current.getMediaState?.();
if (mediaState) { if (mediaState) {
console.log('📊 [PlayerPanel] VideoPlayer current state', { dlog('📊 [PlayerPanel] VideoPlayer current state', {
mediaState, mediaState,
videoPlayState, videoPlayState,
changeReason, changeReason,
@@ -590,7 +605,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const currentModalState = panelInfo?.modal; const currentModalState = panelInfo?.modal;
const prevModalState = modalPrevRef.current; const prevModalState = modalPrevRef.current;
console.log('[PlayerPanel] 🔍 Modal 상태 체크:', { dlog('[PlayerPanel] 🔍 Modal 상태 체크:', {
prevModalState, prevModalState,
currentModalState, currentModalState,
shouldExecuteTrueToFalse: prevModalState === true && currentModalState === false, shouldExecuteTrueToFalse: prevModalState === true && currentModalState === false,
@@ -599,8 +614,8 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// true → false 변화 감지 // true → false 변화 감지
if (prevModalState === true && currentModalState === false) { if (prevModalState === true && currentModalState === false) {
console.log('[PlayerPanel] ▶️ Modal 상태 변화: true → false (전체화면 모드로 복귀)'); dlog('[PlayerPanel] ▶️ Modal 상태 변화: true → false (전체화면 모드로 복귀)');
console.log( dlog(
'[PlayerPanel] 🎯 포커스 복원 준비 - lastFocusedTargetId:', '[PlayerPanel] 🎯 포커스 복원 준비 - lastFocusedTargetId:',
panelInfo?.lastFocusedTargetId panelInfo?.lastFocusedTargetId
); );
@@ -612,7 +627,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (lastFocusedTargetId) { if (lastFocusedTargetId) {
// ShopNowContents가 렌더링될 때까지 대기 후 포커스 복원 // ShopNowContents가 렌더링될 때까지 대기 후 포커스 복원
setTimeout(() => { setTimeout(() => {
console.log('[PlayerPanel] 🔍 800ms 후 포커스 복원 시도:', lastFocusedTargetId); dlog('[PlayerPanel] 🔍 800ms 후 포커스 복원 시도:', lastFocusedTargetId);
Spotlight.focus(lastFocusedTargetId); Spotlight.focus(lastFocusedTargetId);
}, 800); }, 800);
} }
@@ -620,7 +635,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// false → true 변화 감지 (모달이 열림) // false → true 변화 감지 (모달이 열림)
if (prevModalState === false && currentModalState === true) { if (prevModalState === false && currentModalState === true) {
console.log('[PlayerPanel] 📱 Modal 상태 변화: false → true (모달 열림)'); dlog('[PlayerPanel] 📱 Modal 상태 변화: false → true (모달 열림)');
setIsModalClosed(false); // 모달이 열렸음을 표시 setIsModalClosed(false); // 모달이 열렸음을 표시
} }
@@ -1273,7 +1288,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 🔍 DetailPanel 상태 변화 로깅 // 🔍 DetailPanel 상태 변화 로깅
if (result) { if (result) {
console.log('🎬 [PlayerPanel] DetailPanel is now on top (from Player)', { dlog('🎬 [PlayerPanel] DetailPanel is now on top (from Player)', {
topPanelName: topPanel?.name, topPanelName: topPanel?.name,
launchedFromPlayer: topPanel?.panelInfo?.launchedFromPlayer, launchedFromPlayer: topPanel?.panelInfo?.launchedFromPlayer,
modalPlayerPanelExists: panels.some( modalPlayerPanelExists: panels.some(
@@ -1299,7 +1314,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// PlayerPanel이 modal이고 밑에 깔렸을 때 // PlayerPanel이 modal이고 밑에 깔렸을 때
if (isModalPlayerPanel && !isCurrentPanelOnTop && isDetailPanelOnTop) { if (isModalPlayerPanel && !isCurrentPanelOnTop && isDetailPanelOnTop) {
console.log('🔴 [PlayerPanel] Self-pausing due to DetailPanel on top', { dlog('🔴 [PlayerPanel] Self-pausing due to DetailPanel on top', {
isDetailPanelOnTop, isDetailPanelOnTop,
isModalPlayerPanel, isModalPlayerPanel,
isCurrentPanelOnTop, isCurrentPanelOnTop,
@@ -1310,7 +1325,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// PlayerPanel 자신의 상태를 일시정지로 업데이트 // PlayerPanel 자신의 상태를 일시정지로 업데이트
if (videoPlayState?.isPlaying === true || videoPlayState?.isPaused === false) { if (videoPlayState?.isPlaying === true || videoPlayState?.isPaused === false) {
console.log('🔄 [PlayerPanel] Dispatching self-pause to Redux'); dlog('🔄 [PlayerPanel] Dispatching self-pause to Redux');
dispatch( dispatch(
updateVideoPlayState({ updateVideoPlayState({
isPlaying: false, isPlaying: false,
@@ -1404,7 +1419,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
} }
} else { } else {
// showId가 일치하지 않으면 이전 상태를 재활용하지 않고 초기화 // showId가 일치하지 않으면 이전 상태를 재활용하지 않고 초기화
console.log('[PlayerPanel] VOD showDetailInfo mismatch. Clearing playListInfo.', { dlog('[PlayerPanel] VOD showDetailInfo mismatch. Clearing playListInfo.', {
panelInfoShowId: panelInfo.showId, panelInfoShowId: panelInfo.showId,
showDetailInfoId: showDetailInfo[0]?.showId, showDetailInfoId: showDetailInfo[0]?.showId,
}); });
@@ -1686,7 +1701,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
(ev) => { (ev) => {
const type = ev.type; const type = ev.type;
if (type !== 'timeupdate' && type !== 'durationchange') { if (type !== 'timeupdate' && type !== 'durationchange') {
console.log('mediainfoHandler....', type, ev, videoPlayer.current?.getMediaState()); dlog('mediainfoHandler....', type, ev, videoPlayer.current?.getMediaState());
} }
if (ev === 'hlsError' && isNaN(Number(videoPlayer.current?.getMediaState().playbackRate))) { if (ev === 'hlsError' && isNaN(Number(videoPlayer.current?.getMediaState().playbackRate))) {
dispatch( dispatch(
@@ -1717,7 +1732,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const mediaId = videoPlayer.current?.video?.media?.mediaId; const mediaId = videoPlayer.current?.video?.media?.mediaId;
setMediaId(mediaId); setMediaId(mediaId);
setVideoLoaded(true); setVideoLoaded(true);
console.log( dlog(
'[PlayerPanel] 🎬 Video Loaded - shptmBanrTpNm:', '[PlayerPanel] 🎬 Video Loaded - shptmBanrTpNm:',
panelInfoRef.current?.shptmBanrTpNm panelInfoRef.current?.shptmBanrTpNm
); );
@@ -1751,7 +1766,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
useEffect(() => { useEffect(() => {
// 복구 직후: skipModalStyleRecalculation이 true면 저장된 modalStyle 적용 // 복구 직후: skipModalStyleRecalculation이 true면 저장된 modalStyle 적용
if (panelInfo.skipModalStyleRecalculation && !panelInfo.shouldShrinkTo1px) { if (panelInfo.skipModalStyleRecalculation && !panelInfo.shouldShrinkTo1px) {
console.log('[PlayerPanel] Condition 2.5: Using saved modalStyle from expand'); dlog('[PlayerPanel] Condition 2.5: Using saved modalStyle from expand');
const shrinkInfo = panelInfo.playerState?.shrinkInfo; const shrinkInfo = panelInfo.playerState?.shrinkInfo;
// 저장된 modalStyle 사용 (top, left 포함) // 저장된 modalStyle 사용 (top, left 포함)
@@ -1767,7 +1782,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
console.log('[PlayerPanel] Condition 2.5: Removing skipFlag after DOM render'); dlog('[PlayerPanel] Condition 2.5: Removing skipFlag after DOM render');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
@@ -1788,7 +1803,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
panelInfo.modalContainerId && panelInfo.modalContainerId &&
(lastPanelAction === 'previewPush' || lastPanelAction === 'previewUpdate') (lastPanelAction === 'previewPush' || lastPanelAction === 'previewUpdate')
) { ) {
console.log('[PlayerPanel] Condition 1: Calculating modalStyle from DOM', { dlog('[PlayerPanel] Condition 1: Calculating modalStyle from DOM', {
lastPanelAction, lastPanelAction,
}); });
const node = document.querySelector(`[data-spotlight-id="${panelInfo.modalContainerId}"]`); const node = document.querySelector(`[data-spotlight-id="${panelInfo.modalContainerId}"]`);
@@ -1815,17 +1830,17 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
}) })
); );
} else { } else {
console.log('[PlayerPanel] Condition 1: Node not found, using saved modalStyle'); dlog('[PlayerPanel] Condition 1: Node not found, using saved modalStyle');
setModalStyle(panelInfo.modalStyle); setModalStyle(panelInfo.modalStyle);
setModalScale(panelInfo.modalScale); setModalScale(panelInfo.modalScale);
} }
} else if (panelInfo.shouldShrinkTo1px) { } else if (panelInfo.shouldShrinkTo1px) {
console.log('[PlayerPanel] Condition 2: Shrinking - clearing modalStyle'); dlog('[PlayerPanel] Condition 2: Shrinking - clearing modalStyle');
// 축소 상태: 인라인 스타일 제거 (CSS만 적용) // 축소 상태: 인라인 스타일 제거 (CSS만 적용)
setModalStyle({}); setModalStyle({});
setModalScale(1); setModalScale(1);
} else if (isOnTop && !panelInfo.modal && videoPlayer.current) { } else if (isOnTop && !panelInfo.modal && videoPlayer.current) {
console.log('[PlayerPanel] Condition 3: Playing fullscreen video'); dlog('[PlayerPanel] Condition 3: Playing fullscreen video');
if (videoPlayer.current?.getMediaState()?.paused) { if (videoPlayer.current?.getMediaState()?.paused) {
videoPlayer.current.play(); videoPlayer.current.play();
} }
@@ -1923,7 +1938,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 비디오가 새로 선택될 때 타이머 초기화 // 비디오가 새로 선택될 때 타이머 초기화
useEffect(() => { useEffect(() => {
if (currentPlayingUrl) { if (currentPlayingUrl) {
console.log('[PlayerPanel] 🎬 비디오 선택됨 - tabIndexV2 타이머 초기화'); dlog('[PlayerPanel] 🎬 비디오 선택됨 - tabIndexV2 타이머 초기화');
resetTimerTabAutoAdvance(10000); resetTimerTabAutoAdvance(10000);
} }
}, [selectedIndex, resetTimerTabAutoAdvance]); }, [selectedIndex, resetTimerTabAutoAdvance]);
@@ -2322,10 +2337,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const clearTimerV2 = useCallback(() => { const clearTimerV2 = useCallback(() => {
if (timerIdV2.current) { if (timerIdV2.current) {
console.log('[clearTimerV2] 타이머 클리어됨'); dlog('[clearTimerV2] 타이머 클리어됨');
const stack = new Error().stack; const stack = new Error().stack;
const lines = stack.split('\n').slice(1, 4).join(' → '); const lines = stack.split('\n').slice(1, 4).join(' → ');
console.log('[clearTimerV2] 호출 스택:', lines); dlog('[clearTimerV2] 호출 스택:', lines);
} }
clearTimeout(timerIdV2.current); clearTimeout(timerIdV2.current);
timerIdV2.current = null; timerIdV2.current = null;
@@ -2333,19 +2348,19 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const resetTimerV2 = useCallback( const resetTimerV2 = useCallback(
(timeout) => { (timeout) => {
console.log('[TabContainerV2] resetTimerV2 호출', timeout); dlog('[TabContainerV2] resetTimerV2 호출', timeout);
if (timerIdV2.current) { if (timerIdV2.current) {
console.log('[TabContainerV2] 기존 타이머 클리어'); dlog('[TabContainerV2] 기존 타이머 클리어');
clearTimerV2(); clearTimerV2();
} }
if (initialEnterV2) { if (initialEnterV2) {
console.log('[TabContainerV2] initialEnterV2 false로 변경'); dlog('[TabContainerV2] initialEnterV2 false로 변경');
setInitialEnterV2(false); setInitialEnterV2(false);
} }
timerIdV2.current = setTimeout(() => { timerIdV2.current = setTimeout(() => {
console.log('[TabContainerV2] 타이머 실행 - belowContentsVisible false로 변경 (30초 경과)'); dlog('[TabContainerV2] 타이머 실행 - belowContentsVisible false로 변경 (30초 경과)');
setBelowContentsVisible(false); setBelowContentsVisible(false);
}, timeout); }, timeout);
}, },
@@ -2373,9 +2388,9 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// Redux로 오버레이 숨김 // Redux로 오버레이 숨김
useEffect(() => { useEffect(() => {
if (shouldHideOverlays) { if (shouldHideOverlays) {
console.log('[PlayerPanel] shouldHideOverlays true - 오버레이 숨김'); dlog('[PlayerPanel] shouldHideOverlays true - 오버레이 숨김');
setSideContentsVisible(false); setSideContentsVisible(false);
console.log('[setBelowContentsVisible] Redux로 오버레이 숨김 - false로 변경'); dlog('[setBelowContentsVisible] Redux로 오버레이 숨김 - false로 변경');
setBelowContentsVisible(false); setBelowContentsVisible(false);
if (videoPlayer.current?.hideControls) { if (videoPlayer.current?.hideControls) {
@@ -2400,9 +2415,9 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// Redux로 오버레이 표시 // Redux로 오버레이 표시
useEffect(() => { useEffect(() => {
if (shouldShowOverlays) { if (shouldShowOverlays) {
console.log('[PlayerPanel] shouldShowOverlays true - 오버레이 표시'); dlog('[PlayerPanel] shouldShowOverlays true - 오버레이 표시');
setSideContentsVisible(true); setSideContentsVisible(true);
console.log('[setBelowContentsVisible] Redux로 오버레이 표시 - true로 변경'); dlog('[setBelowContentsVisible] Redux로 오버레이 표시 - true로 변경');
setBelowContentsVisible(true); setBelowContentsVisible(true);
if (videoPlayer.current?.showControls) { if (videoPlayer.current?.showControls) {
@@ -2424,33 +2439,33 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const isDetailPanelReturn = prevIsTopPanelDetailFromPlayerRef.current === true; const isDetailPanelReturn = prevIsTopPanelDetailFromPlayerRef.current === true;
if (isDetailPanelReturn) { if (isDetailPanelReturn) {
console.log('[PlayerPanel] ✅ PlayerPanel 내부 DetailPanel에서 복귀함! - 오버레이 표시'); dlog('[PlayerPanel] ✅ PlayerPanel 내부 DetailPanel에서 복귀함! - 오버레이 표시');
} else if (isHomePanelReturn) { } else if (isHomePanelReturn) {
console.log('[PlayerPanel] 📺 HomePanel에서 복귀함 - 오버레이 표시'); dlog('[PlayerPanel] 📺 HomePanel에서 복귀함 - 오버레이 표시');
// HomePanel에서 복귀 시 콘텐츠 타입에 따라 tabIndex 설정 // HomePanel에서 복귀 시 콘텐츠 타입에 따라 tabIndex 설정
console.log('[PlayerPanel] 🔄 HomePanel 복귀 - tabIndex를 콘텐츠 타입에 따라 설정'); dlog('[PlayerPanel] 🔄 HomePanel 복귀 - tabIndex를 콘텐츠 타입에 따라 설정');
if (tabContainerVersion === 2) { if (tabContainerVersion === 2) {
if (panelInfoRef.current.shptmBanrTpNm === 'VOD') { if (panelInfoRef.current.shptmBanrTpNm === 'VOD') {
setTabIndexV2(2); setTabIndexV2(2);
console.log('[PlayerPanel] 📝 VOD 콘텐츠 - tabIndexV2를 2로 설정됨'); dlog('[PlayerPanel] 📝 VOD 콘텐츠 - tabIndexV2를 2로 설정됨');
} else { } else {
setTabIndexV2(1); setTabIndexV2(1);
console.log('[PlayerPanel] 📝 LIVE 콘텐츠 - tabIndexV2를 1로 설정됨'); dlog('[PlayerPanel] 📝 LIVE 콘텐츠 - tabIndexV2를 1로 설정됨');
} }
} }
} else { } else {
console.log('[PlayerPanel] 🔄 그 외 복귀 - 오버레이 표시'); dlog('[PlayerPanel] 🔄 그 외 복귀 - 오버레이 표시');
} }
setSideContentsVisible(true); setSideContentsVisible(true);
console.log('[setBelowContentsVisible] 복귀 - true로 변경'); dlog('[setBelowContentsVisible] 복귀 - true로 변경');
setBelowContentsVisible(true); setBelowContentsVisible(true);
// VideoPlayer가 belowContentsVisible prop을 감지해서 자동으로 controls 표시함 // VideoPlayer가 belowContentsVisible prop을 감지해서 자동으로 controls 표시함
// PlayerPanel 내부 DetailPanel에서 복귀 시에만 포커스 복원 시도 // PlayerPanel 내부 DetailPanel에서 복귀 시에만 포커스 복원 시도
if (isDetailPanelReturn) { if (isDetailPanelReturn) {
const lastFocusedTargetId = panelInfo?.lastFocusedTargetId; const lastFocusedTargetId = panelInfo?.lastFocusedTargetId;
console.log( dlog(
'[PlayerPanel] 🎯 PlayerPanel DetailPanel 복귀 - lastFocusedTargetId:', '[PlayerPanel] 🎯 PlayerPanel DetailPanel 복귀 - lastFocusedTargetId:',
lastFocusedTargetId lastFocusedTargetId
); );
@@ -2458,7 +2473,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (lastFocusedTargetId) { if (lastFocusedTargetId) {
// ShopNowContents가 렌더링될 때까지 잠시 대기 후 포커스 복원 // ShopNowContents가 렌더링될 때까지 잠시 대기 후 포커스 복원
setTimeout(() => { setTimeout(() => {
console.log('[PlayerPanel] 🔍 500ms 후 포커스 복원 시도:', lastFocusedTargetId); dlog('[PlayerPanel] 🔍 500ms 후 포커스 복원 시도:', lastFocusedTargetId);
Spotlight.focus(lastFocusedTargetId); Spotlight.focus(lastFocusedTargetId);
}, 500); }, 500);
} }
@@ -2484,17 +2499,17 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
return; return;
} }
console.log( dlog(
'[PlayerPanel] 📺 Modal false 상태 - shptmBanrTpNm:', '[PlayerPanel] 📺 Modal false 상태 - shptmBanrTpNm:',
panelInfoRef.current?.shptmBanrTpNm panelInfoRef.current?.shptmBanrTpNm
); );
if (panelInfoRef.current?.shptmBanrTpNm === 'VOD') { if (panelInfoRef.current?.shptmBanrTpNm === 'VOD') {
setTabIndexV2(2); setTabIndexV2(2);
console.log('[PlayerPanel] 📝 VOD 콘텐츠 - tabIndexV2를 2로 설정됨'); dlog('[PlayerPanel] 📝 VOD 콘텐츠 - tabIndexV2를 2로 설정됨');
} else { } else {
setTabIndexV2(1); setTabIndexV2(1);
console.log('[PlayerPanel] 📝 LIVE 콘텐츠 - tabIndexV2를 1로 설정됨'); dlog('[PlayerPanel] 📝 LIVE 콘텐츠 - tabIndexV2를 1로 설정됨');
} }
} }
}, [isOnTop, panelInfo.modal, videoVerticalVisible, tabContainerVersion]); }, [isOnTop, panelInfo.modal, videoVerticalVisible, tabContainerVersion]);
@@ -2566,30 +2581,30 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (!isTransitionedTo2) { if (!isTransitionedTo2) {
if (timerIdV2.current) { if (timerIdV2.current) {
console.log('[TabContainerV2] 타이머 클리어 - tabIndex가 2가 아님', tabIndexV2); dlog('[TabContainerV2] 타이머 클리어 - tabIndex가 2가 아님', tabIndexV2);
clearTimerV2(); clearTimerV2();
} }
return; return;
} }
console.log('[TabContainerV2] tabIndex 1 → 2 감지, 타이머 시작'); dlog('[TabContainerV2] tabIndex 1 → 2 감지, 타이머 시작');
if (!belowContentsVisible || videoVerticalVisible) { if (!belowContentsVisible || videoVerticalVisible) {
console.log( dlog(
'[TabContainerV2] early return - belowContentsVisible 또는 videoVerticalVisible 조건 불만족' '[TabContainerV2] early return - belowContentsVisible 또는 videoVerticalVisible 조건 불만족'
); );
return; return;
} }
// tabIndex 1 → 2로 변경된 정확한 시점에 30초 타이머 시작 // tabIndex 1 → 2로 변경된 정확한 시점에 30초 타이머 시작
console.log('[TabContainerV2] 30초 타이머 시작'); dlog('[TabContainerV2] 30초 타이머 시작');
resetTimerV2(REGULAR_TIMEOUT); resetTimerV2(REGULAR_TIMEOUT);
return () => { return () => {
// cleanup: tabIndex가 2가 아니거나 오버레이가 사라질 때만 타이머 클리어 // cleanup: tabIndex가 2가 아니거나 오버레이가 사라질 때만 타이머 클리어
if (!belowContentsVisible || videoVerticalVisible || tabIndexV2 !== 2) { if (!belowContentsVisible || videoVerticalVisible || tabIndexV2 !== 2) {
if (timerIdV2.current) { if (timerIdV2.current) {
console.log('[TabContainerV2] cleanup - 타이머 클리어'); dlog('[TabContainerV2] cleanup - 타이머 클리어');
clearTimerV2(); clearTimerV2();
} }
} }