TGrid, TItemCard 제작 / SearchPanel style 수정 필요

This commit is contained in:
hyunwoo93.cha
2024-01-29 13:52:44 +09:00
parent e39e8230d0
commit 395c49ef17
8 changed files with 221 additions and 21 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,19 @@
import React from "react";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import css from "./TGrid.module.less";
const GridContainer = SpotlightContainerDecorator(
{
leaveFor: { left: "", right: "" },
enterTo: "last-focused",
},
"ul"
);
export default function TGrid({ children }) {
return (
<GridContainer className={css.gridContainer}>{children}</GridContainer>
);
}

View File

@@ -0,0 +1,8 @@
@import "../../style/CommonStyle.module.less";
@import "../../style/utils.module.less";
.gridContainer {
width: 100%;
.flex(@alignCenter:flex-start);
gap: 15px;
}

View File

@@ -0,0 +1,61 @@
import React from "react";
import Spottable from "@enact/spotlight/Spottable";
import css from "./TItemCard.module.less";
const SpottableItemList = Spottable("li");
export default function TItemCard({
children,
imageSource,
imageAlt,
productName,
priceInfo,
...rest
}) {
const parsePriceInfo = (priceInfo) => {
const priceParts = 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 };
};
const { originalPrice, discountedPrice, discountRate } =
parsePriceInfo(priceInfo);
return (
<SpottableItemList {...rest} className={css.container}>
<div className={css.imageContainer}>
<img src={imageSource} alt={imageAlt} />
{discountRate && (
<div className={css.discountBanner}>{discountRate}</div>
)}
</div>
<div className={css.descContainer}>
<h1 className={css.productName}>{productName}</h1>
<p className={css.priceInfo}>
{discountedPrice}
{originalPrice !== discountedPrice && (
<span className={css.originalPrice}>{originalPrice}</span>
)}
</p>
</div>
</SpottableItemList>
);
}

View File

@@ -0,0 +1,72 @@
@import "../../style/CommonStyle.module.less";
@import "../../style/utils.module.less";
.container {
.size(@w: 324px, @h: 438px);
padding: 18px;
border-radius: 12px;
border: 1px solid @COLOR_GRAY02;
background-color: @COLOR_WHITE;
&:focus-within {
border: 4px solid @PRIMARY_COLOR_RED;
box-shadow: 0 0 50px 0 rgba(0, 0, 0, 0.5);
}
.imageContainer {
width: 288px;
height: 288px;
overflow: hidden;
position: relative;
img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.discountBanner {
position: absolute;
.flex();
width: 60px;
height: 60px;
bottom: 12px;
right: 12px;
background-color: @PRIMARY_COLOR_RED;
color: @COLOR_WHITE;
border-radius: 50%;
padding: 5px 10px;
font-size: 26px;
}
}
.descContainer {
.productName {
font-family: @baseFontBold;
font-size: 24px;
color: @COLOR_GRAY06;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
margin-top: 14px;
}
.priceInfo {
margin: 9px 0 12px 0;
font-size: 30px;
font-family: @baseFontBold;
color: @PRIMARY_COLOR_RED;
.originalPrice {
font-family: @baseFont;
margin-left: 5px;
text-decoration: line-through;
color: @COLOR_GRAY04;
font-size: 18px;
}
}
}
}

View File

@@ -17,6 +17,10 @@ import Spotlight from "@enact/spotlight";
import { changeAppStatus } from "../../features/common/commonSlice";
import { getSearch } from "../../features/search/searchSlice";
import SearchNoDataImage from "../../../assets/searchpanel/img-search-nodata.png";
import TGrid from "../../components/TGrid/TGrid";
import TItemCard from "../../components/TItemCard/TItemCard";
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
"div"
@@ -34,6 +38,9 @@ export default function SearchPanel() {
const searchDatas = useSelector(
(state) => state.search.searchDatas.data?.result.results
);
const bestSellerDatas = useSelector(
(state) => state.product.bestSellerData.bestSeller
);
const [currentPage, setCurrentPage] = useState(1);
const [paginatedKeywords, setPaginatedKeywords] = useState([]);
@@ -69,29 +76,43 @@ export default function SearchPanel() {
}
}, []);
const handleSearchSubmit = useCallback(async () => {
setSearchPerformed(true);
const performSearch = useCallback(
async (query) => {
if (!query || query.trim() === "") {
setSearchPerformed(false);
return;
}
if (searchQuery.trim() === "") {
setSearchPerformed(false);
return;
}
setSearchPerformed(true);
try {
await dispatch(
getSearch({
service: "com.lgshop.app",
query: searchQuery,
startIndex: 1,
maxResults: 10,
domain: "theme,show,item",
})
).unwrap();
} catch (error) {
console.error("Search request failed: ", error);
}
try {
await dispatch(
getSearch({
service: "com.lgshop.app",
query: query,
startIndex: 1,
maxResults: 10,
domain: "theme,show,item",
})
).unwrap();
} catch (error) {
console.error("Search request failed: ", error);
}
},
[dispatch]
);
const handleSearchSubmit = useCallback(() => {
performSearch(searchQuery);
}, [searchQuery, dispatch]);
const handleKeywordSearch = useCallback(
(keyword) => {
performSearch(keyword);
},
[performSearch]
);
const handleNext = useCallback(() => {
setCurrentPage((prev) => prev + 1);
setPageChanged(true);
@@ -111,7 +132,26 @@ export default function SearchPanel() {
if (searchDatas && searchDatas.length > 0) {
return <div>data!!</div>;
} else {
return <div>SORRY</div>;
return (
<Container>
<img src={SearchNoDataImage} alt="No Datas" />
<p>{$L("SORRY, NO RESULTS MATCHING YOUR SEARCH")}</p>
<TGrid>
{bestSellerDatas &&
bestSellerDatas
.slice(0, 5)
.map((bestSeller) => (
<TItemCard
key={bestSeller.rankOrd}
imageSource={bestSeller.imgUrl}
imageAlt={bestSeller.prdtNm}
productName={bestSeller.prdtNm}
priceInfo={bestSeller.priceInfo}
/>
))}
</TGrid>
</Container>
);
}
} else {
return (
@@ -129,6 +169,7 @@ export default function SearchPanel() {
key={index}
spotlightId={index === 0 ? "first-keyword-button" : undefined}
className={classNames(css.keywordBox)}
onClick={() => handleKeywordSearch(keyword.keywd)}
>
{keyword.keywd}
</TButton>
@@ -145,7 +186,6 @@ export default function SearchPanel() {
);
}
};
return (
<TPanel className={css.panel}>
<TInput