[mainPanel] subCategory 적용 및 디자인 변경

- Homepanel 쪽으로 파일 위치변경
- subCategory TGrid,TItemCard적용.
- mainSlice 부분 정보 수정
This commit is contained in:
junghoon86.park
2024-01-29 20:25:23 +09:00
parent d690537b3e
commit 7c44840abe
17 changed files with 305 additions and 262 deletions

View File

@@ -1,132 +0,0 @@
import React, { useEffect, useState } from "react";
import { $L } from "../../../utils/helperMethods";
import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight";
import Spottable from "@enact/spotlight/Spottable";
import css from "./SubCategory.module.less";
import testimg from "../../../../assets/icon/nor/ic-category-home-nor@3x.png";
import testimg2 from "../../../../assets/icon/nor/ic-category-gift-nor@3x.png";
import { getSubCategory } from "../../../features/main/mainSlice";
const SubCategory = () => {
const [clickData, setClickData] = useState(null);
const [currentSubCateIndex, setCurrentSubCateIndex] = useState(0);
const handleSubCategory = (index) => {
setCurrentSubCateIndex(index);
if (currentSubCateIndex == index) {
return;
}
};
useEffect(() => {}, []);
return (
<div className={css.container}>
<div className={css.cateList}>
{/* cateBox */}
<ul className={css.cateListBox}>
<li className={css.cateListItem}>
<div className={css.cateImg}>
<img src={testimg} className={css.cateImgDesign} />
</div>
<div className={css.cateName}>Kitchen & food</div>
</li>
<li className={css.cateListItem}>
<div className={css.cateImg}>
<img src={testimg2} className={css.cateImgDesign} />
</div>
<div className={css.cateName}>Kitchen & food</div>
</li>
<li className={css.cateListItem}>
<div className={css.cateImg}>
<img src={testimg} className={css.cateImgDesign} />
</div>
<div className={css.cateName}>Kitchen & food</div>
</li>
<li className={css.cateListItem}>
<div className={css.cateImg}>
<img src={testimg2} className={css.cateImgDesign} />
</div>
<div className={css.cateName}>Kitchen & food</div>
</li>
<li className={css.cateListItem}>
<div className={css.cateImg}>
<img src={testimg} className={css.cateImgDesign} />
</div>
<div className={css.cateName}>Kitchen & food</div>
</li>
<li className={css.cateListItem}>
<div className={css.cateImg}>
<img src={testimg2} className={css.cateImgDesign} />
</div>
<div className={css.cateName}>Kitchen & food</div>
</li>
</ul>
{/* //cateBox */}
{/* productBox */}
<ul className={css.productBox}>
<li className={css.productItem}>
<div className={css.productImg}>
<img src={testimg2} />
</div>
<div className={css.productNm}>
Productl Nameytg Product Name Producthlyg Name Producthlyg
</div>
<div className={css.accBox}>
<div className={css.productAcc}>
"$120.99"
<span className={css.productOriginalAcc}>"$999.99"</span>
</div>
</div>
</li>
<li className={css.productItem}>
<div className={css.productImg}>
<img src={testimg2} />
</div>
<div className={css.productNm}>
Productl Nameytg Product Name Producthlyg Name Producthlyg
</div>
<div className={css.accBox}>
<div className={css.productAcc}>
"$120.99"
<span className={css.productOriginalAcc}>"$999.99"</span>
</div>
</div>
</li>
<li className={css.productItem}>
<div className={css.productImg}>
<img src={testimg2} />
</div>
<div className={css.productNm}>
Productl Nameytg Product Name Producthlyg Name Producthlyg
</div>
<div className={css.accBox}>
<div className={css.productAcc}>
"$120.99"
<span className={css.productOriginalAcc}>"$999.99"</span>
</div>
</div>
</li>
<li className={css.productItem}>
<div className={css.productImg}>
<img src={testimg2} />
</div>
<div className={css.productNm}>
Productl Nameytg Product Name Producthlyg Name Producthlyg
</div>
<div className={css.accBox}>
<div className={css.productAcc}>
"$120.99"
<span className={css.productOriginalAcc}>"$999.99"</span>
</div>
</div>
</li>
</ul>
{/* //productBox */}
</div>
</div>
);
};
export default SubCategory;

View File

@@ -1,97 +0,0 @@
@import "../../../style/CommonStyle.module.less";
.cateListBox {
display: flex;
.cateListItem {
width: 210px;
height: 186px;
margin-right: 30px;
&.activeCate {
border-bottom: 6px solid @PRIMARY_COLOR_RED;
}
&:hover,
&:active,
&:focus,
&:focus-within {
.cateImg {
background-color: @PRIMARY_COLOR_RED;
}
}
&:last-child {
margin-right: 0;
}
.cateImg {
width: 96px;
height: 96px;
border-radius: 48px;
background-color: @COLOR_GRAY08;
padding: 8px;
margin: 0 57px 18px 57px;
.cateImgDesign {
width: 80px;
height: 80px;
object-fit: contain;
}
}
.cateName {
}
}
}
.productBox {
padding: 20px;
background: #f2f2f2;
display: flex;
.productItem {
margin: 20px;
width: 324px;
height: 438px;
background-color: #fff;
padding: 18px;
.productImg {
position: relative;
> img {
width: 288px;
height: 288px;
object-fit: contain;
}
}
.productNm {
margin-top: 14px;
font-size: 24px;
font-weight: bold;
color: #333;
height: 60px;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-height: 1.33;
letter-spacing: normal;
}
&:first-child {
margin-left: 60px;
}
.accBox {
display: flex;
width: 288px;
height: 36px;
margin-top: 9px;
.productAcc {
font-size: 30px;
font-weight: bold;
line-height: 0.93;
letter-spacing: normal;
color: @PRIMARY_COLOR_RED;
}
.productOriginalAcc {
font-size: 18px;
font-weight: normal;
font-stretch: normal;
font-style: normal;
letter-spacing: normal;
color: #767676;
margin: 10px 0 10px 5px;
}
}
}
}

View File

@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import classNames from "classnames";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import css from "./TGrid.module.less"; import css from "./TGrid.module.less";
@@ -12,8 +12,10 @@ const GridContainer = SpotlightContainerDecorator(
"ul" "ul"
); );
export default function TGrid({ children }) { export default function TGrid({ children, type }) {
return ( return (
<GridContainer className={css.gridContainer}>{children}</GridContainer> <GridContainer className={classNames(css.gridContainer, type && css[type])}>
{children}
</GridContainer>
); );
} }

View File

@@ -5,4 +5,13 @@
width: 100%; width: 100%;
.flex(@alignCenter:flex-start); .flex(@alignCenter:flex-start);
gap: 15px; gap: 15px;
&.home {
margin-top: 20px;
width: calc(100% - 60px);
margin-left: 60px;
justify-content: unset;
align-items: unset;
flex-direction: unset;
}
} }

View File

@@ -27,6 +27,7 @@ export default memo(function ProductCard({
rank, rank,
soldoutFlag, soldoutFlag,
type = TYPE_VERTICAL, type = TYPE_VERTICAL,
accType = false,
...rest ...rest
}) { }) {
const handleClick = useCallback( const handleClick = useCallback(
@@ -44,8 +45,9 @@ export default memo(function ProductCard({
.map((item) => item.trim()); .map((item) => item.trim());
let originalPrice, discountedPrice, discountRate; let originalPrice, discountedPrice, discountRate;
if (priceParts.length === 5) {
if (priceParts.length === 4) { [originalPrice, discountedPrice, , discountRate] = priceParts;
} else if (priceParts.length === 4) {
[originalPrice, discountedPrice, , discountRate] = priceParts; [originalPrice, discountedPrice, , discountRate] = priceParts;
} else if (priceParts.length === 2) { } else if (priceParts.length === 2) {
[originalPrice, discountedPrice] = priceParts; [originalPrice, discountedPrice] = priceParts;
@@ -82,7 +84,9 @@ export default memo(function ProductCard({
<h3>{productName}</h3> <h3>{productName}</h3>
<p> <p>
{discountRate ? discountedPrice : originalPrice} {discountRate ? discountedPrice : originalPrice}
{discountRate && <span>{discountRate}</span>} {discountRate && (
<span>{accType ? originalPrice : discountRate}</span>
)}
</p> </p>
</div> </div>
{isBestSeller && rank && ( {isBestSeller && rank && (

View File

@@ -35,7 +35,7 @@ export const getSubCategory = createAsyncThunk(
} }
); );
//메인화면 Live Show 정보 조회 //메인화면 Live Show 정보 조회 IF-LGSP-069
export const getTop20Show = createAsyncThunk( export const getTop20Show = createAsyncThunk(
"main/getTop20Show", "main/getTop20Show",
@@ -44,7 +44,7 @@ export const getTop20Show = createAsyncThunk(
console.log("getTop20Show onSuccess ", response.data); console.log("getTop20Show onSuccess ", response.data);
thunkAPI.dispatch( thunkAPI.dispatch(
mainSlice.actions.updateSubCategoryData(response.data.data) mainSlice.actions.updateTop20ShowData(response.data.data)
); );
}; };
const onFail = (error) => { const onFail = (error) => {
@@ -66,6 +66,7 @@ export const getTop20Show = createAsyncThunk(
const initialState = { const initialState = {
subCategoryData: {}, subCategoryData: {},
top20ShowData: {},
}; };
export const mainSlice = createSlice({ export const mainSlice = createSlice({
@@ -75,7 +76,7 @@ export const mainSlice = createSlice({
updateSubCategoryData: (state, action) => { updateSubCategoryData: (state, action) => {
state.subCategoryData = action.payload; state.subCategoryData = action.payload;
}, },
updateTop20Show: (state, action) => { updateTop20ShowData: (state, action) => {
state.top20ShowData = action.payload; state.top20ShowData = action.payload;
}, },
}, },

View File

@@ -14,7 +14,7 @@ import Spotlight from "@enact/spotlight";
import Marquee from "@enact/sandstone/Marquee"; import Marquee from "@enact/sandstone/Marquee";
import Spottable from "@enact/spotlight/Spottable"; import Spottable from "@enact/spotlight/Spottable";
import CustomImage from "../../CustomImage/CustomImage"; import CustomImage from "../../../components/CustomImage/CustomImage";
import ViedoPlayer from "@enact/sandstone/VideoPlayer"; import ViedoPlayer from "@enact/sandstone/VideoPlayer";
import css from "./Template.module.less"; import css from "./Template.module.less";
import { getAdDetailAMD, getHomeTerms } from "../../../api/homeApi"; import { getAdDetailAMD, getHomeTerms } from "../../../api/homeApi";

View File

@@ -5,9 +5,10 @@ import { $L } from "../../utils/helperMethods";
import css from "../HomePanel/HomePanel.module.less"; import css from "../HomePanel/HomePanel.module.less";
import Template from "../../components/Home/HomeBanner/Template"; import Template from "./HomeBanner/Template";
import OnSale from "../../components/Home/OnSale/OnSale"; import OnSale from "./OnSale/OnSale";
import SubCategory from "../../components/Home/SubCategory/SubCategory"; import SubCategory from "./SubCategory/SubCategory";
import PopularShow from "./PopularShow/PopularShow";
export default function HomePanel() { export default function HomePanel() {
return ( return (
@@ -15,6 +16,7 @@ export default function HomePanel() {
<Template /> <Template />
<SubCategory /> <SubCategory />
<OnSale /> <OnSale />
<PopularShow />
</TPanel> </TPanel>
); );
} }

View File

@@ -5,6 +5,7 @@ import React, {
useMemo, useMemo,
useRef, useRef,
} from "react"; } from "react";
import { useDispatch, useSelector } from "react-redux";
import classNames from "classnames"; import classNames from "classnames";
import { $L } from "../../../utils/helperMethods"; import { $L } from "../../../utils/helperMethods";
import { Job } from "@enact/core/util"; import { Job } from "@enact/core/util";
@@ -32,22 +33,13 @@ const OnSale = ({
onScrollShelf, onScrollShelf,
...rest ...rest
}) => { }) => {
const [currentSaleData, setCurrentSaleData] = useState([]); const dispatch = useDispatch();
const [originalPrice, setOriginalPrice] = useState(null); const HomeSaleInfos = useSelector(
(state) => state.onSale.onSaleData.homeOnSaleInfos
const setSaleView = async (categoryIncFlag, lgCatCd) => { );
try {
const saleData = await getOnSaleInfo({ lgCatCd, categoryIncFlag });
if (saleData) {
setCurrentSaleData(saleData.homeOnSaleInfos);
}
} catch (error) {
console.error("Error saleData: ", error);
}
};
useEffect(() => { useEffect(() => {
setSaleView("Y", ""); dispatch(getOnSaleInfo({ categoryIncFlag: "Y", lgCatCd: "" }));
}, []); }, []);
return ( return (
@@ -55,8 +47,8 @@ const OnSale = ({
<div className={css.bestSeller}> <div className={css.bestSeller}>
<h2 className={css.subTitle}>{$L("ON SALE")}</h2> <h2 className={css.subTitle}>{$L("ON SALE")}</h2>
<ul className={css.onSaleItem}> <ul className={css.onSaleItem}>
{currentSaleData && {HomeSaleInfos &&
currentSaleData.map((item, index) => { HomeSaleInfos.map((item, index) => {
const priceInfo = item.priceInfo; const priceInfo = item.priceInfo;
let salePrice; let salePrice;
const originalPrice = priceInfo.split("|")[0]; const originalPrice = priceInfo.split("|")[0];

View File

@@ -1,3 +1,4 @@
@import "../../../style/CommonStyle.module.less";
.bestSeller { .bestSeller {
padding: 60px 0; padding: 60px 0;
width: 100%; width: 100%;
@@ -7,6 +8,9 @@
border-left: 6px solid #c70850; border-left: 6px solid #c70850;
padding-left: 12px; padding-left: 12px;
box-sizing: border-box; box-sizing: border-box;
color: #1a1a1a;
font-weight: bold;
font-family: "LGSmartUIBold";
} }
.onSaleItem { .onSaleItem {
margin-top: 20px; margin-top: 20px;
@@ -28,7 +32,7 @@
&:active { &:active {
border: 4px solid #c70850; border: 4px solid #c70850;
box-sizing: border-box; box-sizing: border-box;
drop-shadow: 0 0 50px 0.5 #000; .focusDropShadow();
} }
.onSaleItemListImg { .onSaleItemListImg {
width: 300px; width: 300px;

View File

@@ -0,0 +1,53 @@
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { $L } from "../../../utils/helperMethods";
import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight";
import Spottable from "@enact/spotlight/Spottable";
import { getTop20Show } from "../../../features/main/mainSlice";
import css from "../PopularShow/PopularShow.module.less";
const SpottableComponent = Spottable("div");
const PopularShow = (...rest) => {
const dispatch = useDispatch();
const TopInfos = useSelector((state) => state.main.top20ShowData.topInfos);
useEffect(() => {
dispatch(getTop20Show());
}, []);
return (
<div {...rest} className={css.container}>
<div className={css.popularShow}>
<h2 className={css.subTitle}>{$L("POPULAR SHOW")}</h2>
<ul className={css.showList}>
<li className={css.listItem}>
<img src="https://picsum.photos/510/288" className={css.itemImg} />
<div className={css.horizonItem}>
Product Name Product Name Product Name Product Name Product Name
Product Name Product Name Product Name
</div>
</li>
{/* 세로형
<li className={css.listItemVertical}>
<img src="https://picsum.photos/228/402" className={css.itemImg} />
<div className={css.verticalItem}>
Product Name Product Name Product Name Product Name Product Name
Product Name Product Name Product Name Product Name Product Name
Product Name Product Name Product Name Product Name Product Name
Product Name Product Name Product Name Product Name Product Name
Product Name Product Name Product Name Product Name Product Name
Product Name Product Name Product Name Product Name Product Name
Product Name Product Name
</div>
</li>
*/}
</ul>
</div>
</div>
);
};
export default PopularShow;

View File

@@ -0,0 +1,76 @@
@import "../../../style/CommonStyle.module.less";
.popularShow {
padding: 60px 0;
width: 100%;
overflow-x: auto;
margin-left: 60px;
.subTitle {
border-left: 6px solid @PRIMARY_COLOR_RED;
padding-left: 12px;
box-sizing: border-box;
color: #1a1a1a;
font-weight: bold;
font-family: "LGSmartUIBold";
}
.showList {
margin-top: 20px;
display: flex;
overflow: hidden;
> li:nth-child(1n) {
margin-right: 18px;
border: 4px solid transparent;
box-sizing: border-box;
&:focus,
&:hover,
&:focus-within,
&:active {
border: 4px solid @PRIMARY_COLOR_RED;
box-sizing: border-box;
.focusDropShadow();
}
}
.listItem {
width: 546px;
height: 438px;
padding: 18px;
background-color: @COLOR_WHITE;
border-radius: 12px;
border: solid 1px @COLOR_GRAY02;
box-sizing: border-box;
.horizonItem {
width: 510px;
height: 60px;
margin-top: 38px;
color: #333;
font-size: 24px;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
}
.listItemVertical {
display: flex;
width: 546px;
height: 438px;
padding: 18px;
background-color: @COLOR_WHITE;
border-radius: 12px;
border: solid 1px @COLOR_GRAY02;
box-sizing: border-box;
.verticalItem {
margin-left: 11px;
color: #333;
font-size: 24px;
width: 270px;
height: 402px;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 12;
}
}
}
}

View File

@@ -0,0 +1,115 @@
import React, { useEffect, useState } from "react";
import { $L } from "../../../utils/helperMethods";
import { Job } from "@enact/core/util";
import Spotlight from "@enact/spotlight";
import Spottable from "@enact/spotlight/Spottable";
import { useDispatch, useSelector } from "react-redux";
import css from "./SubCategory.module.less";
import Scroller from "@enact/sandstone/Scroller";
import { getOnSaleInfo } from "../../../features/onSale/onSaleSlice";
import testimg from "../../../../assets/icon/nor/ic-category-home-nor@3x.png";
import testimg2 from "../../../../assets/icon/nor/ic-category-gift-nor@3x.png";
import CategoryNav from "../../OnSalePanel/CategoryNav/CategoryNav";
import OnSaleProductCard from "../../OnSalePanel/OnSaleProductCard/OnSaleProductCard";
import OnSaleProductsGrid from "../../OnSalePanel/OnSaleProductsGrid/OnSaleProductsGrid";
import TGrid from "../../../components/TGrid/TGrid";
import TItemCard from "../../../components/TItemCard/TItemCard";
import { getSubCategory } from "../../../features/main/mainSlice";
import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator";
const Container = SpotlightContainerDecorator(
{
enterTo: "default-element",
},
"div"
);
const SubCategory = () => {
const dispatch = useDispatch();
const categoryInfos = useSelector(
(state) => state.onSale.onSaleData.categoryInfos
);
const subCategoryData = useSelector(
(state) => state.main.subCategoryData.categoryItemInfos
);
const testchk = useSelector((state) => state);
const [currentLgCatCd, setCurrentLgCatCd] = useState();
const handleCategoryNav = (lgCatCd) => {
if (currentLgCatCd === lgCatCd) {
return;
}
setCurrentLgCatCd(lgCatCd);
};
useEffect(() => {
console.log(testchk);
if (categoryInfos && !currentLgCatCd) {
const initialLgCatCd = categoryInfos[0].lgCatCd;
setCurrentLgCatCd(initialLgCatCd);
}
getSubCategory({
lgCatCd: currentLgCatCd,
patnrIdList: null,
pageSize: null,
tabType: "CAT00102",
filterType: "CAT00202",
});
}, []);
useEffect(() => {
if (currentLgCatCd) {
dispatch(
getOnSaleInfo({ categoryIncFlag: "Y", lgCatCd: currentLgCatCd })
);
dispatch(
getSubCategory({
lgCatCd: currentLgCatCd,
patnrIdList: null,
pageSize: null,
tabType: "CAT00102",
filterType: "CAT00202",
})
);
}
}, [currentLgCatCd]);
return (
<Container>
<CategoryNav
categoryInfos={categoryInfos}
currentLgCatCd={currentLgCatCd}
onCategoryNavClick={handleCategoryNav}
type="home"
/>
<Scroller
direction="horizontal"
horizontalScrollbar="hidden"
noScrollByWheel={true}
scrollMode="translate"
className={css.homeScroll}
>
<TGrid type="home">
{subCategoryData &&
subCategoryData.slice(0, 9).map((item) => {
return (
<TItemCard
key={item.expsOrd}
imageSource={item.imgUrl}
imageAlt={item.prdtNm}
productName={item.prdtNm}
priceInfo={item.priceInfo}
accType={true}
/>
);
})}
</TGrid>
</Scroller>
</Container>
);
};
export default SubCategory;

View File

@@ -0,0 +1 @@
@import "../../../style/CommonStyle.module.less";

View File

@@ -15,14 +15,21 @@ const Container = SpotlightContainerDecorator(
const SpottableComponent = Spottable("li"); const SpottableComponent = Spottable("li");
const TYPES = { home: "home" };
export default function CategoryNav({ export default function CategoryNav({
categoryInfos, categoryInfos,
currentLgCatCd, currentLgCatCd,
onCategoryNavClick, onCategoryNavClick,
type = "",
...rest ...rest
}) { }) {
return ( return (
<Container {...rest} className={css.container}> <Container
{...rest}
className={classNames(css.container, css[type] ? css[type] : null)}
type=""
>
<Scroller <Scroller
direction="horizontal" direction="horizontal"
horizontalScrollbar="hidden" horizontalScrollbar="hidden"
@@ -34,7 +41,10 @@ export default function CategoryNav({
categoryInfos.map(({ lgCatNm, lgCatCd }) => { categoryInfos.map(({ lgCatNm, lgCatCd }) => {
return ( return (
<SpottableComponent <SpottableComponent
className={classNames(css.category, lgCatCd === currentLgCatCd && css.selected)} className={classNames(
css.category,
lgCatCd === currentLgCatCd && css.selected
)}
key={lgCatCd} key={lgCatCd}
onClick={() => onCategoryNavClick(lgCatCd)} onClick={() => onCategoryNavClick(lgCatCd)}
> >

View File

@@ -14,7 +14,10 @@
font-size: 28px; font-size: 28px;
// @@ font 관련 업데이트 후 수정 // @@ font 관련 업데이트 후 수정
// .font(@fontFamily: @baseFontBold, @fontSize: 28px); // .font(@fontFamily: @baseFontBold, @fontSize: 28px);
&.home {
position: unset;
width: 100%;
}
ul { ul {
display: flex; display: flex;
gap: 30px; gap: 30px;