[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인 경우에만 로그 출력
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
// FP helpers
const pickParams = (keys) => (src) =>
@@ -39,8 +50,7 @@ const createRequestThunk =
const body = data(props);
// 📡 REQUEST 로그: API 호출 전 (tag별로 다르게 표시)
if (DEBUG_MODE)
console.log(
dlog(
`%c[${tag}] 📤 REQUEST - ${method.toUpperCase()} ${url}`,
'background: #4CAF50; color: white; font-weight: bold; padding: 3px;',
{
@@ -54,8 +64,7 @@ const createRequestThunk =
const onSuccess = (response) => {
// ✅ RESPONSE 로그: API 호출 성공 (tag별로 다르게 표시)
if (DEBUG_MODE)
console.log(
dlog(
`%c[${tag}] ✅ RESPONSE SUCCESS - ${method.toUpperCase()} ${url}`,
'background: #2196F3; color: white; font-weight: bold; padding: 3px;',
{
@@ -76,8 +85,7 @@ const createRequestThunk =
const onFail = (error) => {
// ❌ ERROR 로그: API 호출 실패 (tag별로 다르게 표시)
if (DEBUG_MODE)
console.error(
derror(
`%c[${tag}] ❌ RESPONSE ERROR - ${method.toUpperCase()} ${url}`,
'background: #F44336; color: white; font-weight: bold; padding: 3px;',
{
@@ -106,14 +114,14 @@ const createGetThunk = ({ url, type, params = () => ({}), tag }) =>
export const getBestSeller = (callback) => (dispatch, getState) => {
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(changeAppStatus({ showLoadingPanel: { show: false } }));
callback && callback();
};
const onFail = (error) => {
if (DEBUG_MODE) console.error('getBestSeller onFail', error);
derror('getBestSeller onFail', error);
dispatch(changeAppStatus({ showLoadingPanel: { show: false } }));
callback && callback();
};
@@ -718,20 +726,20 @@ export const getUserReviewList = (requestParams) => async (dispatch, getState) =
// Review Filters 추출 함수 (IF-LGSP-100)
const extractReviewFiltersApiData = (apiResponse) => {
try {
console.log('[ReviewFilters] 📥 extractReviewFiltersApiData 호출 - 원본 응답:', apiResponse);
dlog('[ReviewFilters] 📥 extractReviewFiltersApiData 호출 - 원본 응답:', apiResponse);
let data = null;
// ⭐ 핵심: retCode가 0인지 먼저 확인 (HTTP 200이어도 API 에러일 수 있음)
// 응답 구조: { retCode: 0, retMsg: "Success", data: { reviewFilterInfos: {...} } }
if (!apiResponse) {
console.warn('[ReviewFilters] ⚠️ apiResponse가 null/undefined');
dwarn('[ReviewFilters] ⚠️ apiResponse가 null/undefined');
return null;
}
const retCode = apiResponse.retCode;
if (retCode !== 0) {
console.error('[ReviewFilters] ❌ API 에러 - retCode !== 0:', {
derror('[ReviewFilters] ❌ API 에러 - retCode !== 0:', {
retCode: retCode,
retMsg: apiResponse?.retMsg,
fullResponse: apiResponse,
@@ -742,7 +750,7 @@ const extractReviewFiltersApiData = (apiResponse) => {
// reviewFilterInfos 추출: data.reviewFilterInfos
const reviewFilterInfos = apiResponse.data?.reviewFilterInfos || {};
console.log('[ReviewFilters] 🔍 reviewFilterInfos 분석:', {
dlog('[ReviewFilters] 🔍 reviewFilterInfos 분석:', {
patnrId: reviewFilterInfos.patnrId,
prdtId: reviewFilterInfos.prdtId,
hasFilters: !!reviewFilterInfos.filters,
@@ -753,11 +761,11 @@ const extractReviewFiltersApiData = (apiResponse) => {
data = reviewFilterInfos;
if (!data || !data.filters) {
console.warn('[ReviewFilters] ⚠️ filters가 없음:', apiResponse);
dwarn('[ReviewFilters] ⚠️ filters가 없음:', apiResponse);
return null;
}
console.log('[ReviewFilters] ✅ 추출 완료:', {
dlog('[ReviewFilters] ✅ 추출 완료:', {
patnrId: data.patnrId,
prdtId: data.prdtId,
filtersLength: data.filters.length,
@@ -765,7 +773,7 @@ const extractReviewFiltersApiData = (apiResponse) => {
return data;
} catch (error) {
console.error('[ReviewFilters] ❌ extractReviewFiltersApiData 에러:', error);
derror('[ReviewFilters] ❌ extractReviewFiltersApiData 에러:', error);
return null;
}
};
@@ -783,7 +791,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
const body = {};
console.log('[ReviewFilters] 🚀 API 요청 시작:', {
dlog('[ReviewFilters] 🚀 API 요청 시작:', {
requestParams,
params,
body,
@@ -796,7 +804,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
const retCode = response?.data?.retCode;
const retMsg = response?.data?.retMsg;
console.log('[ReviewFilters] ✅ API 응답 수신 (retCode 확인):', {
dlog('[ReviewFilters] ✅ API 응답 수신 (retCode 확인):', {
httpStatus: response?.status,
retCode: retCode,
retMsg: retMsg,
@@ -808,7 +816,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
const filtersData = extractReviewFiltersApiData(response.data);
if (!filtersData) {
console.warn('[ReviewFilters] ⚠️ 필터 데이터 추출 실패:', {
dwarn('[ReviewFilters] ⚠️ 필터 데이터 추출 실패:', {
retCode: retCode,
retMsg: retMsg,
reason: retCode !== 0 ? 'retCode !== 0' : 'filters 데이터 없음',
@@ -816,7 +824,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
return; // 실패 시 dispatch하지 않음
}
console.log('[ReviewFilters] 📊 필터 데이터 추출 성공:', {
dlog('[ReviewFilters] 📊 필터 데이터 추출 성공:', {
patnrId: filtersData.patnrId,
prdtId: filtersData.prdtId,
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,
patnrId: patnrId,
prdtId: prdtId,
@@ -842,7 +850,7 @@ export const getReviewFilters = (requestParams) => (dispatch, getState) => {
};
const onFail = (error) => {
console.error('[ReviewFilters] ❌ API 실패:', {
derror('[ReviewFilters] ❌ API 실패:', {
errorMessage: error?.message || '알 수 없는 에러',
errorType: typeof error,
httpStatus: error?.response?.status,

View File

@@ -66,6 +66,21 @@ import Video from './Video';
import css from './VideoPlayer.module.less';
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 isLeft = is('left');
const isRight = is('right');
@@ -1488,7 +1503,7 @@ const VideoPlayerBase = class extends React.Component {
sourceUnavailable: false,
};
if (!el) {
console.log('yhcho VideoPlayer no el ');
dlog('yhcho VideoPlayer no el ');
updatedState.error = true;
this.setState(updatedState);
return;
@@ -1564,7 +1579,7 @@ const VideoPlayerBase = class extends React.Component {
// 가장 중요한 이벤트만 로그
const shouldLogEvent = ['play', 'pause', 'ended'].includes(ev.type);
if (shouldLogEvent) {
console.log('🔄 [PlayerPanel][VideoPlayer] Event-driven Redux update', {
dlog('🔄 [PlayerPanel][VideoPlayer] Event-driven Redux update', {
eventType: ev.type,
videoState: updatedState,
updateState,
@@ -1573,7 +1588,7 @@ const VideoPlayerBase = class extends React.Component {
}
// 🔍 Redux dispatch 확인
console.log('📤 [PlayerPanel][VideoPlayer] Dispatching Redux update', {
dlog('📤 [PlayerPanel][VideoPlayer] Dispatching Redux update', {
eventType: ev.type,
updateState,
hasDispatch: !!this.props.dispatch,
@@ -1583,7 +1598,7 @@ const VideoPlayerBase = class extends React.Component {
this.props.dispatch(updateVideoPlayState(updateState));
}
} else {
console.log('❌ [PlayerPanel][VideoPlayer] No dispatch prop available', {
derror('❌ [PlayerPanel][VideoPlayer] No dispatch prop available', {
props: Object.keys(this.props),
hasDispatch: !!this.props.dispatch,
hasVideoPlayState: !!this.props.videoPlayState,
@@ -1595,7 +1610,7 @@ const VideoPlayerBase = class extends React.Component {
if (this.props.videoPlayState && typeof this.props.videoPlayState === 'object') {
// Redux 상태 디버깅 (최소한의 중요 이벤트만)
if (ev.type === 'play' || ev.type === 'pause') {
console.log('🔍 [PlayerPanel][VideoPlayer] Redux state debug', {
dlog('🔍 [PlayerPanel][VideoPlayer] Redux state debug', {
videoPlayState: this.props.videoPlayState,
isPaused: this.props.videoPlayState?.isPaused,
isPlaying: this.props.videoPlayState?.isPlaying,
@@ -1624,7 +1639,7 @@ const VideoPlayerBase = class extends React.Component {
// 중요한 상태 변화가 있고 빈번한 이벤트가 아닐 때만 로그
if (hasSignificantChange && !isFrequentEvent) {
console.log('🔄 [PlayerPanel][VideoPlayer] Syncing internal state with Redux', {
dlog('🔄 [PlayerPanel][VideoPlayer] Syncing internal state with Redux', {
timeDiff,
shouldUpdateTime,
pausedDiff: paused !== this.state.paused,
@@ -1703,7 +1718,7 @@ const VideoPlayerBase = class extends React.Component {
* @public
*/
play = () => {
console.log('🟢 [PlayerPanel][VideoPlayer] play() called', {
dlog('🟢 [PlayerPanel][VideoPlayer] play() called', {
currentTime: this.state.currentTime,
duration: this.state.duration,
paused: this.state.paused,
@@ -1712,7 +1727,7 @@ const VideoPlayerBase = class extends React.Component {
});
if (this.state.sourceUnavailable) {
console.log('⚠️ [PlayerPanel][VideoPlayer] play() aborted - source unavailable');
dwarn('⚠️ [PlayerPanel][VideoPlayer] play() aborted - source unavailable');
return;
}
@@ -1747,7 +1762,7 @@ const VideoPlayerBase = class extends React.Component {
* @public
*/
pause = () => {
console.log('🔴 [VideoPlayer] pause() called', {
dlog('🔴 [VideoPlayer] pause() called', {
currentTime: this.state.currentTime,
duration: this.state.duration,
paused: this.state.paused,
@@ -1756,7 +1771,7 @@ const VideoPlayerBase = class extends React.Component {
});
if (this.state.sourceUnavailable) {
console.log('⚠️ [VideoPlayer] pause() aborted - source unavailable');
dwarn('⚠️ [VideoPlayer] pause() aborted - source unavailable');
return;
}
@@ -1779,10 +1794,10 @@ const VideoPlayerBase = class extends React.Component {
playbackRate: 1,
};
console.log('📤 [VideoPlayer] Dispatching pause state', pauseState);
dlog('📤 [VideoPlayer] Dispatching pause state', pauseState);
this.props.dispatch(updateVideoPlayState(pauseState));
} 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
*/
seek = (timeIndex) => {
console.log('⏩ [VideoPlayer] seek() called', {
dlog('⏩ [VideoPlayer] seek() called', {
timeIndex,
currentTime: this.state.currentTime,
duration: this.state.duration,
@@ -1815,7 +1830,7 @@ const VideoPlayerBase = class extends React.Component {
timeIndex >= this.video.duration ? this.video.duration - 1 : timeIndex;
this.video.currentTime = actualSeekTime;
console.log('⏩ [VideoPlayer] Video seek completed', {
dlog('⏩ [VideoPlayer] Video seek completed', {
requestedTime: timeIndex,
actualTime: actualSeekTime,
videoDuration: this.video.duration,
@@ -1831,17 +1846,17 @@ const VideoPlayerBase = class extends React.Component {
playbackRate: this.state.playbackRate,
};
console.log('📤 [VideoPlayer] Dispatching seek state', seekState);
dlog('📤 [VideoPlayer] Dispatching seek state', seekState);
this.props.dispatch(updateVideoPlayState(seekState));
} else {
console.log('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated');
dwarn('⚠️ [VideoPlayer] No dispatch prop available - Redux state not updated');
}
} else {
console.log('❌ [VideoPlayer] seek failed - disabled or source unavailable');
derror('❌ [VideoPlayer] seek failed - disabled or source unavailable');
forward('onSeekFailed', {}, this.props);
}
} 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 { 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 = {
// 기존 상태 - 완전히 호환됨
panels: [],
@@ -29,7 +44,7 @@ const forceTopPanels = [panel_names.ERROR_PANEL, panel_names.INTRO_PANEL, panel_
export const panelsReducer = (state = initialState, action) => {
switch (action.type) {
case types.PUSH_PANEL: {
console.log('[panelReducer] 🔵 PUSH_PANEL START', {
dlog('[panelReducer] 🔵 PUSH_PANEL START', {
newPanelName: action.payload.name,
currentPanels: state.panels.map((p) => p.name),
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),
lastAction,
});
@@ -89,7 +104,7 @@ export const panelsReducer = (state = initialState, action) => {
}
case types.POP_PANEL: {
console.log('[panelReducer] 🔴 POP_PANEL START', {
dlog('[panelReducer] 🔴 POP_PANEL START', {
targetPanel: action.payload || 'last_panel',
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);
}
console.log('[panelReducer] 🔴 POP_PANEL END', {
dlog('[panelReducer] 🔴 POP_PANEL END', {
resultPanels: resultPanels.map((p) => p.name),
lastAction,
});
@@ -159,7 +174,7 @@ export const panelsReducer = (state = initialState, action) => {
};
}
case types.RESET_PANELS: {
console.log('[panelReducer] 🟢 RESET_PANELS START', {
dlog('[panelReducer] 🟢 RESET_PANELS START', {
currentPanels: state.panels.map((p) => p.name),
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),
});
@@ -184,7 +199,7 @@ export const panelsReducer = (state = initialState, action) => {
// [251106] 패널 액션 큐 관련 reducer 케이스들
case types.ENQUEUE_PANEL_ACTION: {
console.log('[panelReducer] 🟠 ENQUEUE_PANEL_ACTION', {
dlog('[panelReducer] 🟠 ENQUEUE_PANEL_ACTION', {
action: action.payload.action,
queueId: action.payload.id,
currentQueueLength: state.panelActionQueue.length,
@@ -201,7 +216,7 @@ export const panelsReducer = (state = initialState, action) => {
}
case types.PROCESS_PANEL_QUEUE: {
console.log('[panelReducer] 🟡 PROCESS_PANEL_QUEUE', {
dlog('[panelReducer] 🟡 PROCESS_PANEL_QUEUE', {
isProcessing: state.isProcessingQueue,
queueLength: state.panelActionQueue.length,
});
@@ -215,7 +230,7 @@ export const panelsReducer = (state = initialState, action) => {
const firstQueueItem = state.panelActionQueue[0];
const remainingQueue = state.panelActionQueue.slice(1);
console.log('[panelReducer] 🟡 PROCESSING_QUEUE_ITEM', {
dlog('[panelReducer] 🟡 PROCESSING_QUEUE_ITEM', {
action: firstQueueItem.action,
queueId: firstQueueItem.id,
remainingQueueLength: remainingQueue.length,
@@ -261,7 +276,7 @@ export const panelsReducer = (state = initialState, action) => {
break;
}
default:
console.warn('[panelReducer] ⚠️ UNKNOWN_QUEUE_ACTION', firstQueueItem.action);
dwarn('[panelReducer] ⚠️ UNKNOWN_QUEUE_ACTION', firstQueueItem.action);
newState = state;
}
@@ -272,7 +287,7 @@ export const panelsReducer = (state = initialState, action) => {
processingTime) /
newTotalProcessed;
console.log('[panelReducer] ✅ QUEUE_ITEM_PROCESSED', {
dlog('[panelReducer] ✅ QUEUE_ITEM_PROCESSED', {
action: firstQueueItem.action,
queueId: firstQueueItem.id,
processingTime,
@@ -290,7 +305,7 @@ export const panelsReducer = (state = initialState, action) => {
},
};
} catch (error) {
console.error('[panelReducer] ❌ QUEUE_PROCESSING_ERROR', {
derror('[panelReducer] ❌ QUEUE_PROCESSING_ERROR', {
action: firstQueueItem.action,
queueId: firstQueueItem.id,
error: error.message,
@@ -315,7 +330,7 @@ export const panelsReducer = (state = initialState, action) => {
}
case types.CLEAR_PANEL_QUEUE: {
console.log('[panelReducer] 🔵 CLEAR_PANEL_QUEUE', {
dlog('[panelReducer] 🔵 CLEAR_PANEL_QUEUE', {
currentQueueLength: state.panelActionQueue.length,
});
@@ -328,7 +343,7 @@ export const panelsReducer = (state = initialState, action) => {
}
case types.SET_QUEUE_PROCESSING: {
console.log('[panelReducer] 🟣 SET_QUEUE_PROCESSING', {
dlog('[panelReducer] 🟣 SET_QUEUE_PROCESSING', {
isProcessing: action.payload.isProcessing,
queueLength: state.panelActionQueue.length,
});
@@ -341,7 +356,7 @@ export const panelsReducer = (state = initialState, action) => {
// [251106] 비동기 패널 액션 관련 reducer 케이스들
case types.ENQUEUE_ASYNC_PANEL_ACTION: {
console.log('[panelReducer] 🟠 ENQUEUE_ASYNC_PANEL_ACTION', {
dlog('[panelReducer] 🟠 ENQUEUE_ASYNC_PANEL_ACTION', {
actionId: action.payload.id,
timestamp: action.payload.timestamp,
});
@@ -361,7 +376,7 @@ export const panelsReducer = (state = initialState, action) => {
}
case types.COMPLETE_ASYNC_PANEL_ACTION: {
console.log('[panelReducer] ✅ COMPLETE_ASYNC_PANEL_ACTION', {
dlog('[panelReducer] ✅ COMPLETE_ASYNC_PANEL_ACTION', {
actionId: action.payload.actionId,
timestamp: action.payload.timestamp,
});
@@ -401,7 +416,7 @@ export const panelsReducer = (state = initialState, action) => {
}
case types.FAIL_ASYNC_PANEL_ACTION: {
console.log('[panelReducer] ❌ FAIL_ASYNC_PANEL_ACTION', {
derror('[panelReducer] ❌ FAIL_ASYNC_PANEL_ACTION', {
actionId: action.payload.actionId,
error: action.payload.error?.message || 'Unknown error',
timestamp: action.payload.timestamp,
@@ -440,7 +455,7 @@ export const panelsReducer = (state = initialState, action) => {
// [251114] 명시적 포커스 이동
case types.FOCUS_PANEL: {
console.log('[panelReducer] 🎯 FOCUS_PANEL', {
dlog('[panelReducer] 🎯 FOCUS_PANEL', {
panelName: action.payload.panelName,
focusTarget: action.payload.focusTarget,
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');
// 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) => {
try {
if (currentAttempts >= maxAttempts) {
@@ -363,7 +378,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// PlayerPanel.jsx의 라인 313-327 useEffect 수정 - detailPanelClosed flag 감지 추가
useEffect(() => {
console.log('[PlayerPanel] 🔍 isOnTop useEffect 호출:', {
dlog('[PlayerPanel] 🔍 isOnTop useEffect 호출:', {
isOnTop,
modal: panelInfo?.modal,
isPaused: panelInfo?.isPaused,
@@ -374,18 +389,18 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 1. Resume Video if needed (isPaused or detailPanelClosed)
if (panelInfo.isPaused || panelInfo.detailPanelClosed) {
if (panelInfo.modal) {
console.log('[PlayerPanel] ▶️ Back on top (Modal) - resuming video');
dlog('[PlayerPanel] ▶️ Back on top (Modal) - resuming video');
dispatch(resumeModalVideo());
} else {
console.log('[PlayerPanel] ▶️ Back on top (Fullscreen) - resuming video');
dlog('[PlayerPanel] ▶️ Back on top (Fullscreen) - resuming video');
dispatch(resumeFullscreenVideo());
}
}
// 2. Reset detailPanelClosed flag
if (panelInfo.detailPanelClosed) {
console.log('[PlayerPanel] 🔄 detailPanelClosed flag 초기화 시작');
console.log('[PlayerPanel] 🔙 DetailPanel에서 복귀 정보:', {
dlog('[PlayerPanel] 🔄 detailPanelClosed flag 초기화 시작');
dlog('[PlayerPanel] 🔙 DetailPanel에서 복귀 정보:', {
detailPanelClosedAt: panelInfo.detailPanelClosedAt,
detailPanelClosedFromSource: panelInfo.detailPanelClosedFromSource,
lastFocusedTargetId: panelInfo.lastFocusedTargetId,
@@ -393,13 +408,13 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 포커스 복원 로직 추가 (1000ms 지연)
if (panelInfo.lastFocusedTargetId) {
console.log(
dlog(
'[PlayerPanel] 🎯 DetailPanel 복귀 후 1000ms 지연 포커스 복원 예약:',
panelInfo.lastFocusedTargetId
);
const focusTimeoutId = setTimeout(() => {
console.log(
dlog(
'[PlayerPanel] 🔍 DetailPanel 복귀 후 포커스 복원 실행:',
panelInfo.lastFocusedTargetId
);
@@ -410,7 +425,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
return () => {
if (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 {
// Not on top
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());
}
}
@@ -464,7 +479,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
(isOnTop && videoPlayState && hasSignificantChange) ||
(isDetailPanelOnTop && (isPlayingChanged || isPausedChanged))
) {
console.log('📊 [PlayerPanel] Significant videoPlayState change', {
dlog('📊 [PlayerPanel] Significant videoPlayState change', {
previousState: previousVideoPlayState.current,
currentState: videoPlayState,
topPanelName: topPanel?.name,
@@ -492,7 +507,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (isOnTop && panelInfo?.isPaused !== undefined && isPausedChanged) {
// 상태 변경 시에만 디버깅 로그 출력
console.log('🔍 [PlayerPanel] PanelInfo isPaused changed', {
dlog('🔍 [PlayerPanel] PanelInfo isPaused changed', {
previousIsPaused: previousPanelInfo.current?.isPaused,
currentIsPaused: panelInfo.isPaused,
isOnTop,
@@ -500,7 +515,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
currentPlayingUrl,
timestamp: new Date().toISOString(),
});
console.log('🎮 [PlayerPanel] PanelInfo isPaused changed', {
dlog('🎮 [PlayerPanel] PanelInfo isPaused changed', {
previousIsPaused: previousPanelInfo.current?.isPaused,
currentIsPaused: panelInfo.isPaused,
videoPlayerExists: !!videoPlayer.current,
@@ -513,10 +528,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (videoPlayer.current) {
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();
} 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();
}
}
@@ -550,7 +565,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
? 'Top panel changed'
: 'VideoPlayer created';
console.log('🎬 [PlayerPanel] VideoPlayer state change', {
dlog('🎬 [PlayerPanel] VideoPlayer state change', {
hasVideoPlayer: !!videoPlayer.current,
currentPlayingUrl,
previousVideoSource: previousVideoSource.current,
@@ -570,7 +585,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (isVideoSourceChanged || videoPlayerJustCreated || isDetailPanelOnTopChanged) {
const mediaState = videoPlayer.current.getMediaState?.();
if (mediaState) {
console.log('📊 [PlayerPanel] VideoPlayer current state', {
dlog('📊 [PlayerPanel] VideoPlayer current state', {
mediaState,
videoPlayState,
changeReason,
@@ -590,7 +605,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const currentModalState = panelInfo?.modal;
const prevModalState = modalPrevRef.current;
console.log('[PlayerPanel] 🔍 Modal 상태 체크:', {
dlog('[PlayerPanel] 🔍 Modal 상태 체크:', {
prevModalState,
currentModalState,
shouldExecuteTrueToFalse: prevModalState === true && currentModalState === false,
@@ -599,8 +614,8 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// true → false 변화 감지
if (prevModalState === true && currentModalState === false) {
console.log('[PlayerPanel] ▶️ Modal 상태 변화: true → false (전체화면 모드로 복귀)');
console.log(
dlog('[PlayerPanel] ▶️ Modal 상태 변화: true → false (전체화면 모드로 복귀)');
dlog(
'[PlayerPanel] 🎯 포커스 복원 준비 - lastFocusedTargetId:',
panelInfo?.lastFocusedTargetId
);
@@ -612,7 +627,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (lastFocusedTargetId) {
// ShopNowContents가 렌더링될 때까지 대기 후 포커스 복원
setTimeout(() => {
console.log('[PlayerPanel] 🔍 800ms 후 포커스 복원 시도:', lastFocusedTargetId);
dlog('[PlayerPanel] 🔍 800ms 후 포커스 복원 시도:', lastFocusedTargetId);
Spotlight.focus(lastFocusedTargetId);
}, 800);
}
@@ -620,7 +635,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// false → true 변화 감지 (모달이 열림)
if (prevModalState === false && currentModalState === true) {
console.log('[PlayerPanel] 📱 Modal 상태 변화: false → true (모달 열림)');
dlog('[PlayerPanel] 📱 Modal 상태 변화: false → true (모달 열림)');
setIsModalClosed(false); // 모달이 열렸음을 표시
}
@@ -1273,7 +1288,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 🔍 DetailPanel 상태 변화 로깅
if (result) {
console.log('🎬 [PlayerPanel] DetailPanel is now on top (from Player)', {
dlog('🎬 [PlayerPanel] DetailPanel is now on top (from Player)', {
topPanelName: topPanel?.name,
launchedFromPlayer: topPanel?.panelInfo?.launchedFromPlayer,
modalPlayerPanelExists: panels.some(
@@ -1299,7 +1314,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// PlayerPanel이 modal이고 밑에 깔렸을 때
if (isModalPlayerPanel && !isCurrentPanelOnTop && isDetailPanelOnTop) {
console.log('🔴 [PlayerPanel] Self-pausing due to DetailPanel on top', {
dlog('🔴 [PlayerPanel] Self-pausing due to DetailPanel on top', {
isDetailPanelOnTop,
isModalPlayerPanel,
isCurrentPanelOnTop,
@@ -1310,7 +1325,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// PlayerPanel 자신의 상태를 일시정지로 업데이트
if (videoPlayState?.isPlaying === true || videoPlayState?.isPaused === false) {
console.log('🔄 [PlayerPanel] Dispatching self-pause to Redux');
dlog('🔄 [PlayerPanel] Dispatching self-pause to Redux');
dispatch(
updateVideoPlayState({
isPlaying: false,
@@ -1404,7 +1419,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
}
} else {
// showId가 일치하지 않으면 이전 상태를 재활용하지 않고 초기화
console.log('[PlayerPanel] VOD showDetailInfo mismatch. Clearing playListInfo.', {
dlog('[PlayerPanel] VOD showDetailInfo mismatch. Clearing playListInfo.', {
panelInfoShowId: panelInfo.showId,
showDetailInfoId: showDetailInfo[0]?.showId,
});
@@ -1686,7 +1701,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
(ev) => {
const type = ev.type;
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))) {
dispatch(
@@ -1717,7 +1732,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const mediaId = videoPlayer.current?.video?.media?.mediaId;
setMediaId(mediaId);
setVideoLoaded(true);
console.log(
dlog(
'[PlayerPanel] 🎬 Video Loaded - shptmBanrTpNm:',
panelInfoRef.current?.shptmBanrTpNm
);
@@ -1751,7 +1766,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
useEffect(() => {
// 복구 직후: skipModalStyleRecalculation이 true면 저장된 modalStyle 적용
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;
// 저장된 modalStyle 사용 (top, left 포함)
@@ -1767,7 +1782,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (typeof window !== 'undefined') {
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(
updatePanel({
name: panel_names.PLAYER_PANEL,
@@ -1788,7 +1803,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
panelInfo.modalContainerId &&
(lastPanelAction === 'previewPush' || lastPanelAction === 'previewUpdate')
) {
console.log('[PlayerPanel] Condition 1: Calculating modalStyle from DOM', {
dlog('[PlayerPanel] Condition 1: Calculating modalStyle from DOM', {
lastPanelAction,
});
const node = document.querySelector(`[data-spotlight-id="${panelInfo.modalContainerId}"]`);
@@ -1815,17 +1830,17 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
})
);
} 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);
setModalScale(panelInfo.modalScale);
}
} else if (panelInfo.shouldShrinkTo1px) {
console.log('[PlayerPanel] Condition 2: Shrinking - clearing modalStyle');
dlog('[PlayerPanel] Condition 2: Shrinking - clearing modalStyle');
// 축소 상태: 인라인 스타일 제거 (CSS만 적용)
setModalStyle({});
setModalScale(1);
} 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) {
videoPlayer.current.play();
}
@@ -1923,7 +1938,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 비디오가 새로 선택될 때 타이머 초기화
useEffect(() => {
if (currentPlayingUrl) {
console.log('[PlayerPanel] 🎬 비디오 선택됨 - tabIndexV2 타이머 초기화');
dlog('[PlayerPanel] 🎬 비디오 선택됨 - tabIndexV2 타이머 초기화');
resetTimerTabAutoAdvance(10000);
}
}, [selectedIndex, resetTimerTabAutoAdvance]);
@@ -2322,10 +2337,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const clearTimerV2 = useCallback(() => {
if (timerIdV2.current) {
console.log('[clearTimerV2] 타이머 클리어됨');
dlog('[clearTimerV2] 타이머 클리어됨');
const stack = new Error().stack;
const lines = stack.split('\n').slice(1, 4).join(' → ');
console.log('[clearTimerV2] 호출 스택:', lines);
dlog('[clearTimerV2] 호출 스택:', lines);
}
clearTimeout(timerIdV2.current);
timerIdV2.current = null;
@@ -2333,19 +2348,19 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const resetTimerV2 = useCallback(
(timeout) => {
console.log('[TabContainerV2] resetTimerV2 호출', timeout);
dlog('[TabContainerV2] resetTimerV2 호출', timeout);
if (timerIdV2.current) {
console.log('[TabContainerV2] 기존 타이머 클리어');
dlog('[TabContainerV2] 기존 타이머 클리어');
clearTimerV2();
}
if (initialEnterV2) {
console.log('[TabContainerV2] initialEnterV2 false로 변경');
dlog('[TabContainerV2] initialEnterV2 false로 변경');
setInitialEnterV2(false);
}
timerIdV2.current = setTimeout(() => {
console.log('[TabContainerV2] 타이머 실행 - belowContentsVisible false로 변경 (30초 경과)');
dlog('[TabContainerV2] 타이머 실행 - belowContentsVisible false로 변경 (30초 경과)');
setBelowContentsVisible(false);
}, timeout);
},
@@ -2373,9 +2388,9 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// Redux로 오버레이 숨김
useEffect(() => {
if (shouldHideOverlays) {
console.log('[PlayerPanel] shouldHideOverlays true - 오버레이 숨김');
dlog('[PlayerPanel] shouldHideOverlays true - 오버레이 숨김');
setSideContentsVisible(false);
console.log('[setBelowContentsVisible] Redux로 오버레이 숨김 - false로 변경');
dlog('[setBelowContentsVisible] Redux로 오버레이 숨김 - false로 변경');
setBelowContentsVisible(false);
if (videoPlayer.current?.hideControls) {
@@ -2400,9 +2415,9 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// Redux로 오버레이 표시
useEffect(() => {
if (shouldShowOverlays) {
console.log('[PlayerPanel] shouldShowOverlays true - 오버레이 표시');
dlog('[PlayerPanel] shouldShowOverlays true - 오버레이 표시');
setSideContentsVisible(true);
console.log('[setBelowContentsVisible] Redux로 오버레이 표시 - true로 변경');
dlog('[setBelowContentsVisible] Redux로 오버레이 표시 - true로 변경');
setBelowContentsVisible(true);
if (videoPlayer.current?.showControls) {
@@ -2424,33 +2439,33 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const isDetailPanelReturn = prevIsTopPanelDetailFromPlayerRef.current === true;
if (isDetailPanelReturn) {
console.log('[PlayerPanel] ✅ PlayerPanel 내부 DetailPanel에서 복귀함! - 오버레이 표시');
dlog('[PlayerPanel] ✅ PlayerPanel 내부 DetailPanel에서 복귀함! - 오버레이 표시');
} else if (isHomePanelReturn) {
console.log('[PlayerPanel] 📺 HomePanel에서 복귀함 - 오버레이 표시');
dlog('[PlayerPanel] 📺 HomePanel에서 복귀함 - 오버레이 표시');
// HomePanel에서 복귀 시 콘텐츠 타입에 따라 tabIndex 설정
console.log('[PlayerPanel] 🔄 HomePanel 복귀 - tabIndex를 콘텐츠 타입에 따라 설정');
dlog('[PlayerPanel] 🔄 HomePanel 복귀 - tabIndex를 콘텐츠 타입에 따라 설정');
if (tabContainerVersion === 2) {
if (panelInfoRef.current.shptmBanrTpNm === 'VOD') {
setTabIndexV2(2);
console.log('[PlayerPanel] 📝 VOD 콘텐츠 - tabIndexV2를 2로 설정됨');
dlog('[PlayerPanel] 📝 VOD 콘텐츠 - tabIndexV2를 2로 설정됨');
} else {
setTabIndexV2(1);
console.log('[PlayerPanel] 📝 LIVE 콘텐츠 - tabIndexV2를 1로 설정됨');
dlog('[PlayerPanel] 📝 LIVE 콘텐츠 - tabIndexV2를 1로 설정됨');
}
}
} else {
console.log('[PlayerPanel] 🔄 그 외 복귀 - 오버레이 표시');
dlog('[PlayerPanel] 🔄 그 외 복귀 - 오버레이 표시');
}
setSideContentsVisible(true);
console.log('[setBelowContentsVisible] 복귀 - true로 변경');
dlog('[setBelowContentsVisible] 복귀 - true로 변경');
setBelowContentsVisible(true);
// VideoPlayer가 belowContentsVisible prop을 감지해서 자동으로 controls 표시함
// PlayerPanel 내부 DetailPanel에서 복귀 시에만 포커스 복원 시도
if (isDetailPanelReturn) {
const lastFocusedTargetId = panelInfo?.lastFocusedTargetId;
console.log(
dlog(
'[PlayerPanel] 🎯 PlayerPanel DetailPanel 복귀 - lastFocusedTargetId:',
lastFocusedTargetId
);
@@ -2458,7 +2473,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (lastFocusedTargetId) {
// ShopNowContents가 렌더링될 때까지 잠시 대기 후 포커스 복원
setTimeout(() => {
console.log('[PlayerPanel] 🔍 500ms 후 포커스 복원 시도:', lastFocusedTargetId);
dlog('[PlayerPanel] 🔍 500ms 후 포커스 복원 시도:', lastFocusedTargetId);
Spotlight.focus(lastFocusedTargetId);
}, 500);
}
@@ -2484,17 +2499,17 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
return;
}
console.log(
dlog(
'[PlayerPanel] 📺 Modal false 상태 - shptmBanrTpNm:',
panelInfoRef.current?.shptmBanrTpNm
);
if (panelInfoRef.current?.shptmBanrTpNm === 'VOD') {
setTabIndexV2(2);
console.log('[PlayerPanel] 📝 VOD 콘텐츠 - tabIndexV2를 2로 설정됨');
dlog('[PlayerPanel] 📝 VOD 콘텐츠 - tabIndexV2를 2로 설정됨');
} else {
setTabIndexV2(1);
console.log('[PlayerPanel] 📝 LIVE 콘텐츠 - tabIndexV2를 1로 설정됨');
dlog('[PlayerPanel] 📝 LIVE 콘텐츠 - tabIndexV2를 1로 설정됨');
}
}
}, [isOnTop, panelInfo.modal, videoVerticalVisible, tabContainerVersion]);
@@ -2566,30 +2581,30 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (!isTransitionedTo2) {
if (timerIdV2.current) {
console.log('[TabContainerV2] 타이머 클리어 - tabIndex가 2가 아님', tabIndexV2);
dlog('[TabContainerV2] 타이머 클리어 - tabIndex가 2가 아님', tabIndexV2);
clearTimerV2();
}
return;
}
console.log('[TabContainerV2] tabIndex 1 → 2 감지, 타이머 시작');
dlog('[TabContainerV2] tabIndex 1 → 2 감지, 타이머 시작');
if (!belowContentsVisible || videoVerticalVisible) {
console.log(
dlog(
'[TabContainerV2] early return - belowContentsVisible 또는 videoVerticalVisible 조건 불만족'
);
return;
}
// tabIndex 1 → 2로 변경된 정확한 시점에 30초 타이머 시작
console.log('[TabContainerV2] 30초 타이머 시작');
dlog('[TabContainerV2] 30초 타이머 시작');
resetTimerV2(REGULAR_TIMEOUT);
return () => {
// cleanup: tabIndex가 2가 아니거나 오버레이가 사라질 때만 타이머 클리어
if (!belowContentsVisible || videoVerticalVisible || tabIndexV2 !== 2) {
if (timerIdV2.current) {
console.log('[TabContainerV2] cleanup - 타이머 클리어');
dlog('[TabContainerV2] cleanup - 타이머 클리어');
clearTimerV2();
}
}