From f70e2b1a214f89ce2c6f2689e2660d0b63472372 Mon Sep 17 00:00:00 2001 From: optrader Date: Sun, 19 Oct 2025 23:37:30 +0900 Subject: [PATCH] [251019] fix: Resolve warnings-1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ• ์ปค๋ฐ‹ ์‹œ๊ฐ„: 2025. 10. 19. 23:37:25 ๐Ÿ“Š ๋ณ€๊ฒฝ ํ†ต๊ณ„: โ€ข ์ด ํŒŒ์ผ: 18๊ฐœ โ€ข ์ถ”๊ฐ€: +347์ค„ โ€ข ์‚ญ์ œ: -449์ค„ ๐Ÿ“ ์ˆ˜์ •๋œ ํŒŒ์ผ: ~ com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx ~ com.twin.app.shoptime/src/utils/fp.js ~ com.twin.app.shoptime/src/utils/helperMethods.js ~ com.twin.app.shoptime/src/utils/lodashFpEx.js ~ com.twin.app.shoptime/src/utils/spotlight-utils.js ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerItemCard/PlayerItemCard.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ShowCard.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoicePromptScreen.jsx ~ com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceResponse.jsx ~ com.twin.app.shoptime/src/views/UserReview/ShowUserReviews.jsx ๐Ÿ”ง ํ•จ์ˆ˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ: ๐Ÿ“Š Function-level changes summary across 18 files: โ€ข Functions added: 8 โ€ข Functions modified: 14 โ€ข Functions deleted: 17 ๐Ÿ“‹ By language: โ€ข javascript: 18 files, 39 function changes ๐Ÿ”ง ์ฃผ์š” ๋ณ€๊ฒฝ ๋‚ด์šฉ: โ€ข UI ์ปดํฌ๋„ŒํŠธ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„  โ€ข ๊ณตํ†ต ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ ์ตœ์ ํ™” Performance: ์ฝ”๋“œ ์ตœ์ ํ™”๋กœ ์„ฑ๋Šฅ ๊ฐœ์„  ๊ธฐ๋Œ€ --- .../components/VideoPlayer/MediaPlayer.jsx | 86 +++--- com.twin.app.shoptime/src/utils/fp.js | 144 ++++++--- .../src/utils/helperMethods.js | 274 +++++++---------- com.twin.app.shoptime/src/utils/lodashFpEx.js | 116 +++---- .../src/utils/spotlight-utils.js | 285 +++++++++--------- .../src/views/DetailPanel/DetailPanel.jsx | 13 - .../DetailPanelSkeleton.jsx | 76 ++--- .../PlayerItemCard/PlayerItemCard.jsx | 7 +- .../PlayerOverlay/PlayerOverlayContents.jsx | 75 ++--- .../src/views/SearchPanel/SearchPanel.new.jsx | 188 ++++++------ .../views/SearchPanel/SearchResults.new.jsx | 123 +++----- .../SearchPanel/SearchResultsNew/ItemCard.jsx | 21 +- .../SearchPanel/SearchResultsNew/ShowCard.jsx | 48 +-- .../src/views/SearchPanel/TInput/TInput.jsx | 8 +- .../VoiceInputOverlay/VoiceInputOverlay.jsx | 107 ++----- .../modes/VoicePromptScreen.jsx | 27 +- .../VoiceInputOverlay/modes/VoiceResponse.jsx | 12 +- .../src/views/UserReview/ShowUserReviews.jsx | 2 +- 18 files changed, 746 insertions(+), 866 deletions(-) diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx index 639ad47e..618358d6 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx +++ b/com.twin.app.shoptime/src/components/VideoPlayer/MediaPlayer.jsx @@ -42,20 +42,20 @@ import Announce from '@enact/ui/AnnounceDecorator/Announce'; import ComponentOverride from '@enact/ui/ComponentOverride'; import { FloatingLayerDecorator } from '@enact/ui/FloatingLayer'; import { FloatingLayerContext } from '@enact/ui/FloatingLayer/FloatingLayerDecorator'; -import Marquee from '@enact/ui/Marquee'; +// import Marquee from '@enact/ui/Marquee'; import Slottable from '@enact/ui/Slottable'; import Touchable from '@enact/ui/Touchable'; -import { panel_names } from '../../utils/Config'; +// import { panel_names } from '../../utils/Config'; import { $L } from '../../utils/helperMethods'; import { SpotlightIds } from '../../utils/SpotlightIds'; import Loader from '../Loader/Loader'; import { MediaControls, MediaSlider, secondsToTime, Times } from '../MediaPlayer'; import PlayerOverlayContents from '../../views/PlayerPanel/PlayerOverlay/PlayerOverlayContents'; import FeedbackContent from './FeedbackContent'; -import FeedbackTooltip from './FeedbackTooltip'; +// import FeedbackTooltip from './FeedbackTooltip'; import Media from './Media'; -import MediaTitle from './MediaTitle'; +// import MediaTitle from './MediaTitle'; import Overlay from './Overlay'; import TReactPlayer from './TReactPlayer'; import Video from './Video'; @@ -78,7 +78,7 @@ const calcNumberValueOfPlaybackRate = (rate) => { const pbArray = String(rate).split('/'); return pbArray.length > 1 ? parseInt(pbArray[0]) / parseInt(pbArray[1]) : parseInt(rate); }; -const SpottableBtn = Spottable('button'); +// const SpottableBtn = Spottable('button'); const SpottableDiv = Touchable(Spottable('div')); const RootContainer = SpotlightContainerDecorator( { @@ -113,7 +113,7 @@ const getDurFmt = (locale) => { const forwardWithState = (type) => adaptEvent(call('addStateToEvent'), forwardWithPrevent(type)); -const forwardToggleMore = forward('onToggleMore'); +// const forwardToggleMore = forward('onToggleMore'); // provide forwarding of events on media controls const forwardControlsAvailable = forward('onControlsAvailable'); @@ -2001,6 +2001,20 @@ const VideoPlayerBase = class extends React.Component { })); }; + onSpotlightFocus = () => { + this.showControls(); + + if (this.state.lastFocusedTarget) { + setTimeout(() => { + Spotlight.focus(this.state.lastFocusedTarget); + }); + } else { + setTimeout(() => { + Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON); + }); + } + }; + slider5WayPressJob = new Job(() => { this.setState({ slider5WayPressed: false }); }, 200); @@ -2087,9 +2101,9 @@ const VideoPlayerBase = class extends React.Component { className, modalClassName, disabled, - infoComponents, - backButton, - promotionTitle, + // infoComponents, + // backButton, + // promotionTitle, initialJumpDelay, jumpDelay, @@ -2105,14 +2119,14 @@ const VideoPlayerBase = class extends React.Component { spotlightDisabled, spotlightId, style, - thumbnailComponent, - thumbnailSrc, - title, + // thumbnailComponent, + // thumbnailSrc, + // title, introTime, - onClickSkipIntro, - onIntroDisabled, + // onClickSkipIntro, + // onIntroDisabled, videoComponent: VideoComponent, - cameraSettingsButton, + // cameraSettingsButton, onBackButton, panelInfo, selectedIndex, @@ -2129,18 +2143,18 @@ const VideoPlayerBase = class extends React.Component { disclaimer, liveTotalTime, currentLiveTimeSeconds, - themeProductInfos, - detailThemeProductImageLength, + // themeProductInfos, + // detailThemeProductImageLength, videoVerticalVisible, handleIndicatorDownClick, handleIndicatorUpClick, - orderPhnNo, + // orderPhnNo, captionEnable, countryCode, - setCurrentTime, - setIsVODPaused, + // setCurrentTime, + // setIsVODPaused, qrCurrentItem, - modalScale, + // modalScale, ...mediaProps } = this.props; @@ -2222,27 +2236,15 @@ const VideoPlayerBase = class extends React.Component { } } + // eslint-disable-next-line no-unused-vars const isQRCodeVisible = playListInfo && qrCurrentItem && !thumbnailUrl && !panelInfo.modal; - const onSpotlightFocus = () => { - this.showControls(); - - if (this.state.lastFocusedTarget) { - setTimeout(() => { - Spotlight.focus(this.state.lastFocusedTarget); - }); - } else { - setTimeout(() => { - Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON); - }); - } - }; - // MediaPanel์—์„œ๋Š” setIsVODPaused ์‚ฌ์šฉ ์•ˆ ํ•จ (PlayerPanel ์ „์šฉ) // if (panelInfo?.shptmBanrTpNm === 'VOD' || panelInfo?.shptmBanrTpNm === 'MEDIA') { // setIsVODPaused(this.state.paused); // } + // eslint-disable-next-line no-unused-vars const getVideoPhoneNumberClassNames = () => { const isQVC = panelInfo?.chanId === 'USQVC' || @@ -2393,7 +2395,7 @@ const VideoPlayerBase = class extends React.Component { playbackRate={this.pulsedPlaybackRate || this.selectPlaybackRate(this.speedIndex)} playbackState={this.pulsedPlaybackState || this.prevCommand} visible={this.state.miniFeedbackVisible && !noMiniFeedback} - > + /> + /> )} )} @@ -2483,11 +2485,11 @@ const VideoPlayerBase = class extends React.Component { holdConfig={controlsHandleAboveHoldConfig} onDown={this.handleControlsHandleAboveDown} onKeyUp={this.handleControlsHandleAboveKeyUp} - onSpotlightDown={onSpotlightFocus} - onSpotlightUp={onSpotlightFocus} - onSpotlightRight={onSpotlightFocus} - onSpotlightLeft={onSpotlightFocus} - onClick={onSpotlightFocus} + onSpotlightDown={this.onSpotlightFocus} + onSpotlightUp={this.onSpotlightFocus} + onSpotlightRight={this.onSpotlightFocus} + onSpotlightLeft={this.onSpotlightFocus} + onClick={this.onSpotlightFocus} selectionKeys={controlsHandleAboveSelectionKeys} spotlightDisabled={this.state.mediaControlsVisible || spotlightDisabled} /> diff --git a/com.twin.app.shoptime/src/utils/fp.js b/com.twin.app.shoptime/src/utils/fp.js index fe45aff2..03a88302 100644 --- a/com.twin.app.shoptime/src/utils/fp.js +++ b/com.twin.app.shoptime/src/utils/fp.js @@ -8,61 +8,127 @@ const safeFp = fp || {}; export const { // ๊ธฐ๋ณธ ํ•จ์ˆ˜ ์กฐํ•ฉ - pipe, flow, curry, compose, - + pipe, + flow, + curry, + compose, + // ๊ธฐ๋ณธ ์ปฌ๋ ‰์…˜ ํ•จ์ˆ˜๋“ค - map, filter, reduce, get, set, - + map, + filter, + reduce, + get, + set, + // ๊ธฐ๋ณธ ํƒ€์ž… ์ฒดํฌ ํ•จ์ˆ˜๋“ค - isEmpty, isNotEmpty, isNil, isNotNil, - + isEmpty, + isNotEmpty, + isNil, + isNotNil, + // ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋“ค - mapAsync, reduceAsync, filterAsync, findAsync, forEachAsync, - + mapAsync, + reduceAsync, + filterAsync, + findAsync, + forEachAsync, + // Promise ๊ด€๋ จ - promisify, then, andThen, otherwise, catch: catchFn, finally: finallyFn, + promisify, + then, + andThen, + otherwise, + catch: catchFn, + finally: finallyFn, isPromise, - + // ์กฐ๊ฑด๋ถ€ ์‹คํ–‰ ํ•จ์ˆ˜๋“ค - when, unless, ifElse, ifT, ifF, ternary, - + when, + unless, + ifElse, + ifT, + ifF, + ternary, + // ๋””๋ฒ„๊น… ๋ฐ ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ - tap, trace, - + tap, + trace, + // ์•ˆ์ „ํ•œ ์‹คํ–‰ - tryCatch, safeGet, getOr, - + tryCatch, + safeGet, + getOr, + // ํƒ€์ž… ์ฒดํฌ ํ™•์žฅ - isJson, notEquals, isNotEqual, isVal, isPrimitive, isRef, isReference, - not, notIncludes, toBool, isFalsy, isTruthy, - + isJson, + notEquals, + isNotEqual, + isVal, + isPrimitive, + isRef, + isReference, + not, + notIncludes, + toBool, + isFalsy, + isTruthy, + // ๊ฐ์ฒด ๋ณ€ํ™˜ - transformObjectKey, toCamelcase, toCamelKey, toSnakecase, toSnakeKey, - toPascalcase, pascalCase, renameKeys, - + transformObjectKey, + toCamelcase, + toCamelKey, + toSnakecase, + toSnakeKey, + toPascalcase, + pascalCase, + renameKeys, + // ๋ฐฐ์—ด ์œ ํ‹ธ๋ฆฌํ‹ฐ - mapWhen, filterWhen, removeByIndex, removeByIdx, removeLast, - append, prepend, insertAt, partition, - + mapWhen, + filterWhen, + removeByIndex, + removeByIdx, + removeLast, + append, + prepend, + insertAt, + partition, + // ํ•จ์ˆ˜ ์กฐํ•ฉ ์œ ํ‹ธ๋ฆฌํ‹ฐ - ap, applyTo, juxt, converge, instanceOf, - + ap, + applyTo, + juxt, + converge, + instanceOf, + // ๋ฌธ์ž์—ด ์œ ํ‹ธ๋ฆฌํ‹ฐ - trimToUndefined, capitalize, isDatetimeString, - + trimToUndefined, + capitalize, + isDatetimeString, + // ์ˆ˜ํ•™ ์œ ํ‹ธ๋ฆฌํ‹ฐ - clampTo, between, - + clampTo, + between, + // ๊ธฐ๋ณธ๊ฐ’ ์ฒ˜๋ฆฌ - defaultTo, defaultWith, elvis, - + defaultTo, + defaultWith, + elvis, + // ํ‚ค ๊ด€๋ จ - key, keyByVal, - mapWithKey, mapWithIdx, forEachWithKey, forEachWithIdx, - reduceWithKey, reduceWithIdx, - + key, + keyByVal, + mapWithKey, + mapWithIdx, + forEachWithKey, + forEachWithIdx, + reduceWithKey, + reduceWithIdx, + // ์œ ํ‹ธ๋ฆฌํ‹ฐ - deepFreeze, times, lazy, + deepFreeze, + times, + lazy, } = safeFp; -export default safeFp; \ No newline at end of file +export default safeFp; diff --git a/com.twin.app.shoptime/src/utils/helperMethods.js b/com.twin.app.shoptime/src/utils/helperMethods.js index 704fe362..e8b5e80b 100644 --- a/com.twin.app.shoptime/src/utils/helperMethods.js +++ b/com.twin.app.shoptime/src/utils/helperMethods.js @@ -1,20 +1,18 @@ -import { Job } from "@enact/core/util"; -import Enact_$L from "@enact/i18n/$L"; +import { Job } from '@enact/core/util'; -import stringReSourceDe from "../../resources/de/strings.json"; -import stringReSourceEn from "../../resources/en/strings.json"; -import stringReSourceGb from "../../resources/gb/strings.json"; -import stringReSourceRu from "../../resources/ru/strings.json"; -import { getRicCode } from "../api/apiConfig"; -import { ERROR_MESSAGES_GROUPS, SECRET_KEY } from "./Config"; +import stringReSourceDe from '../../resources/de/strings.json'; +import stringReSourceEn from '../../resources/en/strings.json'; +import stringReSourceGb from '../../resources/gb/strings.json'; +import stringReSourceRu from '../../resources/ru/strings.json'; +import { ERROR_MESSAGES_GROUPS, SECRET_KEY } from './Config'; let _boundingRectCache = {}; const BOUNDING_RECT_IGNORE_TIME = 10; const generateUUID = () => { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { - var r = (Math.random() * 16) | 0, - v = c === "x" ? r : (r & 0x3) | 0x8; + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); }; @@ -37,10 +35,7 @@ export const getBoundingClientRect = (node) => { const uuid = node.dataset.uuid; if (_boundingRectCache[uuid]) { - if ( - Date.now() - _boundingRectCache[uuid].called < - BOUNDING_RECT_IGNORE_TIME - ) { + if (Date.now() - _boundingRectCache[uuid].called < BOUNDING_RECT_IGNORE_TIME) { return _boundingRectCache[uuid].boundingRect; } } @@ -63,42 +58,38 @@ const stringReSource = { }; export const $L = (str) => { - let languageSetting = "system"; - let resourceKey = ""; + let languageSetting = 'system'; + let resourceKey = ''; - if (typeof window === "object" && window.store) { + if (typeof window === 'object' && window.store) { languageSetting = window.store.getState().localSettings.languageSetting; - if (languageSetting === "system") { + if (languageSetting === 'system') { resourceKey = window.store.getState().common.httpHeader?.cntry_cd; } else { resourceKey = languageSetting; } } const resource = stringReSource[resourceKey]; - if (typeof str === "object") { + if (typeof str === 'object') { if (resource && resource[str.key]) { - return resource[str.key].replace(/{br}/g, "{br}"); + return resource[str.key].replace(/{br}/g, '{br}'); } else { return str.value; } } else if (resource && resource[str]) { - return resource[str].replace(/{br}/g, "{br}"); + return resource[str].replace(/{br}/g, '{br}'); } - return str && str.replace(/{br}/g, "{br}"); + return str && str.replace(/{br}/g, '{br}'); }; export const createQueryString = (object) => { const parts = []; for (const key of Object.getOwnPropertyNames(object)) { - if ( - object[key] !== null && - object[key] !== undefined && - object[key] !== "" - ) { + if (object[key] !== null && object[key] !== undefined && object[key] !== '') { parts.push(`${key}=${encodeURIComponent(object[key])}`); } } - return parts.join("&"); + return parts.join('&'); }; export const wait = (time) => { @@ -110,14 +101,14 @@ export const wait = (time) => { }; export const scaleW = (value) => { - if (typeof window === "object") { + if (typeof window === 'object') { return value * (window.innerWidth / 1920); } return value; }; export const scaleH = (value) => { - if (typeof window === "object") { + if (typeof window === 'object') { return value * (window.innerHeight / 1080); } return value; @@ -150,14 +141,10 @@ let localLaunchParams = { export const getLaunchParams = () => { let params = {}; - if ( - typeof window === "object" && - window.PalmSystem && - window.PalmSystem.launchParams - ) { + if (typeof window === 'object' && window.PalmSystem && window.PalmSystem.launchParams) { try { params = JSON.parse(window.PalmSystem.launchParams); - if (params["x-webos-app-container-launch"] === true) { + if (params['x-webos-app-container-launch'] === true) { params = params.details; } } catch (e) { @@ -170,28 +157,24 @@ export const getLaunchParams = () => { }; export const clearLaunchParams = () => { - console.log("common.clearLaunchParams"); - if ( - typeof window === "object" && - window.PalmSystem && - window.PalmSystem.launchParams - ) { - window.PalmSystem.launchParams = ""; + console.log('common.clearLaunchParams'); + if (typeof window === 'object' && window.PalmSystem && window.PalmSystem.launchParams) { + window.PalmSystem.launchParams = ''; } else { localLaunchParams = {}; } }; export const readLocalStorage = (key, defaultValue) => { - const value = typeof window === "object" && window.localStorage.getItem(key); + const value = typeof window === 'object' && window.localStorage.getItem(key); if (!value && defaultValue !== undefined) { return defaultValue; } - return value === "undefined" ? null : JSON.parse(value); + return value === 'undefined' ? null : JSON.parse(value); }; export const writeLocalStorage = (key, value) => { - if (typeof window === "object") { + if (typeof window === 'object') { window.localStorage.setItem(key, JSON.stringify(value)); } }; @@ -199,34 +182,29 @@ export const writeLocalStorage = (key, value) => { export const convertToTimeFormat = (timeString, isIncludeDate = false) => { const date = new Date(timeString); - let options = { hour: "numeric", minute: "2-digit", hour12: true }; - let pattern = " "; + let options = { hour: 'numeric', minute: '2-digit', hour12: true }; + let pattern = ' '; if (isIncludeDate) { options = { ...options, - month: "2-digit", - day: "2-digit", - year: "numeric", - hour: "2-digit", + month: '2-digit', + day: '2-digit', + year: 'numeric', + hour: '2-digit', }; - pattern = ","; + pattern = ','; } - return new Intl.DateTimeFormat("en-US", options) - .format(date) - .replace(pattern, ""); + return new Intl.DateTimeFormat('en-US', options).format(date).replace(pattern, ''); }; -export const getTranslate3dValueByDirection = ( - element, - isHorizontal = true -) => { +export const getTranslate3dValueByDirection = (element, isHorizontal = true) => { try { const transformStyle = window.getComputedStyle(element).transform; - if (!transformStyle || transformStyle === "none") { - throw new Error("transfrom style not found"); + if (!transformStyle || transformStyle === 'none') { + throw new Error('transfrom style not found'); } const transformMatrix = transformStyle.match(/^matrix\((.+)\)$/); @@ -234,7 +212,7 @@ export const getTranslate3dValueByDirection = ( let index, value; if (transformMatrix) { - const matrixValues = transformMatrix[1].split(", "); + const matrixValues = transformMatrix[1].split(', '); index = isHorizontal ? 4 : 5; @@ -248,28 +226,22 @@ export const getTranslate3dValueByDirection = ( }; export const formatGMTString = (date) => { - let string = date.toISOString().replace(/T/, " ").replace(/\..+/, ""); + let string = date.toISOString().replace(/T/, ' ').replace(/\..+/, ''); return string; }; export const getSpottableDescendants = (containerId) => { - let container = document.querySelector( - `[data-spotlight-id="${containerId}"]` - ); + let container = document.querySelector(`[data-spotlight-id="${containerId}"]`); if (container) { return container.querySelectorAll('[class*="spottable"]'); } return []; }; -export const isElementInContainer = ( - element, - container, - fullyVisible = true -) => { +export const isElementInContainer = (element, container, fullyVisible = true) => { // ์š”์†Œ์™€ ์ปจํ…Œ์ด๋„ˆ์˜ ์‚ฌ๊ฐํ˜• ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ - if (typeof window === "object") { + if (typeof window === 'object') { const elementRect = getBoundingClientRect(element); const containerRect = container ? getBoundingClientRect(container) @@ -334,9 +306,7 @@ export const getRectDiff = (element1, element2) => { }; export const getFormattingCardNo = (cardNumber) => { - return `${"*".repeat(12)}${cardNumber.slice(-4)}` - .replace(/(.{4})/g, "$1-") - .slice(0, -1); + return `${'*'.repeat(12)}${cardNumber.slice(-4)}`.replace(/(.{4})/g, '$1-').slice(0, -1); }; export const getQRCodeUrl = ({ @@ -345,41 +315,41 @@ export const getQRCodeUrl = ({ index, patnrId, prdtId, - dirPurcSelYn = "Y", + dirPurcSelYn = 'Y', prdtData, qrType, - liveFlag = "Y", + liveFlag = 'Y', entryMenu, nowMenu, }) => { if (!serverHOST) { - console.error("getQRCodeUrl: Not Supported, Host is missing"); + console.error('getQRCodeUrl: Not Supported, Host is missing'); return {}; } - let sdpURL = serverHOST.split(".")[0]; - let countryCode = ""; + let sdpURL = serverHOST.split('.')[0]; + let countryCode = ''; - if (sdpURL.indexOf("-") > 0) { - countryCode = sdpURL.split("-")[1]; + if (sdpURL.indexOf('-') > 0) { + countryCode = sdpURL.split('-')[1]; } else { countryCode = sdpURL; } sdpURL = sdpURL.toLowerCase(); - if (serverType !== "system") { + if (serverType !== 'system') { sdpURL = serverType; } - let baseUrl = ""; + let baseUrl = ''; - if (sdpURL.indexOf("qt2") >= 0) { - baseUrl = "https://qt2-m.shoptime.lgappstv.com/"; - } else if (sdpURL.indexOf("qt") >= 0) { - baseUrl = "https://qt-m.shoptime.lgappstv.com/"; + if (sdpURL.indexOf('qt2') >= 0) { + baseUrl = 'https://qt2-m.shoptime.lgappstv.com/'; + } else if (sdpURL.indexOf('qt') >= 0) { + baseUrl = 'https://qt-m.shoptime.lgappstv.com/'; } else { - baseUrl = "https://m.shoptime.lgappstv.com/"; + baseUrl = 'https://m.shoptime.lgappstv.com/'; } const prdtDataStr = JSON.stringify(prdtData); const prdtDataBase64 = btoa(prdtDataStr); @@ -402,25 +372,25 @@ export const getQRCodeUrl = ({ // ex: JANUARY 01, 2024 export const getFormattingDate = (dateString) => { - const date = new Date(dateString.replace(" ", "T")); + const date = new Date(dateString.replace(' ', 'T')); const monthNames = [ - $L("JANUARY"), - $L("FEBRUARY"), - $L("MARCH"), - $L("APRIL"), - $L("MAY"), - $L("JUNE"), - $L("JULY"), - $L("AUGUST"), - $L("SEPTEMBER"), - $L("OCTOBER"), - $L("NOVEMBER"), - $L("DECEMBER"), + $L('JANUARY'), + $L('FEBRUARY'), + $L('MARCH'), + $L('APRIL'), + $L('MAY'), + $L('JUNE'), + $L('JULY'), + $L('AUGUST'), + $L('SEPTEMBER'), + $L('OCTOBER'), + $L('NOVEMBER'), + $L('DECEMBER'), ]; const month = monthNames[date.getMonth()]; - const day = date.getDate().toString().padStart(2, "0"); + const day = date.getDate().toString().padStart(2, '0'); const year = date.getFullYear(); return `${month} ${day}, ${year}`; @@ -437,14 +407,14 @@ export const removeSpecificTags = (html) => { let sanitizedHtml = html; tagPatterns.forEach((pattern) => { - sanitizedHtml = sanitizedHtml.replace(pattern, ""); + sanitizedHtml = sanitizedHtml.replace(pattern, ''); }); return sanitizedHtml; }; export const encryptPhoneNumber = (phoneNumber) => { - if (typeof window === "object") { + if (typeof window === 'object') { return window.CryptoJS.AES.encrypt(phoneNumber, SECRET_KEY).toString(); } @@ -452,7 +422,7 @@ export const encryptPhoneNumber = (phoneNumber) => { }; export const decryptPhoneNumber = (encryptedPhoneNumber) => { - if (typeof window === "object") { + if (typeof window === 'object') { const bytes = window.CryptoJS.AES.decrypt(encryptedPhoneNumber, SECRET_KEY); return bytes.toString(window.CryptoJS.enc.Utf8); } @@ -461,63 +431,54 @@ export const decryptPhoneNumber = (encryptedPhoneNumber) => { }; export const formatLocalDateTime = (date) => { - const isDate = (obj) => - Object.prototype.toString.call(obj) === "[object Date]"; + const isDate = (obj) => Object.prototype.toString.call(obj) === '[object Date]'; - if (typeof window === "object" && isDate(date)) { + if (typeof window === 'object' && isDate(date)) { const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, "0"); - const day = String(date.getDate()).padStart(2, "0"); - const hours = String(date.getHours()).padStart(2, "0"); - const minutes = String(date.getMinutes()).padStart(2, "0"); - const seconds = String(date.getSeconds()).padStart(2, "0"); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } - return ""; + return ''; }; export const parseLocalizedNumber = (numberString, countryCode) => { // ์œ ๋Ÿฝ์‹: 1.499,00 -> 1499.00 - if (countryCode === "DE") { - return parseFloat(numberString.replace(/\./g, "").replace(",", ".")); + if (countryCode === 'DE') { + return parseFloat(numberString.replace(/\./g, '').replace(',', '.')); } // ๋ฏธ๊ตญ์‹: 1,499.00 -> 1499.00 - if (countryCode === "US" || countryCode === "GB") { - return parseFloat(numberString.replace(/[^0-9.-]+/g, "")); + if (countryCode === 'US' || countryCode === 'GB') { + return parseFloat(numberString.replace(/[^0-9.-]+/g, '')); } // ๋Ÿฌ์‹œ์•„์‹: 1 499,00 -> 1499.00 - if (countryCode === "RU") { - return parseFloat(numberString.replace(/\s/g, "").replace(",", ".")); + if (countryCode === 'RU') { + return parseFloat(numberString.replace(/\s/g, '').replace(',', '.')); } return parseFloat(numberString); }; -export const formatCurrencyValue = ( - value, - currSign, - currSignLoc, - isDiscount = false -) => { - if (value === "-" || value === 0) return "-"; +export const formatCurrencyValue = (value, currSign, currSignLoc, isDiscount = false) => { + if (value === '-' || value === 0) return '-'; const numValue = parseFloat(value); - if (isNaN(numValue)) return "-"; + if (isNaN(numValue)) return '-'; - const sign = isDiscount && numValue > 0 ? "- " : ""; - const formattedValue = parseFloat(numValue.toFixed(2)).toLocaleString( - "en-US", - { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - } - ); + const sign = isDiscount && numValue > 0 ? '- ' : ''; + const formattedValue = parseFloat(numValue.toFixed(2)).toLocaleString('en-US', { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }); if (!currSign || !currSignLoc) return `${sign}${formattedValue}`; - return currSignLoc === "L" + return currSignLoc === 'L' ? `${sign}${currSign} ${formattedValue}` : `${sign}${formattedValue} ${currSign}`; }; @@ -536,44 +497,31 @@ export const getTimeDifferenceByMilliseconds = ( return false; } - const convertedStartTime = new Date(startTimeString.replace(/ /, "T") + "Z"); - const convertedEndTime = new Date(endTimeString.replace(/ /, "T") + "Z"); + const convertedStartTime = new Date(startTimeString.replace(/ /, 'T') + 'Z'); + const convertedEndTime = new Date(endTimeString.replace(/ /, 'T') + 'Z'); const timeDifference = convertedEndTime - convertedStartTime; return timeDifference > threshold; }; -export const getErrorMessage = ( - errorCode, - retMsg, - retDetailCode, - returnBindStrings -) => { - const group = ERROR_MESSAGES_GROUPS.find((group) => - group.codes.includes(Number(errorCode)) - ); +export const getErrorMessage = (errorCode, retMsg, retDetailCode, returnBindStrings) => { + const foundGroup = ERROR_MESSAGES_GROUPS.find((group) => group.codes.includes(Number(errorCode))); const errorPrefix = errorCode ? retDetailCode ? `[${errorCode}-${retDetailCode}] ` : `[${errorCode}] ` - : ""; + : ''; - if (group) { - if ( - errorCode === 1120 && - returnBindStrings && - typeof returnBindStrings === "object" - ) { - return `${errorPrefix} ${group.message} (ID: ${returnBindStrings.join( - ", " - )})`; + if (foundGroup) { + if (errorCode === 1120 && returnBindStrings && typeof returnBindStrings === 'object') { + return `${errorPrefix} ${foundGroup.message} (ID: ${returnBindStrings.join(', ')})`; } - return errorPrefix + group.message; + return errorPrefix + foundGroup.message; } else if (retMsg) { return errorPrefix + retMsg; } else { - return errorPrefix + "An unknown error occurred. Please try again later."; + return errorPrefix + 'An unknown error occurred. Please try again later.'; } }; diff --git a/com.twin.app.shoptime/src/utils/lodashFpEx.js b/com.twin.app.shoptime/src/utils/lodashFpEx.js index 88b2cc76..82d4c97a 100644 --- a/com.twin.app.shoptime/src/utils/lodashFpEx.js +++ b/com.twin.app.shoptime/src/utils/lodashFpEx.js @@ -24,7 +24,7 @@ const promisify = (a, ...args) => { const cond = fp.cond([ [fp.isFunction, () => fnPromisify(a, ...args)], [isPromise, fp.identity], - [fp.T, (a) => Promise.resolve(a)], + [fp.T, (val) => Promise.resolve(val)], ]); const result = cond(a); @@ -75,7 +75,7 @@ const toBool = (a) => fp.cond([ [fp.equals('true'), fp.T], [fp.equals('false'), fp.F], - [fp.T, (a) => !!a], + [fp.T, (val) => !!val], ])(a); /** @@ -83,9 +83,9 @@ const toBool = (a) => * (isTrue๊ฐ€ true๋ฉด t(์‹คํ–‰)๋ฐ˜ํ™˜, false๋ฉด f(์‹คํ–‰)๋ฐ˜ํ™˜) */ const ternary = fp.curry((evaluator, trueHandler, falseHandler, a) => { - const executor = fp.curry((t, f, a, isTrue) => { - const result = isTrue ? (fp.isFunction(t) ? t(a) : t) : fp.isFunction(f) ? f(a) : f; - return result; + const executor = fp.curry((t, f, val, isTrue) => { + const evalResult = isTrue ? (fp.isFunction(t) ? t(val) : t) : fp.isFunction(f) ? f(val) : f; + return evalResult; }); const getEvaluator = (fn) => (fp.isNil(fn) ? fp.identity : fn); const result = executor(trueHandler, falseHandler, a, getEvaluator(evaluator)(a)); @@ -110,7 +110,7 @@ const pascalCase = fp.pipe(fp.camelCase, fp.upperFirst); const mapAsync = fp.curry(async (asyncMapper, arr) => { const composer = fp.pipe( fp.flatMapDeep(fp.pipe(asyncMapper, promisify)), - async (a) => await Promise.all(a), + async (a) => await Promise.all(a) ); const result = await composer(arr); @@ -124,7 +124,7 @@ const mapAsync = fp.curry(async (asyncMapper, arr) => { const filterAsync = fp.curry(async (asyncFilter, arr) => { const composer = fp.pipe( mapAsync(async (item) => ((await asyncFilter(item)) ? item : false)), - then(fp.filter(fp.pipe(fp.equals(false), not))), + then(fp.filter(fp.pipe(fp.equals(false), not))) ); const result = await composer(arr); @@ -139,7 +139,7 @@ const findAsync = fp.curry(async (asyncFn, arr) => { mapAsync(asyncFn), then(fp.indexOf(true)), then((idx) => fp.get(`[${idx}]`, arr)), - otherwise(fp.always(undefined)), + otherwise(fp.always(undefined)) ); const result = await composer(arr); @@ -182,8 +182,8 @@ const forEachAsync = fp.curry(async (cb, collection) => { const key = fp.curry((a, v) => { const composer = fp.pipe( fp.entries, - fp.find(([k, val]) => fp.equals(v, val)), - fp.head, + fp.find(([, val]) => fp.equals(v, val)), + fp.head ); const result = composer(a); return result; @@ -198,6 +198,14 @@ const isJson = (a) => { return fp.isString(a) && !composer(() => JSON.parse(a)); }; +/** + * Reference type ์—ฌ๋ถ€ ์ฒดํฌ ํ•จ์ˆ˜ (์ „๋ฐฉ ์„ ์–ธ) + */ +const isRef = fp.pipe( + (a) => fp.isNil(a) || fp.isBoolean(a) || fp.isNumber(a) || fp.isString(a), + not +); + /** * shallow freeze ๋ณด์™„ * (๋Œ€์ƒ object์˜ refence ํƒ€์ž…์˜ properties๊นŒ์ง€ object.freeze ์ฒ˜๋ฆฌ) @@ -212,31 +220,31 @@ const deepFreeze = (obj) => { }; const transformObjectKey = fp.curry((transformFn, dest) => { - const convertRecursively = (dest) => { + const convertRecursively = (source) => { const convertTo = (o) => { const composer = fp.pipe( fp.entries, - fp.reduce((acc, [k, v]) => { + fp.reduce((acc, [k, val]) => { const cond = fp.cond([ [fp.isPlainObject, convertTo], - [fp.isArray, (v) => v.map(cond)], - [fp.T, (a) => a], + [fp.isArray, (arr) => arr.map(cond)], + [fp.T, (item) => item], ]); const transformedKey = transformFn(k); if (!fp.has(transformedKey, acc)) { - acc[transformedKey] = cond(v); + acc[transformedKey] = cond(val); return acc; } else { throw new Error( - `${transformedKey} already exist. duplicated property name is not supported.`, + `${transformedKey} already exist. duplicated property name is not supported.` ); } - }, {}), + }, {}) ); const result = composer(o); return result; }; - const result = convertTo(dest); + const result = convertTo(source); return result; }; @@ -356,7 +364,7 @@ const append = fp.concat; * array ์ธ์ž์˜ (index์ƒ)์•ž์ชฝ์— value์ธ์ž๋ฅผ ์ถ”๊ฐ€ */ const prepend = fp.curry((array, value) => - fp.isArray(value) ? fp.concat(value, array) : fp.concat([value], array), + fp.isArray(value) ? fp.concat(value, array) : fp.concat([value], array) ); /** @@ -381,9 +389,9 @@ const reduceWithKey = fp.curry((f, acc, a) => fp.reduce.convert({ cap: false })( const isVal = (a) => fp.isNil(a) || fp.isBoolean(a) || fp.isNumber(a) || fp.isString(a); /** - * Array, Object, Function + * Array, Object, Function (์ด๋ฏธ ์œ„์—์„œ ์„ ์–ธ๋จ) */ -const isRef = fp.pipe(isVal, not); +// const isRef = fp.pipe(isVal, not); const isFalsy = (a) => { return fp.isNil(a) || fp.some(fp.equals(a), [0, -0, NaN, false, '']); @@ -397,7 +405,7 @@ const isTruthy = (a) => !isFalsy(a); * fp.getOr์˜ ๋ฐ˜ํ™˜๊ฐ’์ด null์ธ ๊ฒฝ์šฐ, ๊ธฐ๋ณธ๊ฐ’ ๋ฐ˜ํ™˜๋˜๊ฒŒ ์ˆ˜์ •ํ•œ ๋ฒ„์ „ * circular dependency ๋•Œ๋ฌธ์— closure๋กœ ์ž‘์„ฑ */ -const getOr = (({ curry, getOr }) => { +const getOr = (({ curry }) => { const _getOr = curry((defaultValue, path, target) => { const val = fp.get(path, target); return fp.isNil(val) ? defaultValue : val; @@ -413,9 +421,7 @@ const getOr = (({ curry, getOr }) => { * @param {Function} fn ์‹คํ–‰ํ•  ํ•จ์ˆ˜ * @param {*} value ๋Œ€์ƒ ๊ฐ’ */ -const when = fp.curry((predicate, fn, value) => - predicate(value) ? fn(value) : value -); +const when = fp.curry((predicate, fn, value) => (predicate(value) ? fn(value) : value)); /** * ์กฐ๊ฑด์ด ๊ฑฐ์ง“์ผ ๋•Œ๋งŒ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰, ์ฐธ์ด๋ฉด ์›๋ž˜ ๊ฐ’ ๋ฐ˜ํ™˜ @@ -423,9 +429,7 @@ const when = fp.curry((predicate, fn, value) => * @param {Function} fn ์‹คํ–‰ํ•  ํ•จ์ˆ˜ * @param {*} value ๋Œ€์ƒ ๊ฐ’ */ -const unless = fp.curry((predicate, fn, value) => - !predicate(value) ? fn(value) : value -); +const unless = fp.curry((predicate, fn, value) => (!predicate(value) ? fn(value) : value)); /** * if-else ์กฐ๊ฑด๋ถ€ ์‹คํ–‰ @@ -495,7 +499,9 @@ const safeGet = fp.curry((path, defaultValue, obj) => { * @param {Array} array ๋Œ€์ƒ ๋ฐฐ์—ด */ const mapWhen = fp.curry((predicate, fn, array) => - array.map(function(item) { return predicate(item) ? fn(item) : item; }) + array.map(function (item) { + return predicate(item) ? fn(item) : item; + }) ); /** @@ -514,12 +520,16 @@ const filterWhen = fp.curry((condition, predicate, array) => * @param {Object} obj ๋Œ€์ƒ ๊ฐ์ฒด */ const renameKeys = fp.curry((keyMap, obj) => - fp.reduce((acc, [oldKey, newKey]) => { - if (fp.has(oldKey, obj)) { - acc[newKey] = obj[oldKey]; - } - return acc; - }, {}, fp.toPairs(keyMap)) + fp.reduce( + (acc, [oldKey, newKey]) => { + if (fp.has(oldKey, obj)) { + acc[newKey] = obj[oldKey]; + } + return acc; + }, + {}, + fp.toPairs(keyMap) + ) ); /** @@ -545,7 +555,11 @@ const applyTo = fp.curry((value, fn) => fn(value)); * @param {Array} fns ํ•จ์ˆ˜ ๋ฐฐ์—ด * @param {*} value ๋Œ€์ƒ ๊ฐ’ */ -const juxt = fp.curry((fns, value) => fns.map(function(fn) { return fn(value); })); +const juxt = fp.curry((fns, value) => + fns.map(function (fn) { + return fn(value); + }) +); /** * ์—ฌ๋Ÿฌ ํ•จ์ˆ˜์˜ ๊ฒฐ๊ณผ๋ฅผ converge ํ•จ์ˆ˜๋กœ ์กฐํ•ฉ @@ -555,7 +569,9 @@ const juxt = fp.curry((fns, value) => fns.map(function(fn) { return fn(value); } */ const converge = fp.curry((convergeFn, fns, value) => { // Chromium 68 ํ˜ธํ™˜์„ฑ: spread ์—ฐ์‚ฐ์ž ๋Œ€์‹  apply ์‚ฌ์šฉ - const results = fns.map(function(fn) { return fn(value); }); + const results = fns.map(function (fn) { + return fn(value); + }); return convergeFn.apply(null, results); }); @@ -572,7 +588,7 @@ const trimToUndefined = (str) => { * ์ฒซ ๊ธ€์ž ๋Œ€๋ฌธ์ž, ๋‚˜๋จธ์ง€ ์†Œ๋ฌธ์ž * @param {string} str ๋Œ€์ƒ ๋ฌธ์ž์—ด */ -const capitalize = function(str) { +const capitalize = function (str) { if (!str || typeof str !== 'string') return str; return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); }; @@ -583,9 +599,7 @@ const capitalize = function(str) { * @param {number} max ์ตœ๋Œ“๊ฐ’ * @param {number} value ๋Œ€์ƒ ๊ฐ’ */ -const clampTo = fp.curry((min, max, value) => - Math.min(Math.max(value, min), max) -); +const clampTo = fp.curry((min, max, value) => Math.min(Math.max(value, min), max)); /** * ๊ฐ’์ด min๊ณผ max ์‚ฌ์ด์— ์žˆ๋Š”์ง€ ํ™•์ธ @@ -593,27 +607,21 @@ const clampTo = fp.curry((min, max, value) => * @param {number} max ์ตœ๋Œ“๊ฐ’ * @param {number} value ๋Œ€์ƒ ๊ฐ’ */ -const between = fp.curry((min, max, value) => - value >= min && value <= max -); +const between = fp.curry((min, max, value) => value >= min && value <= max); /** * null/undefined์ผ ๋•Œ ๊ธฐ๋ณธ๊ฐ’ ๋ฐ˜ํ™˜ * @param {*} defaultValue ๊ธฐ๋ณธ๊ฐ’ * @param {*} value ๋Œ€์ƒ ๊ฐ’ */ -const defaultTo = fp.curry((defaultValue, value) => - value == null ? defaultValue : value -); +const defaultTo = fp.curry((defaultValue, value) => (value == null ? defaultValue : value)); /** * Elvis ์—ฐ์‚ฐ์ž ๊ตฌํ˜„ (null safe ํ•จ์ˆ˜ ์ ์šฉ) * @param {Function} fn ์ ์šฉํ•  ํ•จ์ˆ˜ * @param {*} value ๋Œ€์ƒ ๊ฐ’ */ -const elvis = fp.curry((fn, value) => - value == null ? undefined : fn(value) -); +const elvis = fp.curry((fn, value) => (value == null ? undefined : fn(value))); /** * ๋ฐฐ์—ด์„ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‘ ๊ทธ๋ฃน์œผ๋กœ ๋ถ„ํ•  @@ -622,7 +630,9 @@ const elvis = fp.curry((fn, value) => */ const partition = fp.curry((predicate, array) => [ array.filter(predicate), - array.filter(function(item) { return !predicate(item); }) + array.filter(function (item) { + return !predicate(item); + }), ]); /** @@ -647,7 +657,7 @@ const lazy = (fn) => { let cached = false; let result; // Chromium 68 ํ˜ธํ™˜์„ฑ: spread ์—ฐ์‚ฐ์ž ๋Œ€์‹  arguments ์‚ฌ์šฉ - return function() { + return function () { if (!cached) { result = fn.apply(this, arguments); cached = true; @@ -756,4 +766,4 @@ export default { partition, times, lazy, -}; \ No newline at end of file +}; diff --git a/com.twin.app.shoptime/src/utils/spotlight-utils.js b/com.twin.app.shoptime/src/utils/spotlight-utils.js index 437b35d6..93bed41c 100644 --- a/com.twin.app.shoptime/src/utils/spotlight-utils.js +++ b/com.twin.app.shoptime/src/utils/spotlight-utils.js @@ -1,11 +1,11 @@ // spotlight-utils.js -import {getTargetByContainer} from '@enact/spotlight/src/target'; -import {getTargetBySelector} from '@enact/spotlight/src/target'; -import {getContainerConfig} from '@enact/spotlight/src/container'; -import {isContainer, getContainerId} from '@enact/spotlight/src/container'; -import {getContainersForNode} from '@enact/spotlight/src/container'; -import {isNavigable} from '@enact/spotlight/src/container'; -import {setLastContainer} from '@enact/spotlight/src/container'; +import { getTargetByContainer } from '@enact/spotlight/src/target'; +import { getTargetBySelector } from '@enact/spotlight/src/target'; +import { getContainerConfig } from '@enact/spotlight/src/container'; +import { isContainer, getContainerId } from '@enact/spotlight/src/container'; +import { getContainersForNode } from '@enact/spotlight/src/container'; +import { isNavigable } from '@enact/spotlight/src/container'; +import { setLastContainer } from '@enact/spotlight/src/container'; import Spotlight from '@enact/spotlight'; // lodash ์—†์ด last ํ•จ์ˆ˜ ์ง์ ‘ ๊ตฌํ˜„ @@ -15,13 +15,13 @@ const last = (array) => { // focusElement ํ•จ์ˆ˜๋Š” spotlight ๋‚ด๋ถ€ ํ•จ์ˆ˜์ด๋ฏ€๋กœ, ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜ spotlight์˜ focus๋ฅผ ์‚ฌ์šฉ const focusElement = (target, containerIds) => { - console.log("focusElement called with:", target, containerIds); + console.log('focusElement called with:', target, containerIds); if (target && typeof target.focus === 'function') { try { target.focus(); return true; } catch (e) { - console.error("Focus failed:", e); + console.error('Focus failed:', e); return false; } } @@ -39,40 +39,40 @@ const focusElement = (target, containerIds) => { * navigable target is found. */ export const getPredictedFocus = (elem) => { - let target = elem; - - if (!elem) { - target = getTargetByContainer(); - } else if (typeof elem === 'string') { - if (getContainerConfig(elem)) { - // String is a container ID - target = getTargetByContainer(elem); - } else if (/^[\w\d-]+$/.test(elem)) { - // Support component IDs consisting of alphanumeric, dash, or underscore - target = getTargetBySelector(`[data-spotlight-id=${elem}]`); - } else { - // Treat as a CSS selector - target = getTargetBySelector(elem); - } - } else if (isContainer(elem)) { - // elem is a container element - target = getTargetByContainer(getContainerId(elem)); + let target = elem; + + if (!elem) { + target = getTargetByContainer(); + } else if (typeof elem === 'string') { + if (getContainerConfig(elem)) { + // String is a container ID + target = getTargetByContainer(elem); + } else if (/^[\w\d-]+$/.test(elem)) { + // Support component IDs consisting of alphanumeric, dash, or underscore + target = getTargetBySelector(`[data-spotlight-id=${elem}]`); + } else { + // Treat as a CSS selector + target = getTargetBySelector(elem); } - - // Check navigability without attempting to focus - const nextContainerIds = getContainersForNode(target); - const nextContainerId = last(nextContainerIds); - - if (isNavigable(target, nextContainerId, true)) { - return target; - } - - return null; - }; + } else if (isContainer(elem)) { + // elem is a container element + target = getTargetByContainer(getContainerId(elem)); + } + + // Check navigability without attempting to focus + const nextContainerIds = getContainersForNode(target); + const nextContainerId = last(nextContainerIds); + + if (isNavigable(target, nextContainerId, true)) { + return target; + } + + return null; +}; // ๋ฉ”์ธ focus ํ•จ์ˆ˜ export const focus = (elem) => { - console.log("focus test", elem); + console.log('focus test', elem); var target = elem; var wasContainerId = false; @@ -86,7 +86,7 @@ export const focus = (elem) => { wasContainerId = true; } else if (/^[\w\d-]+$/.test(elem)) { // ์•ŒํŒŒ๋ฒณ, ์ˆซ์ž, ๋Œ€์‹œ, ์–ธ๋”์Šค์ฝ”์–ด๋กœ ๊ตฌ์„ฑ๋œ ์ปดํฌ๋„ŒํŠธ ID ์ง€์› - target = getTargetBySelector("[data-spotlight-id=".concat(elem, "]")); + target = getTargetBySelector('[data-spotlight-id='.concat(elem, ']')); } else { // CSS ์…€๋ ‰ํ„ฐ๋กœ ์ฒ˜๋ฆฌ target = getTargetBySelector(elem); @@ -123,118 +123,117 @@ export const focus = (elem) => { /** * spotlightId๋กœ ์ง์ ‘ ํฌ์ปค์Šค๋ฅผ ์„ค์ •ํ•˜๋Š” ํ•จ์ˆ˜ - * + * * @param {String} spotlightId - data-spotlight-id ์†์„ฑ๊ฐ’ * @param {Boolean} force - ๊ฐ•์ œ ํฌ์ปค์Šค ์—ฌ๋ถ€ (๊ธฐ๋ณธ๊ฐ’: false) * @returns {Boolean} ํฌ์ปค์Šค ์„ฑ๊ณต ์—ฌ๋ถ€ */ export const focusById = (spotlightId, force = false) => { - // spotlightId ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ - if (!spotlightId || typeof spotlightId !== 'string') { - console.error('[focusById] spotlightId๋Š” ๋ฐ˜๋“œ์‹œ ๋ฌธ์ž์—ด์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.'); + // spotlightId ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ + if (!spotlightId || typeof spotlightId !== 'string') { + console.error('[focusById] spotlightId๋Š” ๋ฐ˜๋“œ์‹œ ๋ฌธ์ž์—ด์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.'); + return false; + } + + try { + // data-spotlight-id ์†์„ฑ์„ ๊ฐ€์ง„ ์š”์†Œ ์ง์ ‘ ๊ฒ€์ƒ‰ + const targetElement = document.querySelector(`[data-spotlight-id="${spotlightId}"]`); + + if (!targetElement) { + console.warn(`[focusById] spotlightId "${spotlightId}"๋ฅผ ๊ฐ€์ง„ ์š”์†Œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.`); return false; } - - try { - // data-spotlight-id ์†์„ฑ์„ ๊ฐ€์ง„ ์š”์†Œ ์ง์ ‘ ๊ฒ€์ƒ‰ - const targetElement = document.querySelector(`[data-spotlight-id="${spotlightId}"]`); - - if (!targetElement) { - console.warn(`[focusById] spotlightId "${spotlightId}"๋ฅผ ๊ฐ€์ง„ ์š”์†Œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.`); + + // ์š”์†Œ๊ฐ€ ํ˜„์žฌ ๋ณด์ด๊ณ  ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ + if (!isElementVisible(targetElement)) { + console.warn(`[focusById] ์š”์†Œ "${spotlightId}"๊ฐ€ ๋ณด์ด์ง€ ์•Š๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.`); + if (!force) return false; + } + + // Spotlight์˜ isSpottable๋กœ ํฌ์ปค์Šค ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ + if (typeof Spotlight !== 'undefined' && Spotlight.isSpottable) { + if (!Spotlight.isSpottable(targetElement) && !force) { + console.warn(`[focusById] ์š”์†Œ "${spotlightId}"๊ฐ€ ํ˜„์žฌ spottableํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.`); return false; } - - // ์š”์†Œ๊ฐ€ ํ˜„์žฌ ๋ณด์ด๊ณ  ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ - if (!isElementVisible(targetElement)) { - console.warn(`[focusById] ์š”์†Œ "${spotlightId}"๊ฐ€ ๋ณด์ด์ง€ ์•Š๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.`); - if (!force) return false; - } - - // Spotlight์˜ isSpottable๋กœ ํฌ์ปค์Šค ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ํ™•์ธ - if (typeof Spotlight !== 'undefined' && Spotlight.isSpottable) { - if (!Spotlight.isSpottable(targetElement) && !force) { - console.warn(`[focusById] ์š”์†Œ "${spotlightId}"๊ฐ€ ํ˜„์žฌ spottableํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.`); - return false; - } - } - - // ์ง์ ‘ DOM ํฌ์ปค์Šค ์‹œ๋„ - if (force) { - // ๊ฐ•์ œ ๋ชจ๋“œ: DOM focus() ์ง์ ‘ ํ˜ธ์ถœ - console.log(`[focusById] ๊ฐ•์ œ ํฌ์ปค์Šค ๋ชจ๋“œ: "${spotlightId}"`); + } + + // ์ง์ ‘ DOM ํฌ์ปค์Šค ์‹œ๋„ + if (force) { + // ๊ฐ•์ œ ๋ชจ๋“œ: DOM focus() ์ง์ ‘ ํ˜ธ์ถœ + console.log(`[focusById] ๊ฐ•์ œ ํฌ์ปค์Šค ๋ชจ๋“œ: "${spotlightId}"`); + targetElement.focus(); + return true; + } else { + // ์ผ๋ฐ˜ ๋ชจ๋“œ: Spotlight ์‹œ์Šคํ…œ ์‚ฌ์šฉ + console.log(`[focusById] Spotlight ํฌ์ปค์Šค: "${spotlightId}"`); + + // Spotlight.focus() ์‚ฌ์šฉ (์„ ํƒ์ž ํ˜•ํƒœ๋กœ ์ „๋‹ฌ) + const focusResult = focus(`[data-spotlight-id="${spotlightId}"]`); + + if (!focusResult) { + // Spotlight ํฌ์ปค์Šค ์‹คํŒจ ์‹œ ์ง์ ‘ ํฌ์ปค์Šค ์‹œ๋„ + console.log(`[focusById] Spotlight ํฌ์ปค์Šค ์‹คํŒจ, ์ง์ ‘ ํฌ์ปค์Šค ์‹œ๋„: "${spotlightId}"`); targetElement.focus(); - return true; - } else { - // ์ผ๋ฐ˜ ๋ชจ๋“œ: Spotlight ์‹œ์Šคํ…œ ์‚ฌ์šฉ - console.log(`[focusById] Spotlight ํฌ์ปค์Šค: "${spotlightId}"`); - - // Spotlight.focus() ์‚ฌ์šฉ (์„ ํƒ์ž ํ˜•ํƒœ๋กœ ์ „๋‹ฌ) - const focusResult = focus(`[data-spotlight-id="${spotlightId}"]`); - - if (!focusResult) { - // Spotlight ํฌ์ปค์Šค ์‹คํŒจ ์‹œ ์ง์ ‘ ํฌ์ปค์Šค ์‹œ๋„ - console.log(`[focusById] Spotlight ํฌ์ปค์Šค ์‹คํŒจ, ์ง์ ‘ ํฌ์ปค์Šค ์‹œ๋„: "${spotlightId}"`); - targetElement.focus(); - return document.activeElement === targetElement; - } - - return focusResult; + return document.activeElement === targetElement; } - - } catch (error) { - console.error(`[focusById] ํฌ์ปค์Šค ์„ค์ • ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: "${spotlightId}"`, error); - return false; + + return focusResult; } - }; - - /** - * ์š”์†Œ๊ฐ€ ๋ณด์ด๊ณ  ํฌ์ปค์Šค ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜ - * - * @param {Element} element - ํ™•์ธํ•  DOM ์š”์†Œ - * @returns {Boolean} ์š”์†Œ์˜ ๊ฐ€์‹œ์„ฑ ๋ฐ ํ™œ์„ฑํ™” ์ƒํƒœ - */ - const isElementVisible = (element) => { - if (!element) return false; - - // ์š”์†Œ๊ฐ€ DOM์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ - if (!element.isConnected) return false; - - // disabled ์†์„ฑ ํ™•์ธ - if (element.disabled) return false; - - // display: none ๋˜๋Š” visibility: hidden ํ™•์ธ - const style = window.getComputedStyle(element); - if (style.display === 'none' || style.visibility === 'hidden') return false; - - // opacity๊ฐ€ 0์ธ์ง€ ํ™•์ธ - if (parseFloat(style.opacity) === 0) return false; - - // ์š”์†Œ์˜ ํฌ๊ธฐ๊ฐ€ 0์ธ์ง€ ํ™•์ธ - const rect = element.getBoundingClientRect(); - if (rect.width === 0 && rect.height === 0) return false; - - return true; - }; - - /** - * ํ˜„์žฌ ํฌ์ปค์Šค๋œ ์š”์†Œ์˜ spotlightId๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜ - * - * @returns {String|null} ํ˜„์žฌ ํฌ์ปค์Šค๋œ ์š”์†Œ์˜ spotlightId ๋˜๋Š” null - */ - export const getCurrentSpotlightId = () => { - const current = document.activeElement; - if (current && current.hasAttribute('data-spotlight-id')) { - return current.getAttribute('data-spotlight-id'); - } - return null; - }; - - /** - * ํŠน์ • spotlightId๋ฅผ ๊ฐ€์ง„ ์š”์†Œ๊ฐ€ ํ˜„์žฌ ํฌ์ปค์Šค๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ•จ์ˆ˜ - * - * @param {String} spotlightId - ํ™•์ธํ•  spotlightId - * @returns {Boolean} ํ•ด๋‹น ์š”์†Œ๊ฐ€ ํ˜„์žฌ ํฌ์ปค์Šค๋˜์–ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€ - */ - export const isCurrentlyFocused = (spotlightId) => { - return getCurrentSpotlightId() === spotlightId; - }; \ No newline at end of file + } catch (error) { + console.error(`[focusById] ํฌ์ปค์Šค ์„ค์ • ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: "${spotlightId}"`, error); + return false; + } +}; + +/** + * ์š”์†Œ๊ฐ€ ๋ณด์ด๊ณ  ํฌ์ปค์Šค ๊ฐ€๋Šฅํ•œ ์ƒํƒœ์ธ์ง€ ํ™•์ธํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜ + * + * @param {Element} element - ํ™•์ธํ•  DOM ์š”์†Œ + * @returns {Boolean} ์š”์†Œ์˜ ๊ฐ€์‹œ์„ฑ ๋ฐ ํ™œ์„ฑํ™” ์ƒํƒœ + */ +const isElementVisible = (element) => { + if (!element) return false; + + // ์š”์†Œ๊ฐ€ DOM์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ + if (!element.isConnected) return false; + + // disabled ์†์„ฑ ํ™•์ธ + if (element.disabled) return false; + + // display: none ๋˜๋Š” visibility: hidden ํ™•์ธ + const style = window.getComputedStyle(element); + if (style.display === 'none' || style.visibility === 'hidden') return false; + + // opacity๊ฐ€ 0์ธ์ง€ ํ™•์ธ + if (parseFloat(style.opacity) === 0) return false; + + // ์š”์†Œ์˜ ํฌ๊ธฐ๊ฐ€ 0์ธ์ง€ ํ™•์ธ + const rect = element.getBoundingClientRect(); + if (rect.width === 0 && rect.height === 0) return false; + + return true; +}; + +/** + * ํ˜„์žฌ ํฌ์ปค์Šค๋œ ์š”์†Œ์˜ spotlightId๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜ + * + * @returns {String|null} ํ˜„์žฌ ํฌ์ปค์Šค๋œ ์š”์†Œ์˜ spotlightId ๋˜๋Š” null + */ +export const getCurrentSpotlightId = () => { + const current = document.activeElement; + if (current && current.hasAttribute('data-spotlight-id')) { + return current.getAttribute('data-spotlight-id'); + } + return null; +}; + +/** + * ํŠน์ • spotlightId๋ฅผ ๊ฐ€์ง„ ์š”์†Œ๊ฐ€ ํ˜„์žฌ ํฌ์ปค์Šค๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ•จ์ˆ˜ + * + * @param {String} spotlightId - ํ™•์ธํ•  spotlightId + * @returns {Boolean} ํ•ด๋‹น ์š”์†Œ๊ฐ€ ํ˜„์žฌ ํฌ์ปค์Šค๋˜์–ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€ + */ +export const isCurrentlyFocused = (spotlightId) => { + return getCurrentSpotlightId() === spotlightId; +}; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx index c335beda..a2f3d987 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx @@ -3,11 +3,9 @@ import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useSta import { useDispatch, useSelector } from 'react-redux'; -import Spinner from '@enact/sandstone/Spinner'; import Spotlight from '@enact/spotlight'; import { setContainerLastFocusedElement } from '@enact/spotlight/src/container'; -import indicatorDefaultImage from '../../../assets/images/img-thumb-empty-144@3x.png'; import { getDeviceAdditionInfo } from '../../actions/deviceActions'; import { getThemeCurationDetailInfo } from '../../actions/homeActions'; import { getMainCategoryDetail, getMainYouMayLike } from '../../actions/mainActions'; @@ -22,7 +20,6 @@ import TBody from '../../components/TBody/TBody'; import TPanel from '../../components/TPanel/TPanel'; import { panel_names } from '../../utils/Config'; import fp from '../../utils/fp'; -import { $L, getQRCodeUrl } from '../../utils/helperMethods'; import { SpotlightIds } from '../../utils/SpotlightIds'; import DetailPanelBackground from './components/DetailPanelBackground'; import THeaderCustom from './components/THeaderCustom'; @@ -51,11 +48,6 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { const panels = useSelector((state) => state.panels.panels); const [selectedIndex, setSelectedIndex] = useState(0); - const localRecentItems = useSelector((state) => - fp.pipe(() => state, fp.get('localSettings.recentItems'))() - ); - const { httpHeader } = useSelector((state) => state.common); - const { popupVisible, activePopup } = useSelector((state) => state.common.popup); const [lgCatCd, setLgCatCd] = useState(''); const [themeProductInfo, setThemeProductInfo] = useState(null); @@ -561,11 +553,6 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { } }, [themeData, selectedIndex]); - const imageUrl = useMemo( - () => fp.pipe(() => productData, fp.get('thumbnailUrl960'))(), - [productData] - ); - // ํƒ€์ดํ‹€๊ณผ aria-label ๋ฉ”๋ชจ์ด์ œ์ด์…˜ (์„ฑ๋Šฅ ์ตœ์ ํ™”) const headerTitle = useMemo( () => diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.jsx b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.jsx index 57a945c7..f6fdfe05 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.jsx @@ -7,39 +7,39 @@ export default function DetailPanelSkeleton() { return (
{/* 1. Left Margin Section - 60px */} -
+
{/* 2. Info Section - 650px (์™ผ์ชฝ ์˜์—ญ ์Šค์ผˆ๋ ˆํ†ค) */}
{/* ์ œํ’ˆ ํƒœ๊ทธ ์Šค์ผˆ๋ ˆํ†ค */} -
+
{/* ์ œํ’ˆ ์ •๋ณด ์Šค์ผˆ๋ ˆํ†ค */}
-
-
-
+
+
+
{/* QR ์ฝ”๋“œ ์Šค์ผˆ๋ ˆํ†ค */} -
+
{/* ๋ฒ„ํŠผ๋“ค ์Šค์ผˆ๋ ˆํ†ค */}
-
-
+
+
{/* ์ฃผ๋ฌธ ์ „ํ™” ์„น์…˜ ์Šค์ผˆ๋ ˆํ†ค */} -
+
{/* ์•ก์…˜ ๋ฒ„ํŠผ๋“ค ์Šค์ผˆ๋ ˆํ†ค */}
-
-
-
+
+
+
@@ -52,57 +52,57 @@ export default function DetailPanelSkeleton() {
{/* ์ œํ’ˆ ์ด๋ฏธ์ง€/๋น„๋””์˜ค ์Šค์ผˆ๋ ˆํ†ค */}
-
+
{/* ์ œํ’ˆ ์„ค๋ช… ์Šค์ผˆ๋ ˆํ†ค */}
-
-
-
-
-
+
+
+
+
+
{/* ๋ฆฌ๋ทฐ ์„น์…˜ ์Šค์ผˆ๋ ˆํ†ค */}
-
+
-
+
-
-
-
+
+
+
-
+
-
-
-
+
+
+
{/* ์ถ”์ฒœ ์ƒํ’ˆ ์Šค์ผˆ๋ ˆํ†ค */}
-
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
@@ -112,4 +112,4 @@ export default function DetailPanelSkeleton() {
); -} \ No newline at end of file +} diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerItemCard/PlayerItemCard.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerItemCard/PlayerItemCard.jsx index 4d4df032..ad30893c 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerItemCard/PlayerItemCard.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerItemCard/PlayerItemCard.jsx @@ -7,7 +7,7 @@ import Spottable from '@enact/spotlight/Spottable'; import defaultLogoImg from '../../../../assets/images/ic-tab-partners-default@3x.png'; import CustomImage from '../../../components/CustomImage/CustomImage'; import { convertUtcToLocal } from '../../../components/MediaPlayer/util'; -import { $L, removeSpecificTags } from '../../../utils/helperMethods'; +import { $L } from '../../../utils/helperMethods'; import css1 from './PlayerItemCard.module.less'; import css2 from './PlayerItemCard.v2.module.less'; @@ -33,11 +33,9 @@ export const removeDotAndColon = (string) => { }; export default memo(function PlayerItemCard({ - children, disabled, imageAlt, imageSource, - imgType = IMAGETYPES.imgHorizontal, logo, onBlur, onClick, @@ -47,10 +45,8 @@ export default memo(function PlayerItemCard({ soldoutFlag, spotlightId, patnerName, - selectedIndex, videoVerticalVisible, currentVideoVisible, - dangerouslySetInnerHTML, currentTime, liveInfo, startDt, @@ -144,6 +140,7 @@ export default memo(function PlayerItemCard({

{patnerName}

+ {/* eslint-disable-next-line react/no-danger */}

{liveInfo && liveInfo.showType === 'live' && (
state.common.httpHeader?.cntry_cd); const dispatch = useDispatch(); @@ -66,7 +65,7 @@ function PlayerOverlayContents({ } setIsSubtitleActive((prev) => !prev); - }, [dispatch, captionEnable]); + }, [dispatch, captionEnable, setIsSubtitleActive]); const patncLogoPath = useMemo(() => { let logo = playListInfo[selectedIndex]?.patncLogoPath; @@ -75,7 +74,7 @@ function PlayerOverlayContents({ } return logo; - }, [playListInfo, selectedIndex, panelInfo]); + }, [playListInfo, selectedIndex, panelInfo, type]); const partnerName = useMemo(() => { let name = playListInfo[selectedIndex]?.patncNm; @@ -84,7 +83,7 @@ function PlayerOverlayContents({ } return name; - }, [playListInfo, selectedIndex, panelInfo]); + }, [playListInfo, selectedIndex, panelInfo, type]); const showName = useMemo(() => { let name = playListInfo[selectedIndex]?.showNm; @@ -93,21 +92,24 @@ function PlayerOverlayContents({ } return name ? name.replace(//gi, ' ') : ''; - }, [playListInfo, selectedIndex, panelInfo]); + }, [playListInfo, selectedIndex, panelInfo, type]); - const onSpotlightMoveTabButton = (e) => { + const onSpotlightMoveTabButton = useCallback((e) => { e.stopPropagation(); e.preventDefault(); Spotlight.focus(SpotlightIds.PLAYER_TAB_BUTTON); - }; + }, []); - const onSpotlightMoveMediaButton = (e) => { - e.stopPropagation(); - if (type === 'LIVE') { - return Spotlight.focus('videoIndicator-down-button'); - } - Spotlight.focus('videoPlayer_mediaControls'); - }; + const onSpotlightMoveMediaButton = useCallback( + (e) => { + e.stopPropagation(); + if (type === 'LIVE') { + return Spotlight.focus('videoIndicator-down-button'); + } + Spotlight.focus('videoPlayer_mediaControls'); + }, + [type] + ); const onSpotlightMoveSlider = useCallback( (e) => { @@ -120,33 +122,36 @@ function PlayerOverlayContents({ [type] ); - const onSpotlightMoveSideTab = (e) => { + const onSpotlightMoveSideTab = useCallback((e) => { e.stopPropagation(); e.preventDefault(); Spotlight.focus('tab-0'); - }; + }, []); - const onSpotlightMoveBelowTab = (e) => { - e.stopPropagation(); - e.preventDefault(); + const onSpotlightMoveBelowTab = useCallback( + (e) => { + e.stopPropagation(); + e.preventDefault(); - // tabIndexV2์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ฒ„ํŠผ์œผ๋กœ ํฌ์ปค์Šค ์ด๋™ - if (tabIndexV2 === 0) { - // ShopNow ํƒญ: Close ๋ฒ„ํŠผ์œผ๋กœ - // Spotlight.focus('below-tab-close-button'); - Spotlight.focus('shownow_close_button'); - } else if (tabIndexV2 === 1) { - // LIVE CHANNEL ํƒญ: LIVE CHANNEL ๋ฒ„ํŠผ์œผ๋กœ - Spotlight.focus('below-tab-live-channel-button'); - } else if (tabIndexV2 === 2) { - // ShopNowButton: ShopNowButton์œผ๋กœ - Spotlight.focus('below-tab-shop-now-button'); - } - }; + // tabIndexV2์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ฒ„ํŠผ์œผ๋กœ ํฌ์ปค์Šค ์ด๋™ + if (tabIndexV2 === 0) { + // ShopNow ํƒญ: Close ๋ฒ„ํŠผ์œผ๋กœ + // Spotlight.focus('below-tab-close-button'); + Spotlight.focus('shownow_close_button'); + } else if (tabIndexV2 === 1) { + // LIVE CHANNEL ํƒญ: LIVE CHANNEL ๋ฒ„ํŠผ์œผ๋กœ + Spotlight.focus('below-tab-live-channel-button'); + } else if (tabIndexV2 === 2) { + // ShopNowButton: ShopNowButton์œผ๋กœ + Spotlight.focus('below-tab-shop-now-button'); + } + }, + [tabIndexV2] + ); - const onSpotlightMoveBackButton = () => { + const onSpotlightMoveBackButton = useCallback(() => { return Spotlight.focus(SpotlightIds.PLAYER_BACK_BUTTON); - }; + }, []); const currentSideButtonStatus = useMemo(() => { if ( @@ -158,7 +163,7 @@ function PlayerOverlayContents({ return true; } return false; - }, [panelInfo, sideContentsVisible, tabContainerVersion]); + }, [type, panelInfo, sideContentsVisible, tabContainerVersion]); const noLiveContentsVisible = useMemo(() => { if (!Array.isArray(playListInfo) || playListInfo.length === 0) { diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx index c41928c6..3f3ca075 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.new.jsx @@ -4,11 +4,9 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import classNames from 'classnames'; import { useDispatch, useSelector } from 'react-redux'; -import { Job } from '@enact/core/util'; import Spotlight from '@enact/spotlight'; import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; -import { setContainerLastFocusedElement } from '@enact/spotlight/src/container'; import micIcon from '../../../assets/images/searchpanel/image-mic.png'; import hotPicksImage from '../../../assets/images/searchpanel/img-hotpicks.png'; @@ -16,7 +14,7 @@ import hotPicksBrandImage from '../../../assets/images/searchpanel/img-search-ho import { sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions'; import { getMyRecommandedKeyword } from '../../actions/myPageActions'; import { popPanel, updatePanel } from '../../actions/panelActions'; -import { getSearch, resetSearch, searchMain } from '../../actions/searchActions'; +import { getSearch, resetSearch } from '../../actions/searchActions'; // import { // showErrorToast, // showInfoToast, @@ -28,15 +26,11 @@ import { getSearch, resetSearch, searchMain } from '../../actions/searchActions' import TBody from '../../components/TBody/TBody'; import TInput, { ICONS, KINDS } from './TInput/TInput'; import TPanel from '../../components/TPanel/TPanel'; -import TScroller from '../../components/TScroller/TScroller'; import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator'; import TVirtualGridList from '../../components/TVirtualGridList/TVirtualGridList'; // import VirtualKeyboardContainer from "../../components/TToast/VirtualKeyboardContainer"; import usePrevious from '../../hooks/usePrevious'; import { LOG_CONTEXT_NAME, LOG_MENU, LOG_MESSAGE_ID, panel_names } from '../../utils/Config'; -import { SpotlightIds } from '../../utils/SpotlightIds'; -import NoSearchResults from './NoSearchResults/NoSearchResults'; -import RecommendedKeywords from './RecommendedKeywords/RecommendedKeywords'; import SearchInputOverlay from './SearchInpuOverlay'; import css from './SearchPanel.new.module.less'; import SearchResultsNew from './SearchResults.new'; @@ -54,7 +48,6 @@ const SectionContainer = SpotlightContainerDecorator({ enterTo: 'last-focused' } const SpottableMicButton = Spottable('div'); const SpottableKeyword = Spottable('div'); const SpottableProduct = Spottable('div'); -const SpottableLi = Spottable('li'); const ITEMS_PER_PAGE = 9; @@ -70,7 +63,7 @@ const SPOTLIGHT_IDS = { SEARCH_VERTICAL_PAGENATOR: 'search_verticalPagenator', }; -export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOptions = [] }) { +export default function SearchPanel({ panelInfo, isOnTop, spotlightId }) { const dispatch = useDispatch(); const loadingComplete = useSelector((state) => state.common?.loadingComplete); const recommandedKeywords = useSelector( @@ -90,16 +83,15 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt const [showVirtualKeyboard, setShowVirtualKeyboard] = useState(false); const [isVoiceOverlayVisible, setIsVoiceOverlayVisible] = useState(false); const [isSearchOverlayVisible, setIsSearchOverlayVisible] = useState(false); - const [voiceMode, setVoiceMode] = useState(VOICE_MODES.PROMPT); //์ธํ’‹์ฐฝ ํฌ์ปค์Šค ๊ตฌ๋ถ„์„ ์œ„ํ•จ const [inputFocus, setInputFocus] = useState(false); const _onFocus = useCallback(() => { setInputFocus(true); - }, [inputFocus]); + }, []); const _onBlur = useCallback(() => { setInputFocus(false); - }, [inputFocus]); + }, []); // TInput์˜ ์ž…๋ ฅ ๋ชจ๋“œ ์ƒํƒœ (webOS ํ‚ค๋ณด๋“œ๊ฐ€ ๋œจ๋Š”์ง€ ์—ฌ๋ถ€) const [isInputModeActive, setIsInputModeActive] = useState(false); @@ -132,19 +124,6 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt // ๊ฐ€์งœ ๋ฐ์ดํ„ฐ - ์‹ค์ œ๋กœ๋Š” Redux store๋‚˜ API์—์„œ ๊ฐ€์ ธ์™€์•ผ ํ•จ const recentSearches = useMemo(() => ['Puppy food', 'Dog toy', 'Fitness'], []); - const recentResultSearches = useMemo( - () => [ - 'Puppy food', - 'Dog toy', - "Mather's Day", - 'Gift', - 'Easter Day', - 'Royal Canin puppy food2', - 'Shark', - ], - [] - ); - const topSearches = useMemo( () => ["Mather's Day", 'Gift', 'Easter Day', 'Royal Canin puppy food', 'Fitness', 'Parrot'], [] @@ -207,28 +186,30 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt if (loadingComplete && !recommandedKeywords) { dispatch(getMyRecommandedKeyword()); } - }, [loadingComplete]); + }, [loadingComplete, recommandedKeywords, dispatch]); useEffect(() => { if (isOnTop) { let menu; - if (!searchPerformed) menu = LOG_MENU.SEARCH_SEARCH; - else { - if (searchQueryRef.current) + if (!searchPerformed) { + menu = LOG_MENU.SEARCH_SEARCH; + } else { + if (searchQueryRef.current) { menu = Object.keys(searchDatas).length > 0 ? LOG_MENU.SEARCH_RESULT : LOG_MENU.SEARCH_BEST_SELLER; + } } dispatch(sendLogGNB(menu)); } - }, [isOnTop, searchDatas, searchPerformed]); + }, [isOnTop, searchDatas, searchPerformed, dispatch, searchQueryRef]); useEffect(() => { if (!searchQuery) { dispatch(resetSearch()); } - }, [dispatch]); + }, [dispatch, searchQuery]); useEffect(() => { if (recommandedKeywords) { @@ -303,35 +284,17 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt // ๊ฒ€์ƒ‰ ์‹œ ๊ฐ€์ƒ ํ‚ค๋ณด๋“œ ์ˆจ๊น€ setShowVirtualKeyboard(false); }, - [dispatch, searchPerformed, searchDatas, searchQuery] + // eslint-disable-next-line react-hooks/exhaustive-deps + [dispatch, searchPerformed] ); - const handleNext = useCallback(() => { - if (!isOnTopRef.current) { - return; - } - setCurrentPage((prev) => prev + 1); - setPageChanged(true); - }, [currentPage]); - - const handlePrev = useCallback(() => { - if (!isOnTopRef.current) { - return; - } - setCurrentPage((prev) => (prev > 1 ? prev - 1 : prev)); - setPageChanged(true); - }, [currentPage]); - - const hasPrevPage = currentPage > 1; - const hasNextPage = currentPage * ITEMS_PER_PAGE < recommandedKeywords?.length; - useEffect(() => { if (panelInfo && isOnTop) { if (panelInfo.currentSpot && firstSpot) { Spotlight.focus(panel_names.SEARCH_PANEL); } } - }, [panelInfo, isOnTop]); + }, [panelInfo, isOnTop, firstSpot]); // SearchPanel์ด ์ฒ˜์Œ ์—ด๋ฆด ๋•Œ TInput์œผ๋กœ ํฌ์ปค์Šค ์„ค์ • useEffect(() => { @@ -349,20 +312,23 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt initialFocusTimerRef.current = null; } }; - }, [isOnTop]); + }, [isOnTop, isOnTopRef]); useEffect(() => { return () => { + const currentSearchVal = searchQueryRef.current; + const currentFocusedId = focusedContainerIdRef.current; dispatch( updatePanel({ name: panel_names.SEARCH_PANEL, panelInfo: { - searchVal: searchQueryRef.current, - focusedContainerId: focusedContainerIdRef.current, + searchVal: currentSearchVal, + focusedContainerId: currentFocusedId, }, }) ); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Cleanup all timers on component unmount @@ -373,7 +339,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt spotlightResumeTimerRef.current = null; } }; - }, []); + }, [isOnTopRef]); const handleKeydown = useCallback( (e) => { @@ -426,7 +392,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt return; } }, - [searchQuery, position, handleSearchSubmit, showVirtualKeyboard] + [searchQuery, position, handleSearchSubmit, showVirtualKeyboard, isOnTopRef] ); const cursorPosition = useCallback(() => { @@ -442,7 +408,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt } // ๋งˆ์ดํฌ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ voice overlay ํ† ๊ธ€ setIsVoiceOverlayVisible((prev) => !prev); - }, []); + }, [isOnTopRef]); const onCancel = useCallback(() => { if (!isOnTopRef.current) { @@ -461,7 +427,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt dispatch(resetSearch()); Spotlight.focus(SPOTLIGHT_IDS.SEARCH_INPUT_BOX); } - }, [searchQuery, dispatch, isVoiceOverlayVisible]); + }, [searchQuery, dispatch, isVoiceOverlayVisible, isOnTopRef]); const onFocusedContainerId = useCallback( (containerId) => { @@ -484,17 +450,9 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt }, 0); } }, - [panelInfo, firstSpot] + [panelInfo, firstSpot, panels] ); - const panelInfoFall = useMemo(() => { - const newPanelInfo = { ...panelInfo }; - if (firstSpot) { - newPanelInfo.currentSpot = null; - } - return newPanelInfo; - }, [panelInfo, firstSpot]); - // ํ‚ค์›Œ๋“œ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ const handleKeywordClick = useCallback( (keyword) => { @@ -505,7 +463,16 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt setIsSearchOverlayVisible(false); setInputFocus(false); }, - [handleSearchSubmit, dispatch] + // eslint-disable-next-line react-hooks/exhaustive-deps + [handleSearchSubmit] + ); + + // ํ‚ค์›Œ๋“œ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ ์ƒ์„ฑ ํ•จ์ˆ˜ + const createKeywordClickHandler = useCallback( + (keyword) => { + return () => handleKeywordClick(keyword); + }, + [handleKeywordClick] ); const handleKeywordInput = (keyword) => { @@ -514,10 +481,33 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt setInputFocus(false); }; - // ์ƒํ’ˆ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ - const handleProductClick = useCallback((product) => { - // ์ƒํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ๋กœ์ง ๊ตฌํ˜„ - console.log('Product clicked:', product); + // TInput icon click handler + const handleInputIconClick = useCallback(() => { + if (showVirtualKeyboard) { + handleSearchSubmit(searchQuery); + } else { + setShowVirtualKeyboard(true); + } + }, [showVirtualKeyboard, handleSearchSubmit, searchQuery]); + + // Microphone button keydown handler + const handleMicKeyDown = useCallback( + (e) => { + if (e.key === 'Enter') { + onClickMic(); + } + }, + [onClickMic] + ); + + // Voice overlay close handler + const handleVoiceOverlayClose = useCallback(() => { + setIsVoiceOverlayVisible(false); + }, []); + + // Search overlay close handler + const handleSearchOverlayClose = useCallback(() => { + setIsSearchOverlayVisible(false); }, []); // ํ…Œ์ŠคํŠธ์šฉ Toast ํ•ธ๋“ค๋Ÿฌ๋“ค @@ -573,7 +563,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt ); }, - [] + [hotPicks] ); useEffect(() => { @@ -587,7 +577,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt return ( - + {isOnTop && ( {/* ๊ฒ€์ƒ‰ ๋‚ด์šฉ์žˆ์„๋•Œ ๊ฒ€์ƒ‰ ๋ถ€๋ถ„ */} {/* ๊ฒ€์ƒ‰ ์ž…๋ ฅ ์˜์—ญ - overlay ์—ด๋ฆด ๋•Œ ์ˆจ๊น€ (visibility๋กœ ์ฒ˜๋ฆฌ) */} @@ -609,7 +599,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt searchDatas && css.searchValue /* ์ด๊ฑด ๊ฒฐ๊ณผ๊ฐ’ ์žˆ์„๋•Œ๋งŒ. ์กฐ๊ฑด ์ถ”๊ฐ€ํ•„์š” */, (isVoiceOverlayVisible || isSearchOverlayVisible) && css.hidden )} - data-wheel-point={true} + data-wheel-point="true" spotlightId={SPOTLIGHT_IDS.SEARCH_INPUT_LAYER} >
@@ -625,19 +615,13 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt icon={ICONS.search} value={searchQuery} onChange={handleSearchChange} - onIconClick={() => { - if (showVirtualKeyboard) { - handleSearchSubmit(searchQuery); - } else { - setShowVirtualKeyboard(true); - } - }} + onIconClick={handleInputIconClick} onKeyDown={handleKeydown} onKeyUp={cursorPosition} spotlightId={SPOTLIGHT_IDS.SEARCH_INPUT_BOX} forcedSpotlight="recent-keyword-0" tabIndex={0} - spotlightBoxDisabled={true} + spotlightBoxDisabled onFocus={_onFocus} onBlur={_onBlur} onInputModeChange={handleInputModeChange} @@ -647,11 +631,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt className={css.microphoneButton} onClick={onClickMic} onFocus={onFocusMic} - onKeyDown={(e) => { - if (e.key === 'Enter') { - onClickMic(); - } - }} + onKeyDown={handleMicKeyDown} spotlightId={SPOTLIGHT_IDS.MICROPHONE_BUTTON} >
@@ -714,11 +694,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt {/* ์ตœ๊ทผ ๊ฒ€์ƒ‰์–ด ์„น์…˜ */}
-
+
Your Recent Searches
@@ -726,7 +706,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt handleKeywordClick(keyword)} + onClick={createKeywordClickHandler(keyword)} spotlightId={`recent-keyword-${index}`} > {keyword} @@ -738,11 +718,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt {/* ์ธ๊ธฐ ๊ฒ€์ƒ‰์–ด ์„น์…˜ */}
-
+
Top Searches
@@ -750,7 +730,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt handleKeywordClick(keyword)} + onClick={createKeywordClickHandler(keyword)} spotlightId={`top-keyword-${index}`} > {keyword} @@ -762,11 +742,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt {/* ์ธ๊ธฐ ๋ธŒ๋žœ๋“œ ์„น์…˜ */}
-
+
Popular Brands
@@ -774,7 +754,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt handleKeywordClick(brand)} + onClick={createKeywordClickHandler(brand)} spotlightId={`brand-${index}`} > {brand} @@ -786,11 +766,11 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt {/* Hot Picks for You ์„น์…˜ */}
-
+
Hot Picks for You
@@ -842,8 +822,8 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt {isVoiceOverlayVisible && ( setIsVoiceOverlayVisible(false)} - mode={voiceMode} + onClose={handleVoiceOverlayClose} + mode={VOICE_MODES.PROMPT} suggestions={voiceSuggestions} searchQuery={searchQuery} onSearchChange={handleSearchChange} @@ -853,7 +833,7 @@ export default function SearchPanel({ panelInfo, isOnTop, spotlightId, scrollOpt {isSearchOverlayVisible && ( setIsSearchOverlayVisible(false)} + onClose={handleSearchOverlayClose} searchQuery={searchQuery} onSearchChange={handleSearchChange} onSearchSubmit={handleSearchSubmit} diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.jsx index 15737829..4baed33c 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResults.new.jsx @@ -1,27 +1,15 @@ -import React, { - useCallback, - useMemo, - useRef, - useState, -} from 'react'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; import classNames from 'classnames'; -import { useDispatch } from 'react-redux'; -import SpotlightContainerDecorator - from '@enact/spotlight/SpotlightContainerDecorator'; import Spottable from '@enact/spotlight/Spottable'; import downBtnImg from '../../../assets/images/btn/search_btn_down_arrow.png'; import upBtnImg from '../../../assets/images/btn/search_btn_up_arrow.png'; -import hotPicksImage from '../../../assets/images/searchpanel/img-hotpicks.png'; -import hotPicksBrandImage - from '../../../assets/images/searchpanel/img-search-hotpicks.png'; import CustomImage from '../../components/CustomImage/CustomImage'; import TButtonTab, { LIST_TYPE } from '../../components/TButtonTab/TButtonTab'; import TDropDown from '../../components/TDropDown/TDropDown'; -import TVirtualGridList - from '../../components/TVirtualGridList/TVirtualGridList'; +import TVirtualGridList from '../../components/TVirtualGridList/TVirtualGridList'; import { $L } from '../../utils/helperMethods'; import { SpotlightIds } from '../../utils/SpotlightIds'; import css from './SearchResults.new.module.less'; @@ -30,39 +18,29 @@ import ShowCard from './SearchResultsNew/ShowCard'; const ITEMS_PER_PAGE = 10; -const SearchResultsNew = ({ - itemInfo, - showInfo, - themeInfo, - shopperHouseInfo, - keywordClick, -}) => { +const SearchResultsNew = ({ itemInfo, showInfo, themeInfo, shopperHouseInfo, keywordClick }) => { // ShopperHouse ๋ฐ์ดํ„ฐ๋ฅผ ItemCard ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ const convertedShopperHouseItems = useMemo(() => { - if ( - !shopperHouseInfo || - !shopperHouseInfo.results || - shopperHouseInfo.results.length === 0 - ) { + if (!shopperHouseInfo || !shopperHouseInfo.results || shopperHouseInfo.results.length === 0) { return null; } const docs = shopperHouseInfo.results[0].docs || []; - return docs.map((doc, index) => { + return docs.map((doc) => { const contentId = doc.contentId; - const tokens = contentId.split("_"); - const patnrId = tokens?.[4] || ""; - const prdtId = tokens?.[5] || ""; + const tokens = contentId.split('_'); + const patnrId = tokens?.[4] || ''; + const prdtId = tokens?.[5] || ''; return { - thumbnail: doc.thumnail || doc.imgPath || "", //์ด๋ฏธ์ง€ ๊ฒฝ๋กœ - title: doc.title || doc.prdtName || "", // ์ œ๋ชฉ - dcPrice: doc.dcPrice || doc.price || "", // ํ• ์ธ๊ฐ€๊ฒฉ - price: doc.orgPrice || doc.price || "", // ์›๊ฐ€ + thumbnail: doc.thumnail || doc.imgPath || '', //์ด๋ฏธ์ง€ ๊ฒฝ๋กœ + title: doc.title || doc.prdtName || '', // ์ œ๋ชฉ + dcPrice: doc.dcPrice || doc.price || '', // ํ• ์ธ๊ฐ€๊ฒฉ + price: doc.orgPrice || doc.price || '', // ์›๊ฐ€ soldout: doc.soldout || false, // ํ’ˆ์ ˆ ์—ฌ๋ถ€ contentId, //์ฝ˜ํ…ํŠธ ์•„์ด๋”” - reviewGrade: doc.reviewGrade || "", //๋ฆฌ๋ทฐ ์ ์ˆ˜ (์ถ”๊ฐ€ ์ •๋ณด) - partnerName: doc.partnerName || "", //ํŒŒํŠธ๋„ˆ ๋„ค์ž„ + reviewGrade: doc.reviewGrade || '', //๋ฆฌ๋ทฐ ์ ์ˆ˜ (์ถ”๊ฐ€ ์ •๋ณด) + partnerName: doc.partnerName || '', //ํŒŒํŠธ๋„ˆ ๋„ค์ž„ patnrId, // ํŒŒํŠธ๋„ˆ ์•„์ด๋”” prdtId, // ์ƒํ’ˆ ์•„์ด๋”” }; @@ -70,8 +48,7 @@ const SearchResultsNew = ({ }, [shopperHouseInfo]); const getButtonTabList = () => { // ShopperHouse ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉ, ์—†์œผ๋ฉด ๊ธฐ์กด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์‚ฌ์šฉ - const itemLength = - convertedShopperHouseItems?.length || itemInfo?.length || 0; + const itemLength = convertedShopperHouseItems?.length || itemInfo?.length || 0; const showLength = showInfo?.length || 0; return [ @@ -90,7 +67,7 @@ const SearchResultsNew = ({ const [visibleCount, setVisibleCount] = useState(ITEMS_PER_PAGE); const [styleChange, setStyleChange] = useState(false); - const [filterMethods, setFilterMethods] = useState([]); + const filterMethods = []; const cbChangePageRef = useRef(null); if (!buttonTabList) { @@ -98,8 +75,7 @@ const SearchResultsNew = ({ } // ํ˜„์žฌ ํƒญ์˜ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ - ShopperHouse ๋ฐ์ดํ„ฐ ์šฐ์„  - const currentData = - tab === 0 ? convertedShopperHouseItems || itemInfo : showInfo; + const currentData = tab === 0 ? convertedShopperHouseItems || itemInfo : showInfo; // ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ (์ฒ˜์Œ๋ถ€ํ„ฐ visibleCount ๊ฐœ์ˆ˜๋งŒํผ) const displayedData = useMemo(() => { @@ -147,8 +123,8 @@ const SearchResultsNew = ({ [dropDownTab] ); - const SpottableLi = Spottable("li"); - const SpottableDiv = Spottable("div"); + const SpottableLi = Spottable('li'); + const SpottableDiv = Spottable('div'); // ๋งจ ์ฒ˜์Œ์œผ๋กœ ์ด๋™ (์œ„ ๋ฒ„ํŠผ) const upBtnClick = () => { @@ -167,8 +143,7 @@ const SearchResultsNew = ({ // ProductCard ์ปดํฌ๋„ŒํŠธ const renderItem = useCallback( ({ index, ...rest }) => { - const { bgImgPath, title, partnerLogo, partnerName, keyword } = - themeInfo[index]; + const { bgImgPath, title, partnerLogo, partnerName, keyword } = themeInfo[index]; return (
- {partnerName} + {partnerName}
{keyword && (
- {keyword.map((item, index) => ( - # {item} + {keyword.map((item, keywordIndex) => ( + # {item} ))}
)} @@ -209,37 +180,25 @@ const SearchResultsNew = ({
How about these?
    - keywordClick("Puppy food")} - > - Puppy food - - keywordClick("Dog toy")} - > - Dog toy - - keywordClick("Fitness")} - > - Fitness - + {[ + { text: 'Puppy food', key: 'puppy-food' }, + { text: 'Dog toy', key: 'dog-toy' }, + { text: 'Fitness', key: 'fitness' }, + ].map(({ text, key }) => { + const handleClick = () => keywordClick(text); + return ( + + {text} + + ); + })}
{themeInfo && themeInfo?.length > 0 && ( -
+
-
-
- Hot Picks ({themeInfo?.length}) -
+
+
Hot Picks ({themeInfo?.length})
)} -
+
{hasMore && ( - + )} - +
diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx index 6f53d98b..6f10a5b3 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ItemCard.jsx @@ -14,7 +14,9 @@ const ItemCard = ({ onClick, itemInfo }) => { const _handleItemClick = useCallback( (patnrId, prdtId) => (ev) => { - onClick && onClick(ev); + if (onClick) { + onClick(ev); + } dispatch( pushPanel({ name: panel_names.DETAIL_PANEL, @@ -25,20 +27,17 @@ const ItemCard = ({ onClick, itemInfo }) => { }) ); }, - [onClick] + [onClick, dispatch] ); return ( <> - + {itemInfo.map((item, index) => { const { thumbnail, title, dcPrice, price, soldout, contentId } = item; - const tokens = contentId && contentId.split("_"); - const patnrId = tokens?.[4] || ""; - const prdtId = tokens?.[5] || ""; + const tokens = contentId && contentId.split('_'); + const patnrId = tokens?.[4] || ''; + const prdtId = tokens?.[5] || ''; return ( { soldoutFlag={soldout} dcPrice={dcPrice} originPrice={price} - spotlightId={"searchItemContents" + index} - label={index * 1 + 1 + " of " + itemInfo.length + 1} + spotlightId={'searchItemContents' + index} + label={index * 1 + 1 + ' of ' + itemInfo.length + 1} lastLabel=" go to detail, button" /> ); diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ShowCard.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ShowCard.jsx index 9e1c7659..a9fdb04c 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ShowCard.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchResultsNew/ShowCard.jsx @@ -2,29 +2,25 @@ import React, { useCallback } from 'react'; import { useDispatch } from 'react-redux'; -import SpotlightContainerDecorator - from '@enact/spotlight/SpotlightContainerDecorator'; +import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; import { pushPanel } from '../../../actions/panelActions'; -import TItemCardNew, { - IMAGETYPES, - TYPES, -} from '../../../components/TItemCard/TItemCard.new'; +import TItemCardNew, { TYPES } from '../../../components/TItemCard/TItemCard.new'; import { panel_names } from '../../../utils/Config'; import { SpotlightIds } from '../../../utils/SpotlightIds'; import css from './ShowCard.module.less'; -const Container = SpotlightContainerDecorator({ enterTo: null }, "div"); +const Container = SpotlightContainerDecorator({ enterTo: null }, 'div'); const ShowCard = ({ onClick, showInfo }) => { const dispatch = useDispatch(); - const _onClick = useCallback( - (contentId, thumbnail, liveFlag) => { - const tokens = contentId && contentId.split("_"); + const handleClick = useCallback( + (contentId, thumbnail, liveFlag) => () => { + const tokens = contentId && contentId.split('_'); - const linkTpCd = tokens[1] || ""; - const patnrId = tokens[4] || ""; - const showId = tokens[5] || ""; + const linkTpCd = tokens[1] || ''; + const patnrId = tokens[4] || ''; + const showId = tokens[5] || ''; if (onClick) { onClick(); @@ -39,30 +35,20 @@ const ShowCard = ({ onClick, showInfo }) => { chanId: showId, linkTpCd, thumbnail, - shptmBanrTpNm: liveFlag === "Y" ? "LIVE" : "VOD", + shptmBanrTpNm: liveFlag === 'Y' ? 'LIVE' : 'VOD', }, }) ); }, - [onClick] + [onClick, dispatch] ); return ( {showInfo.map((item, index) => { - const { - contentId, - endTime, - liveFlag, - partnerId, - partnerLogo, - partnerName, - startTime, - thumbnail, - title, - } = item; - const tokkens = contentId && contentId.split("_"); - const showId = tokkens[5] || ""; + const { contentId, liveFlag, partnerLogo, thumbnail, title } = item; + const tokkens = contentId && contentId.split('_'); + const showId = tokkens[5] || ''; return ( { imageSource={thumbnail} productName={title} logo={partnerLogo} - onClick={() => { - _onClick(contentId, thumbnail, liveFlag); - }} + onClick={handleClick(contentId, thumbnail, liveFlag)} productId={showId} - spotlightId={"categoryShowContents" + index} + spotlightId={'categoryShowContents' + index} data-wheel-point="true" logoDisplay="true" /> diff --git a/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx b/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx index ead6042a..ee7e5245 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/TInput/TInput.jsx @@ -19,13 +19,9 @@ const Container = Spottable('div'); export default function TInput({ kind, icon, - border, - color, className, spotlightDisabled, - spotlightBoxDisabled, spotlightId, - disabled, onKeyDown, scrollTop, onIconClick, @@ -79,13 +75,13 @@ export default function TInput({ onFocus(); } handleScrollReset(); - }, [onFocus]); + }, [onFocus, handleScrollReset]); const _onBlur = useCallback(() => { if (onBlur) { onBlur(); } handleStopScrolling(); - }, [onBlur]); + }, [onBlur, handleStopScrolling]); // onActivate: ๋‚ด๋ถ€ input์— ์‹ค์ œ๋กœ ํฌ์ปค์Šค๊ฐ€ ๊ฐ€์„œ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ (webOS ํ‚ค๋ณด๋“œ๊ฐ€ ๋œจ๋Š” ์‹œ์ ) const _onActivate = useCallback(() => { 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 621f7038..e5e5b7a7 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/VoiceInputOverlay.jsx @@ -63,7 +63,6 @@ export const VOICE_VERSION = { const OVERLAY_SPOTLIGHT_ID = 'voice-input-overlay-container'; const INPUT_SPOTLIGHT_ID = 'voice-overlay-input-box'; const MIC_SPOTLIGHT_ID = 'voice-overlay-mic-button'; -const MIC_WEBSPEECH_SPOTLIGHT_ID = 'voice-overlay-mic-webspeech-button'; // ๐Ÿ”ง ์‹คํ—˜์  ๊ธฐ๋Šฅ: Wake Word Detection ("Hey Shoptime") // false๋กœ ์„ค์ •ํ•˜๋ฉด ์ด ๊ธฐ๋Šฅ์€ ์™„์ „ํžˆ ๋น„ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค @@ -93,7 +92,6 @@ const VoiceInputOverlay = ({ suggestions = [], searchQuery = '', onSearchChange, - onSearchSubmit, }) => { const dispatch = useDispatch(); const lastFocusedElement = useRef(null); @@ -117,7 +115,6 @@ const VoiceInputOverlay = ({ wakeWordRestartTimerRef, ]; - const [inputFocus, setInputFocus] = useState(false); const [micFocused, setMicFocused] = useState(false); // ๋‚ด๋ถ€ ๋ชจ๋“œ ์ƒํƒœ ๊ด€๋ฆฌ (prompt -> listening -> response -> close) const [currentMode, setCurrentMode] = useState(mode); @@ -126,7 +123,7 @@ const VoiceInputOverlay = ({ // STT ์‘๋‹ต ํ…์ŠคํŠธ ์ €์žฅ const [sttResponseText, setSttResponseText] = useState(''); // Voice Version (์–ด๋–ค ์Œ์„ฑ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ• ์ง€ ๊ฒฐ์ •) - const [voiceVersion, setVoiceVersion] = useState(VOICE_VERSION.WEB_SPEECH); + const voiceVersion = VOICE_VERSION.WEB_SPEECH; // ๐Ÿ”Š Beep ์†Œ๋ฆฌ ์žฌ์ƒ ํ•จ์ˆ˜ - zero dependencies const playBeep = useCallback(() => { @@ -222,16 +219,15 @@ const VoiceInputOverlay = ({ } }, []); - const { isListening, interimText, startListening, stopListening, error, isSupported } = - useWebSpeech( - isVisible, // Overlay๊ฐ€ ์—ด๋ ค์žˆ์„ ๋•Œ๋งŒ ํ™œ์„ฑํ™” (voiceInputMode์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ดˆ๊ธฐํ™”) - handleWebSpeechSTT, - { - lang: 'en-US', - continuous: false, // ์นจ๋ฌต ๊ฐ์ง€ ํ›„ ์ž๋™ ์ข…๋ฃŒ - interimResults: true, - } - ); + const { isListening, interimText, startListening, stopListening, isSupported } = useWebSpeech( + isVisible, // Overlay๊ฐ€ ์—ด๋ ค์žˆ์„ ๋•Œ๋งŒ ํ™œ์„ฑํ™” (voiceInputMode์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ดˆ๊ธฐํ™”) + handleWebSpeechSTT, + { + lang: 'en-US', + continuous: false, // ์นจ๋ฌต ๊ฐ์ง€ ํ›„ ์ž๋™ ์ข…๋ฃŒ + interimResults: true, + } + ); // โ›” VUI ํ…Œ์ŠคํŠธ ๋น„ํ™œ์„ฑํ™”: VoicePanel ๋…๋ฆฝ ํ…Œ์ŠคํŠธ ์‹œ ์ถฉ๋Œ ๋ฐฉ์ง€ // Redux์—์„œ voice ์ƒํƒœ ๊ฐ€์ ธ์˜ค๊ธฐ @@ -393,7 +389,7 @@ const VoiceInputOverlay = ({ stopListening(); } }; - }, [ENABLE_WAKE_WORD, isVisible, currentMode, startListening, stopListening]); + }, [isVisible, currentMode, startListening, stopListening]); // Overlay๊ฐ€ ์—ด๋ฆด ๋•Œ ํฌ์ปค์Šค๋ฅผ overlay ๋‚ด๋ถ€๋กœ ์ด๋™ useEffect(() => { @@ -459,6 +455,7 @@ const VoiceInputOverlay = ({ audioContextRef.current = null; } }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Suggestion ๋ฒ„ํŠผ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ - Input ์ฐฝ์— ํ…์ŠคํŠธ๋งŒ ์„ค์ • @@ -615,15 +612,6 @@ const VoiceInputOverlay = ({ handleTalkAgain, ]); - // ์ž…๋ ฅ์ฐฝ ํฌ์ปค์Šค ํ•ธ๋“ค๋Ÿฌ - const handleInputFocus = useCallback(() => { - setInputFocus(true); - }, []); - - const handleInputBlur = useCallback(() => { - setInputFocus(false); - }, []); - // ๋งˆ์ดํฌ ๋ฒ„ํŠผ ํฌ์ปค์Šค ํ•ธ๋“ค๋Ÿฌ (VUI) const handleMicFocus = useCallback(() => { setMicFocused(true); @@ -633,52 +621,6 @@ const VoiceInputOverlay = ({ setMicFocused(false); }, []); - // VUI ๋งˆ์ดํฌ ๋ฒ„ํŠผ ํด๋ฆญ ํ•ธ๋“ค๋Ÿฌ (voiceVersion์ด VUI์ผ ๋•Œ๋งŒ ์ž‘๋™) - const handleVUIMicClick = useCallback( - (e) => { - // voiceVersion์ด VUI๊ฐ€ ์•„๋‹ˆ๋ฉด ์ฐจ๋‹จ - if (voiceVersion !== VOICE_VERSION.VUI) return; - - if (DEBUG_MODE) { - console.log('[VoiceInputOverlay.v2] handleVUIMicClick called, currentMode:', currentMode); - } - - // ์ด๋ฒคํŠธ ์ „ํŒŒ ๋ฐฉ์ง€ - dim ๋ ˆ์ด์–ด์˜ onClick ์‹คํ–‰ ๋ฐฉ์ง€ - if (e && e.stopPropagation) { - e.stopPropagation(); - } - if (e && e.nativeEvent && e.nativeEvent.stopImmediatePropagation) { - e.nativeEvent.stopImmediatePropagation(); - } - - if (currentMode === VOICE_MODES.PROMPT) { - // prompt ๋ชจ๋“œ์—์„œ ํด๋ฆญ ์‹œ -> VUI listening ๋ชจ๋“œ๋กœ ์ „ํ™˜ - if (DEBUG_MODE) { - console.log('[VoiceInputOverlay.v2] Switching to VUI LISTENING mode'); - } - setVoiceInputMode(VOICE_INPUT_MODE.VUI); - setCurrentMode(VOICE_MODES.LISTENING); - // ์ด ์‹œ์ ์—์„œ webOS Voice Framework๊ฐ€ ์ž๋™์œผ๋กœ ์Œ์„ฑ์ธ์‹ ์‹œ์ž‘ - // (์ด๋ฏธ registerVoiceFramework()๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ) - } else if (currentMode === VOICE_MODES.LISTENING && voiceInputMode === VOICE_INPUT_MODE.VUI) { - // VUI listening ๋ชจ๋“œ์—์„œ ํด๋ฆญ ์‹œ -> ์ข…๋ฃŒ - if (DEBUG_MODE) { - console.log('[VoiceInputOverlay.v2] Closing from VUI LISTENING mode'); - } - setVoiceInputMode(null); - onClose(); - } else { - // ๊ธฐํƒ€ ๋ชจ๋“œ์—์„œ๋Š” ๋ฐ”๋กœ ์ข…๋ฃŒ - if (DEBUG_MODE) { - console.log('[VoiceInputOverlay.v2] Closing from other mode'); - } - setVoiceInputMode(null); - onClose(); - } - }, - [currentMode, voiceInputMode, voiceVersion, onClose] - ); - // Overlay ๋‹ซ๊ธฐ ํ•ธ๋“ค๋Ÿฌ (๋ชจ๋“  ๋‹ซ๊ธฐ ๋™์ž‘์„ ํ†ตํ•ฉ) const handleClose = useCallback(() => { if (DEBUG_MODE) { @@ -756,6 +698,18 @@ const VoiceInputOverlay = ({ [currentMode, handleClose, playBeep, startListening, stopListening] ); + // ๋งˆ์ดํฌ ๋ฒ„ํŠผ ํ‚ค๋‹ค์šด ํ•ธ๋“ค๋Ÿฌ + const handleMicKeyDown = useCallback( + (e) => { + if (e.key === 'Enter' || e.keyCode === 13) { + e.preventDefault(); + e.stopPropagation(); + handleWebSpeechMicClick(e); + } + }, + [handleWebSpeechMicClick] + ); + // Memoize microphone button rendering const microphoneButton = useMemo(() => { if (voiceVersion !== VOICE_VERSION.WEB_SPEECH) return null; @@ -771,13 +725,7 @@ const VoiceInputOverlay = ({ micFocused && css.focused )} onClick={handleWebSpeechMicClick} - onKeyDown={(e) => { - if (e.key === 'Enter' || e.keyCode === 13) { - e.preventDefault(); - e.stopPropagation(); - handleWebSpeechMicClick(e); - } - }} + onKeyDown={handleMicKeyDown} onFocus={handleMicFocus} onBlur={handleMicBlur} spotlightId={MIC_SPOTLIGHT_ID} @@ -806,6 +754,7 @@ const VoiceInputOverlay = ({ voiceInputMode, micFocused, handleWebSpeechMicClick, + handleMicKeyDown, handleMicFocus, handleMicBlur, ]); @@ -845,7 +794,7 @@ const VoiceInputOverlay = ({ {/* voiceVersion์— ๋”ฐ๋ผ ํ•˜๋‚˜์˜ ๋งˆ์ดํฌ๋งŒ ํ‘œ์‹œ */} diff --git a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoicePromptScreen.jsx b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoicePromptScreen.jsx index 229e9845..3ffd7c07 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoicePromptScreen.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoicePromptScreen.jsx @@ -16,8 +16,8 @@ const PromptContainer = SpotlightContainerDecorator( ); const VoicePromptScreen = ({ title = 'Try saying', suggestions = [], onSuggestionClick }) => { - const handleBubbleClick = (suggestion, index) => { - console.log(`[VoicePromptScreen] Bubble clicked: ${suggestion}`, index); + const handleBubbleClick = (suggestion) => { + console.log(`[VoicePromptScreen] Bubble clicked: ${suggestion}`); // ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๋กœ suggestion ํ…์ŠคํŠธ ์ „๋‹ฌ (API ํ˜ธ์ถœ์€ ๋ถ€๋ชจ์—์„œ ์ฒ˜๋ฆฌ) if (onSuggestionClick) { @@ -33,16 +33,19 @@ const VoicePromptScreen = ({ title = 'Try saying', suggestions = [], onSuggestio >
{title}
- {suggestions.map((suggestion, index) => ( - handleBubbleClick(suggestion, index)} - spotlightId={`voice-bubble-${index}`} - > -
{suggestion}
-
- ))} + {suggestions.map((suggestion, index) => { + const handleClick = () => handleBubbleClick(suggestion); + return ( + +
{suggestion}
+
+ ); + })}
); diff --git a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceResponse.jsx b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceResponse.jsx index 8d20fd96..761a7b79 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceResponse.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/VoiceInputOverlay/modes/VoiceResponse.jsx @@ -46,18 +46,16 @@ const VoiceResponse = ({ responseText = '', onTalkAgain }) => { } }; + const handleButtonClick = () => { + handleTalkAgainClick(); + }; + return (
{ - if (e.key === 'Enter' || e.keyCode === 13) { - e.preventDefault(); - handleTalkAgainClick(); - } - }} + onClick={handleButtonClick} spotlightId="voice-talk-again-button" > TALK AGAIN diff --git a/com.twin.app.shoptime/src/views/UserReview/ShowUserReviews.jsx b/com.twin.app.shoptime/src/views/UserReview/ShowUserReviews.jsx index c07642d6..ef1d9add 100644 --- a/com.twin.app.shoptime/src/views/UserReview/ShowUserReviews.jsx +++ b/com.twin.app.shoptime/src/views/UserReview/ShowUserReviews.jsx @@ -39,7 +39,7 @@ const ShowUserReviews = ({ hasVideo, launchedFromPlayer }) => { }, }) ); - }, [dispatch, productData, reviewData, reviewListData]); + }, [dispatch, productData, reviewData, reviewListData, hasVideo, launchedFromPlayer]); const handleKeyDown = useCallback((event) => { if (event.key === 'ArrowUp') {