import React, { // useMemo, useCallback, useEffect, useRef, // useState, } from 'react'; import { useSelector, useDispatch } from 'react-redux'; // import { I18nContext } from "@enact/i18n"; // import classNames from "classnames"; // import PropTypes from "prop-types"; import Spotlight from '@enact/spotlight'; import { Job } from '@enact/core/util'; import platform from '@enact/core/platform'; import { ThemeDecorator } from '@enact/sandstone/ThemeDecorator'; // import "../../../assets/fontello/css/fontello.css"; import { changeAppStatus, // cancelFocusElement, // focusElement, // setExitApp, // setPreventMouse, // setShowPopup, // setTermsAgreeYn, getTermsAgreeYn, deleteOldDb8Datas, sendBroadCast, getConnectionStatus, getConnectionInfo, getDeviceId, getHttpHeaderForServiceRequest, getSystemSettings, checkFirstLaunch, setDeepLink, setGNBMenu, setSecondLayerInfo, } from '../actions/commonActions'; import { getShoptimeTerms } from '../actions/empActions'; import { getHomeMenu, getHomeTerms } from '../actions/homeActions'; import { getMyRecommandedKeyword, getMyUpcomingAlertShow } from '../actions/myPageActions'; import { pushPanel } from '../actions/panelActions'; import { enqueuePanelHistory } from '../actions/panelHistoryActions'; import NotSupportedVersion from '../components/NotSupportedVersion/NotSupportedVersion'; import ToastContainer from '../components/TToast/ToastContainer'; import usePrevious from '../hooks/usePrevious'; import { lunaTest } from '../lunaSend/lunaTest'; import { store } from '../store/store'; import * as Config from '../utils/Config'; import { // $L, clearLaunchParams, // getCountry, getLaunchParams, // getUUID, // resizeTo, } from '../utils/helperMethods'; import { SpotlightIds } from '../utils/SpotlightIds'; import ErrorBoundary from '../views/ErrorBoundary'; import MainView from '../views/MainView/MainView'; import css from './App.module.less'; import { handleBypassLink } from './bypassLinkHandler'; import { handleDeepLink } from './deepLinkHandler'; import { sendLogTotalRecommend } from '../actions/logActions'; import { types } from '../actions/actionTypes'; // import { // startFocusMonitoring, // stopFocusMonitoring, // } from "../utils/focus-monitor"; // import { PanelHoc } from "../components/TPanel/TPanel"; // DEBUG_MODE - true인 경우에만 로그 출력 const DEBUG_MODE = false; let foreGroundChangeTimer = null; // 기존 콘솔 메서드를 백업 const originalConsole = { log: console.log, error: console.error, warn: console.warn, info: console.info, }; const enableConsole = () => { console.log = originalConsole.log; console.error = originalConsole.error; console.warn = originalConsole.warn; console.info = originalConsole.info; }; const disableConsole = () => { console.log = function () {}; // console.error = function() {}; console.warn = function () {}; console.info = function () {}; }; // console.log 자동 Object 직렬화 오버라이드 const originalConsoleLog = console.log; const originalConsoleError = console.error; const originalConsoleWarn = console.warn; const processArgs = (args) => { return args.map((arg) => { if (typeof arg === 'object' && arg !== null && !Array.isArray(arg)) { try { return JSON.stringify(arg, null, 2); } catch (e) { return `[Object: ${e.message}]`; } } return arg; }); }; // Voice 관련 로그를 VoicePanel로 전송하는 헬퍼 함수 const sendVoiceLogToPanel = (args) => { try { const firstArg = args[0]; // [Voice] 또는 [VoiceConductor] 태그 확인 if ( typeof firstArg === 'string' && (firstArg.includes('[Voice]') || firstArg.includes('[VoiceConductor]')) ) { // 로그 타입 결정 let logType = 'INFO'; let title = firstArg; if ( firstArg.includes('ERROR') || firstArg.includes('Error') || firstArg.includes('Failed') || firstArg.includes('failed') ) { logType = 'ERROR'; } else if ( firstArg.includes('Response') || firstArg.includes('response') || firstArg.includes('success') ) { logType = 'RESPONSE'; } else if ( firstArg.includes('Registering') || firstArg.includes('Sending') || firstArg.includes('request') ) { logType = 'REQUEST'; } else if ( firstArg.includes('received') || firstArg.includes('Handling') || firstArg.includes('⭐') ) { logType = 'ACTION'; } else if (firstArg.includes('command')) { logType = 'COMMAND'; } // 데이터 수집 const logData = {}; if (args.length > 1) { args.slice(1).forEach((arg, index) => { if (typeof arg === 'object') { Object.assign(logData, arg); } else { logData[`arg${index + 1}`] = arg; } }); } // Redux로 dispatch store.dispatch({ type: types.VOICE_ADD_LOG, payload: { timestamp: new Date().toISOString(), type: logType, title: title.replace(/^\[Voice\]\s*/, '').replace(/^\[VoiceConductor\]\s*/, ''), data: Object.keys(logData).length > 0 ? logData : { message: firstArg }, success: logType !== 'ERROR', }, }); } } catch (error) { // 로깅 중 에러가 발생해도 원래 로그는 출력되어야 함 originalConsoleLog.call(console, '[VoiceLog] Error sending to panel:', error); } }; console.log = function (...args) { if (DEBUG_MODE) { // Voice 로그를 VoicePanel로 전송 sendVoiceLogToPanel(args); // 원래 console.log 실행 originalConsoleLog.apply(console, processArgs(args)); } }; console.error = function (...args) { if (DEBUG_MODE) { // Voice 로그를 VoicePanel로 전송 (에러는 강제로 ERROR 타입) try { const firstArg = args[0]; if ( typeof firstArg === 'string' && (firstArg.includes('[Voice]') || firstArg.includes('[VoiceConductor]')) ) { const logData = {}; if (args.length > 1) { args.slice(1).forEach((arg, index) => { if (typeof arg === 'object') { Object.assign(logData, arg); } else { logData[`arg${index + 1}`] = arg; } }); } store.dispatch({ type: types.VOICE_ADD_LOG, payload: { timestamp: new Date().toISOString(), type: 'ERROR', title: firstArg.replace(/^\[Voice\]\s*/, '').replace(/^\[VoiceConductor\]\s*/, ''), data: Object.keys(logData).length > 0 ? logData : { message: firstArg }, success: false, }, }); } } catch (error) { originalConsoleError.call(console, '[VoiceLog] Error sending error to panel:', error); } originalConsoleError.apply(console, processArgs(args)); } }; console.warn = function (...args) { if (DEBUG_MODE) { // Voice 로그를 VoicePanel로 전송 (경고는 ERROR 타입으로) try { const firstArg = args[0]; if ( typeof firstArg === 'string' && (firstArg.includes('[Voice]') || firstArg.includes('[VoiceConductor]')) ) { const logData = {}; if (args.length > 1) { args.slice(1).forEach((arg, index) => { if (typeof arg === 'object') { Object.assign(logData, arg); } else { logData[`arg${index + 1}`] = arg; } }); } store.dispatch({ type: types.VOICE_ADD_LOG, payload: { timestamp: new Date().toISOString(), type: 'ERROR', title: 'WARNING: ' + firstArg.replace(/^\[Voice\]\s*/, '').replace(/^\[VoiceConductor\]\s*/, ''), data: Object.keys(logData).length > 0 ? logData : { message: firstArg }, success: false, }, }); } } catch (error) { originalConsoleWarn.call(console, '[VoiceLog] Error sending warning to panel:', error); } originalConsoleWarn.apply(console, processArgs(args)); } }; const originFocus = Spotlight.focus; const originMove = Spotlight.move; const originSilentlyFocus = Spotlight.silentlyFocus; let lastLoggedSpotlightId = null; let lastLoggedBlurSpotlightId = null; // eslint-disable-line no-unused-vars let focusLoggingSuppressed = 0; const resolveSpotlightIdFromNode = (node) => { if (!node) return undefined; if (node.dataset && node.dataset.spotlightId) { return node.dataset.spotlightId; } if (typeof node.getAttribute === 'function') { const idFromAttr = node.getAttribute('data-spotlight-id'); if (idFromAttr) { return idFromAttr; } } if (node.id) { return node.id; } return undefined; }; const logFocusTransition = (previousNode, currentNode) => { if (!Config.FOCUS_DEBUG) { return; } const previousId = resolveSpotlightIdFromNode(previousNode); const currentId = resolveSpotlightIdFromNode(currentNode); if (previousId && previousId !== currentId) { if (DEBUG_MODE) console.log(`[SpotlightFocus] blur - ${previousId}`); lastLoggedBlurSpotlightId = previousId; } if (currentId && currentId !== lastLoggedSpotlightId) { if (DEBUG_MODE) console.log(`[SpotlightFocus] focus - ${currentId}`); lastLoggedSpotlightId = currentId; } }; Spotlight.focus = function (elem, containerOption) { const previousNode = Spotlight.getCurrent(); const ret = originFocus.apply(this, [elem, containerOption]); // this 바인딩을 유지하여 originFocus 호출 const current = Spotlight.getCurrent(); if ((ret === true || current !== previousNode) && focusLoggingSuppressed === 0) { logFocusTransition(previousNode, current); } if (ret === true) { const floatLayerNode = document.getElementById('floatLayer'); const tabLayoutNode = document.getElementById(SpotlightIds.TAB_LAYOUT); //팝업이 존재할 경우 if (floatLayerNode && floatLayerNode.childElementCount > 0) { if (!floatLayerNode.contains(current)) { if (floatLayerNode.lastElementChild) { const spottableNode = floatLayerNode.lastElementChild.querySelector( '[data-spotlight-container="true"]' ); if (spottableNode) { originFocus.apply(this, [spottableNode]); // this 바인딩을 유지하여 originFocus 호출 } } } } else { //GNB가 열린 상태에서 Panel에 포커스 가는 경우 if (current && store.getState().common.isGnbOpened && !tabLayoutNode.contains(current)) { store.dispatch( sendBroadCast({ type: 'deActivateTab', moreInfo: { reason: 'focus' }, }) ); } } } return ret; }; Spotlight.move = function (...args) { if (!originMove) { return false; } const previousNode = Spotlight.getCurrent(); focusLoggingSuppressed += 1; let ret; try { ret = originMove.apply(this, args); } finally { focusLoggingSuppressed = Math.max(0, focusLoggingSuppressed - 1); } const current = Spotlight.getCurrent(); if (current !== previousNode) { logFocusTransition(previousNode, current); } return ret; }; Spotlight.silentlyFocus = function (...args) { if (!originSilentlyFocus) { return false; } const previousNode = Spotlight.getCurrent(); focusLoggingSuppressed += 1; let ret; try { ret = originSilentlyFocus.apply(this, args); } finally { focusLoggingSuppressed = Math.max(0, focusLoggingSuppressed - 1); } const current = Spotlight.getCurrent(); if (current !== previousNode) { logFocusTransition(previousNode, current); } return ret; }; // Spotlight Focus 추적 로그 [251115] // DOM 이벤트 리스너로 대체 // document.addEventListener('focusin', (ev) => { // console.log('[SPOTLIGHT FOCUS-IN]', ev.target); // }); // document.addEventListener('focusout', (ev) => { // console.log('[SPOTLIGHT FOCUS-OUT]', ev.target); // }); // // Spotlight 커스텀 이벤트가 있다면 추가 // if (typeof Spotlight !== 'undefined' && Spotlight.addEventListener) { // Spotlight.addEventListener('focus', (ev) => { // console.log('[SPOTLIGHT: focus]', ev.target); // }); // } function AppBase(_props /* eslint-disable-line no-unused-vars */) { const dispatch = useDispatch(); const httpHeader = useSelector((state) => state.common.httpHeader); const httpHeaderRef = useRef(httpHeader); const webOSVersion = useSelector((state) => state.common.appStatus.webOSVersion); const deviceId = useSelector((state) => state.common.appStatus.deviceId); const loginUserData = useSelector((state) => state.common.appStatus.loginUserData); const loginUserDataRef = useRef(loginUserData); const cursorVisible = useSelector((state) => state.common.appStatus.cursorVisible); const introTermsAgree = useSelector((state) => state.common.introTermsAgree); const deviceRegistered = useSelector((state) => state.common.deviceRegistered); // const optionalTermsAgree = useSelector((state) => state.common.optionalTermsAgree); const termsLoading = useSelector((state) => state.common.termsLoading); // termsFlag 전체 상태 확인 // const termsFlag = useSelector((state) => state.common.termsFlag); const termsData = useSelector((state) => state.home.termsData); // // 🔽 Spotlight focus/blur 로그 (옵션) // useEffect(() => { // if (!Config.FOCUS_DEBUG) { // return undefined; // } // const handleFocusLog = (event) => { // const spotlightId = resolveSpotlightIdFromEvent(event); // if (!spotlightId || spotlightId === lastLoggedSpotlightId) { // return; // } // console.log(`[SpotlightFocus] focus - ${spotlightId}`); // lastLoggedSpotlightId = spotlightId; // }; // const handleBlurLog = (event) => { // const spotlightId = resolveSpotlightIdFromEvent(event); // if (!spotlightId || spotlightId === lastLoggedBlurSpotlightId) { // return; // } // console.log(`[SpotlightFocus] blur - ${spotlightId}`); // lastLoggedBlurSpotlightId = spotlightId; // }; // const hasSpotlightListener = typeof Spotlight.addEventListener === 'function'; // if (hasSpotlightListener) { // Spotlight.addEventListener('focus', handleFocusLog); // Spotlight.addEventListener('blur', handleBlurLog); // return () => { // Spotlight.removeEventListener('focus', handleFocusLog); // Spotlight.removeEventListener('blur', handleBlurLog); // }; // } // if (typeof document !== 'undefined') { // document.addEventListener('spotlightfocus', handleFocusLog); // document.addEventListener('spotlightblur', handleBlurLog); // return () => { // document.removeEventListener('spotlightfocus', handleFocusLog); // document.removeEventListener('spotlightblur', handleBlurLog); // }; // } // return undefined; // }, [Config.FOCUS_DEBUG]); useEffect(() => { if (termsData && termsData.data && termsData.data.terms) { dispatch(getTermsAgreeYn()); } }, [termsData, dispatch]); const introTermsAgreeRef = usePrevious(introTermsAgree); const logEnable = useSelector((state) => state.localSettings.logEnable); const oldDb8Deleted = useSelector((state) => state.localSettings.oldDb8Deleted); // const macAddress = useSelector((state) => state.common.macAddress); const deviceCountryCode = (httpHeader && httpHeader['X-Device-Country']) || ''; useEffect(() => { if (!cursorVisible && !Spotlight.getCurrent()) { Spotlight.focus(); } }, [cursorVisible]); useEffect(() => { if (logEnable) { enableConsole(); } else { disableConsole(); } }, [logEnable]); useEffect(() => { if (!oldDb8Deleted) { dispatch(deleteOldDb8Datas()); } }, [oldDb8Deleted, dispatch]); const hideCursor = useRef( new Job((func) => { func(); console.log('hide cursor'); }, 5000) ); // 컴포넌트에서 모니터링 시작 - 한시적 모니터링 // useEffect(() => { // startFocusMonitoring(); // return () => stopFocusMonitoring(); // }, []); // 임시 작업용 코드 -> 인트로 팝업 표시 // useEffect(() => { // const timer = setTimeout(() => { // dispatch( // pushPanel({ name: Config.panel_names.INTRO_PANEL, panelInfo: {} }) // ); // }, 1000); // return () => clearTimeout(timer); // }, [dispatch]); // called by [receive httpHeader, launch, relaunch] const initService = useCallback( (haveyInit = true) => { // console.log( // "<<<<<<<<<<<<< appinfo >>>>>>>>>>>>{heavyInit, appinfo} ", // haveyInit, // appinfo // ); // console.log('[App.js] initService,httpHeaderRef.current', httpHeaderRef.current); // console.log('[App.js] haveyInit', haveyInit); // 앱 초기화 시 HomePanel 자동 기록 // console.log('[App.js] Recording initial HomePanel on app start'); dispatch( enqueuePanelHistory( 'homepanel', {}, 'APP_INITIALIZE', new Date().toISOString(), false, // fromGNB: false (앱 초기화) false // fromResetPanel: false (앱 초기화) ) ); if (httpHeaderRef.current) { if (haveyInit) { dispatch(changeAppStatus({ connectionFailed: false })); if (typeof window === 'object' && window.PalmSystem) { dispatch( changeAppStatus({ // Chromium68 호환성을 위해 Optional Chaining 제거 cursorVisible: window.PalmSystem && window.PalmSystem.cursor && window.PalmSystem.cursor.visibility, }) ); } dispatch(getHomeMenu()); dispatch(getMyRecommandedKeyword()); dispatch(getMyUpcomingAlertShow()); } const launchParams = getLaunchParams(); // console.log( // 'initService...{haveyInit, launchParams}', // haveyInit, // JSON.stringify(launchParams) // ); // pyh TODO: edit or delete later (line 196 ~ 198) // Chromium68 호환성을 위해 Optional Chaining 제거 if (launchParams && launchParams.bypass) { dispatch(handleBypassLink(launchParams.bypass)); } if (launchParams && launchParams.contentTarget) { dispatch(handleDeepLink(launchParams.contentTarget)); } else { dispatch( sendLogTotalRecommend({ contextName: Config.LOG_CONTEXT_NAME.ENTRY, messageId: Config.LOG_MESSAGE_ID.ENTRY_INFO, entry_menu: 'App', }) ); } dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); dispatch( sendLogTotalRecommend({ contextName: Config.LOG_CONTEXT_NAME.SHOPTIME, messageId: Config.LOG_MESSAGE_ID.VIEW_CHANGE, visible: true, }) ); clearLaunchParams(); } }, [dispatch], ); const handleRelaunchEvent = useCallback(() => { // console.log('[App] handleRelaunchEvent triggered'); const launchParams = getLaunchParams(); clearLaunchParams(); if (!launchParams) { if (introTermsAgreeRef.current) { initService(false); } if (typeof window === 'object' && window.PalmSystem) { window.PalmSystem.activate(); } return; } /* VUI_DISABLE_START - VUI Intent 처리 비활성화 */ // Voice Intent 처리 (최우선) // if (launchParams.intent) { // const { intent, intentParam, languageCode } = launchParams; // console.log('[App] Voice Intent received:', { intent, intentParam, languageCode }); // // SearchContent 또는 PlayContent intent 처리 // if (intent === 'SearchContent' || intent === 'PlayContent') { // dispatch( // pushPanel({ // name: Config.panel_names.SEARCH_PANEL, // panelInfo: { // voiceSearch: true, // 음성 검색 플래그 // searchVal: intentParam, // 검색어 // languageCode: languageCode, // }, // }) // ); // console.log(`[App] Opening SearchPanel with voice query: ${intentParam}`); // if (typeof window === 'object' && window.PalmSystem) { // window.PalmSystem.activate(); // } // return; // } // } /* VUI_DISABLE_END */ // 기존 로직 유지 if (introTermsAgreeRef.current) { initService(false); } if (typeof window === 'object' && window.PalmSystem) { window.PalmSystem.activate(); } }, [initService, introTermsAgreeRef]); const visibilityChanged = useCallback(() => { // console.log('document is hidden', document.hidden); // console.log('document.visibilityState= ', document.visibilityState); if (document.hidden && typeof window === 'object') { clearTimeout(foreGroundChangeTimer); } else { // change to foreground // set foreground flag using delay time. clearTimeout(foreGroundChangeTimer); foreGroundChangeTimer = setTimeout(() => { // console.log( // 'visibility changed !!! ==> set to foreground cursorVisible', // // Chromium68 호환성을 위해 Optional Chaining 제거 // JSON.stringify( // window.PalmSystem && window.PalmSystem.cursor && window.PalmSystem.cursor.visibility // ) // ); // eslint-disable-line no-console if (platform.platformName !== 'webos') { //for debug dispatch( changeAppStatus({ isAppForeground: true, cursorVisible: !platform.touchscreen, }) ); } else if (typeof window === 'object') { dispatch( changeAppStatus({ isAppForeground: true, // Chromium68 호환성을 위해 Optional Chaining 제거 cursorVisible: window.PalmSystem && window.PalmSystem.cursor && window.PalmSystem.cursor.visibility, }) ); } }, 1000); } }, [dispatch]); useEffect(() => { const keyDownEvent = (_event /* eslint-disable-line no-unused-vars */) => { dispatch(changeAppStatus({ cursorVisible: false })); Spotlight.setPointerMode(false); }; // throttle을 사용하여 마우스 이동 이벤트 최적화 (100ms마다 최대 1회 실행) let lastMoveTime = 0; const THROTTLE_MS = 100; const mouseMoveEvent = (_event /* eslint-disable-line no-unused-vars */) => { const now = Date.now(); if (now - lastMoveTime < THROTTLE_MS) { // throttle 기간 내에는 hideCursor만 재시작 hideCursor.current.start(() => { dispatch(changeAppStatus({ cursorVisible: false })); Spotlight.setPointerMode(false); }); return; } lastMoveTime = now; dispatch(changeAppStatus({ cursorVisible: true })); Spotlight.setPointerMode(true); hideCursor.current.start(() => { dispatch(changeAppStatus({ cursorVisible: false })); Spotlight.setPointerMode(false); }); }; if (typeof window === 'object' && window.PalmSystem) { window.PalmSystem.activate(); window.lunaTest = (service, method, subscribe, parameters) => lunaTest(service, method, subscribe, parameters); } dispatch(getConnectionStatus()); dispatch(getConnectionInfo()); dispatch(getDeviceId()); dispatch(getHttpHeaderForServiceRequest()); dispatch(getSystemSettings()); document.addEventListener('visibilitychange', visibilityChanged); document.addEventListener('webOSRelaunch', handleRelaunchEvent); //local virtual cursorvisiblilty if (typeof window === 'object' && !window.PalmSystem) { document.addEventListener('keydown', keyDownEvent, true); document.addEventListener('mousemove', mouseMoveEvent, true); document.addEventListener('wheel', mouseMoveEvent, true); } return () => { document.removeEventListener('visibilitychange', visibilityChanged); document.removeEventListener('webOSRelaunch', handleRelaunchEvent); if (typeof window === 'object' && !window.PalmSystem) { document.removeEventListener('keydown', keyDownEvent); document.removeEventListener('mousemove', mouseMoveEvent); document.removeEventListener('wheel', mouseMoveEvent); } }; }, [dispatch, visibilityChanged, handleRelaunchEvent]); useEffect(() => { let userDataChanged = false; if (JSON.stringify(loginUserDataRef.current) !== JSON.stringify(loginUserData)) { userDataChanged = true; } else if (userDataChanged || httpHeaderRef.current === null) { //계정정보 변경시 또는 초기 로딩시 if (!httpHeader) { dispatch( changeAppStatus({ showLoadingPanel: { show: true, type: 'launching' }, }) ); } dispatch(checkFirstLaunch()); dispatch( getHomeTerms({ mbrNo: loginUserData.userNumber, trmsTpCdList: 'MST00401, MST00402, MST00405', // 선택약관 추가 25.06 }) ); httpHeaderRef.current = httpHeader; } loginUserDataRef.current = loginUserData; }, [httpHeader, deviceId, dispatch, loginUserData]); useEffect(() => { if ( webOSVersion && Number(webOSVersion) >= 6 && deviceCountryCode && deviceCountryCode === 'US' && deviceId ) { dispatch(getShoptimeTerms()); } }, [webOSVersion, deviceId, dispatch, deviceCountryCode]); // 테스트용 인트로 화면 표시 // useEffect(() => { // setTimeout(() => { // console.log("App.js optionalTermsTest 팝업 표시"); // dispatch(setShowPopup({ activePopup: "optionalTermsConfirmBottom" })); // }, 1000); // }, [dispatch]); // 약관 동의 및 선택 약관 팝업 처리 useEffect(() => { if (introTermsAgree === undefined || termsLoading) { // 약관 동의 여부 확인 전에는 아무것도 하지 않음 return; } console.log('[App.js] deviceRegistered', deviceRegistered); if (introTermsAgree || deviceRegistered) { initService(true); } else { // 필수 약관에 동의하지 않은 경우 dispatch(pushPanel({ name: Config.panel_names.INTRO_PANEL, panelInfo: {} })); dispatch(changeAppStatus({ showLoadingPanel: { show: false } })); } }, [introTermsAgree, deviceRegistered, dispatch, initService, termsLoading]); useEffect(() => { const launchParmas = getLaunchParams(); const linkTpNm = launchParmas.contentTarget ? launchParmas.contentTarget.split('_')[2] || '' : Config.LOG_MENU.APP; const linkTpCd = launchParmas.contentTarget ? launchParmas.contentTarget.split('_')[1] || '' : '1000'; if (launchParmas.contentTarget) { dispatch( setDeepLink({ contentTarget: launchParmas.contentTarget, isDeepLink: true, }) ); } dispatch(setGNBMenu(linkTpNm)); dispatch( setSecondLayerInfo({ deeplinkId: launchParmas.contentTarget ?? '', linkTpCd, logTpNo: Config.LOG_TP_NO.SECOND_LAYER, }) ); }, [dispatch, initService]); return ( {webOSVersion === '' ? null : Number(webOSVersion) < 4 ? ( ) : ( )} {/* */} ); } const App = ThemeDecorator({ noAutoFocus: true }, AppBase); export default App; export { App, AppBase };