From 3b95810946a73ccd4354019504b6c50e696314d7 Mon Sep 17 00:00:00 2001 From: optrader Date: Sun, 23 Nov 2025 22:14:06 +0900 Subject: [PATCH] =?UTF-8?q?[251123]=20fix:=20CategoryPanel=20webOS?= =?UTF-8?q?=EC=9A=A9=20=EC=9E=AC=EC=8B=9C=EB=8F=84=20=EB=B0=8F=20=EA=B0=80?= =?UTF-8?q?=EB=93=9C=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ• 컀밋 μ‹œκ°„: 2025. 11. 23. 22:14:06 πŸ“Š λ³€κ²½ 톡계: β€’ 총 파일: 3개 β€’ μΆ”κ°€: +44쀄 β€’ μ‚­μ œ: -17쀄 πŸ“ μˆ˜μ •λœ 파일: ~ com.twin.app.shoptime/src/actions/mainActions.js ~ com.twin.app.shoptime/src/components/TabLayout/TabLayout.jsx ~ com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx πŸ”§ ν•¨μˆ˜ λ³€κ²½ λ‚΄μš©: πŸ“„ com.twin.app.shoptime/src/actions/mainActions.js (javascript): πŸ”„ Modified: getMainCategoryShowDetail(), getTop20Show() πŸ”§ μ£Όμš” λ³€κ²½ λ‚΄μš©: β€’ 핡심 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 κ°œμ„  β€’ UI μ»΄ν¬λ„ŒνŠΈ μ•„ν‚€ν…μ²˜ κ°œμ„  --- .../src/actions/mainActions.js | 60 +++-- .../src/components/TabLayout/TabLayout.jsx | 214 ++++++------------ .../src/views/CategoryPanel/CategoryPanel.jsx | 206 ++++++----------- 3 files changed, 188 insertions(+), 292 deletions(-) diff --git a/com.twin.app.shoptime/src/actions/mainActions.js b/com.twin.app.shoptime/src/actions/mainActions.js index 398f2358..9239497a 100644 --- a/com.twin.app.shoptime/src/actions/mainActions.js +++ b/com.twin.app.shoptime/src/actions/mainActions.js @@ -152,8 +152,10 @@ export const getMainCategoryShowDetail = (props) => (dispatch, getState) => { // μ„œλΈŒμΉ΄ν…Œκ³ λ¦¬ 쑰회 IF-LGSP-051 let getSubCategoryKey = null; let lastSubCategoryParams = {}; +const SUB_CATEGORY_RETRY_LIMIT = 3; +const SUB_CATEGORY_RETRY_DELAY_MS = 400; export const getSubCategory = - (params, pageNo = 1, key = null, clear = false) => + (params, pageNo = 1, key = null, clear = false, retryCount = 0) => (dispatch, getState) => { const { lgCatCd, patnrIdList, tabType, filterType, recommendIncFlag } = params; let pageSize = params.pageSize || CATEGORY_DATA_MAX_RESULTS_LIMIT; @@ -214,6 +216,22 @@ export const getSubCategory = }; const onFail = (error) => { + const nextRetryCount = retryCount + 1; + const canRetry = nextRetryCount < SUB_CATEGORY_RETRY_LIMIT; + + if (canRetry) { + console.warn('getSubCategory retry', { + lgCatCd, + pageNo, + retryCount: nextRetryCount, + }); + + setTimeout(() => { + dispatch(getSubCategory(params, pageNo, currentKey, clear, nextRetryCount)); + }, SUB_CATEGORY_RETRY_DELAY_MS * nextRetryCount); + return; + } + console.error('getSubCategory onFail', error); if (pageNo === 1) { lastSubCategoryParams = {}; @@ -234,23 +252,23 @@ export const getSubCategory = export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => { if (!lastSubCategoryParams) { -// <<<<<<< HEAD + // <<<<<<< HEAD console.warn('No previous category parameters found'); -// ======= -// console.warn("No previous category parameters found"); -// >>>>>>> gitlab/develop + // ======= + // console.warn("No previous category parameters found"); + // >>>>>>> gitlab/develop return; } const subCategoryData = getState().main.subCategoryData; const targetData = -// <<<<<<< HEAD + // <<<<<<< HEAD subCategoryData[key]?.subCatItemList || subCategoryData[key]?.subCatShowList || []; -// ======= -// subCategoryData[key]?.subCatItemList || -// subCategoryData[key]?.subCatShowList || -// []; -// >>>>>>> gitlab/develop + // ======= + // subCategoryData[key]?.subCatItemList || + // subCategoryData[key]?.subCatShowList || + // []; + // >>>>>>> gitlab/develop const totalCount = subCategoryData[key]?.total ?? 0; const startIndex = CATEGORY_DATA_MAX_RESULTS_LIMIT * (pageNo - 1); if ( @@ -261,13 +279,13 @@ export const continueGetSubCategory = (key, pageNo) => (dispatch, getState) => { //ignore query return; } -// <<<<<<< HEAD + // <<<<<<< HEAD dispatch(getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey)); -// ======= -// dispatch( -// getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey) -// ); -// >>>>>>> gitlab/develop + // ======= + // dispatch( + // getSubCategory({ ...lastSubCategoryParams }, pageNo, getSubCategoryKey) + // ); + // >>>>>>> gitlab/develop }; const clearSubCategory = () => ({ @@ -341,11 +359,11 @@ export const getMainYouMayLike = getState, 'get', URLS.GET_YOUMAYLIKE, -// <<<<<<< HEAD + // <<<<<<< HEAD { lgCatCd, exclCurationId, exclPatnrId, exclPrdtId, catDpTh3, catDpTh4 }, -// ======= -// { lgCatCd, catDpTh3, catDpTh4, exclCurationId, exclPatnrId, exclPrdtId }, -// >>>>>>> gitlab/develop + // ======= + // { lgCatCd, catDpTh3, catDpTh4, exclCurationId, exclPatnrId, exclPrdtId }, + // >>>>>>> gitlab/develop {}, onSuccess, onFail diff --git a/com.twin.app.shoptime/src/components/TabLayout/TabLayout.jsx b/com.twin.app.shoptime/src/components/TabLayout/TabLayout.jsx index 4d05b9d8..af53db66 100644 --- a/com.twin.app.shoptime/src/components/TabLayout/TabLayout.jsx +++ b/com.twin.app.shoptime/src/components/TabLayout/TabLayout.jsx @@ -1,42 +1,23 @@ -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import classNames from 'classnames'; -import { - useDispatch, - useSelector, -} from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; //μ•„μ΄μ½˜ import { Job } from '@enact/core/util'; //enact import Skinnable from '@enact/sandstone/Skinnable'; import Spotlight from '@enact/spotlight'; -import SpotlightContainerDecorator - from '@enact/spotlight/SpotlightContainerDecorator'; +import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; import { Cancelable } from '@enact/ui/Cancelable'; -import shoptimeFullIconRuc - from '../../../assets/images/icons/ic-lnb-logo-shoptime-ruc-white.png'; +import shoptimeFullIconRuc from '../../../assets/images/icons/ic-lnb-logo-shoptime-ruc-white.png'; //이미지 -import shoptimeFullIcon - from '../../../assets/images/icons/ic-lnb-logo-shoptime@3x.png'; +import shoptimeFullIcon from '../../../assets/images/icons/ic-lnb-logo-shoptime@3x.png'; import { gnbOpened } from '../../actions/commonActions'; -import { - checkEnterThroughGNB, - resetHomeInfo, -} from '../../actions/homeActions'; +import { checkEnterThroughGNB, resetHomeInfo } from '../../actions/homeActions'; import { resetPanels } from '../../actions/panelActions'; -import { - clearShopperHouseData, - resetSearch, - resetVoiceSearch, -} from '../../actions/searchActions'; +import { clearShopperHouseData, resetSearch, resetVoiceSearch } from '../../actions/searchActions'; import usePrevious from '../../hooks/usePrevious'; import useScrollTo from '../../hooks/useScrollTo'; import { panel_names } from '../../utils/Config'; @@ -55,32 +36,14 @@ import TabItem from './TabItem'; import TabItemSub from './TabItemSub'; import css from './TabLayout.module.less'; -const Container = SpotlightContainerDecorator( - { enterTo: "default-element" }, - "div" -); +const Container = SpotlightContainerDecorator({ enterTo: 'default-element' }, 'div'); -const MainContainer = SpotlightContainerDecorator( - { enterTo: "last-focused" }, - "div" -); +const MainContainer = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div'); -const CancelableDiv = Cancelable( - { modal: true, onCancel: "handleCancel" }, - Skinnable(Container) -); +const CancelableDiv = Cancelable({ modal: true, onCancel: 'handleCancel' }, Skinnable(Container)); class TabMenuItem { - constructor( - icons = "", - title = "", - spotlightId, - path, - patncNm, - target, - id, - children = [] - ) { + constructor(icons = '', title = '', spotlightId, path, patncNm, target, id, children = []) { this.icons = icons; this.title = title; this.spotlightId = spotlightId; @@ -147,55 +110,49 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { const [mainSelectedIndex, setMainSelectedIndex] = useState(-1); const [secondDepthReduce, setSecondDepthReduce] = useState(false); const [lastFocusId, setLastFocusId] = useState(null); - const [selectedTitle, setSelectedTitle] = useState(""); + const [selectedTitle, setSelectedTitle] = useState(''); const [selectedSubItemId, setSelectedSubItemId] = useState(null); const [selectedSubIndex, setSelectedSubIndex] = useState(-1); const [subTabLastFocusId, setSubTabLastFocusId] = useState(null); const [tabs, setTabs] = useState([]); const [tabFocused, setTabFocused] = useState([false, false, false]); //COLLABSED_MAIN, ACTIVATED_MAIN, ACTIVATED_SUB const panelSwitching = useRef(null); - const cursorVisible = useSelector( - (state) => state.common.appStatus.cursorVisible - ); + const cursorVisible = useSelector((state) => state.common.appStatus.cursorVisible); const cursorVisibleRef = usePrevious(cursorVisible); const data = useSelector((state) => state.home.menuData?.data); const panels = useSelector((state) => state.panels.panels); const { loginUserData } = useSelector((state) => state.common.appStatus); const menuItems = useSelector((state) => state.home.menuItems); - const webOSVersion = useSelector( - (state) => state.common.appStatus.webOSVersion - ); + const webOSVersion = useSelector((state) => state.common.appStatus.webOSVersion); const httpHeader = useSelector((state) => state.common.httpHeader); const broadcast = useSelector( (state) => state.common.broadcast, - (newState) => newState?.type !== "deActivateTab" // 'deActivateTab'일 λ•Œλ§Œ λ¦¬λ Œλ”λ§ ν—ˆμš© + (newState) => newState?.type !== 'deActivateTab' // 'deActivateTab'일 λ•Œλ§Œ λ¦¬λ Œλ”λ§ ν—ˆμš© ); - const deviceCountryCode = httpHeader["X-Device-Country"]; + const deviceCountryCode = httpHeader['X-Device-Country']; const mouseNavOpen = useRef(new Job((func) => func(), 1000)); const mouseMainEntered = useRef(false); const scrollTopJobRef = useRef(new Job((func) => func(), 0)); const getMenuData = (type) => { let result = []; - + switch (type) { - case "GNB": + case 'GNB': result = - data?.gnb && - data.gnb.map((item) => ({ + data?.gnb?.map((item) => ({ title: item.menuNm, - })); + })) || []; break; //μΉ΄ν…Œκ³ λ¦¬ case 10500: result = - data?.homeCategory && - data.homeCategory.map((item) => ({ + data?.homeCategory?.map((item) => ({ icons: CategoryIcon, id: item.lgCatCd, title: item.lgCatNm, - spotlightId: "spotlight_category", + spotlightId: 'spotlight_category', target: [ { name: panel_names.CATEGORY_PANEL, @@ -211,34 +168,33 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { }, }, ], - })); + })) || []; break; //λΈŒλžœλ“œ case 10300: result = - data?.shortFeaturedBrands && - data.shortFeaturedBrands.map((item) => ({ + data?.shortFeaturedBrands?.map((item) => ({ icons: FeaturedBrandIcon, id: item.patnrId, path: item.patncLogoPath, patncNm: item.patncNm, - spotlightId: "spotlight_featuredbrand", + spotlightId: 'spotlight_featuredbrand', target: [ { name: panel_names.FEATURED_BRANDS_PANEL, - panelInfo: { from: "gnb", patnrId: item.patnrId }, + panelInfo: { from: 'gnb', patnrId: item.patnrId }, }, ], - })); + })) || []; break; // case 10600: - result = data.mypage - .map((item) => ({ + result = ( + data?.mypage?.map((item) => ({ icons: MyPageIcon, id: item.menuId, title: item.menuNm, - spotlightId: "spotlight_mypage", + spotlightId: 'spotlight_mypage', target: [ { name: panel_names.MY_PAGE_PANEL, @@ -249,26 +205,23 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { }, }, ], - })) - .filter((item) => { - if (!loginUserData.userNumber && item.title === "My Orders") { - return false; - } - if ( - webOSVersion < "6.0" && - (item.title === "My Orders" || item.title === "My Info") - ) { - return false; - } - return true; - }); + })) || [] + ).filter((item) => { + if (!loginUserData.userNumber && item.title === 'My Orders') { + return false; + } + if (webOSVersion < '6.0' && (item.title === 'My Orders' || item.title === 'My Info')) { + return false; + } + return true; + }); break; case 10700: result = [ { icons: SearchIcon, - spotlightId: "spotlight_search", + spotlightId: 'spotlight_search', target: [{ name: panel_names.SEARCH_PANEL }], }, ]; @@ -278,7 +231,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { result = [ { icons: HomeIcon, - spotlightId: "spotlight_home", + spotlightId: 'spotlight_home', target: [{ name: panel_names.HOME_PANEL }], }, ]; @@ -288,7 +241,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { result = [ { icons: OnSaleIcon, - spotlightId: "spotlight_onsale", + spotlightId: 'spotlight_onsale', target: [{ name: panel_names.ON_SALE_PANEL }], }, ]; @@ -298,7 +251,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { result = [ { icons: TrendingNowIcon, - spotlightId: "spotlight_trendingnow", + spotlightId: 'spotlight_trendingnow', target: [{ name: panel_names.TRENDING_NOW_PANEL }], }, ]; @@ -308,16 +261,16 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { result = [ { icons: HotPicksIcon, - spotlightId: "spotlight_hotpicks", + spotlightId: 'spotlight_hotpicks', target: [{ name: panel_names.HOT_PICKS_PANEL }], }, ]; break; - case 10800: + case 10800: result = [ { icons: CartIcon, - spotlightId: "spotlight_cart", + spotlightId: 'spotlight_cart', target: [{ name: panel_names.CART_PANEL }], }, ]; @@ -331,7 +284,12 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { if (data) { for (let i = 0; i < menuItems.length; i++) { const currentKey = menuItems[i].menuId; - const menuInfo = getMenuData(currentKey || "GNB"); + const menuInfo = getMenuData(currentKey || 'GNB') || []; + + if (!Array.isArray(menuInfo) || menuInfo.length === 0) { + menuItems[i].children = []; + continue; + } for (let j = 0; j < menuInfo.length; j++) { if (![10600, 10500, 10300].includes(currentKey)) { @@ -595,7 +553,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { }, [mainExpanded, mainSelectedIndex]); const logoImg = useMemo(() => { - if (deviceCountryCode === "RU") { + if (deviceCountryCode === 'RU') { return shoptimeFullIconRuc; } else return shoptimeFullIcon; }, [deviceCountryCode]); @@ -608,11 +566,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { }, [topPanelName]); const showSubTab = useMemo(() => { - if ( - tabActivated && - tabs[mainSelectedIndex] && - tabs[mainSelectedIndex].hasChildren() - ) { + if (tabActivated && tabs[mainSelectedIndex] && tabs[mainSelectedIndex].hasChildren()) { return true; // μ„œλΈŒ 탭이 μžˆλŠ” 경우 } return false; // μ„œλΈŒ 탭이 μ—†λŠ” 경우 @@ -640,7 +594,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { dispatch(gnbOpened(true)); if (panels.length === 0) { - Spotlight.focus("spotlight_home"); + Spotlight.focus('spotlight_home'); return; } @@ -650,7 +604,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { // else { if (!subTabLastFocusId) { - Spotlight.focus("spotlight_home"); + Spotlight.focus('spotlight_home'); } } } @@ -664,7 +618,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { useEffect(() => { if (!panelInfo) { setMainSelectedIndex(-1); - setLastFocusId("spotlight_home"); + setLastFocusId('spotlight_home'); setSubTabLastFocusId(null); return; } @@ -681,17 +635,11 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { subTarget = panelInfo.lgCatCd; } // case: Featured Brands 2depth - else if ( - topPanelName === panel_names.FEATURED_BRANDS_PANEL && - panelInfo?.patnrId - ) { + else if (topPanelName === panel_names.FEATURED_BRANDS_PANEL && panelInfo?.patnrId) { subTarget = panelInfo.patnrId; } // case: My Info 2depth - else if ( - topPanelName === panel_names.MY_PAGE_PANEL && - panelInfo?.menuId - ) { + else if (topPanelName === panel_names.MY_PAGE_PANEL && panelInfo?.menuId) { subTarget = panelInfo.menuId; } } @@ -716,8 +664,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { }, [tabActivated, subTabLastFocusId, mainSelectedIndex]); useEffect(() => { - const hasFeaturedBrands = - tabs[mainSelectedIndex]?.children[0]?.path !== undefined; + const hasFeaturedBrands = tabs[mainSelectedIndex]?.children[0]?.path !== undefined; const SCROLL_OFFSET_INDEX = hasFeaturedBrands ? 8 : 9; @@ -735,9 +682,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { tabs[mainSelectedIndex]?.children.length - 1 >= selectedSubIndex ) { const targetScrollIndex = selectedSubIndex - SCROLL_OFFSET_INDEX; - scrollTopJobRef.current.start(() => - scrollTop({ y: y * targetScrollIndex }) - ); + scrollTopJobRef.current.start(() => scrollTop({ y: y * targetScrollIndex })); return () => scrollTopJobRef.current.stop(); } @@ -770,8 +715,8 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { }, [cursorVisible]); useEffect(() => { - if (broadcast?.type === "deActivateTab") { - console.log("TabLayout deactivateTab by broadcast"); + if (broadcast?.type === 'deActivateTab') { + console.log('TabLayout deactivateTab by broadcast'); deActivateTab(); } }, [broadcast]); @@ -803,7 +748,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { const moveFocusToMainTab = useCallback( (e) => { - if (e.key === "ArrowLeft" && showSubTab && lastFocusId) { + if (e.key === 'ArrowLeft' && showSubTab && lastFocusId) { Spotlight.focus(lastFocusId); } }, @@ -846,16 +791,14 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) { {tabs.map((item, index) => ( - + {showSubTab && tabs[mainSelectedIndex]?.children.map((item, index) => { return ( ); diff --git a/com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx b/com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx index d336c31e..93fbd201 100644 --- a/com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx +++ b/com.twin.app.shoptime/src/views/CategoryPanel/CategoryPanel.jsx @@ -1,38 +1,25 @@ -import React, { - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react"; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import classNames from "classnames"; -import { useDispatch, useSelector } from "react-redux"; +import 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 { setContainerLastFocusedElement } from "@enact/spotlight/src/container"; +import { Job } from '@enact/core/util'; +import Spotlight from '@enact/spotlight'; +import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator'; +import { setContainerLastFocusedElement } from '@enact/spotlight/src/container'; -import { - sendLogCuration, - sendLogGNB, - sendLogTotalRecommend, -} from "../../actions/logActions"; -import { - continueGetSubCategory, - getSubCategory, -} from "../../actions/mainActions"; -import { updatePanel } from "../../actions/panelActions"; -import SectionTitle from "../../components/SectionTitle/SectionTitle"; -import TBody from "../../components/TBody/TBody"; -import TButton, { TYPES } from "../../components/TButton/TButton"; -import TButtonTab, { LIST_TYPE } from "../../components/TButtonTab/TButtonTab"; -import TDropDown from "../../components/TDropDown/TDropDown"; -import THeader from "../../components/THeader/THeader"; -import TPanel from "../../components/TPanel/TPanel"; -import TVerticalPagenator from "../../components/TVerticalPagenator/TVerticalPagenator"; -import usePrevious from "../../hooks/usePrevious"; +import { sendLogCuration, sendLogGNB, sendLogTotalRecommend } from '../../actions/logActions'; +import { continueGetSubCategory, getSubCategory } from '../../actions/mainActions'; +import { updatePanel } from '../../actions/panelActions'; +import SectionTitle from '../../components/SectionTitle/SectionTitle'; +import TBody from '../../components/TBody/TBody'; +import TButton, { TYPES } from '../../components/TButton/TButton'; +import TButtonTab, { LIST_TYPE } from '../../components/TButtonTab/TButtonTab'; +import TDropDown from '../../components/TDropDown/TDropDown'; +import THeader from '../../components/THeader/THeader'; +import TPanel from '../../components/TPanel/TPanel'; +import TVerticalPagenator from '../../components/TVerticalPagenator/TVerticalPagenator'; +import usePrevious from '../../hooks/usePrevious'; import { CATEGORY_DATA_MAX_RESULTS_LIMIT, LOG_CONTEXT_NAME, @@ -40,28 +27,21 @@ import { LOG_MESSAGE_ID, LOG_TP_NO, panel_names, -} from "../../utils/Config"; -import { - $L, - getSpottableDescendants, - isElementInContainer, -} from "../../utils/helperMethods"; -import { SpotlightIds } from "../../utils/SpotlightIds"; -import ItemContents from "./CategoryContents/ItemContents/ItemContents"; -import ShowContents from "./CategoryContents/ShowContents/ShowContents"; -import css from "./CategoryPanel.module.less"; +} from '../../utils/Config'; +import { $L, getSpottableDescendants, isElementInContainer } from '../../utils/helperMethods'; +import { SpotlightIds } from '../../utils/SpotlightIds'; +import ItemContents from './CategoryContents/ItemContents/ItemContents'; +import ShowContents from './CategoryContents/ShowContents/ShowContents'; +import css from './CategoryPanel.module.less'; -const Container = SpotlightContainerDecorator({ enterTo: null }, "div"); +const Container = SpotlightContainerDecorator({ enterTo: null }, 'div'); -const TabContainer = SpotlightContainerDecorator( - { enterTo: "last-focused" }, - "div" -); +const TabContainer = SpotlightContainerDecorator({ enterTo: 'last-focused' }, 'div'); const INDEX_ITEM = 0; const INDEX_SHOWS = 1; const getButtonTabList = () => { - return [$L("ITEM"), $L("SHOWS")]; + return [$L('ITEM'), $L('SHOWS')]; }; let buttonTabList = null; @@ -93,9 +73,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { const [tab, setTab] = useState(panelInfo.tab ? panelInfo.tab : INDEX_ITEM); const tabRef = usePrevious(tab); const categoryDatasRef = usePrevious(categoryDatas); - const [dropDownTab, setDropDownTab] = useState( - panelInfo.dropDownTab ? panelInfo.dropDownTab : 0 - ); + const [dropDownTab, setDropDownTab] = useState(panelInfo.dropDownTab ? panelInfo.dropDownTab : 0); const dropDownTabRef = usePrevious(dropDownTab); const [filterMethods, setFilterMethods] = useState([]); const [styleChange, setStyleChange] = useState(false); @@ -143,19 +121,19 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { } logParamsRef.current = { - cnttTpNm: "", + cnttTpNm: '', expsOrd: `${panelInfo?.expsOrd}`, lgCatCd, lgCatNm, linkTpCd: panelInfo?.linkTpCd, logTpNo: LOG_TP_NO.CURATION.CATEGORY, - sortTpNm: "", + sortTpNm: '', }; }, [categoryItemInfos, categoryShowInfos, panelInfo?.expsOrd, tab]); useEffect(() => { const timer = setTimeout(() => { - const cnttTpNm = tab === INDEX_SHOWS ? "Show" : "Item"; + const cnttTpNm = tab === INDEX_SHOWS ? 'Show' : 'Item'; dispatch(sendLogCuration({ ...logParamsRef.current, cnttTpNm })); }, 1000); @@ -164,7 +142,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { useEffect(() => { const timer = setTimeout(() => { - const sortTpNm = dropDownTab === 0 ? "New" : "Popular"; + const sortTpNm = dropDownTab === 0 ? 'New' : 'Popular'; dispatch(sendLogCuration({ ...logParamsRef.current, sortTpNm })); }, 1000); @@ -172,15 +150,20 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { }, [dropDownTab, panelInfo?.expsOrd]); const reload = useCallback(() => { - const tabType = tabRef.current === INDEX_SHOWS ? "CAT00101" : "CAT00102"; - const filterType = dropDownTabRef.current === 0 ? "CAT00202" : "CAT00201"; - const pageSize = "20"; + const tabType = tabRef.current === INDEX_SHOWS ? 'CAT00101' : 'CAT00102'; + const filterType = dropDownTabRef.current === 0 ? 'CAT00202' : 'CAT00201'; + const pageSize = '20'; + const hasCategoryData = + tabRef.current === INDEX_SHOWS + ? !!categoryDatas?.categoryShowInfos + : !!categoryDatas?.categoryItemInfos; if ( categoryParams?.lgCatCd !== lgCatCd || categoryParams?.tabType !== tabType || categoryParams?.filterType !== filterType || - categoryParams?.pageSize !== pageSize + categoryParams?.pageSize !== pageSize || + !hasCategoryData ) { dispatch( getSubCategory( @@ -196,7 +179,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { ) ); } - }, [categoryParams, lgCatCd, tab, dropDownTab]); + }, [categoryDatas, categoryParams, lgCatCd, tab, dropDownTab]); //panelInfo changed useEffect(() => { @@ -207,9 +190,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { if (panelInfo.tab !== tab) { setContainerLastFocusedElement(null, [SpotlightIds.SHOW_PRODUCTS_BOX]); setContainerLastFocusedElement(null, [SpotlightIds.SHOW_CONTENTS_BOX]); - setContainerLastFocusedElement(null, [ - SpotlightIds.CATEGORY_CONTENTS_BOX, - ]); + setContainerLastFocusedElement(null, [SpotlightIds.CATEGORY_CONTENTS_BOX]); setTab(panelInfo.tab ? panelInfo.tab : INDEX_ITEM); } else if (panelInfo.currentSpot) { Spotlight.focus(panelInfo.currentSpot); @@ -217,7 +198,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { setTimeout(() => { if (tab === INDEX_ITEM) { - Spotlight.focus(`[data-spotlight-id="${"tab-" + tab}"]`); + Spotlight.focus(`[data-spotlight-id="${'tab-' + tab}"]`); } Spotlight.focus(SpotlightIds.TBODY); if (panelInfo.currentSpot) { @@ -230,13 +211,9 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { useEffect(() => { if (categoryDatas) { - const tabNode = document.querySelector( - `[data-spotlight-id="${"tab-" + tab}"]` - ); + const tabNode = document.querySelector(`[data-spotlight-id="${'tab-' + tab}"]`); if (tabNode) { - setContainerLastFocusedElement(tabNode, [ - SpotlightIds.CATEGORY_TAB_CONTAINER, - ]); + setContainerLastFocusedElement(tabNode, [SpotlightIds.CATEGORY_TAB_CONTAINER]); } } }, [tab, categoryDatas, panelInfo]); @@ -247,9 +224,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { setContainerLastFocusedElement(null, [SpotlightIds.CATEGORY_CONTENTS_BOX]); reload(); if (categoryFilterCd) { - const detailCdNmValues = categoryFilterCd - .map((item) => $L(item.detailCdNm)) - .reverse(); + const detailCdNmValues = categoryFilterCd.map((item) => $L(item.detailCdNm)).reverse(); setFilterMethods(detailCdNmValues); } @@ -274,7 +249,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { const target = ev.currentTarget; let currentSpotId = null; if (target) { - currentSpotId = target.getAttribute("data-spotlight-id"); + currentSpotId = target.getAttribute('data-spotlight-id'); } dispatch( updatePanel({ @@ -293,43 +268,28 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { let clickedTopShow = null; let clickedTopShowPrd = null; - if ( - categoryItemInfos?.subCatItemList && - currentSpotId.includes("categoryItemContents") - ) { - const clickedNumber = Number( - currentSpotId.replace("categoryItemContents", "") - ); + if (categoryItemInfos?.subCatItemList && currentSpotId.includes('categoryItemContents')) { + const clickedNumber = Number(currentSpotId.replace('categoryItemContents', '')); clickedItem = categoryItemInfos.subCatItemList[clickedNumber]; } - if ( - categoryShowInfos?.subCatShowList && - currentSpotId.includes("categoryShowContents") - ) { - const clickedNumber = Number( - currentSpotId.replace("categoryShowContents", "") - ); + if (categoryShowInfos?.subCatShowList && currentSpotId.includes('categoryShowContents')) { + const clickedNumber = Number(currentSpotId.replace('categoryShowContents', '')); clickedShow = categoryShowInfos.subCatShowList[clickedNumber]; } if (topShowInfo?.productInfos) { - if (currentSpotId.includes("showCategory-spotlightId")) { - const clickedId = currentSpotId.replace( - "showCategory-spotlightId-", - "" - ); - clickedTopShowPrd = topShowInfo.productInfos.find( - (item) => clickedId === item.prdtId - ); - } else if (currentSpotId.includes("category-topshow")) { + if (currentSpotId.includes('showCategory-spotlightId')) { + const clickedId = currentSpotId.replace('showCategory-spotlightId-', ''); + clickedTopShowPrd = topShowInfo.productInfos.find((item) => clickedId === item.prdtId); + } else if (currentSpotId.includes('category-topshow')) { clickedTopShow = topShowInfo; } } const params = { - tabTitle: tabRef.current === 0 ? "ITEM" : "SHOWS", - sortType: dropDownTabRef.current === 0 ? "NEW" : "MOST POPULAR", + tabTitle: tabRef.current === 0 ? 'ITEM' : 'SHOWS', + sortType: dropDownTabRef.current === 0 ? 'NEW' : 'MOST POPULAR', contextName: LOG_CONTEXT_NAME.CATEGORY, messageId: LOG_MESSAGE_ID.CONTENTCLICK, }; @@ -359,8 +319,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { // 탑쇼 μƒν’ˆ 둜그 if (clickedTopShowPrd) { const { prdtId, prdtNm, priceInfo } = clickedTopShowPrd; - const [regularPrice, discountPrice, , , discountRate] = - priceInfo?.split("|") || []; + const [regularPrice, discountPrice, , , discountRate] = priceInfo?.split('|') || []; sendLog({ ...params, category: categoryShowInfos?.catNm, @@ -387,8 +346,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { // μ•„μ΄ν…œ 둜그 if (clickedItem) { const { prdtNm, priceInfo, brndNm, prdtId, patnrId } = clickedItem; - const [regularPrice, discountPrice, , , discountRate] = - priceInfo?.split("|") || []; + const [regularPrice, discountPrice, , , discountRate] = priceInfo?.split('|') || []; sendLog({ ...params, category: categoryItemInfos?.catNm, @@ -428,7 +386,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { cbChangePageRef.current(0, true, false); } setContainerLastFocusedElement(null, [SpotlightIds.CATEGORY_CONTENTS_BOX]); - Spotlight.focus("tab-" + tab); + Spotlight.focus('tab-' + tab); }, [tab]); //onScroll* event can't use Callback @@ -437,14 +395,9 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { tabRef.current === INDEX_SHOWS ? SpotlightIds.SHOW_CONTENTS_BOX : SpotlightIds.CATEGORY_CONTENTS_BOX; - const targetKey = - tabRef.current === INDEX_SHOWS - ? "categoryShowInfos" - : "categoryItemInfos"; + const targetKey = tabRef.current === INDEX_SHOWS ? 'categoryShowInfos' : 'categoryItemInfos'; const targetData = categoryDatasRef.current[targetKey]; - const subKey = targetData?.subCatItemList - ? "subCatItemList" - : "subCatShowList"; + const subKey = targetData?.subCatItemList ? 'subCatItemList' : 'subCatShowList'; const spottableDescendants = getSpottableDescendants(targetContentsBoxId); const visibleIndexes = []; @@ -473,40 +426,33 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { }, []); const showGotoTopButton = useMemo(() => { - const targetData = - tab === INDEX_SHOWS ? categoryShowInfos : categoryItemInfos; - const subKey = targetData?.subCatItemList - ? "subCatItemList" - : "subCatShowList"; + const targetData = tab === INDEX_SHOWS ? categoryShowInfos : categoryItemInfos; + const subKey = targetData?.subCatItemList ? 'subCatItemList' : 'subCatShowList'; if (!targetData || !targetData[subKey] || targetData.total < 5) { return false; } - return subKey === "subCatShowList" + return subKey === 'subCatShowList' ? targetData[subKey].length + 1 >= targetData.total : targetData[subKey].length >= targetData.total; }, [tab, categoryShowInfos, categoryItemInfos]); const itemCountNumbers = useMemo(() => { if (categoryItemInfos && tab === INDEX_ITEM) { - return categoryItemInfos.subCatItemList.length > 0 - ? categoryItemInfos.total - : "0"; + return categoryItemInfos.subCatItemList.length > 0 ? categoryItemInfos.total : '0'; } else if (categoryShowInfos && tab === INDEX_SHOWS) { - return categoryShowInfos.subCatShowList.length > 0 - ? categoryShowInfos.total - : "0"; + return categoryShowInfos.subCatShowList.length > 0 ? categoryShowInfos.total : '0'; } else { return; } }, [categoryItemInfos, categoryShowInfos, tab]); useEffect(() => { - const c = document.getElementById("floatLayer"); + const c = document.getElementById('floatLayer'); - c.classList.add("category_dropdown"); + c.classList.add('category_dropdown'); return () => { - c.classList.remove("category_dropdown"); + c.classList.remove('category_dropdown'); }; }, []); @@ -521,7 +467,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { { deleteFocus={true} > @@ -570,9 +516,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => { )} {tab === INDEX_ITEM && } - {tab === INDEX_SHOWS && ( - - )} + {tab === INDEX_SHOWS && } {showGotoTopButton && (