[251105] fix: VoiceResults Focus문제 해결

🕐 커밋 시간: 2025. 11. 05. 11:00:46

📊 변경 통계:
  • 총 파일: 2개
  • 추가: +29줄
  • 삭제: -5줄

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

🔧 주요 변경 내용:
  • 소규모 기능 개선
This commit is contained in:
2025-11-05 11:00:46 +09:00
parent 96e194d53a
commit 463db62b8c
2 changed files with 29 additions and 5 deletions

View File

@@ -939,16 +939,16 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
return 'SEARCH_RESULT_LOADED'; return 'SEARCH_RESULT_LOADED';
} }
// 새로운 음성 검색 결과 모드로 진입 (모드 변경으로 감지 - 일관성 유지) // 새로운 음성 검색 결과 모드로 진입 (모드 변경 또는 데이터 도착으로 감지)
// - currentMode가 VOICE_RESULT로 변경되고 // - currentMode가 VOICE_RESULT 이고, 새로운 ShopperHouse 데이터가 도착했으면
// - 이전에는 VOICE_RESULT가 아니었으면
// - 🎯 중요: isOnTop이 변화하지 않았을 때만 (이미 SearchPanel이 열려있고 새로 검색한 경우) // - 🎯 중요: isOnTop이 변화하지 않았을 때만 (이미 SearchPanel이 열려있고 새로 검색한 경우)
// DetailPanel 복귀(isOnTop 변화)는 위의 DETAIL_PANEL_RETURN에서 먼저 처리됨 // DetailPanel 복귀(isOnTop 변화)는 위의 DETAIL_PANEL_RETURN에서 먼저 처리됨
if ( if (
isOnTop === isOnTopRef.current && isOnTop === isOnTopRef.current &&
currentMode === SEARCH_PANEL_MODES.VOICE_RESULT && currentMode === SEARCH_PANEL_MODES.VOICE_RESULT &&
currentModeRef.current !== SEARCH_PANEL_MODES.VOICE_RESULT && shopperHouseData &&
shopperHouseData // 🎯 [개선] 모드 변경 OR 새로운 데이터 도착 감지
(currentModeRef.current !== SEARCH_PANEL_MODES.VOICE_RESULT || shopperHouseDataRef.current !== shopperHouseData)
) { ) {
if (DEBUG_MODE) { if (DEBUG_MODE) {
console.log('[FOCUS] 🎯 Scenario: NEW_SEARCH_LOADED (Voice Result Mode)', { console.log('[FOCUS] 🎯 Scenario: NEW_SEARCH_LOADED (Voice Result Mode)', {
@@ -956,6 +956,8 @@ 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: currentModeRef.current !== SEARCH_PANEL_MODES.VOICE_RESULT,
dataChanged: shopperHouseDataRef.current !== shopperHouseData,
}); });
} }
return 'NEW_SEARCH_LOADED'; return 'NEW_SEARCH_LOADED';
@@ -968,6 +970,14 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
hasShopperHouseData: !!shopperHouseData, hasShopperHouseData: !!shopperHouseData,
}); });
} }
// 🎯 [중요] 새로운 음성 검색 결과가 도착했으면 NEW_SEARCH_LOADED 우선 처리
// 이렇게 하면 VOICE_OVERLAY_CLOSED 시나리오에서 TInput으로 가는 것을 방지
if (shopperHouseData && currentMode === SEARCH_PANEL_MODES.VOICE_RESULT) {
if (DEBUG_MODE) {
console.log('[FOCUS] 🔄 VOICE_OVERLAY_CLOSED + new data → NEW_SEARCH_LOADED 우선 처리');
}
return 'NEW_SEARCH_LOADED';
}
return 'VOICE_OVERLAY_CLOSED'; return 'VOICE_OVERLAY_CLOSED';
} }
@@ -1840,6 +1850,17 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
unifiedFocusTimerRef.current = null; unifiedFocusTimerRef.current = null;
}, focusDelay); }, focusDelay);
// 🎯 [NEW_SEARCH_LOADED] 1초 후 다시 첫 번째 아이템으로 포커스 이동
// TInputSimple과 Mic Icon의 포커스 충돌 해결을 위해
if (scenario === 'NEW_SEARCH_LOADED' && targetId === 'searchItemContents0') {
setTimeout(() => {
if (DEBUG_MODE) {
console.log('[FOCUS] 🔄 NEW_SEARCH_LOADED: 1 번째 상품으로 다시 포커스 이동');
}
Spotlight.focus('searchItemContents0');
}, 500); // 0.5초 후
}
// Cleanup: 컴포넌트 언마운트 또는 targetId 변경 시 타이머 정리 // Cleanup: 컴포넌트 언마운트 또는 targetId 변경 시 타이머 정리
return () => { return () => {
if (unifiedFocusTimerRef.current) { if (unifiedFocusTimerRef.current) {

View File

@@ -260,6 +260,9 @@ const VoiceInputOverlay = ({
// 약간의 지연 후 닫기 (사용자가 결과를 인지할 수 있도록) // 약간의 지연 후 닫기 (사용자가 결과를 인지할 수 있도록)
closeTimerRef.current = setTimeout(() => { closeTimerRef.current = setTimeout(() => {
// 음성 검색 결과가 도착했을 때는 포커스 복원을 하지 않음
// SearchPanel의 포커스 로직이 첫 번째 상품으로 포커스를 이동시킴
lastFocusedElement.current = null;
onClose(); onClose();
}, 500); }, 500);
} }