Files
shoptime/com.twin.app.shoptime/src/components/TabLayout/TabLayout.jsx

545 lines
14 KiB
JavaScript

import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";
import { panel_names } from "../../utils/Config";
import TabItem from "./TabItem";
import css from "./TabLayout.module.less";
//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 { Job } from "@enact/core/util";
//이미지
import shoptimeFullIcon from "../../../assets/icons/ic-lnb-logo-shoptime@3x.png";
import shopTimeIcon from "../../../assets/icons/ic-lnb-shoptime-symbol@3x.png";
import CartIcon from "./iconComponents/CartIcon";
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 { resetPanels } from "../../features/panels/panelsSlice";
const Container = SpotlightContainerDecorator(
{ enterTo: "default-element" },
"div"
);
const MainContainer = SpotlightContainerDecorator(
{ enterTo: "last-focused", continue5WayHold: true },
"div"
);
const CancelableDiv = Cancelable(
{ modal: true, onCancel: "handleCancel" },
Skinnable(Container)
);
class TabMenuItem {
constructor(icons = "", title = "", target, children = []) {
this.icons = icons;
this.title = title;
this.target = target;
this.children = []; //TabMenuItem
if (children && children.length > 0) {
for (let i = 0; i < children.length; i++) {
const tabmenu = new TabMenuItem(
children[i].icons,
children[i].title,
children[i].target,
children[i].children
);
this.children.push(tabmenu);
}
}
}
hasChildren = () => {
return this.children.length > 0;
};
getChildren = () => {
return this.children;
};
}
const deActivateTabJabFunc = (func) => {
func();
};
let deActivateTabJob = new Job(deActivateTabJabFunc, 2000);
const COLLABSED_MAIN = 0;
const ACTIVATED_MAIN = 1;
const ACTIVATED_SUB = 2;
const EXTRA_AREA = 3;
const MAIN_TITLE = 0;
const SUB_TITLE = 1;
const PANELS_HAS_TAB = [
panel_names.CART_PANEL,
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 }) {
const dispatch = useDispatch();
const [mainExpanded, setMainExpanded] = useState(false);
const [mainSelectedIndex, setMainSelectedIndex] = useState(-1);
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);
const data = useSelector((state) => state.home.menuData?.data);
const menuItems = useMemo(
() => [
{
icons: CategoryIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.CATEGORY_PANEL }],
},
],
},
{
icons: MyPageIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.MY_PAGE_PANEL }],
},
],
},
{
icons: SearchIcon,
title: "",
children: [
{
title: "12323232",
target: [{ name: panel_names.SEARCH_PANEL }],
},
],
},
{
icons: HomeIcon,
title: "",
children: [
{
title: "43534543",
target: [{ name: panel_names.HOME_PANEL }],
},
],
},
{
icons: FeaturedBrandIcon,
title: "",
children: [
{
title: "dsadasd",
target: [{ name: panel_names.FEATURED_BRANDS_PANEL }],
},
],
},
{
icons: OnSaleIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.ON_SALE_PANEL }],
},
],
},
{
icons: TrendingNowIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.TRENDING_NOW_PANEL }],
},
],
},
{
icons: HotPicksIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.HOT_PICKS_PANEL }],
},
],
},
{
icons: CartIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.CART_PANEL }],
},
],
},
//메뉴 추가 필요 20240112 chw
],
[data]
);
const getMenuData = (type) => {
let result = [];
switch (type) {
case "gnb":
data?.gnb.map((item) => {
result.push(item.menuNm);
});
console.log("#result", result);
return result;
case "homeCategory":
return "123123";
case "msgInfos":
return result;
case "mypage":
return result;
case "shortCategory":
return result;
case "shortFeaturedBrands":
return result;
}
};
const dataDivide = () => {
if (data) {
// console.log("data", data);
// Object.keys(data).map((key) => {
// title = getMenuData(key);
// return title;
// });
const title = getMenuData("gnb");
// const subTitle = getMenuData(menu);
for (let i = 0; i < menuItems.length; i++) {
menuItems[i].title = title[i];
menuItems[i].children.title = title[i];
}
}
console.log("#menuItems", menuItems);
return menuItems;
};
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].target,
menuItems[i].children
);
t.push(tabmenu);
}
return t;
}, [data]);
useEffect(() => {
dataDivide();
setTabs(makeTabmenu());
}, [data]);
const deActivateTab = useCallback(() => {
setTabFocused([false, false, false, false]);
setMainSelectedIndex(-1);
setMainExpanded(false);
}, []);
const onTabHasFocus = useCallback(
(type) => (event) => {
switch (type) {
case COLLABSED_MAIN:
case ACTIVATED_MAIN: {
if (!cursorVisible) {
const parent = event.target.parentNode;
const children = parent.childNodes;
const index = Array.prototype.indexOf.call(children, event.target);
setMainExpanded(true);
setMainSelectedIndex(index);
} else {
if (!panelSwitching.current) {
setMainExpanded(true);
}
}
break;
}
case ACTIVATED_SUB: {
setMainExpanded(false);
break;
}
case EXTRA_AREA: {
if (cursorVisible) {
deActivateTabJob.start(deActivateTab);
return;
}
}
}
setTabFocused((prevState) => {
const prev = [...prevState];
prev[type] = true;
return prev;
});
},
[cursorVisible, deActivateTab]
);
const onTabBlur = useCallback(
(type) => (event) => {
switch (type) {
case ACTIVATED_MAIN: {
if (!cursorVisible) {
setMainExpanded(false);
}
break;
}
case ACTIVATED_SUB: {
if (!cursorVisible) {
}
break;
}
case EXTRA_AREA: {
if (cursorVisible) {
deActivateTabJob.stop();
return;
}
}
}
setTabFocused((prevState) => {
const prev = [...prevState];
prev[type] = true;
return prev;
});
},
[cursorVisible]
);
const handleNavigation = useCallback(
({ index, target }) => {
setMainSelectedIndex(index);
if (target) {
dispatch(resetPanels(target));
deActivateTab();
// panelSwitching.current = true;
// panelSwitchingJob.start(panelSwitching);
} else if (cursorVisible) {
setMainExpanded(true);
}
},
[deActivateTab, dispatch]
);
const onClickSubItem = useCallback(
({ index, target }) => {
if (target) {
dispatch(resetPanels(target));
deActivateTab();
panelSwitching.current = true;
// panelSwitchingJob.start(panelSwitching);
}
},
[dispatch, deActivateTab]
);
const onClickExtraArea = useCallback(
({ index, target }) => {
deActivateTabJob.startAfter(100, deActivateTab);
},
[dispatch, deActivateTab]
);
const tabActivated = useMemo(() => {
return mainExpanded || mainSelectedIndex >= 0;
}, [mainExpanded, mainSelectedIndex]);
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, tabs, mainSelectedIndex]);
const backKeyHandler = useCallback(
(ev) => {
if (tabActivated) {
deActivateTab();
ev.stopPropagation();
ev.preventDefault();
return true;
}
},
[tabActivated, deActivateTab]
);
useEffect(() => {
if (tabActivated) {
setTimeout(() => {
Spotlight.focus("activatedMain");
}, 0);
}
if (onTabActivated) {
onTabActivated(tabActivated && showTab);
}
}, [tabActivated, showTab]);
useEffect(() => {}, [showSubTab, mainSelectedIndex]);
if (!showTab) {
return null;
}
return (
<div className={classNames(css.tabLayoutWrap, !tabActivated && css.hide)}>
{/* collabsed Main */}
<Container
className={css.tabWrap}
onFocus={onTabHasFocus(COLLABSED_MAIN)}
onMouseOver={onTabHasFocus(COLLABSED_MAIN)}
onBlur={onTabBlur(COLLABSED_MAIN)}
onMouseLeave={onTabBlur(COLLABSED_MAIN)}
>
<img className={css.logo} src={shopTimeIcon} alt="" />
{tabs.map((item, index) => (
<TabItem
key={"tabitem" + index}
expanded={false}
selected={mainSelectedIndex === index}
index={index}
onClick={handleNavigation}
icons={item.icons}
/>
))}
</Container>
{
<CancelableDiv
spotlightRestrict="self-only"
spotlightId="activatedMain"
className={classNames(
css.expandedRootContainer,
!tabActivated && css.hide
)}
handleCancel={backKeyHandler}
>
{/* expanded Main */}
<MainContainer
className={classNames(css.tabWrap, mainExpanded && css.expanded)}
onFocus={onTabHasFocus(ACTIVATED_MAIN)}
onMouseOver={onTabHasFocus(COLLABSED_MAIN)}
onBlur={onTabBlur(ACTIVATED_MAIN)}
onMouseLeave={onTabBlur(ACTIVATED_MAIN)}
>
<h1 className={classNames(css.logo, mainExpanded && css.expanded)}>
<img
src={mainExpanded ? shoptimeFullIcon : shopTimeIcon}
alt=""
/>
</h1>
{tabActivated &&
tabs.map((item, index) => (
<TabItem
key={"tabitemExpanded" + index}
onClick={handleNavigation}
deActivateTab={deActivateTab}
icons={item.icons}
expanded={mainExpanded}
selected={mainSelectedIndex === index}
title={item.title}
index={index}
/>
))}
</MainContainer>
{/* Sub */}
{
<Container
spotlightId="activatedSub"
className={classNames(
css.tabWrap,
css.secondDepthLayout,
!showSubTab && css.hide
)}
onFocus={onTabHasFocus(ACTIVATED_SUB)}
onMouseOver={onTabHasFocus(ACTIVATED_SUB)}
onBlur={onTabBlur(ACTIVATED_SUB)}
onMouseLeave={onTabBlur(ACTIVATED_SUB)}
>
{showSubTab &&
tabs[mainSelectedIndex].children.map((item, index) => {
return (
<TabItem
key={"tabitemSubmenu" + index}
onClick={onClickSubItem}
expanded={true}
index={index}
isSubItem={true}
mainExpanded={mainExpanded}
deActivateTab={deActivateTab}
title={item.title}
/>
);
})}
</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>
);
}