[251025] feat(views): Fix SearchPanel focus restoration
🕐 커밋 시간: 2025. 10. 25. 10:52:35 Implement proper focus restoration when returning from DetailPanel to SearchPanel. Added usePanelHistory-based detection for panel transitions and enhanced isOnTop calculation using MainView's panel stack logic. Created panelUtils utility functions for accurate panel state management and improved spotlight ID handling in ItemCard component for better focus tracking across panel navigation. 📊 변경 통계: • 총 파일: 7개 • 추가: +307줄 • 삭제: -61줄 📁 추가된 파일: + com.twin.app.shoptime/src/utils/panelUtils.js 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/panelHistoryActions.js ~ com.twin.app.shoptime/src/hooks/usePanelHistory/usePanelHistory.js ~ com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js ~ com.twin.app.shoptime/src/reducers/panelHistoryReducer.js ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • 공통 유틸리티 함수 최적화 • 대규모 기능 개발 • 모듈 구조 개선
This commit is contained in:
@@ -8,6 +8,10 @@
|
||||
|
||||
import { types } from '../actions/actionTypes';
|
||||
import { enqueuePanelHistory, clearPanelHistory } from '../actions/panelHistoryActions';
|
||||
import { calculateIsPanelOnTop } from '../utils/panelUtils'; // 🎯 isOnTop 유틸리티 함수 import
|
||||
|
||||
// DEBUG_MODE - true인 경우에만 로그 출력
|
||||
const DEBUG_MODE = true;
|
||||
|
||||
/**
|
||||
* Panel history middleware
|
||||
@@ -18,7 +22,7 @@ import { enqueuePanelHistory, clearPanelHistory } from '../actions/panelHistoryA
|
||||
*/
|
||||
export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
// 모든 PANEL 관련 액션 로깅
|
||||
if (action.type && (
|
||||
if (DEBUG_MODE && action.type && (
|
||||
action.type.includes('PANEL') ||
|
||||
action.type === 'CLEAR_PANEL_HISTORY'
|
||||
)) {
|
||||
@@ -44,7 +48,7 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
|
||||
// 임시: CLEAR_PANEL_HISTORY 무력화
|
||||
if (action.type === 'CLEAR_PANEL_HISTORY') {
|
||||
console.log('[PANEL DEBUG] CLEAR_PANEL_HISTORY BLOCKED!');
|
||||
if (DEBUG_MODE) console.log('[PANEL DEBUG] CLEAR_PANEL_HISTORY BLOCKED!');
|
||||
return action; // 액션을 전달하지 않음
|
||||
}
|
||||
|
||||
@@ -55,6 +59,12 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
const state = store.getState();
|
||||
const panels = state.panels?.panels || [];
|
||||
|
||||
// 🎯 [isOnTop 계산] 유틸리티 함수 사용 (MainView 로직과 정확히 일치)
|
||||
// calculateIsPanelOnTop 함수는 MainView의 renderTopPanel 로직을 기반으로 정확한 isOnTop 상태 계산
|
||||
const calculateIsOnTop = (targetPanelName) => {
|
||||
return calculateIsPanelOnTop(panels, targetPanelName);
|
||||
};
|
||||
|
||||
try {
|
||||
switch (action.type) {
|
||||
// PUSH_PANEL: 새 panel 추가
|
||||
@@ -64,14 +74,17 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
|
||||
if (panelName) {
|
||||
const isGNB = isGNBCall();
|
||||
console.log('[PANEL] PUSH_PANEL:', { panelName, panelInfo, isGNB, timestamp: new Date().toISOString() });
|
||||
store.dispatch(enqueuePanelHistory(panelName, panelInfo, 'PUSH', new Date().toISOString(), isGNB, false));
|
||||
const isOnTop = calculateIsOnTop(panelName); // 🎯 isOnTop 계산
|
||||
if (DEBUG_MODE) console.log('[PANEL] PUSH_PANEL:', { panelName, panelInfo, isGNB, isOnTop, timestamp: new Date().toISOString() });
|
||||
store.dispatch(enqueuePanelHistory(panelName, panelInfo, 'PUSH', new Date().toISOString(), isGNB, false, isOnTop));
|
||||
|
||||
// PanelHistory 상태 로그 (state 업데이트 후)
|
||||
const logPanelHistoryAfter = () => {
|
||||
const stateAfter = store.getState();
|
||||
const panelHistoryAfter = stateAfter.panelHistory;
|
||||
console.log('[PANEL_HISTORY] After PUSH_PANEL:', panelHistoryAfter);
|
||||
if (DEBUG_MODE) {
|
||||
const stateAfter = store.getState();
|
||||
const panelHistoryAfter = stateAfter.panelHistory;
|
||||
console.log('[PANEL_HISTORY] After PUSH_PANEL:', panelHistoryAfter);
|
||||
}
|
||||
};
|
||||
|
||||
// state 업데이트가 완료된 후 로그
|
||||
@@ -88,14 +101,17 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
const topPanel = panels[panels.length - 1];
|
||||
if (topPanel && topPanel.name) {
|
||||
const isGNB = isGNBCall();
|
||||
console.log('[PANEL] POP_PANEL:', { panelName: topPanel.name, panelInfo: topPanel.panelInfo || {}, isGNB, timestamp: new Date().toISOString() });
|
||||
store.dispatch(enqueuePanelHistory(topPanel.name, topPanel.panelInfo || {}, 'POP', new Date().toISOString(), isGNB, false));
|
||||
const isOnTop = calculateIsOnTop(topPanel.name); // 🎯 isOnTop 계산
|
||||
if (DEBUG_MODE) console.log('[PANEL] POP_PANEL:', { panelName: topPanel.name, panelInfo: topPanel.panelInfo || {}, isGNB, isOnTop, timestamp: new Date().toISOString() });
|
||||
store.dispatch(enqueuePanelHistory(topPanel.name, topPanel.panelInfo || {}, 'POP', new Date().toISOString(), isGNB, false, isOnTop));
|
||||
|
||||
// PanelHistory 상태 로그 (state 업데이트 후)
|
||||
const logPanelHistoryAfter = () => {
|
||||
const stateAfter = store.getState();
|
||||
const panelHistoryAfter = stateAfter.panelHistory;
|
||||
console.log('[PANEL_HISTORY] After POP_PANEL:', panelHistoryAfter);
|
||||
if (DEBUG_MODE) {
|
||||
const stateAfter = store.getState();
|
||||
const panelHistoryAfter = stateAfter.panelHistory;
|
||||
console.log('[PANEL_HISTORY] After POP_PANEL:', panelHistoryAfter);
|
||||
}
|
||||
};
|
||||
|
||||
// state 업데이트가 완료된 후 로그
|
||||
@@ -112,14 +128,17 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
|
||||
if (panelName) {
|
||||
const isGNB = isGNBCall();
|
||||
console.log('[PANEL] UPDATE_PANEL:', { panelName, panelInfo, isGNB, timestamp: new Date().toISOString() });
|
||||
store.dispatch(enqueuePanelHistory(panelName, panelInfo, 'UPDATE', new Date().toISOString(), isGNB, false));
|
||||
const isOnTop = calculateIsOnTop(panelName); // 🎯 isOnTop 계산
|
||||
if (DEBUG_MODE) console.log('[PANEL] UPDATE_PANEL:', { panelName, panelInfo, isGNB, isOnTop, timestamp: new Date().toISOString() });
|
||||
store.dispatch(enqueuePanelHistory(panelName, panelInfo, 'UPDATE', new Date().toISOString(), isGNB, false, isOnTop));
|
||||
|
||||
// PanelHistory 상태 로그 (state 업데이트 후)
|
||||
const logPanelHistoryAfter = () => {
|
||||
const stateAfter = store.getState();
|
||||
const panelHistoryAfter = stateAfter.panelHistory;
|
||||
console.log('[PANEL_HISTORY] After UPDATE_PANEL:', panelHistoryAfter);
|
||||
if (DEBUG_MODE) {
|
||||
const stateAfter = store.getState();
|
||||
const panelHistoryAfter = stateAfter.panelHistory;
|
||||
console.log('[PANEL_HISTORY] After UPDATE_PANEL:', panelHistoryAfter);
|
||||
}
|
||||
};
|
||||
|
||||
// state 업데이트가 완료된 후 로그
|
||||
@@ -131,11 +150,11 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
|
||||
// RESET_PANELS: GNB 네비게이션 또는 완전 초기화
|
||||
case types.RESET_PANELS: {
|
||||
console.log('[PANEL] RESET_PANELS:', {
|
||||
if (DEBUG_MODE) console.log('[PANEL] RESET_PANELS:', {
|
||||
payload: action.payload,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory);
|
||||
if (DEBUG_MODE) console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory);
|
||||
|
||||
// 모든 RESET_PANELS를 기록
|
||||
const isGNB = isGNBCall();
|
||||
@@ -144,7 +163,8 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
// payload가 있는 경우 (GNB 탭, 패널 내 네비게이션 등)
|
||||
const firstPanel = action.payload[0];
|
||||
if (firstPanel && firstPanel.name) {
|
||||
console.log('[PANEL_DEBUG] RESET_PANELS to:', firstPanel.name, { isGNB, fromResetPanel: true });
|
||||
const isOnTop = calculateIsOnTop(firstPanel.name); // 🎯 isOnTop 계산
|
||||
if (DEBUG_MODE) console.log('[PANEL_DEBUG] RESET_PANELS to:', firstPanel.name, { isGNB, isOnTop, fromResetPanel: true });
|
||||
// RESET 이동을 히스토리에 기록
|
||||
store.dispatch(enqueuePanelHistory(
|
||||
firstPanel.name,
|
||||
@@ -152,31 +172,36 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
'RESET',
|
||||
new Date().toISOString(),
|
||||
isGNB, // TabLayout/TIconButton이면 true
|
||||
true // fromResetPanel: 항상 true
|
||||
true, // fromResetPanel: 항상 true
|
||||
isOnTop // 🎯 isOnTop 정보 추가
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// 완전 초기화 (payload가 없는 경우 - HomePanel, 앱 초기화 등)
|
||||
console.log('[PANEL_DEBUG] Complete panel history reset (payload empty)', { isGNB, fromResetPanel: true });
|
||||
if (DEBUG_MODE) console.log('[PANEL_DEBUG] Complete panel history reset (payload empty)', { isGNB, fromResetPanel: true });
|
||||
store.dispatch(clearPanelHistory());
|
||||
|
||||
// HomePanel 초기화 기록 (앱 시작 시)
|
||||
console.log('[PANEL_DEBUG] Recording initial HomePanel');
|
||||
if (DEBUG_MODE) console.log('[PANEL_DEBUG] Recording initial HomePanel');
|
||||
const isOnTop = calculateIsOnTop('homepanel'); // 🎯 isOnTop 계산
|
||||
store.dispatch(enqueuePanelHistory(
|
||||
'homepanel',
|
||||
{},
|
||||
'APP_INITIALIZE',
|
||||
new Date().toISOString(),
|
||||
isGNB, // TIconButton Home 버튼이면 true
|
||||
true // fromResetPanel: true
|
||||
true, // fromResetPanel: true
|
||||
isOnTop // 🎯 isOnTop 정보 추가
|
||||
));
|
||||
}
|
||||
|
||||
// PanelHistory 상태 로그 (초기화 후)
|
||||
const logPanelHistoryAfter = () => {
|
||||
const stateAfter = store.getState();
|
||||
const panelHistoryAfter = stateAfter.panelHistory;
|
||||
console.log('[PANEL_HISTORY] After RESET_PANELS:', panelHistoryAfter);
|
||||
if (DEBUG_MODE) {
|
||||
const stateAfter = store.getState();
|
||||
const panelHistoryAfter = stateAfter.panelHistory;
|
||||
console.log('[PANEL_HISTORY] After RESET_PANELS:', panelHistoryAfter);
|
||||
}
|
||||
};
|
||||
|
||||
// state 업데이트가 완료된 후 로그
|
||||
@@ -189,7 +214,7 @@ export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[panelHistoryMiddleware] 오류:', error);
|
||||
if (DEBUG_MODE) console.error('[panelHistoryMiddleware] 오류:', error);
|
||||
// Middleware 오류가 앱 전체에 영향 주지 않도록 처리
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user