934 lines
26 KiB
JavaScript
934 lines
26 KiB
JavaScript
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";
|
|
//enact
|
|
import Skinnable from "@enact/sandstone/Skinnable";
|
|
import Spotlight from "@enact/spotlight";
|
|
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 shoptimeFullIcon from "../../../assets/images/icons/ic-lnb-logo-shoptime@3x.png";
|
|
import { gnbOpened } from "../../actions/commonActions";
|
|
import { checkEnterThroughGNB, resetHomeInfo } from "../../actions/homeActions";
|
|
import { resetPanels } from "../../actions/panelActions";
|
|
import usePrevious from "../../hooks/usePrevious";
|
|
import useScrollTo from "../../hooks/useScrollTo";
|
|
import { panel_names } from "../../utils/Config";
|
|
import { SpotlightIds } from "../../utils/SpotlightIds";
|
|
import TScroller from "../TScroller/TScroller";
|
|
import CategoryIcon from "./iconComponents/CategoryIcon";
|
|
import FeaturedBrandIcon from "./iconComponents/FeaturedBrandIcon";
|
|
import HomeIcon from "./iconComponents/HomeIcon";
|
|
import HotPicksIcon from "./iconComponents/HotPicksIcon";
|
|
import MyPageIcon from "./iconComponents/MyPageIcon";
|
|
import OnSaleIcon from "./iconComponents/OnSaleIcon";
|
|
import SearchIcon from "./iconComponents/SearchIcon";
|
|
import TrendingNowIcon from "./iconComponents/TrendingNowIcon";
|
|
import TabItem from "./TabItem";
|
|
import TabItemSub from "./TabItemSub";
|
|
import css from "./TabLayout.module.less";
|
|
|
|
const Container = SpotlightContainerDecorator(
|
|
{ enterTo: "default-element" },
|
|
"div"
|
|
);
|
|
|
|
const MainContainer = SpotlightContainerDecorator(
|
|
{ enterTo: "last-focused" },
|
|
"div"
|
|
);
|
|
|
|
const CancelableDiv = Cancelable(
|
|
{ modal: true, onCancel: "handleCancel" },
|
|
Skinnable(Container)
|
|
);
|
|
|
|
class TabMenuItem {
|
|
constructor(
|
|
icons = "",
|
|
title = "",
|
|
spotlightId,
|
|
path,
|
|
patncNm,
|
|
target,
|
|
id,
|
|
children = []
|
|
) {
|
|
this.icons = icons;
|
|
this.title = title;
|
|
this.spotlightId = spotlightId;
|
|
this.path = path;
|
|
this.target = target;
|
|
this.id = id;
|
|
this.patncNm = patncNm;
|
|
this.children = children.map(
|
|
(child) =>
|
|
new TabMenuItem(
|
|
child.icons,
|
|
child.title,
|
|
child.spotlightId,
|
|
child.path,
|
|
child.patncNm,
|
|
child.target,
|
|
child.id
|
|
)
|
|
);
|
|
}
|
|
|
|
hasChildren = () => {
|
|
return this.children.length > 0;
|
|
};
|
|
|
|
getChildren = () => {
|
|
return this.children;
|
|
};
|
|
}
|
|
|
|
const deActivateTabJabFunc = (func) => {
|
|
func();
|
|
};
|
|
let deActivateTabJob = new Job(deActivateTabJabFunc, 2000);
|
|
|
|
const clearPanelSwitching = (ref) => {
|
|
if (ref) {
|
|
ref.current = false;
|
|
}
|
|
};
|
|
let panelSwitchingJob = new Job(clearPanelSwitching, 500);
|
|
|
|
const COLLABSED_MAIN = 0;
|
|
const ACTIVATED_MAIN = 1;
|
|
const ACTIVATED_SUB = 2;
|
|
const EXTRA_AREA = 3;
|
|
|
|
const PANELS_HAS_TAB = [
|
|
panel_names.CATEGORY_PANEL,
|
|
panel_names.FEATURED_BRANDS_PANEL,
|
|
panel_names.HOME_PANEL,
|
|
panel_names.HOT_PICKS_PANEL,
|
|
panel_names.MY_PAGE_PANEL,
|
|
panel_names.ON_SALE_PANEL,
|
|
panel_names.SEARCH_PANEL,
|
|
panel_names.TRENDING_NOW_PANEL,
|
|
];
|
|
|
|
export default function TabLayout({ topPanelName, onTabActivated, panelInfo }) {
|
|
const { getScrollTo, scrollTop } = useScrollTo();
|
|
const dispatch = useDispatch();
|
|
const [mainExpanded, setMainExpanded] = useState(false);
|
|
const [mainSelectedIndex, setMainSelectedIndex] = useState(-1);
|
|
const [secondDepthReduce, setSecondDepthReduce] = useState(false);
|
|
const [lastFocusId, setLastFocusId] = useState(null);
|
|
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 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 httpHeader = useSelector((state) => state.common.httpHeader);
|
|
const broadcast = useSelector(
|
|
(state) => state.common.broadcast,
|
|
(newState) => newState?.type !== "deActivateTab" // 'deActivateTab'일 때만 리렌더링 허용
|
|
);
|
|
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":
|
|
result =
|
|
data?.gnb &&
|
|
data.gnb.map((item) => ({
|
|
title: item.menuNm,
|
|
}));
|
|
break;
|
|
|
|
//카테고리
|
|
case 10500:
|
|
result =
|
|
data?.homeCategory &&
|
|
data.homeCategory.map((item) => ({
|
|
icons: CategoryIcon,
|
|
id: item.lgCatCd,
|
|
title: item.lgCatNm,
|
|
spotlightId: "spotlight_category",
|
|
target: [
|
|
{
|
|
name: panel_names.CATEGORY_PANEL,
|
|
panelInfo: {
|
|
lgCatNm: item.lgCatNm,
|
|
lgCatCd: item.lgCatCd,
|
|
COUNT: item.COUNT,
|
|
currentSpot: null,
|
|
dropDownTab: 0,
|
|
tab: 0,
|
|
focusedContainerId: null,
|
|
expsOrd: item?.expsOrd,
|
|
},
|
|
},
|
|
],
|
|
}));
|
|
break;
|
|
//브랜드
|
|
case 10300:
|
|
result =
|
|
data?.shortFeaturedBrands &&
|
|
data.shortFeaturedBrands.map((item) => ({
|
|
icons: FeaturedBrandIcon,
|
|
id: item.patnrId,
|
|
path: item.patncLogoPath,
|
|
patncNm: item.patncNm,
|
|
spotlightId: "spotlight_featuredbrand",
|
|
target: [
|
|
{
|
|
name: panel_names.FEATURED_BRANDS_PANEL,
|
|
panelInfo: { from: "gnb", patnrId: item.patnrId },
|
|
},
|
|
],
|
|
}));
|
|
break;
|
|
//
|
|
case 10600:
|
|
result = data.mypage
|
|
.map((item) => ({
|
|
icons: MyPageIcon,
|
|
id: item.menuId,
|
|
title: item.menuNm,
|
|
spotlightId: "spotlight_mypage",
|
|
target: [
|
|
{
|
|
name: panel_names.MY_PAGE_PANEL,
|
|
panelInfo: {
|
|
menuNm: item.menuNm,
|
|
menuOrd: item.menuOrd,
|
|
menuId: item.menuId,
|
|
},
|
|
},
|
|
],
|
|
}))
|
|
.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",
|
|
target: [{ name: panel_names.SEARCH_PANEL }],
|
|
},
|
|
];
|
|
break;
|
|
|
|
case 10100:
|
|
result = [
|
|
{
|
|
icons: HomeIcon,
|
|
spotlightId: "spotlight_home",
|
|
target: [{ name: panel_names.HOME_PANEL }],
|
|
},
|
|
];
|
|
break;
|
|
|
|
case 10400:
|
|
result = [
|
|
{
|
|
icons: OnSaleIcon,
|
|
spotlightId: "spotlight_onsale",
|
|
target: [{ name: panel_names.ON_SALE_PANEL }],
|
|
},
|
|
];
|
|
break;
|
|
|
|
case 10150:
|
|
result = [
|
|
{
|
|
icons: TrendingNowIcon,
|
|
spotlightId: "spotlight_trendingnow",
|
|
target: [{ name: panel_names.TRENDING_NOW_PANEL }],
|
|
},
|
|
];
|
|
break;
|
|
|
|
case 10200:
|
|
result = [
|
|
{
|
|
icons: HotPicksIcon,
|
|
spotlightId: "spotlight_hotpicks",
|
|
target: [{ name: panel_names.HOT_PICKS_PANEL }],
|
|
},
|
|
];
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
const dataDivide = useCallback(() => {
|
|
if (data) {
|
|
for (let i = 0; i < menuItems.length; i++) {
|
|
const currentKey = menuItems[i].menuId;
|
|
const menuInfo = getMenuData(currentKey || "GNB");
|
|
|
|
for (let j = 0; j < menuInfo.length; j++) {
|
|
if (![10600, 10500, 10300].includes(currentKey)) {
|
|
menuItems[i].target = menuInfo[j].target;
|
|
}
|
|
menuItems[i].spotlightId = menuInfo[j].spotlightId;
|
|
menuItems[i].icons = menuInfo[j].icons;
|
|
|
|
if ([10600, 10500, 10300].includes(currentKey)) {
|
|
menuItems[i].children = menuInfo.map((item) => ({
|
|
id: item.id,
|
|
title: item.title,
|
|
path: item.path,
|
|
patncNm: item.patncNm,
|
|
target: item.target,
|
|
spotlightId: `secondDepth-${item.id}`,
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (menuItems) {
|
|
setTabs(makeTabmenu());
|
|
}
|
|
}, [menuItems, loginUserData]);
|
|
|
|
const makeTabmenu = useCallback(() => {
|
|
const t = [];
|
|
for (let i = 0; i < menuItems.length; i++) {
|
|
const tabmenu = new TabMenuItem(
|
|
menuItems[i].icons,
|
|
menuItems[i].title,
|
|
menuItems[i].spotlightId,
|
|
menuItems[i].path,
|
|
menuItems[i].patncNm,
|
|
menuItems[i].target,
|
|
menuItems[i].id,
|
|
menuItems[i].children
|
|
);
|
|
t.push(tabmenu);
|
|
}
|
|
|
|
return t;
|
|
}, [menuItems]);
|
|
|
|
useEffect(() => {
|
|
dataDivide();
|
|
}, [menuItems, loginUserData]);
|
|
|
|
const deActivateTab = useCallback(() => {
|
|
setTabFocused([false, false, false, false]);
|
|
setMainSelectedIndex(-1);
|
|
setMainExpanded(false);
|
|
dispatch(gnbOpened(false));
|
|
}, [dispatch]);
|
|
|
|
const onTabHasFocus = useCallback(
|
|
(type) => (event) => {
|
|
switch (type) {
|
|
case COLLABSED_MAIN: {
|
|
if (cursorVisibleRef.current) {
|
|
mouseNavOpen.current.start(() => {
|
|
setMainExpanded(true);
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
case ACTIVATED_MAIN: {
|
|
if (!cursorVisibleRef.current) {
|
|
const parent = event.target.parentNode;
|
|
const children = parent.childNodes;
|
|
const index = Array.prototype.indexOf.call(children, event.target);
|
|
setMainExpanded(true);
|
|
setMainSelectedIndex(index - 1);
|
|
setSecondDepthReduce(false);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ACTIVATED_SUB: {
|
|
if (!cursorVisibleRef.current) {
|
|
setMainExpanded(true);
|
|
}
|
|
}
|
|
case EXTRA_AREA: {
|
|
if (cursorVisibleRef.current) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
setTabFocused((prevState) => {
|
|
const prev = [...prevState];
|
|
prev[type] = true;
|
|
return prev;
|
|
});
|
|
},
|
|
[deActivateTab]
|
|
);
|
|
|
|
const onTabBlur = useCallback(
|
|
(type) => (event) => {
|
|
switch (type) {
|
|
case COLLABSED_MAIN: {
|
|
if (cursorVisibleRef.current) {
|
|
mouseNavOpen.current.stop();
|
|
}
|
|
break;
|
|
}
|
|
case ACTIVATED_MAIN: {
|
|
if (!cursorVisibleRef.current) {
|
|
setMainExpanded(false);
|
|
}
|
|
break;
|
|
}
|
|
case ACTIVATED_SUB: {
|
|
if (!cursorVisibleRef.current) {
|
|
}
|
|
break;
|
|
}
|
|
case EXTRA_AREA: {
|
|
if (cursorVisibleRef.current) {
|
|
deActivateTabJob.stop();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
setTabFocused((prevState) => {
|
|
const prev = [...prevState];
|
|
prev[type] = true;
|
|
return prev;
|
|
});
|
|
},
|
|
[]
|
|
);
|
|
|
|
const onFocus = useCallback(() => {
|
|
if (showSubTab) {
|
|
setSecondDepthReduce((prev) => !prev);
|
|
}
|
|
}, [showSubTab]);
|
|
|
|
const spotToPanelJob = useRef(
|
|
new Job(() => {
|
|
const node = document.querySelector(`[id="${SpotlightIds.TPANEL}"]`);
|
|
|
|
if (node) {
|
|
Spotlight.focus(node);
|
|
}
|
|
})
|
|
);
|
|
|
|
const spotToPanel = useCallback((delayed = false) => {
|
|
const node = document.querySelector(`[id="${SpotlightIds.TPANEL}"]`);
|
|
|
|
if (node) {
|
|
if (delayed) {
|
|
spotToPanelJob.current.start(() => {
|
|
Spotlight.focus(node);
|
|
});
|
|
} else {
|
|
Spotlight.focus(node);
|
|
}
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
spotToPanelJob.current.stop();
|
|
};
|
|
}, []);
|
|
|
|
const handleNavigation = useCallback(
|
|
({ index, target }) => {
|
|
setMainSelectedIndex(index);
|
|
mouseMainEntered.current = false;
|
|
mouseNavOpen.current.stop();
|
|
|
|
// second depth가 있을 경우 클릭 시 expanded
|
|
if (!target) {
|
|
setMainExpanded(true);
|
|
}
|
|
|
|
//같은패널로 클릭이벤트가 호출될때
|
|
if (
|
|
Array.isArray(target) &&
|
|
target[0]?.name &&
|
|
panels[0]?.name &&
|
|
panels[0]?.name === target[0]?.name
|
|
) {
|
|
deActivateTab();
|
|
spotToPanel();
|
|
return;
|
|
}
|
|
|
|
// 홈패널일 경우
|
|
if (target && target[0]?.name === panel_names.HOME_PANEL) {
|
|
deActivateTab();
|
|
spotToPanel(true);
|
|
dispatch(resetPanels());
|
|
dispatch(checkEnterThroughGNB(true));
|
|
dispatch(resetHomeInfo());
|
|
return;
|
|
}
|
|
|
|
//그 외 나머지
|
|
if (target) {
|
|
deActivateTab();
|
|
dispatch(resetPanels(target));
|
|
panelSwitching.current = true;
|
|
panelSwitchingJob.start(panelSwitching);
|
|
spotToPanel();
|
|
}
|
|
|
|
dispatch(resetHomeInfo());
|
|
},
|
|
[deActivateTab, dispatch, panels]
|
|
);
|
|
|
|
const onClickSubItem = useCallback(
|
|
({ target, itemId }) => {
|
|
if (selectedSubItemId === itemId) {
|
|
deActivateTab();
|
|
spotToPanel();
|
|
return;
|
|
}
|
|
|
|
if (target) {
|
|
dispatch(resetPanels(target));
|
|
deActivateTab();
|
|
panelSwitching.current = true;
|
|
panelSwitchingJob.start(panelSwitching);
|
|
spotToPanel();
|
|
}
|
|
|
|
dispatch(resetHomeInfo());
|
|
},
|
|
[dispatch, deActivateTab, selectedSubItemId]
|
|
);
|
|
const onClickExtraArea = useCallback(
|
|
({ index, target }) => {
|
|
deActivateTabJob.startAfter(100, deActivateTab);
|
|
},
|
|
[deActivateTab]
|
|
);
|
|
|
|
const tabActivated = useMemo(() => {
|
|
return mainExpanded || mainSelectedIndex >= 0;
|
|
}, [mainExpanded, mainSelectedIndex]);
|
|
|
|
const logoImg = useMemo(() => {
|
|
if (deviceCountryCode === "RU") {
|
|
return shoptimeFullIconRuc;
|
|
} else return shoptimeFullIcon;
|
|
}, [deviceCountryCode]);
|
|
|
|
const showTab = useMemo(() => {
|
|
if (!topPanelName || PANELS_HAS_TAB.indexOf(topPanelName) >= 0) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}, [topPanelName]);
|
|
|
|
const showSubTab = useMemo(() => {
|
|
if (
|
|
tabActivated &&
|
|
tabs[mainSelectedIndex] &&
|
|
tabs[mainSelectedIndex].hasChildren()
|
|
) {
|
|
return true; // 서브 탭이 있는 경우
|
|
}
|
|
return false; // 서브 탭이 없는 경우
|
|
}, [tabActivated, mainSelectedIndex, tabs]);
|
|
|
|
const backKeyHandler = useCallback(
|
|
(ev) => {
|
|
if (tabActivated) {
|
|
Spotlight.focus(SpotlightIds.HOME_TBODY);
|
|
const node = document.querySelector(`[id="${SpotlightIds.TBODY}"]`);
|
|
if (node) {
|
|
Spotlight.focus(node);
|
|
}
|
|
deActivateTab();
|
|
ev?.stopPropagation();
|
|
return true;
|
|
}
|
|
},
|
|
[tabActivated, deActivateTab]
|
|
);
|
|
|
|
// 메인탭 라스트 포커스
|
|
useEffect(() => {
|
|
if (tabActivated) {
|
|
dispatch(gnbOpened(true));
|
|
|
|
if (panels.length === 0) {
|
|
Spotlight.focus("spotlight_home");
|
|
return;
|
|
}
|
|
|
|
if (lastFocusId) {
|
|
Spotlight.focus(lastFocusId);
|
|
}
|
|
//
|
|
else {
|
|
if (!subTabLastFocusId) {
|
|
Spotlight.focus("spotlight_home");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (onTabActivated) {
|
|
onTabActivated(tabActivated && showTab);
|
|
}
|
|
}, [dispatch, showTab, tabActivated]);
|
|
|
|
//서브탭 라스트 포커스 & 서브탭 초기화
|
|
useEffect(() => {
|
|
if (!panelInfo) {
|
|
setMainSelectedIndex(-1);
|
|
setLastFocusId("spotlight_home");
|
|
setSubTabLastFocusId(null);
|
|
return;
|
|
}
|
|
|
|
let subTarget;
|
|
|
|
// if panelInfo is not that of PlayerPanel
|
|
if (!panelInfo?.shptmBanrTpNm) {
|
|
// case: Category 2depth
|
|
if (
|
|
topPanelName === panel_names.CATEGORY_PANEL && //
|
|
panelInfo?.lgCatCd
|
|
) {
|
|
subTarget = panelInfo.lgCatCd;
|
|
}
|
|
// case: Featured Brands 2depth
|
|
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
|
|
) {
|
|
subTarget = panelInfo.menuId;
|
|
}
|
|
}
|
|
|
|
if (subTarget) {
|
|
setSelectedSubItemId(subTarget);
|
|
setSubTabLastFocusId(`secondDepth-${subTarget}`);
|
|
}
|
|
}, [panelInfo, topPanelName]);
|
|
|
|
// esc키로 Home으로 이동시 SubItemId 초기화
|
|
useEffect(() => {
|
|
if (topPanelName === null && selectedSubItemId) {
|
|
setSelectedSubItemId(null);
|
|
}
|
|
}, [panels, selectedSubItemId]);
|
|
|
|
useEffect(() => {
|
|
if (tabActivated && showSubTab && subTabLastFocusId !== null) {
|
|
Spotlight.focus(subTabLastFocusId);
|
|
}
|
|
}, [tabActivated, subTabLastFocusId, mainSelectedIndex]);
|
|
|
|
useEffect(() => {
|
|
const hasFeaturedBrands =
|
|
tabs[mainSelectedIndex]?.children[0]?.path !== undefined;
|
|
|
|
const SCROLL_OFFSET_INDEX = hasFeaturedBrands ? 8 : 9;
|
|
|
|
const y = hasFeaturedBrands ? 110 : 100;
|
|
|
|
if (selectedSubIndex >= 0) {
|
|
if (selectedSubIndex === 0) {
|
|
scrollTopJobRef.current.start(() => scrollTop({ y: 0 }));
|
|
return () => scrollTopJobRef.current.stop();
|
|
}
|
|
}
|
|
|
|
if (
|
|
selectedSubIndex > SCROLL_OFFSET_INDEX &&
|
|
tabs[mainSelectedIndex]?.children.length - 1 >= selectedSubIndex
|
|
) {
|
|
const targetScrollIndex = selectedSubIndex - SCROLL_OFFSET_INDEX;
|
|
scrollTopJobRef.current.start(() =>
|
|
scrollTop({ y: y * targetScrollIndex })
|
|
);
|
|
|
|
return () => scrollTopJobRef.current.stop();
|
|
}
|
|
}, [selectedSubIndex]);
|
|
|
|
// 1Depth > 2Depth로 넘어갈때 서브메뉴가 없을때만 ( 의존성배열 )
|
|
useEffect(() => {
|
|
if (tabActivated && lastFocusId && !showSubTab) {
|
|
Spotlight.focus(lastFocusId);
|
|
}
|
|
}, [panels, lastFocusId]);
|
|
|
|
useEffect(() => {
|
|
setSecondDepthReduce(false);
|
|
|
|
if (showSubTab) {
|
|
tabs[mainSelectedIndex]?.children.forEach((item) => {
|
|
if (item.path) {
|
|
setSecondDepthReduce(true);
|
|
}
|
|
});
|
|
}
|
|
}, [secondDepthReduce, showSubTab, mainSelectedIndex]);
|
|
|
|
//[SHOPTIME-2052] 사방향키로 GNB 이동 후 매직마우스로 변경시 이동되면서 포커싱 되었던 메뉴가 selected됨
|
|
useEffect(() => {
|
|
if (cursorVisible && !showSubTab) {
|
|
setMainSelectedIndex(-1);
|
|
}
|
|
}, [cursorVisible]);
|
|
|
|
useEffect(() => {
|
|
if (broadcast?.type === "deActivateTab") {
|
|
console.log("TabLayout deactivateTab by broadcast");
|
|
deActivateTab();
|
|
}
|
|
}, [broadcast]);
|
|
|
|
const onMainMouseEnter = useCallback(
|
|
(ev) => {
|
|
mouseMainEntered.current = true;
|
|
onTabHasFocus(COLLABSED_MAIN)(ev);
|
|
},
|
|
[onTabHasFocus]
|
|
);
|
|
|
|
const onMainMouseLeave = useCallback(
|
|
(ev) => {
|
|
mouseMainEntered.current = false;
|
|
onTabBlur(COLLABSED_MAIN)(ev);
|
|
},
|
|
[onTabBlur]
|
|
);
|
|
|
|
const onMainMouseMove = useCallback(
|
|
(ev) => {
|
|
if (!mouseMainEntered.current) {
|
|
onMainMouseEnter(ev);
|
|
}
|
|
},
|
|
[onMainMouseEnter]
|
|
);
|
|
|
|
const moveFocusToMainTab = useCallback(
|
|
(e) => {
|
|
if (e.key === "ArrowLeft" && showSubTab && lastFocusId) {
|
|
Spotlight.focus(lastFocusId);
|
|
}
|
|
},
|
|
[showSubTab, lastFocusId]
|
|
);
|
|
|
|
if (!showTab) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className={classNames(css.tabLayoutWrap, !tabActivated && css.hide)}
|
|
id={SpotlightIds.TAB_LAYOUT}
|
|
>
|
|
{data && (
|
|
<>
|
|
{
|
|
<CancelableDiv
|
|
spotlightRestrict="self-only"
|
|
spotlightId="activatedMain"
|
|
className={classNames(css.expandedRootContainer)}
|
|
handleCancel={backKeyHandler}
|
|
id="tabLayout"
|
|
>
|
|
{/* expanded Main */}
|
|
<MainContainer
|
|
className={classNames(
|
|
css.mainTabContainer,
|
|
css.tabWrap,
|
|
mainExpanded && css.expanded
|
|
)}
|
|
onFocus={onTabHasFocus(ACTIVATED_MAIN)}
|
|
onBlur={onTabBlur(ACTIVATED_MAIN)}
|
|
onMouseMove={onMainMouseMove}
|
|
onMouseEnter={onMainMouseEnter}
|
|
onMouseLeave={onMainMouseLeave}
|
|
>
|
|
<h1 className={css.logo}>
|
|
<img
|
|
src={logoImg}
|
|
alt=""
|
|
className={classNames(
|
|
deviceCountryCode === "RU" && css.rucLogo
|
|
)}
|
|
/>
|
|
</h1>
|
|
|
|
{tabs.map((item, index) => (
|
|
<TabItem
|
|
{...item}
|
|
key={"tabitemExpanded" + index}
|
|
onFocus={onFocus}
|
|
spotlightId={item.spotlightId}
|
|
setLastFocusId={setLastFocusId}
|
|
onClick={handleNavigation}
|
|
deActivateTab={deActivateTab}
|
|
showSubTab={showSubTab}
|
|
icons={item.icons}
|
|
expanded={mainExpanded}
|
|
mainSelected={
|
|
(panels.length === 0 &&
|
|
item.spotlightId === "spotlight_home") ||
|
|
(panels[0]?.name === panel_names.PLAYER_PANEL &&
|
|
panels.length === 1 &&
|
|
item.spotlightId === "spotlight_home") ||
|
|
(Array.isArray(item.target) &&
|
|
item.target[0]?.name &&
|
|
panels[0]?.name === item.target[0]?.name)
|
|
}
|
|
selected={
|
|
Array.isArray(item.children[0]?.target) &&
|
|
item.children[0]?.target[0]?.name &&
|
|
panels[0]?.name === item.children[0]?.target?.[0].name
|
|
}
|
|
subTabTarget={item.children[index]?.target}
|
|
setSelectedTitle={setSelectedTitle}
|
|
title={item.title}
|
|
index={index}
|
|
opened={mainSelectedIndex === index}
|
|
tabActivated={tabActivated}
|
|
setSubTabLastFocusId={setSubTabLastFocusId}
|
|
length={tabs.length}
|
|
/>
|
|
))}
|
|
</MainContainer>
|
|
{/* Sub */}
|
|
{
|
|
<Container
|
|
spotlightId="activatedSub"
|
|
className={classNames(
|
|
css.tabWrap,
|
|
css.secondDepthLayout,
|
|
secondDepthReduce && css.secondDepthReduce,
|
|
!showSubTab && css.hide
|
|
)}
|
|
onFocus={onTabHasFocus(ACTIVATED_SUB)}
|
|
onMouseOver={onTabHasFocus(ACTIVATED_SUB)}
|
|
onBlur={onTabBlur(ACTIVATED_SUB)}
|
|
onMouseLeave={onTabBlur(ACTIVATED_SUB)}
|
|
onKeyDown={moveFocusToMainTab}
|
|
>
|
|
<TScroller
|
|
cbScrollTo={getScrollTo}
|
|
className={css.scrollWrap}
|
|
>
|
|
{showSubTab &&
|
|
tabs[mainSelectedIndex]?.children.map((item, index) => {
|
|
return (
|
|
<TabItemSub
|
|
{...item}
|
|
mainMenuTitle={
|
|
tabs && tabs[mainSelectedIndex]?.title
|
|
}
|
|
key={"tabitemSubmenu" + index}
|
|
spotlightId={item.spotlightId}
|
|
setLastFocusId={setSubTabLastFocusId}
|
|
onClick={onClickSubItem}
|
|
expanded={mainExpanded}
|
|
index={index}
|
|
isSubItem={true}
|
|
deActivateTab={deActivateTab}
|
|
title={item.title + "-sub"}
|
|
itemId={item.id}
|
|
path={item.path}
|
|
patncNm={item.patncNm}
|
|
showSubTab={showSubTab}
|
|
setSelectedTitle={setSelectedTitle}
|
|
setSelectedSubItemId={setSelectedSubItemId}
|
|
setSelectedSubIndex={setSelectedSubIndex}
|
|
selected={
|
|
Array.isArray(item.target) &&
|
|
item.target[0]?.panelInfo &&
|
|
panels[0]?.panelInfo === item.target[0]?.panelInfo
|
|
}
|
|
label={
|
|
index * 1 +
|
|
1 +
|
|
" of " +
|
|
tabs[mainSelectedIndex]?.children.length
|
|
}
|
|
/>
|
|
);
|
|
})}
|
|
</TScroller>
|
|
</Container>
|
|
}
|
|
{/* Extra Area*/}
|
|
{tabActivated && (
|
|
<Container
|
|
className={classNames(css.tabWrap, css.extraArea)}
|
|
onClick={onClickExtraArea}
|
|
onFocus={onTabHasFocus(EXTRA_AREA)}
|
|
onMouseOver={onTabHasFocus(EXTRA_AREA)}
|
|
onBlur={onTabBlur(EXTRA_AREA)}
|
|
onMouseLeave={onTabBlur(EXTRA_AREA)}
|
|
/>
|
|
)}
|
|
</CancelableDiv>
|
|
}
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|