[HomePanel]SubCategory 상품 부분 VirtualGridList 적용

- SubCategoryItem생성.
This commit is contained in:
junghoon86.park
2024-02-05 13:19:39 +09:00
parent a8ebe10027
commit d212c318fc
3 changed files with 183 additions and 15 deletions

View File

@@ -1,15 +1,19 @@
import React, { useEffect, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import VirtualGridList from "@enact/sandstone/VirtualList";
import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator";
import Spottable from "@enact/spotlight/Spottable";
import ri from "@enact/ui/resolution";
import { getSubCategory } from "../../../actions/mainActions";
import { getOnSaleInfo } from "../../../actions/onSaleActions";
import TGrid from "../../../components/TGrid/TGrid";
import TItemCard from "../../../components/TItemCard/TItemCard";
import css from "../../HomePanel/SubCategory/SubCategory.module.less";
import CategoryNav from "../../OnSalePanel/CategoryNav/CategoryNav";
import SubCategoryItem from "../SubCategoryItem/SubCategoryItem";
const Container = SpotlightContainerDecorator(
{
@@ -25,7 +29,7 @@ const SubCategory = () => {
const categoryInfos = useSelector(
(state) => state.onSale.onSaleData.categoryInfos
);
const subCategoryData = useSelector(
const categoryItemInfos = useSelector(
(state) => state.main.subCategoryData.categoryItemInfos
);
const [currentLgCatCd, setCurrentLgCatCd] = useState();
@@ -58,28 +62,46 @@ const SubCategory = () => {
);
}
}, [currentLgCatCd]);
const renderItem = useCallback(
({ index, ...rest }) => {
const itemData = categoryItemInfos[index];
return (
<SubCategoryItem
subCategoryData={categoryItemInfos}
currentLgCatCd={currentLgCatCd}
itemNum={itemData}
key={itemData.rankOrd}
{...rest}
/>
);
},
[categoryItemInfos]
);
return (
<Container>
<CategoryNav
categoryInfos={categoryInfos}
currentCategoryCode={currentLgCatCd}
currentLgCatCd={currentLgCatCd}
onCategoryNavClick={handleCategoryNav}
type="home"
/>
<TGrid type="home">
{subCategoryData &&
subCategoryData.slice(0, 9).map((item) => {
return (
<TItemCard
key={item.rankOrd}
imageSource={item.imgUrl}
imageAlt={item.prdtNm}
productName={item.prdtNm}
priceInfo={item.priceInfo}
/>
);
})}
{categoryItemInfos && categoryItemInfos.length > 0 && (
<VirtualGridList
className={css.virtualGridList}
dataSize={categoryItemInfos.length}
direction="horizontal"
horizontalScrollbar="hidden"
itemRenderer={renderItem}
itemSize={{
minWidth: ri.scale(324 * 2),
minHeight: ri.scale(438 * 2),
}}
noScrollByWheel
scrollMode="translate"
/>
)}
</TGrid>
</Container>
);

View File

@@ -0,0 +1,60 @@
import React, { useCallback } from "react";
import classNames from "classnames";
import Spottable from "@enact/spotlight/Spottable";
import css from "./SubCategoryItem.module.less";
const SpottableComponent = Spottable("li");
export default function SubCategoryItem({
subCategoryData,
itemNum,
currentLgCatCd,
...rest
}) {
const parsePriceInfo = useCallback(
(priceInfo) => {
const priceParts = itemNum.priceInfo
.split("|")
.filter((part) => part !== "N")
.map((item) => item.trim());
let originalPrice, discountedPrice, discountRate;
if (priceParts.length === 4) {
[originalPrice, discountedPrice, , discountRate] = priceParts;
} else if (priceParts.length === 2) {
[originalPrice, discountedPrice] = priceParts;
discountRate = null;
} else {
originalPrice = null;
discountedPrice = null;
discountRate = null;
}
return { originalPrice, discountedPrice, discountRate };
},
[itemNum.priceInfo]
);
const { originalPrice, discountedPrice, discountRate } = parsePriceInfo(
itemNum.priceInfo
);
return (
<SpottableComponent {...rest} className={css.vertical}>
<div>
<img src={itemNum.imgUrl} alt={itemNum.prdtNm} />
{discountRate && <span>{discountRate}</span>}
</div>
<div>
<h3>{itemNum.prdtNm}</h3>
<p>
{discountRate ? discountedPrice : originalPrice}
{discountRate && <span>{originalPrice}</span>}
</p>
</div>
</SpottableComponent>
);
}

View File

@@ -0,0 +1,86 @@
@import "../../../style/CommonStyle.module.less";
@import "../../../style/utils.module.less";
.vertical {
/* normal */
position: relative;
display: flex;
flex-direction: column;
gap: 12px;
.size(@w: 324px, @h: 438px);
padding: 18px;
border-radius: 12px;
border: solid 1px @COLOR_GRAY02;
background-color: @COLOR_WHITE;
// top contents (image contetns)
> div:nth-child(1) {
position: relative;
.size(@w: 288px, @h: 288px);
color: @COLOR_WHITE;
img {
.size(@w: 288px, @h: 288px);
object-fit: contain;
border: solid 1px #f0f0f0;
}
// discount rate
span {
.position(@position: absolute, @right: 12px, @bottom: 12px);
.size(@w: 60px, @h: 60px);
border-radius: 60px;
background-color: @PRIMARY_COLOR_RED;
.font(@fontFamily: "ArialBold", @fontSize:26px);
text-align: center;
line-height: 60px;
}
// sold out
> div:nth-child(3) {
.position(@position: absolute, @top: 0, @right: 0);
.flex();
.size(@w: 288px, @h: 288px);
background-color: rgba(26, 26, 26, 0.6);
.font(@fontFamily: @baseFontBold, @fontSize: 36px);
}
}
// bottom contents
> div:nth-child(2) {
.flex(@direction: column, @alignCenter: flex-start);
gap: 6px;
flex-grow: 1;
h3 {
.font(@fontFamily: @baseFontBold, @fontSize: 24px);
color: @COLOR_GRAY06;
.elip(@clamp:2);
word-break: break-all;
overflow: hidden;
}
p {
.flex(@justifyCenter: flex-start);
gap: 5px;
.font(@fontFamily: @baseFontBold, @fontSize: 30px);
color: @PRIMARY_COLOR_RED;
letter-spacing: -1px;
span {
.font(@fontFamily: @baseFont, @fontSize: 18px);
color: @COLOR_GRAY04;
text-decoration: line-through;
}
}
}
/* focused */
&:focus-within {
border: solid 1px @PRIMARY_COLOR_RED;
box-shadow: inset 0 0 0 4px @PRIMARY_COLOR_RED,
0 0 50px 0 rgba(0, 0, 0, 0.5);
// best seller
div:nth-child(3) {
background-color: @PRIMARY_COLOR_RED;
}
}
}