[251123] fix: CategoryPanel webOS용 재시도 및 가드로직 추가
🕐 커밋 시간: 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 컴포넌트 아키텍처 개선
This commit is contained in:
@@ -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 = {};
|
||||
|
||||
@@ -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,30 +110,26 @@ 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));
|
||||
@@ -179,23 +138,21 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
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,15 +205,12 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
},
|
||||
},
|
||||
],
|
||||
}))
|
||||
.filter((item) => {
|
||||
if (!loginUserData.userNumber && item.title === "My Orders") {
|
||||
})) || []
|
||||
).filter((item) => {
|
||||
if (!loginUserData.userNumber && item.title === 'My Orders') {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
webOSVersion < "6.0" &&
|
||||
(item.title === "My Orders" || item.title === "My Info")
|
||||
) {
|
||||
if (webOSVersion < '6.0' && (item.title === 'My Orders' || item.title === 'My Info')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -268,7 +221,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
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,7 +261,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
result = [
|
||||
{
|
||||
icons: HotPicksIcon,
|
||||
spotlightId: "spotlight_hotpicks",
|
||||
spotlightId: 'spotlight_hotpicks',
|
||||
target: [{ name: panel_names.HOT_PICKS_PANEL }],
|
||||
},
|
||||
];
|
||||
@@ -317,7 +270,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
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 }) {
|
||||
<img
|
||||
src={logoImg}
|
||||
alt=""
|
||||
className={classNames(
|
||||
deviceCountryCode === "RU" && css.rucLogo
|
||||
)}
|
||||
className={classNames(deviceCountryCode === 'RU' && css.rucLogo)}
|
||||
/>
|
||||
</h1>
|
||||
|
||||
{tabs.map((item, index) => (
|
||||
<TabItem
|
||||
{...item}
|
||||
key={"tabitemExpanded" + index}
|
||||
key={'tabitemExpanded' + index}
|
||||
onFocus={onFocus}
|
||||
spotlightId={item.spotlightId}
|
||||
setLastFocusId={setLastFocusId}
|
||||
@@ -865,11 +808,10 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
icons={item.icons}
|
||||
expanded={mainExpanded}
|
||||
mainSelected={
|
||||
(panels.length === 0 &&
|
||||
item.spotlightId === "spotlight_home") ||
|
||||
(panels.length === 0 && item.spotlightId === 'spotlight_home') ||
|
||||
(panels[0]?.name === panel_names.PLAYER_PANEL &&
|
||||
panels.length === 1 &&
|
||||
item.spotlightId === "spotlight_home") ||
|
||||
item.spotlightId === 'spotlight_home') ||
|
||||
(Array.isArray(item.target) &&
|
||||
item.target[0]?.name &&
|
||||
panels[0]?.name === item.target[0]?.name)
|
||||
@@ -906,19 +848,14 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
onMouseLeave={onTabBlur(ACTIVATED_SUB)}
|
||||
onKeyDown={moveFocusToMainTab}
|
||||
>
|
||||
<TScroller
|
||||
cbScrollTo={getScrollTo}
|
||||
className={css.scrollWrap}
|
||||
>
|
||||
<TScroller cbScrollTo={getScrollTo} className={css.scrollWrap}>
|
||||
{showSubTab &&
|
||||
tabs[mainSelectedIndex]?.children.map((item, index) => {
|
||||
return (
|
||||
<TabItemSub
|
||||
{...item}
|
||||
mainMenuTitle={
|
||||
tabs && tabs[mainSelectedIndex]?.title
|
||||
}
|
||||
key={"tabitemSubmenu" + index}
|
||||
mainMenuTitle={tabs && tabs[mainSelectedIndex]?.title}
|
||||
key={'tabitemSubmenu' + index}
|
||||
spotlightId={item.spotlightId}
|
||||
setLastFocusId={setSubTabLastFocusId}
|
||||
onClick={onClickSubItem}
|
||||
@@ -926,7 +863,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
index={index}
|
||||
isSubItem={true}
|
||||
deActivateTab={deActivateTab}
|
||||
title={item.title + "-sub"}
|
||||
title={item.title + '-sub'}
|
||||
itemId={item.id}
|
||||
path={item.path}
|
||||
patncNm={item.patncNm}
|
||||
@@ -940,10 +877,7 @@ export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
||||
panels[0]?.panelInfo === item.target[0]?.panelInfo
|
||||
}
|
||||
label={
|
||||
index * 1 +
|
||||
1 +
|
||||
" of " +
|
||||
tabs[mainSelectedIndex]?.children.length
|
||||
index * 1 + 1 + ' of ' + tabs[mainSelectedIndex]?.children.length
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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 }) => {
|
||||
<TBody className={css.tBody} scrollable={false}>
|
||||
<TVerticalPagenator
|
||||
className={css.tVerticalPagenator}
|
||||
spotlightId={"category_verticalPagenator"}
|
||||
spotlightId={'category_verticalPagenator'}
|
||||
defaultContainerId={panelInfo?.focusedContainerId}
|
||||
onScrollStop={onScrollStop}
|
||||
onFocusedContainerId={onFocusedContainerId}
|
||||
@@ -530,7 +476,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => {
|
||||
deleteFocus={true}
|
||||
>
|
||||
<Container
|
||||
spotlightId={"categorypanel_top_point_area"}
|
||||
spotlightId={'categorypanel_top_point_area'}
|
||||
data-wheel-point={true}
|
||||
className={css.cateContainer}
|
||||
>
|
||||
@@ -570,9 +516,7 @@ const CategoryPanel = ({ panelInfo, isOnTop, spotlightId }) => {
|
||||
</TabContainer>
|
||||
)}
|
||||
{tab === INDEX_ITEM && <ItemContents onClick={handleItemClick} />}
|
||||
{tab === INDEX_SHOWS && (
|
||||
<ShowContents onClick={handleItemClick} />
|
||||
)}
|
||||
{tab === INDEX_SHOWS && <ShowContents onClick={handleItemClick} />}
|
||||
</Container>
|
||||
{showGotoTopButton && (
|
||||
<TButton
|
||||
|
||||
Reference in New Issue
Block a user