1 Commits

Author SHA1 Message Date
0cd22f4989 [251216] fix: panelHistoryMiddleware log
🕐 커밋 시간: 2025. 12. 16. 10:09:15

📊 변경 통계:
  • 총 파일: 1개
  • 추가: +7줄
  • 삭제: -4줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js

🔧 주요 변경 내용:
  • 핵심 비즈니스 로직 개선
  • 코드 정리 및 최적화
2025-12-16 10:09:15 +09:00
33 changed files with 805 additions and 1469 deletions

View File

@@ -85,7 +85,6 @@ export const handleDeepLink = (contentTarget) => (dispatch, _getState) => {
patnrId: patnrId, patnrId: patnrId,
chanId: chanId, chanId: chanId,
shptmBanrTpNm: "LIVE", shptmBanrTpNm: "LIVE",
modal: false, // DeepLink 진입 시 fullscreen으로 재생
// expsOrd: expsOrd, // expsOrd: expsOrd,
}; };
break; break;
@@ -102,7 +101,6 @@ export const handleDeepLink = (contentTarget) => (dispatch, _getState) => {
patnrId: patnrId, patnrId: patnrId,
showId: showId, showId: showId,
shptmBanrTpNm: "VOD", shptmBanrTpNm: "VOD",
modal: false, // DeepLink 진입 시 fullscreen으로 재생
// expsOrd: expsOrd, // expsOrd: expsOrd,
}; };
break; break;
@@ -276,18 +274,6 @@ export const handleDeepLink = (contentTarget) => (dispatch, _getState) => {
const action = const action =
panelName === panel_names.HOME_PANEL ? updateHomeInfo : pushPanel; panelName === panel_names.HOME_PANEL ? updateHomeInfo : pushPanel;
// 🔽 LS(Live Show) 또는 VS(VOD Show)인 경우 DeepLink 진입 플래그 설정
if ((type === 'LS' || type === 'VS') && action === pushPanel) {
dispatch(
updateHomeInfo({
name: panel_names.HOME_PANEL,
panelInfo: {
isDeepLinkEntry: true, // DeepLink PlayerPanel 진입 플래그
},
})
);
}
dispatch( dispatch(
action({ action({
name: panelName, name: panelName,

View File

@@ -99,25 +99,17 @@ export const finishMediaPreview = () => (dispatch, getState) => {
export const finishModalMediaForce = () => (dispatch, getState) => { export const finishModalMediaForce = () => (dispatch, getState) => {
const panels = getState().panels.panels; const panels = getState().panels.panels;
// console.log('[🟡UNIQUE_DETAIL_CLEANUP🟡] finishModalMediaForce called', {
// panelCount: panels.length,
// panelNames: panels.map((p) => p.name),
// });
const hasProductVideoPanel = panels.some( const hasProductVideoPanel = panels.some(
(panel) => (panel) =>
panel.name === panel_names.MEDIA_PANEL && panel.name === panel_names.MEDIA_PANEL &&
(panel.panelInfo?.modal || panel.panelInfo?.modalContainerId === 'product-video-player') (panel.panelInfo?.modal || panel.panelInfo?.modalContainerId === 'product-video-player')
); );
// console.log('[🟡UNIQUE_DETAIL_CLEANUP🟡] hasProductVideoPanel:', hasProductVideoPanel);
if (hasProductVideoPanel) { if (hasProductVideoPanel) {
if (startMediaFocusTimer) { if (startMediaFocusTimer) {
clearTimeout(startMediaFocusTimer); clearTimeout(startMediaFocusTimer);
startMediaFocusTimer = null; startMediaFocusTimer = null;
} }
// console.log('[🟡UNIQUE_DETAIL_CLEANUP🟡] Calling popPanel(panel_names.MEDIA_PANEL)');
dispatch(popPanel(panel_names.MEDIA_PANEL)); dispatch(popPanel(panel_names.MEDIA_PANEL));
} }
}; };

View File

@@ -6,7 +6,7 @@ import { updateHomeInfo } from './homeActions';
import { createDebugHelpers } from '../utils/debug'; import { createDebugHelpers } from '../utils/debug';
// 디버그 헬퍼 설정 // 디버그 헬퍼 설정
const DEBUG_MODE = false; const DEBUG_MODE = true;
const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE); const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE);
// 시작 메뉴 추적을 위한 상수 // 시작 메뉴 추적을 위한 상수
@@ -40,20 +40,12 @@ export const pushPanel = (panel, duplicatable = false) => ({
}); });
export const popPanel = (panelName) => { export const popPanel = (panelName) => {
const stack = new Error().stack;
const stackLines = stack?.split('\n') || [];
// console.log('[💜UNIQUE_PANEL_STACK💜] popPanel action dispatcher - REMOVING PANEL:', {
// panelName,
// timestamp: Date.now(),
// fullStack: stackLines.slice(1, 6).map((line) => line.trim()),
// });
if (DEBUG_MODE) { if (DEBUG_MODE) {
console.log('[💜UNIQUE_PANEL_STACK💜] popPanel action creator stack:', { console.log('[PANEL-TRACE] popPanel action creator', {
panelName, panelName,
caller: stackLines[2]?.trim(), caller: new Error().stack?.split('\n')[2]?.trim(),
}); });
console.trace('[PANEL-TRACE] popPanel stack trace');
} }
return { return {
type: types.POP_PANEL, type: types.POP_PANEL,

View File

@@ -74,7 +74,7 @@ export const startVideoPlayer =
}) => }) =>
(dispatch, getState) => { (dispatch, getState) => {
const caller = new Error().stack?.split('\n')[2]?.trim(); const caller = new Error().stack?.split('\n')[2]?.trim();
dlog('[PTRACE-SP] startVideoPlayer call', { console.log('[PTRACE-SP] startVideoPlayer call', {
modal, modal,
modalContainerId, modalContainerId,
modalClassName, modalClassName,
@@ -115,7 +115,7 @@ export const startVideoPlayer =
// 기존 PlayerPanel이 어디든 있으면 완전히 초기화: 타이머 정리 후 pop → 새로 push // 기존 PlayerPanel이 어디든 있으면 완전히 초기화: 타이머 정리 후 pop → 새로 push
if (existingPlayerPanel) { if (existingPlayerPanel) {
dlog('[PTRACE-SP] startVideoPlayer: popping existing player before push', { console.log('[PTRACE-SP] startVideoPlayer: popping existing player before push', {
stack: panels.map((p) => p.name), stack: panels.map((p) => p.name),
}); });
dlog('[startVideoPlayer] 🔄 Resetting existing PLAYER_PANEL before start'); dlog('[startVideoPlayer] 🔄 Resetting existing PLAYER_PANEL before start');
@@ -148,14 +148,14 @@ export const startVideoPlayer =
// [COMMENTED OUT] 비디오 재생 시 강제 포커스 이동 비활성화 // [COMMENTED OUT] 비디오 재생 시 강제 포커스 이동 비활성화
// if (modal && modalContainerId && !spotlightDisable) { // if (modal && modalContainerId && !spotlightDisable) {
// dlog('[startVideoPlayer] 🎯 Setting Spotlight focus - containerId:', modalContainerId); // console.log('[startVideoPlayer] 🎯 Setting Spotlight focus - containerId:', modalContainerId);
// Spotlight.setPointerMode(false); // Spotlight.setPointerMode(false);
// startVideoFocusTimer = setTimeout(() => { // startVideoFocusTimer = setTimeout(() => {
// dlog('[startVideoPlayer] 🔍 Spotlight.focus called'); // console.log('[startVideoPlayer] 🔍 Spotlight.focus called');
// Spotlight.focus(modalContainerId); // Spotlight.focus(modalContainerId);
// }, 0); // }, 0);
// } else { // } else {
// dlog('[startVideoPlayer] ⏭️ Spotlight focus skipped - modal:', modal, ', modalContainerId:', !!modalContainerId, ', spotlightDisable:', spotlightDisable); // console.log('[startVideoPlayer] ⏭️ Spotlight focus skipped - modal:', modal, ', modalContainerId:', !!modalContainerId, ', spotlightDisable:', spotlightDisable);
// } // }
dlog('[startVideoPlayer] ✅ END'); dlog('[startVideoPlayer] ✅ END');
@@ -196,7 +196,7 @@ export const startVideoPlayerNew =
}) => }) =>
(dispatch, getState) => { (dispatch, getState) => {
const caller = new Error().stack?.split('\n')[2]?.trim(); const caller = new Error().stack?.split('\n')[2]?.trim();
dlog('[PTRACE-SPN] startVideoPlayerNew call', { console.log('[PTRACE-SPN] startVideoPlayerNew call', {
bannerId, bannerId,
modal, modal,
modalContainerId, modalContainerId,
@@ -239,7 +239,7 @@ export const startVideoPlayerNew =
// 기존 PlayerPanel이 있으면 완전히 초기화: 타이머 정리 후 pop → 새로 push // 기존 PlayerPanel이 있으면 완전히 초기화: 타이머 정리 후 pop → 새로 push
if (existingPlayerPanel) { if (existingPlayerPanel) {
dlog('[PTRACE-SPN] popping existing player before push', { console.log('[PTRACE-SPN] popping existing player before push', {
stack: panels.map((p) => p.name), stack: panels.map((p) => p.name),
}); });
dlog('[startVideoPlayerNew] *** 🔄 Resetting existing PLAYER_PANEL before start'); dlog('[startVideoPlayerNew] *** 🔄 Resetting existing PLAYER_PANEL before start');
@@ -332,14 +332,14 @@ export const startVideoPlayerNew =
// [COMMENTED OUT] 비디오 재생 시 강제 포커스 이동 비활성화 // [COMMENTED OUT] 비디오 재생 시 강제 포커스 이동 비활성화
// if (modal && modalContainerId && !spotlightDisable) { // if (modal && modalContainerId && !spotlightDisable) {
// dlog('[startVideoPlayerNew] *** 🎯 Setting Spotlight focus - containerId:', modalContainerId); // console.log('[startVideoPlayerNew] *** 🎯 Setting Spotlight focus - containerId:', modalContainerId);
// Spotlight.setPointerMode(false); // Spotlight.setPointerMode(false);
// startVideoFocusTimer = setTimeout(() => { // startVideoFocusTimer = setTimeout(() => {
// dlog('[startVideoPlayerNew] *** 🔍 Spotlight.focus called'); // console.log('[startVideoPlayerNew] *** 🔍 Spotlight.focus called');
// Spotlight.focus(modalContainerId); // Spotlight.focus(modalContainerId);
// }, 0); // }, 0);
// } else { // } else {
// dlog('[startVideoPlayerNew] *** ⏭️ Spotlight focus skipped - modal:', modal, ', modalContainerId:', !!modalContainerId, ', spotlightDisable:', spotlightDisable); // console.log('[startVideoPlayerNew] *** ⏭️ Spotlight focus skipped - modal:', modal, ', modalContainerId:', !!modalContainerId, ', spotlightDisable:', spotlightDisable);
// } // }
dlog('[startVideoPlayerNew] *** ✅ END'); dlog('[startVideoPlayerNew] *** ✅ END');
@@ -352,7 +352,7 @@ export const finishVideoPreview = () => (dispatch, getState) => {
const panels = getState().panels.panels; const panels = getState().panels.panels;
const topPanel = panels[panels.length - 1]; const topPanel = panels[panels.length - 1];
if (topPanel && topPanel.name === panel_names.PLAYER_PANEL && topPanel.panelInfo.modal) { if (topPanel && topPanel.name === panel_names.PLAYER_PANEL && topPanel.panelInfo.modal) {
dlog('[PANEL-TRACE] finishVideoPreview: popping modal player', { console.log('[PANEL-TRACE] finishVideoPreview: popping modal player', {
topPanelName: topPanel.name, topPanelName: topPanel.name,
modal: topPanel.panelInfo.modal, modal: topPanel.panelInfo.modal,
stack: panels.map((p) => p.name), stack: panels.map((p) => p.name),
@@ -417,7 +417,7 @@ export const pauseModalVideo = () => (dispatch, getState) => {
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal (panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal
); );
dlog('[Detail-BG] ⏸️ pauseModalVideo - Pausing modal video', { console.log('[Detail-BG] ⏸️ pauseModalVideo - Pausing modal video', {
found: !!modalPlayerPanel, found: !!modalPlayerPanel,
playerPanelModal: modalPlayerPanel?.panelInfo?.modal, playerPanelModal: modalPlayerPanel?.panelInfo?.modal,
currentIsPaused: modalPlayerPanel?.panelInfo?.isPaused, currentIsPaused: modalPlayerPanel?.panelInfo?.isPaused,
@@ -438,11 +438,11 @@ export const pauseModalVideo = () => (dispatch, getState) => {
}) })
); );
dlog('[Detail-BG] ✅ pauseModalVideo - Modal video paused successfully', { console.log('[Detail-BG] ✅ pauseModalVideo - Modal video paused successfully', {
timestamp: Date.now(), timestamp: Date.now(),
}); });
} else { } else {
dlog('[Detail-BG] ⚠️ pauseModalVideo - No modal PlayerPanel found', { console.log('[Detail-BG] ⚠️ pauseModalVideo - No modal PlayerPanel found', {
timestamp: Date.now(), timestamp: Date.now(),
}); });
} }
@@ -457,7 +457,7 @@ export const resumeModalVideo = () => (dispatch, getState) => {
(panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal (panel) => panel.name === panel_names.PLAYER_PANEL && panel.panelInfo?.modal
); );
dlog('[Detail-BG] ▶️ resumeModalVideo - Resuming modal video', { console.log('[Detail-BG] ▶️ resumeModalVideo - Resuming modal video', {
found: !!modalPlayerPanel, found: !!modalPlayerPanel,
playerPanelModal: modalPlayerPanel?.panelInfo?.modal, playerPanelModal: modalPlayerPanel?.panelInfo?.modal,
currentIsPaused: modalPlayerPanel?.panelInfo?.isPaused, currentIsPaused: modalPlayerPanel?.panelInfo?.isPaused,
@@ -478,11 +478,11 @@ export const resumeModalVideo = () => (dispatch, getState) => {
}) })
); );
dlog('[Detail-BG] ✅ resumeModalVideo - Modal video resumed successfully', { console.log('[Detail-BG] ✅ resumeModalVideo - Modal video resumed successfully', {
timestamp: Date.now(), timestamp: Date.now(),
}); });
} else { } else {
dlog('[Detail-BG] ⚠️ resumeModalVideo - Modal video not paused or panel not found', { console.log('[Detail-BG] ⚠️ resumeModalVideo - Modal video not paused or panel not found', {
found: !!modalPlayerPanel, found: !!modalPlayerPanel,
isPaused: modalPlayerPanel?.panelInfo?.isPaused, isPaused: modalPlayerPanel?.panelInfo?.isPaused,
timestamp: Date.now(), timestamp: Date.now(),
@@ -499,7 +499,7 @@ export const pauseFullscreenVideo = () => (dispatch, getState) => {
(panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal (panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal
); );
dlog('[Detail-BG] ⏸️ pauseFullscreenVideo - Pausing fullscreen video', { console.log('[Detail-BG] ⏸️ pauseFullscreenVideo - Pausing fullscreen video', {
found: !!fullscreenPlayerPanel, found: !!fullscreenPlayerPanel,
playerPanelModal: fullscreenPlayerPanel?.panelInfo?.modal, playerPanelModal: fullscreenPlayerPanel?.panelInfo?.modal,
currentIsPaused: fullscreenPlayerPanel?.panelInfo?.isPaused, currentIsPaused: fullscreenPlayerPanel?.panelInfo?.isPaused,
@@ -517,11 +517,11 @@ export const pauseFullscreenVideo = () => (dispatch, getState) => {
}) })
); );
dlog('[Detail-BG] ✅ pauseFullscreenVideo - Fullscreen video paused successfully', { console.log('[Detail-BG] ✅ pauseFullscreenVideo - Fullscreen video paused successfully', {
timestamp: Date.now(), timestamp: Date.now(),
}); });
} else { } else {
dlog('[Detail-BG] ⚠️ pauseFullscreenVideo - No fullscreen PlayerPanel found', { console.log('[Detail-BG] ⚠️ pauseFullscreenVideo - No fullscreen PlayerPanel found', {
timestamp: Date.now(), timestamp: Date.now(),
}); });
} }
@@ -536,7 +536,7 @@ export const resumeFullscreenVideo = () => (dispatch, getState) => {
(panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal (panel) => panel.name === panel_names.PLAYER_PANEL && !panel.panelInfo?.modal
); );
dlog('[Detail-BG] ▶️ resumeFullscreenVideo - Resuming fullscreen video', { console.log('[Detail-BG] ▶️ resumeFullscreenVideo - Resuming fullscreen video', {
found: !!fullscreenPlayerPanel, found: !!fullscreenPlayerPanel,
playerPanelModal: fullscreenPlayerPanel?.panelInfo?.modal, playerPanelModal: fullscreenPlayerPanel?.panelInfo?.modal,
currentIsPaused: fullscreenPlayerPanel?.panelInfo?.isPaused, currentIsPaused: fullscreenPlayerPanel?.panelInfo?.isPaused,
@@ -554,11 +554,11 @@ export const resumeFullscreenVideo = () => (dispatch, getState) => {
}) })
); );
dlog('[Detail-BG] ✅ resumeFullscreenVideo - Fullscreen video resumed successfully', { console.log('[Detail-BG] ✅ resumeFullscreenVideo - Fullscreen video resumed successfully', {
timestamp: Date.now(), timestamp: Date.now(),
}); });
} else { } else {
dlog('[Detail-BG] ⚠️ resumeFullscreenVideo - Fullscreen video not paused or panel not found', { console.log('[Detail-BG] ⚠️ resumeFullscreenVideo - Fullscreen video not paused or panel not found', {
found: !!fullscreenPlayerPanel, found: !!fullscreenPlayerPanel,
isPaused: fullscreenPlayerPanel?.panelInfo?.isPaused, isPaused: fullscreenPlayerPanel?.panelInfo?.isPaused,
timestamp: Date.now(), timestamp: Date.now(),
@@ -601,7 +601,7 @@ export const hideModalVideo = () => (dispatch, getState) => {
}, },
}; };
// dlog('[HomePanel] hideModalVideo: saving shrinkInfo', { // console.log('[HomePanel] hideModalVideo: saving shrinkInfo', {
// shrinkInfo: updatedPlayerState.shrinkInfo, // shrinkInfo: updatedPlayerState.shrinkInfo,
// modalStyle: panelInfo.modalStyle, // modalStyle: panelInfo.modalStyle,
// }); // });
@@ -1038,7 +1038,7 @@ export const resumePlayerControl = (ownerId) => (dispatch, getState) => {
* 이 액션은 어떤 배너에서든 클릭 시 호출됩니다. * 이 액션은 어떤 배너에서든 클릭 시 호출됩니다.
*/ */
export const goToFullScreen = () => (dispatch, getState) => { export const goToFullScreen = () => (dispatch, getState) => {
dlog('[Detail-BG] 🎬 goToFullScreen - Setting PlayerPanel to fullscreen mode', { console.log('[Detail-BG] 🎬 goToFullScreen - Setting PlayerPanel to fullscreen mode', {
targetModal: false, targetModal: false,
action: 'updatePanel', action: 'updatePanel',
timestamp: Date.now(), timestamp: Date.now(),
@@ -1055,7 +1055,7 @@ export const goToFullScreen = () => (dispatch, getState) => {
}) })
); );
dlog('[Detail-BG] ✅ goToFullScreen - PlayerPanel modal set to false (fullscreen)', { console.log('[Detail-BG] ✅ goToFullScreen - PlayerPanel modal set to false (fullscreen)', {
timestamp: Date.now(), timestamp: Date.now(),
}); });
}; };
@@ -1268,7 +1268,7 @@ export const startBannerVideo = (videoInfo) => (dispatch, getState) => {
...rest ...rest
} = videoInfo; } = videoInfo;
dlog('[Detail-BG] 🎥 startBannerVideo - Starting banner video', { console.log('[Detail-BG] 🎥 startBannerVideo - Starting banner video', {
modalStatus: modal, modalStatus: modal,
bannerId, bannerId,
displayMode: modal ? 'VISIBLE (modal=true)' : 'FULLSCREEN (modal=false)', displayMode: modal ? 'VISIBLE (modal=true)' : 'FULLSCREEN (modal=false)',
@@ -1295,7 +1295,7 @@ export const startBannerVideo = (videoInfo) => (dispatch, getState) => {
// 기존 PlayerPanel이 있으면 초기화 // 기존 PlayerPanel이 있으면 초기화
if (existingPlayerPanel) { if (existingPlayerPanel) {
dlog('[startBannerVideo] 🔄 Resetting existing PLAYER_PANEL before start'); dlog('[startBannerVideo] 🔄 Resetting existing PLAYER_PANEL before start');
dlog('[Detail-BG] 🔄 startBannerVideo - Clearing existing PlayerPanel', { console.log('[Detail-BG] 🔄 startBannerVideo - Clearing existing PlayerPanel', {
existingModalStatus: existingPlayerPanel.panelInfo?.modal, existingModalStatus: existingPlayerPanel.panelInfo?.modal,
timestamp: Date.now(), timestamp: Date.now(),
}); });
@@ -1304,7 +1304,7 @@ export const startBannerVideo = (videoInfo) => (dispatch, getState) => {
} }
// 새로운 PlayerPanel push // 새로운 PlayerPanel push
dlog('[Detail-BG] startBannerVideo - Pushing new PlayerPanel with modal status', { console.log('[Detail-BG] startBannerVideo - Pushing new PlayerPanel with modal status', {
modal, modal,
modalContainerId, modalContainerId,
timestamp: Date.now(), timestamp: Date.now(),
@@ -1331,7 +1331,7 @@ export const startBannerVideo = (videoInfo) => (dispatch, getState) => {
) )
); );
dlog('[Detail-BG] ✅ startBannerVideo - PlayerPanel pushed with modal=' + modal, { console.log('[Detail-BG] ✅ startBannerVideo - PlayerPanel pushed with modal=' + modal, {
timestamp: Date.now(), timestamp: Date.now(),
}); });

View File

@@ -483,7 +483,7 @@
.default-style(); .default-style();
.scrollInfo { .scrollInfo {
width: 850px; width: 900px;
background-color: @BG_COLOR_01; background-color: @BG_COLOR_01;
color: @COLOR_GRAY03; color: @COLOR_GRAY03;
display: flex; display: flex;

View File

@@ -16,7 +16,7 @@ import { calculateIsPanelOnTop } from '../utils/panelUtils'; // 🎯 isOnTop 유
// DEBUG_MODE - true인 경우에만 로그 출력 // DEBUG_MODE - true인 경우에만 로그 출력
// ⚠️ [251122] panelHistory 로그 비활성화 - 로그 생성 차단 // ⚠️ [251122] panelHistory 로그 비활성화 - 로그 생성 차단
const DEBUG_MODE = false; const DEBUG_MODE = true;
/** /**
* Panel history middleware * Panel history middleware
@@ -33,8 +33,8 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
(action.type.includes('PANEL') || action.type === 'CLEAR_PANEL_HISTORY') (action.type.includes('PANEL') || action.type === 'CLEAR_PANEL_HISTORY')
) { ) {
const caller = new Error().stack.split('\n')[1]?.trim(); const caller = new Error().stack.split('\n')[1]?.trim();
// console.log(`[PANEL DEBUG] ${action.type} from: ${caller}`); console.log(`[PANEL DEBUG] ${action.type} from: ${caller}`);
// console.log(' Payload:', action.payload); console.log(' Payload:', action.payload);
} }
// GNB 호출 식별을 위한 helper 함수 // GNB 호출 식별을 위한 helper 함수
@@ -81,7 +81,7 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
const isGNB = isGNBCall(); const isGNB = isGNBCall();
const isOnTop = calculateIsOnTop(panelName); // 🎯 isOnTop 계산 const isOnTop = calculateIsOnTop(panelName); // 🎯 isOnTop 계산
if (DEBUG_MODE) if (DEBUG_MODE)
console.log(`[PANEL] PUSH_PANEL: ${panelName}`, { console.log('[PANEL] PUSH_PANEL:', {
panelName, panelName,
panelInfo, panelInfo,
isGNB, isGNB,
@@ -126,7 +126,7 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
if (panels.length > 0) { if (panels.length > 0) {
const topPanel = panels[panels.length - 1]; const topPanel = panels[panels.length - 1];
if (DEBUG_MODE) { if (DEBUG_MODE) {
console.log(`[PANEL-TRACE] POP_PANEL middleware stack: ${topPanel?.name}`, { console.log('[PANEL-TRACE] POP_PANEL middleware stack', {
stack: panels.map((p) => p.name), stack: panels.map((p) => p.name),
topPanel: topPanel?.name, topPanel: topPanel?.name,
payload: action.payload, payload: action.payload,
@@ -137,7 +137,7 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
const isGNB = isGNBCall(); const isGNB = isGNBCall();
const isOnTop = calculateIsOnTop(topPanel.name); // 🎯 isOnTop 계산 const isOnTop = calculateIsOnTop(topPanel.name); // 🎯 isOnTop 계산
if (DEBUG_MODE) if (DEBUG_MODE)
console.log(`[PANEL] POP_PANEL: ${topPanel.name}`, { console.log('[PANEL] POP_PANEL:', {
panelName: topPanel.name, panelName: topPanel.name,
panelInfo: topPanel.panelInfo || {}, panelInfo: topPanel.panelInfo || {},
isGNB, isGNB,
@@ -185,7 +185,7 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
const isGNB = isGNBCall(); const isGNB = isGNBCall();
const isOnTop = calculateIsOnTop(panelName); // 🎯 isOnTop 계산 const isOnTop = calculateIsOnTop(panelName); // 🎯 isOnTop 계산
if (DEBUG_MODE) if (DEBUG_MODE)
console.log(`[PANEL] UPDATE_PANEL: ${panelName}`, { console.log('[PANEL] UPDATE_PANEL:', {
panelName, panelName,
panelInfo, panelInfo,
isGNB, isGNB,
@@ -226,15 +226,11 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
// RESET_PANELS: GNB 네비게이션 또는 완전 초기화 // RESET_PANELS: GNB 네비게이션 또는 완전 초기화
case types.RESET_PANELS: { case types.RESET_PANELS: {
if (DEBUG_MODE) { if (DEBUG_MODE)
const resetPanelNameForLog = (action.payload && action.payload.length > 0) console.log('[PANEL] RESET_PANELS:', {
? action.payload[0].name
: 'homepanel';
console.log(`[PANEL] RESET_PANELS: ${resetPanelNameForLog}`, {
payload: action.payload, payload: action.payload,
timestamp: new Date().toISOString(), timestamp: new Date().toISOString(),
}); });
}
if (DEBUG_MODE) if (DEBUG_MODE)
console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory); console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory);

View File

@@ -94,12 +94,6 @@ export const panelsReducer = (state = initialState, action) => {
} }
case types.POP_PANEL: { case types.POP_PANEL: {
// console.log('[💜UNIQUE_PANEL_STACK💜] POP_PANEL reducer START', {
// targetPanel: action.payload || 'last_panel',
// currentPanels: state.panels.map((p) => p.name),
// timestamp: Date.now(),
// });
dlog('[panelReducer] 🔴 POP_PANEL START', { dlog('[panelReducer] 🔴 POP_PANEL START', {
targetPanel: action.payload || 'last_panel', targetPanel: action.payload || 'last_panel',
currentPanels: state.panels.map((p) => p.name), currentPanels: state.panels.map((p) => p.name),
@@ -124,13 +118,6 @@ export const panelsReducer = (state = initialState, action) => {
resultPanels = state.panels.slice(0, state.panels.length - 1); resultPanels = state.panels.slice(0, state.panels.length - 1);
} }
// console.log('[💜UNIQUE_PANEL_STACK💜] POP_PANEL reducer END', {
// resultPanels: resultPanels.map((p) => p.name),
// panelCount: resultPanels.length,
// lastAction,
// timestamp: Date.now(),
// });
dlog('[panelReducer] 🔴 POP_PANEL END', { dlog('[panelReducer] 🔴 POP_PANEL END', {
resultPanels: resultPanels.map((p) => p.name), resultPanels: resultPanels.map((p) => p.name),
lastAction, lastAction,

View File

@@ -113,8 +113,7 @@ export const ACTIVE_POPUP = {
toast: 'toast', toast: 'toast',
optionalConfirm: 'optionalConfirm', optionalConfirm: 'optionalConfirm',
energyPopup: 'energyPopup', energyPopup: 'energyPopup',
addCartPopup: 'addCartPopup', addCartPopup: 'addCartPopup',
scrollPopup: 'scrollPopup',
}; };
export const DEBUG_VIDEO_SUBTITLE_TEST = false; export const DEBUG_VIDEO_SUBTITLE_TEST = false;
export const AUTO_SCROLL_DELAY = 600; export const AUTO_SCROLL_DELAY = 600;

View File

@@ -458,7 +458,7 @@ const tap = fp.curry((fn, value) => {
* @param {*} value 대상 값 * @param {*} value 대상 값
*/ */
const trace = fp.curry((label, value) => { const trace = fp.curry((label, value) => {
// console.log(label, value); console.log(label, value);
return value; return value;
}); });

View File

@@ -280,7 +280,6 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
useEffect(() => { useEffect(() => {
return () => { return () => {
// console.log('[🟡UNIQUE_DETAIL_CLEANUP🟡] DetailPanel cleanup - calling finishModalMediaForce');
dispatch(finishModalMediaForce()); dispatch(finishModalMediaForce());
}; };
}, [dispatch]); }, [dispatch]);
@@ -304,25 +303,26 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
const sourcePanel = panelInfo?.sourcePanel; const sourcePanel = panelInfo?.sourcePanel;
const sourceMenu = panelInfo?.sourceMenu; const sourceMenu = panelInfo?.sourceMenu;
// console.log('[🔴UNIQUE_DETAIL_UNMOUNT🔴] DetailPanel cleanup/unmount triggered', { console.log('[DP-TRACE] Detail unmount start', {
// sourcePanel, sourcePanel,
// sourceMenu, sourceMenu,
// panelsSnapshot: panels.map((p) => p.name), panelsSnapshot: panels.map((p) => p.name),
// timestamp: Date.now(), });
// });
console.log('[Detail-BG] 306-line sourcePanel:', sourcePanel, 'sourceMenu:', sourceMenu);
// DetailPanel이 unmount되는 시점 // DetailPanel이 unmount되는 시점
// console.log('[🔴UNIQUE_DETAIL_UNMOUNT🔴] DetailPanel unmount details:', { console.log('[DetailPanel] unmount:', {
// sourcePanel, sourcePanel,
// sourceMenu, sourceMenu,
// timestamp: Date.now(), timestamp: Date.now(),
// }); });
// sourcePanel에 따른 상태 업데이트 // sourcePanel에 따른 상태 업데이트
switch (sourcePanel) { switch (sourcePanel) {
case panel_names.PLAYER_PANEL: { case panel_names.PLAYER_PANEL: {
// PlayerPanel에서 온 경우: PlayerPanel에 detailPanelClosed flag 전달 // PlayerPanel에서 온 경우: PlayerPanel에 detailPanelClosed flag 전달
console.log('[PANEL][DetailPanel] unmount - PlayerPanel에 detailPanelClosed flag 전달'); console.log('[DetailPanel] unmount - PlayerPanel에 detailPanelClosed flag 전달');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
@@ -385,14 +385,6 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
const sourcePanel = panelInfo?.sourcePanel; const sourcePanel = panelInfo?.sourcePanel;
const sourceMenu = panelInfo?.sourceMenu; const sourceMenu = panelInfo?.sourceMenu;
// console.log('[🟠UNIQUE_DETAIL_BACK🟠] onBackClick triggered', {
// sourcePanel,
// sourceMenu,
// isCancelClick,
// currentPanels: panels.map((p) => p.name),
// timestamp: Date.now(),
// });
fp.pipe( fp.pipe(
() => { () => {
dispatch(clearAllToasts()); // BuyOption Toast 포함 모든 토스트 제거 dispatch(clearAllToasts()); // BuyOption Toast 포함 모든 토스트 제거
@@ -401,7 +393,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
switch (sourcePanel) { switch (sourcePanel) {
case panel_names.PLAYER_PANEL: case panel_names.PLAYER_PANEL:
// PlayerPanel에서 온 경우: 플레이어 비디오는 그대로 두고 모달만 정리 // PlayerPanel에서 온 경우: 플레이어 비디오는 그대로 두고 모달만 정리
console.log('[🟠UNIQUE_DETAIL_BACK🟠] PlayerPanel 출신: 모달 정리만 수행'); console.log('[DetailPanel] onBackClick - PlayerPanel 출신: 모달 정리만 수행');
dispatch(finishModalMediaForce()); // MEDIA_PANEL(ProductVideo) 강제 종료 dispatch(finishModalMediaForce()); // MEDIA_PANEL(ProductVideo) 강제 종료
dispatch(finishVideoPreview()); dispatch(finishVideoPreview());
break; break;
@@ -410,18 +402,17 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
case panel_names.SEARCH_PANEL: case panel_names.SEARCH_PANEL:
default: default:
// HomePanel, SearchPanel 등에서 온 경우: 백그라운드 비디오 일시 중지 // HomePanel, SearchPanel 등에서 온 경우: 백그라운드 비디오 일시 중지
// console.log( console.log(
// '[🟠UNIQUE_DETAIL_BACK🟠] source panel:', '[DetailPanel] onBackClick - source panel:',
// sourcePanel, sourcePanel,
// '백그라운드 비디오 일시 중지' '백그라운드 비디오 일시 중지'
// ); );
dispatch(pauseFullscreenVideo()); // PLAYER_PANEL 비디오 중지 dispatch(pauseFullscreenVideo()); // PLAYER_PANEL 비디오 중지
dispatch(finishModalMediaForce()); // MEDIA_PANEL(ProductVideo) 강제 종료 dispatch(finishModalMediaForce()); // MEDIA_PANEL(ProductVideo) 강제 종료
dispatch(finishVideoPreview()); dispatch(finishVideoPreview());
break; break;
} }
// console.log('[🟠UNIQUE_DETAIL_BACK🟠] Calling popPanel(DETAIL_PANEL)');
dispatch(popPanel(panel_names.DETAIL_PANEL)); dispatch(popPanel(panel_names.DETAIL_PANEL));
}, },
() => { () => {
@@ -443,7 +434,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
if (shouldUpdatePanel) { if (shouldUpdatePanel) {
console.log( console.log(
'[PANEL][DetailPanel] onBackClick - PlayerPanel에 detailPanelClosed flag 전달' '[DetailPanel] onBackClick - PlayerPanel에 detailPanelClosed flag 전달'
); );
dispatch( dispatch(
updatePanel({ updatePanel({

View File

@@ -1,32 +1,9 @@
import React, { import React, { useCallback } from "react";
useCallback, import css from "./ProductDescription.module.less";
useMemo, import { $L, removeSpecificTags } from "../../../../utils/helperMethods";
} from 'react'; import Spottable from "@enact/spotlight/Spottable";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import { import Spotlight from "@enact/spotlight";
useDispatch,
useSelector,
} from 'react-redux';
import Spotlight from '@enact/spotlight';
import SpotlightContainerDecorator
from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable';
import {
setHidePopup,
setShowPopup,
} from '../../../../actions/commonActions';
import TButtonScroller
from '../../../../components/TButtonScroller/TButtonScroller';
import TNewPopUp from '../../../../components/TPopUp/TNewPopUp';
import * as Config from '../../../../utils/Config';
import {
$L,
removeSpecificTags,
} from '../../../../utils/helperMethods';
import css from './ProductDescription.module.less';
// TVerticalPagenator 제거됨 - TScrollerNew와 충돌 문제로 인해 // TVerticalPagenator 제거됨 - TScrollerNew와 충돌 문제로 인해
const SpottableComponent = Spottable("div"); const SpottableComponent = Spottable("div");
@@ -41,23 +18,12 @@ const Container = SpotlightContainerDecorator(
"div" "div"
); );
export default function ProductDescription({ productInfo }) { export default function ProductDescription({ productInfo }) {
const { popupVisible, activePopup } = useSelector(
(state) => state.common.popup
);
const dispatch = useDispatch();
const productDescription = useCallback(() => { const productDescription = useCallback(() => {
const sanitizedString = removeSpecificTags(productInfo?.prdtDesc); const sanitizedString = removeSpecificTags(productInfo?.prdtDesc);
return { __html: sanitizedString }; return { __html: sanitizedString };
}, [productInfo?.prdtDesc]); }, [productInfo?.prdtDesc]);
const productDescriptionText = useMemo(() => {
return removeSpecificTags(productInfo?.prdtDesc);
}, [productInfo?.prdtDesc]);
// 왼쪽 화살표 키 이벤트 처리 // 왼쪽 화살표 키 이벤트 처리
const handleKeyDown = useCallback((ev) => { const handleKeyDown = useCallback((ev) => {
if (ev.keyCode === 37) { // 왼쪽 화살표 키 if (ev.keyCode === 37) { // 왼쪽 화살표 키
@@ -68,16 +34,6 @@ export default function ProductDescription({ productInfo }) {
} }
}, []); }, []);
const descriptionClick = useCallback(() => {
dispatch(setShowPopup(Config.ACTIVE_POPUP.scrollPopup));
},
[dispatch]
);
const _onClose = useCallback(()=>{
dispatch(setHidePopup());
},[dispatch])
// ProductDescription: Container 직접 사용 패턴 // ProductDescription: Container 직접 사용 패턴
// prdtDesc가 없으면 렌더링하지 않음 // prdtDesc가 없으면 렌더링하지 않음
if (!productInfo?.prdtDesc) { if (!productInfo?.prdtDesc) {
@@ -85,61 +41,36 @@ export default function ProductDescription({ productInfo }) {
} }
return ( return (
<> <Container
<Container className={css.descriptionContainer}
className={css.descriptionContainer} spotlightId="product-description-container"
spotlightId="product-description-container" >
{/* <SpottableComponent
className={css.titleWrapper}
spotlightId="product-description-title"
onClick={() => console.log("[ProductDescription] Title clicked")}
onFocus={() => console.log("[ProductDescription] Title focused")}
onBlur={() => console.log("[ProductDescription] Title blurred")}
> */}
<div className={css.titleWrapper}>
<div className={css.title}>{$L("DESCRIPTION")}</div>
</div>
{/* </SpottableComponent> */}
<SpottableComponent
className={css.descriptionWrapper}
spotlightId="product-description-content"
onClick={() => console.log("[ProductDescription] Content clicked")}
onFocus={() => console.log("[ProductDescription] Content focused")}
onBlur={() => console.log("[ProductDescription] Content blurred")}
onKeyDown={handleKeyDown}
> >
{/* <SpottableComponent <div
className={css.titleWrapper} className={css.productDescription}
spotlightId="product-description-title" dangerouslySetInnerHTML={productDescription()}
onClick={() => console.log("[ProductDescription] Title clicked")} />
onFocus={() => console.log("[ProductDescription] Title focused")} </SpottableComponent>
onBlur={() => console.log("[ProductDescription] Title blurred")} </Container>
> */}
<div className={css.titleWrapper}>
<div className={css.title}>{$L("DESCRIPTION")}</div>
</div>
{/* </SpottableComponent> */}
<SpottableComponent
className={css.descriptionWrapper}
spotlightId="product-description-content"
// onClick={() => console.log("[ProductDescription] Content clicked")}
onClick={descriptionClick}
onFocus={() => console.log("[ProductDescription] Content focused")}
onBlur={() => console.log("[ProductDescription] Content blurred")}
onKeyDown={handleKeyDown}
>
<div
className={css.productDescription}
dangerouslySetInnerHTML={productDescription()}
/>
</SpottableComponent>
</Container>
{activePopup === Config.ACTIVE_POPUP.scrollPopup && (
<TNewPopUp
kind="scrollPopup"
open={popupVisible}
hasText
title={$L("DESCRIPTION")}
onClick={_onClose}
hasButton
button1Text={$L("OK")}
>
<TButtonScroller
boxHeight={460}
width={844}
kind={"figmaTermsPopup"}
>
<div
className={css.scrollContainer}
dangerouslySetInnerHTML={{ __html: productDescriptionText }}
/>
</TButtonScroller>
</TNewPopUp>
)}
</>
); );
} }

View File

@@ -51,8 +51,3 @@
} }
} }
.scrollContainer {
padding: 31px;
font-size: 26px;
line-height: 1.5;
}

View File

@@ -5,10 +5,11 @@
position: relative; position: relative;
width: 1114px; // ProductDetail과 동일한 고정 크기 width: 1114px; // ProductDetail과 동일한 고정 크기
max-width: 1114px; max-width: 1114px;
height: 632px !important; // ProductDetail과 동일한 고정 높이 height: 740px; // ProductDetail과 동일한 고정 높이
margin-bottom: 30px; // ProductDetail과 동일한 간격
cursor: pointer; cursor: pointer;
background-color: rgba(0, 0, 0, 1); background-color: rgba(0, 0, 0, 1);
border-radius: 12px 12px 0 0; border-radius: 12px;
box-sizing: border-box; box-sizing: border-box;
padding: 6px; // 포커스 테두리를 위한 공간 padding: 6px; // 포커스 테두리를 위한 공간
overflow: hidden; overflow: hidden;
@@ -79,7 +80,7 @@
z-index: 23; // MediaPanel(z-index: 22)보다 위에 표시되어야 비디오 재생 중에도 포커스 테두리가 보임 z-index: 23; // MediaPanel(z-index: 22)보다 위에 표시되어야 비디오 재생 중에도 포커스 테두리가 보임
border: 6px solid @PRIMARY_COLOR_RED; border: 6px solid @PRIMARY_COLOR_RED;
box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5); box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5);
border-radius: 12px 12px 0px 0px; border-radius: 12px;
content: ""; content: "";
} }
@@ -216,28 +217,30 @@
} }
.notice { .notice {
width: calc(100% - 10px);
height: 54px;
background: #000000;
.flex(@justifyCenter:flex-start);
padding: 6px 18px 18px 18px;
border-radius: 0 0 12px 12px;
margin-bottom: 30px; // ProductDetail과 동일한 간격
.marquee {
width: 100%; width: 100%;
height: 100%; height: 54px;
} background: #000000;
img { .flex(@justifyCenter:flex-start);
width: 18px; padding: 6px 18px 18px 18px;
height: 18px; position: absolute;
margin: 10px 12px 0 0; bottom: 0;
object-fit: contain; border-radius: 0 0 12px 12px;
}
span { .marquee {
line-height: normal; width: 100%;
letter-spacing: normal; height: 100%;
text-align: left; }
.font(@fontFamily:@baseFont, @fontSize:20px); img {
color: @COLOR_GRAY04; width: 18px;
} height: 18px;
} margin: 10px 12px 0 0;
object-fit: contain;
}
span {
line-height: normal;
letter-spacing: normal;
text-align: left;
.font(@fontFamily:@baseFont, @fontSize:20px);
color: @COLOR_GRAY04;
}
}

View File

@@ -311,7 +311,6 @@ export default function ProductVideo({
if (!canPlayVideo) return null; if (!canPlayVideo) return null;
return ( return (
<>
<SpottableComponent <SpottableComponent
className={css.videoContainer} className={css.videoContainer}
onClick={handleVideoClick} onClick={handleVideoClick}
@@ -331,13 +330,12 @@ export default function ProductVideo({
<img src={playImg} alt="재생" /> <img src={playImg} alt="재생" />
</div> </div>
</div> </div>
<div className={css.notice}>
<Marquee className={css.marquee} marqueeOn="render">
<img src={ic_warning} alt={disclaimer} />
<span>{disclaimer}</span>
</Marquee>
</div>
</SpottableComponent> </SpottableComponent>
<div className={css.notice}>
<Marquee className={css.marquee} marqueeOn="render">
<img src={ic_warning} alt={disclaimer} />
<span>{disclaimer}</span>
</Marquee>
</div>
</>
); );
} }

View File

@@ -1,41 +1,21 @@
import React, { import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { import { useDispatch, useSelector } from 'react-redux';
useDispatch,
useSelector,
} from 'react-redux';
import { Job } from '@enact/core/util'; import { Job } from '@enact/core/util';
import SpotlightContainerDecorator import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable'; import Spottable from '@enact/spotlight/Spottable';
import { clearThemeDetail } from '../../../../actions/homeActions'; import { clearThemeDetail } from '../../../../actions/homeActions';
import { finishModalMediaForce } from '../../../../actions/mediaActions'; import { finishModalMediaForce } from '../../../../actions/mediaActions';
import { import { popPanel, pushPanel, updatePanel } from '../../../../actions/panelActions';
popPanel,
pushPanel,
updatePanel,
} from '../../../../actions/panelActions';
import { finishVideoPreview } from '../../../../actions/playActions'; import { finishVideoPreview } from '../../../../actions/playActions';
import THeader from '../../../../components/THeader/THeader'; import THeader from '../../../../components/THeader/THeader';
import TItemCardNew from '../../../../components/TItemCard/TItemCard.new'; import TItemCardNew from '../../../../components/TItemCard/TItemCard.new';
import TVerticalPagenator import TVerticalPagenator from '../../../../components/TVerticalPagenator/TVerticalPagenator';
from '../../../../components/TVerticalPagenator/TVerticalPagenator'; import TVirtualGridList from '../../../../components/TVirtualGridList/TVirtualGridList';
import TVirtualGridList
from '../../../../components/TVirtualGridList/TVirtualGridList';
import useScrollTo from '../../../../hooks/useScrollTo'; import useScrollTo from '../../../../hooks/useScrollTo';
import { import { LOG_CONTEXT_NAME, LOG_MESSAGE_ID, panel_names } from '../../../../utils/Config';
LOG_CONTEXT_NAME,
LOG_MESSAGE_ID,
panel_names,
} from '../../../../utils/Config';
import { $L } from '../../../../utils/helperMethods'; import { $L } from '../../../../utils/helperMethods';
import css from './YouMayAlsoLike.module.less'; import css from './YouMayAlsoLike.module.less';
@@ -178,7 +158,7 @@ export default function YouMayAlsoLike({
// DetailPanel을 언마운트하지 않고 상품 정보만 업데이트 // DetailPanel을 언마운트하지 않고 상품 정보만 업데이트
// 이렇게 하면 백그라운드 비디오 제어 상태가 유지됨 // 이렇게 하면 백그라운드 비디오 제어 상태가 유지됨
dispatch( dispatch(
pushPanel({ updatePanel({
name: panel_names.DETAIL_PANEL, name: panel_names.DETAIL_PANEL,
panelInfo: { panelInfo: {
showNm: panelInfo?.showNm, showNm: panelInfo?.showNm,
@@ -190,8 +170,8 @@ export default function YouMayAlsoLike({
launchedFromPlayer: launchedFromPlayer, launchedFromPlayer: launchedFromPlayer,
bgVideoInfo: bgVideoInfo, // 백그라운드 비디오 정보 유지 bgVideoInfo: bgVideoInfo, // 백그라운드 비디오 정보 유지
fromPanel: { fromPanel: {
fromYouMayLike: true, // YouMayLike에서 선택된 상품임을 표시 fromYouMayLike: true, // YouMayLike에서 선택된 상품임을 표시
}, // 출처 정보 통합 객체 }, // 출처 정보 통합 객체
}, },
}) })
); );

View File

@@ -78,35 +78,35 @@ export default function ThemeItemCard({
const { originalPrice, discountedPrice, discountRate } = const { originalPrice, discountedPrice, discountRate } =
usePriceInfo(priceInfo) || {}; usePriceInfo(priceInfo) || {};
// const mockEnergyLabel = [ const mockEnergyLabel = [
// { {
// "enrgLblExpsOrd": "0", "enrgLblExpsOrd": "0",
// "enrgLblTpCd": "EL_TYPE_05", "enrgLblTpCd": "EL_TYPE_05",
// "enrgLblCd": "MNLC", "enrgLblCd": "MNLC",
// "enrgClasCd": "A", "enrgClasCd": "A",
// "enrgLblIcnUrl": "http://eic-ngfts.lge.com/fts/gftsDownload.lge?biz_code=LGSHOPPING&func_code=IMAGE&file_path=/lgshopping/image/gb_class_arrows_ag_a.png", "enrgLblIcnUrl": "http://eic-ngfts.lge.com/fts/gftsDownload.lge?biz_code=LGSHOPPING&func_code=IMAGE&file_path=/lgshopping/image/gb_class_arrows_ag_a.png",
// "enrgLblUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241113229264&ORIGINAL_NAME_b1_a1=27U511SA EU (E).pdf&FILE_NAME=27U511SA EU (E)[20241113011401634].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N", "enrgLblUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241113229264&ORIGINAL_NAME_b1_a1=27U511SA EU (E).pdf&FILE_NAME=27U511SA EU (E)[20241113011401634].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N",
// "enrgShetUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241125231113&ORIGINAL_NAME_b1_a1=27U511SA-W.pdf&FILE_NAME=27U511SA-W[20241125231113].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N" "enrgShetUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241125231113&ORIGINAL_NAME_b1_a1=27U511SA-W.pdf&FILE_NAME=27U511SA-W[20241125231113].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N"
// }, },
// { {
// "enrgLblExpsOrd": "0", "enrgLblExpsOrd": "0",
// "enrgLblTpCd": "EL_TYPE_05", "enrgLblTpCd": "EL_TYPE_05",
// "enrgLblCd": "MNLC", "enrgLblCd": "MNLC",
// "enrgClasCd": "D", "enrgClasCd": "D",
// "enrgLblIcnUrl": "http://eic-ngfts.lge.com/fts/gftsDownload.lge?biz_code=LGSHOPPING&func_code=IMAGE&file_path=/lgshopping/image/gb_class_arrows_ag_d.png", "enrgLblIcnUrl": "http://eic-ngfts.lge.com/fts/gftsDownload.lge?biz_code=LGSHOPPING&func_code=IMAGE&file_path=/lgshopping/image/gb_class_arrows_ag_d.png",
// "enrgLblUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241230236057&ORIGINAL_NAME_b1_a1=27U421A EU (E).pdf&FILE_NAME=27U421A EU (E)[20241230015816192].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N", "enrgLblUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241230236057&ORIGINAL_NAME_b1_a1=27U421A EU (E).pdf&FILE_NAME=27U421A EU (E)[20241230015816192].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N",
// "enrgShetUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241224235911&ORIGINAL_NAME_b1_a1=27U421A-B.pdf&FILE_NAME=27U421A-B[20241224235911].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N" "enrgShetUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241224235911&ORIGINAL_NAME_b1_a1=27U421A-B.pdf&FILE_NAME=27U421A-B[20241224235911].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N"
// }, },
// { {
// "enrgLblExpsOrd": "0", "enrgLblExpsOrd": "0",
// "enrgLblTpCd": "EL_TYPE_05", "enrgLblTpCd": "EL_TYPE_05",
// "enrgLblCd": "MNLC", "enrgLblCd": "MNLC",
// "enrgClasCd": "D", "enrgClasCd": "D",
// "enrgLblIcnUrl": "http://eic-ngfts.lge.com/fts/gftsDownload.lge?biz_code=LGSHOPPING&func_code=IMAGE&file_path=/lgshopping/image/gb_class_arrows_ag_d.png", "enrgLblIcnUrl": "http://eic-ngfts.lge.com/fts/gftsDownload.lge?biz_code=LGSHOPPING&func_code=IMAGE&file_path=/lgshopping/image/gb_class_arrows_ag_d.png",
// "enrgLblUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241230236057&ORIGINAL_NAME_b1_a1=27U421A EU (E).pdf&FILE_NAME=27U421A EU (E)[20241230015816192].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N", "enrgLblUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241230236057&ORIGINAL_NAME_b1_a1=27U421A EU (E).pdf&FILE_NAME=27U421A EU (E)[20241230015816192].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N",
// "enrgShetUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241224235911&ORIGINAL_NAME_b1_a1=27U421A-B.pdf&FILE_NAME=27U421A-B[20241224235911].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N" "enrgShetUrl": "https://www.lg.com/uk/lgecs.downloadFile.ldwf?DOC_ID=20241224235911&ORIGINAL_NAME_b1_a1=27U421A-B.pdf&FILE_NAME=27U421A-B[20241224235911].pdf&TC=DwnCmd&GSRI_DOC=GSRI&SPEC_DOWNLOAD=N"
// } }
// ]; ];
const setEnactFitZIndex = (zIndexValue) => { const setEnactFitZIndex = (zIndexValue) => {
const target = document.getElementById("floatLayer"); const target = document.getElementById("floatLayer");
@@ -211,7 +211,7 @@ export default function ThemeItemCard({
))} ))}
</div> </div>
)} */} )} */}
{/* {mockEnergyLabel && mockEnergyLabel.length > 0 && ( {mockEnergyLabel && mockEnergyLabel.length > 0 && (
<div className={css.energyLabels}> <div className={css.energyLabels}>
{mockEnergyLabel.map((label, labelIndex) => ( {mockEnergyLabel.map((label, labelIndex) => (
<SpottableTemp <SpottableTemp
@@ -228,7 +228,7 @@ export default function ThemeItemCard({
</SpottableTemp> </SpottableTemp>
))} ))}
</div> </div>
)} */} )}
</div> </div>
</SpottableDiv> </SpottableDiv>
{(() => { {(() => {

View File

@@ -93,6 +93,9 @@ export default function THeaderCustom({
role="button" role="button"
/> />
)} )}
{type === "theme" && themeTitle && (
<span className={css.themeTitle} dangerouslySetInnerHTML={{ __html: themeTitle }} />
)}
{kind ? ( {kind ? (
"" ""
) : ( ) : (
@@ -104,9 +107,6 @@ export default function THeaderCustom({
}} }}
/> />
)} )}
{type === "theme" && themeTitle && (
<span className={css.themeTitle} dangerouslySetInnerHTML={{ __html: `[${themeTitle}]` }} />
)}
<Marquee <Marquee
marqueeOn="render" marqueeOn="render"
className={css.title} className={css.title}

View File

@@ -61,5 +61,4 @@
color: #eaeaea; color: #eaeaea;
width: max-content; width: max-content;
margin-right: 20px; margin-right: 20px;
margin-left: 10px;
} }

View File

@@ -1,26 +1,14 @@
import React, { import React, { useCallback, useEffect, useRef, useState, useMemo, forwardRef } from 'react';
forwardRef,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { import { off, on } from '@enact/core/dispatcher';
off,
on,
} from '@enact/core/dispatcher';
import { Job } from '@enact/core/util'; import { Job } from '@enact/core/util';
import Scroller from '@enact/sandstone/Scroller'; import Scroller from '@enact/sandstone/Scroller';
import Spotlight from '@enact/spotlight'; import Spotlight from '@enact/spotlight';
import AutoScrollAreaDetail, { import AutoScrollAreaDetail, { POSITION } from '../AutoScrollAreaDetail/AutoScrollAreaDetail';
POSITION,
} from '../AutoScrollAreaDetail/AutoScrollAreaDetail';
import css from './TScrollerDetail.module.less'; import css from './TScrollerDetail.module.less';
/** /**
@@ -218,8 +206,7 @@ const TScrollerDetail = forwardRef(
onScrollStop={_onScrollStop} onScrollStop={_onScrollStop}
onScroll={_onScroll} onScroll={_onScroll}
scrollMode={scrollMode || 'translate'} scrollMode={scrollMode || 'translate'}
// focusableScrollbar={focusableScrollbar} focusableScrollbar={focusableScrollbar}
focusableScrollbar={false}
className={classNames(isMounted && css.tScroller, noScrollByWheel && css.preventScroll)} className={classNames(isMounted && css.tScroller, noScrollByWheel && css.preventScroll)}
direction={direction} direction={direction}
horizontalScrollbar={horizontalScrollbar} horizontalScrollbar={horizontalScrollbar}
@@ -233,7 +220,7 @@ const TScrollerDetail = forwardRef(
}} }}
noScrollByWheel={noScrollByWheel} noScrollByWheel={noScrollByWheel}
noScrollByDrag noScrollByDrag
// rest props에서 ref만 제외하고 전달 // rest props에서 ref만 제외하고 전달
{...(rest.ref ? { ...rest, ref: undefined } : rest)} {...(rest.ref ? { ...rest, ref: undefined } : rest)}
> >
{children} {children}

View File

@@ -5,8 +5,8 @@ import { useDispatch, useSelector } from "react-redux";
import { Job } from "@enact/core/util"; import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight"; import Spotlight from "@enact/spotlight";
import { pushPanel, updatePanel } from "../../../../../actions/panelActions"; import { updatePanel } from "../../../../../actions/panelActions";
// import { startVideoPlayer } from "../../../../../actions/playActions"; import { startVideoPlayer } from "../../../../../actions/playActions";
import TItemCard, { import TItemCard, {
removeDotAndColon, removeDotAndColon,
} from "../../../../../components/TItemCard/TItemCard"; } from "../../../../../components/TItemCard/TItemCard";
@@ -113,36 +113,27 @@ export default function RecommendedShowsProductList({
); );
} }
// 🆕 DetailPanel로 이동 (ShopByShow 방식) let y =
index < 2
? 0
: index === 2
? scaleH(208)
: scaleH(index * 248 - 248 - 40);
dispatch( dispatch(
pushPanel({ startVideoPlayer({
name: panel_names.DETAIL_PANEL, modal: false,
panelInfo: { patnrId, prdtId }, patnrId,
prdtId,
showId,
shptmBanrTpNm: "VOD",
thumbnail: videoThumbnail,
targetId: "spotlightId-" + prdtId,
y,
}) })
); );
// 🔴 기존 PlayerPanel 로직 (주석처리)
// let y =
// index < 2
// ? 0
// : index === 2
// ? scaleH(208)
// : scaleH(index * 248 - 248 - 40);
//
// dispatch(
// startVideoPlayer({
// modal: false,
// patnrId,
// prdtId,
// showId,
// shptmBanrTpNm: "VOD",
// thumbnail: videoThumbnail,
// targetId: "spotlightId-" + prdtId,
// y,
// })
// );
}, },
[catCd, dispatch, patnrId] [catCd, dispatch, patnrId, showId, videoThumbnail]
); );
const handleFocus = useCallback(() => { const handleFocus = useCallback(() => {

View File

@@ -6,11 +6,7 @@ import Spotlight from '@enact/spotlight';
import { SpotlightContainerDecorator } from '@enact/spotlight/SpotlightContainerDecorator'; import { SpotlightContainerDecorator } from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable'; import Spottable from '@enact/spotlight/Spottable';
import { import { pushPanel, updatePanel, navigateFromBestSeller } from '../../../actions/panelActions';
navigateFromBestSeller,
pushPanel,
updatePanel,
} from '../../../actions/panelActions';
import { navigateToDetailFromHome } from '../../../actions/panelNavigationActions'; import { navigateToDetailFromHome } from '../../../actions/panelNavigationActions';
import SectionTitle from '../../../components/SectionTitle/SectionTitle'; import SectionTitle from '../../../components/SectionTitle/SectionTitle';
import Tag from '../../../components/TItemCard/Tag'; import Tag from '../../../components/TItemCard/Tag';
@@ -19,20 +15,13 @@ import TItemCardNew from '../../../components/TItemCard/TItemCard.new';
import TScroller from '../../../components/TScroller/TScroller'; import TScroller from '../../../components/TScroller/TScroller';
import useScrollReset from '../../../hooks/useScrollReset'; import useScrollReset from '../../../hooks/useScrollReset';
import useScrollTo from '../../../hooks/useScrollTo'; import useScrollTo from '../../../hooks/useScrollTo';
import { import { LOG_CONTEXT_NAME, LOG_MESSAGE_ID, panel_names } from '../../../utils/Config';
LOG_CONTEXT_NAME,
LOG_MESSAGE_ID,
panel_names,
} from '../../../utils/Config';
import { $L, scaleW } from '../../../utils/helperMethods'; import { $L, scaleW } from '../../../utils/helperMethods';
import { SpotlightIds } from '../../../utils/SpotlightIds'; import { SpotlightIds } from '../../../utils/SpotlightIds';
import css from './BestSeller.module.less'; import css from './BestSeller.module.less';
const SpottableComponent = Spottable('div'); const SpottableComponent = Spottable('div');
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
{ enterTo: 'last-focused' },
'div'
);
const BestSeller = ({ const BestSeller = ({
order, order,
@@ -44,26 +33,15 @@ const BestSeller = ({
shelfTitle, shelfTitle,
}) => { }) => {
const { getScrollTo, scrollLeft } = useScrollTo(); const { getScrollTo, scrollLeft } = useScrollTo();
const { handleScrollReset, handleStopScrolling } = useScrollReset( const { handleScrollReset, handleStopScrolling } = useScrollReset(scrollLeft, true);
scrollLeft,
true
);
const dispatch = useDispatch(); const dispatch = useDispatch();
const { cursorVisible } = useSelector((state) => state.common.appStatus); const { cursorVisible } = useSelector((state) => state.common.appStatus);
const bestSellerDatas = useSelector( const bestSellerDatas = useSelector((state) => state.product.bestSellerData?.bestSeller);
(state) => state.product.bestSellerData?.bestSeller
);
const bestSellerNewDatas = useSelector( const bestSellerNewDatas = useSelector((state) => state.foryou?.recommendInfo?.recommendProduct);
(state) => state.foryou?.recommendInfo?.recommendProduct
);
const { userNumber } = useSelector(
(state) => state.common.appStatus.loginUserData
);
const [drawChk, setDrawChk] = useState(false); const [drawChk, setDrawChk] = useState(false);
const [firstChk, setFirstChk] = useState(0); const [firstChk, setFirstChk] = useState(0);
@@ -73,45 +51,37 @@ const BestSeller = ({
useEffect(() => { useEffect(() => {
setBestInfos( setBestInfos(
bestSellerNewDatas?.filter( bestSellerNewDatas?.filter((item) => item.recommendTpCd === 'BESTSELLER') || [] // 기본값으로 빈 배열 설정
(item) => item.recommendTpCd === 'BESTSELLER'
) || [] // 기본값으로 빈 배열 설정
); );
}, [bestSellerNewDatas]); }, [bestSellerNewDatas]);
useEffect(() => { useEffect(() => {
if (userNumber) { if (!bestInfos || bestInfos.length === 0) {
if (!bestInfos || bestInfos.length === 0) {
const baseData =
bestSellerDatas?.map((item) => ({
...item,
foryou: false,
})) || [];
setBestItemNewData(baseData);
return;
}
const recommendedData =
bestInfos[0].productInfos?.map((item) => ({
...item,
foryou: true,
})) || [];
const recommendedPrdtIds = new Set(
recommendedData.map((item) => item.prdtId)
);
const baseData = const baseData =
bestSellerDatas?.map((item) => ({ bestSellerDatas?.map((item) => ({
...item, ...item,
foryou: recommendedPrdtIds.has(item.prdtId), foryou: false,
})) || []; })) || [];
setBestItemNewData(baseData); setBestItemNewData(baseData);
} else { return;
setBestItemNewData(bestSellerDatas);
} }
}, [bestSellerDatas, bestInfos, userNumber]);
const recommendedData =
bestInfos[0].productInfos?.map((item) => ({
...item,
foryou: true,
})) || [];
const recommendedPrdtIds = new Set(recommendedData.map((item) => item.prdtId));
const baseData =
bestSellerDatas?.map((item) => ({
...item,
foryou: recommendedPrdtIds.has(item.prdtId),
})) || [];
setBestItemNewData(baseData);
}, [bestSellerDatas, bestInfos]);
const orderStyle = useMemo(() => ({ order: order }), [order]); const orderStyle = useMemo(() => ({ order: order }), [order]);
@@ -174,10 +144,7 @@ const BestSeller = ({
if (c) { if (c) {
let cAriaLabel = c.getAttribute('aria-label'); let cAriaLabel = c.getAttribute('aria-label');
if (cAriaLabel) { if (cAriaLabel) {
const newcAriaLabel = cAriaLabel.replace( const newcAriaLabel = cAriaLabel.replace('Best Seller, Heading 1,', '');
'Best Seller, Heading 1,',
''
);
c.setAttribute('aria-label', newcAriaLabel); c.setAttribute('aria-label', newcAriaLabel);
} }
} }

View File

@@ -54,9 +54,6 @@ export default function HomeBanner({
const popupVisible = useSelector((state) => state.common.popup.popupVisible); const popupVisible = useSelector((state) => state.common.popup.popupVisible);
const panels = useSelector((state) => state.panels.panels); const panels = useSelector((state) => state.panels.panels);
const isDeepLinkEntry = useSelector(
(state) => state.home.homeInfo?.panelInfo?.isDeepLinkEntry
);
// 🔽 useFocusHistory - 경량화된 범용 포커스 히스토리 // 🔽 useFocusHistory - 경량화된 범용 포커스 히스토리
const focusHistory = useFocusHistory({ const focusHistory = useFocusHistory({
enableLogging: true, enableLogging: true,
@@ -167,11 +164,10 @@ export default function HomeBanner({
videoData = targetBannerData.bannerDetailInfos?.[0]; videoData = targetBannerData.bannerDetailInfos?.[0];
} }
// 🔽 [251221] DetailPanel이나 DeepLink PlayerPanel이 떠 있으면 배너 자동 재생 스킵 // DetailPanel이 떠 있는 동안에는 배너 자동 재생을 스킵 (PlayerPanel 모달 재설정 방지)
const hasDetailPanel = panels.some((p) => p.name === panel_names.DETAIL_PANEL); const hasDetailPanel = panels.some((p) => p.name === panel_names.DETAIL_PANEL);
const hasPlayerPanel = panels.some((p) => p.name === panel_names.PLAYER_PANEL);
if (!hasDetailPanel && !hasPlayerPanel && !isDeepLinkEntry && videoData && (videoData.shptmBanrTpNm === 'LIVE' || videoData.shptmBanrTpNm === 'VOD')) { if (!hasDetailPanel && videoData && (videoData.shptmBanrTpNm === 'LIVE' || videoData.shptmBanrTpNm === 'VOD')) {
console.log('[HomeBanner] 초기 비디오 자동 재생:', defaultFocus); console.log('[HomeBanner] 초기 비디오 자동 재생:', defaultFocus);
dispatch( dispatch(
@@ -189,7 +185,7 @@ export default function HomeBanner({
}) })
); );
} }
}, [bannerDataList, defaultFocus, dispatch, panels, isDeepLinkEntry]); }, [bannerDataList, defaultFocus, dispatch, panels]);
const renderItem = useCallback( const renderItem = useCallback(
(index, isHorizontal) => { (index, isHorizontal) => {

View File

@@ -7,7 +7,10 @@ import React, {
} from 'react'; } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux'; import {
useDispatch,
useSelector,
} from 'react-redux';
import { applyMiddleware } from 'redux'; import { applyMiddleware } from 'redux';
import Spotlight from '@enact/spotlight'; import Spotlight from '@enact/spotlight';
@@ -20,11 +23,11 @@ import {
import hsn from '../../../assets/images/bg/hsn_new.png'; import hsn from '../../../assets/images/bg/hsn_new.png';
import koreaKiosk from '../../../assets/images/bg/koreaKiosk_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 nbcu from '../../../assets/images/bg/nbcu_new.png';
import ontv4u from '../../../assets/images/bg/ontv4u_new.png'; import ontv4u from '../../../assets/images/bg/ontv4u_new.png';
import Pinkfong from '../../../assets/images/bg/Pinkfong_new.png'; import Pinkfong from '../../../assets/images/bg/Pinkfong_new.png';
import qvc from '../../../assets/images/bg/qvc_new.png'; import qvc from '../../../assets/images/bg/qvc_new.png';
import shoplc from '../../../assets/images/bg/shoplc_new.png'; import shoplc from '../../../assets/images/bg/shoplc_new.png';
import nbcu from '../../../assets/images/bg/nbcu_new.png';
import { types } from '../../actions/actionTypes'; import { types } from '../../actions/actionTypes';
import { import {
changeAppStatus, changeAppStatus,
@@ -42,8 +45,14 @@ import {
getHomeMainContents, getHomeMainContents,
updateHomeInfo, updateHomeInfo,
} from '../../actions/homeActions'; } from '../../actions/homeActions';
import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions'; import {
import { getSubCategory, getTop20Show } from '../../actions/mainActions'; sendLogGNB,
sendLogTotalRecommend,
} from '../../actions/logActions';
import {
getSubCategory,
getTop20Show,
} from '../../actions/mainActions';
import { setMyPageTermsAgree } from '../../actions/myPageActions'; import { setMyPageTermsAgree } from '../../actions/myPageActions';
import { getHomeOnSaleInfo } from '../../actions/onSaleActions'; import { getHomeOnSaleInfo } from '../../actions/onSaleActions';
import { updatePanel } from '../../actions/panelActions'; import { updatePanel } from '../../actions/panelActions';
@@ -60,7 +69,8 @@ import TButton, { TYPES } from '../../components/TButton/TButton';
import TPanel from '../../components/TPanel/TPanel'; import TPanel from '../../components/TPanel/TPanel';
import TNewPopUp from '../../components/TPopUp/TNewPopUp'; import TNewPopUp from '../../components/TPopUp/TNewPopUp';
import TPopUp from '../../components/TPopUp/TPopUp'; import TPopUp from '../../components/TPopUp/TPopUp';
import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator'; import TVerticalPagenator
from '../../components/TVerticalPagenator/TVerticalPagenator';
import useDebugKey from '../../hooks/useDebugKey'; import useDebugKey from '../../hooks/useDebugKey';
import { useFocusHistory } from '../../hooks/useFocusHistory/useFocusHistory'; import { useFocusHistory } from '../../hooks/useFocusHistory/useFocusHistory';
import usePrevious from '../../hooks/usePrevious'; import usePrevious from '../../hooks/usePrevious';
@@ -168,113 +178,68 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
// }); // });
const isGnbOpened = useSelector((state) => state.common.isGnbOpened); const isGnbOpened = useSelector((state) => state.common.isGnbOpened);
const homeLayoutInfo = useSelector((state) => state.home.layoutData); const homeLayoutInfo = useSelector((state) => state.home.layoutData);
const panelInfo = useSelector( const panelInfo = useSelector((state) => state.home.homeInfo?.panelInfo ?? {});
(state) => state.home.homeInfo?.panelInfo ?? {}
);
const panels = useSelector((state) => state.panels.panels); const panels = useSelector((state) => state.panels.panels);
const webOSVersion = useSelector( const webOSVersion = useSelector((state) => state.common.appStatus?.webOSVersion);
(state) => state.common.appStatus?.webOSVersion
);
const enterThroughGNB = useSelector((state) => state.home.enterThroughGNB); const enterThroughGNB = useSelector((state) => state.home.enterThroughGNB);
const defaultFocus = useSelector((state) => state.home.defaultFocus); const defaultFocus = useSelector((state) => state.home.defaultFocus);
const bannerDataList = useSelector( const bannerDataList = useSelector((state) => state.home.bannerData?.bannerInfos);
(state) => state.home.bannerData?.bannerInfos
);
// ✅ PlayerPanel의 shouldShrinkTo1px 상태 추적 // ✅ PlayerPanel의 shouldShrinkTo1px 상태 추적
const playerPanelShouldShrink = useSelector((state) => { const playerPanelShouldShrink = useSelector((state) => {
const playerPanel = state.panels.panels.find( const playerPanel = state.panels.panels.find((p) => p.name === panel_names.PLAYER_PANEL);
(p) => p.name === panel_names.PLAYER_PANEL
);
return playerPanel?.panelInfo?.shouldShrinkTo1px ?? false; return playerPanel?.panelInfo?.shouldShrinkTo1px ?? false;
}); });
// ✅ PlayerPanel의 modal 상태 추적 (false → true 감지용) // ✅ PlayerPanel의 modal 상태 추적 (false → true 감지용)
const playerModalState = useSelector((state) => { const playerModalState = useSelector((state) => {
const playerPanel = state.panels.panels.find( const playerPanel = state.panels.panels.find((p) => p.name === panel_names.PLAYER_PANEL);
(p) => p.name === panel_names.PLAYER_PANEL
);
return playerPanel?.panelInfo?.modal ?? false; return playerPanel?.panelInfo?.modal ?? false;
}); });
const prevPlayerModalStateRef = useRef(false); const prevPlayerModalStateRef = useRef(false);
const categoryInfos = useSelector( const categoryInfos = useSelector((state) => state.onSale.homeOnSaleData?.data?.categoryInfos);
(state) => state.onSale.homeOnSaleData?.data?.categoryInfos
);
const categoryItemInfos = useSelector( const categoryItemInfos = useSelector((state) => state.main.subCategoryData?.categoryItemInfos);
(state) => state.main.subCategoryData?.categoryItemInfos
);
const { popupVisible, activePopup } = useSelector( const { popupVisible, activePopup } = useSelector((state) => state.common.popup);
(state) => state.common.popup
);
const eventPopInfosData = useSelector( const eventPopInfosData = useSelector((state) => state.event.eventData.eventPopInfo);
(state) => state.event.eventData.eventPopInfo
);
const eventData = useSelector((state) => state.event.eventData); const eventData = useSelector((state) => state.event.eventData);
const eventClickSuccess = useSelector( const eventClickSuccess = useSelector((state) => state.event.eventClickSuccess);
(state) => state.event.eventClickSuccess const homeOnSaleInfos = useSelector((state) => state.onSale.homeOnSaleData?.data.homeOnSaleInfos);
); const bestSellerDatas = useSelector((state) => state.product.bestSellerData?.bestSeller);
const homeOnSaleInfos = useSelector(
(state) => state.onSale.homeOnSaleData?.data.homeOnSaleInfos
);
const bestSellerDatas = useSelector(
(state) => state.product.bestSellerData?.bestSeller
);
const topInfos = useSelector((state) => state.main.top20ShowData.topInfos); const topInfos = useSelector((state) => state.main.top20ShowData.topInfos);
const isDeepLink = useSelector( const isDeepLink = useSelector((state) => state.common.deepLinkInfo.isDeepLink);
(state) => state.common.deepLinkInfo.isDeepLink
);
// 선택약관 관련 Redux 상태 // 선택약관 관련 Redux 상태
const termsData = useSelector((state) => state.home.termsData); const termsData = useSelector((state) => state.home.termsData);
const termsIdMap = useSelector((state) => state.home.termsIdMap); const termsIdMap = useSelector((state) => state.home.termsIdMap);
const optionalTermsAvailable = useSelector( const optionalTermsAvailable = useSelector((state) => state.home.optionalTermsAvailable);
(state) => state.home.optionalTermsAvailable
);
const optionalTermsData = useSelector((state) => { const optionalTermsData = useSelector((state) => {
if ( if (state.home.termsData && state.home.termsData.data && state.home.termsData.data.terms) {
state.home.termsData && return state.home.termsData.data.terms.find((term) => term.trmsTpCd === 'MST00405');
state.home.termsData.data &&
state.home.termsData.data.terms
) {
return state.home.termsData.data.terms.find(
(term) => term.trmsTpCd === 'MST00405'
);
} }
return null; return null;
}); });
const termsLoading = useSelector((state) => state.common.termsLoading); const termsLoading = useSelector((state) => state.common.termsLoading);
const currentTermsFlag = useSelector((state) => state.common.termsFlag); const currentTermsFlag = useSelector((state) => state.common.termsFlag);
const optionalTermsPopupFlow = useSelector( const optionalTermsPopupFlow = useSelector((state) => state.common.optionalTermsPopupFlow);
(state) => state.common.optionalTermsPopupFlow
);
const { userNumber } = useSelector(
(state) => state.common.appStatus.loginUserData
);
const [btnDisabled, setBtnDisabled] = useState(true); const [btnDisabled, setBtnDisabled] = useState(true);
const [arrowBottom, setArrowBottom] = useState(true); const [arrowBottom, setArrowBottom] = useState(true);
const [firstSpot, setFirstSpot] = useState(false); const [firstSpot, setFirstSpot] = useState(false);
const [eventPopOpen, setEventPopOpen] = useState(false); const [eventPopOpen, setEventPopOpen] = useState(false);
const [nowShelf, setNowShelf] = useState(panelInfo.nowShelf); const [nowShelf, setNowShelf] = useState(panelInfo.nowShelf);
const [firstLgCatCd, setFirstLgCatCd] = useState( const [firstLgCatCd, setFirstLgCatCd] = useState(panelInfo.currentCatCd ?? null);
panelInfo.currentCatCd ?? null
);
const [cateCd, setCateCd] = useState(panelInfo.currentCatCd ?? null); const [cateCd, setCateCd] = useState(panelInfo.currentCatCd ?? null);
const [cateNm, setCateNm] = useState(panelInfo.currentCateName ?? null); const [cateNm, setCateNm] = useState(panelInfo.currentCateName ?? null);
// 선택약관 팝업 상태 // 선택약관 팝업 상태
const [isOptionalConfirmVisible, setIsOptionalConfirmVisible] = const [isOptionalConfirmVisible, setIsOptionalConfirmVisible] = useState(false);
useState(false);
const [isOptionalTermsVisible, setIsOptionalTermsVisible] = useState(false); const [isOptionalTermsVisible, setIsOptionalTermsVisible] = useState(false);
const [optionalTermsAgreed, setOptionalTermsAgreed] = useState(false); const [optionalTermsAgreed, setOptionalTermsAgreed] = useState(false);
const { entryMenu, nowMenu } = useSelector((state) => state.common.menu); const { entryMenu, nowMenu } = useSelector((state) => state.common.menu);
const [focusedContainerId, setFocusedContainerId] = useState( const [focusedContainerId, setFocusedContainerId] = useState(panelInfo.focusedContainerId);
panelInfo.focusedContainerId
);
// DetailPanel 진입 시 포커스 대상 저장 // DetailPanel 진입 시 포커스 대상 저장
const lastFocusedTargetRef = useRef(panelInfo.lastFocusedTargetId || null); const lastFocusedTargetRef = useRef(panelInfo.lastFocusedTargetId || null);
@@ -289,9 +254,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
useEffect(() => { useEffect(() => {
if (prevIsOnTopRef.current && !isOnTop) { if (prevIsOnTopRef.current && !isOnTop) {
const current = Spotlight.getCurrent(); const current = Spotlight.getCurrent();
const tBody = document.querySelector( const tBody = document.querySelector(`[data-spotlight-id="${SpotlightIds.HOME_TBODY}"]`);
`[data-spotlight-id="${SpotlightIds.HOME_TBODY}"]`
);
if (current && tBody && tBody.contains(current)) { if (current && tBody && tBody.contains(current)) {
const targetId = current.getAttribute('data-spotlight-id'); const targetId = current.getAttribute('data-spotlight-id');
@@ -323,9 +286,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
ImagePreloader.preloadAllImages(BACKGROUND_IMAGES) ImagePreloader.preloadAllImages(BACKGROUND_IMAGES)
.then((results) => { .then((results) => {
const successCount = results.filter((r) => r !== null).length; const successCount = results.filter((r) => r !== null).length;
dlog( dlog(`[HomePanel] Background images preloaded: ${successCount}/${results.length} images`);
`[HomePanel] Background images preloaded: ${successCount}/${results.length} images`
);
// 프리로딩 통계 정보 로깅 (디버깅용) // 프리로딩 통계 정보 로깅 (디버깅용)
const stats = ImagePreloader.getStats(); const stats = ImagePreloader.getStats();
@@ -351,9 +312,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
const sortedHomeLayoutInfo = useMemo(() => { const sortedHomeLayoutInfo = useMemo(() => {
if (homeLayoutInfo && homeLayoutInfo.homeLayoutInfo) { if (homeLayoutInfo && homeLayoutInfo.homeLayoutInfo) {
const sorted = [...homeLayoutInfo.homeLayoutInfo].sort( const sorted = [...homeLayoutInfo.homeLayoutInfo].sort((x, y) => x.expsOrd - y.expsOrd);
(x, y) => x.expsOrd - y.expsOrd
);
return sorted; return sorted;
} }
return []; return [];
@@ -378,9 +337,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
const expandAttemptRef = useRef(0); // 복구 시도 횟수 const expandAttemptRef = useRef(0); // 복구 시도 횟수
const loadingComplete = useSelector((state) => state.common?.loadingComplete); const loadingComplete = useSelector((state) => state.common?.loadingComplete);
const isVideoTransitionLocked = useSelector( const isVideoTransitionLocked = useSelector((state) => state.home.videoTransitionLocked);
(state) => state.home.videoTransitionLocked
);
// 선택약관 동의 핸들러 // 선택약관 동의 핸들러
const handleOptionalAgree = useCallback(() => { const handleOptionalAgree = useCallback(() => {
@@ -458,9 +415,9 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
optionalTerms: 'Y', optionalTerms: 'Y',
}, },
}); });
setTimeout(() => { setTimeout(()=>{
Spotlight.focus('home_tbody'); Spotlight.focus('home_tbody');
}, 100); },100)
}, [handleOptionalAgree, dispatch, currentTermsFlag]); }, [handleOptionalAgree, dispatch, currentTermsFlag]);
const handleOptionalDeclineClick = useCallback(() => { const handleOptionalDeclineClick = useCallback(() => {
@@ -469,9 +426,9 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
} }
dispatch(updateOptionalTermsAgreement(false)); dispatch(updateOptionalTermsAgreement(false));
setIsOptionalConfirmVisible(false); setIsOptionalConfirmVisible(false);
setTimeout(() => { setTimeout(()=>{
Spotlight.focus('home_tbody'); Spotlight.focus('home_tbody');
}, 100); },100)
}, [dispatch]); }, [dispatch]);
const handleTermsPopupClosed = useCallback(() => { const handleTermsPopupClosed = useCallback(() => {
@@ -542,12 +499,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
return () => clearTimeout(timer); return () => clearTimeout(timer);
} }
}, [ }, [shouldShowOptionalTermsPopup, termsLoading, isOptionalConfirmVisible, dispatch]);
shouldShowOptionalTermsPopup,
termsLoading,
isOptionalConfirmVisible,
dispatch,
]);
const onCancel = useCallback(() => { const onCancel = useCallback(() => {
const currentSpot = Spotlight.getCurrent(); const currentSpot = Spotlight.getCurrent();
@@ -598,8 +550,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
const containerId = sortedHomeLayoutInfo[0].shptmApphmDspyOptCd; const containerId = sortedHomeLayoutInfo[0].shptmApphmDspyOptCd;
const navigableEls = getContainerNavigableElements(containerId); const navigableEls = getContainerNavigableElements(containerId);
const navigableIds = navigableEls.filter((el) => typeof el === 'string'); const navigableIds = navigableEls.filter((el) => typeof el === 'string');
const target = const target = containerId === TEMPLATE_CODE_CONF.TOP ? 'banner0' : containerId;
containerId === TEMPLATE_CODE_CONF.TOP ? 'banner0' : containerId;
if (navigableIds.length > 0) { if (navigableIds.length > 0) {
setContainerLastFocusedElement(null, navigableIds); setContainerLastFocusedElement(null, navigableIds);
@@ -675,9 +626,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
<HomeBanner <HomeBanner
key={el.shptmApphmDspyOptCd} key={el.shptmApphmDspyOptCd}
spotlightId={el.shptmApphmDspyOptCd} spotlightId={el.shptmApphmDspyOptCd}
firstSpot={ firstSpot={!panelInfo.focusedContainerId && !panelInfo.currentSpot}
!panelInfo.focusedContainerId && !panelInfo.currentSpot
}
className={css.homeBannerWrap} className={css.homeBannerWrap}
handleShelfFocus={handleItemFocus( handleShelfFocus={handleItemFocus(
el.shptmApphmDspyOptCd, el.shptmApphmDspyOptCd,
@@ -769,7 +718,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
} else break; } else break;
} }
case TEMPLATE_CODE_CONF.PICK_FOR_YOU: { case TEMPLATE_CODE_CONF.PICK_FOR_YOU: {
if (userNumber) { if (bestSellerDatas && bestSellerDatas.length > 0) {
return ( return (
<PickedForYou <PickedForYou
key={el.shptmApphmDspyOptCd} key={el.shptmApphmDspyOptCd}
@@ -788,20 +737,18 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
} }
} }
})} })}
{loadingComplete && {loadingComplete && sortedHomeLayoutInfo && sortedHomeLayoutInfo.length > 0 && (
sortedHomeLayoutInfo && <TButton
sortedHomeLayoutInfo.length > 0 && ( className={css.tButton}
<TButton onClick={handleTopButtonClick}
className={css.tButton} size={null}
onClick={handleTopButtonClick} type={TYPES.topButton}
size={null} spotlightId={'home-top-btn'}
type={TYPES.topButton} spotlightDisabled={btnDisabled}
spotlightId={'home-top-btn'} data-wheel-point={true}
spotlightDisabled={btnDisabled} aria-label="Move to Top, Button"
data-wheel-point={true} />
aria-label="Move to Top, Button" )}
/>
)}
</> </>
); );
}, [ }, [
@@ -967,9 +914,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
// console.log('[HomePanel] playVideo 호출 완료'); // console.log('[HomePanel] playVideo 호출 완료');
if (isDeepLink || (!panels.length && !panelInfo.focusedContainerId)) { if (isDeepLink || (!panels.length && !panelInfo.focusedContainerId)) {
dispatch( dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } }));
changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } })
);
dispatch(getHomeMainContents()); dispatch(getHomeMainContents());
dispatch(getHomeLayout()); dispatch(getHomeLayout());
dispatch( dispatch(
@@ -1126,9 +1071,6 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
const detailPanelClosedTime = useSelector( const detailPanelClosedTime = useSelector(
(state) => state.home.homeInfo?.panelInfo?.detailPanelClosedAt (state) => state.home.homeInfo?.panelInfo?.detailPanelClosedAt
); );
const isDeepLinkEntry = useSelector(
(state) => state.home.homeInfo?.panelInfo?.isDeepLinkEntry
);
useEffect(() => { useEffect(() => {
if (detailPanelClosed && isOnTop) { if (detailPanelClosed && isOnTop) {
@@ -1140,18 +1082,9 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
// console.log('[HomePanel] *** videoPlayIntentRef.current:', videoPlayIntentRef.current); // console.log('[HomePanel] *** videoPlayIntentRef.current:', videoPlayIntentRef.current);
// console.log('[HomePanel] *** lastPlayedBannerIdRef.current:', lastPlayedBannerIdRef.current); // console.log('[HomePanel] *** lastPlayedBannerIdRef.current:', lastPlayedBannerIdRef.current);
// 🔽 [251221] DeepLink로 PlayerPanel이 진입한 경우 자동 재생 스킵
// (플래그 리셋은 PlayerPanel cleanup에서 처리하므로 여기서는 스킵만)
if (isDeepLinkEntry) {
dlog('[HomePanel] *** [DeepLink] isDeepLinkEntry=true 감지 - 자동 재생 스킵');
return;
}
// 🔽 videoPlayIntentRef가 null인 경우: 비디오 재생 가능한 첫 번째 배너 찾기 // 🔽 videoPlayIntentRef가 null인 경우: 비디오 재생 가능한 첫 번째 배너 찾기
if (!videoPlayIntentRef.current && bannerDataList) { if (!videoPlayIntentRef.current && bannerDataList) {
dlog( dlog('[HomePanel] *** videoPlayIntentRef가 null - 첫 번째 비디오 배너 검색');
'[HomePanel] *** videoPlayIntentRef가 null - 첫 번째 비디오 배너 검색'
);
// HomeBanner.jsx의 defaultFocus 계산 로직과 동일 // HomeBanner.jsx의 defaultFocus 계산 로직과 동일
let targetIndex = 0; let targetIndex = 0;
@@ -1205,10 +1138,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
}; };
lastPlayedBannerIdRef.current = bannerId; lastPlayedBannerIdRef.current = bannerId;
dlog( dlog('[HomePanel] *** videoPlayIntentRef 설정 완료:', videoPlayIntentRef.current);
'[HomePanel] *** videoPlayIntentRef 설정 완료:',
videoPlayIntentRef.current
);
} else { } else {
dlog('[HomePanel] *** ⚠️ 비디오 재생 가능한 배너를 찾지 못함'); dlog('[HomePanel] *** ⚠️ 비디오 재생 가능한 배너를 찾지 못함');
} }
@@ -1251,8 +1181,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
// 🔽 DetailPanel에서 돌아온 뒤 포커스를 마지막 포커스 대상에 복원 // 🔽 DetailPanel에서 돌아온 뒤 포커스를 마지막 포커스 대상에 복원
dlog('[HomePanel] *** 🎯 Focus 복원 준비'); dlog('[HomePanel] *** 🎯 Focus 복원 준비');
const targetFocusId = const targetFocusId = panelInfo.lastFocusedTargetId || lastFocusedTargetRef.current;
panelInfo.lastFocusedTargetId || lastFocusedTargetRef.current;
dlog( dlog(
'[HomePanel] *** 📍 targetFocusId:', '[HomePanel] *** 📍 targetFocusId:',
targetFocusId, targetFocusId,
@@ -1290,7 +1219,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
); );
} }
} }
}, [detailPanelClosed, isOnTop, bannerDataList, isDeepLinkEntry, dispatch]); }, [detailPanelClosed, isOnTop, bannerDataList, dispatch]);
// ======= // =======
// const justCameBack = !prevIsOnTopRef.current && isOnTop; // const justCameBack = !prevIsOnTopRef.current && isOnTop;
@@ -1321,9 +1250,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
targetSpotlightCateNm = c.getAttribute('data-catcd-nm'); targetSpotlightCateNm = c.getAttribute('data-catcd-nm');
} }
const tBody = document.querySelector( const tBody = document.querySelector(`[data-spotlight-id="${SpotlightIds.HOME_TBODY}"]`);
`[data-spotlight-id="${SpotlightIds.HOME_TBODY}"]`
);
const currentSpot = c && tBody.contains(c) ? targetSpotlightId : null; const currentSpot = c && tBody.contains(c) ? targetSpotlightId : null;
dispatch(checkEnterThroughGNB(false)); dispatch(checkEnterThroughGNB(false));
@@ -1336,8 +1263,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
currentCateName: targetSpotlightCateNm, currentCateName: targetSpotlightCateNm,
// <<<<<<< HEAD // <<<<<<< HEAD
focusedContainerId: focusedContainerIdRef.current, focusedContainerId: focusedContainerIdRef.current,
lastFocusedTargetId: lastFocusedTargetId: lastFocusedTargetRef.current || panelInfo.lastFocusedTargetId,
lastFocusedTargetRef.current || panelInfo.lastFocusedTargetId,
// ======= // =======
// focusedContainerId: focusedContainerId, // focusedContainerId: focusedContainerId,
// >>>>>>> gitlab/develop // >>>>>>> gitlab/develop
@@ -1413,9 +1339,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
<> <>
{/* HomePanel용 메모리 상주 그라데이션 배경 */} {/* HomePanel용 메모리 상주 그라데이션 배경 */}
<div <div
className={classNames(css.gradientBackground, { className={classNames(css.gradientBackground, { [css.visible]: showGradientBackground })}
[css.visible]: showGradientBackground,
})}
aria-hidden="true" aria-hidden="true"
/> />
@@ -1445,10 +1369,7 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
)} )}
{arrowBottom && ( {arrowBottom && (
<p <p className={classNames(css.arrow, css.arrowBottom)} onClick={handleArrowClick} />
className={classNames(css.arrow, css.arrowBottom)}
onClick={handleArrowClick}
/>
)} )}
{activePopup === ACTIVE_POPUP.exitPopup && ( {activePopup === ACTIVE_POPUP.exitPopup && (
@@ -1465,8 +1386,9 @@ const HomePanel = ({ isOnTop, showGradientBackground = false }) => {
text={$L('Are you sure you want to exit Shop Time?')} text={$L('Are you sure you want to exit Shop Time?')}
/> />
)} )}
{(activePopup === ACTIVE_POPUP.eventPopup || {(activePopup === ACTIVE_POPUP.eventPopup || activePopup === ACTIVE_POPUP.smsPopup) && (
activePopup === ACTIVE_POPUP.smsPopup) && <EventPopUpBanner />} <EventPopUpBanner />
)}
{/* 선택약관 동의 팝업 */} {/* 선택약관 동의 팝업 */}
<OptionalConfirm <OptionalConfirm
open={isOptionalConfirmVisible} open={isOptionalConfirmVisible}

View File

@@ -1,14 +1,24 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, {
useCallback,
useEffect,
useMemo,
useState,
} from 'react';
import { useDispatch, useSelector } from 'react-redux'; import {
useDispatch,
useSelector,
} from 'react-redux';
import Spotlight from '@enact/spotlight'; import Spotlight from '@enact/spotlight';
import { SpotlightContainerDecorator } from '@enact/spotlight/SpotlightContainerDecorator'; import {
SpotlightContainerDecorator,
} from '@enact/spotlight/SpotlightContainerDecorator';
import Spottable from '@enact/spotlight/Spottable'; import Spottable from '@enact/spotlight/Spottable';
import { getContainerId } from '@enact/spotlight/src/container'; import { getContainerId } from '@enact/spotlight/src/container';
import { updateHomeInfo } from '../../../actions/homeActions'; import { updateHomeInfo } from '../../../actions/homeActions';
import { popPanel, pushPanel } from '../../../actions/panelActions'; import { pushPanel, popPanel } from '../../../actions/panelActions';
import { startVideoPlayer } from '../../../actions/playActions'; import { startVideoPlayer } from '../../../actions/playActions';
import SectionTitle from '../../../components/SectionTitle/SectionTitle'; import SectionTitle from '../../../components/SectionTitle/SectionTitle';
import Tag from '../../../components/TItemCard/Tag'; import Tag from '../../../components/TItemCard/Tag';
@@ -25,15 +35,18 @@ import {
LOG_MESSAGE_ID, LOG_MESSAGE_ID,
panel_names, panel_names,
} from '../../../utils/Config'; } from '../../../utils/Config';
import { $L, scaleW } from '../../../utils/helperMethods'; import {
$L,
scaleW,
} from '../../../utils/helperMethods';
import { SpotlightIds } from '../../../utils/SpotlightIds'; import { SpotlightIds } from '../../../utils/SpotlightIds';
import { TEMPLATE_CODE_CONF } from '../HomePanel'; import { TEMPLATE_CODE_CONF } from '../HomePanel';
import css from '../PopularShow/PopularShow.module.less'; import css from '../PopularShow/PopularShow.module.less';
const SpottableComponent = Spottable('div'); const SpottableComponent = Spottable("div");
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
{ enterTo: 'last-focused' }, { enterTo: "last-focused" },
'div' "div"
); );
const PopularShow = ({ const PopularShow = ({
@@ -59,13 +72,9 @@ const PopularShow = ({
const panels = useSelector((state) => state.panels.panels); const panels = useSelector((state) => state.panels.panels);
const topInfos = useSelector((state) => state.main.top20ShowData.topInfos); const topInfos = useSelector((state) => state.main.top20ShowData.topInfos);
const recommendInfo = useSelector( const recommendInfo = useSelector((state) => state.foryou?.recommendInfo?.recommendShow);
(state) => state.foryou?.recommendInfo?.recommendShow
);
const { userNumber } = useSelector(
(state) => state.common.appStatus.loginUserData
);
const orderStyle = useMemo(() => ({ order: order }), [order]); const orderStyle = useMemo(() => ({ order: order }), [order]);
const [drawChk, setDrawChk] = useState(false); const [drawChk, setDrawChk] = useState(false);
@@ -78,46 +87,41 @@ const PopularShow = ({
setDrawChk(true); setDrawChk(true);
}, [topInfos]); }, [topInfos]);
useEffect(() => { useEffect(()=>{
setShowInfos( setShowInfos(
recommendInfo?.filter((item) => item.recommendTpCd === 'POPULARSHOW') || recommendInfo?.filter(
[] (item) => item.recommendTpCd === "POPULARSHOW"
); ) || []
}, [recommendInfo]); )
},[recommendInfo])
useEffect(() => { useEffect(() => {
if (userNumber) { if (!showInfos || showInfos.length === 0) {
if (!showInfos || showInfos.length === 0) { const baseData = topInfos?.map((item) => ({
const baseData = ...item,
topInfos?.map((item) => ({ foryou: false,
...item, })) || [];
foryou: false, setShowNewInfos(baseData);
})) || []; return;
setShowNewInfos(baseData);
return;
}
const recommendedData =
showInfos[0].showInfos?.map((item) => ({
...item,
foryou: true,
})) || [];
const recommendedPrdtIds = new Set(
recommendedData?.map((item) => item.showId)
);
const baseData =
topInfos?.map((item) => ({
...item,
foryou: recommendedPrdtIds.has(item.showId),
})) || [];
setShowNewInfos([...baseData]);
} else {
setShowNewInfos(topInfos);
} }
}, [topInfos, showInfos, userNumber]);
const recommendedData = showInfos[0].showInfos?.map((item) => ({
...item,
foryou: true,
})) || [];
const recommendedPrdtIds = new Set(recommendedData?.map(item => item.showId));
const baseData = topInfos?.map((item) => ({
...item,
foryou: recommendedPrdtIds.has(item.showId),
})) || [];
setShowNewInfos([ ...baseData]);
}, [topInfos, showInfos]);
const handleCardClick = useCallback( const handleCardClick = useCallback(
(patnrId, showId, catCd, showUrl) => () => { (patnrId, showId, catCd, showUrl) => () => {
@@ -131,7 +135,7 @@ const PopularShow = ({
startVideoPlayer({ startVideoPlayer({
showId, showId,
patnrId, patnrId,
shptmBanrTpNm: 'VOD', shptmBanrTpNm: "VOD",
lgCatCd: catCd, lgCatCd: catCd,
modal: false, modal: false,
showUrl: showUrl, showUrl: showUrl,
@@ -147,7 +151,7 @@ const PopularShow = ({
{ {
name: panel_names.TRENDING_NOW_PANEL, name: panel_names.TRENDING_NOW_PANEL,
panelInfo: { panelInfo: {
pageName: 'PS', pageName: "PS",
focusedContainerId: SpotlightIds.TRENDING_NOW_POPULAR_SHOW, focusedContainerId: SpotlightIds.TRENDING_NOW_POPULAR_SHOW,
}, },
}, },
@@ -175,23 +179,23 @@ const PopularShow = ({
if (firstChk === 0 && itemIndex === 0) { if (firstChk === 0 && itemIndex === 0) {
const c = Spotlight.getCurrent(); const c = Spotlight.getCurrent();
const getAriaLabel = c.getAttribute('aria-label'); const getAriaLabel = c.getAttribute("aria-label");
if (c) { if (c) {
let cAriaLabel = c.getAttribute('aria-label'); let cAriaLabel = c.getAttribute("aria-label");
cAriaLabel = 'POPULAR SHOW, Heading 1,' + cAriaLabel; cAriaLabel = "POPULAR SHOW, Heading 1," + cAriaLabel;
c.setAttribute('aria-label', cAriaLabel); c.setAttribute("aria-label", cAriaLabel);
} }
setFirstChk(1); setFirstChk(1);
} else if (firstChk === 1 && itemIndex === 0) { } else if (firstChk === 1 && itemIndex === 0) {
const c = Spotlight.getCurrent(); const c = Spotlight.getCurrent();
if (c) { if (c) {
let cAriaLabel = c.getAttribute('aria-label'); let cAriaLabel = c.getAttribute("aria-label");
if (cAriaLabel) { if (cAriaLabel) {
const newcAriaLabel = cAriaLabel.replace( const newcAriaLabel = cAriaLabel.replace(
'POPULAR SHOW, Heading 1,', "POPULAR SHOW, Heading 1,",
'' ""
); );
c.setAttribute('aria-label', newcAriaLabel); c.setAttribute("aria-label", newcAriaLabel);
} }
} }
} else { } else {
@@ -242,7 +246,7 @@ const PopularShow = ({
> >
<SectionTitle <SectionTitle
className={css.subTitle} className={css.subTitle}
title={$L('POPULAR SHOW')} title={$L("POPULAR SHOW")}
data-title-index="homePopularShow" data-title-index="homePopularShow"
label="POPULAR SHOW" label="POPULAR SHOW"
/> />
@@ -267,11 +271,11 @@ const PopularShow = ({
patncNm, patncNm,
catCd, catCd,
showUrl, showUrl,
// <<<<<<< HEAD // <<<<<<< HEAD
foryou, foryou,
// ======= // =======
productInfos, productInfos,
// >>>>>>> gitlab/develop // >>>>>>> gitlab/develop
}, },
itemIndex itemIndex
) => { ) => {
@@ -289,18 +293,18 @@ const PopularShow = ({
showId={showId} showId={showId}
showTitle={showNm} showTitle={showNm}
imageSource={ imageSource={
thumbnailUrl && thumbnailUrl960 (thumbnailUrl && thumbnailUrl960) ?
? thumbnailUrl !== thumbnailUrl960 thumbnailUrl !== thumbnailUrl960
? thumbnailUrl960 ? thumbnailUrl960
: thumbnailUrl
: thumbnailUrl : thumbnailUrl
: thumbnailUrl
} }
imageAlt={showNm} imageAlt={showNm}
productName={productInfos[0].prdtNm} productName={productInfos[0].prdtNm}
nonPosition={true} nonPosition={true}
type={TYPES.videoShow} type={TYPES.videoShow}
imgType={ imgType={
vtctpYn !== 'Y' vtctpYn !== "Y"
? IMAGETYPES.imgHorizontal ? IMAGETYPES.imgHorizontal
: IMAGETYPES.imgVertical : IMAGETYPES.imgVertical
} }
@@ -309,11 +313,11 @@ const PopularShow = ({
onFocus={handleFocus(itemIndex)} onFocus={handleFocus(itemIndex)}
onBlur={handleBlur(itemIndex)} onBlur={handleBlur(itemIndex)}
onClick={handleCardClick(patnrId, showId, catCd, showUrl)} onClick={handleCardClick(patnrId, showId, catCd, showUrl)}
firstLabel={patncNm + ' '} firstLabel={patncNm + " "}
label={itemIndex * 1 + 1 + ' of ' + showNewInfos.length} label={itemIndex * 1 + 1 + " of " + showNewInfos.length}
lastLabel=" go to detail, button" lastLabel=" go to detail, button"
> >
{foryou === true && <Tag text={'For You'} />} {foryou === true && <Tag text={"For You"} />}
</TItemCardNew> </TItemCardNew>
); );
} }
@@ -325,7 +329,7 @@ const PopularShow = ({
className={css.displayBox} className={css.displayBox}
onClick={handleMoreCardClick} onClick={handleMoreCardClick}
onFocus={_handleItemFocus} onFocus={_handleItemFocus}
spotlightId={'home-popularshow-more-btn'} spotlightId={"home-popularshow-more-btn"}
></SpottableComponent> ></SpottableComponent>
</div> </div>
)} )}

View File

@@ -8,32 +8,21 @@ import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
import { sendLogCuration } from '../../../actions/logActions'; import { sendLogCuration } from '../../../actions/logActions';
import { getSubCategory } from '../../../actions/mainActions'; import { getSubCategory } from '../../../actions/mainActions';
import { import { pushPanel, navigateFromSubCategory } from '../../../actions/panelActions';
navigateFromSubCategory,
pushPanel,
} from '../../../actions/panelActions';
import Tag from '../../../components/TItemCard/Tag'; import Tag from '../../../components/TItemCard/Tag';
import TItemCardNew from '../../../components/TItemCard/TItemCard.new'; import TItemCardNew from '../../../components/TItemCard/TItemCard.new';
import TScroller from '../../../components/TScroller/TScroller'; import TScroller from '../../../components/TScroller/TScroller';
import usePrevious from '../../../hooks/usePrevious'; import usePrevious from '../../../hooks/usePrevious';
import useScrollReset from '../../../hooks/useScrollReset'; import useScrollReset from '../../../hooks/useScrollReset';
import useScrollTo from '../../../hooks/useScrollTo'; import useScrollTo from '../../../hooks/useScrollTo';
import { import { LOG_CONTEXT_NAME, LOG_MESSAGE_ID, LOG_TP_NO, panel_names } from '../../../utils/Config';
LOG_CONTEXT_NAME,
LOG_MESSAGE_ID,
LOG_TP_NO,
panel_names,
} from '../../../utils/Config';
import { SpotlightIds } from '../../../utils/SpotlightIds'; import { SpotlightIds } from '../../../utils/SpotlightIds';
import CategoryNav from '../../HomePanel/SubCategory/CategoryNav/CategoryNav'; import CategoryNav from '../../HomePanel/SubCategory/CategoryNav/CategoryNav';
import css from '../../HomePanel/SubCategory/SubCategory.module.less'; import css from '../../HomePanel/SubCategory/SubCategory.module.less';
const SpottableComponent = Spottable('div'); const SpottableComponent = Spottable('div');
const Container = SpotlightContainerDecorator({ enterTo: null }, 'div'); const Container = SpotlightContainerDecorator({ enterTo: null }, 'div');
const ContainerBasic = SpotlightContainerDecorator( const ContainerBasic = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
{ enterTo: 'last-focused' },
'div'
);
const getExpsOrdByLgCatCd = (array, value) => { const getExpsOrdByLgCatCd = (array, value) => {
const expsOrd = array.findIndex(({ lgCatCd }) => value === lgCatCd) + 1; const expsOrd = array.findIndex(({ lgCatCd }) => value === lgCatCd) + 1;
@@ -51,24 +40,12 @@ export default memo(function SubCategory({
}) { }) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { getScrollTo, scrollLeft } = useScrollTo(); const { getScrollTo, scrollLeft } = useScrollTo();
const { handleScrollReset, handleStopScrolling } = useScrollReset( const { handleScrollReset, handleStopScrolling } = useScrollReset(scrollLeft, false);
scrollLeft,
false
);
const categoryInfos = useSelector( const categoryInfos = useSelector((state) => state.home.menuData?.data?.homeCategory);
(state) => state.home.menuData?.data?.homeCategory const categoryItemInfos = useSelector((state) => state.main.subCategoryData?.categoryItemInfos);
);
const categoryItemInfos = useSelector(
(state) => state.main.subCategoryData?.categoryItemInfos
);
const foruItemInfos = useSelector( const foruItemInfos = useSelector((state) => state.main.recommendProduct[0]?.productInfos);
(state) => state.main.recommendProduct[0]?.productInfos
);
const { userNumber } = useSelector(
(state) => state.common.appStatus.loginUserData
);
const nowMenu = useSelector((state) => state.common.menu.nowMenu); const nowMenu = useSelector((state) => state.common.menu.nowMenu);
@@ -230,45 +207,35 @@ export default memo(function SubCategory({
}, [handleShelfFocus]); }, [handleShelfFocus]);
useEffect(() => { useEffect(() => {
if (userNumber) { if (!foruItemInfos || foruItemInfos.length === 0) {
if (!foruItemInfos || foruItemInfos.length === 0) {
const baseData =
categoryItemInfos?.subCatItemList?.map((item) => ({
...item,
foryou: false,
})) || [];
setCategoryItemNewData(baseData);
return;
}
const recommendedData =
foruItemInfos?.map((item) => ({
...item,
foryou: true,
})) || [];
const recommendedPrdtIds = new Set(
recommendedData.map((item) => item.prdtId)
);
const baseData = const baseData =
categoryItemInfos?.subCatItemList?.map((item) => ({ categoryItemInfos?.subCatItemList?.map((item) => ({
...item, ...item,
foryou: recommendedPrdtIds.has(item.prdtId), foryou: false,
})) || []; })) || [];
setCategoryItemNewData(baseData);
setCategoryItemNewData([...baseData]); return;
} else {
setCategoryItemNewData(categoryItemInfos?.subCatItemList);
} }
}, [categoryItemInfos?.subCatItemList, foruItemInfos, userNumber]);
const recommendedData =
foruItemInfos?.map((item) => ({
...item,
foryou: true,
})) || [];
const recommendedPrdtIds = new Set(recommendedData.map((item) => item.prdtId));
const baseData =
categoryItemInfos?.subCatItemList?.map((item) => ({
...item,
foryou: recommendedPrdtIds.has(item.prdtId),
})) || [];
setCategoryItemNewData([...baseData]);
}, [categoryItemInfos?.subCatItemList, foruItemInfos]);
return ( return (
<Container <Container spotlightId={spotlightId} data-wheel-point onFocus={_handleShelfFocus}>
spotlightId={spotlightId}
data-wheel-point
onFocus={_handleShelfFocus}
>
<CategoryNav <CategoryNav
categoryInfos={categoryInfos} categoryInfos={categoryInfos}
currentCategoryCode={currentLgCatCd} currentCategoryCode={currentLgCatCd}
@@ -326,12 +293,7 @@ export default memo(function SubCategory({
offerInfo={offerInfo} offerInfo={offerInfo}
data-catcd-num={currentLgCatCd} data-catcd-num={currentLgCatCd}
data-catcd-nm={currentLgCatNm} data-catcd-nm={currentLgCatNm}
label={ label={itemIndex * 1 + 1 + ' of ' + (categoryItemNewData?.length || 0)}
itemIndex * 1 +
1 +
' of ' +
(categoryItemNewData?.length || 0)
}
lastLabel=" go to detail, button" lastLabel=" go to detail, button"
euEnrgLblInfos={euEnrgLblInfos} euEnrgLblInfos={euEnrgLblInfos}
> >

View File

@@ -209,9 +209,6 @@ export default function MainView({ className, initService }) {
const hasFeaturedBrandsPanel = panels.some( const hasFeaturedBrandsPanel = panels.some(
(panel) => panel?.name === Config.panel_names.FEATURED_BRANDS_PANEL (panel) => panel?.name === Config.panel_names.FEATURED_BRANDS_PANEL
); );
const hasTrendingNowPanel = panels.some(
(panel) => panel?.name === Config.panel_names.TRENDING_NOW_PANEL
);
// 단독 패널 체크 - CheckOutPanel, CartPanel 등 단독으로 렌더링되어야 하는 패널들 // 단독 패널 체크 - CheckOutPanel, CartPanel 등 단독으로 렌더링되어야 하는 패널들
if (DEBUG_MODE) { if (DEBUG_MODE) {
console.log(`[PANEL_MainView] 🔍 Top panel name: ${topPanel?.name}`); console.log(`[PANEL_MainView] 🔍 Top panel name: ${topPanel?.name}`);
@@ -253,11 +250,7 @@ export default function MainView({ className, initService }) {
'[MainView] Rendering 3-layer structure: PlayerPanel + DetailPanel + MediaPanel' '[MainView] Rendering 3-layer structure: PlayerPanel + DetailPanel + MediaPanel'
); );
} }
if (hasFeaturedBrandsPanel || hasTrendingNowPanel) { renderingPanels = hasFeaturedBrandsPanel ? panels.slice(-4) : panels.slice(-3);
renderingPanels = panels.slice(-4);
} else {
renderingPanels = panels.slice(-3);
}
} else if ( } else if (
panels[panels.length - 1]?.name === Config.panel_names.PLAYER_PANEL || panels[panels.length - 1]?.name === Config.panel_names.PLAYER_PANEL ||
panels[panels.length - 1]?.name === Config.panel_names.PLAYER_PANEL_NEW || panels[panels.length - 1]?.name === Config.panel_names.PLAYER_PANEL_NEW ||
@@ -265,11 +258,7 @@ export default function MainView({ className, initService }) {
panels[panels.length - 2]?.name === Config.panel_names.PLAYER_PANEL || panels[panels.length - 2]?.name === Config.panel_names.PLAYER_PANEL ||
panels[panels.length - 2]?.name === Config.panel_names.MEDIA_PANEL panels[panels.length - 2]?.name === Config.panel_names.MEDIA_PANEL
) { ) {
if (hasFeaturedBrandsPanel || hasTrendingNowPanel) { renderingPanels = hasFeaturedBrandsPanel ? panels.slice(-3) : panels.slice(-2);
renderingPanels = panels.slice(-3);
} else {
renderingPanels = panels.slice(-2);
}
} else { } else {
renderingPanels = panels.slice(-1); renderingPanels = panels.slice(-1);
} }

View File

@@ -391,7 +391,6 @@ const MediaPanel = React.forwardRef(
const onEnded = useCallback( const onEnded = useCallback(
(e) => { (e) => {
debugLog('[MediaPanel] Video ended'); debugLog('[MediaPanel] Video ended');
// console.log('[🔥UNIQUE_MEDIA_ENDED🔥] MediaPanel onEnded triggered - will pop after 1500ms');
// continuousPlay는 MediaPlayer(VideoPlayer) 컴포넌트 내부에서 loop 속성으로 처리 // continuousPlay는 MediaPlayer(VideoPlayer) 컴포넌트 내부에서 loop 속성으로 처리
// onEnded가 호출되면 loop=false 인 경우이므로 패널을 닫음 // onEnded가 호출되면 loop=false 인 경우이므로 패널을 닫음
Spotlight.pause(); Spotlight.pause();
@@ -403,7 +402,6 @@ const MediaPanel = React.forwardRef(
// ✅ 새로운 타이머 저장 (cleanup 시 정리용) // ✅ 새로운 타이머 저장 (cleanup 시 정리용)
onEndedTimerRef.current = setTimeout(() => { onEndedTimerRef.current = setTimeout(() => {
// console.log('[🔥UNIQUE_MEDIA_ENDED🔥] Executing popPanel(MEDIA_PANEL) after 1500ms');
Spotlight.resume(); Spotlight.resume();
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL)); dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL));
onEndedTimerRef.current = null; onEndedTimerRef.current = null;

View File

@@ -26,7 +26,7 @@
video { video {
max-width: 100%; max-width: 100%;
max-height: 100%; max-height: 100%;
object-fit: contain; /* 높이 기준으로 맞추고 좌우는 잘림 */ object-fit: contain; /* 비율 유지하면서 컨테이너 안에 맞춤 */
} }
} }

View File

@@ -912,7 +912,7 @@ const MediaPanel = React.forwardRef(
} }
if (!panelInfo.modal) { if (!panelInfo.modal) {
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL)); dispatch(PanelActions.popPanel());
dispatch(changeAppStatus({ cursorVisible: false })); dispatch(changeAppStatus({ cursorVisible: false }));
document?.dispatchEvent?.(new CustomEvent('detailpanel-scroll-reset')); document?.dispatchEvent?.(new CustomEvent('detailpanel-scroll-reset'));
@@ -937,7 +937,7 @@ const MediaPanel = React.forwardRef(
// 패널이 2개 존재할때만 popPanel 진행 // 패널이 2개 존재할때만 popPanel 진행
// fullscreen 전환 중이면 popPanel하지 않음 // fullscreen 전환 중이면 popPanel하지 않음
if (panelInfo.modal && !isOnTop && !isTransitioningToFullscreen.current) { if (panelInfo.modal && !isOnTop && !isTransitioningToFullscreen.current) {
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL)); dispatch(PanelActions.popPanel());
} else { } else {
Spotlight.focus('tbody'); Spotlight.focus('tbody');
} }
@@ -1576,7 +1576,7 @@ const MediaPanel = React.forwardRef(
) { ) {
// case: Featured Brands // case: Featured Brands
if (panelInfo?.sourcePanel === panel_names.FEATURED_BRANDS_PANEL) { if (panelInfo?.sourcePanel === panel_names.FEATURED_BRANDS_PANEL) {
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL)); dispatch(PanelActions.popPanel());
} }
} }
}, [ }, [
@@ -2043,25 +2043,19 @@ const MediaPanel = React.forwardRef(
(e) => { (e) => {
const currentInfo = panelInfoRef.current; const currentInfo = panelInfoRef.current;
// console.log('[🔥UNIQUE_MEDIA_ENDED🔥] onEnded triggered - shptmBanrTpNm:', currentInfo?.shptmBanrTpNm);
// MEDIA: 기존 동작 유지 (배경 복원 없이 즉시 pop) // MEDIA: 기존 동작 유지 (배경 복원 없이 즉시 pop)
if (currentInfo.shptmBanrTpNm === 'MEDIA') { if (currentInfo.shptmBanrTpNm === 'MEDIA') {
// console.log('[🔥UNIQUE_MEDIA_ENDED🔥] MEDIA type - popPanel will be called'); console.log('[MediaPanel] 🚫 Skipping background restoration for ended media');
Spotlight.pause(); Spotlight.pause();
setTimeout(() => { setTimeout(() => {
// console.log('[🔥UNIQUE_MEDIA_ENDED🔥] setTimeout fired - dispatching popPanel(MEDIA_PANEL)');
Spotlight.resume(); Spotlight.resume();
dispatch(PanelActions.popPanel(panel_names.MEDIA_PANEL)); dispatch(PanelActions.popPanel());
}, VIDEO_END_ACTION_DELAY); }, VIDEO_END_ACTION_DELAY);
e?.stopPropagation();
e?.preventDefault();
return; return;
} }
// VOD: modal 여부에 따라 동작 분리 // VOD: modal 여부에 따라 동작 분리
if (currentInfo.shptmBanrTpNm === 'VOD') { if (currentInfo.shptmBanrTpNm === 'VOD') {
// console.log('[🔥UNIQUE_MEDIA_ENDED🔥] VOD type - popPanel will be called');
Spotlight.pause(); Spotlight.pause();
setTimeout(() => { setTimeout(() => {
stopExternalPlayer(); stopExternalPlayer();
@@ -2080,8 +2074,6 @@ const MediaPanel = React.forwardRef(
e?.preventDefault(); e?.preventDefault();
return; return;
} }
// console.log('[🔥UNIQUE_MEDIA_ENDED🔥] Unknown shptmBanrTpNm - no action taken');
}, },
[dispatch, focusBackButtonOrFallback, stopExternalPlayer] [dispatch, focusBackButtonOrFallback, stopExternalPlayer]
); );

View File

@@ -30,7 +30,6 @@ import {
getMainLiveShow, getMainLiveShow,
getMainLiveShowNowProduct, getMainLiveShowNowProduct,
} from '../../actions/mainActions'; } from '../../actions/mainActions';
import { updateHomeInfo } from '../../actions/homeActions';
import * as PanelActions from '../../actions/panelActions'; import * as PanelActions from '../../actions/panelActions';
import { updatePanel } from '../../actions/panelActions'; import { updatePanel } from '../../actions/panelActions';
import { import {
@@ -408,10 +407,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
lastFocusedTargetId: panelInfo.lastFocusedTargetId, lastFocusedTargetId: panelInfo.lastFocusedTargetId,
}); });
// TabContainerV2의 tabIndex를 ShopNowContents(0)로 리셋
dlog('[PlayerPanel] 📑 TabContainerV2 tabIndex를 ShopNowContents(0)로 리셋');
setTabIndexV2(0);
// 포커스 복원 로직 추가 (1000ms 지연) // 포커스 복원 로직 추가 (1000ms 지연)
if (panelInfo.lastFocusedTargetId) { if (panelInfo.lastFocusedTargetId) {
dlog( dlog(
@@ -436,7 +431,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
}; };
} }
console.log('[PANEL] PlayerPanel updatePanel - detailPanelClosed reset');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
@@ -509,10 +503,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// PanelInfo 상태 변화 모니터링 useEffect (isPaused가 실제로 변경될 때만) // PanelInfo 상태 변화 모니터링 useEffect (isPaused가 실제로 변경될 때만)
useEffect(() => { useEffect(() => {
const isOnTop = panel_names.HOME_PANEL === topPanel?.name;
const isPausedChanged = previousPanelInfo.current?.isPaused !== panelInfo?.isPaused; const isPausedChanged = previousPanelInfo.current?.isPaused !== panelInfo?.isPaused;
// isOnTop 여부와 관계없이 isPaused 변경을 감지하여 비디오 제어 if (isOnTop && panelInfo?.isPaused !== undefined && isPausedChanged) {
if (panelInfo?.isPaused !== undefined && isPausedChanged) {
// 상태 변경 시에만 디버깅 로그 출력 // 상태 변경 시에만 디버깅 로그 출력
dlog('🔍 [PlayerPanel] PanelInfo isPaused changed', { dlog('🔍 [PlayerPanel] PanelInfo isPaused changed', {
previousIsPaused: previousPanelInfo.current?.isPaused, previousIsPaused: previousPanelInfo.current?.isPaused,
@@ -545,7 +539,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
} }
previousPanelInfo.current = panelInfo; previousPanelInfo.current = panelInfo;
}, [panelInfo?.isPaused, currentPlayingUrl]); }, [panelInfo?.isPaused, topPanel?.name, currentPlayingUrl]);
// VideoPlayer 인스턴스 및 소스 변경 모니터링 (중요 변화만) // VideoPlayer 인스턴스 및 소스 변경 모니터링 (중요 변화만)
useEffect(() => { useEffect(() => {
@@ -653,7 +647,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
useEffect(() => { useEffect(() => {
if (currentLiveShowInfo && Object.keys(currentLiveShowInfo).length > 0) { if (currentLiveShowInfo && Object.keys(currentLiveShowInfo).length > 0) {
if (currentLiveShowInfo.showId !== panelInfo?.showId) { if (currentLiveShowInfo.showId !== panelInfo?.showId) {
console.log('[PANEL] PlayerPanel updatePanel - LIVE showId update');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
@@ -1153,7 +1146,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
videoPlayer.current?.hideControls(); videoPlayer.current?.hideControls();
setSelectedIndex(backupInitialIndex); setSelectedIndex(backupInitialIndex);
if (panelInfo.shptmBanrTpNm === 'MEDIA') { if (panelInfo.shptmBanrTpNm === 'MEDIA') {
console.log('[PANEL] PlayerPanel updatePanel - DETAIL_PANEL launchedFromPlayer false');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.DETAIL_PANEL, name: panel_names.DETAIL_PANEL,
@@ -1171,7 +1163,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
if (!panelInfo.modal) { if (!panelInfo.modal) {
console.log('[PlayerPanel] popPanel - closeButtonHandler'); console.log('[PlayerPanel] popPanel - closeButtonHandler');
dispatch(PanelActions.popPanel()); dispatch(PanelActions.popPanel());
// 🔽 [251221] cleanup useEffect에서 isDeepLinkEntry 리셋 처리
dispatch(changeAppStatus({ cursorVisible: false })); dispatch(changeAppStatus({ cursorVisible: false }));
//딮링크로 플레이어 진입 후 이전버튼 클릭시 //딮링크로 플레이어 진입 후 이전버튼 클릭시
@@ -1208,17 +1199,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
topPanel: panels[panels.length - 1]?.name, topPanel: panels[panels.length - 1]?.name,
stack: panels.map((p) => p.name), stack: panels.map((p) => p.name),
}); });
// 🔽 [251221] PlayerPanel unmount 시 DeepLink 플래그 리셋
dispatch(
updateHomeInfo({
name: panel_names.HOME_PANEL,
panelInfo: {
isDeepLinkEntry: false,
},
})
);
const topPanelName = panels[panels.length - 1]?.name; const topPanelName = panels[panels.length - 1]?.name;
if ( if (
panelInfo.modal && panelInfo.modal &&
@@ -1232,7 +1212,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
Spotlight.focus('tbody'); Spotlight.focus('tbody');
} }
}; };
}, [panelInfo?.modal, isOnTop, panels, dispatch]); }, [panelInfo?.modal, isOnTop, panels]);
useEffect(() => { useEffect(() => {
if (showNowInfos && panelInfo.shptmBanrTpNm === 'LIVE') { if (showNowInfos && panelInfo.shptmBanrTpNm === 'LIVE') {
@@ -1329,21 +1309,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
// 최상단 패널이 DetailPanel이고 PlayerPanel에서 진입했는지 확인 // 최상단 패널이 DetailPanel이고 PlayerPanel에서 진입했는지 확인
const isTopPanelDetailFromPlayer = useMemo(() => { const isTopPanelDetailFromPlayer = useMemo(() => {
let result = const result =
topPanel?.name === panel_names.DETAIL_PANEL && topPanel?.name === panel_names.DETAIL_PANEL &&
topPanel?.panelInfo?.launchedFromPlayer === true; topPanel?.panelInfo?.launchedFromPlayer === true;
// MediaPanel이 최상단에 있고 그 아래가 DetailPanel인 경우도 체크
if (!result && topPanel?.name === panel_names.MEDIA_PANEL) {
const prevPanel = panels[panels.length - 2];
if (
prevPanel?.name === panel_names.DETAIL_PANEL &&
prevPanel?.panelInfo?.launchedFromPlayer === true
) {
result = true;
}
}
// 🔍 DetailPanel 상태 변화 로깅 // 🔍 DetailPanel 상태 변화 로깅
if (result) { if (result) {
dlog('🎬 [PlayerPanel] DetailPanel is now on top (from Player)', { dlog('🎬 [PlayerPanel] DetailPanel is now on top (from Player)', {
@@ -1889,7 +1858,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
dlog('[PlayerPanel] Condition 2.5: Removing skipFlag after DOM render'); dlog('[PlayerPanel] Condition 2.5: Removing skipFlag after DOM render');
console.log('[PANEL] PlayerPanel updatePanel - skipModalStyleRecalculation remove');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
@@ -1930,7 +1898,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
scale = width / window.innerWidth; scale = width / window.innerWidth;
setModalScale(scale); setModalScale(scale);
} }
console.log('[PANEL] PlayerPanel updatePanel - modalStyle and scale update');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
@@ -2256,7 +2223,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
); );
Spotlight.focus('playVideoShopNowBox'); Spotlight.focus('playVideoShopNowBox');
} else { } else {
console.log('[PANEL] PlayerPanel updatePanel - handleIndicatorDownClick');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
@@ -2304,7 +2270,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
); );
Spotlight.focus('playVideoShopNowBox'); Spotlight.focus('playVideoShopNowBox');
} else { } else {
console.log('[PANEL] PlayerPanel updatePanel - handleIndicatorUpClick');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.PLAYER_PANEL, name: panel_names.PLAYER_PANEL,
@@ -2424,7 +2389,6 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
const onEnded = useCallback( const onEnded = useCallback(
(e) => { (e) => {
if (panelInfoRef.current.shptmBanrTpNm === 'MEDIA') { if (panelInfoRef.current.shptmBanrTpNm === 'MEDIA') {
console.log('[PANEL] PlayerPanel updatePanel - DETAIL_PANEL video ended');
dispatch( dispatch(
updatePanel({ updatePanel({
name: panel_names.DETAIL_PANEL, name: panel_names.DETAIL_PANEL,

View File

@@ -1,11 +1,5 @@
// src/views/SearchPanel/SearchPanel.new.jsx // src/views/SearchPanel/SearchPanel.new.jsx
import React, { import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
@@ -39,9 +33,7 @@ import {
// showWarningToast, // showWarningToast,
// } from '../../actions/toastActions'; // } from '../../actions/toastActions';
import TBody from '../../components/TBody/TBody'; import TBody from '../../components/TBody/TBody';
import TItemCardNew, { import TItemCardNew, { removeDotAndColon } from '../../components/TItemCard/TItemCard.new';
removeDotAndColon,
} from '../../components/TItemCard/TItemCard.new';
import TPanel from '../../components/TPanel/TPanel'; import TPanel from '../../components/TPanel/TPanel';
import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator'; import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator';
import TVirtualGridList from '../../components/TVirtualGridList/TVirtualGridList'; import TVirtualGridList from '../../components/TVirtualGridList/TVirtualGridList';
@@ -49,22 +41,15 @@ import usePanelHistory from '../../hooks/usePanelHistory/usePanelHistory';
// import VirtualKeyboardContainer from "../../components/TToast/VirtualKeyboardContainer"; // import VirtualKeyboardContainer from "../../components/TToast/VirtualKeyboardContainer";
import usePrevious from '../../hooks/usePrevious'; import usePrevious from '../../hooks/usePrevious';
import { useSearchHistory } from '../../hooks/useSearchHistory'; import { useSearchHistory } from '../../hooks/useSearchHistory';
import { import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../utils/Config';
LOG_CONTEXT_NAME,
LOG_MENU,
LOG_MESSAGE_ID,
panel_names,
} from '../../utils/Config';
import { createDebugHelpers } from '../../utils/debug';
import NoSearchResults from './NoSearchResults/NoSearchResults'; import NoSearchResults from './NoSearchResults/NoSearchResults';
// import NoSearchResults from './NoSearchResults/NoSearchResults'; // import NoSearchResults from './NoSearchResults/NoSearchResults';
import SearchInputOverlay from './SearchInputOverlay'; import SearchInputOverlay from './SearchInputOverlay';
import css from './SearchPanel.new.module.less'; import css from './SearchPanel.new.module.less';
import SearchResultsNew from './SearchResults.new.v2'; import SearchResultsNew from './SearchResults.new.v2';
import TInputSimple, { ICONS, KINDS } from './TInput/TInputSimple'; import TInputSimple, { ICONS, KINDS } from './TInput/TInputSimple';
import VoiceInputOverlay, { import VoiceInputOverlay, { VOICE_MODES } from './VoiceInputOverlay/VoiceInputOverlay';
VOICE_MODES, import { createDebugHelpers } from '../../utils/debug';
} from './VoiceInputOverlay/VoiceInputOverlay';
// 디버그 헬퍼 설정 // 디버그 헬퍼 설정
const DEBUG_MODE = false; const DEBUG_MODE = false;
@@ -90,22 +75,13 @@ export const SEARCH_PANEL_MODES = {
VOICE_RESULT: 'voice_result', // 음성 검색 결과 표시 VOICE_RESULT: 'voice_result', // 음성 검색 결과 표시
}; };
const ContainerBasic = SpotlightContainerDecorator( const ContainerBasic = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
{ enterTo: 'last-focused' },
'div'
);
// 검색 입력 영역 컨테이너 // 검색 입력 영역 컨테이너
const InputContainer = SpotlightContainerDecorator( const InputContainer = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
{ enterTo: 'last-focused' },
'div'
);
// 콘텐츠 섹션 컨테이너 // 콘텐츠 섹션 컨테이너
const SectionContainer = SpotlightContainerDecorator( const SectionContainer = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div');
{ enterTo: 'last-focused' },
'div'
);
// 메모리 누수 방지를 위한 안전한 이미지 컴포넌트 (컴포넌트 외부로 이동) // 메모리 누수 방지를 위한 안전한 이미지 컴포넌트 (컴포넌트 외부로 이동)
const SafeImageComponent = ({ src, alt, className, ...props }) => { const SafeImageComponent = ({ src, alt, className, ...props }) => {
@@ -142,9 +118,7 @@ const SafeImageComponent = ({ src, alt, className, ...props }) => {
}; };
}, []); }, []);
return ( return <img ref={imgRef} src={src} alt={alt} className={className} {...props} />;
<img ref={imgRef} src={src} alt={alt} className={className} {...props} />
);
}; };
const ITEMS_PER_PAGE = 9; const ITEMS_PER_PAGE = 9;
@@ -178,36 +152,22 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// 0hun: 패널 전역 상태 // 0hun: 패널 전역 상태
const panels = useSelector((state) => state.panels.panels); const panels = useSelector((state) => state.panels.panels);
// 0hun: 음성 검색 결과에 대한 전역 상태 // 0hun: 음성 검색 결과에 대한 전역 상태
const shopperHouseData = useSelector( const shopperHouseData = useSelector((state) => state.search.shopperHouseData);
(state) => state.search.shopperHouseData const shopperHouseError = useSelector((state) => state.search.shopperHouseError);
);
const shopperHouseError = useSelector(
(state) => state.search.shopperHouseError
);
// 0hun: 음성 검색 searchId (Redux에서 별도 관리) // 0hun: 음성 검색 searchId (Redux에서 별도 관리)
const shopperHouseSearchId = useSelector( const shopperHouseSearchId = useSelector((state) => state.search.shopperHouseSearchId);
(state) => state.search.shopperHouseSearchId
);
// 0hun: 음성 검색 relativeQueries (Redux에서 별도 관리) // 0hun: 음성 검색 relativeQueries (Redux에서 별도 관리)
const shopperHouseRelativeQueries = useSelector( const shopperHouseRelativeQueries = useSelector(
(state) => state.search.shopperHouseRelativeQueries (state) => state.search.shopperHouseRelativeQueries
); );
// 🔄 이전 shopperHouseData (sortingType 변경 시 사용) // 🔄 이전 shopperHouseData (sortingType 변경 시 사용)
const preShopperHouseData = useSelector( const preShopperHouseData = useSelector((state) => state.search.preShopperHouseData);
(state) => state.search.preShopperHouseData
);
// 0hun: 검색 메인, Hot Picks for you 영역에 대한 전역 상태 값 // 0hun: 검색 메인, Hot Picks for you 영역에 대한 전역 상태 값
const hotPicksForYou = useSelector( const hotPicksForYou = useSelector((state) => state.search.searchMainData.hotPicksForYou);
(state) => state.search.searchMainData.hotPicksForYou
);
// 0hun: 검색 메인, Popular Brands 영역에 대한 전역 상태 값 // 0hun: 검색 메인, Popular Brands 영역에 대한 전역 상태 값
const popularBrands = useSelector( const popularBrands = useSelector((state) => state.search.searchMainData.popularBrands);
(state) => state.search.searchMainData.popularBrands
);
// 0hun: 검색 메인, Top Searchs 영역에 대한 전역 상태 값 // 0hun: 검색 메인, Top Searchs 영역에 대한 전역 상태 값
const topSearchs = useSelector( const topSearchs = useSelector((state) => state.search.searchMainData.topSearchs);
(state) => state.search.searchMainData.topSearchs
);
// jhun: 검색 메인, Today Deals 영역에 대한 전역 상태 값 // jhun: 검색 메인, Today Deals 영역에 대한 전역 상태 값
const tsvInfo = useSelector((state) => state.search.searchMainData.tsvInfo); const tsvInfo = useSelector((state) => state.search.searchMainData.tsvInfo);
@@ -217,9 +177,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// 0hun: 초기 포커스 유무를 나타내는 Boolean 상태 // 0hun: 초기 포커스 유무를 나타내는 Boolean 상태
const [firstSpot, setFirstSpot] = useState(false); const [firstSpot, setFirstSpot] = useState(false);
// 0hun: 검색어 상태 // 0hun: 검색어 상태
const [searchQuery, setSearchQuery] = useState( const [searchQuery, setSearchQuery] = useState(panelInfo.searchVal ? panelInfo.searchVal : null);
panelInfo.searchVal ? panelInfo.searchVal : null
);
// 0hun: 검색 컨테이너 포커스 position 상태 값 // 0hun: 검색 컨테이너 포커스 position 상태 값
const [position, setPosition] = useState(null); const [position, setPosition] = useState(null);
// 0hun: 가상 키보드 Display 유무 Boolean 값 (주석: 현재 VirtualKeyboardContainer가 비활성화됨) // 0hun: 가상 키보드 Display 유무 Boolean 값 (주석: 현재 VirtualKeyboardContainer가 비활성화됨)
@@ -233,17 +191,14 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// ✨ [Phase 3] TInput의 입력 모드 상태 제거 (더 이상 InputField가 없으므로 불필요) // ✨ [Phase 3] TInput의 입력 모드 상태 제거 (더 이상 InputField가 없으므로 불필요)
// const [isInputModeActive, setIsInputModeActive] = useState(false); // const [isInputModeActive, setIsInputModeActive] = useState(false);
// 0hun: 현재 포커스된 container의 spotlightId를 관리하는 상태 값 // 0hun: 현재 포커스된 container의 spotlightId를 관리하는 상태 값
const [focusedContainerId, setFocusedContainerId] = useState( const [focusedContainerId, setFocusedContainerId] = useState(panelInfo?.focusedContainerId);
panelInfo?.focusedContainerId
);
// ✨ [Phase 1] SearchPanel의 현재 모드 상태 (VoiceInputOverlay의 VOICE_MODES와 동일한 개념) // ✨ [Phase 1] SearchPanel의 현재 모드 상태 (VoiceInputOverlay의 VOICE_MODES와 동일한 개념)
const [currentMode, setCurrentMode] = useState(SEARCH_PANEL_MODES.INITIAL); const [currentMode, setCurrentMode] = useState(SEARCH_PANEL_MODES.INITIAL);
const [isShopperHousePending, setIsShopperHousePending] = useState(false); const [isShopperHousePending, setIsShopperHousePending] = useState(false);
const [voiceOverlayMode, setVoiceOverlayMode] = useState(VOICE_MODES.PROMPT); const [voiceOverlayMode, setVoiceOverlayMode] = useState(VOICE_MODES.PROMPT);
const [voiceOverlayResponseText, setVoiceOverlayResponseText] = useState(''); const [voiceOverlayResponseText, setVoiceOverlayResponseText] = useState('');
const [isVoiceOverlayBubbleSearch, setIsVoiceOverlayBubbleSearch] = const [isVoiceOverlayBubbleSearch, setIsVoiceOverlayBubbleSearch] = useState(false);
useState(false);
const [shouldFocusVoiceResult, setShouldFocusVoiceResult] = useState(false); const [shouldFocusVoiceResult, setShouldFocusVoiceResult] = useState(false);
// 🎯 HowAboutThese 포커스 관리 - 검색 입력 영역 포커스 감지용 상태 // 🎯 HowAboutThese 포커스 관리 - 검색 입력 영역 포커스 감지용 상태
@@ -330,16 +285,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
const unifiedFocusTimerRef = useRef(null); const unifiedFocusTimerRef = useRef(null);
// ShopperHouse 에러 팝업 상태 가져오기 // ShopperHouse 에러 팝업 상태 가져오기
const shopperHouseErrorPopup = useSelector( const shopperHouseErrorPopup = useSelector((state) => state.search.shopperHouseErrorPopup);
(state) => state.search.shopperHouseErrorPopup
);
// API 실패 시 fallback reference 초기화 // API 실패 시 fallback reference 초기화
useEffect(() => { useEffect(() => {
if ( if (shopperHouseErrorPopup?.visible && shopperHouseErrorPopup?.type === 'API_FAILURE') {
shopperHouseErrorPopup?.visible &&
shopperHouseErrorPopup?.type === 'API_FAILURE'
) {
dlog('[SearchPanel] 🧹 API 실패 감지 - fallbackShopperHouseData 초기화'); dlog('[SearchPanel] 🧹 API 실패 감지 - fallbackShopperHouseData 초기화');
shopperHouseDataRef.current = null; shopperHouseDataRef.current = null;
} }
@@ -357,12 +307,8 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
/** /**
* useSearchHistory Hook 적용 * useSearchHistory Hook 적용
*/ */
const { const { normalSearches, addNormalSearch, refreshHistory, executeSearchFromHistory } =
normalSearches, useSearchHistory();
addNormalSearch,
refreshHistory,
executeSearchFromHistory,
} = useSearchHistory();
/** /**
* 🎯 [DetailPanel 복귀 감지] usePanelHistory Hook 적용 * 🎯 [DetailPanel 복귀 감지] usePanelHistory Hook 적용
@@ -476,9 +422,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// ✨ [Phase 4] Enter/OK 키 처리 - SearchInputOverlay 표시 // ✨ [Phase 4] Enter/OK 키 처리 - SearchInputOverlay 표시
if (e.key === 'Enter' || e.keyCode === 13) { if (e.key === 'Enter' || e.keyCode === 13) {
dlog( dlog('[DEBUG] [SearchPanel] TInputSimple에서 Enter/OK 키 감지 → SearchInputOverlay 오픈');
'[DEBUG] [SearchPanel] TInputSimple에서 Enter/OK 키 감지 → SearchInputOverlay 오픈'
);
e.preventDefault(); e.preventDefault();
// ✨ [Phase 6] SearchInputOverlay 오픈 후 자동으로 입력 준비 완료 // ✨ [Phase 6] SearchInputOverlay 오픈 후 자동으로 입력 준비 완료
@@ -506,11 +450,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
]; ];
if (arrowKeys.includes(e.key)) { if (arrowKeys.includes(e.key)) {
// 입력 필드가 비어있고 왼쪽 화살표인 경우에만 방지 // 입력 필드가 비어있고 왼쪽 화살표인 경우에만 방지
if ( if (position === 0 && (e.key === 'Left' || e.key === 'ArrowLeft') && !searchQuery) {
position === 0 &&
(e.key === 'Left' || e.key === 'ArrowLeft') &&
!searchQuery
) {
e.preventDefault(); e.preventDefault();
return; return;
} }
@@ -521,9 +461,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// DOM 쿼리 최적화: 캐싱된 input element 사용 // DOM 쿼리 최적화: 캐싱된 input element 사용
const input = const input =
inputElementRef.current || inputElementRef.current ||
document.querySelector( document.querySelector(`[data-spotlight-id="input-field-box"] > input`);
`[data-spotlight-id="input-field-box"] > input`
);
if (input) { if (input) {
inputElementRef.current = input; // 캐싱 inputElementRef.current = input; // 캐싱
if (position === input.value.length) { if (position === input.value.length) {
@@ -720,9 +658,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
'[DEBUG]-VOICE_RESULT: Clearing ShopperHouse data (searchId will be preserved for 2nd search)' '[DEBUG]-VOICE_RESULT: Clearing ShopperHouse data (searchId will be preserved for 2nd search)'
); );
dlog('[VoiceInput]-SearchPanel-onCancel-VOICE_RESULT'); dlog('[VoiceInput]-SearchPanel-onCancel-VOICE_RESULT');
dlog( dlog('[VoiceInput] 🧹 VOICE_RESULT 모드에서 ESC 누름 - clearShopperHouseData 호출');
'[VoiceInput] 🧹 VOICE_RESULT 모드에서 ESC 누름 - clearShopperHouseData 호출'
);
} }
// 🎯 [포커스 로직 통합] 포커스는 상태 변경에 의해 자동으로 처리됨 // 🎯 [포커스 로직 통합] 포커스는 상태 변경에 의해 자동으로 처리됨
setIsShopperHousePending(false); setIsShopperHousePending(false);
@@ -880,9 +816,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
if (isReturningFromDetailPanel) { if (isReturningFromDetailPanel) {
const currentSpot = currentPanel?.panelInfo?.currentSpot; const currentSpot = currentPanel?.panelInfo?.currentSpot;
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[Focus] usePanelHistory로 DetailPanel 복귀 감지 - 이전 상품으로 포커스 이동');
'[Focus] usePanelHistory로 DetailPanel 복귀 감지 - 이전 상품으로 포커스 이동'
);
dlog('[FOCUS] 🎯 Scenario: DETAIL_PANEL_RETURN (usePanelHistory)', { dlog('[FOCUS] 🎯 Scenario: DETAIL_PANEL_RETURN (usePanelHistory)', {
currentSpot, currentSpot,
mode: currentMode, mode: currentMode,
@@ -926,9 +860,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
) { ) {
const usedHistoryOnTop = currentIsOnTop && isOnTopChange?.becameOnTop; const usedHistoryOnTop = currentIsOnTop && isOnTopChange?.becameOnTop;
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[Focus] 개선된 방식으로 DetailPanel 복귀 감지 - 이전 상품으로 포커스 이동');
'[Focus] 개선된 방식으로 DetailPanel 복귀 감지 - 이전 상품으로 포커스 이동'
);
dlog('[FOCUS] 🎯 Scenario: DETAIL_PANEL_RETURN (improved fallback)', { dlog('[FOCUS] 🎯 Scenario: DETAIL_PANEL_RETURN (improved fallback)', {
currentSpot: panelInfo.currentSpot, currentSpot: panelInfo.currentSpot,
mode: currentMode, mode: currentMode,
@@ -996,8 +928,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
prevMode: currentModeRef.current, prevMode: currentModeRef.current,
nextMode: currentMode, nextMode: currentMode,
isOnTopChanged: isOnTop !== isOnTopRef.current, isOnTopChanged: isOnTop !== isOnTopRef.current,
modeChanged: modeChanged: currentModeRef.current !== SEARCH_PANEL_MODES.VOICE_RESULT,
currentModeRef.current !== SEARCH_PANEL_MODES.VOICE_RESULT,
dataChanged: shopperHouseDataRef.current !== shopperHouseData, dataChanged: shopperHouseDataRef.current !== shopperHouseData,
}); });
} }
@@ -1015,9 +946,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// 이렇게 하면 VOICE_OVERLAY_CLOSED 시나리오에서 TInput으로 가는 것을 방지 // 이렇게 하면 VOICE_OVERLAY_CLOSED 시나리오에서 TInput으로 가는 것을 방지
if (shopperHouseData && currentMode === SEARCH_PANEL_MODES.VOICE_RESULT) { if (shopperHouseData && currentMode === SEARCH_PANEL_MODES.VOICE_RESULT) {
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[FOCUS] 🔄 VOICE_OVERLAY_CLOSED + new data → NEW_SEARCH_LOADED 우선 처리');
'[FOCUS] 🔄 VOICE_OVERLAY_CLOSED + new data → NEW_SEARCH_LOADED 우선 처리'
);
} }
return 'NEW_SEARCH_LOADED'; return 'NEW_SEARCH_LOADED';
} }
@@ -1080,10 +1009,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
let currentSpot = null; let currentSpot = null;
// 1. usePanelHistory의 currentSpot 우선 사용 // 1. usePanelHistory의 currentSpot 우선 사용
if ( if (isReturningFromDetailPanel && currentPanel?.panelInfo?.currentSpot) {
isReturningFromDetailPanel &&
currentPanel?.panelInfo?.currentSpot
) {
currentSpot = currentPanel.panelInfo.currentSpot; currentSpot = currentPanel.panelInfo.currentSpot;
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog('[FOCUS] 🎯 usePanelHistory currentSpot 사용:', currentSpot); dlog('[FOCUS] 🎯 usePanelHistory currentSpot 사용:', currentSpot);
@@ -1093,19 +1019,13 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
else if (panelInfo?.currentSpot) { else if (panelInfo?.currentSpot) {
currentSpot = panelInfo.currentSpot; currentSpot = panelInfo.currentSpot;
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[FOCUS] 🔄 fallback으로 panelInfo.currentSpot 사용:', currentSpot);
'[FOCUS] 🔄 fallback으로 panelInfo.currentSpot 사용:',
currentSpot
);
} }
} }
if (currentSpot && currentSpot.startsWith('searchItemContents')) { if (currentSpot && currentSpot.startsWith('searchItemContents')) {
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[FOCUS] 🎯 DETAIL_PANEL_RETURN: 이전 상품으로 포커스 복원:', currentSpot);
'[FOCUS] 🎯 DETAIL_PANEL_RETURN: 이전 상품으로 포커스 복원:',
currentSpot
);
} }
return currentSpot; return currentSpot;
} else { } else {
@@ -1146,9 +1066,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// SearchInputOverlay에서 검색을 실행하면 isSearchOverlayVisible이 false로 설정되고 // SearchInputOverlay에서 검색을 실행하면 isSearchOverlayVisible이 false로 설정되고
// 동시에 검색 결과에 따라 모드가 변경되므로, 이 케이스는 검색어 선택 후 닫을 때만 발생 // 동시에 검색 결과에 따라 모드가 변경되므로, 이 케이스는 검색어 선택 후 닫을 때만 발생
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED - TInputSimple으로 포커스');
'[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED - TInputSimple으로 포커스'
);
} }
return SPOTLIGHT_IDS.SEARCH_INPUT_BOX; return SPOTLIGHT_IDS.SEARCH_INPUT_BOX;
@@ -1372,27 +1290,17 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
{...rest} {...rest}
> >
<div className={css.productImageWrapper}> <div className={css.productImageWrapper}>
<SafeImage <SafeImage src={bgImgPath} alt={curationNm} className={css.productImage} />
src={bgImgPath}
alt={curationNm}
className={css.productImage}
/>
</div> </div>
<div className={css.productInfo}> <div className={css.productInfo}>
{showBrandLogo && ( {showBrandLogo && (
<div className={css.productBrandWrapper}> <div className={css.productBrandWrapper}>
<SafeImage <SafeImage src={patncLogoPath} alt={patncNm} className={css.brandLogo} />
src={patncLogoPath}
alt={patncNm}
className={css.brandLogo}
/>
</div> </div>
)} )}
<div className={css.productDetails}> <div className={css.productDetails}>
{showBrandName && <div className={css.brandName}>{patncNm}</div>} {showBrandName && <div className={css.brandName}>{patncNm}</div>}
{showProductTitle && ( {showProductTitle && <div className={css.productTitle}>{curationNm}</div>}
<div className={css.productTitle}>{curationNm}</div>
)}
</div> </div>
</div> </div>
</SpottableProduct> </SpottableProduct>
@@ -1415,8 +1323,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
const renderTsvItem = useCallback( const renderTsvItem = useCallback(
({ index, ...rest }) => { ({ index, ...rest }) => {
const { offerInfo, prdtId, imgUrl, patnrId, prdtNm, priceInfo } = const { offerInfo, prdtId, imgUrl, patnrId, prdtNm, priceInfo } = tsvInfo[index];
tsvInfo[index];
return ( return (
<TItemCardNew <TItemCardNew
@@ -1429,9 +1336,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
priceInfo={priceInfo} priceInfo={priceInfo}
productId={prdtId} productId={prdtId}
productName={prdtNm} productName={prdtNm}
spotlightId={ spotlightId={'searchMain-tsvInfo-spotlightId-' + removeDotAndColon(prdtId)}
'searchMain-tsvInfo-spotlightId-' + removeDotAndColon(prdtId)
}
{...rest} {...rest}
/> />
); );
@@ -1698,13 +1603,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// 우선순위 2: 음성 검색 결과가 있으면 VOICE_RESULT 모드 // 우선순위 2: 음성 검색 결과가 있으면 VOICE_RESULT 모드
else if (shopperHouseData || isShopperHousePending) { else if (shopperHouseData || isShopperHousePending) {
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[DEBUG]-MODE: shopperHouseData EXISTS or pending VOICE_RESULT', {
'[DEBUG]-MODE: shopperHouseData EXISTS or pending VOICE_RESULT', hasData: !!shopperHouseData,
{ isPending: isShopperHousePending,
hasData: !!shopperHouseData, });
isPending: isShopperHousePending,
}
);
} }
nextMode = SEARCH_PANEL_MODES.VOICE_RESULT; nextMode = SEARCH_PANEL_MODES.VOICE_RESULT;
} }
@@ -1738,23 +1640,20 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// 모드가 변경되었을 때만 업데이트 // 모드가 변경되었을 때만 업데이트
if (nextMode !== currentMode) { if (nextMode !== currentMode) {
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog(`[DEBUG]-VOICE_RESULT 🔀 Mode changed: ${currentMode} → ${nextMode}`, {
`[DEBUG]-VOICE_RESULT 🔀 Mode changed: ${currentMode} → ${nextMode}`, isVoiceOverlayVisible,
{ shopperHouseData: !!shopperHouseData,
isVoiceOverlayVisible, isShopperHousePending,
shopperHouseData: !!shopperHouseData, searchPerformed,
isShopperHousePending, searchQuery,
searchPerformed, hasSearchResults: !!(
searchQuery, searchDatas?.theme?.length > 0 ||
hasSearchResults: !!( searchDatas?.item?.length > 0 ||
searchDatas?.theme?.length > 0 || searchDatas?.show?.length > 0
searchDatas?.item?.length > 0 || ),
searchDatas?.show?.length > 0 isSearchOverlayVisible,
), inputFocus,
isSearchOverlayVisible, });
inputFocus,
}
);
} }
setCurrentMode(nextMode); setCurrentMode(nextMode);
} else { } else {
@@ -1880,14 +1779,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// NEW_SEARCH_LOADED: 음성 검색 결과 로드 시 VoiceInputOverlay와 충돌 방지 // NEW_SEARCH_LOADED: 음성 검색 결과 로드 시 VoiceInputOverlay와 충돌 방지
// 다른 시나리오에서는 기존과 같은 지연 시간 (100ms) // 다른 시나리오에서는 기존과 같은 지연 시간 (100ms)
const focusDelay = const focusDelay =
scenario === 'DETAIL_PANEL_RETURN' || scenario === 'NEW_SEARCH_LOADED' scenario === 'DETAIL_PANEL_RETURN' || scenario === 'NEW_SEARCH_LOADED' ? 50 : 100;
? 50
: 100;
unifiedFocusTimerRef.current = setTimeout(() => { unifiedFocusTimerRef.current = setTimeout(() => {
const targetElement = document.querySelector( const targetElement = document.querySelector(`[data-spotlight-id="${targetId}"]`);
`[data-spotlight-id="${targetId}"]`
);
if (targetElement || targetId === SPOTLIGHT_IDS.SEARCH_INPUT_BOX) { if (targetElement || targetId === SPOTLIGHT_IDS.SEARCH_INPUT_BOX) {
Spotlight.focus(targetId); Spotlight.focus(targetId);
@@ -1910,14 +1805,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
} }
// 🎯 DETAIL_PANEL_RETURN에서 요소를 찾지 못하면 fallback으로 첫 번째 상품 시도 // 🎯 DETAIL_PANEL_RETURN에서 요소를 찾지 못하면 fallback으로 첫 번째 상품 시도
if ( if (scenario === 'DETAIL_PANEL_RETURN' && targetId.startsWith('searchItemContents')) {
scenario === 'DETAIL_PANEL_RETURN' &&
targetId.startsWith('searchItemContents')
) {
const fallbackTarget = 'searchItemContents0'; const fallbackTarget = 'searchItemContents0';
const fallbackElement = document.querySelector( const fallbackElement = document.querySelector(`[data-spotlight-id="${fallbackTarget}"]`);
`[data-spotlight-id="${fallbackTarget}"]`
);
if (fallbackElement) { if (fallbackElement) {
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog(
@@ -1935,15 +1825,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// 🎯 [NEW_SEARCH_LOADED] 1초 후 다시 첫 번째 아이템으로 포커스 이동 // 🎯 [NEW_SEARCH_LOADED] 1초 후 다시 첫 번째 아이템으로 포커스 이동
// TInputSimple과 Mic Icon의 포커스 충돌 해결을 위해 // TInputSimple과 Mic Icon의 포커스 충돌 해결을 위해
if ( if (scenario === 'NEW_SEARCH_LOADED' && targetId === 'searchItemContents0') {
scenario === 'NEW_SEARCH_LOADED' &&
targetId === 'searchItemContents0'
) {
setTimeout(() => { setTimeout(() => {
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[FOCUS] 🔄 NEW_SEARCH_LOADED: 1 번째 상품으로 다시 포커스 이동');
'[FOCUS] 🔄 NEW_SEARCH_LOADED: 1 번째 상품으로 다시 포커스 이동'
);
} }
Spotlight.focus('searchItemContents0'); Spotlight.focus('searchItemContents0');
}, 500); // 0.5초 후 }, 500); // 0.5초 후
@@ -1981,13 +1866,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
isVoiceOverlayVisibleRef.current = isVoiceOverlayVisible; isVoiceOverlayVisibleRef.current = isVoiceOverlayVisible;
isSearchOverlayVisibleRef.current = isSearchOverlayVisible; isSearchOverlayVisibleRef.current = isSearchOverlayVisible;
currentModeRef.current = currentMode; currentModeRef.current = currentMode;
}, [ }, [shopperHouseData, searchDatas, isVoiceOverlayVisible, isSearchOverlayVisible, currentMode]);
shopperHouseData,
searchDatas,
isVoiceOverlayVisible,
isSearchOverlayVisible,
currentMode,
]);
/** /**
* 🎯 SearchInputOverlay 닫힘 후 포커스 관리 * 🎯 SearchInputOverlay 닫힘 후 포커스 관리
@@ -2010,13 +1889,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
}); });
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[FOCUS] 🎯 SearchInputOverlay 닫힘 포커스 관리 useEffect 실행', {
'[FOCUS] 🎯 SearchInputOverlay 닫힘 포커스 관리 useEffect 실행', shouldFocusSearchInput,
{ timestamp: new Date().toISOString(),
shouldFocusSearchInput, });
timestamp: new Date().toISOString(),
}
);
} }
// 500ms 후 TInputSimple에 포커스 이동 // 500ms 후 TInputSimple에 포커스 이동
@@ -2027,13 +1903,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
}); });
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[FOCUS] 500ms 타이머 콜백 실행 - TInputSimple으로 포커스 이동', {
'[FOCUS] 500ms 타이머 콜백 실행 - TInputSimple으로 포커스 이동', targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX,
{ timestamp: new Date().toISOString(),
targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX, });
timestamp: new Date().toISOString(),
}
);
} }
dlog('[DEBUG] Spotlight.focus() 호출 직전', { dlog('[DEBUG] Spotlight.focus() 호출 직전', {
@@ -2077,12 +1950,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
}); });
if (focusTimer) { if (focusTimer) {
if (DEBUG_MODE) { if (DEBUG_MODE) {
dlog( dlog('[FOCUS] 🧹 SearchInputOverlay 포커스 관리 useEffect cleanup - 타이머 정리', {
'[FOCUS] 🧹 SearchInputOverlay 포커스 관리 useEffect cleanup - 타이머 정리', timestamp: new Date().toISOString(),
{ });
timestamp: new Date().toISOString(),
}
);
} }
clearTimeout(focusTimer); clearTimeout(focusTimer);
} }
@@ -2183,18 +2053,12 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
}, [currentMode, isOnTop, refreshHistory]); }, [currentMode, isOnTop, refreshHistory]);
return ( return (
<TPanel <TPanel className={css.container} handleCancel={onCancel} spotlightId={spotlightId}>
className={css.container}
handleCancel={onCancel}
spotlightId={spotlightId}
>
{/* ✨ [Phase 2] spotlightDisabled를 currentMode로 제어 */} {/* ✨ [Phase 2] spotlightDisabled를 currentMode로 제어 */}
<TBody <TBody
className={css.tBody} className={css.tBody}
scrollable scrollable
spotlightDisabled={ spotlightDisabled={!isOnTop || currentMode === SEARCH_PANEL_MODES.SEARCH_INPUT}
!isOnTop || currentMode === SEARCH_PANEL_MODES.SEARCH_INPUT
}
> >
<ContainerBasic> <ContainerBasic>
{isOnTop && ( {isOnTop && (
@@ -2214,8 +2078,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
className={classNames( className={classNames(
css.inputContainer, css.inputContainer,
inputFocus === true && css.inputFocus, inputFocus === true && css.inputFocus,
searchDatas && searchDatas && css.searchValue /* 이건 결과값 있을때만. 조건 추가필요 */,
css.searchValue /* 이건 결과값 있을때만. 조건 추가필요 */,
(currentMode === SEARCH_PANEL_MODES.VOICE_INPUT || (currentMode === SEARCH_PANEL_MODES.VOICE_INPUT ||
currentMode === SEARCH_PANEL_MODES.INPUT_FOCUSED) && currentMode === SEARCH_PANEL_MODES.INPUT_FOCUSED) &&
css.hidden css.hidden
@@ -2266,7 +2129,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
placeholder="Search products or brands" placeholder="Search products or brands"
/> />
</div> </div>
{/* <SpottableMicButton <SpottableMicButton
className={css.microphoneButton} className={css.microphoneButton}
onClick={onClickMic} onClick={onClickMic}
onFocus={onFocusMic} onFocus={onFocusMic}
@@ -2285,7 +2148,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
<div className={css.microphoneCircle}> <div className={css.microphoneCircle}>
<SafeImage src={micIcon} alt="Microphone" className={css.microphoneIcon} /> <SafeImage src={micIcon} alt="Microphone" className={css.microphoneIcon} />
</div> </div>
</SpottableMicButton> */} </SpottableMicButton>
</div> </div>
</InputContainer> </InputContainer>

View File

@@ -291,7 +291,7 @@ const TrendingNowPanel = ({ panelInfo, spotlightId, isOnTop, ...rest }) => {
return ( return (
<div className={css.trendingNowWrap}> <div className={css.trendingNowWrap}>
{isOnTop && selectedIndex >= 1 && showButton && ( {selectedIndex >= 1 && showButton && (
<TButton <TButton
className={classNames(css.button, css.prevBtn)} className={classNames(css.button, css.prevBtn)}
onClick={handleIndicatorClick("prev")} onClick={handleIndicatorClick("prev")}
@@ -411,7 +411,7 @@ const TrendingNowPanel = ({ panelInfo, spotlightId, isOnTop, ...rest }) => {
</TVerticalPagenator> </TVerticalPagenator>
</TBody> </TBody>
</TPanel> </TPanel>
{isOnTop && topInfos && {topInfos &&
topInfos?.length > 0 && topInfos?.length > 0 &&
selectedIndex !== topInfos?.length - 1 && selectedIndex !== topInfos?.length - 1 &&
showButton && ( showButton && (