[CategoryPanel] 카테고리 패널 작업 진행 중 / TODO: ITEM 탭 구현 및 데이터 백그라운드 페칭
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
import React from "react";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
|
||||
import ItemContents from "./ItemContents/ItemContents";
|
||||
import ShowContents from "./ShowContents/ShowContents";
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ leaveFor: { left: "", right: "" }, enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
export default function CategoryContents({ activeTab }) {
|
||||
const datas = useSelector((state) => state.main.subCategoryData);
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{activeTab === "SHOW" ? <ShowContents /> : <ItemContents />}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from "react";
|
||||
|
||||
export default function ItemContents() {
|
||||
return <p>ITEM</p>;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from "react";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import Spottable from "@enact/spotlight/Spottable";
|
||||
|
||||
import css from "./ShowContents.module.less";
|
||||
import ShowLists from "./ShowLists/ShowLists";
|
||||
import ShowProductContents from "./ShowProductContents/ShowProductContents";
|
||||
|
||||
const SpottableVideoContainer = Spottable("div");
|
||||
|
||||
export default function ShowContents() {
|
||||
const showContentDatas = useSelector((state) => state.main.subCategoryData);
|
||||
const { categoryShowInfos, partnerInfos, topShowInfo } =
|
||||
showContentDatas || {};
|
||||
|
||||
console.log("showContentDatas", showContentDatas);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showContentDatas &&
|
||||
topShowInfo &&
|
||||
categoryShowInfos &&
|
||||
categoryShowInfos.length > 0 && (
|
||||
<>
|
||||
<h1 className={css.topsTitle}>{topShowInfo.showNm}</h1>
|
||||
<div className={css.topShowContainer}>
|
||||
<SpottableVideoContainer className={css.videoContainer}>
|
||||
<img src={topShowInfo.thumbnailUrl} alt={topShowInfo.showNm} />
|
||||
</SpottableVideoContainer>
|
||||
<ShowProductContents />
|
||||
</div>
|
||||
<div>
|
||||
<ShowLists />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
@import "../../../../style/CommonStyle.module.less";
|
||||
@import "../../../../style/utils.module.less";
|
||||
|
||||
.topsTitle {
|
||||
margin: 70px 0 26px;
|
||||
color: @COLOR_GRAY08;
|
||||
.font(@fontFamily: @baseFontBold, @fontSize: 36px);
|
||||
}
|
||||
|
||||
.topShowContainer {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
.videoContainer {
|
||||
.size(@w: 754px, @h: 438px);
|
||||
border: 1px solid @COLOR_GRAY02;
|
||||
background-color: #fff;
|
||||
padding: 11px 18px;
|
||||
border-radius: 12px;
|
||||
box-sizing: border-box;
|
||||
|
||||
> img {
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:focus-within {
|
||||
outline: 4px solid @PRIMARY_COLOR_RED;
|
||||
outline-offset: -3px;
|
||||
box-shadow: inset 0 0 0 4px @PRIMARY_COLOR_RED,
|
||||
0 0 50px 0 rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { VirtualGridList } from "@enact/sandstone/VirtualList";
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
import Spottable from "@enact/spotlight/Spottable";
|
||||
|
||||
import { scaleH, scaleW } from "../../../../../utils/helperMethods";
|
||||
import css from "./ShowLists.module.less";
|
||||
import ShowListsItem from "./ShowListsItem";
|
||||
|
||||
const LIST_ITEM_CONF = {
|
||||
ITEM_WIDTH: 546,
|
||||
ITEM_HEIGHT: 438,
|
||||
SPACING: 18,
|
||||
};
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
export default function ShowLists() {
|
||||
const showListDatas = useSelector(
|
||||
(state) => state.main.subCategoryData?.categoryShowInfos
|
||||
);
|
||||
|
||||
const renderItem = useCallback(
|
||||
({ index, ...rest }) => {
|
||||
const ItemInfo = showListDatas[index];
|
||||
const {
|
||||
catNm,
|
||||
dfltThumbnailImgPath,
|
||||
hstNm,
|
||||
lgCatCd,
|
||||
pathnLogoPath,
|
||||
patnrId,
|
||||
showId,
|
||||
showNm,
|
||||
thumbnailUrl,
|
||||
total,
|
||||
vtctpYn,
|
||||
} = ItemInfo;
|
||||
|
||||
return (
|
||||
<ShowListsItem
|
||||
key={showId}
|
||||
thumbnail={thumbnailUrl}
|
||||
title={showNm}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[showListDatas]
|
||||
);
|
||||
|
||||
console.log("showListDatas", showListDatas);
|
||||
|
||||
return (
|
||||
<Container className={css.container}>
|
||||
{showListDatas && showListDatas.length > 0 && (
|
||||
<VirtualGridList
|
||||
className={css.grid}
|
||||
dataSize={showListDatas.length}
|
||||
direction="vertical"
|
||||
verticalScrollbar="hidden"
|
||||
itemRenderer={renderItem}
|
||||
itemSize={{
|
||||
minWidth: scaleW(LIST_ITEM_CONF.ITEM_WIDTH),
|
||||
minHeight: scaleH(LIST_ITEM_CONF.ITEM_HEIGHT),
|
||||
}}
|
||||
noScrollByWheel
|
||||
scrollMode="translate"
|
||||
spacing={scaleW(LIST_ITEM_CONF.SPACING)}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
@import "../../../../../style/CommonStyle.module.less";
|
||||
@import "../../../../../style/utils.module.less";
|
||||
|
||||
.container {
|
||||
.size(@w: 100%, @h: auto);
|
||||
margin-top: 60px;
|
||||
|
||||
.grid {
|
||||
overflow: unset;
|
||||
|
||||
> div {
|
||||
overflow: unset !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
|
||||
import Spottable from "@enact/spotlight/Spottable";
|
||||
|
||||
import css from "./ShowListsItem.module.less";
|
||||
|
||||
const ShowListsItemContainer = Spottable("div");
|
||||
|
||||
export default function ShowListsItem({ thumbnail, title }) {
|
||||
return (
|
||||
<ShowListsItemContainer className={css.container}>
|
||||
<div className={css.imgWrap}>
|
||||
<img src={thumbnail} alt={title} />
|
||||
</div>
|
||||
<div className={css.titleWrap}>
|
||||
<p className={css.title}>{title}</p>
|
||||
</div>
|
||||
</ShowListsItemContainer>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
@import "../../../../../style/CommonStyle.module.less";
|
||||
@import "../../../../../style/utils.module.less";
|
||||
|
||||
.container {
|
||||
.size(@w: 100%, @h: 100%);
|
||||
border-radius: 12px;
|
||||
border: 1px solid @COLOR_GRAY02;
|
||||
background-color: @COLOR_WHITE;
|
||||
padding: 18px;
|
||||
|
||||
.imgWrap {
|
||||
.size(@w: 100%, @h: 288px);
|
||||
|
||||
> img {
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.titleWrap {
|
||||
.size(@w: 100%, @h: calc(100% - 288px));
|
||||
display: flex;
|
||||
padding-top: 18px;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
.font(@fontFamily: @baseFontBold, @fontSize: 24px);
|
||||
color: @COLOR_GRAY06;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
&::after {
|
||||
.focused(@boxShadow: 50px, @borderRadius:12px);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import React, { useCallback } from "react";
|
||||
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { VirtualGridList } from "@enact/sandstone/VirtualList";
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
|
||||
import TItemCard from "../../../../../components/TItemCard/TItemCard";
|
||||
import { scaleH, scaleW } from "../../../../../utils/helperMethods";
|
||||
import css from "./ShowProductContents.module.less";
|
||||
|
||||
const LIST_ITEM_CONF = {
|
||||
ITEM_WIDTH: 324,
|
||||
ITEM_HEIGHT: 438,
|
||||
SPACING: 18,
|
||||
};
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
export default function ShowProductContents() {
|
||||
const showProductContentDatas = useSelector(
|
||||
(state) => state.main.subCategoryData?.topShowInfo
|
||||
);
|
||||
const { productInfos } = showProductContentDatas || {};
|
||||
|
||||
const renderItem = useCallback(
|
||||
({ index, ...rest }) => {
|
||||
const productInfo = productInfos[index];
|
||||
const { imgUrl, prdtId, prdtNm, priceInfo } = productInfo;
|
||||
|
||||
return (
|
||||
<TItemCard
|
||||
{...rest}
|
||||
key={prdtId}
|
||||
imageAlt={prdtId}
|
||||
imageSource={imgUrl}
|
||||
priceInfo={priceInfo}
|
||||
productName={prdtNm}
|
||||
/>
|
||||
);
|
||||
},
|
||||
[productInfos]
|
||||
);
|
||||
|
||||
return (
|
||||
<Container className={css.container}>
|
||||
{productInfos && productInfos.length > 0 && (
|
||||
<VirtualGridList
|
||||
classname={css.grid}
|
||||
dataSize={productInfos.length}
|
||||
direction="horizontal"
|
||||
horizontalScrollbar="hidden"
|
||||
itemRenderer={renderItem}
|
||||
itemSize={{
|
||||
minWidth: scaleW(LIST_ITEM_CONF.ITEM_WIDTH),
|
||||
minHeight: scaleH(LIST_ITEM_CONF.ITEM_HEIGHT),
|
||||
}}
|
||||
noScrollByWheel
|
||||
scrollMode="translate"
|
||||
spacing={scaleW(LIST_ITEM_CONF.SPACING)}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
@import "../../../../../style/CommonStyle.module.less";
|
||||
@import "../../../../../style/utils.module.less";
|
||||
|
||||
.container {
|
||||
.flex();
|
||||
width: calc(100% - 790px);
|
||||
margin: 0 18px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.grid {
|
||||
height: 438px;
|
||||
overflow: unset;
|
||||
|
||||
> div {
|
||||
overflow: unset !important;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,150 @@
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import Spotlight from "@enact/spotlight";
|
||||
|
||||
import { getSubCategory } from "../../actions/mainActions";
|
||||
import SectionTitle from "../../components/SectionTitle/SectionTitle";
|
||||
import TBody from "../../components/TBody/TBody";
|
||||
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 { $L } from "../../utils/helperMethods";
|
||||
import ItemContents from "./CategoryContents/ItemContents/ItemContents";
|
||||
import ShowContents from "./CategoryContents/ShowContents/ShowContents";
|
||||
import css from "./CategoryPanel.module.less";
|
||||
|
||||
const getButtonTabList = () => {
|
||||
return [$L("SHOW"), $L("ITEM")];
|
||||
};
|
||||
|
||||
let buttonTabList = null;
|
||||
|
||||
export default function CategoryPanel() {
|
||||
return <TPanel>Category</TPanel>;
|
||||
if (!buttonTabList) {
|
||||
buttonTabList = getButtonTabList();
|
||||
}
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const categoryDatas = useSelector((state) => state.main.subCategoryData);
|
||||
const panelInfos = useSelector((state) => state.panels.panels?.[0]);
|
||||
|
||||
const { lgCatCd, lgCatNm, COUNT } = panelInfos.panelInfo || {};
|
||||
const {
|
||||
bannerInfos,
|
||||
categoryDescInfos,
|
||||
categoryFilterCd,
|
||||
categoryItemInfos,
|
||||
categoryShowInfos,
|
||||
categoryTabTypeCd,
|
||||
partnerInfos,
|
||||
topShowInfo,
|
||||
} = categoryDatas || {};
|
||||
|
||||
const [tab, setTab] = useState(0);
|
||||
const [dropDownTab, setDropDownTab] = useState(0);
|
||||
const [filterMethods, setFilterMethods] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
setTab(0);
|
||||
setDropDownTab(0);
|
||||
|
||||
if (panelInfos?.panelInfo) {
|
||||
dispatch(getSubCategory({ lgCatCd, filterType: "CAT00202" }));
|
||||
}
|
||||
}, [panelInfos, lgCatCd, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (categoryDatas) {
|
||||
const detailCdNmValues = categoryFilterCd
|
||||
.map((item) => item.detailCdNm)
|
||||
.reverse();
|
||||
|
||||
setFilterMethods(detailCdNmValues);
|
||||
}
|
||||
}, [categoryDatas, tab]);
|
||||
|
||||
useEffect(() => {
|
||||
const tabType = tab === 0 ? "CAT00101" : "CAT00102";
|
||||
|
||||
dispatch(getSubCategory({ lgCatCd, tabType }));
|
||||
}, [tab, dispatch]);
|
||||
|
||||
const handleItemClick = useCallback(
|
||||
({ index }) => {
|
||||
if (index === tab) return;
|
||||
|
||||
setTab(index);
|
||||
},
|
||||
[tab]
|
||||
);
|
||||
|
||||
const handleSelectFilter = useCallback(({ selected }) => {
|
||||
setDropDownTab(selected);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const filterType = dropDownTab === 0 ? "CAT00202" : "CAT00201";
|
||||
|
||||
dispatch(getSubCategory({ lgCatCd, filterType }));
|
||||
}, [dropDownTab, dispatch]);
|
||||
|
||||
console.log(
|
||||
"panelInfos",
|
||||
panelInfos.panelInfo,
|
||||
"categoryDatas",
|
||||
categoryDatas
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
Spotlight.focus(`tab-${tab}`);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<TPanel>
|
||||
<THeader title="Category" />
|
||||
<TBody className={css.tBody}>
|
||||
<div className={css.paddingContainer}>
|
||||
{panelInfos && panelInfos.panelInfo && categoryDatas && (
|
||||
<SectionTitle
|
||||
title={lgCatNm}
|
||||
className={css.title}
|
||||
itemCount={
|
||||
categoryItemInfos
|
||||
? categoryItemInfos.length > 0
|
||||
? categoryItemInfos[0].total
|
||||
: "0"
|
||||
: categoryShowInfos.length > 0
|
||||
? categoryShowInfos[0].total
|
||||
: "0"
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{buttonTabList && buttonTabList.length > 0 && (
|
||||
<div className={css.tabContainer}>
|
||||
<TButtonTab
|
||||
contents={buttonTabList}
|
||||
onItemClick={handleItemClick}
|
||||
selectedIndex={tab}
|
||||
listType={LIST_TYPE.medium}
|
||||
/>
|
||||
<TDropDown
|
||||
className={css.dropdown}
|
||||
onSelect={handleSelectFilter}
|
||||
selectedIndex={dropDownTab}
|
||||
width="small"
|
||||
>
|
||||
{filterMethods}
|
||||
</TDropDown>
|
||||
</div>
|
||||
)}
|
||||
{tab === 0 && <ShowContents />}
|
||||
{tab === 1 && <ItemContents />}
|
||||
</div>
|
||||
</TBody>
|
||||
</TPanel>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
@import "../../style/CommonStyle.module.less";
|
||||
@import "../../style/utils.module.less";
|
||||
|
||||
.tBody {
|
||||
width: 100%;
|
||||
height: calc(100% - 90px);
|
||||
background-color: @BG_COLOR_01;
|
||||
|
||||
.paddingContainer {
|
||||
padding-left: 60px;
|
||||
|
||||
.title {
|
||||
margin: 38px 0 33px 0;
|
||||
}
|
||||
|
||||
.tabContainer {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
position: relative;
|
||||
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user