[251031] fix: SearchInputOverlay TurnBack Focus

🕐 커밋 시간: 2025. 10. 31. 10:44:59

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

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx

🔧 주요 변경 내용:
  • 중간 규모 기능 개선
This commit is contained in:
2025-10-31 10:44:59 +09:00
parent 0b1d435e62
commit 973a1da459

View File

@@ -226,6 +226,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
// 마이크 버튼 포커스 가능 여부 상태
const [isMicFocusable, setIsMicFocusable] = useState(true);
// 🎯 SearchInputOverlay 닫힘 후 포커스 관리 - 명시적 플래그
const [shouldFocusSearchInput, setShouldFocusSearchInput] = useState(false);
// 🐛 [DEBUG] shopperHouseData 상태 변경 추적 (DEBUG_MODE가 true일 경우에만)
useEffect(() => {
if (DEBUG_MODE) {
@@ -645,7 +648,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
if (DEBUG_MODE) {
console.log('[DEBUG]-onCancel: closing SearchInputOverlay');
}
setIsSearchOverlayVisible(false);
handleSearchOverlayClose();
return;
}
@@ -949,9 +952,21 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
}
// Search Overlay가 닫힌 상황
// - isSearchOverlayVisible이 true → false로 변경되고
// - 검색이 수행되지 않았거나 SearchPanel이 SEARCH_RESULT 모드가 아닌 경우
if (!isSearchOverlayVisible && isSearchOverlayVisibleRef.current) {
if (DEBUG_MODE) {
console.log('[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED');
console.log('[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED', {
isSearchOverlayVisible,
prevIsSearchOverlayVisible: isSearchOverlayVisibleRef.current,
currentMode,
searchPerformed,
hasSearchResults: !!(
searchDatas?.theme?.length > 0 ||
searchDatas?.item?.length > 0 ||
searchDatas?.show?.length > 0
),
});
}
return 'SEARCH_OVERLAY_CLOSED';
}
@@ -1035,13 +1050,21 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
return 'searchItemContents0';
case 'VOICE_OVERLAY_CLOSED':
case 'SEARCH_OVERLAY_CLOSED':
// Overlay 닫힘 → ShopperHouse 데이터 있으면 상품, 없으면 TInput
// Voice Overlay 닫힘 → ShopperHouse 데이터 있으면 상품, 없으면 TInput
if (shopperHouseData) {
return 'searchItemContents0';
}
return SPOTLIGHT_IDS.SEARCH_INPUT_BOX;
case 'SEARCH_OVERLAY_CLOSED':
// 🎯 SearchInputOverlay 닫힘 (ESC/Back) → 항상 TInputSimple으로 포커스
// SearchInputOverlay에서 검색을 실행하면 isSearchOverlayVisible이 false로 설정되고
// 동시에 검색 결과에 따라 모드가 변경되므로, 이 케이스는 검색어 선택 후 닫을 때만 발생
if (DEBUG_MODE) {
console.log('[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED - TInputSimple으로 포커스');
}
return SPOTLIGHT_IDS.SEARCH_INPUT_BOX;
default:
return null;
}
@@ -1070,6 +1093,10 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
* Search overlay close handler
*/
const handleSearchOverlayClose = useCallback(() => {
console.log('[DEBUG] 🚪 handleSearchOverlayClose 호출됨 - 직접 확인!', {
timestamp: new Date().toISOString(),
});
if (DEBUG_MODE) {
console.log('[DEBUG] 🚪 SearchInputOverlay closing');
}
@@ -1079,6 +1106,15 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
(searchDatas?.item?.length || 0) > 0 ||
(searchDatas?.show?.length || 0) > 0;
// 🎯 SearchInputOverlay 닫힘 후 TInputSimple으로 포커스 이동을 위한 플래그 설정
console.log('[DEBUG] setShouldFocusSearchInput(true) 설정 직전', {
timestamp: new Date().toISOString(),
});
setShouldFocusSearchInput(true);
console.log('[DEBUG] setShouldFocusSearchInput(true) 설정됨!', {
timestamp: new Date().toISOString(),
});
// 🎯 [포커스 로직 통합] 포커스는 상태 변경(isSearchOverlayVisible)에 의해 자동으로 처리됨
setIsSearchOverlayVisible(false);
@@ -1742,6 +1778,98 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
currentModeRef.current = currentMode;
}, [shopperHouseData, searchDatas, isVoiceOverlayVisible, isSearchOverlayVisible, currentMode]);
/**
* 🎯 SearchInputOverlay 닫힘 후 포커스 관리
* shouldFocusSearchInput 플래그가 true로 설정되면 500ms 후 TInputSimple으로 포커스 이동
* - 명시적 플래그를 통해 SearchInputOverlay 닫힘 시나리오 처리
* - 다른 포커스 로직과 독립적으로 동작
* - 자동으로 플래그 초기화
*/
useEffect(() => {
console.log('[DEBUG] shouldFocusSearchInput useEffect 실행됨!', {
shouldFocusSearchInput,
timestamp: new Date().toISOString(),
});
if (shouldFocusSearchInput) {
let focusTimer = null;
console.log('[DEBUG] shouldFocusSearchInput === true, 타이머 설정 중...', {
timestamp: new Date().toISOString(),
});
if (DEBUG_MODE) {
console.log('[FOCUS] 🎯 SearchInputOverlay 닫힘 후 포커스 관리 useEffect 실행', {
shouldFocusSearchInput,
timestamp: new Date().toISOString(),
});
}
// 500ms 후 TInputSimple에 포커스 이동
focusTimer = setTimeout(() => {
console.log('[DEBUG] ⏰ 500ms 타이머 콜백 실행!', {
targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX,
timestamp: new Date().toISOString(),
});
if (DEBUG_MODE) {
console.log('[FOCUS] ⏰ 500ms 타이머 콜백 실행 - TInputSimple으로 포커스 이동', {
targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX,
timestamp: new Date().toISOString(),
});
}
console.log('[DEBUG] Spotlight.focus() 호출 직전', {
targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX,
});
Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX);
console.log('[DEBUG] Spotlight.focus() 호출 완료!', {
targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX,
timestamp: new Date().toISOString(),
});
if (DEBUG_MODE) {
console.log('[FOCUS] ✅ Spotlight.focus() 호출 완료', {
targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX,
timestamp: new Date().toISOString(),
});
}
console.log('[DEBUG] setShouldFocusSearchInput(false) 호출 직전', {
timestamp: new Date().toISOString(),
});
// 포커스 이동 완료 후 플래그 초기화
setShouldFocusSearchInput(false);
console.log('[DEBUG] setShouldFocusSearchInput(false) 호출 완료!', {
timestamp: new Date().toISOString(),
});
}, 500);
console.log('[DEBUG] 타이머 설정 완료 - 500ms 후 포커스 이동 예약됨', {
timestamp: new Date().toISOString(),
});
// Cleanup: 타이머 정리
return () => {
console.log('[DEBUG] shouldFocusSearchInput useEffect cleanup 실행', {
timestamp: new Date().toISOString(),
});
if (focusTimer) {
if (DEBUG_MODE) {
console.log('[FOCUS] 🧹 SearchInputOverlay 포커스 관리 useEffect cleanup - 타이머 정리', {
timestamp: new Date().toISOString(),
});
}
clearTimeout(focusTimer);
}
};
}
}, [shouldFocusSearchInput, DEBUG_MODE]);
/**
* LOG 용도,
* 현재 menu 위치를 설정하여, 로그를 보내는 용도