[251122] fix: Comment정리-1
🕐 커밋 시간: 2025. 11. 22. 18:19:45 📊 변경 통계: • 총 파일: 10개 • 추가: +150줄 • 삭제: -152줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/App/App.js ~ com.twin.app.shoptime/src/actions/panelActions.js ~ com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js ~ com.twin.app.shoptime/src/utils/ImagePreloader.js ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.v2.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx ~ com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/App/App.js (javascript): ❌ Deleted: resolveSpotlightIdFromEvent() 📄 com.twin.app.shoptime/src/actions/panelActions.js (javascript): 🔄 Modified: resetPanels() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): 🔄 Modified: extractProductMeta() 📄 com.twin.app.shoptime/src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.v2.jsx (javascript): ❌ Deleted: logDetailPanelInit(), logImageLoaded(), logImageError() 📄 com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx (javascript): 🔄 Modified: Spottable() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • 공통 유틸리티 함수 최적화 • UI 컴포넌트 아키텍처 개선 Performance: 코드 최적화로 성능 개선 기대
This commit is contained in:
@@ -424,20 +424,20 @@ const resolveSpotlightIdFromEvent = (event) => {
|
||||
// Spotlight Focus 추적 로그 [251115]
|
||||
// DOM 이벤트 리스너로 대체
|
||||
|
||||
document.addEventListener('focusin', (ev) => {
|
||||
console.log('[SPOTLIGHT FOCUS-IN]', ev.target);
|
||||
});
|
||||
// document.addEventListener('focusin', (ev) => {
|
||||
// console.log('[SPOTLIGHT FOCUS-IN]', ev.target);
|
||||
// });
|
||||
|
||||
document.addEventListener('focusout', (ev) => {
|
||||
console.log('[SPOTLIGHT FOCUS-OUT]', ev.target);
|
||||
});
|
||||
// document.addEventListener('focusout', (ev) => {
|
||||
// console.log('[SPOTLIGHT FOCUS-OUT]', ev.target);
|
||||
// });
|
||||
|
||||
// Spotlight 커스텀 이벤트가 있다면 추가
|
||||
if (typeof Spotlight !== 'undefined' && Spotlight.addEventListener) {
|
||||
Spotlight.addEventListener('focus', (ev) => {
|
||||
console.log('[SPOTLIGHT: focus]', ev.target);
|
||||
});
|
||||
}
|
||||
// // Spotlight 커스텀 이벤트가 있다면 추가
|
||||
// if (typeof Spotlight !== 'undefined' && Spotlight.addEventListener) {
|
||||
// Spotlight.addEventListener('focus', (ev) => {
|
||||
// console.log('[SPOTLIGHT: focus]', ev.target);
|
||||
// });
|
||||
// }
|
||||
|
||||
function AppBase(props) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
@@ -17,8 +17,8 @@ export const SOURCE_MENUS = {
|
||||
HOME_GENERAL: 'home_general',
|
||||
THEMED_PRODUCT: 'themed_product',
|
||||
GENERAL_PRODUCT: 'general_product',
|
||||
PLAYER_SHOP_NOW: 'player_shop_now', // PlayerPanel의 ShopNow에서 진입
|
||||
PLAYER_MEDIA: 'player_media', // PlayerPanel의 Media에서 진입
|
||||
PLAYER_SHOP_NOW: 'player_shop_now', // PlayerPanel의 ShopNow에서 진입
|
||||
PLAYER_MEDIA: 'player_media', // PlayerPanel의 Media에서 진입
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -117,19 +117,22 @@ export const navigateToDetail = ({
|
||||
case SOURCE_MENUS.HOME_RANDOM_UNIT:
|
||||
case SOURCE_MENUS.HOME_ROLLING_UNIT:
|
||||
case SOURCE_MENUS.HOME_GENERAL: {
|
||||
|
||||
// ✅ 그라데이션 배경 표시 - HomePanel→DetailPanel 전환 시 (PlayerPanel 출신 제외)
|
||||
|
||||
if (!panelInfo.launchedFromPlayer) {
|
||||
dispatch(updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
showGradientBackground: true,
|
||||
}
|
||||
}));
|
||||
console.log('[TRACE-GRADIENT] 🟢 navigateToDetail set showGradientBackground: true - source:', sourceMenu);
|
||||
dispatch(
|
||||
updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
showGradientBackground: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
// console.log('[TRACE-GRADIENT] 🟢 navigateToDetail set showGradientBackground: true - source:', sourceMenu);
|
||||
} else {
|
||||
console.log('[TRACE-GRADIENT] 🔵 navigateToDetail skipped gradient - launchedFromPlayer: true');
|
||||
console.log(
|
||||
'[TRACE-GRADIENT] 🔵 navigateToDetail skipped gradient - launchedFromPlayer: true'
|
||||
);
|
||||
}
|
||||
|
||||
// HomePanel Redux 상태에 포커스 스냅샷 저장 (Detail→Home 복귀 시 사용)
|
||||
@@ -228,7 +231,7 @@ export const navigateToDetail = ({
|
||||
},
|
||||
})
|
||||
);
|
||||
panelInfo.sourcePanel = panel_names.HOME_PANEL; // ✅ source panel 정보
|
||||
panelInfo.sourcePanel = panel_names.HOME_PANEL; // ✅ source panel 정보
|
||||
panelInfo.fromHome = true;
|
||||
break;
|
||||
}
|
||||
@@ -247,14 +250,14 @@ export const navigateToDetail = ({
|
||||
})
|
||||
);
|
||||
}
|
||||
panelInfo.sourcePanel = panel_names.SEARCH_PANEL; // ✅ source panel 정보
|
||||
panelInfo.sourcePanel = panel_names.SEARCH_PANEL; // ✅ source panel 정보
|
||||
panelInfo.fromSearch = true;
|
||||
panelInfo.searchQuery = additionalInfo.searchVal;
|
||||
break;
|
||||
|
||||
case SOURCE_MENUS.THEMED_PRODUCT:
|
||||
// 테마 상품: 별도 처리 필요할 경우
|
||||
panelInfo.sourcePanel = panel_names.HOME_PANEL; // ✅ source panel 정보 (HOME으로 간주)
|
||||
panelInfo.sourcePanel = panel_names.HOME_PANEL; // ✅ source panel 정보 (HOME으로 간주)
|
||||
break;
|
||||
|
||||
case SOURCE_MENUS.PLAYER_SHOP_NOW:
|
||||
@@ -271,7 +274,7 @@ export const navigateToDetail = ({
|
||||
}
|
||||
|
||||
// PlayerPanel 정보 보존 (복귀 시 필요)
|
||||
panelInfo.sourcePanel = panel_names.PLAYER_PANEL; // ✅ source panel 정보
|
||||
panelInfo.sourcePanel = panel_names.PLAYER_PANEL; // ✅ source panel 정보
|
||||
panelInfo.fromPlayer = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
*
|
||||
* Panel action (PUSH, POP, UPDATE, RESET)을 감지하고
|
||||
* 자동으로 panel history에 기록
|
||||
*
|
||||
* ⚠️ [251122] DEBUG_MODE = false로 설정되어 모든 로그 출력 비활성화됨
|
||||
* - 로그가 필요하면 DEBUG_MODE를 true로 변경하면 됨
|
||||
* - middleware 동작 자체는 영향받지 않음 (로그만 출력 안됨)
|
||||
*/
|
||||
|
||||
import { types } from '../actions/actionTypes';
|
||||
@@ -11,7 +15,8 @@ import { enqueuePanelHistory, clearPanelHistory } from '../actions/panelHistoryA
|
||||
import { calculateIsPanelOnTop } from '../utils/panelUtils'; // 🎯 isOnTop 유틸리티 함수 import
|
||||
|
||||
// DEBUG_MODE - true인 경우에만 로그 출력
|
||||
const DEBUG_MODE = true;
|
||||
// ⚠️ [251122] panelHistory 로그 비활성화 - 로그 생성 차단
|
||||
const DEBUG_MODE = false;
|
||||
|
||||
/**
|
||||
* Panel history middleware
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
* HomePanel에서 백그라운드로 DetailPanelBackground 이미지들을 미리 로드하여
|
||||
* DetailPanel 진입 시 로딩 지연을 방지
|
||||
*/
|
||||
|
||||
// DEBUG_MODE - true인 경우에만 로그 출력
|
||||
const DEBUG_MODE = false;
|
||||
|
||||
class ImagePreloader {
|
||||
constructor() {
|
||||
this.cache = new Map(); // 로드된 이미지 캐시
|
||||
@@ -33,13 +37,13 @@ class ImagePreloader {
|
||||
img.onload = () => {
|
||||
this.cache.set(src, img);
|
||||
this.loadPromises.delete(src);
|
||||
console.log(`[ImagePreloader] Image loaded: ${src}`);
|
||||
if (DEBUG_MODE) console.log(`[ImagePreloader] Image loaded: ${src}`);
|
||||
resolve(img);
|
||||
};
|
||||
|
||||
img.onerror = () => {
|
||||
this.loadPromises.delete(src);
|
||||
console.error(`[ImagePreloader] Failed to load: ${src}`);
|
||||
if (DEBUG_MODE) console.error(`[ImagePreloader] Failed to load: ${src}`);
|
||||
reject(new Error(`Failed to load image: ${src}`));
|
||||
};
|
||||
|
||||
@@ -58,17 +62,17 @@ class ImagePreloader {
|
||||
*/
|
||||
preloadAllImages(imageMap) {
|
||||
if (this.preloadStarted) {
|
||||
console.log('[ImagePreloader] Preloading already started');
|
||||
if (DEBUG_MODE) console.log('[ImagePreloader] Preloading already started');
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
this.preloadStarted = true;
|
||||
console.log('[ImagePreloader] Starting background preload...');
|
||||
if (DEBUG_MODE) console.log('[ImagePreloader] Starting background preload...');
|
||||
|
||||
const promises = Object.values(imageMap).map(src =>
|
||||
this.preloadImage(src).catch(error => {
|
||||
const promises = Object.values(imageMap).map((src) =>
|
||||
this.preloadImage(src).catch((error) => {
|
||||
// 개별 이미지 로드 실패 시 전체 작업을 중단하지 않음
|
||||
console.warn('[ImagePreloader] Single image load failed:', error.message);
|
||||
if (DEBUG_MODE) console.warn('[ImagePreloader] Single image load failed:', error.message);
|
||||
return null;
|
||||
})
|
||||
);
|
||||
@@ -102,7 +106,7 @@ class ImagePreloader {
|
||||
return {
|
||||
cached: this.cache.size,
|
||||
loading: this.loadPromises.size,
|
||||
preloadStarted: this.preloadStarted
|
||||
preloadStarted: this.preloadStarted,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,16 @@
|
||||
// src/views/DetailPanel/DetailPanel.new.jsx
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
useDispatch,
|
||||
useSelector,
|
||||
} from 'react-redux';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
|
||||
import Spotlight from '@enact/spotlight';
|
||||
import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
|
||||
|
||||
import { getDeviceAdditionInfo } from '../../actions/deviceActions';
|
||||
import { getThemeCurationDetailInfo, updateHomeInfo } from '../../actions/homeActions';
|
||||
import {
|
||||
getMainCategoryDetail,
|
||||
getMainYouMayLike,
|
||||
} from '../../actions/mainActions';
|
||||
import { getMainCategoryDetail, getMainYouMayLike } from '../../actions/mainActions';
|
||||
import { finishModalMediaForce } from '../../actions/mediaActions';
|
||||
import {
|
||||
popPanel,
|
||||
updatePanel,
|
||||
} from '../../actions/panelActions';
|
||||
import { popPanel, updatePanel } from '../../actions/panelActions';
|
||||
import {
|
||||
finishVideoPreview,
|
||||
pauseFullscreenVideo,
|
||||
@@ -34,10 +18,7 @@ import {
|
||||
pauseModalVideo,
|
||||
resumeModalVideo,
|
||||
} from '../../actions/playActions';
|
||||
import {
|
||||
clearProductDetail,
|
||||
getProductOptionId,
|
||||
} from '../../actions/productActions';
|
||||
import { clearProductDetail, getProductOptionId } from '../../actions/productActions';
|
||||
import { clearAllToasts } from '../../actions/toastActions';
|
||||
import TBody from '../../components/TBody/TBody';
|
||||
import TPanel from '../../components/TPanel/TPanel';
|
||||
@@ -152,13 +133,15 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
|
||||
// ✅ DetailPanelBackground 이미지 완전 렌더링 후 그라데이션 배경 숨기기
|
||||
const handleBackgroundImageReady = useCallback(() => {
|
||||
console.log('[TRACE-GRADIENT] ✅ DetailPanel - BackgroundImage fully rendered, hiding gradient');
|
||||
dispatch(updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
showGradientBackground: false,
|
||||
}
|
||||
}));
|
||||
// console.log('[TRACE-GRADIENT] ✅ DetailPanel - BackgroundImage fully rendered, hiding gradient');
|
||||
dispatch(
|
||||
updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
showGradientBackground: false,
|
||||
},
|
||||
})
|
||||
);
|
||||
}, [dispatch]);
|
||||
|
||||
// ✅ [251120] DetailPanel이 사라질 때 처리 - sourcePanel에 따라 switch 문으로 처리
|
||||
@@ -179,32 +162,36 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
case panel_names.PLAYER_PANEL: {
|
||||
// PlayerPanel에서 온 경우: PlayerPanel에 detailPanelClosed flag 전달
|
||||
console.log('[DetailPanel] unmount - PlayerPanel에 detailPanelClosed flag 전달');
|
||||
dispatch(updatePanel({
|
||||
name: panel_names.PLAYER_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
lastFocusedTargetId: panelInfo?.lastFocusedTargetId, // ✅ 포커스 복원 타겟 전달
|
||||
}
|
||||
}));
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.PLAYER_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
lastFocusedTargetId: panelInfo?.lastFocusedTargetId, // ✅ 포커스 복원 타겟 전달
|
||||
},
|
||||
})
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case panel_names.HOME_PANEL: {
|
||||
// HomePanel에서 온 경우: HomePanel에 detailPanelClosed flag 전달
|
||||
console.log('[DetailPanel] unmount - HomePanel에 detailPanelClosed flag 전달');
|
||||
console.log('[TRACE-GRADIENT] 🔶 DetailPanel unmount - HomePanel 복귀');
|
||||
// console.log('[DetailPanel] unmount - HomePanel에 detailPanelClosed flag 전달');
|
||||
// console.log('[TRACE-GRADIENT] 🔶 DetailPanel unmount - HomePanel 복귀');
|
||||
|
||||
dispatch(updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
showGradientBackground: false, // ✅ 명시적으로 그라데이션 끔기
|
||||
}
|
||||
}));
|
||||
dispatch(
|
||||
updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
showGradientBackground: false, // ✅ 명시적으로 그라데이션 끔기
|
||||
},
|
||||
})
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -215,8 +202,8 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
updatePanel({
|
||||
name: panel_names.SEARCH_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
},
|
||||
})
|
||||
@@ -253,7 +240,11 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
case panel_names.SEARCH_PANEL:
|
||||
default:
|
||||
// HomePanel, SearchPanel 등에서 온 경우: 백그라운드 비디오 일시 중지
|
||||
console.log('[DetailPanel] onBackClick - source panel:', sourcePanel, '백그라운드 비디오 일시 중지');
|
||||
console.log(
|
||||
'[DetailPanel] onBackClick - source panel:',
|
||||
sourcePanel,
|
||||
'백그라운드 비디오 일시 중지'
|
||||
);
|
||||
dispatch(pauseFullscreenVideo()); // PLAYER_PANEL 비디오 중지
|
||||
dispatch(finishModalMediaForce()); // MEDIA_PANEL(ProductVideo) 강제 종료
|
||||
dispatch(finishVideoPreview());
|
||||
@@ -271,7 +262,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
fp.pipe(
|
||||
() => panels,
|
||||
fp.get('length'),
|
||||
(length) => length === 3 // PlayerPanel이 [1]에 있고 DetailPanel이 [2]에 있는 상태
|
||||
(length) => length === 3 // PlayerPanel이 [1]에 있고 DetailPanel이 [2]에 있는 상태
|
||||
)() &&
|
||||
fp.pipe(
|
||||
() => panels,
|
||||
@@ -280,14 +271,16 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
)();
|
||||
|
||||
if (shouldUpdatePanel) {
|
||||
console.log('[DetailPanel] onBackClick - PlayerPanel에 detailPanelClosed flag 전달');
|
||||
console.log(
|
||||
'[DetailPanel] onBackClick - PlayerPanel에 detailPanelClosed flag 전달'
|
||||
);
|
||||
dispatch(
|
||||
updatePanel({
|
||||
name: panel_names.PLAYER_PANEL,
|
||||
panelInfo: {
|
||||
thumbnail: fp.pipe(() => panelInfo, fp.get('thumbnailUrl'))(),
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
lastFocusedTargetId: panelInfo?.lastFocusedTargetId, // ✅ 포커스 복원 타겟 전달
|
||||
},
|
||||
@@ -300,15 +293,17 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
case panel_names.HOME_PANEL: {
|
||||
// HomePanel에서 온 경우: HomePanel에 detailPanelClosed flag 전달
|
||||
console.log('[DetailPanel] onBackClick - HomePanel에 detailPanelClosed flag 전달');
|
||||
dispatch(updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
showGradientBackground: false,
|
||||
}
|
||||
}));
|
||||
dispatch(
|
||||
updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
showGradientBackground: false,
|
||||
},
|
||||
})
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -319,8 +314,8 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
updatePanel({
|
||||
name: panel_names.SEARCH_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosed: true, // ✅ flag
|
||||
detailPanelClosedAt: Date.now(), // ✅ 시점 기록
|
||||
detailPanelClosedFromSource: sourceMenu, // ✅ 출처
|
||||
},
|
||||
})
|
||||
@@ -843,9 +838,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
// 백그라운드 전체화면 비디오 제어: DetailPanel 진입/퇴장 시
|
||||
useEffect(() => {
|
||||
// PlayerPanel이 존재하는지 확인 (Modal 또는 Fullscreen)
|
||||
const playerPanel = panels.find(
|
||||
(panel) => panel.name === panel_names.PLAYER_PANEL
|
||||
);
|
||||
const playerPanel = panels.find((panel) => panel.name === panel_names.PLAYER_PANEL);
|
||||
const hasPlayerPanel = !!playerPanel;
|
||||
const isModal = playerPanel?.panelInfo?.modal;
|
||||
|
||||
@@ -856,7 +849,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
hasPlayerPanel,
|
||||
isModal,
|
||||
hasProductVideo,
|
||||
sourceMenu: panelInfo?.sourceMenu
|
||||
sourceMenu: panelInfo?.sourceMenu,
|
||||
});
|
||||
|
||||
// PlayerPanel이 있고, 제품에 비디오가 있을 때만 비디오 멈춤
|
||||
@@ -916,7 +909,6 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
||||
|
||||
return (
|
||||
<div ref={containerRef}>
|
||||
|
||||
<DetailPanelBackground
|
||||
launchedFromPlayer={panelLaunchedFromPlayer}
|
||||
patnrId={panelPatnrId}
|
||||
|
||||
@@ -619,12 +619,12 @@ export default function ProductAllSection({
|
||||
// console.log('[BuyNow] Buy Now button clicked');
|
||||
e.stopPropagation();
|
||||
|
||||
console.log('[ProductAllSection] 🛒 BUY NOW clicked - productData:', {
|
||||
prdtId: productData?.prdtId,
|
||||
patnrId: productData?.patnrId,
|
||||
prdtNm: productData?.prdtNm,
|
||||
hasProductData: !!productData,
|
||||
});
|
||||
// console.log('[ProductAllSection] 🛒 BUY NOW clicked - productData:', {
|
||||
// prdtId: productData?.prdtId,
|
||||
// patnrId: productData?.patnrId,
|
||||
// prdtNm: productData?.prdtNm,
|
||||
// hasProductData: !!productData,
|
||||
// });
|
||||
if (openToast === false) {
|
||||
dispatch(
|
||||
showToast({
|
||||
@@ -665,41 +665,41 @@ export default function ProductAllSection({
|
||||
|
||||
// 스크롤 컨테이너의 클릭 이벤트 추적용 로깅
|
||||
const handleScrollContainerClick = useCallback((e) => {
|
||||
console.log('📱 [ProductAllSection] TScrollerDetail onClick 감지됨', {
|
||||
eventType: e.type,
|
||||
target: e.target?.className,
|
||||
currentTarget: e.currentTarget?.className,
|
||||
bubbles: e.bubbles,
|
||||
defaultPrevented: e.defaultPrevented,
|
||||
timestamp: new Date().getTime(),
|
||||
eventPath: e
|
||||
.composedPath?.()
|
||||
.slice(0, 5)
|
||||
.map((el) => ({
|
||||
tag: el.tagName,
|
||||
className: el.className,
|
||||
id: el.id,
|
||||
})),
|
||||
});
|
||||
// console.log('📱 [ProductAllSection] TScrollerDetail onClick 감지됨', {
|
||||
// eventType: e.type,
|
||||
// target: e.target?.className,
|
||||
// currentTarget: e.currentTarget?.className,
|
||||
// bubbles: e.bubbles,
|
||||
// defaultPrevented: e.defaultPrevented,
|
||||
// timestamp: new Date().getTime(),
|
||||
// eventPath: e
|
||||
// .composedPath?.()
|
||||
// .slice(0, 5)
|
||||
// .map((el) => ({
|
||||
// tag: el.tagName,
|
||||
// className: el.className,
|
||||
// id: el.id,
|
||||
// })),
|
||||
// });
|
||||
}, []);
|
||||
|
||||
// ContentContainer 레벨 클릭 이벤트 추적
|
||||
const handleContentContainerClick = useCallback((e) => {
|
||||
console.log('🎯 [ProductAllSection] ContentContainer onClick 감지됨', {
|
||||
eventType: e.type,
|
||||
target: e.target?.className,
|
||||
currentTarget: e.currentTarget?.className,
|
||||
bubbles: e.bubbles,
|
||||
defaultPrevented: e.defaultPrevented,
|
||||
eventPath: e
|
||||
.composedPath?.()
|
||||
.slice(0, 8)
|
||||
.map((el) => ({
|
||||
tag: el.tagName,
|
||||
className: el.className,
|
||||
id: el.id,
|
||||
})),
|
||||
});
|
||||
// console.log('🎯 [ProductAllSection] ContentContainer onClick 감지됨', {
|
||||
// eventType: e.type,
|
||||
// target: e.target?.className,
|
||||
// currentTarget: e.currentTarget?.className,
|
||||
// bubbles: e.bubbles,
|
||||
// defaultPrevented: e.defaultPrevented,
|
||||
// eventPath: e
|
||||
// .composedPath?.()
|
||||
// .slice(0, 8)
|
||||
// .map((el) => ({
|
||||
// tag: el.tagName,
|
||||
// className: el.className,
|
||||
// id: el.id,
|
||||
// })),
|
||||
// });
|
||||
}, []);
|
||||
|
||||
// ADD TO CART 버튼 클릭 핸들러
|
||||
@@ -998,7 +998,7 @@ export default function ProductAllSection({
|
||||
|
||||
// 아래로 스크롤: 즉시 1px 축소 (HomePanel과 동일)
|
||||
if (isScrollingDown && currentScrollTop > 0) {
|
||||
console.log('🚀 [ProductVideo.v3] onScroll Down - immediate minimize');
|
||||
// console.log('🚀 [ProductVideo.v3] onScroll Down - immediate minimize');
|
||||
dispatch(minimizeModalMedia());
|
||||
setShouldMinimizeMedia(true);
|
||||
|
||||
@@ -1010,7 +1010,7 @@ export default function ProductAllSection({
|
||||
}
|
||||
// 위로 스크롤 (최상단 아님): 1초 후 복구
|
||||
else if (!isScrollingDown && currentScrollTop > 1) {
|
||||
console.log('🚀 [ProductVideo.v3] onScroll Up - expand after 1s');
|
||||
// console.log('🚀 [ProductVideo.v3] onScroll Up - expand after 1s');
|
||||
|
||||
if (scrollExpandTimerRef.current) {
|
||||
clearTimeout(scrollExpandTimerRef.current);
|
||||
@@ -1023,7 +1023,7 @@ export default function ProductAllSection({
|
||||
}
|
||||
// 최상단 도달: 즉시 복구 (HomePanel과 동일)
|
||||
else if (currentScrollTop <= 1) {
|
||||
console.log('🚀 [ProductVideo.v3] onScroll AtTop - immediate expand');
|
||||
// console.log('🚀 [ProductVideo.v3] onScroll AtTop - immediate expand');
|
||||
dispatch(restoreModalMedia());
|
||||
setShouldMinimizeMedia(false);
|
||||
|
||||
@@ -1053,12 +1053,12 @@ export default function ProductAllSection({
|
||||
}
|
||||
}
|
||||
|
||||
console.log('📍 [ProductAllSection] 스크롤 멈춤 - 위치:', currentScrollTop);
|
||||
// console.log('📍 [ProductAllSection] 스크롤 멈춤 - 위치:', currentScrollTop);
|
||||
|
||||
const shouldMinimize = currentScrollTop > 0;
|
||||
setShouldMinimizeMedia((prev) => {
|
||||
if (prev === shouldMinimize) return prev;
|
||||
console.log('📍 [ProductAllSection] setShouldMinimizeMedia 호출:', shouldMinimize);
|
||||
// console.log('📍 [ProductAllSection] setShouldMinimizeMedia 호출:', shouldMinimize);
|
||||
return shouldMinimize;
|
||||
});
|
||||
},
|
||||
@@ -1067,11 +1067,11 @@ export default function ProductAllSection({
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldMinimizeMedia && !mediaMinimizedRef.current) {
|
||||
console.log('📍 [ProductAllSection] MediaPanel 최소화 (effect)');
|
||||
// console.log('📍 [ProductAllSection] MediaPanel 최소화 (effect)');
|
||||
dispatch(minimizeModalMedia());
|
||||
mediaMinimizedRef.current = true;
|
||||
} else if (!shouldMinimizeMedia && mediaMinimizedRef.current) {
|
||||
console.log('📍 [ProductAllSection] MediaPanel 복원 (effect)');
|
||||
// console.log('📍 [ProductAllSection] MediaPanel 복원 (effect)');
|
||||
dispatch(restoreModalMedia());
|
||||
mediaMinimizedRef.current = false;
|
||||
}
|
||||
@@ -1181,7 +1181,7 @@ export default function ProductAllSection({
|
||||
// 컴포넌트 unmount 시 timer cleanup
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
console.log('[ProductAllSection] unmount - cleanup 시작');
|
||||
// console.log('[ProductAllSection] unmount - cleanup 시작');
|
||||
|
||||
// QR code timer cleanup
|
||||
if (timerRef.current) {
|
||||
@@ -1208,7 +1208,7 @@ export default function ProductAllSection({
|
||||
|
||||
// 🔽 useDetailFocus 포커스 타이머는 Hook의 useEffect cleanup에서 자동으로 정리됨
|
||||
|
||||
console.log('[ProductAllSection] cleanup 완료 on unmount');
|
||||
// console.log('[ProductAllSection] cleanup 완료 on unmount');
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -1501,7 +1501,7 @@ export default function ProductAllSection({
|
||||
continuousPlay={true}
|
||||
onVideoPlaying={() => setIsVideoPlaying(true)}
|
||||
onScrollToImages={handleScrollToImagesV1}
|
||||
onFocus={() => console.log('[ProductVideo V1] Focused')}
|
||||
onFocus={() => {}}
|
||||
data-spotlight-id="product-video-player-container"
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
// src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.jsx
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import ImagePreloader from '../../../../utils/ImagePreloader';
|
||||
|
||||
import hsn from '../../../../../assets/images/bg/hsn_new.png';
|
||||
import koreaKiosk from '../../../../../assets/images/bg/koreaKiosk_new.png';
|
||||
import lgelectronics
|
||||
from '../../../../../assets/images/bg/lgelectronics_new.png';
|
||||
import lgelectronics from '../../../../../assets/images/bg/lgelectronics_new.png';
|
||||
import ontv4u from '../../../../../assets/images/bg/ontv4u_new.png';
|
||||
import Pinkfong from '../../../../../assets/images/bg/Pinkfong_new.png';
|
||||
import qvc from '../../../../../assets/images/bg/qvc_new.png';
|
||||
@@ -29,7 +22,11 @@ import css from './DetailPanelBackground.module.less';
|
||||
* - 이 값에 따라 배경 UI를 다르게 표시할 수 있음
|
||||
* @param {Function} onImageReady - 이미지가 DOM에 완전히 렌더링되었을 때 호출되는 콜백
|
||||
*/
|
||||
export default function DetailPanelBackground({ launchedFromPlayer = false, patnrId, onImageReady }) {
|
||||
export default function DetailPanelBackground({
|
||||
launchedFromPlayer = false,
|
||||
patnrId,
|
||||
onImageReady,
|
||||
}) {
|
||||
const [imageReady, setImageReady] = useState(false);
|
||||
const imgRef = useRef(null);
|
||||
|
||||
@@ -59,16 +56,16 @@ export default function DetailPanelBackground({ launchedFromPlayer = false, patn
|
||||
|
||||
const isDOMReady = isLoaded && isRendered;
|
||||
|
||||
if (isDOMReady) {
|
||||
console.log('[DetailPanelBackground] ✅ 이미지 DOM 완전 렌더링 완료:', {
|
||||
imgSrc: detailPanelBg,
|
||||
complete: img.complete,
|
||||
naturalWidth: img.naturalWidth,
|
||||
naturalHeight: img.naturalHeight,
|
||||
offsetHeight: img.offsetHeight,
|
||||
offsetWidth: img.offsetWidth,
|
||||
});
|
||||
}
|
||||
// if (isDOMReady) {
|
||||
// console.log('[DetailPanelBackground] ✅ 이미지 DOM 완전 렌더링 완료:', {
|
||||
// imgSrc: detailPanelBg,
|
||||
// complete: img.complete,
|
||||
// naturalWidth: img.naturalWidth,
|
||||
// naturalHeight: img.naturalHeight,
|
||||
// offsetHeight: img.offsetHeight,
|
||||
// offsetWidth: img.offsetWidth,
|
||||
// });
|
||||
// }
|
||||
|
||||
return isDOMReady;
|
||||
}, [detailPanelBg]);
|
||||
@@ -78,26 +75,26 @@ export default function DetailPanelBackground({ launchedFromPlayer = false, patn
|
||||
useEffect(() => {
|
||||
// launchedFromPlayer가 true이면 배경 이미지를 로드하지 않음 (PlayerPanel 비디오 보이도록)
|
||||
if (launchedFromPlayer) {
|
||||
console.log('[DetailPanelBackground] Skip background image loading - launchedFromPlayer=true (showing PlayerPanel video)');
|
||||
// console.log('[DetailPanelBackground] Skip background image loading - launchedFromPlayer=true (showing PlayerPanel video)');
|
||||
setImageReady(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// launchedFromPlayer가 false일 때만 배경 이미지 로드
|
||||
console.log('[DetailPanelBackground] Loading background image - launchedFromPlayer=false');
|
||||
// console.log('[DetailPanelBackground] Loading background image - launchedFromPlayer=false');
|
||||
if (ImagePreloader.isLoaded(detailPanelBg)) {
|
||||
console.log('[DetailPanelBackground] Using preloaded image:', detailPanelBg);
|
||||
// console.log('[DetailPanelBackground] Using preloaded image:', detailPanelBg);
|
||||
setImageReady(true);
|
||||
} else {
|
||||
// 프리로드되지 않았다면 즉시 로드 시도
|
||||
console.log('[DetailPanelBackground] Image not preloaded, loading on-demand:', detailPanelBg);
|
||||
// console.log('[DetailPanelBackground] Image not preloaded, loading on-demand:', detailPanelBg);
|
||||
ImagePreloader.preloadImage(detailPanelBg)
|
||||
.then(() => {
|
||||
console.log('[DetailPanelBackground] On-demand image loaded:', detailPanelBg);
|
||||
// console.log('[DetailPanelBackground] On-demand image loaded:', detailPanelBg);
|
||||
setImageReady(true);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('[DetailPanelBackground] On-demand image load failed:', e);
|
||||
// console.error('[DetailPanelBackground] On-demand image load failed:', e);
|
||||
// 실패해도 이미지를 표시해야 함
|
||||
setImageReady(true);
|
||||
});
|
||||
@@ -137,23 +134,18 @@ export default function DetailPanelBackground({ launchedFromPlayer = false, patn
|
||||
}
|
||||
}, [imageReady, onImageReady, checkImageFullyLoaded]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('[DetailPanelBackground] 배경 이미지 경로:', detailPanelBg);
|
||||
console.log('[DetailPanelBackground] launchedFromPlayer:', launchedFromPlayer);
|
||||
console.log('[DetailPanelBackground] imageReady:', imageReady);
|
||||
}, [detailPanelBg, launchedFromPlayer, imageReady]);
|
||||
// useEffect(() => {
|
||||
// console.log('[DetailPanelBackground] 배경 이미지 경로:', detailPanelBg);
|
||||
// console.log('[DetailPanelBackground] launchedFromPlayer:', launchedFromPlayer);
|
||||
// console.log('[DetailPanelBackground] imageReady:', imageReady);
|
||||
// }, [detailPanelBg, launchedFromPlayer, imageReady]);
|
||||
|
||||
//partnrId 1 = QVC, 2 = HSN, 4 = ONTV, 9 = LG ELECTRONICS, 11 = SHOPLC, 19 = PINKPONG, 16 = KOREA KIOSK,
|
||||
|
||||
return (
|
||||
<div className={css.backgroundContainer}>
|
||||
{/* 이미지가 준비되지 않았을 때 placeholder 표시 */}
|
||||
{!imageReady && (
|
||||
<div
|
||||
className={css.backgroundPlaceholder}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
{!imageReady && <div className={css.backgroundPlaceholder} aria-hidden="true" />}
|
||||
|
||||
{/* 실제 배경 이미지 - launchedFromPlayer가 false일 때만 표시 */}
|
||||
{imageReady && !launchedFromPlayer && (
|
||||
@@ -163,24 +155,18 @@ export default function DetailPanelBackground({ launchedFromPlayer = false, patn
|
||||
alt=""
|
||||
className={css.backgroundImage}
|
||||
aria-hidden="true"
|
||||
onLoad={() => console.log('[DetailPanelBackground] 이미지 로드 완료')}
|
||||
onError={(e) => console.error('[DetailPanelBackground] 이미지 로드 실패:', e)}
|
||||
// onLoad={() => console.log('[DetailPanelBackground] 이미지 로드 완료')}
|
||||
// onError={(e) => console.error('[DetailPanelBackground] 이미지 로드 실패:', e)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 그라데이션 레이어들 - launchedFromPlayer일 때만 추가 */}
|
||||
{/* 1. 270도 방향 그라데이션 (왼쪽→오른쪽, 투명→불투명) */}
|
||||
{launchedFromPlayer && (
|
||||
<div className={css.gradientLayer1} aria-hidden="true" />
|
||||
)}
|
||||
{launchedFromPlayer && <div className={css.gradientLayer1} aria-hidden="true" />}
|
||||
{/* 2. 180도 방향 그라데이션 (위→아래, 투명→불투명) */}
|
||||
{launchedFromPlayer && (
|
||||
<div className={css.gradientLayer2} aria-hidden="true" />
|
||||
)}
|
||||
{launchedFromPlayer && <div className={css.gradientLayer2} aria-hidden="true" />}
|
||||
{/* 3. 투명 그라데이션 */}
|
||||
{launchedFromPlayer && (
|
||||
<div className={css.gradientLayer3} aria-hidden="true" />
|
||||
)}
|
||||
{launchedFromPlayer && <div className={css.gradientLayer3} aria-hidden="true" />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,26 +18,26 @@ import css from './DetailPanelBackground.module.less';
|
||||
* @param {boolean} visible - 표시 여부
|
||||
* @param {string} imageUrl - 이미지 URL
|
||||
*/
|
||||
const logDetailPanelInit = (patnrId, visible, imageUrl) => {
|
||||
console.log(`[DetailPanelBackgroundV2] patnrId: ${patnrId}, visible: ${visible}, imageUrl: ${imageUrl}`);
|
||||
};
|
||||
// const logDetailPanelInit = (patnrId, visible, imageUrl) => {
|
||||
// console.log(`[DetailPanelBackgroundV2] patnrId: ${patnrId}, visible: ${visible}, imageUrl: ${imageUrl}`);
|
||||
// };
|
||||
|
||||
/**
|
||||
* 이미지 로드 성공 로그
|
||||
* @param {number} patnrId - 파트너사 ID
|
||||
*/
|
||||
const logImageLoaded = (patnrId) => {
|
||||
console.log(`[DetailPanelBackgroundV2] Image loaded: patnrId=${patnrId}`);
|
||||
};
|
||||
// const logImageLoaded = (patnrId) => {
|
||||
// console.log(`[DetailPanelBackgroundV2] Image loaded: patnrId=${patnrId}`);
|
||||
// };
|
||||
|
||||
/**
|
||||
* 이미지 로드 실패 로그
|
||||
* @param {number} patnrId - 파트너사 ID
|
||||
* @param {Error} error - 에러 객체
|
||||
*/
|
||||
const logImageError = (patnrId, error) => {
|
||||
console.error(`[DetailPanelBackgroundV2] Image load failed: patnrId=${patnrId}`, error);
|
||||
};
|
||||
// const logImageError = (patnrId, error) => {
|
||||
// console.error(`[DetailPanelBackgroundV2] Image load failed: patnrId=${patnrId}`, error);
|
||||
// };
|
||||
|
||||
/**
|
||||
* 개선된 배경 이미지 컴포넌트 v2
|
||||
@@ -53,18 +53,21 @@ export default function DetailPanelBackgroundV2({
|
||||
patnrId,
|
||||
visible = true,
|
||||
launchedFromPlayer = false,
|
||||
usePlaceholder = false
|
||||
usePlaceholder = false,
|
||||
}) {
|
||||
// 파트너사별 배경 이미지 맵
|
||||
const BG_MAP = useMemo(() => ({
|
||||
1: qvc, // QVC
|
||||
2: hsn, // HSN
|
||||
4: ontv4u, // ONTV4U
|
||||
9: lgelectronics,// LG ELECTRONICS
|
||||
11: shoplc, // SHOPLC
|
||||
16: koreaKiosk, // KOREA KIOSK
|
||||
19: Pinkfong, // PINKFONG
|
||||
}), []);
|
||||
const BG_MAP = useMemo(
|
||||
() => ({
|
||||
1: qvc, // QVC
|
||||
2: hsn, // HSN
|
||||
4: ontv4u, // ONTV4U
|
||||
9: lgelectronics, // LG ELECTRONICS
|
||||
11: shoplc, // SHOPLC
|
||||
16: koreaKiosk, // KOREA KIOSK
|
||||
19: Pinkfong, // PINKFONG
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const backgroundImageUrl = useMemo(() => {
|
||||
return BG_MAP[patnrId] || qvc; // 기본값은 QVC
|
||||
@@ -75,9 +78,12 @@ export default function DetailPanelBackgroundV2({
|
||||
logImageLoaded(patnrId);
|
||||
}, [patnrId]);
|
||||
|
||||
const handleImageError = useCallback((e) => {
|
||||
logImageError(patnrId, e);
|
||||
}, [patnrId]);
|
||||
const handleImageError = useCallback(
|
||||
(e) => {
|
||||
logImageError(patnrId, e);
|
||||
},
|
||||
[patnrId]
|
||||
);
|
||||
|
||||
// 개발 환경에서만 로깅
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
@@ -113,7 +119,8 @@ export default function DetailPanelBackgroundV2({
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
background: 'linear-gradient(270deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.77) 70%, rgba(0, 0, 0, 1) 100%)',
|
||||
background:
|
||||
'linear-gradient(270deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.77) 70%, rgba(0, 0, 0, 1) 100%)',
|
||||
zIndex: 3,
|
||||
}}
|
||||
aria-hidden="true"
|
||||
@@ -190,7 +197,7 @@ export default function DetailPanelBackgroundV2({
|
||||
export function PreloadedBackgroundImages({
|
||||
selectedPatnrId,
|
||||
isHomePanelOnTop = true,
|
||||
launchedFromPlayer = false
|
||||
launchedFromPlayer = false,
|
||||
}) {
|
||||
// 모든 파트너사 ID 목록
|
||||
const allPatnrIds = useMemo(() => [1, 2, 4, 9, 11, 16, 19], []);
|
||||
@@ -205,7 +212,7 @@ export function PreloadedBackgroundImages({
|
||||
isHomePanelOnTop,
|
||||
launchedFromPlayer,
|
||||
shouldShowBackground,
|
||||
allPatnrIds
|
||||
allPatnrIds,
|
||||
});
|
||||
}, [selectedPatnrId, isHomePanelOnTop, launchedFromPlayer, shouldShowBackground]);
|
||||
|
||||
|
||||
@@ -67,16 +67,6 @@ export default function FavoriteBtn({
|
||||
onFavoriteFlagChanged(favoriteFlag === 'Y' ? 'N' : 'Y');
|
||||
}, [dispatch, favoriteFlag, onFavoriteFlagChanged]);
|
||||
|
||||
const handleFavoriteKeyDown = useCallback(
|
||||
(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
handleFavoriteClick();
|
||||
}
|
||||
},
|
||||
[handleFavoriteClick]
|
||||
);
|
||||
|
||||
const handleSpotlightDown = useCallback(
|
||||
(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -107,7 +97,6 @@ export default function FavoriteBtn({
|
||||
aria-label="Register in Favorites"
|
||||
tabIndex={0}
|
||||
onClick={handleFavoriteClick}
|
||||
onKeyDown={handleFavoriteKeyDown}
|
||||
onSpotlightDown={handleSpotlightDown}
|
||||
data-spotlight-next-down={
|
||||
kind === 'item_detail' ? nextDownId || 'product-details-button' : undefined
|
||||
|
||||
@@ -57,13 +57,13 @@ import shoplc from '../../../assets/images/bg/shoplc_new.png';
|
||||
|
||||
// 파트너사별 배경 이미지 맵
|
||||
const BACKGROUND_IMAGES = {
|
||||
1: qvc, // QVC
|
||||
2: hsn, // HSN
|
||||
4: ontv4u, // ONTV
|
||||
1: qvc, // QVC
|
||||
2: hsn, // HSN
|
||||
4: ontv4u, // ONTV
|
||||
9: lgelectronics, // LG ELECTRONICS
|
||||
11: shoplc, // SHOPLC
|
||||
16: koreaKiosk, // KOREA KIOSK
|
||||
19: Pinkfong, // PINKFONG
|
||||
11: shoplc, // SHOPLC
|
||||
16: koreaKiosk, // KOREA KIOSK
|
||||
19: Pinkfong, // PINKFONG
|
||||
};
|
||||
// [COMMENTED OUT] useVideoMove 관련 코드 주석 처리 - 향후 사용 검토 필요
|
||||
// import { useVideoMove } from '../../hooks/useVideoTransition/useVideoMove';
|
||||
@@ -98,16 +98,16 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// ✅ showGradientBackground prop 변경 추적 로그
|
||||
const prevShowGradientBackground = usePrevious(showGradientBackground);
|
||||
useEffect(() => {
|
||||
if (prevShowGradientBackground !== showGradientBackground) {
|
||||
console.log('[TRACE-GRADIENT] 📊 HomePanel prop changed:', {
|
||||
prev: prevShowGradientBackground,
|
||||
current: showGradientBackground,
|
||||
isOnTop: isOnTop
|
||||
});
|
||||
}
|
||||
}, [showGradientBackground, prevShowGradientBackground, isOnTop]);
|
||||
// const prevShowGradientBackground = usePrevious(showGradientBackground);
|
||||
// useEffect(() => {
|
||||
// if (prevShowGradientBackground !== showGradientBackground) {
|
||||
// console.log('[TRACE-GRADIENT] 📊 HomePanel prop changed:', {
|
||||
// prev: prevShowGradientBackground,
|
||||
// current: showGradientBackground,
|
||||
// isOnTop: isOnTop
|
||||
// });
|
||||
// }
|
||||
// }, [showGradientBackground, prevShowGradientBackground, isOnTop]);
|
||||
|
||||
useDebugKey({ isLandingPage: true });
|
||||
|
||||
@@ -187,7 +187,6 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
const verticalPagenatorRef = useRef(null);
|
||||
const currentSentMenuRef = useRef(null);
|
||||
|
||||
|
||||
// ✅ [251119] DetailPanelBackground 이미지 프리로딩
|
||||
// HomePanel 마운트 시 백그라운드로 모든 파트너사 배경 이미지를 미리 로드하여
|
||||
// DetailPanel 진입 시 로딩 지연을 방지함
|
||||
@@ -198,8 +197,10 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
setTimeout(() => {
|
||||
ImagePreloader.preloadAllImages(BACKGROUND_IMAGES)
|
||||
.then((results) => {
|
||||
const successCount = results.filter(r => r !== null).length;
|
||||
console.log(`[HomePanel] Background images preloaded: ${successCount}/${results.length} images`);
|
||||
const successCount = results.filter((r) => r !== null).length;
|
||||
console.log(
|
||||
`[HomePanel] Background images preloaded: ${successCount}/${results.length} images`
|
||||
);
|
||||
|
||||
// 프리로딩 통계 정보 로깅 (디버깅용)
|
||||
const stats = ImagePreloader.getStats();
|
||||
@@ -756,36 +757,36 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
// 비디오가 재생이 아니면 videoPlayIntentRef의 bannerId로 비디오 재생
|
||||
// [251116] isHomeOnTop인 경우에는 비디오가 항상 재생되어야 함
|
||||
useEffect(() => {
|
||||
console.log('[HomeActive] useEffect 실행 - isOnTop:', isOnTop);
|
||||
console.log('[HomeActive] videoPlayIntentRef.current:', videoPlayIntentRef.current);
|
||||
console.log(
|
||||
'[HomeActive] panels 상태:',
|
||||
panels.map((p) => ({ name: p.name, modal: p.panelInfo?.modal }))
|
||||
);
|
||||
// console.log('[HomeActive] useEffect 실행 - isOnTop:', isOnTop);
|
||||
// console.log('[HomeActive] videoPlayIntentRef.current:', videoPlayIntentRef.current);
|
||||
// console.log(
|
||||
// '[HomeActive] panels 상태:',
|
||||
// panels.map((p) => ({ name: p.name, modal: p.panelInfo?.modal }))
|
||||
// );
|
||||
|
||||
const isHomePanelActive = isOnTop;
|
||||
console.log('[HomeActive] isHomePanelActive:', isHomePanelActive);
|
||||
// console.log('[HomeActive] isHomePanelActive:', isHomePanelActive);
|
||||
|
||||
if (!isHomePanelActive) {
|
||||
console.log('[HomeActive] 조건 실패: isHomePanelActive가 false');
|
||||
// console.log('[HomeActive] 조건 실패: isHomePanelActive가 false');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!videoPlayIntentRef.current?.bannerId) {
|
||||
console.log('[HomeActive] 조건 실패: videoPlayIntentRef.current?.bannerId가 없음', {
|
||||
hasRef: !!videoPlayIntentRef.current,
|
||||
hasBannerId: !!videoPlayIntentRef.current?.bannerId,
|
||||
});
|
||||
// console.log('[HomeActive] 조건 실패: videoPlayIntentRef.current?.bannerId가 없음', {
|
||||
// hasRef: !!videoPlayIntentRef.current,
|
||||
// hasBannerId: !!videoPlayIntentRef.current?.bannerId,
|
||||
// });
|
||||
return;
|
||||
}
|
||||
|
||||
const bannerId = videoPlayIntentRef.current.bannerId;
|
||||
console.log('[HomeActive] 비디오 재생 시도 - bannerId:', bannerId);
|
||||
console.log('[HomeActive] 마지막 재생한 배너:', lastPlayedBannerIdRef.current);
|
||||
// console.log('[HomeActive] 비디오 재생 시도 - bannerId:', bannerId);
|
||||
// console.log('[HomeActive] 마지막 재생한 배너:', lastPlayedBannerIdRef.current);
|
||||
|
||||
// ✅ [251116] 중복 재생 방지: 같은 배너면 스킵
|
||||
if (lastPlayedBannerIdRef.current === bannerId) {
|
||||
console.log('[HomeActive] 중복 호출 감지 - 스킵 (이미 재생 중)');
|
||||
// console.log('[HomeActive] 중복 호출 감지 - 스킵 (이미 재생 중)');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -799,7 +800,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
// }
|
||||
|
||||
// ✅ [251116] startVideoPlayerNew로 비디오 자동 재생
|
||||
console.log('[HomeActive] dispatch(startVideoPlayerNew) 호출 직전:', { bannerId, modal: true });
|
||||
// console.log('[HomeActive] dispatch(startVideoPlayerNew) 호출 직전:', { bannerId, modal: true });
|
||||
|
||||
// Spotlight.focus(bannerId);
|
||||
// dispatch(
|
||||
@@ -809,11 +810,11 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
// modalContainerId: 'banner-modal-' + bannerId,
|
||||
// })
|
||||
// );
|
||||
console.log('[HomeActive] dispatch(startVideoPlayerNew) 호출 완료');
|
||||
// console.log('[HomeActive] dispatch(startVideoPlayerNew) 호출 완료');
|
||||
|
||||
// 재생 기록 업데이트
|
||||
lastPlayedBannerIdRef.current = bannerId;
|
||||
console.log('[HomeActive] 재생 기록 업데이트:', bannerId);
|
||||
// console.log('[HomeActive] 재생 기록 업데이트:', bannerId);
|
||||
}, [isOnTop, dispatch]);
|
||||
|
||||
// ✅ [251120] DetailPanel 닫힘 감지 useEffect - detailPanelClosed flag 사용
|
||||
@@ -826,13 +827,13 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (detailPanelClosed && isOnTop) {
|
||||
console.log('[TRACE-GRADIENT] 🔄 detailPanelClosed flag triggered - HomePanel reactivated');
|
||||
console.log('[HomePanel] *** ✅ HomePanel isOnTop = true');
|
||||
console.log('[HomePanel] *** detailPanelClosed:', detailPanelClosed);
|
||||
console.log('[HomePanel] *** detailPanelClosedTime:', detailPanelClosedTime);
|
||||
console.log('[HomePanel] *** isOnTop:', isOnTop);
|
||||
console.log('[HomePanel] *** videoPlayIntentRef.current:', videoPlayIntentRef.current);
|
||||
console.log('[HomePanel] *** lastPlayedBannerIdRef.current:', lastPlayedBannerIdRef.current);
|
||||
// console.log('[TRACE-GRADIENT] 🔄 detailPanelClosed flag triggered - HomePanel reactivated');
|
||||
// console.log('[HomePanel] *** ✅ HomePanel isOnTop = true');
|
||||
// console.log('[HomePanel] *** detailPanelClosed:', detailPanelClosed);
|
||||
// console.log('[HomePanel] *** detailPanelClosedTime:', detailPanelClosedTime);
|
||||
// console.log('[HomePanel] *** isOnTop:', isOnTop);
|
||||
// console.log('[HomePanel] *** videoPlayIntentRef.current:', videoPlayIntentRef.current);
|
||||
// console.log('[HomePanel] *** lastPlayedBannerIdRef.current:', lastPlayedBannerIdRef.current);
|
||||
|
||||
// 🔽 videoPlayIntentRef가 null인 경우: 비디오 재생 가능한 첫 번째 배너 찾기
|
||||
if (!videoPlayIntentRef.current && bannerDataList) {
|
||||
@@ -858,7 +859,9 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
break;
|
||||
}
|
||||
} else if (
|
||||
bannerDetailInfos.find((el) => el.shptmBanrTpNm === 'LIVE' || el.shptmBanrTpNm === 'VOD')
|
||||
bannerDetailInfos.find(
|
||||
(el) => el.shptmBanrTpNm === 'LIVE' || el.shptmBanrTpNm === 'VOD'
|
||||
)
|
||||
) {
|
||||
targetIndex = i;
|
||||
targetBannerData = data;
|
||||
@@ -904,7 +907,12 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
// 🔽 [251118] 현재 스크롤 위치 확인하여 비디오 크기 결정
|
||||
const currentScrollTop = prevScrollTopRef.current;
|
||||
const shouldShrink = currentScrollTop > 0;
|
||||
console.log('[HomePanel] *** 비디오 복구 - currentScrollTop:', currentScrollTop, ', shouldShrink:', shouldShrink);
|
||||
console.log(
|
||||
'[HomePanel] *** 비디오 복구 - currentScrollTop:',
|
||||
currentScrollTop,
|
||||
', shouldShrink:',
|
||||
shouldShrink
|
||||
);
|
||||
|
||||
dispatch(
|
||||
startVideoPlayerNew({
|
||||
@@ -927,7 +935,15 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
// 🔽 DetailPanel에서 돌아온 뒤 포커스를 마지막 포커스 대상에 복원
|
||||
console.log('[HomePanel] *** 🎯 Focus 복원 준비');
|
||||
const targetFocusId = panelInfo.lastFocusedTargetId || lastFocusedTargetRef.current;
|
||||
console.log('[HomePanel] *** 📍 targetFocusId:', targetFocusId, '(panelInfo.lastFocusedTargetId:', panelInfo.lastFocusedTargetId, ', lastFocusedTargetRef:', lastFocusedTargetRef.current, ')');
|
||||
console.log(
|
||||
'[HomePanel] *** 📍 targetFocusId:',
|
||||
targetFocusId,
|
||||
'(panelInfo.lastFocusedTargetId:',
|
||||
panelInfo.lastFocusedTargetId,
|
||||
', lastFocusedTargetRef:',
|
||||
lastFocusedTargetRef.current,
|
||||
')'
|
||||
);
|
||||
if (targetFocusId) {
|
||||
console.log('[HomePanel] *** ⏰ 300ms 후 Spotlight.focus 호출 예정');
|
||||
setTimeout(() => {
|
||||
@@ -944,14 +960,16 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
|
||||
// detailPanelClosed 플래그 초기화 (다음 사이클에서 재사용 방지)
|
||||
console.log('[HomePanel] *** detailPanelClosed flag 초기화');
|
||||
dispatch(updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: false,
|
||||
detailPanelClosedAt: undefined,
|
||||
detailPanelClosedFromSource: undefined,
|
||||
}
|
||||
}));
|
||||
dispatch(
|
||||
updateHomeInfo({
|
||||
name: panel_names.HOME_PANEL,
|
||||
panelInfo: {
|
||||
detailPanelClosed: false,
|
||||
detailPanelClosedAt: undefined,
|
||||
detailPanelClosedFromSource: undefined,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [detailPanelClosed, isOnTop, bannerDataList, dispatch]);
|
||||
@@ -1003,11 +1021,10 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
|
||||
console.log('[HomePanel] 🔍 Modal 상태 체크:', {
|
||||
prevModalState,
|
||||
playerModalState,
|
||||
shouldExecute: prevModalState === false && playerModalState === true
|
||||
shouldExecute: prevModalState === false && playerModalState === true,
|
||||
});
|
||||
|
||||
if (prevModalState === false && playerModalState === true) {
|
||||
|
||||
console.log('>>>>>[HomePanel] ▶️ PlayerPanel이 Fullscreen에서 Banner로 전환됨');
|
||||
// 0.5초 후 비디오가 재생되는 배너에 포커스 테두리 효과 적용
|
||||
// const focusTimer = setTimeout(() => {
|
||||
|
||||
Reference in New Issue
Block a user