🕐 커밋 시간: 2025. 11. 22. 18:19:45 📊 변경 통계: • 총 파일: 10개 • 추가: +150줄 • 삭제: -152줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/App/App.js ~ com.twin.app.shoptime/src/actions/panelActions.js ~ com.twin.app.shoptime/src/middleware/panelHistoryMiddleware.js ~ com.twin.app.shoptime/src/utils/ImagePreloader.js ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.v2.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx ~ com.twin.app.shoptime/src/views/HomePanel/HomePanel.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/App/App.js (javascript): ❌ Deleted: resolveSpotlightIdFromEvent() 📄 com.twin.app.shoptime/src/actions/panelActions.js (javascript): 🔄 Modified: resetPanels() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): 🔄 Modified: extractProductMeta() 📄 com.twin.app.shoptime/src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.v2.jsx (javascript): ❌ Deleted: logDetailPanelInit(), logImageLoaded(), logImageError() 📄 com.twin.app.shoptime/src/views/DetailPanel/components/FavoriteBtn.jsx (javascript): 🔄 Modified: Spottable() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • 공통 유틸리티 함수 최적화 • UI 컴포넌트 아키텍처 개선 Performance: 코드 최적화로 성능 개선 기대
312 lines
10 KiB
JavaScript
312 lines
10 KiB
JavaScript
/**
|
|
* src/middleware/panelHistoryMiddleware.js
|
|
* Panel history 자동 추적 middleware
|
|
*
|
|
* Panel action (PUSH, POP, UPDATE, RESET)을 감지하고
|
|
* 자동으로 panel history에 기록
|
|
*
|
|
* ⚠️ [251122] DEBUG_MODE = false로 설정되어 모든 로그 출력 비활성화됨
|
|
* - 로그가 필요하면 DEBUG_MODE를 true로 변경하면 됨
|
|
* - middleware 동작 자체는 영향받지 않음 (로그만 출력 안됨)
|
|
*/
|
|
|
|
import { types } from '../actions/actionTypes';
|
|
import { enqueuePanelHistory, clearPanelHistory } from '../actions/panelHistoryActions';
|
|
import { calculateIsPanelOnTop } from '../utils/panelUtils'; // 🎯 isOnTop 유틸리티 함수 import
|
|
|
|
// DEBUG_MODE - true인 경우에만 로그 출력
|
|
// ⚠️ [251122] panelHistory 로그 비활성화 - 로그 생성 차단
|
|
const DEBUG_MODE = false;
|
|
|
|
/**
|
|
* Panel history middleware
|
|
* 모든 panel action을 감지하여 panelHistory reducer로 자동 기록
|
|
*
|
|
* @param {Object} store - Redux store
|
|
* @returns {Function} middleware function
|
|
*/
|
|
export const panelHistoryMiddleware = (store) => (next) => (action) => {
|
|
// 모든 PANEL 관련 액션 로깅
|
|
if (
|
|
DEBUG_MODE &&
|
|
action.type &&
|
|
(action.type.includes('PANEL') || action.type === 'CLEAR_PANEL_HISTORY')
|
|
) {
|
|
const caller = new Error().stack.split('\n')[1]?.trim();
|
|
console.log(`[PANEL DEBUG] ${action.type} from: ${caller}`);
|
|
console.log(' Payload:', action.payload);
|
|
}
|
|
|
|
// GNB 호출 식별을 위한 helper 함수
|
|
const isGNBCall = () => {
|
|
const stack = new Error().stack;
|
|
if (!stack) return false;
|
|
|
|
const stackLines = stack.split('\n');
|
|
for (const line of stackLines) {
|
|
if (line.includes('TabLayout.jsx') || line.includes('TIconButton.jsx')) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// 임시: CLEAR_PANEL_HISTORY 무력화
|
|
if (action.type === 'CLEAR_PANEL_HISTORY') {
|
|
if (DEBUG_MODE) console.log('[PANEL DEBUG] CLEAR_PANEL_HISTORY BLOCKED!');
|
|
return action; // 액션을 전달하지 않음
|
|
}
|
|
|
|
// 원래 액션 실행
|
|
const result = next(action);
|
|
|
|
// Panel action 후 history 업데이트
|
|
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 추가
|
|
case types.PUSH_PANEL: {
|
|
if (action.payload) {
|
|
const { name: panelName, panelInfo = {} } = action.payload;
|
|
|
|
if (panelName) {
|
|
const isGNB = isGNBCall();
|
|
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 = () => {
|
|
if (DEBUG_MODE) {
|
|
const stateAfter = store.getState();
|
|
const panelHistoryAfter = stateAfter.panelHistory;
|
|
const panelsAfter = stateAfter.panels.panels;
|
|
console.log('[PANEL_HISTORY] After PUSH_PANEL:', {
|
|
panelHistory: panelHistoryAfter,
|
|
panels: panelsAfter,
|
|
});
|
|
}
|
|
};
|
|
|
|
// state 업데이트가 완료된 후 로그
|
|
Promise.resolve().then(logPanelHistoryAfter);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// POP_PANEL: panel 제거 후 이전 panel 기록
|
|
case types.POP_PANEL: {
|
|
// POP 후 top panel을 기록 (이전 패널로 돌아감)
|
|
if (panels.length > 0) {
|
|
const topPanel = panels[panels.length - 1];
|
|
if (topPanel && topPanel.name) {
|
|
const isGNB = isGNBCall();
|
|
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 = () => {
|
|
if (DEBUG_MODE) {
|
|
const stateAfter = store.getState();
|
|
const panelHistoryAfter = stateAfter.panelHistory;
|
|
const panelsAfter = stateAfter.panels.panels;
|
|
console.log('[PANEL_HISTORY] After POP_PANEL:', {
|
|
panelHistory: panelHistoryAfter,
|
|
panels: panelsAfter,
|
|
});
|
|
}
|
|
};
|
|
|
|
// state 업데이트가 완료된 후 로그
|
|
Promise.resolve().then(logPanelHistoryAfter);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// UPDATE_PANEL: panel 정보 업데이트 기록
|
|
case types.UPDATE_PANEL: {
|
|
if (action.payload) {
|
|
const { name: panelName, panelInfo = {} } = action.payload;
|
|
|
|
if (panelName) {
|
|
const isGNB = isGNBCall();
|
|
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 = () => {
|
|
if (DEBUG_MODE) {
|
|
const stateAfter = store.getState();
|
|
const panelHistoryAfter = stateAfter.panelHistory;
|
|
const panelsAfter = stateAfter.panels.panels;
|
|
console.log('[PANEL_HISTORY] After UPDATE_PANEL:', {
|
|
panelHistory: panelHistoryAfter,
|
|
panels: panelsAfter,
|
|
});
|
|
}
|
|
};
|
|
|
|
// state 업데이트가 완료된 후 로그
|
|
Promise.resolve().then(logPanelHistoryAfter);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// RESET_PANELS: GNB 네비게이션 또는 완전 초기화
|
|
case types.RESET_PANELS: {
|
|
if (DEBUG_MODE)
|
|
console.log('[PANEL] RESET_PANELS:', {
|
|
payload: action.payload,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
if (DEBUG_MODE)
|
|
console.log('[PANEL_HISTORY] Before RESET_PANELS:', store.getState().panelHistory);
|
|
|
|
// 모든 RESET_PANELS를 기록
|
|
const isGNB = isGNBCall();
|
|
|
|
if (action.payload && action.payload.length > 0) {
|
|
// payload가 있는 경우 (GNB 탭, 패널 내 네비게이션 등)
|
|
const firstPanel = action.payload[0];
|
|
if (firstPanel && firstPanel.name) {
|
|
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,
|
|
firstPanel.panelInfo || {},
|
|
'RESET',
|
|
new Date().toISOString(),
|
|
isGNB, // TabLayout/TIconButton이면 true
|
|
true, // fromResetPanel: 항상 true
|
|
isOnTop // 🎯 isOnTop 정보 추가
|
|
)
|
|
);
|
|
}
|
|
} else {
|
|
// 완전 초기화 (payload가 없는 경우 - HomePanel, 앱 초기화 등)
|
|
if (DEBUG_MODE)
|
|
console.log('[PANEL_DEBUG] Complete panel history reset (payload empty)', {
|
|
isGNB,
|
|
fromResetPanel: true,
|
|
});
|
|
store.dispatch(clearPanelHistory());
|
|
|
|
// 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
|
|
isOnTop // 🎯 isOnTop 정보 추가
|
|
)
|
|
);
|
|
}
|
|
|
|
// PanelHistory 상태 로그 (초기화 후)
|
|
const logPanelHistoryAfter = () => {
|
|
if (DEBUG_MODE) {
|
|
const stateAfter = store.getState();
|
|
const panelHistoryAfter = stateAfter.panelHistory;
|
|
const panelsAfter = stateAfter.panels.panels;
|
|
console.log('[PANEL_HISTORY] After RESET_PANELS:', {
|
|
panelHistory: panelHistoryAfter,
|
|
panels: panelsAfter,
|
|
});
|
|
}
|
|
};
|
|
|
|
// state 업데이트가 완료된 후 로그
|
|
Promise.resolve().then(logPanelHistoryAfter);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// Other actions are ignored
|
|
break;
|
|
}
|
|
} catch (error) {
|
|
if (DEBUG_MODE) console.error('[panelHistoryMiddleware] 오류:', error);
|
|
// Middleware 오류가 앱 전체에 영향 주지 않도록 처리
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
export default panelHistoryMiddleware;
|