From 2838e4b8ec321335aca7324862d6bb02eaf76c0c Mon Sep 17 00:00:00 2001 From: optrader Date: Fri, 24 Oct 2025 21:16:53 +0000 Subject: [PATCH] =?UTF-8?q?[251024]=20[251025]=20feat:=20Voice=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=9B=84=20=ED=8F=AC=EC=BB=A4=EC=8A=A4=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 10. 24. 21:16:53 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 2๊ฐœ โ€ข ์ถ”๊ฐ€: +76์ค„ โ€ข ์‚ญ์ œ: -21์ค„ ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx ๐Ÿ”ง ์ฃผ์š” ๋ณ€๊ฒฝ ๋‚ด์šฉ: โ€ข ์†Œ๊ทœ๋ชจ ๊ธฐ๋Šฅ ๊ฐœ์„  --- .../views/SearchPanel/SearchPanel.new.v2.jsx | 58 +++++++++++++++++-- .../SearchPanel/SearchResults.new.v2.jsx | 39 ++++++++----- 2 files changed, 76 insertions(+), 21 deletions(-) diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx index 40d234dc..4865a7db 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx @@ -183,6 +183,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { const [voiceOverlayMode, setVoiceOverlayMode] = useState(VOICE_MODES.PROMPT); const [voiceOverlayResponseText, setVoiceOverlayResponseText] = useState(''); const [isVoiceOverlayBubbleSearch, setIsVoiceOverlayBubbleSearch] = useState(false); + const [shouldFocusVoiceResult, setShouldFocusVoiceResult] = useState(false); // ๐Ÿ› [DEBUG] shopperHouseData ์ƒํƒœ ๋ณ€๊ฒฝ ์ถ”์  (DEBUG_MODE๊ฐ€ true์ผ ๊ฒฝ์šฐ์—๋งŒ) useEffect(() => { @@ -657,11 +658,15 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { setVoiceOverlayResponseText(''); setIsVoiceOverlayBubbleSearch(false); setIsVoiceOverlayVisible(false); - // โœ… VoiceOverlay๊ฐ€ ๋‹ซํž ๋•Œ ํ•ญ์ƒ TInput์œผ๋กœ ํฌ์ปค์Šค ์ด๋™ - setTimeout(() => { - Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX); - }, 150); // Overlay ๋‹ซํžˆ๋Š” ์‹œ๊ฐ„์„ ๊ณ ๋ คํ•œ ์ง€์—ฐ - }, []); + setShouldFocusVoiceResult(false); + + // ShopperHouse ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์„ ๋•Œ๋งŒ ๊ฒ€์ƒ‰ ์ธํ’‹์œผ๋กœ ํฌ์ปค์Šค ๋ณต์› + if (!shopperHouseData) { + setTimeout(() => { + Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX); + }, 150); // Overlay ๋‹ซํžˆ๋Š” ์‹œ๊ฐ„์„ ๊ณ ๋ คํ•œ ์ง€์—ฐ + } + }, [shopperHouseData]); const handleHowAboutTheseQueryClick = useCallback( (rawQuery) => { @@ -678,6 +683,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { setVoiceOverlayMode(VOICE_MODES.RESPONSE); setIsVoiceOverlayBubbleSearch(true); setIsVoiceOverlayVisible(true); + setShouldFocusVoiceResult(false); dispatch(getShopperHouseSearch(trimmedQuery, shopperHouseSearchId)); }, @@ -1161,7 +1167,47 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { clearTimeout(focusTimer); }; } - }, [shopperHouseData, isOnTop, currentMode]); + }, [shopperHouseData, isOnTop, currentMode, DEBUG_MODE]); + + useEffect(() => { + if ( + isOnTop && + currentMode === SEARCH_PANEL_MODES.VOICE_RESULT && + shopperHouseData?.results?.[0]?.docs?.length > 0 && + !isVoiceOverlayVisible + ) { + if (DEBUG_MODE) { + console.log('[DEBUG] ๐ŸŽฏ ShopperHouse ๋ฐ์ดํ„ฐ ๊ฐ์ง€ - ์ƒํ’ˆ ํฌ์ปค์Šค ์˜ˆ์•ฝ'); + } + setShouldFocusVoiceResult(true); + } + }, [isOnTop, currentMode, shopperHouseData, isVoiceOverlayVisible, DEBUG_MODE]); + + useEffect(() => { + if (!shouldFocusVoiceResult) { + return; + } + + const focusTimer = setTimeout(() => { + const targetId = 'searchItemContents0'; + const targetElement = document.querySelector(`[data-spotlight-id="${targetId}"]`); + + if (targetElement) { + Spotlight.focus(targetId); + if (DEBUG_MODE) { + console.log('[DEBUG] ๐ŸŽฏ ShopperHouse ์ฒซ ์ƒํ’ˆ์œผ๋กœ ํฌ์ปค์Šค ์ด๋™:', targetId); + } + } else if (DEBUG_MODE) { + console.log('[DEBUG] โš ๏ธ ShopperHouse ์ฒซ ์ƒํ’ˆ์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค'); + } + + setShouldFocusVoiceResult(false); + }, 200); + + return () => { + clearTimeout(focusTimer); + }; + }, [shouldFocusVoiceResult, DEBUG_MODE]); /** * LOG ์šฉ๋„, diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx index 48936424..6c3c8232 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.v2.jsx @@ -151,6 +151,7 @@ const SearchResultsNew = ({ const buttonTabList = useMemo(() => getButtonTabList(), [getButtonTabList]); // ํ˜„์žฌ ํƒญ์˜ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ - ShopperHouse ๋ฐ์ดํ„ฐ ์šฐ์„  + const hasShopperHouseItems = convertedShopperHouseItems?.length > 0; const currentData = tab === 0 ? convertedShopperHouseItems || itemInfo : showInfo; // ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ (์ฒ˜์Œ๋ถ€ํ„ฐ visibleCount ๊ฐœ์ˆ˜๋งŒํผ) @@ -209,20 +210,22 @@ const SearchResultsNew = ({ } const targetId = - themeInfo?.length > 0 - ? 'searchProduct-0' - : itemInfo?.length > 0 - ? 'searchItemContents0' - : showInfo?.length > 0 - ? 'categoryShowContents0' - : null; + hasShopperHouseItems + ? 'searchItemContents0' + : themeInfo?.length > 0 + ? 'searchProduct-0' + : itemInfo?.length > 0 + ? 'searchItemContents0' + : showInfo?.length > 0 + ? 'categoryShowContents0' + : null; if (!targetId) { Spotlight.focus('search-input-box'); } else { Spotlight.focus(targetId); } - }, []); + }, [hasShopperHouseItems, themeInfo, itemInfo, showInfo]); // 10๊ฐœ์”ฉ ์ถ”๊ฐ€ ๋กœ๋“œ (์•„๋ž˜ ๋ฒ„ํŠผ) const downBtnClick = useCallback(() => { @@ -283,13 +286,15 @@ const SearchResultsNew = ({ useEffect(() => { const targetId = panelInfo?.currentSpot ? panelInfo?.currentSpot - : themeInfo?.length > 0 - ? 'searchProduct-0' - : itemInfo?.length > 0 - ? 'searchItemContents0' - : showInfo?.length > 0 - ? 'categoryShowContents0' - : null; + : hasShopperHouseItems + ? 'searchItemContents0' + : themeInfo?.length > 0 + ? 'searchProduct-0' + : itemInfo?.length > 0 + ? 'searchItemContents0' + : showInfo?.length > 0 + ? 'categoryShowContents0' + : null; if (!targetId) return; @@ -301,6 +306,10 @@ const SearchResultsNew = ({ itemInfo?.length, showInfo?.length, convertedShopperHouseItems?.length, // shopperHouseInfo ๋Œ€์‹  ๊ตฌ์ฒด์ ์ธ ์˜์กด์„ฑ ์‚ฌ์šฉ + hasShopperHouseItems, + themeInfo, + itemInfo, + showInfo, ]); return (