[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:
2025-11-22 18:19:45 +09:00
parent 9878c39512
commit 251e1ee3d4
10 changed files with 304 additions and 301 deletions

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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,
};
}

View File

@@ -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}

View File

@@ -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"
/>
) : (

View File

@@ -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>
);
}

View File

@@ -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]);

View File

@@ -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

View File

@@ -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(() => {