[SearchPanel] 리팩토링 및 컴포넌트화

This commit is contained in:
hyunwoo93.cha
2024-02-22 20:02:23 +09:00
parent 572a0e5dfa
commit 96d708cb1a
16 changed files with 217 additions and 246 deletions

View File

@@ -24,19 +24,7 @@ export default function SearchPanel() {
const recommandedKeywords = useSelector(
(state) => state.myPage.recommandedKeywordData.data?.keywords
);
const { searchDatas: searchDatas, totalCount: totalCount } = useSelector(
(state) => state.search
);
const {
theme: themeDatas,
show: showDatas,
item: itemDatas,
} = searchDatas || {};
const {
theme: themeCount,
show: showCount,
item: itemCount,
} = totalCount || {};
const { searchDatas: searchDatas } = useSelector((state) => state.search);
const searchPerformed = useSelector((state) => state.search.searchPerformed);
@@ -90,10 +78,6 @@ export default function SearchPanel() {
} else {
dispatch(resetSearch());
}
setContainerLastFocusedElement(null, ["searchResultsItemBox"]);
setContainerLastFocusedElement(null, ["searchResultsShowBox"]);
setContainerLastFocusedElement(null, ["searchResultsThemeBox"]);
},
[dispatch, searchQuery]
);
@@ -126,15 +110,7 @@ export default function SearchPanel() {
/>
{searchPerformed ? (
Object.keys(searchDatas).length > 0 ? (
<SearchResults
themeDatas={themeDatas}
itemDatas={itemDatas}
showDatas={showDatas}
themeCount={themeCount}
showCount={showCount}
itemCount={itemCount}
query={searchQuery}
/>
<SearchResults />
) : (
<NoSearchResults />
)

View File

@@ -1,5 +1,5 @@
@import "../../../../../style/CommonStyle.module.less";
@import "../../../../../style/utils.module.less";
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.card {
.size(@w: 561px, @h:150px);

View File

@@ -2,7 +2,7 @@ import React, { memo } from "react";
import Spottable from "@enact/spotlight/Spottable";
import IcLiveShow from "../../../../../../assets/images/tag/tag-liveshow.svg";
import IcLiveShow from "../../../../../assets/images/tag/tag-liveshow.svg";
import css from "./SearchShowCard.module.less";
const CardContainer = Spottable("div");

View File

@@ -1,5 +1,5 @@
@import "../../../../../style/CommonStyle.module.less";
@import "../../../../../style/utils.module.less";
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.card {
.size(@w: 344px, @h: 281px);

View File

@@ -1,9 +1,9 @@
@import "../../../../../style/CommonStyle.module.less";
@import "../../../../../style/utils.module.less";
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.card {
.size(@w: 560px, @h: 140px);
background-image: url("../../../../../../assets/images/searchpanel/bg_srch_curation.png");
background-image: url("../../../../../assets/images/searchpanel/bg_srch_curation.png");
border: 2px solid #ccc;
background-size: cover;
background-repeat: no-repeat;

View File

@@ -1,46 +0,0 @@
import React, { useEffect, useState } from "react";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import useScrollTo from "../../../../hooks/useScrollTo";
import { SEARCH_DATA_MAX_RESULTS_LIMIT } from "../../../../utils/Config";
import SearchItemCard from "./SearchItemCard/SearchItemCard";
import css from "./SearchItemResults.module.less";
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
export default function SearchItemResults({ itemDatas, itemCount, ...rest }) {
delete rest.query;
const { getScrollTo, scrollLeft } = useScrollTo();
useEffect(() => {
if (itemDatas.length <= SEARCH_DATA_MAX_RESULTS_LIMIT) {
scrollLeft();
}
}, [itemDatas]);
return (
<Container className={css.container}>
{itemDatas && (
<></>
// <TVirtualGridList
// spotlightId="searchResultsItemBox"
// cbScrollTo={getScrollTo}
// className={css.grid}
// items={itemDatas}
// dataSize={itemDatas.length}
// direction="horizontal"
// itemCard={SearchItemCard}
// itemWidth={561}
// itemHeight={150}
// spacing={30}
// />
)}
</Container>
);
}

View File

@@ -1,12 +0,0 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
.flex();
margin: 30px 0 50px;
width: 100%;
}
.grid {
height: 150px;
}

View File

@@ -1,52 +1,57 @@
import React from "react";
import { useSelector } from "react-redux";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
import { $L } from "../../../utils/helperMethods";
import SearchItemResults from "./SearchItemResults/SearchItemResults";
import css from "./SearchResults.module.less";
import SearchShowResults from "./SearchShowResults/SearchShowResults";
import SearchThemeResults from "./SearchThemeResults/SearchThemeResults";
import SearchResultsType from "./SearchResultsType";
const Container = SpotlightContainerDecorator(
{ enterTo: "last-focused" },
"div"
);
export default function SearchResults({
themeDatas,
itemDatas,
showDatas,
themeCount,
itemCount,
showCount,
query,
}) {
export default function SearchResults() {
const searchDatas = useSelector((state) => state.search.searchDatas) || {};
const totalCount = useSelector((state) => state.search.totalCount) || {};
const results = Object.entries(searchDatas).reduce((acc, [key, data]) => {
if (!data) return acc;
const titleMap = {
theme: $L("Hot Picks"),
show: $L("Shows"),
item: $L("Items"),
};
const item = {
title: titleMap[key],
category: key,
data,
};
if (key !== "theme") {
item.count = totalCount[key];
}
acc.push(item);
return acc;
}, []);
return (
<Container className={css.container}>
{themeDatas && (
<>
<SectionTitle title={$L("Hot Picks")} />
<SearchThemeResults themeDatas={themeDatas} themeCount={themeCount} />
</>
)}
{showDatas && (
<>
<SectionTitle title={$L("Shows")} itemCount={showCount} />
<SearchShowResults showDatas={showDatas} showCount={showCount} />
</>
)}
{itemDatas && (
<>
<SectionTitle title={$L("Items")} itemCount={itemCount} />
<SearchItemResults
itemDatas={itemDatas}
itemCount={itemCount}
query={query}
{results &&
results.map(({ title, category, data, count }, index) => (
<SearchResultsType
key={index}
title={title}
data={data}
count={count}
category={category}
/>
</>
)}
))}
</Container>
);
}

View File

@@ -0,0 +1,142 @@
import React, { useCallback, useEffect } from "react";
import classNames from "classnames";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
import TVirtualGridList from "../../../components/TVirtualGridList/TVirtualGridList";
import useScrollTo from "../../../hooks/useScrollTo";
import { SEARCH_DATA_MAX_RESULTS_LIMIT } from "../../../utils/Config";
import SearchItemCard from "./SearchCard/SearchItemCard";
import SearchShowCard from "./SearchCard/SearchShowCard";
import SearchThemeCard from "./SearchCard/SearchThemeCard";
import css from "./SearchResultsType.module.less";
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
const ITEM_SIZE = {
theme: {
itemWidth: 560,
itemHeight: 130,
spacing: 30,
},
show: {
itemWidth: 344,
itemHeight: 281,
spacing: 0,
},
item: {
itemWidth: 561,
itemHeight: 150,
spacing: 30,
},
};
export default function SearchResultsType({ title, data, count, category }) {
const { getScrollTo, scrollLeft } = useScrollTo();
useEffect(() => {
if (data.length <= SEARCH_DATA_MAX_RESULTS_LIMIT) {
scrollLeft();
}
}, [data]);
const renderItem = useCallback(
({ index, ...rest }) => {
switch (category) {
case "theme": {
const {
contentId,
endTime,
keyword,
partnerLogo,
partnerName,
startTime,
title,
} = data[index];
return <SearchThemeCard title={title} keyword={keyword} {...rest} />;
}
case "show": {
const {
contentId,
endTime,
liveFlag,
partnerId,
partnerLogo,
partnerName,
startTime,
thumbnail,
title,
} = data[index];
return (
<SearchShowCard
liveFlag={liveFlag}
thumbnail={thumbnail}
title={title}
{...rest}
/>
);
}
case "item": {
const {
contentId,
dcPrice,
partnerLogo,
partnerName,
price,
reviewGrade,
soldout,
thumbnail,
title,
} = data[index];
return (
<SearchItemCard
thumbnail={thumbnail}
title={title}
price={price}
dcPrice={dcPrice}
{...rest}
/>
);
}
default:
return;
}
},
[data, category]
);
const { itemWidth, itemHeight, spacing } = ITEM_SIZE[category] || {};
return (
<>
<SectionTitle title={title} itemCount={count ? count : null} />
<Container
className={classNames(css.container, category && css[category])}
>
<TVirtualGridList
cbScrollTo={getScrollTo}
className={css.grid}
dataSize={data.length}
renderItem={renderItem}
direction="horizontal"
itemWidth={itemWidth}
itemHeight={itemHeight}
spacing={spacing}
/>
</Container>
</>
);
}

View File

@@ -0,0 +1,26 @@
@import "../../../style/CommonStyle.module.less";
@import "../../../style/utils.module.less";
.container {
.flex();
margin: 30px 0 50px;
width: 100%;
&.theme {
.grid {
height: 141px;
}
}
&.show {
.grid {
height: 281px;
}
}
&.item {
.grid {
height: 150px;
}
}
}

View File

@@ -1,46 +0,0 @@
import React, { useEffect } from "react";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import useScrollTo from "../../../../hooks/useScrollTo";
import { SEARCH_DATA_MAX_RESULTS_LIMIT } from "../../../../utils/Config";
import SearchShowCard from "./SearchShowCard/SearchShowCard";
import css from "./SearchShowResults.module.less";
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
export default function SearchShowResults({ showDatas, showCount, ...rest }) {
delete rest.query;
const { getScrollTo, scrollLeft } = useScrollTo();
useEffect(() => {
if (showDatas.length <= SEARCH_DATA_MAX_RESULTS_LIMIT) {
scrollLeft();
}
}, [showDatas]);
return (
<Container className={css.container}>
{showDatas && (
<></>
// <TVirtualGridList
// spotlightId="searchResultsShowBox"
// className={css.grid}
// cbScrollTo={getScrollTo}
// items={showDatas}
// dataSize={showDatas.length}
// direction="horizontal"
// itemCard={SearchShowCard}
// itemWidth={344}
// itemHeight={281}
// spacing={0}
// />
)}
</Container>
);
}

View File

@@ -1,12 +0,0 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
.flex();
margin: 30px 0 50px;
width: 100%;
}
.grid {
height: 281px;
}

View File

@@ -1,50 +0,0 @@
import React, { useEffect } from "react";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import TVirtualGridList from "../../../../components/TVirtualGridList/TVirtualGridList";
import useScrollTo from "../../../../hooks/useScrollTo";
import { SEARCH_DATA_MAX_RESULTS_LIMIT } from "../../../../utils/Config";
import SearchThemeCard from "./SearchThemeCard/SearchThemeCard";
import css from "./SearchThemeResults.module.less";
const Container = SpotlightContainerDecorator(
{ leaveFor: { right: "" }, enterTo: "last-focused" },
"div"
);
export default function SearchThemeResults({
themeDatas,
themeCount,
...rest
}) {
delete rest.query;
const { getScrollTo, scrollLeft } = useScrollTo();
useEffect(() => {
if (themeDatas.length <= SEARCH_DATA_MAX_RESULTS_LIMIT) {
scrollLeft();
}
}, [themeDatas]);
return (
<Container className={css.container}>
{themeDatas && (
<></>
// <TVirtualGridList
// spotlightId="searchResultsThemeBox"
// className={css.grid}
// items={themeDatas}
// cbScrollTo={getScrollTo}
// dataSize={themeDatas.length}
// direction="horizontal"
// itemCard={SearchThemeCard}
// itemWidth={560}
// itemHeight={130}
// spacing={30}
// />
)}
</Container>
);
}

View File

@@ -1,12 +0,0 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
.flex();
margin: 30px 0 50px;
width: 100%;
}
.grid {
height: 141px;
}