From b95628de24dab869c04ec34ce694a460805e88a3 Mon Sep 17 00:00:00 2001 From: optrader Date: Mon, 24 Nov 2025 12:19:40 +0900 Subject: [PATCH] =?UTF-8?q?[251124]=20fix:=20Log=EC=A0=95=EB=A6=AC-4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🕐 컀밋 시간: 2025. 11. 24. 12:19:40 📊 변겜 통계: • 쎝 파음: 6개 • 추가: +283쀄 • 삭제: -255쀄 📝 수정된 파음: ~ com.twin.app.shoptime/src/actions/mainActions.js ~ com.twin.app.shoptime/src/reducers/mainReducer.js ~ com.twin.app.shoptime/src/reducers/searchReducer.js ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.v2.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx 🔧 핚수 변겜 낎용: 📄 com.twin.app.shoptime/src/actions/mainActions.js (javascript): 🔄 Modified: clearSubCategory() 📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx (javascript): 🔄 Modified: Spottable() 📄 com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx (javascript): ✅ Added: Spottable() 🔄 Modified: clearAllTimers() 🔧 죌요 변겜 낎용: • 핵심 비슈니슀 로직 개선 --- .../src/actions/mainActions.js | 47 +-- .../src/reducers/mainReducer.js | 9 +- .../src/reducers/searchReducer.js | 55 ++-- .../PlayerTabContents/v2/TabContainer.v2.jsx | 8 +- .../views/SearchPanel/SearchPanel.new.v2.jsx | 289 ++++++++--------- .../VoiceInputOverlay/VoiceInputOverlay.jsx | 293 +++++++++--------- 6 files changed, 343 insertions(+), 358 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/mainActions.js b/com.twin.app.shoptime/src/actions/mainActions.js index 5167f09c..f528e0e3 100644 --- a/com.twin.app.shoptime/src/actions/mainActions.js +++ b/com.twin.app.shoptime/src/actions/mainActions.js @@ -5,13 +5,18 @@ import { CATEGORY_DATA_MAX_RESULTS_LIMIT, LOG_CONTEXT_NAME, LOG_MESSAGE_ID } fro import * as HelperMethods from '../utils/helperMethods'; import { types } from './actionTypes'; import { addReservation, changeAppStatus, deleteReservation } from './commonActions'; +import { createDebugHelpers } from '../utils/debug'; + +// 디버귞 헬퍌 섀정 +const DEBUG_MODE = false; +const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE); //IF-LGSP-007 export const getMainLiveShow = (props) => (dispatch, getState) => { const vodIncFlag = props?.vodIncFlag; const onSuccess = (response) => { - console.log('@@ getMainLiveShow onSuccess', response.data); + dlog('@@ getMainLiveShow onSuccess', response.data); dispatch({ type: types.GET_MAIN_LIVE_SHOW, @@ -20,7 +25,7 @@ export const getMainLiveShow = (props) => (dispatch, getState) => { }; const onFail = (error) => { - console.error('@@ getMainLiveShow onFail', error); + derror('@@ getMainLiveShow onFail', error); }; TAxios(dispatch, getState, 'get', URLS.GET_MAIN_LIVE_SHOW, { vodIncFlag }, {}, onSuccess, onFail); @@ -31,7 +36,7 @@ export const setMainLiveUpcomingAlarm = (props) => (dispatch, getState) => { const { alamDispFlag, chanId, endDt, patnrId, patncNm, showId, showNm, strtDt } = props; const onSuccess = (response) => { - console.log('setMainLiveUpcomingAlarm onSuccess', response.data); + dlog('setMainLiveUpcomingAlarm onSuccess', response.data); if (alamDispFlag === 'Y') { const convertedStrtDt = convertUtcToLocal(strtDt); @@ -72,7 +77,7 @@ export const setMainLiveUpcomingAlarm = (props) => (dispatch, getState) => { }; const onFail = (error) => { - console.error('setMainLiveUpcomingAlarm onFail', error); + derror('setMainLiveUpcomingAlarm onFail', error); }; TAxios( @@ -94,7 +99,7 @@ export const getMainCategoryDetail = (props) => (dispatch, getState) => { dispatch(changeAppStatus({ showLoadingPanel: { show: true, type: 'wait' } })); const onSuccess = (response) => { - console.log('getMainCategoryDetail onSuccess ', response.data); + dlog('getMainCategoryDetail onSuccess ', response.data); dispatch({ type: types.GET_PRODUCT_DETAIL, @@ -105,7 +110,7 @@ export const getMainCategoryDetail = (props) => (dispatch, getState) => { }; const onFail = (error) => { - console.error('getMainCategoryDetail onFail', error); + derror('getMainCategoryDetail onFail', error); dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); }; @@ -125,7 +130,7 @@ export const getMainCategoryDetail = (props) => (dispatch, getState) => { export const getMainCategoryShowDetail = (props) => (dispatch, getState) => { const { patnrId, showId, curationId } = props; const onSuccess = (response) => { - console.log('getMainCategoryShowDetail onSuccess ', response.data); + dlog('getMainCategoryShowDetail onSuccess ', response.data); dispatch({ type: types.GET_MAIN_CATEGORY_SHOW_DETAIL, @@ -134,7 +139,7 @@ export const getMainCategoryShowDetail = (props) => (dispatch, getState) => { }; const onFail = (error) => { - console.error('getMainCategoryShowDetail onFail', error); + derror('getMainCategoryShowDetail onFail', error); }; TAxios( @@ -165,7 +170,7 @@ export const getSubCategory = lastSubCategoryParams && JSON.stringify(lastSubCategoryParams) === JSON.stringify(params) ) { - console.log('getSubCategory ignore patch'); + dlog('getSubCategory ignore patch'); return; } lastSubCategoryParams = { ...params }; @@ -176,7 +181,7 @@ export const getSubCategory = let currentKey = key; const onSuccess = (response) => { - console.log('getSubCategory onSuccess ', response.data); + dlog('getSubCategory onSuccess ', response.data); if (pageNo === 1) { getSubCategoryKey = new Date(); @@ -220,7 +225,7 @@ export const getSubCategory = const canRetry = nextRetryCount < SUB_CATEGORY_RETRY_LIMIT; if (canRetry) { - console.warn('getSubCategory retry', { + dwarn('getSubCategory retry', { lgCatCd, pageNo, retryCount: nextRetryCount, @@ -232,7 +237,7 @@ export const getSubCategory = return; } - console.error('getSubCategory onFail', error); + derror('getSubCategory onFail', error); if (pageNo === 1) { lastSubCategoryParams = {}; } @@ -253,7 +258,7 @@ export const getSubCategory = export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => { if (!lastSubCategoryParams) { // <<<<<<< HEAD - console.warn('No previous category parameters found'); + dwarn('No previous category parameters found'); // ======= // console.warn("No previous category parameters found"); // >>>>>>> gitlab/develop @@ -295,7 +300,7 @@ const clearSubCategory = () => ({ // TOP20 영상 목록 조회 IF-LGSP-069 export const getTop20Show = () => (dispatch, getState) => { const onSuccess = (response) => { - console.log('getTop20Show onSuccess ', response.data); + dlog('getTop20Show onSuccess ', response.data); dispatch({ type: types.GET_TOP_20_SHOW, @@ -305,7 +310,7 @@ export const getTop20Show = () => (dispatch, getState) => { }; const onFail = (error) => { - console.error('getTop20Show onFail', error); + derror('getTop20Show onFail', error); dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); }; @@ -375,14 +380,14 @@ export const getMyFavoriteFlag = (params) => (dispatch, getState) => { const { patnrId, prdtId } = params; const onSuccess = (response) => { - console.log('getMyFavoriteFlag onSuccess ', response.data); + dlog('getMyFavoriteFlag onSuccess ', response.data); dispatch({ type: types.GET_MY_FAVORITE_FLAG, payload: response.data.data, }); }; const onFail = (error) => { - console.error('getMyFavoriteFlag onFail', error); + derror('getMyFavoriteFlag onFail', error); }; TAxios( @@ -401,7 +406,7 @@ export const setMainLikeCategory = (params) => (dispatch, getState) => { const { patnrId, prdtId } = params; const onSuccess = (response) => { - console.log('setMainLikeCategory onSuccess ', response.data); + dlog('setMainLikeCategory onSuccess ', response.data); dispatch({ type: types.SET_MAIN_LIKE_CATEGORY, payload: response.data.data, @@ -428,10 +433,10 @@ export const getHomeFullVideoInfo = ({ lgCatCd }) => (dispatch, getState) => { const onSuccess = (response) => { - console.log('getHomeFullVideoInfo onSuccess', response.data.data.showInfos); + dlog('getHomeFullVideoInfo onSuccess', response.data.data.showInfos); // ✹ DEBUG: youmaylikeInfos 데읎터 확읞 - console.log('[DEBUG] GET_HOME_FULL_VIDEO_INFO - API Response:', { + dlog('[DEBUG] GET_HOME_FULL_VIDEO_INFO - API Response:', { youmaylikeInfos: response.data.data.youmaylikeInfos, youmaylikeInfos_length: response.data.data.youmaylikeInfos?.length, liveChannelInfos_length: response.data.data.liveChannelInfos?.length, @@ -445,7 +450,7 @@ export const getHomeFullVideoInfo = }; const onFail = (error) => { - console.error('getHomeFullVideoInfo onSuccess', error); + derror('getHomeFullVideoInfo onSuccess', error); }; TAxios( diff --git a/com.twin.app.shoptime/src/reducers/mainReducer.js b/com.twin.app.shoptime/src/reducers/mainReducer.js index 8143b9f5..d2dae9a7 100644 --- a/com.twin.app.shoptime/src/reducers/mainReducer.js +++ b/com.twin.app.shoptime/src/reducers/mainReducer.js @@ -1,5 +1,10 @@ import { types } from '../actions/actionTypes'; import { CATEGORY_DATA_MAX_RESULTS_LIMIT } from '../utils/Config'; +import { createDebugHelpers } from '../utils/debug'; + +// 디버귞 헬퍌 섀정 +const DEBUG_MODE = false; +const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE); const initialState = { subCategoryData: {}, @@ -159,7 +164,7 @@ export const mainReducer = (state = initialState, action) => { const { data, lgCatCd } = action.payload; // ✹ DEBUG: Reducer에서 youmaylikeInfos 저장 확읞 - console.log('[DEBUG] Reducer - GET_HOME_FULL_VIDEO_INFO:', { + dlog('[DEBUG] Reducer - GET_HOME_FULL_VIDEO_INFO:', { youmaylikeInfos_length: data.youmaylikeInfos?.length, youmaylikeInfos: data.youmaylikeInfos, }); @@ -197,7 +202,7 @@ export const mainReducer = (state = initialState, action) => { }; } case types.CLEAR_SHOPNOW_INFO: - console.log('[DEBUG] Reducer - CLEAR_SHOPNOW_INFO called - youmaylikeInfos will be null'); + dlog('[DEBUG] Reducer - CLEAR_SHOPNOW_INFO called - youmaylikeInfos will be null'); return { ...state, fullVideolgCatCd: '', diff --git a/com.twin.app.shoptime/src/reducers/searchReducer.js b/com.twin.app.shoptime/src/reducers/searchReducer.js index a45ceed8..979dcc1c 100644 --- a/com.twin.app.shoptime/src/reducers/searchReducer.js +++ b/com.twin.app.shoptime/src/reducers/searchReducer.js @@ -1,4 +1,9 @@ import { types } from '../actions/actionTypes'; +import { createDebugHelpers } from '../utils/debug'; + +// 디버귞 헬퍌 섀정 +const DEBUG_MODE = false; +const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE); const initialState = { searchDatas: {}, @@ -81,8 +86,8 @@ export const searchReducer = (state = initialState, action) => { }; case types.RESET_VOICE_SEARCH: - console.log('[VoiceInput]-searchReducer-RESET_VOICE_SEARCH'); - console.log( + dlog('[VoiceInput]-searchReducer-RESET_VOICE_SEARCH'); + dlog( JSON.stringify( { action: 'RESET_VOICE_SEARCH', @@ -120,7 +125,7 @@ export const searchReducer = (state = initialState, action) => { const newPreKey = action.payload?.results?.[0]?.searchId || 'null'; const oldPreKey = state.preShopperHouseData?.results?.[0]?.searchId || 'null'; - console.log('[ShopperHouse]-DIFF (after backup) preShopperHouseKey:', oldPreKey, '→', newPreKey); + dlog('[ShopperHouse]-DIFF (after backup) preShopperHouseKey:', oldPreKey, '→', newPreKey); return { ...state, @@ -150,7 +155,16 @@ export const searchReducer = (state = initialState, action) => { const preSortingType = state.preShopperHouseData?.results?.[0]?.sortingType || 'null'; // [VoiceInput] Redux에 저장 로귞 - console.log('[ShopperHouse]-DIFF (after API) shopperHouseKey:', newKey, '| preShopperHouseKey:', preKey, '| sortingType:', sortingType || 'null', '| preSortingType:', preSortingType); + dlog( + '[ShopperHouse]-DIFF (after API) shopperHouseKey:', + newKey, + '| preShopperHouseKey:', + preKey, + '| sortingType:', + sortingType || 'null', + '| preSortingType:', + preSortingType + ); return { ...state, @@ -167,7 +181,7 @@ export const searchReducer = (state = initialState, action) => { } case types.SET_SHOPPERHOUSE_ERROR: - console.log('[VoiceInput] ❌ Redux shopperHouseError 저장:', action.payload); + dlog('[VoiceInput] ❌ Redux shopperHouseError 저장:', action.payload); return { ...state, shopperHouseError: action.payload, @@ -177,7 +191,7 @@ export const searchReducer = (state = initialState, action) => { }; case types.SHOW_SHOPPERHOUSE_ERROR: - console.log('[ShopperHouse] 🔎 Redux shopperHouseErrorPopup 표시:', action.payload); + dlog('[ShopperHouse] 🔎 Redux shopperHouseErrorPopup 표시:', action.payload); return { ...state, shopperHouseErrorPopup: { @@ -190,7 +204,7 @@ export const searchReducer = (state = initialState, action) => { }; case types.HIDE_SHOPPERHOUSE_ERROR: - console.log('[ShopperHouse] ✅ Redux shopperHouseErrorPopup 숚김'); + dlog('[ShopperHouse] ✅ Redux shopperHouseErrorPopup 숚김'); return { ...state, shopperHouseErrorPopup: { @@ -203,16 +217,13 @@ export const searchReducer = (state = initialState, action) => { }; case types.CLEAR_SHOPPERHOUSE_DATA: - console.log('[DEBUG] 🧹 Redux shopperHouseData 쎈Ʞ화 혞출 - 혞출 슀택 추적:'); - console.log( - '[DEBUG] 혞출 위치:', - new Error().stack?.split('\n')[1]?.trim() || '(슀택 추적 불가)' - ); - console.log( + dlog('[DEBUG] 🧹 Redux shopperHouseData 쎈Ʞ화 혞출 - 혞출 슀택 추적:'); + dlog('[DEBUG] 혞출 위치:', new Error().stack?.split('\n')[1]?.trim() || '(슀택 추적 불가)'); + dlog( '[VoiceInput] 🧹 Redux shopperHouseData 쎈Ʞ화 (searchId & relativeQueries & preShopperHouseData는 유지)' ); - console.log('[VoiceInput]-searchReducer-CLEAR_SHOPPERHOUSE_DATA'); - console.log( + dlog('[VoiceInput]-searchReducer-CLEAR_SHOPPERHOUSE_DATA'); + dlog( JSON.stringify( { shopperHouseData_cleared: true, @@ -239,7 +250,7 @@ export const searchReducer = (state = initialState, action) => { // 🔜 검색 메읞 데읎터 처늬 case types.GET_SEARCH_MAIN: { - console.log('🔍 [searchReducer] GET_SEARCH_MAIN 받은 payload:', action.payload); + dlog('🔍 [searchReducer] GET_SEARCH_MAIN 받은 payload:', action.payload); // 여러 가능한 구조 확읞 let resultData = null; @@ -247,15 +258,15 @@ export const searchReducer = (state = initialState, action) => { if (action.payload?.result) { // payload.result 구조 resultData = action.payload.result; - console.log('✅ [searchReducer] payload.result 구조 확읞'); + dlog('✅ [searchReducer] payload.result 구조 확읞'); } else if (action.payload?.data?.result) { // payload.data.result 구조 resultData = action.payload.data.result; - console.log('✅ [searchReducer] payload.data.result 구조 확읞'); + dlog('✅ [searchReducer] payload.data.result 구조 확읞'); } else if (action.payload?.data) { // payload.data에 직접 데읎터가 있는 겜우 resultData = action.payload.data; - console.log('✅ [searchReducer] payload.data 직접 구조 확읞'); + dlog('✅ [searchReducer] payload.data 직접 구조 확읞'); } if (!resultData) { @@ -264,7 +275,7 @@ export const searchReducer = (state = initialState, action) => { return state; } - console.log('[searchReducer] ✅ GET_SEARCH_MAIN success'); + dlog('[searchReducer] ✅ GET_SEARCH_MAIN success'); return { ...state, @@ -278,7 +289,7 @@ export const searchReducer = (state = initialState, action) => { } case types.CLEAR_SEARCH_MAIN_DATA: - console.log('[searchReducer] 🧹 searchMainData 쎈Ʞ화'); + dlog('[searchReducer] 🧹 searchMainData 쎈Ʞ화'); return { ...state, searchMainData: { @@ -291,7 +302,7 @@ export const searchReducer = (state = initialState, action) => { // 🎯 [Phase 1] SearchPanel 몚드 제얎 명령 case types.SWITCH_TO_SEARCH_INPUT_OVERLAY: - console.log('[searchReducer] 🔄 SWITCH_TO_SEARCH_INPUT_OVERLAY 명령 저장', { + dlog('[searchReducer] 🔄 SWITCH_TO_SEARCH_INPUT_OVERLAY 명령 저장', { source: action.payload?.source, timestamp: new Date().toISOString(), }); diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx index a9dabf68..1beae590 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx @@ -7,6 +7,12 @@ import Spotlight from '@enact/spotlight'; import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; +import { createDebugHelpers } from '../../../../utils/debug'; + +// 디버귞 헬퍌 섀정 +const DEBUG_MODE = false; +const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE); + // import icon_arrow_right from '../../../../../assets/images/icons'; import icon_arrow_dwon from '../../../../../assets/images/player/icon_tabcontainer_arrow_down.png'; import icon_shop_now from '../../../../../assets/images/player/icon_tabcontainer_shopnow.png'; @@ -74,7 +80,7 @@ export default function TabContainerV2({ // ✹ DEBUG: youmaylikeInfos 데읎터 로귞 useEffect(() => { - console.log('[DEBUG] TabContainerV2 - youmaylikeInfos:', { + dlog('[DEBUG] TabContainerV2 - youmaylikeInfos:', { exists: !!youmaylikeInfos, length: youmaylikeInfos?.length, data: youmaylikeInfos, 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 505d4fcd..046fb8ef 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 @@ -1,37 +1,19 @@ // src/views/SearchPanel/SearchPanel.new.jsx -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import classNames from 'classnames'; -import { - useDispatch, - useSelector, -} from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import Spotlight from '@enact/spotlight'; -import SpotlightContainerDecorator - from '@enact/spotlight/SpotlightContainerDecorator'; +import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; import micIcon from '../../../assets/images/searchpanel/image-mic.png'; import hotPicksImage from '../../../assets/images/searchpanel/img-hotpicks.png'; -import hotPicksBrandImage - from '../../../assets/images/searchpanel/img-search-hotpicks.png'; -import { - sendLogGNB, - sendLogTotalRecommend, -} from '../../actions/logActions'; +import hotPicksBrandImage from '../../../assets/images/searchpanel/img-search-hotpicks.png'; +import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions'; import { getMyRecommandedKeyword } from '../../actions/myPageActions'; -import { - popPanel, - pushPanel, - updatePanel, -} from '../../actions/panelActions'; +import { popPanel, pushPanel, updatePanel } from '../../actions/panelActions'; import { clearPanelCommand, clearShopperHouseData, @@ -51,36 +33,27 @@ import { // showWarningToast, // } from '../../actions/toastActions'; import TBody from '../../components/TBody/TBody'; -import TItemCardNew, { - removeDotAndColon, -} from '../../components/TItemCard/TItemCard.new'; +import TItemCardNew, { removeDotAndColon } from '../../components/TItemCard/TItemCard.new'; import TPanel from '../../components/TPanel/TPanel'; -import TVerticalPagenator - from '../../components/TVerticalPagenator/TVerticalPagenator'; -import TVirtualGridList - from '../../components/TVirtualGridList/TVirtualGridList'; +import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator'; +import TVirtualGridList from '../../components/TVirtualGridList/TVirtualGridList'; import usePanelHistory from '../../hooks/usePanelHistory/usePanelHistory'; // import VirtualKeyboardContainer from "../../components/TToast/VirtualKeyboardContainer"; import usePrevious from '../../hooks/usePrevious'; import { useSearchHistory } from '../../hooks/useSearchHistory'; -import { - LOG_CONTEXT_NAME, - LOG_MENU, - LOG_MESSAGE_ID, - panel_names, -} from '../../utils/Config'; +import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../utils/Config'; import NoSearchResults from './NoSearchResults/NoSearchResults'; // import NoSearchResults from './NoSearchResults/NoSearchResults'; import SearchInputOverlay from './SearchInputOverlay'; import css from './SearchPanel.new.module.less'; import SearchResultsNew from './SearchResults.new.v2'; -import TInputSimple, { - ICONS, - KINDS, -} from './TInput/TInputSimple'; -import VoiceInputOverlay, { - VOICE_MODES, -} from './VoiceInputOverlay/VoiceInputOverlay'; +import TInputSimple, { ICONS, KINDS } from './TInput/TInputSimple'; +import VoiceInputOverlay, { VOICE_MODES } from './VoiceInputOverlay/VoiceInputOverlay'; +import { createDebugHelpers } from '../../utils/debug'; + +// 디버귞 헬퍌 섀정 +const DEBUG_MODE = false; +const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE); /** * ✹ Mode-Based Architecture 도입 @@ -240,7 +213,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // 🐛 [DEBUG] shopperHouseData 상태 변겜 추적 (DEBUG_MODE가 true음 겜우에만) useEffect(() => { if (DEBUG_MODE) { - console.log('[DEBUG] 📊 SearchPanel shopperHouseData 상태 변겜:', { + dlog('[DEBUG] 📊 SearchPanel shopperHouseData 상태 변겜:', { hasData: !!shopperHouseData, dataLength: shopperHouseData?.results?.[0]?.docs?.length || 0, searchId: shopperHouseData?.results?.[0]?.searchId || '(없음)', @@ -256,7 +229,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // 🐛 [DEBUG] SearchPanel 마욎튞/얞마욎튞 추적 (DEBUG_MODE가 true음 겜우에만) useEffect(() => { if (DEBUG_MODE) { - console.log('[DEBUG] 🚀 SearchPanel 마욎튞됚 - 쎈Ʞ shopperHouseData 상태:', { + dlog('[DEBUG] 🚀 SearchPanel 마욎튞됚 - 쎈Ʞ shopperHouseData 상태:', { hasData: !!shopperHouseData, dataLength: shopperHouseData?.results?.[0]?.docs?.length || 0, currentMode, @@ -266,7 +239,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { return () => { if (DEBUG_MODE) { - console.log('[DEBUG] 🔚 SearchPanel 얞마욎튞됚 - shopperHouseData 상태:', { + dlog('[DEBUG] 🔚 SearchPanel 얞마욎튞됚 - shopperHouseData 상태:', { hasData: !!shopperHouseData, dataLength: shopperHouseData?.results?.[0]?.docs?.length || 0, timestamp: new Date().toISOString(), @@ -278,7 +251,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // 🐛 [DEBUG] isOnTop 상태 변겜 추적 (DetailPanel <-> SearchPanel 전환, DEBUG_MODE가 true음 겜우에만) useEffect(() => { if (isOnTopRef.current !== isOnTop && DEBUG_MODE) { - console.log('[DEBUG] 🔄 SearchPanel isOnTop 상태 변겜:', { + dlog('[DEBUG] 🔄 SearchPanel isOnTop 상태 변겜:', { from: isOnTopRef.current, to: isOnTop, shopperHouseData_preserved: !!shopperHouseData, @@ -317,7 +290,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // API 싀팚 시 fallback reference 쎈Ʞ화 useEffect(() => { if (shopperHouseErrorPopup?.visible && shopperHouseErrorPopup?.type === 'API_FAILURE') { - console.log('[SearchPanel] 🧹 API 싀팚 감지 - fallbackShopperHouseData 쎈Ʞ화'); + dlog('[SearchPanel] 🧹 API 싀팚 감지 - fallbackShopperHouseData 쎈Ʞ화'); shopperHouseDataRef.current = null; } }, [shopperHouseErrorPopup?.visible, shopperHouseErrorPopup?.type]); @@ -356,7 +329,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { currentPanel?.panelInfo?.currentSpot; if (DEBUG_MODE && isReturning) { - console.log('[FOCUS] 🎯 DetailPanel 복귀 감지:', { + dlog('[FOCUS] 🎯 DetailPanel 복귀 감지:', { current: currentPanel?.panelName, previous: previousPanel?.panelName, action: currentPanel?.action, @@ -449,9 +422,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // ✹ [Phase 4] Enter/OK í‚€ 처늬 - SearchInputOverlay 표시 if (e.key === 'Enter' || e.keyCode === 13) { - console.log( - '[DEBUG] [SearchPanel] TInputSimple에서 Enter/OK í‚€ 감지 → SearchInputOverlay 였픈' - ); + dlog('[DEBUG] [SearchPanel] TInputSimple에서 Enter/OK í‚€ 감지 → SearchInputOverlay 였픈'); e.preventDefault(); // ✹ [Phase 6] SearchInputOverlay 였픈 후 자동윌로 입력 쀀비 완료 @@ -525,7 +496,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // * 0hun: input에 포컀슀 발생하여 가상 킀볎드 활성 시, `isInputModeActive` 상태 Boolean 값 섀정 // */ // const handleInputModeChange = useCallback((isActive) => { - // console.log( + // dlog( // "[SearchPanel] TInput 입력 몚드:", // isActive ? "활성화 (킀볎드 표시)" : "비활성화 (킀볎드 숚김)" // ); @@ -613,7 +584,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { } if (DEBUG_MODE) { - console.log( + dlog( '🎀 [DEBUG][SearchPanel] openVoiceOverlay called, current isVoiceOverlayVisible:', isVoiceOverlayVisible ); @@ -636,7 +607,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { */ const onCancel = useCallback(() => { if (DEBUG_MODE) { - console.log('[DEBUG]-onCancel called', { + dlog('[DEBUG]-onCancel called', { isOnTop: isOnTopRef.current, isVoiceOverlayVisible, isSearchOverlayVisible, @@ -649,7 +620,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { if (!isOnTopRef.current) { if (DEBUG_MODE) { - console.log('[DEBUG]-onCancel: isOnTopRef is false, returning'); + dlog('[DEBUG]-onCancel: isOnTopRef is false, returning'); } return; } @@ -657,7 +628,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // VoiceInputOverlay가 엎렀있윌멎 뚌저 ë‹«êž° if (isVoiceOverlayVisible) { if (DEBUG_MODE) { - console.log('[DEBUG]-onCancel: closing VoiceInputOverlay'); + dlog('[DEBUG]-onCancel: closing VoiceInputOverlay'); } setIsVoiceOverlayVisible(false); return; @@ -666,7 +637,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // SearchInputOverlay가 엎렀있윌멎 뚌저 ë‹«êž° if (isSearchOverlayVisible) { if (DEBUG_MODE) { - console.log('[DEBUG]-onCancel: closing SearchInputOverlay'); + dlog('[DEBUG]-onCancel: closing SearchInputOverlay'); } handleSearchOverlayClose(); return; @@ -674,7 +645,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // ✹ [Phase 5] VOICE_RESULT 몚드에서 ESC/뒀로가Ʞ 누륎멎 INITIAL 몚드로 돌아가Ʞ if (DEBUG_MODE) { - console.log('[DEBUG]-VOICE_RESULT check:', { + dlog('[DEBUG]-VOICE_RESULT check:', { currentMode, isVoiceResultMode: currentMode === SEARCH_PANEL_MODES.VOICE_RESULT, VOICE_RESULT_value: SEARCH_PANEL_MODES.VOICE_RESULT, @@ -683,11 +654,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { if (currentMode === SEARCH_PANEL_MODES.VOICE_RESULT) { if (DEBUG_MODE) { - console.log( + dlog( '[DEBUG]-VOICE_RESULT: Clearing ShopperHouse data (searchId will be preserved for 2nd search)' ); - console.log('[VoiceInput]-SearchPanel-onCancel-VOICE_RESULT'); - console.log('[VoiceInput] 🧹 VOICE_RESULT 몚드에서 ESC 누멄 - clearShopperHouseData 혞출'); + dlog('[VoiceInput]-SearchPanel-onCancel-VOICE_RESULT'); + dlog('[VoiceInput] 🧹 VOICE_RESULT 몚드에서 ESC 누멄 - clearShopperHouseData 혞출'); } // 🎯 [포컀슀 로직 통합] 포컀슀는 상태 변겜에 의핎 자동윌로 처늬됚 setIsShopperHousePending(false); @@ -696,17 +667,17 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { } if (DEBUG_MODE) { - console.log('[DEBUG]-onCancel: normal cancel logic', { searchQuery }); + dlog('[DEBUG]-onCancel: normal cancel logic', { searchQuery }); } if (searchQuery === null || searchQuery === '') { if (DEBUG_MODE) { - console.log('[DEBUG]-onCancel: popping panel'); + dlog('[DEBUG]-onCancel: popping panel'); } dispatch(popPanel(panel_names.SEARCH_PANEL)); } else { if (DEBUG_MODE) { - console.log('[DEBUG]-onCancel: resetting search query'); + dlog('[DEBUG]-onCancel: resetting search query'); } setSearchQuery(''); // 🎯 [포컀슀 로직 통합] 포컀슀는 상태 변겜(searchQuery)에 의핎 자동윌로 처늬됚 @@ -820,7 +791,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { const analyzeCurrentScenario = useCallback(() => { // DEBUG: 몚든 Ʞ볞 상태값 출력 if (DEBUG_MODE) { - console.log('[DEBUG] analyzeCurrentScenario 혞출됚:', { + dlog('[DEBUG] analyzeCurrentScenario 혞출됚:', { // 🎯 Ʞ졎 isOnTop곌 usePanelHistory의 isOnTop 비교 propIsOnTop: isOnTop, historyIsOnTop: currentIsOnTop, @@ -845,8 +816,8 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { if (isReturningFromDetailPanel) { const currentSpot = currentPanel?.panelInfo?.currentSpot; if (DEBUG_MODE) { - console.log('[Focus] usePanelHistory로 DetailPanel 복귀 감지 - 읎전 상품윌로 포컀슀 읎동'); - console.log('[FOCUS] 🎯 Scenario: DETAIL_PANEL_RETURN (usePanelHistory)', { + dlog('[Focus] usePanelHistory로 DetailPanel 복귀 감지 - 읎전 상품윌로 포컀슀 읎동'); + dlog('[FOCUS] 🎯 Scenario: DETAIL_PANEL_RETURN (usePanelHistory)', { currentSpot, mode: currentMode, fromSearchResult: currentMode === SEARCH_PANEL_MODES.SEARCH_RESULT, @@ -862,7 +833,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // 🎯 [개선된 fallback] usePanelHistory의 isOnTop 정볎 활용 // DetailPanel에서 방ꞈ 복귀한 상황 (usePanelHistory가 없을 겜우륌 대비) if (DEBUG_MODE) { - console.log('[DEBUG] 개선된 DETAIL_PANEL_RETURN 조걎 확읞 (fallback):', { + dlog('[DEBUG] 개선된 DETAIL_PANEL_RETURN 조걎 확읞 (fallback):', { // 🎯 여러 isOnTop 소슀 비교 propIsOnTop: isOnTop, historyIsOnTop: currentIsOnTop, @@ -889,8 +860,8 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { ) { const usedHistoryOnTop = currentIsOnTop && isOnTopChange?.becameOnTop; if (DEBUG_MODE) { - console.log('[Focus] 개선된 방식윌로 DetailPanel 복귀 감지 - 읎전 상품윌로 포컀슀 읎동'); - console.log('[FOCUS] 🎯 Scenario: DETAIL_PANEL_RETURN (improved fallback)', { + dlog('[Focus] 개선된 방식윌로 DetailPanel 복귀 감지 - 읎전 상품윌로 포컀슀 읎동'); + dlog('[FOCUS] 🎯 Scenario: DETAIL_PANEL_RETURN (improved fallback)', { currentSpot: panelInfo.currentSpot, mode: currentMode, fromSearchResult: currentMode === SEARCH_PANEL_MODES.SEARCH_RESULT, @@ -908,7 +879,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // - 위의 DETAIL_PANEL_RETURN읎 아닌 겜우 (= currentSpot읎 없거나 몚드가 검색 결곌 아님) if (isOnTop && !isOnTopRef.current) { if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 Scenario: INITIAL_OPEN', { + dlog('[FOCUS] 🎯 Scenario: INITIAL_OPEN', { currentSpot: panelInfo?.currentSpot, mode: currentMode, }); @@ -927,7 +898,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { currentModeRef.current !== SEARCH_PANEL_MODES.SEARCH_RESULT ) { if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 Scenario: SEARCH_RESULT_LOADED (Mode Changed)', { + dlog('[FOCUS] 🎯 Scenario: SEARCH_RESULT_LOADED (Mode Changed)', { themeCount: searchDatas?.theme?.length || 0, itemCount: searchDatas?.item?.length || 0, showCount: searchDatas?.show?.length || 0, @@ -948,10 +919,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { currentMode === SEARCH_PANEL_MODES.VOICE_RESULT && shopperHouseData && // 🎯 [개선] 몚드 변겜 OR 새로욎 데읎터 도착 감지 - (currentModeRef.current !== SEARCH_PANEL_MODES.VOICE_RESULT || shopperHouseDataRef.current !== shopperHouseData) + (currentModeRef.current !== SEARCH_PANEL_MODES.VOICE_RESULT || + shopperHouseDataRef.current !== shopperHouseData) ) { if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 Scenario: NEW_SEARCH_LOADED (Voice Result Mode)', { + dlog('[FOCUS] 🎯 Scenario: NEW_SEARCH_LOADED (Voice Result Mode)', { itemCount: shopperHouseData?.results?.[0]?.docs?.length || 0, prevMode: currentModeRef.current, nextMode: currentMode, @@ -966,7 +938,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // Voice Overlay가 닫힌 상황 if (!isVoiceOverlayVisible && isVoiceOverlayVisibleRef.current) { if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 Scenario: VOICE_OVERLAY_CLOSED', { + dlog('[FOCUS] 🎯 Scenario: VOICE_OVERLAY_CLOSED', { hasShopperHouseData: !!shopperHouseData, }); } @@ -974,7 +946,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // 읎렇게 하멎 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 우선 처늬'); + dlog('[FOCUS] 🔄 VOICE_OVERLAY_CLOSED + new data → NEW_SEARCH_LOADED 우선 처늬'); } return 'NEW_SEARCH_LOADED'; } @@ -986,7 +958,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // - 검색읎 수행되지 않았거나 SearchPanel읎 SEARCH_RESULT 몚드가 아닌 겜우 if (!isSearchOverlayVisible && isSearchOverlayVisibleRef.current) { if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED', { + dlog('[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED', { isSearchOverlayVisible, prevIsSearchOverlayVisible: isSearchOverlayVisibleRef.current, currentMode, @@ -1040,25 +1012,25 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { if (isReturningFromDetailPanel && currentPanel?.panelInfo?.currentSpot) { currentSpot = currentPanel.panelInfo.currentSpot; if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 usePanelHistory currentSpot 사용:', currentSpot); + dlog('[FOCUS] 🎯 usePanelHistory currentSpot 사용:', currentSpot); } } // 2. fallback: Ʞ졎 panelInfo.currentSpot 사용 else if (panelInfo?.currentSpot) { currentSpot = panelInfo.currentSpot; if (DEBUG_MODE) { - console.log('[FOCUS] 🔄 fallback윌로 panelInfo.currentSpot 사용:', currentSpot); + dlog('[FOCUS] 🔄 fallback윌로 panelInfo.currentSpot 사용:', currentSpot); } } if (currentSpot && currentSpot.startsWith('searchItemContents')) { if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 DETAIL_PANEL_RETURN: 읎전 상품윌로 포컀슀 복원:', currentSpot); + dlog('[FOCUS] 🎯 DETAIL_PANEL_RETURN: 읎전 상품윌로 포컀슀 복원:', currentSpot); } return currentSpot; } else { if (DEBUG_MODE) { - console.log( + dlog( '[FOCUS] ⚠ DETAIL_PANEL_RETURN: currentSpot읎 유횚하지 않음, fallback윌로 읎동:', { currentSpot, @@ -1094,7 +1066,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // SearchInputOverlay에서 검색을 싀행하멎 isSearchOverlayVisible읎 false로 섀정되고 // 동시에 검색 결곌에 따띌 몚드가 변겜되므로, 읎 쌀읎슀는 검색얎 선택 후 닫을 때만 발생 if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED - TInputSimple윌로 포컀슀'); + dlog('[FOCUS] 🎯 Scenario: SEARCH_OVERLAY_CLOSED - TInputSimple윌로 포컀슀'); } return SPOTLIGHT_IDS.SEARCH_INPUT_BOX; @@ -1118,7 +1090,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { */ const handleTransitionToSearchInput = useCallback(() => { if (DEBUG_MODE) { - console.log('[SearchPanel] 🔄 handleTransitionToSearchInput 혞출'); + dlog('[SearchPanel] 🔄 handleTransitionToSearchInput 혞출'); } // Redux Thunk 액션윌로 몚든 전환 로직 처늬 @@ -1135,12 +1107,12 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { * Search overlay close handler */ const handleSearchOverlayClose = useCallback(() => { - console.log('[DEBUG] 🚪 handleSearchOverlayClose 혞출됚 - 직접 확읞!', { + dlog('[DEBUG] 🚪 handleSearchOverlayClose 혞출됚 - 직접 확읞!', { timestamp: new Date().toISOString(), }); if (DEBUG_MODE) { - console.log('[DEBUG] 🚪 SearchInputOverlay closing'); + dlog('[DEBUG] 🚪 SearchInputOverlay closing'); } const hasSearchResults = @@ -1149,11 +1121,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { (searchDatas?.show?.length || 0) > 0; // 🎯 SearchInputOverlay 닫힘 후 TInputSimple윌로 포컀슀 읎동을 위한 플래귞 섀정 - console.log('[DEBUG] setShouldFocusSearchInput(true) 섀정 직전', { + dlog('[DEBUG] setShouldFocusSearchInput(true) 섀정 직전', { timestamp: new Date().toISOString(), }); setShouldFocusSearchInput(true); - console.log('[DEBUG] setShouldFocusSearchInput(true) 섀정됚!', { + dlog('[DEBUG] setShouldFocusSearchInput(true) 섀정됚!', { timestamp: new Date().toISOString(), }); @@ -1171,7 +1143,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { */ const handleVoiceOverlayClose = useCallback(() => { if (DEBUG_MODE) { - console.log( + dlog( '🚪 [DEBUG][SearchPanel] handleVoiceOverlayClose called, setting isVoiceOverlayVisible to FALSE' ); } @@ -1213,7 +1185,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // Redux state 업데읎튞륌 위핎 앜간의 지연 후 API 혞출 setTimeout(() => { - console.log('[HowAboutThese] 🔄 Redux 업데읎튞 후 API 혞출'); + dlog('[HowAboutThese] 🔄 Redux 업데읎튞 후 API 혞출'); dispatch(getShopperHouseSearch(trimmedQuery, shopperHouseSearchId)); }, 50); // 50ms 지연 @@ -1337,40 +1309,40 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { [hotPicksForYou, dispatch, SafeImage] ); - const handleClick = useCallback((patnrId, prdtId) => { - dispatch( - pushPanel({ - name: panel_names.DETAIL_PANEL, - panelInfo: { patnrId, prdtId }, - }) - ); - },[dispatch]) - + const handleClick = useCallback( + (patnrId, prdtId) => { + dispatch( + pushPanel({ + name: panel_names.DETAIL_PANEL, + panelInfo: { patnrId, prdtId }, + }) + ); + }, + [dispatch] + ); const renderTsvItem = useCallback( - ({ index, ...rest }) => { - const { offerInfo, prdtId, imgUrl, patnrId, prdtNm, priceInfo } = - tsvInfo[index]; - - return ( - {handleClick(patnrId,prdtId)}} - offerInfo={offerInfo} - priceInfo={priceInfo} - productId={prdtId} - productName={prdtNm} - spotlightId={ - "searchMain-tsvInfo-spotlightId-" + removeDotAndColon(prdtId) - } - {...rest} - /> - ); - }, - [tsvInfo,handleClick] - ); + ({ index, ...rest }) => { + const { offerInfo, prdtId, imgUrl, patnrId, prdtNm, priceInfo } = tsvInfo[index]; + return ( + { + handleClick(patnrId, prdtId); + }} + offerInfo={offerInfo} + priceInfo={priceInfo} + productId={prdtId} + productName={prdtNm} + spotlightId={'searchMain-tsvInfo-spotlightId-' + removeDotAndColon(prdtId)} + {...rest} + /> + ); + }, + [tsvInfo, handleClick] + ); /** * ✹ [Phase 2] 몚드별 윘텐잠 렌더링 (VoiceInputOverlay의 renderModeContent와 동음한 팹턮) @@ -1553,7 +1525,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) {
- )} - ); } @@ -1606,7 +1576,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { let nextMode = SEARCH_PANEL_MODES.INITIAL; if (DEBUG_MODE) { - console.log('[DEBUG]-MODE DECISION useEffect running', { + dlog('[DEBUG]-MODE DECISION useEffect running', { isVoiceOverlayVisible, hasShopperHouseData: !!shopperHouseData, shopperHouseData_detail: shopperHouseData ? 'EXISTS' : 'NULL', @@ -1626,14 +1596,14 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // 우선순위 1: 음성 입력 였버레읎가 엎렀있윌멎 VOICE_INPUT 몚드 if (isVoiceOverlayVisible) { if (DEBUG_MODE) { - console.log('[DEBUG]-MODE: isVoiceOverlayVisible is TRUE → VOICE_INPUT'); + dlog('[DEBUG]-MODE: isVoiceOverlayVisible is TRUE → VOICE_INPUT'); } nextMode = SEARCH_PANEL_MODES.VOICE_INPUT; } // 우선순위 2: 음성 검색 결곌가 있윌멎 VOICE_RESULT 몚드 else if (shopperHouseData || isShopperHousePending) { if (DEBUG_MODE) { - console.log('[DEBUG]-MODE: shopperHouseData EXISTS or pending → VOICE_RESULT', { + dlog('[DEBUG]-MODE: shopperHouseData EXISTS or pending → VOICE_RESULT', { hasData: !!shopperHouseData, isPending: isShopperHousePending, }); @@ -1648,21 +1618,21 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { searchDatas?.show?.length > 0 ) { if (DEBUG_MODE) { - console.log('[DEBUG]-MODE: searchResults EXISTS → SEARCH_RESULT'); + dlog('[DEBUG]-MODE: searchResults EXISTS → SEARCH_RESULT'); } nextMode = SEARCH_PANEL_MODES.SEARCH_RESULT; } // 우선순위 4: 검색 입력 였버레읎가 엎렀있윌멎 SEARCH_INPUT 몚드 else if (isSearchOverlayVisible) { if (DEBUG_MODE) { - console.log('[DEBUG]-MODE: isSearchOverlayVisible is TRUE → SEARCH_INPUT'); + dlog('[DEBUG]-MODE: isSearchOverlayVisible is TRUE → SEARCH_INPUT'); } nextMode = SEARCH_PANEL_MODES.SEARCH_INPUT; } // 우선순위 5: 쎈Ʞ 상태 (Ʞ볞값) else { if (DEBUG_MODE) { - console.log('[DEBUG]-MODE: No condition met → INITIAL'); + dlog('[DEBUG]-MODE: No condition met → INITIAL'); } nextMode = SEARCH_PANEL_MODES.INITIAL; } @@ -1670,7 +1640,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // 몚드가 변겜되었을 때만 업데읎튞 if (nextMode !== currentMode) { if (DEBUG_MODE) { - console.log(`[DEBUG]-VOICE_RESULT 🔀 Mode changed: ${currentMode} → ${nextMode}`, { + dlog(`[DEBUG]-VOICE_RESULT 🔀 Mode changed: ${currentMode} → ${nextMode}`, { isVoiceOverlayVisible, shopperHouseData: !!shopperHouseData, isShopperHousePending, @@ -1688,7 +1658,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { setCurrentMode(nextMode); } else { if (DEBUG_MODE) { - console.log('[DEBUG]-MODE: Mode unchanged -', currentMode); + dlog('[DEBUG]-MODE: Mode unchanged -', currentMode); } } }, [ @@ -1711,11 +1681,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { */ useEffect(() => { if (DEBUG_MODE) { - console.log('[DEBUG]-searchQuery useEffect:', { searchQuery }); + dlog('[DEBUG]-searchQuery useEffect:', { searchQuery }); } if (!searchQuery) { if (DEBUG_MODE) { - console.log('[DEBUG]-VOICE_RESULT: searchQuery is empty, calling resetSearch'); + dlog('[DEBUG]-VOICE_RESULT: searchQuery is empty, calling resetSearch'); } dispatch(resetSearch()); } @@ -1757,7 +1727,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { */ useEffect(() => { if (DEBUG_MODE) { - console.log('[DEBUG][Focus] Focus useEffect 혞출됚 - 상태값 확읞:', { + dlog('[DEBUG][Focus] Focus useEffect 혞출됚 - 상태값 확읞:', { isOnTop, panelInfo: panelInfo, currentMode, @@ -1809,9 +1779,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // NEW_SEARCH_LOADED: 음성 검색 결곌 로드 시 VoiceInputOverlay와 충돌 방지 // 닀륞 시나늬였에서는 Ʞ졎곌 같은 지연 시간 (100ms) const focusDelay = - scenario === 'DETAIL_PANEL_RETURN' || scenario === 'NEW_SEARCH_LOADED' - ? 50 - : 100; + scenario === 'DETAIL_PANEL_RETURN' || scenario === 'NEW_SEARCH_LOADED' ? 50 : 100; unifiedFocusTimerRef.current = setTimeout(() => { const targetElement = document.querySelector(`[data-spotlight-id="${targetId}"]`); @@ -1819,7 +1787,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { if (targetElement || targetId === SPOTLIGHT_IDS.SEARCH_INPUT_BOX) { Spotlight.focus(targetId); if (DEBUG_MODE) { - console.log('[FOCUS] ✅ 포컀슀 읎동 완료:', { + dlog('[FOCUS] ✅ 포컀슀 읎동 완료:', { targetId, scenario, hasElement: !!targetElement, @@ -1829,7 +1797,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { } } else { if (DEBUG_MODE) { - console.log('[FOCUS] ⚠ 포컀슀 대상 요소륌 ì°Ÿì§€ 못했습니닀:', { + dlog('[FOCUS] ⚠ 포컀슀 대상 요소륌 ì°Ÿì§€ 못했습니닀:', { targetId, scenario, timestamp: new Date().toISOString(), @@ -1842,7 +1810,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { const fallbackElement = document.querySelector(`[data-spotlight-id="${fallbackTarget}"]`); if (fallbackElement) { if (DEBUG_MODE) { - console.log( + dlog( '[FOCUS] 🔄 DETAIL_PANEL_RETURN fallback: 첫 번짞 상품윌로 포컀슀:', fallbackTarget ); @@ -1860,7 +1828,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { if (scenario === 'NEW_SEARCH_LOADED' && targetId === 'searchItemContents0') { setTimeout(() => { if (DEBUG_MODE) { - console.log('[FOCUS] 🔄 NEW_SEARCH_LOADED: 1쎈 후 첫 번짞 상품윌로 닀시 포컀슀 읎동'); + dlog('[FOCUS] 🔄 NEW_SEARCH_LOADED: 1쎈 후 첫 번짞 상품윌로 닀시 포컀슀 읎동'); } Spotlight.focus('searchItemContents0'); }, 500); // 0.5쎈 후 @@ -1908,7 +1876,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { * - 자동윌로 플래귞 쎈Ʞ화 */ useEffect(() => { - console.log('[DEBUG] shouldFocusSearchInput useEffect 싀행됚!', { + dlog('[DEBUG] shouldFocusSearchInput useEffect 싀행됚!', { shouldFocusSearchInput, timestamp: new Date().toISOString(), }); @@ -1916,12 +1884,12 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { if (shouldFocusSearchInput) { let focusTimer = null; - console.log('[DEBUG] shouldFocusSearchInput === true, 타읎뚞 섀정 쀑...', { + dlog('[DEBUG] shouldFocusSearchInput === true, 타읎뚞 섀정 쀑...', { timestamp: new Date().toISOString(), }); if (DEBUG_MODE) { - console.log('[FOCUS] 🎯 SearchInputOverlay 닫힘 후 포컀슀 ꎀ늬 useEffect 싀행', { + dlog('[FOCUS] 🎯 SearchInputOverlay 닫힘 후 포컀슀 ꎀ늬 useEffect 싀행', { shouldFocusSearchInput, timestamp: new Date().toISOString(), }); @@ -1929,65 +1897,62 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { // 500ms 후 TInputSimple에 포컀슀 읎동 focusTimer = setTimeout(() => { - console.log('[DEBUG] ⏰ 500ms 타읎뚞 윜백 싀행!', { + dlog('[DEBUG] ⏰ 500ms 타읎뚞 윜백 싀행!', { targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX, timestamp: new Date().toISOString(), }); if (DEBUG_MODE) { - console.log('[FOCUS] ⏰ 500ms 타읎뚞 윜백 싀행 - TInputSimple윌로 포컀슀 읎동', { + dlog('[FOCUS] ⏰ 500ms 타읎뚞 윜백 싀행 - TInputSimple윌로 포컀슀 읎동', { targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX, timestamp: new Date().toISOString(), }); } - console.log('[DEBUG] Spotlight.focus() 혞출 직전', { + dlog('[DEBUG] Spotlight.focus() 혞출 직전', { targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX, }); Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX); - console.log('[DEBUG] Spotlight.focus() 혞출 완료!', { + dlog('[DEBUG] Spotlight.focus() 혞출 완료!', { targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX, timestamp: new Date().toISOString(), }); if (DEBUG_MODE) { - console.log('[FOCUS] ✅ Spotlight.focus() 혞출 완료', { + dlog('[FOCUS] ✅ Spotlight.focus() 혞출 완료', { targetId: SPOTLIGHT_IDS.SEARCH_INPUT_BOX, timestamp: new Date().toISOString(), }); } - console.log('[DEBUG] setShouldFocusSearchInput(false) 혞출 직전', { + dlog('[DEBUG] setShouldFocusSearchInput(false) 혞출 직전', { timestamp: new Date().toISOString(), }); // 포컀슀 읎동 완료 후 플래귞 쎈Ʞ화 setShouldFocusSearchInput(false); - console.log('[DEBUG] setShouldFocusSearchInput(false) 혞출 완료!', { + dlog('[DEBUG] setShouldFocusSearchInput(false) 혞출 완료!', { timestamp: new Date().toISOString(), }); }, 500); - console.log('[DEBUG] 타읎뚞 섀정 완료 - 500ms 후 포컀슀 읎동 예앜됚', { + dlog('[DEBUG] 타읎뚞 섀정 완료 - 500ms 후 포컀슀 읎동 예앜됚', { timestamp: new Date().toISOString(), }); // Cleanup: 타읎뚞 정늬 return () => { - console.log('[DEBUG] shouldFocusSearchInput useEffect cleanup 싀행', { + dlog('[DEBUG] shouldFocusSearchInput useEffect cleanup 싀행', { timestamp: new Date().toISOString(), }); if (focusTimer) { if (DEBUG_MODE) { - console.log( - '[FOCUS] 🧹 SearchInputOverlay 포컀슀 ꎀ늬 useEffect cleanup - 타읎뚞 정늬', - { - timestamp: new Date().toISOString(), - } - ); + dlog('[FOCUS] 🧹 SearchInputOverlay 포컀슀 ꎀ늬 useEffect cleanup - 타읎뚞 정늬', { + timestamp: new Date().toISOString(), + }); } clearTimeout(focusTimer); } @@ -2149,7 +2114,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { } // ✅ INITIAL, VOICE_RESULT & SEARCH_RESULT 몚드에서 TInputSimple 낎부 포컀슀 활성화 onKeyDown={handleKeydown} onMouseDown={() => { - console.log( + dlog( '[DEBUG] [SearchPanel] TInputSimple에서 마우슀 큎늭 감지 → SearchInputOverlay 였픈' ); setIsSearchOverlayVisible(true); diff --git a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx index a80868ac..1a33691f 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx @@ -34,6 +34,7 @@ import { readLocalStorage, writeLocalStorage } from '../../../utils/helperMethod import TInputSimple, { ICONS, KINDS } from '../TInput/TInputSimple'; import ApiStatusDisplay from './ApiStatusDisplay'; import VoiceApiError from './modes/VoiceApiError'; +import { createDebugHelpers } from '../../../utils/debug'; import VoiceListening from './modes/VoiceListening'; import VoiceNotRecognized from './modes/VoiceNotRecognized'; import VoiceNotRecognizedCircle from './modes/VoiceNotRecognizedCircle'; @@ -56,6 +57,7 @@ const SpottableDebugButton = Spottable('div'); // Debug mode constant - 항상 디버귞 화멎 표시 const DEBUG_MODE = false; +const { dlog, dwarn, derror } = createDebugHelpers(DEBUG_MODE); // Voice overlay 몚드 상수 export const VOICE_MODES = { @@ -150,7 +152,7 @@ const VoiceInputOverlay = ({ externalShopperHouseData = null, // 🎯 [포컀슀 충돌 핎결] 왞부 음성 검색 결곌 데읎터 }) => { if (DEBUG_MODE) { - console.log('🔄 [DEBUG] VoiceInputOverlay render - isVisible:', isVisible, 'mode:', mode); + dlog('🔄 [DEBUG] VoiceInputOverlay render - isVisible:', isVisible, 'mode:', mode); } const dispatch = useDispatch(); @@ -198,7 +200,7 @@ const VoiceInputOverlay = ({ const [webSpeechEventLogs, setWebSpeechEventLogs] = useState(() => { const persisted = readLocalStorage(VOICE_EVENT_LOGS_KEY, []); if (DEBUG_MODE) { - console.log('📚 [DEBUG] Loaded webSpeechEventLogs from localStorage:', persisted); + dlog('📚 [DEBUG] Loaded webSpeechEventLogs from localStorage:', persisted); } return persisted; }); @@ -222,7 +224,7 @@ const VoiceInputOverlay = ({ const [legacySearchHistory, setLegacySearchHistory] = useState(() => { const history = readLocalStorage(SEARCH_HISTORY_KEY, DEFAULT_SUGGESTIONS); if (DEBUG_MODE) { - console.log('📚 [DEBUG] Loaded legacy searchHistory from localStorage:', history); + dlog('📚 [DEBUG] Loaded legacy searchHistory from localStorage:', history); } return history; }); @@ -231,11 +233,11 @@ const VoiceInputOverlay = ({ // ⭐ isVisible prop 변겜 추적 useEffect(() => { - console.log('👁 [DEBUG][VoiceInputOverlay] isVisible prop changed to:', isVisible); + dlog('👁 [DEBUG][VoiceInputOverlay] isVisible prop changed to:', isVisible); if (isVisible) { - console.log('📺 [DEBUG][VoiceInputOverlay] Overlay is now VISIBLE, mode:', currentMode); + dlog('📺 [DEBUG][VoiceInputOverlay] Overlay is now VISIBLE, mode:', currentMode); } else { - console.log('🙈 [DEBUG][VoiceInputOverlay] Overlay is now HIDDEN'); + dlog('🙈 [DEBUG][VoiceInputOverlay] Overlay is now HIDDEN'); } }, [isVisible, currentMode]); @@ -268,7 +270,7 @@ const VoiceInputOverlay = ({ }; if (DEBUG_MODE) { - console.log(`[WebSpeech Event] ${event}: ${details}`); + dlog(`[WebSpeech Event] ${event}: ${details}`); } setWebSpeechEventLogs((prev) => { @@ -281,11 +283,9 @@ const VoiceInputOverlay = ({ // ⭐ currentMode 변겜 추적 useEffect(() => { - console.log('🔀 [DEBUG][VoiceInputOverlay] currentMode changed to:', currentMode); + dlog('🔀 [DEBUG][VoiceInputOverlay] currentMode changed to:', currentMode); if (isVisible) { - console.log( - `📍 [DEBUG][VoiceInputOverlay] Current state: isVisible=true, mode=${currentMode}` - ); + dlog(`📍 [DEBUG][VoiceInputOverlay] Current state: isVisible=true, mode=${currentMode}`); // 몚드 변겜 읎벀튞 로깅 addWebSpeechEventLog('MODE_CHANGE', `Mode switched to: ${currentMode}`); } @@ -296,7 +296,7 @@ const VoiceInputOverlay = ({ if (webSpeechEventLogs.length > 0) { writeLocalStorage(VOICE_EVENT_LOGS_KEY, webSpeechEventLogs); if (DEBUG_MODE) { - console.log( + dlog( '💟 [DEBUG] Saved webSpeechEventLogs to localStorage:', webSpeechEventLogs.length, 'logs' @@ -329,14 +329,14 @@ const VoiceInputOverlay = ({ writeLocalStorage(SEARCH_HISTORY_KEY, newHistory); if (DEBUG_MODE) { - console.log('💟 [VoiceInputOverlay.v2] Legacy search history updated:', newHistory); + dlog('💟 [VoiceInputOverlay.v2] Legacy search history updated:', newHistory); } return newHistory; }); if (DEBUG_MODE) { - console.log( + dlog( '🎀 [VoiceInputOverlay] Voice search added to history:', trimmedText, 'searchId:', @@ -383,12 +383,12 @@ const VoiceInputOverlay = ({ // 🎯 API 싀팚 감지 - APIERROR 몚드로 전환 useEffect(() => { if (shopperHouseErrorPopup?.visible && shopperHouseErrorPopup?.type === 'API_FAILURE') { - console.log('[VoiceInputOverlay] 🚚 API 싀팚 감지 - APIERROR 몚드로 전환'); + dlog('[VoiceInputOverlay] 🚚 API 싀팚 감지 - APIERROR 몚드로 전환'); setCurrentMode(VOICE_MODES.APIERROR); // 3쎈 후 자동윌로 PROMPT 몚드로 복귀 const timer = setTimeout(() => { - console.log('[VoiceInputOverlay] ⏰ 3쎈 후 PROMPT 몚드로 복귀'); + dlog('[VoiceInputOverlay] ⏰ 3쎈 후 PROMPT 몚드로 복귀'); setCurrentMode(VOICE_MODES.PROMPT); }, 3000); @@ -398,15 +398,15 @@ const VoiceInputOverlay = ({ // 🎯 VoiceResponse 에러 핞듀러 - 빈 query 처늬 const handleVoiceResponseError = useCallback((error) => { - console.log('[VoiceInputOverlay] ⚠ VoiceResponse 에러 수신:', error); + dlog('[VoiceInputOverlay] ⚠ VoiceResponse 에러 수신:', error); if (error.type === 'EMPTY_QUERY') { - console.log('[VoiceInputOverlay] 🚚 빈 query 에러 - NOTRECOGNIZED 몚드로 전환'); + dlog('[VoiceInputOverlay] 🚚 빈 query 에러 - NOTRECOGNIZED 몚드로 전환'); setCurrentMode(VOICE_MODES.NOTRECOGNIZED); // 3쎈 후 자동윌로 PROMPT 몚드로 복귀 const timer = setTimeout(() => { - console.log('[VoiceInputOverlay] ⏰ 3쎈 후 PROMPT 몚드로 복귀 (빈 query 에러)'); + dlog('[VoiceInputOverlay] ⏰ 3쎈 후 PROMPT 몚드로 복귀 (빈 query 에러)'); setCurrentMode(VOICE_MODES.PROMPT); }, 3000); @@ -421,14 +421,14 @@ const VoiceInputOverlay = ({ useEffect(() => { shopperHouseSearchIdRef.current = shopperHouseSearchId; if (shopperHouseSearchId) { - console.log('[VoiceInput] 🔄 searchId ref 업데읎튞:', shopperHouseSearchId); + dlog('[VoiceInput] 🔄 searchId ref 업데읎튞:', shopperHouseSearchId); } }, [shopperHouseSearchId]); // 🔍 DEBUG: shopperHouseData 변겜 추적 useEffect(() => { if (DEBUG_MODE) { - console.log('🔍 [DEBUG] shopperHouseData changed:', { + dlog('🔍 [DEBUG] shopperHouseData changed:', { shopperHouseData, refValue: shopperHouseDataRef.current, isVisible, @@ -440,7 +440,7 @@ const VoiceInputOverlay = ({ // 🔄 WebSpeech 에러 재시작 핚수 const restartWebSpeech = useCallback(() => { if (DEBUG_MODE) { - console.log('[VoiceInput] 🔄 Restarting WebSpeech after error'); + dlog('[VoiceInput] 🔄 Restarting WebSpeech after error'); } // 읎벀튞 로귞 Ʞ록 @@ -479,7 +479,7 @@ const VoiceInputOverlay = ({ // 앜간의 지연 후 새로 시작 (안정성을 위핎) setTimeout(() => { if (DEBUG_MODE) { - console.log('[VoiceInput] ✅ Restart complete - ready for new input'); + dlog('[VoiceInput] ✅ Restart complete - ready for new input'); } }, 300); }, [dispatch, onSearchChange, addWebSpeechEventLog]); @@ -489,7 +489,7 @@ const VoiceInputOverlay = ({ // Bubble 큎늭윌로 검색읎 시작된 겜우 WebSpeech 였류륌 우회 if (isBubbleClickSearch) { if (DEBUG_MODE) { - console.log('[VoiceInput] 🔇 WebSpeech 였류 우회 (bubble click search)'); + dlog('[VoiceInput] 🔇 WebSpeech 였류 우회 (bubble click search)'); } return; } @@ -540,20 +540,20 @@ const VoiceInputOverlay = ({ // 음성 읞식 쀑지 if (isListening) { - console.log('[VoiceInput] 🛑 Stopping listening due to error'); + dlog('[VoiceInput] 🛑 Stopping listening due to error'); stopListening(); } // 에러 몚드로 전환 (NOTRECOGNIZED) - 사용자에게 에러 상태 표시 if (isVisible) { - console.log('[VoiceInput] 🔀 Switching to NOTRECOGNIZED mode due to error'); + dlog('[VoiceInput] 🔀 Switching to NOTRECOGNIZED mode due to error'); setCurrentMode(VOICE_MODES.NOTRECOGNIZED); setVoiceInputMode(null); // 음부 에러 타입은 자동 재시작 시도 const autoRetryErrors = ['network', 'aborted', 'service-not-allowed']; if (autoRetryErrors.includes(errorType)) { - console.log('[VoiceInput] 🔄 Auto-restarting for error type:', errorType); + dlog('[VoiceInput] 🔄 Auto-restarting for error type:', errorType); setTimeout(() => { restartWebSpeech(); }, 2000); // 2쎈 후 자동 재시작 @@ -640,7 +640,7 @@ const VoiceInputOverlay = ({ // ⚠ 최적화: 싀시간 상태 표시 제거, 결곌만 표시 useEffect(() => { if (DEBUG_MODE) { - console.log('🔍 [DEBUG] shopperHouseError useEffect running:', { + dlog('🔍 [DEBUG] shopperHouseError useEffect running:', { isVisible, hasError: !!shopperHouseError, error: shopperHouseError, @@ -650,7 +650,7 @@ const VoiceInputOverlay = ({ // ✹ 쎈Ʞ화 쀑에는 였류 처늬 안 핹 if (isInitializingRef.current) { if (DEBUG_MODE) { - console.log('🔍 [DEBUG] Skipping error check - overlay is initializing'); + dlog('🔍 [DEBUG] Skipping error check - overlay is initializing'); } return; } @@ -658,7 +658,7 @@ const VoiceInputOverlay = ({ // 였류가 발생한 겜우 - API 상태 표시 업데읎튞만 (팝업 대신) if (shopperHouseError && isVisible) { if (DEBUG_MODE) { - console.log('[VoiceInputOverlay] ❌ API error - showing result only:', shopperHouseError); + dlog('[VoiceInputOverlay] ❌ API error - showing result only:', shopperHouseError); } // ⚠ 심각한 였류만 표시 (5xx 서버 였류, 컀슀텀 메시지) @@ -676,7 +676,7 @@ const VoiceInputOverlay = ({ // ShopperHouse API 응답 수신 시 overlay ë‹«êž° 및 API 상태 업데읎튞 useEffect(() => { if (DEBUG_MODE) { - console.log('🔍 [DEBUG] shopperHouseData useEffect running:', { + dlog('🔍 [DEBUG] shopperHouseData useEffect running:', { isVisible, hasData: !!shopperHouseData, refValue: shopperHouseDataRef.current, @@ -688,7 +688,7 @@ const VoiceInputOverlay = ({ // ✹ 쎈Ʞ화 쀑에는 close 로직 싀행 안 핹 (쀑복 ë‹«êž° 방지) if (isInitializingRef.current) { if (DEBUG_MODE) { - console.log('🔍 [DEBUG] Skipping close check - overlay is initializing'); + dlog('🔍 [DEBUG] Skipping close check - overlay is initializing'); } return; } @@ -696,7 +696,7 @@ const VoiceInputOverlay = ({ // 읎전 값곌 비교하여 새로욎 데읎터가 듀얎왔을 때만 ë‹«êž° if (isVisible && shopperHouseData && shopperHouseData !== shopperHouseDataRef.current) { if (DEBUG_MODE) { - console.log('[VoiceInputOverlay.v2] ShopperHouse data received, closing overlay', { + dlog('[VoiceInputOverlay.v2] ShopperHouse data received, closing overlay', { oldRef: shopperHouseDataRef.current, newData: shopperHouseData, }); @@ -708,7 +708,7 @@ const VoiceInputOverlay = ({ setApiStatusMessage('Success'); if (DEBUG_MODE) { - console.log('[VoiceInputOverlay] 📍 API Status updated:', { + dlog('[VoiceInputOverlay] 📍 API Status updated:', { status: 'success', message: 'Success', }); @@ -723,7 +723,7 @@ const VoiceInputOverlay = ({ // STT 텍슀튞 수신 시 처늬 // useEffect(() => { // if (lastSTTText && sttTimestamp && isVisible) { - // console.log('[VoiceInputOverlay.v2] STT text received in overlay:', lastSTTText); + // dlog('[VoiceInputOverlay.v2] STT text received in overlay:', lastSTTText); // // // 입력찜에 텍슀튞 표시 (부몚 컎포넌튞로 전달) // if (onSearchChange) { @@ -745,7 +745,7 @@ const VoiceInputOverlay = ({ if (!ENABLE_WAKE_WORD) return; if (DEBUG_MODE) { - console.log('🎉 [VoiceInputOverlay.v2] Wake word detected! Switching to LISTENING mode'); + dlog('🎉 [VoiceInputOverlay.v2] Wake word detected! Switching to LISTENING mode'); } // Ʞ졎 타읎뚞 정늬 @@ -766,7 +766,7 @@ const VoiceInputOverlay = ({ // 15쎈 타읎뚞 섀정 listeningTimerRef.current = setTimeout(() => { if (DEBUG_MODE) { - console.log('⏰ [VoiceInputOverlay.v2] 15쎈 타임아웃 - PROMPT 몚드로 복귀'); + dlog('⏰ [VoiceInputOverlay.v2] 15쎈 타임아웃 - PROMPT 몚드로 복귀'); } setCurrentMode(VOICE_MODES.PROMPT); setVoiceInputMode(null); @@ -789,7 +789,7 @@ const VoiceInputOverlay = ({ if (detected) { if (DEBUG_MODE) { - console.log('🎉 [VoiceInputOverlay.v2] Wake word detected in PROMPT mode:', text); + dlog('🎉 [VoiceInputOverlay.v2] Wake word detected in PROMPT mode:', text); } handleWakeWordDetected(); } @@ -799,7 +799,7 @@ const VoiceInputOverlay = ({ useEffect(() => { if (isVisible && voiceVersion === VOICE_VERSION.WEB_SPEECH && isSupported === false) { if (DEBUG_MODE) { - console.log('⚠ [VoiceInputOverlay.v2] WebSpeech not supported, switching to NOINIT mode'); + dlog('⚠ [VoiceInputOverlay.v2] WebSpeech not supported, switching to NOINIT mode'); } setCurrentMode(VOICE_MODES.NOINIT); } @@ -808,7 +808,7 @@ const VoiceInputOverlay = ({ // 🎀 음성 입력 최종 처늬 핚수 (15쎈 타읎뚞 & 3쎈 silence detection 공통 사용) const processFinalVoiceInput = useCallback( (source) => { - console.log(`[VoiceInput] 🏁 음성 입력 종료 (${source})`); + dlog(`[VoiceInput] 🏁 음성 입력 종료 (${source})`); // 몚든 타읎뚞 정늬 및 ref 쎈Ʞ화 clearTimerRef(listeningTimerRef); @@ -833,9 +833,9 @@ const VoiceInputOverlay = ({ ? reduxFinalText.trim() : interimRefText; - console.log('[VoiceInput] ├─ Redux finalText:', reduxFinalText || '(없음)'); - console.log('[VoiceInput] ├─ interimRef:', interimRefText || '(없음)'); - console.log('[VoiceInput] └─ 사용할 텍슀튞:', finalText, `(Ꞟ읎: ${finalText.length})`); + dlog('[VoiceInput] ├─ Redux finalText:', reduxFinalText || '(없음)'); + dlog('[VoiceInput] ├─ interimRef:', interimRefText || '(없음)'); + dlog('[VoiceInput] └─ 사용할 텍슀튞:', finalText, `(Ꞟ읎: ${finalText.length})`); if (finalText && finalText.length >= 3) { // STT 텍슀튞 저장 @@ -851,11 +851,11 @@ const VoiceInputOverlay = ({ // ✹ ShopperHouse API 자동 혞출 (2ì°š 발화 시 searchId 포핚) const query = finalText.trim(); - console.log('[VoiceInput] 📀 API 요청 전송'); - console.log('[VoiceInput] ├─ query:', query); - console.log('[VoiceInput] ├─ ref 값:', shopperHouseSearchIdRef.current); - console.log('[VoiceInput] ├─ currentSearchId:', currentSearchId); - console.log('[VoiceInput] └─ searchId:', currentSearchId || '(없음 - 첫 번짞 발화)'); + dlog('[VoiceInput] 📀 API 요청 전송'); + dlog('[VoiceInput] ├─ query:', query); + dlog('[VoiceInput] ├─ ref 값:', shopperHouseSearchIdRef.current); + dlog('[VoiceInput] ├─ currentSearchId:', currentSearchId); + dlog('[VoiceInput] └─ searchId:', currentSearchId || '(없음 - 첫 번짞 발화)'); // API 혞출 읎벀튞 로깅 const searchIdInfo = currentSearchId @@ -878,14 +878,14 @@ const VoiceInputOverlay = ({ ); } else { // 입력읎 없거나 너묎 짧윌멎 NOTRECOGNIZED 몚드로 전환 - console.log('[VoiceInput] ⚠ 입력 없음 또는 너묎 짧음 - NOTRECOGNIZED 몚드로 전환'); - console.log('[VoiceInput] └─ finalText Ꞟ읎:', finalText.length); + dlog('[VoiceInput] ⚠ 입력 없음 또는 너묎 짧음 - NOTRECOGNIZED 몚드로 전환'); + dlog('[VoiceInput] └─ finalText Ꞟ읎:', finalText.length); setCurrentMode(VOICE_MODES.NOTRECOGNIZED); setVoiceInputMode(null); // 3쎈 후 자동윌로 PROMPT 몚드로 복귀 const timer = setTimeout(() => { - console.log('[VoiceInputOverlay] ⏰ 3쎈 후 PROMPT 몚드로 복귀 (NOTRECOGNIZED)'); + dlog('[VoiceInputOverlay] ⏰ 3쎈 후 PROMPT 몚드로 복귀 (NOTRECOGNIZED)'); setCurrentMode(VOICE_MODES.PROMPT); }, 3000); @@ -913,13 +913,13 @@ const VoiceInputOverlay = ({ // currentMode === VOICE_MODES.LISTENING && // !isListening // ) { - // console.log('🎙 [VoiceInputOverlay.v2] Auto-starting Web Speech API after mode change...'); + // dlog('🎙 [VoiceInputOverlay.v2] Auto-starting Web Speech API after mode change...'); // startListening(); // // // 15쎈 타읎뚞 섀정 // clearTimerRef(listeningTimerRef); // listeningTimerRef.current = setTimeout(() => { - // console.log('⏰ [VoiceInputOverlay.v2] 15쎈 타임아웃 - WebSpeech 자동 종료'); + // dlog('⏰ [VoiceInputOverlay.v2] 15쎈 타임아웃 - WebSpeech 자동 종료'); // stopListening(); // setCurrentMode(VOICE_MODES.PROMPT); // setVoiceInputMode(null); @@ -961,7 +961,7 @@ const VoiceInputOverlay = ({ const trimmedText = interimText?.trim() || ''; if (!hasReached5Chars && trimmedText.length >= 5) { // 처음 5Ꞁ자에 도달했을 때만 활성화 - console.log('[VoiceInput] 🎯 5Ꞁ자 도달! SilenceCheck 활성화'); + dlog('[VoiceInput] 🎯 5Ꞁ자 도달! SilenceCheck 활성화'); setHasReached5Chars(true); setIsSilenceCheckActive(true); } else if (hasReached5Chars && trimmedText.length < 5) { @@ -983,7 +983,7 @@ const VoiceInputOverlay = ({ // 3쎈 silence detection: 마지막 입력 후 3쎈 동안 추가 입력읎 없윌멎 자동 종료 clearTimerRef(silenceDetectionTimerRef); silenceDetectionTimerRef.current = setTimeout(() => { - console.log('[VoiceInput] 🔇 3쎈 동안 입력 없음 - 자동 종료'); + dlog('[VoiceInput] 🔇 3쎈 동안 입력 없음 - 자동 종료'); addWebSpeechEventLog('SILENCE_3S', 'No input detected for 3 seconds - auto finish'); processFinalVoiceInput('3쎈 silence detection'); }, 3000); // 3쎈 @@ -1010,9 +1010,7 @@ const VoiceInputOverlay = ({ if (currentMode !== VOICE_MODES.PROMPT) return; if (DEBUG_MODE) { - console.log( - '🎙 [VoiceInputOverlay.v2] Starting background listening for wake word detection' - ); + dlog('🎙 [VoiceInputOverlay.v2] Starting background listening for wake word detection'); } // PROMPT 몚드에서 백귞띌욎드 늬슀닝 시작 @@ -1037,7 +1035,7 @@ const VoiceInputOverlay = ({ setSilenceSeconds(0); if (DEBUG_MODE) { - console.log('⏱ [VoiceInputOverlay.v2] Starting countdown from 15'); + dlog('⏱ [VoiceInputOverlay.v2] Starting countdown from 15'); } // 1쎈마닀 칎욎튞닀욎 @@ -1045,7 +1043,7 @@ const VoiceInputOverlay = ({ setCountdown((prev) => { const next = prev - 1; if (DEBUG_MODE) { - console.log('⏱ [VoiceInputOverlay.v2] Countdown:', next); + dlog('⏱ [VoiceInputOverlay.v2] Countdown:', next); } if (next <= 0) { clearIntervalRef(countdownIntervalRef); @@ -1080,7 +1078,7 @@ const VoiceInputOverlay = ({ setSilenceSeconds((prev) => { const next = prev + 1; if (DEBUG_MODE) { - console.log('🚊 [VoiceInput] Silence Detection Progress:', next); + dlog('🚊 [VoiceInput] Silence Detection Progress:', next); } if (next >= 3) { // 3쎈 도달하멎 interval 정늬 (타읎뚞가 ê³§ 종료됚) @@ -1098,11 +1096,11 @@ const VoiceInputOverlay = ({ // VoiceInputOverlay 얞마욎튞 시에만 쎈Ʞ화 useEffect(() => { - console.log('[VoiceInput] 🚀 VoiceInputOverlay 마욎튞됚 (searchId 유지)'); + dlog('[VoiceInput] 🚀 VoiceInputOverlay 마욎튞됚 (searchId 유지)'); // Cleanup: 얞마욎튞 시에만 쎈Ʞ화 return () => { - console.log('[VoiceInput] 🔚 VoiceInputOverlay 얞마욎튞 - searchId 쎈Ʞ화'); + dlog('[VoiceInput] 🔚 VoiceInputOverlay 얞마욎튞 - searchId 쎈Ʞ화'); // dispatch(clearShopperHouseData()); dispatch(clearSTTText()); }; @@ -1111,34 +1109,34 @@ const VoiceInputOverlay = ({ // Overlay가 엎늎 때 포컀슀륌 overlay 낎부로 읎동 useEffect(() => { if (DEBUG_MODE) { - console.log('👁 [DEBUG] isVisible useEffect triggered - isVisible:', isVisible); + dlog('👁 [DEBUG] isVisible useEffect triggered - isVisible:', isVisible); } if (isVisible) { if (DEBUG_MODE) { - console.log('✅ [DEBUG] ===== OVERLAY OPENING ====='); + dlog('✅ [DEBUG] ===== OVERLAY OPENING ====='); } // ✹ 쎈Ʞ화 시작 플래귞 섀정 (close 로직 음시 찚닚) isInitializingRef.current = true; if (DEBUG_MODE) { - console.log('🚧 [DEBUG] isInitializingRef set to TRUE - close logic DISABLED'); + dlog('🚧 [DEBUG] isInitializingRef set to TRUE - close logic DISABLED'); } // 현재 포컀슀된 요소 저장 lastFocusedElement.current = Spotlight.getCurrent(); - console.log('[lastFocusedElement] 🚀 Current focused element:', Spotlight.getCurrent()); + dlog('[lastFocusedElement] 🚀 Current focused element:', Spotlight.getCurrent()); // ✹ shopperHouseDataRef륌 null로 쎈Ʞ화 shopperHouseDataRef.current = null; if (DEBUG_MODE) { - console.log('🔍 [DEBUG] shopperHouseDataRef initialized to NULL'); + dlog('🔍 [DEBUG] shopperHouseDataRef initialized to NULL'); } // 몚드 쎈Ʞ화 (항상 prompt 몚드로 시작) if (DEBUG_MODE) { - console.log('🔀 [DEBUG] Setting currentMode to:', mode); + dlog('🔀 [DEBUG] Setting currentMode to:', mode); } setCurrentMode(mode); setVoiceInputMode(null); @@ -1149,12 +1147,12 @@ const VoiceInputOverlay = ({ // ✹ 쎈Ʞ화 완료 - close 로직 활성화 isInitializingRef.current = false; if (DEBUG_MODE) { - console.log('✅ [DEBUG] Initialization complete, close logic ENABLED'); + dlog('✅ [DEBUG] Initialization complete, close logic ENABLED'); } }, 100); } else { if (DEBUG_MODE) { - console.log('❌ [DEBUG] ===== OVERLAY CLOSING ====='); + dlog('❌ [DEBUG] ===== OVERLAY CLOSING ====='); } // Overlay가 닫힐 때 원래 포컀슀 복원 및 상태 쎈Ʞ화 @@ -1168,7 +1166,8 @@ const VoiceInputOverlay = ({ // 🎯 [포컀슀 충돌 핎결] VoiceInputOverlay륌 통한 음성 검색 후에는 TInput윌로 포컀슀 복원하지 않음 // SearchResults의 첫 번짞 상품윌로 포컀슀가 가도록 SearchPanel에 위임 // shopperHouseData가 있윌멎 (음성 검색 결곌가 있윌멎) 포컀슀 복원하지 않음 - const hasVoiceSearchResult = shopperHouseData && shopperHouseData.results && shopperHouseData.results.length > 0; + const hasVoiceSearchResult = + shopperHouseData && shopperHouseData.results && shopperHouseData.results.length > 0; if (lastFocusedElement.current && !isVoiceResultMode && !hasVoiceSearchResult) { focusRestoreTimerRef.current = setTimeout(() => { Spotlight.focus(lastFocusedElement.current); @@ -1195,7 +1194,7 @@ const VoiceInputOverlay = ({ // 🔄 API 에러 재시작 핚수 const handleApiErrorRestart = useCallback(() => { if (DEBUG_MODE) { - console.log('[VoiceInput] 🔄 Restarting after API error'); + dlog('[VoiceInput] 🔄 Restarting after API error'); } // ShopperHouse 에러 상태 정늬 (Redux) @@ -1216,14 +1215,14 @@ const VoiceInputOverlay = ({ setIsBubbleClickSearch(false); // bubble 큎늭 상태 쎈Ʞ화 if (DEBUG_MODE) { - console.log('[VoiceInput] ✅ API error restart complete - ready for new input'); + dlog('[VoiceInput] ✅ API error restart complete - ready for new input'); } }, [dispatch, onSearchChange]); // API 재시도 핚수 const handleApiErrorRetry = useCallback(() => { if (DEBUG_MODE) { - console.log('[VoiceInput] 🔄 Retrying API call after error'); + dlog('[VoiceInput] 🔄 Retrying API call after error'); } // 읎전 에러 상태 정늬 @@ -1235,9 +1234,9 @@ const VoiceInputOverlay = ({ const currentSearchId = shopperHouseSearchIdRef.current; if (DEBUG_MODE) { - console.log('[VoiceInput] 🔄 Retrying API call'); - console.log('[VoiceInput] ├─ query:', query); - console.log('[VoiceInput] └─ searchId:', currentSearchId || '(없음 - 첫 번짞 발화)'); + dlog('[VoiceInput] 🔄 Retrying API call'); + dlog('[VoiceInput] ├─ query:', query); + dlog('[VoiceInput] └─ searchId:', currentSearchId || '(없음 - 첫 번짞 발화)'); } // 닀시 API 혞출 @@ -1267,7 +1266,7 @@ const VoiceInputOverlay = ({ // Overlay ë‹«êž° 핞듀러 (몚든 ë‹«êž° 동작을 통합) const handleClose = useCallback(() => { if (DEBUG_MODE) { - console.log('🚪 [DEBUG] handleClose called - closing overlay'); + dlog('🚪 [DEBUG] handleClose called - closing overlay'); } // 1. 타읎뚞 정늬 @@ -1309,7 +1308,7 @@ const VoiceInputOverlay = ({ const handleSuggestionClick = useCallback( (suggestion) => { if (DEBUG_MODE) { - console.log('💡 [DEBUG] handleSuggestionClick called with:', suggestion); + dlog('💡 [DEBUG] handleSuggestionClick called with:', suggestion); } // Bubble 큎늭윌로 검색 시작 상태 섀정 @@ -1339,9 +1338,9 @@ const VoiceInputOverlay = ({ const currentSearchId = shopperHouseSearchIdRef.current; if (DEBUG_MODE) { - console.log('🔍 [DEBUG] Calling ShopperHouse API from bubble click'); - console.log('[VoiceInput] ├─ query:', query); - console.log('[VoiceInput] └─ searchId:', currentSearchId || '(없음 - 첫 번짞 발화)'); + dlog('🔍 [DEBUG] Calling ShopperHouse API from bubble click'); + dlog('[VoiceInput] ├─ query:', query); + dlog('[VoiceInput] └─ searchId:', currentSearchId || '(없음 - 첫 번짞 발화)'); } // API 혞출 읎벀튞 로깅 (Bubble 큎늭) @@ -1379,7 +1378,7 @@ const VoiceInputOverlay = ({ // Input 찜에서 API 혞출 핞듀러 (돋볎Ʞ 아읎윘 큎늭 시에만) const handleSearchSubmit = useCallback(() => { if (DEBUG_MODE) { - console.log('[VoiceInputOverlay.v2] Search submit:', searchQuery); + dlog('[VoiceInputOverlay.v2] Search submit:', searchQuery); } if (searchQuery && searchQuery.trim()) { // ShopperHouse API 혞출 @@ -1423,7 +1422,7 @@ const VoiceInputOverlay = ({ (e) => { if (e.key === 'Enter' || e.keyCode === 13) { e.preventDefault(); - console.log( + dlog( '[VoiceInputOverlay] 🔄 TInputSimple에서 Enter í‚€ 감지 → SearchInputOverlay 전환 시작' ); // 🎯 SearchPanel의 윜백 혞출 @@ -1439,7 +1438,7 @@ const VoiceInputOverlay = ({ // ⚠ [251031] 마우슀 큎늭 시 프늬징 발생 - 추후 원읞 분석 후 활성화 필요 // const handleInputMouseDown = useCallback((e) => { // e.preventDefault(); - // console.log('[VoiceInputOverlay] 🖱 TInputSimple에서 마우슀 큎늭 감지 → SearchInputOverlay 전환 시작'); + // dlog('[VoiceInputOverlay] 🖱 TInputSimple에서 마우슀 큎늭 감지 → SearchInputOverlay 전환 시작'); // // 🎯 SearchPanel의 윜백 혞출 // if (onTransitionToSearchInput) { // onTransitionToSearchInput(); @@ -1450,14 +1449,14 @@ const VoiceInputOverlay = ({ const handleInputModeChange = useCallback( (inputMode) => { if (DEBUG_MODE) { - console.log('[VoiceInputOverlay] TInput 몚드 변겜:', inputMode); + dlog('[VoiceInputOverlay] TInput 몚드 변겜:', inputMode); } if (inputMode === 'input') { // Input 몚드로 전환되멎 Overlay ë‹«êž° // SearchPanel의 TInput윌로 자연슀럜게 전환됚 if (DEBUG_MODE) { - console.log('⌚ [DEBUG] Input 몚드로 전환됚 - VoiceInputOverlay 닫고 SearchPanel로 읎동'); + dlog('⌚ [DEBUG] Input 몚드로 전환됚 - VoiceInputOverlay 닫고 SearchPanel로 읎동'); } handleClose(); } @@ -1469,7 +1468,7 @@ const VoiceInputOverlay = ({ const handleToggleDashboard = useCallback(() => { setShowDashboard((prev) => !prev); if (DEBUG_MODE) { - console.log('🔧 [DEBUG] Dashboard toggled:', !showDashboard); + dlog('🔧 [DEBUG] Dashboard toggled:', !showDashboard); } }, [showDashboard]); @@ -1484,7 +1483,7 @@ const VoiceInputOverlay = ({ // 몚드에 따륞 컚텐잠 렌더링 - Memoized const renderModeContent = useMemo(() => { if (DEBUG_MODE) { - console.log( + dlog( '🎬 [DEBUG][VoiceInputOverlay] renderModeContent called', '| currentMode:', currentMode, @@ -1527,8 +1526,8 @@ const VoiceInputOverlay = ({ } // ✹ [DEBUG] Redux 상태 확읞 로귞 - console.log('[VoiceInput]-shopperHouseRelativeQueries'); - console.log( + dlog('[VoiceInput]-shopperHouseRelativeQueries'); + dlog( JSON.stringify( { hasRelativeQueries: hasRelativeQueries, @@ -1549,25 +1548,19 @@ const VoiceInputOverlay = ({ ); if (DEBUG_MODE) { - console.log( + dlog( '✅ [DEBUG][VoiceInputOverlay] MODE = PROMPT | Rendering VoicePromptScreen', hasRelativeQueries ? '(with relativeQueries)' : '(with legacySearchHistory)', promptSuggestions.length, 'suggestions' ); if (hasRelativeQueries) { - console.log( - '[DEBUG][VoiceInputOverlay] ├─ searchId:', - shopperHouseSearchId || '(없음)' - ); - console.log('[DEBUG][VoiceInputOverlay] ├─ relativeQueries:', promptSuggestions); - console.log('[DEBUG][VoiceInputOverlay] └─ promptTitle:', promptTitle); + dlog('[DEBUG][VoiceInputOverlay] ├─ searchId:', shopperHouseSearchId || '(없음)'); + dlog('[DEBUG][VoiceInputOverlay] ├─ relativeQueries:', promptSuggestions); + dlog('[DEBUG][VoiceInputOverlay] └─ promptTitle:', promptTitle); } else { - console.log('[DEBUG][VoiceInputOverlay] ├─ relativeQueries가 없음'); - console.log( - '[DEBUG][VoiceInputOverlay] └─ legacySearchHistory 사용:', - promptSuggestions - ); + dlog('[DEBUG][VoiceInputOverlay] ├─ relativeQueries가 없음'); + dlog('[DEBUG][VoiceInputOverlay] └─ legacySearchHistory 사용:', promptSuggestions); } } return ( @@ -1581,7 +1574,7 @@ const VoiceInputOverlay = ({ } case VOICE_MODES.LISTENING: if (DEBUG_MODE) { - console.log( + dlog( '🎀 [DEBUG][VoiceInputOverlay] MODE = LISTENING | Rendering VoiceListening (15쎈 타읎뚞)' ); } @@ -1595,7 +1588,7 @@ const VoiceInputOverlay = ({ ); case VOICE_MODES.RESPONSE: if (DEBUG_MODE) { - console.log( + dlog( '💬 [DEBUG][VoiceInputOverlay] MODE = RESPONSE | Rendering VoiceResponse with text:', sttResponseText, 'isLoading: true (항상 로딩 애니메읎션 표시)' @@ -1614,12 +1607,12 @@ const VoiceInputOverlay = ({ ); case VOICE_MODES.NOINIT: if (DEBUG_MODE) { - console.log('⚠ [DEBUG][VoiceInputOverlay] MODE = NOINIT | Rendering VoiceNotRecognized'); + dlog('⚠ [DEBUG][VoiceInputOverlay] MODE = NOINIT | Rendering VoiceNotRecognized'); } return ; case VOICE_MODES.NOTRECOGNIZED: if (DEBUG_MODE) { - console.log( + dlog( '❌ [DEBUG][VoiceInputOverlay] MODE = NOTRECOGNIZED | Rendering VoiceNotRecognized with error message' ); } @@ -1631,7 +1624,7 @@ const VoiceInputOverlay = ({ ); case VOICE_MODES.APIERROR: if (DEBUG_MODE) { - console.log( + dlog( '💥 [DEBUG][VoiceInputOverlay] MODE = APIERROR | Rendering VoiceApiError with error details', shopperHouseError ); @@ -1651,7 +1644,7 @@ const VoiceInputOverlay = ({ return ; default: { if (DEBUG_MODE) { - console.log('🔄 [DEBUG][VoiceInputOverlay] MODE = DEFAULT | Rendering VoicePromptScreen'); + dlog('🔄 [DEBUG][VoiceInputOverlay] MODE = DEFAULT | Rendering VoicePromptScreen'); } // default 쌀읎슀에서도 promptSuggestions 계산 const hasRelativeQueries = !!shopperHouseRelativeQueries; @@ -1712,8 +1705,8 @@ const VoiceInputOverlay = ({ const handleWebSpeechMicClick = useCallback( (e) => { if (DEBUG_MODE) { - console.log('🎀 [DEBUG] handleWebSpeechMicClick called, currentMode:', currentMode); - console.log('🎀 [DEBUG] CURRENT_WEBSPEECH_VERSION:', CURRENT_WEBSPEECH_VERSION); + dlog('🎀 [DEBUG] handleWebSpeechMicClick called, currentMode:', currentMode); + dlog('🎀 [DEBUG] CURRENT_WEBSPEECH_VERSION:', CURRENT_WEBSPEECH_VERSION); } // 읎벀튞 전파 방지 - dim 레읎얎의 onClick 싀행 방지 @@ -1730,9 +1723,9 @@ const VoiceInputOverlay = ({ if (CURRENT_WEBSPEECH_VERSION === 'v1') { if (currentMode === VOICE_MODES.PROMPT) { // ✹ PROMPT 몚드에서만 LISTENING윌로 전환 가능 - console.log('\n🎀 ════════════════════════════════════════════════════════════════'); - console.log('🎀 [VoiceInput] MIC BUTTON CLICKED - WebSpeech Initialization Flow (V1)'); - console.log('🎀 ════════════════════════════════════════════════════════════════\n'); + dlog('\n🎀 ════════════════════════════════════════════════════════════════'); + dlog('🎀 [VoiceInput] MIC BUTTON CLICKED - WebSpeech Initialization Flow (V1)'); + dlog('🎀 ════════════════════════════════════════════════════════════════\n'); // 📋 닚계별 처늬: // 1. WebSpeech 완전 cleanup (읎전 상태 제거) @@ -1743,56 +1736,56 @@ const VoiceInputOverlay = ({ // ============================================================ // 1⃣ WebSpeech 완전 cleanup (읎전 상태 제거) // ============================================================ - console.log('[VoiceInput] 📍 [STEP 1] WebSpeech Cleanup'); - console.log('[VoiceInput] ├─ Dispatching: cleanupWebSpeech()'); + dlog('[VoiceInput] 📍 [STEP 1] WebSpeech Cleanup'); + dlog('[VoiceInput] ├─ Dispatching: cleanupWebSpeech()'); dispatch(cleanupWebSpeech()); - console.log('[VoiceInput] └─ ✅ Cleanup dispatched\n'); + dlog('[VoiceInput] └─ ✅ Cleanup dispatched\n'); // ============================================================ // 2⃣ Redux STT 데읎터 쎈Ʞ화 (searchId는 Redux에서 유지됚) // ============================================================ - console.log('[VoiceInput] 📍 [STEP 2] STT Data Clear'); - console.log('[VoiceInput] ├─ Dispatching: clearSTTText()'); + dlog('[VoiceInput] 📍 [STEP 2] STT Data Clear'); + dlog('[VoiceInput] ├─ Dispatching: clearSTTText()'); dispatch(clearSTTText()); - console.log('[VoiceInput] ├─ Clearing interim text buffer'); + dlog('[VoiceInput] ├─ Clearing interim text buffer'); // ✅ TInput 쎈Ʞ화 if (onSearchChange) { onSearchChange({ value: '' }); - console.log('[VoiceInput] ├─ TInput cleared'); + dlog('[VoiceInput] ├─ TInput cleared'); } // ✅ Interim text ref 쎈Ʞ화 interimTextRef.current = ''; - console.log('[VoiceInput] ├─ Interim text ref cleared'); + dlog('[VoiceInput] ├─ Interim text ref cleared'); // Ʞ졎 타읎뚞 정늬 clearTimerRef(listeningTimerRef); clearTimerRef(silenceDetectionTimerRef); - console.log('[VoiceInput] ├─ Previous timers cleared'); + dlog('[VoiceInput] ├─ Previous timers cleared'); // UI 몚드 업데읎튞 setVoiceInputMode(VOICE_INPUT_MODE.WEBSPEECH); setCurrentMode(VOICE_MODES.LISTENING); - console.log('[VoiceInput] ├─ UI mode set to WEBSPEECH / LISTENING'); + dlog('[VoiceInput] ├─ UI mode set to WEBSPEECH / LISTENING'); // ✅ LISTENING 몚드 진입 시 로귞 쎈Ʞ화 (새로욎 음성 입력 시작) setWebSpeechEventLogs([]); writeLocalStorage(VOICE_EVENT_LOGS_KEY, []); - console.log('[VoiceInput] └─ ✅ Event logs cleared\n'); + dlog('[VoiceInput] └─ ✅ Event logs cleared\n'); if (DEBUG_MODE) { - console.log('🧹 [DEBUG] Cleared webSpeechEventLogs on mic click'); + dlog('🧹 [DEBUG] Cleared webSpeechEventLogs on mic click'); } // ============================================================ // 3⃣ WebSpeech 재쎈Ʞ화 (앜간의 지연 후) // ============================================================ - console.log('[VoiceInput] ⏳ [STEP 3] Waiting 100ms for Redux state sync...'); + dlog('[VoiceInput] ⏳ [STEP 3] Waiting 100ms for Redux state sync...'); const reinitializeWebSpeech = setTimeout(() => { - console.log('[VoiceInput] 📍 [STEP 3] WebSpeech Initialization'); - console.log('[VoiceInput] ├─ Dispatching: initializeWebSpeech()'); - console.log('[VoiceInput] │ └─ lang: en-US, continuous: true, interimResults: true'); + dlog('[VoiceInput] 📍 [STEP 3] WebSpeech Initialization'); + dlog('[VoiceInput] ├─ Dispatching: initializeWebSpeech()'); + dlog('[VoiceInput] │ └─ lang: en-US, continuous: true, interimResults: true'); // Redux 상태 업데읎튞륌 Ʞ닀늬Ʞ 위핎 앜간의 지연 dispatch( @@ -1803,37 +1796,37 @@ const VoiceInputOverlay = ({ }) ); - console.log('[VoiceInput] └─ ✅ Initialize dispatched\n'); + dlog('[VoiceInput] └─ ✅ Initialize dispatched\n'); // ============================================================ // 4⃣ WebSpeech 슉시 시작 // ============================================================ - console.log('[VoiceInput] 📍 [STEP 4] WebSpeech Start'); - console.log('[VoiceInput] ├─ Dispatching: startWebSpeech()'); + dlog('[VoiceInput] 📍 [STEP 4] WebSpeech Start'); + dlog('[VoiceInput] ├─ Dispatching: startWebSpeech()'); dispatch(startWebSpeech()); - console.log('[VoiceInput] └─ ✅ Start dispatched\n'); + dlog('[VoiceInput] └─ ✅ Start dispatched\n'); // ============================================================ // 5⃣ 15쎈 타읎뚞 섀정 및 쀀비 완료 // ============================================================ - console.log('[VoiceInput] 📍 [STEP 5] Setup MaxListeningTime Timer'); - console.log('[VoiceInput] ├─ Setting 15-second listening timeout'); + dlog('[VoiceInput] 📍 [STEP 5] Setup MaxListeningTime Timer'); + dlog('[VoiceInput] ├─ Setting 15-second listening timeout'); listeningTimerRef.current = setTimeout(() => { - console.log('[VoiceInput] ⏲ [TIMEOUT] 15-second max listening time reached'); + dlog('[VoiceInput] ⏲ [TIMEOUT] 15-second max listening time reached'); addWebSpeechEventLog('TIMEOUT_15S', '15 second timeout reached - finishing input'); processFinalVoiceInput('15쎈 타임아웃'); }, 15000); // 15쎈 - console.log('[VoiceInput] ├─ ⏲ Timer started (15000ms)'); - console.log('[VoiceInput] └─ ✅ Timer configured\n'); + dlog('[VoiceInput] ├─ ⏲ Timer started (15000ms)'); + dlog('[VoiceInput] └─ ✅ Timer configured\n'); // ============================================================ // ✹ INITIALIZATION COMPLETE // ============================================================ - console.log('🎀 ════════════════════════════════════════════════════════════════'); - console.log('✹ [VoiceInput] 음성 읞식 쀀비 완료! (Voice Recognition Ready!)'); - console.log('✹ [VoiceInput] Waiting for voice input... (max 15 seconds)'); - console.log('🎀 ════════════════════════════════════════════════════════════════\n'); + dlog('🎀 ════════════════════════════════════════════════════════════════'); + dlog('✹ [VoiceInput] 음성 읞식 쀀비 완료! (Voice Recognition Ready!)'); + dlog('✹ [VoiceInput] Waiting for voice input... (max 15 seconds)'); + dlog('🎀 ════════════════════════════════════════════════════════════════\n'); }, 100); // Cleanup: 얞마욎튞 시 타읎뚞 정늬 @@ -1843,7 +1836,7 @@ const VoiceInputOverlay = ({ } else { // listening 몚드 또는 Ʞ타 몚드에서 큎늭 시 -> overlay ë‹«êž° if (DEBUG_MODE) { - console.log('🎀 [DEBUG] Closing overlay (not in PROMPT mode)'); + dlog('🎀 [DEBUG] Closing overlay (not in PROMPT mode)'); } handleClose(); } @@ -1852,12 +1845,12 @@ const VoiceInputOverlay = ({ // V2: Promise 첎읞 비동Ʞ 방식 (믞래 - 아직 구현 대Ʞ 쀑) // ============================================================ else if (CURRENT_WEBSPEECH_VERSION === 'v2') { - console.log('\n🎀 ════════════════════════════════════════════════════════════════'); - console.log('🎀 [VoiceInput] MIC BUTTON CLICKED - WebSpeech Initialization Flow (V2)'); - console.log('🎀 ════════════════════════════════════════════════════════════════\n'); + dlog('\n🎀 ════════════════════════════════════════════════════════════════'); + dlog('🎀 [VoiceInput] MIC BUTTON CLICKED - WebSpeech Initialization Flow (V2)'); + dlog('🎀 ════════════════════════════════════════════════════════════════\n'); if (DEBUG_MODE) { - console.log('🎀 [DEBUG] V2 flow triggered'); + dlog('🎀 [DEBUG] V2 flow triggered'); } // ⚠ V2 로직은 여Ʞ에 구현됚 @@ -2135,7 +2128,7 @@ const VoiceInputOverlay = ({ inputFocus={inputFocused} onKeyDown={handleInputKeyDown} onMouseDown={() => { - console.log('[InputSimple] 마우슀 큎늭 감지'); + dlog('[InputSimple] 마우슀 큎늭 감지'); if (onTransitionToSearchInput) { onTransitionToSearchInput(); }