From ae36aa8bb30f73b75338215b9836a5a79019c26c Mon Sep 17 00:00:00 2001 From: Taeeun Kim Date: Thu, 11 Apr 2024 16:28:44 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=83=9C=EA=B7=B8=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#64)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 검색 api에서 태그 검색일때의 endpoint 추가 * feat: 태그 검색 기능 구현 * feat: 검색결과 없을 때 화면 구현 * feat: 태그 검색 결과 리스트 컴포넌트 구현 * feat: Text 컴포넌트에서 외부 className을 받을 수 있게 수정 * feat: 검색 페이지에서 태그 검색 결과일 경우 분기처리 * feat: 더보기 버튼을 리스트 컴포넌트로 위치 이동 * feat: 태그 검색을 일반 검색과 분리 * feat: 상품 검색 더보기 페이지 구현 * feat: 태그 검색을 했을 때 input value 스타일 변경 * style: 사용 안하는 코드 import 제거 * feat: ProductSearchResultList 스토리북 추가 * fix: 검색이 되었을 때 resetQuery를 하도록 수정 * style: fix lint error * feat: 태그 검색 페이지 분리 * feat: 말풍선 아이콘 교체 * feat: ProductItem 디자인 수정 * feat: ProductSearchResultList -> ProductSearchResultPreviewList로 이름 변경 * feat: 버튼 스타일 변경 * feat: ProductOverviewList로 교체 * fix: 상품 상세 경로 수정 * refactor: 인자로 endpoint를 넘겨주게끔 변경 --- .storybook/preview-body.html | 51 +++++++++-- src/assets/search-notfound.png | Bin 0 -> 9509 bytes src/components/Common/Svg/SvgSprite.tsx | 53 ++++++++++-- src/components/Common/Text/Text.tsx | 5 +- .../Product/ProductItem/ProductItem.tsx | 5 +- .../ProductOverviewList.tsx | 9 +- .../productOverviewList.css.ts | 13 +++ .../ProductSearchResultList.tsx | 34 -------- ...ProductSearchResultPreviewList.stories.tsx | 16 ++++ .../ProductSearchResultPreviewList.tsx | 51 +++++++++++ .../productSearchResultPreivewList.css.ts | 15 ++++ .../RecipeSearchResultList.tsx | 9 +- .../Search/SearchInput/SearchInput.tsx | 20 ++++- .../Search/SearchInput/searchInput.css.ts | 16 +++- .../SearchNotFound/SearchNotFound.stories.tsx | 13 +++ .../Search/SearchNotFound/SearchNotFound.tsx | 24 ++++++ .../SearchNotFound/searchNotFound.css.ts | 7 ++ .../TagSearchResultList.stories.tsx | 17 ++++ .../TagSearchResultList.tsx | 52 ++++++++++++ .../tagSearchResult.css.ts | 8 ++ src/components/Search/index.ts | 3 +- .../useInfiniteProductSearchResultsQuery.ts | 12 +-- src/hooks/search/useSearch.ts | 31 +++++-- src/mocks/handlers/searchHandlers.ts | 2 +- .../ProductSearchListPage.tsx | 36 ++++++++ .../productSearchListPage.css.ts | 6 ++ src/pages/SearchPage/SearchPage.tsx | 80 ++++++++++-------- src/pages/SearchPage/TagSearchResultPage.tsx | 35 ++++++++ src/pages/SearchPage/searchPage.css.ts | 24 +++--- src/router/index.tsx | 18 ++++ 30 files changed, 546 insertions(+), 119 deletions(-) create mode 100644 src/assets/search-notfound.png delete mode 100644 src/components/Search/ProductSearchResultList/ProductSearchResultList.tsx create mode 100644 src/components/Search/ProductSearchResultList/ProductSearchResultPreviewList.stories.tsx create mode 100644 src/components/Search/ProductSearchResultList/ProductSearchResultPreviewList.tsx create mode 100644 src/components/Search/ProductSearchResultList/productSearchResultPreivewList.css.ts create mode 100644 src/components/Search/SearchNotFound/SearchNotFound.stories.tsx create mode 100644 src/components/Search/SearchNotFound/SearchNotFound.tsx create mode 100644 src/components/Search/SearchNotFound/searchNotFound.css.ts create mode 100644 src/components/Search/TagSearchResultList/TagSearchResultList.stories.tsx create mode 100644 src/components/Search/TagSearchResultList/TagSearchResultList.tsx create mode 100644 src/components/Search/TagSearchResultList/tagSearchResult.css.ts create mode 100644 src/pages/ProductSearchListPage/ProductSearchListPage.tsx create mode 100644 src/pages/ProductSearchListPage/productSearchListPage.css.ts create mode 100644 src/pages/SearchPage/TagSearchResultPage.tsx diff --git a/.storybook/preview-body.html b/.storybook/preview-body.html index ec34bccc0..23699d190 100644 --- a/.storybook/preview-body.html +++ b/.storybook/preview-body.html @@ -110,16 +110,55 @@ - - + + + + + + + + - - - + + diff --git a/src/assets/search-notfound.png b/src/assets/search-notfound.png new file mode 100644 index 0000000000000000000000000000000000000000..a8bb7e024cb062cf29e2780d118310ad3e8bfa77 GIT binary patch literal 9509 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 b;{B=0=Yh^R7k4D=Yy#R4eT^zL+ZX=_^;Ji` literal 0 HcmV?d00001 diff --git a/src/components/Common/Svg/SvgSprite.tsx b/src/components/Common/Svg/SvgSprite.tsx index af9c52d72..922b6ec46 100644 --- a/src/components/Common/Svg/SvgSprite.tsx +++ b/src/components/Common/Svg/SvgSprite.tsx @@ -106,14 +106,55 @@ const SvgSprite = () => { - - - - + + + + + + + + + - - + + diff --git a/src/components/Common/Text/Text.tsx b/src/components/Common/Text/Text.tsx index 2297bfee4..e2ff5229d 100644 --- a/src/components/Common/Text/Text.tsx +++ b/src/components/Common/Text/Text.tsx @@ -1,3 +1,5 @@ +import cx from 'classnames'; + import { text } from './text.css'; import type { TextElement, TextVariants, OverridableComponentPropsWithoutRef } from './text.types'; @@ -9,12 +11,13 @@ const Text = ({ weight = 'regular', color = 'default', as, + className, ...props }: TextProps) => { const Component = as || 'p'; return ( - + {children} ); diff --git a/src/components/Product/ProductItem/ProductItem.tsx b/src/components/Product/ProductItem/ProductItem.tsx index 526b91980..ebcec3389 100644 --- a/src/components/Product/ProductItem/ProductItem.tsx +++ b/src/components/Product/ProductItem/ProductItem.tsx @@ -12,6 +12,7 @@ import { } from './productItem.css'; import { SvgIcon } from '@/components/Common'; +import { vars } from '@/styles/theme.css'; import type { Product } from '@/types/product'; interface ProductItemProps { @@ -44,13 +45,13 @@ const ProductItem = ({ product }: ProductItemProps) => {
- + {averageRating.toFixed(1)}
- + {reviewCount} diff --git a/src/components/Product/ProductOverviewList/ProductOverviewList.tsx b/src/components/Product/ProductOverviewList/ProductOverviewList.tsx index d18ba0cd3..66d615cb7 100644 --- a/src/components/Product/ProductOverviewList/ProductOverviewList.tsx +++ b/src/components/Product/ProductOverviewList/ProductOverviewList.tsx @@ -8,9 +8,10 @@ import type { Product } from '@/types/product'; interface ProductOverviewListProps { products: Product[]; + isSearchPage?: boolean; } -const ProductOverviewList = ({ products }: ProductOverviewListProps) => { +const ProductOverviewList = ({ products, isSearchPage = false }: ProductOverviewListProps) => { return (
    {products.map(({ id, image, name, price, averageRating }) => ( @@ -18,6 +19,12 @@ const ProductOverviewList = ({ products }: ProductOverviewListProps) => { + {isSearchPage && ( + <> +
    +
    + + )} ))}
diff --git a/src/components/Product/ProductOverviewList/productOverviewList.css.ts b/src/components/Product/ProductOverviewList/productOverviewList.css.ts index d48c09e7b..1d89fd9d0 100644 --- a/src/components/Product/ProductOverviewList/productOverviewList.css.ts +++ b/src/components/Product/ProductOverviewList/productOverviewList.css.ts @@ -5,3 +5,16 @@ export const container = style({ flexDirection: 'column', gap: 20, }); + +export const showMoreButton = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: '100%', + height: 38, + padding: '9px 0', + margin: '20px 0', + background: '#efefef', + fontSize: 14, + borderRadius: 6, +}); diff --git a/src/components/Search/ProductSearchResultList/ProductSearchResultList.tsx b/src/components/Search/ProductSearchResultList/ProductSearchResultList.tsx deleted file mode 100644 index f796afe23..000000000 --- a/src/components/Search/ProductSearchResultList/ProductSearchResultList.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { useRef } from 'react'; - -import { ProductOverviewList } from '@/components/Product'; -import { useIntersectionObserver } from '@/hooks/common'; -import { useInfiniteProductSearchResultsQuery } from '@/hooks/queries/search'; - -interface ProductSearchResultListProps { - searchQuery: string; -} - -const ProductSearchResultList = ({ searchQuery }: ProductSearchResultListProps) => { - const { data: searchResponse, fetchNextPage, hasNextPage } = useInfiniteProductSearchResultsQuery(searchQuery); - const scrollRef = useRef(null); - useIntersectionObserver(fetchNextPage, scrollRef, hasNextPage); - - if (!searchResponse) { - return null; - } - - const products = searchResponse.pages.flatMap((page) => page.products); - - if (products.length === 0) { - return

검색한 상품을 찾을 수 없습니다.

; - } - - return ( - <> - -
- - ); -}; - -export default ProductSearchResultList; diff --git a/src/components/Search/ProductSearchResultList/ProductSearchResultPreviewList.stories.tsx b/src/components/Search/ProductSearchResultList/ProductSearchResultPreviewList.stories.tsx new file mode 100644 index 000000000..903bdc224 --- /dev/null +++ b/src/components/Search/ProductSearchResultList/ProductSearchResultPreviewList.stories.tsx @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import ProductSearchResultPreviewList from './ProductSearchResultPreviewList'; + +const meta: Meta = { + title: 'search/ProductSearchResultPreviewList', + component: ProductSearchResultPreviewList, + args: { + searchQuery: '꼬북칩', + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/components/Search/ProductSearchResultList/ProductSearchResultPreviewList.tsx b/src/components/Search/ProductSearchResultList/ProductSearchResultPreviewList.tsx new file mode 100644 index 000000000..2dcc4c185 --- /dev/null +++ b/src/components/Search/ProductSearchResultList/ProductSearchResultPreviewList.tsx @@ -0,0 +1,51 @@ +import { useRef } from 'react'; +import { Link } from 'react-router-dom'; + +import { showMoreLink } from './productSearchResultPreivewList.css'; +import SearchNotFound from '../SearchNotFound/SearchNotFound'; + +import { Text } from '@/components/Common'; +import { ProductOverviewList } from '@/components/Product'; +import { PATH } from '@/constants/path'; +import { useIntersectionObserver } from '@/hooks/common'; +import { useInfiniteProductSearchResultsQuery } from '@/hooks/queries/search'; +import displaySlice from '@/utils/displaySlice'; + +interface ProductSearchResultPreviewListProps { + searchQuery: string; +} + +const ProductSearchResultPreviewList = ({ searchQuery }: ProductSearchResultPreviewListProps) => { + const { + data: searchResponse, + fetchNextPage, + hasNextPage, + } = useInfiniteProductSearchResultsQuery(searchQuery, 'products'); + const scrollRef = useRef(null); + useIntersectionObserver(fetchNextPage, scrollRef, hasNextPage); + + if (!searchResponse) { + return null; + } + + const products = searchResponse.pages.flatMap((page) => page.products); + const productToDisplay = displaySlice(true, products); + + if (products.length === 0) { + return ; + } + + return ( + <> + + + + 더보기 + + +
+ + ); +}; + +export default ProductSearchResultPreviewList; diff --git a/src/components/Search/ProductSearchResultList/productSearchResultPreivewList.css.ts b/src/components/Search/ProductSearchResultList/productSearchResultPreivewList.css.ts new file mode 100644 index 000000000..7ad896228 --- /dev/null +++ b/src/components/Search/ProductSearchResultList/productSearchResultPreivewList.css.ts @@ -0,0 +1,15 @@ +import { vars } from '@/styles/theme.css'; +import { style } from '@vanilla-extract/css'; + +export const showMoreLink = style({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: '100%', + height: 44, + padding: '12px 0', + margin: '20px 0', + border: `1px solid ${vars.colors.border.default}`, + fontSize: 14, + borderRadius: 6, +}); diff --git a/src/components/Search/RecipeSearchResultList/RecipeSearchResultList.tsx b/src/components/Search/RecipeSearchResultList/RecipeSearchResultList.tsx index 89496d2c2..bdc5134b9 100644 --- a/src/components/Search/RecipeSearchResultList/RecipeSearchResultList.tsx +++ b/src/components/Search/RecipeSearchResultList/RecipeSearchResultList.tsx @@ -1,8 +1,9 @@ -import { Link, Text } from '@fun-eat/design-system'; import { useRef } from 'react'; -import { Link as RouterLink } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import { styled } from 'styled-components'; +import SearchNotFound from '../SearchNotFound/SearchNotFound'; + import { RecipeItem } from '@/components/Recipe'; import { PATH } from '@/constants/path'; import { useIntersectionObserver } from '@/hooks/common'; @@ -20,7 +21,7 @@ const RecipeSearchResultList = ({ searchQuery }: RecipeSearchResultListProps) => const recipes = searchResponse.pages.flatMap((page) => page.recipes); if (recipes.length === 0) { - return 검색한 꿀조합을 찾을 수 없습니다.; + return ; } return ( @@ -28,7 +29,7 @@ const RecipeSearchResultList = ({ searchQuery }: RecipeSearchResultListProps) => {recipes.map((recipe) => (
  • - +
  • diff --git a/src/components/Search/SearchInput/SearchInput.tsx b/src/components/Search/SearchInput/SearchInput.tsx index 1a15dec38..092a878ce 100644 --- a/src/components/Search/SearchInput/SearchInput.tsx +++ b/src/components/Search/SearchInput/SearchInput.tsx @@ -1,16 +1,20 @@ import type { ComponentPropsWithRef, ForwardedRef } from 'react'; import { forwardRef } from 'react'; -import { iconWrapperButton, inputContainer, searchInput } from './searchInput.css'; +import { iconWrapperButton, inputContainer, searchInput, tagInputWrapper } from './searchInput.css'; -import { SvgIcon } from '@/components/Common'; +import { Text, SvgIcon } from '@/components/Common'; interface SearchInputProps extends ComponentPropsWithRef<'input'> { isInputSubmitted: boolean; + isTagSearch?: boolean; } const SearchInput = forwardRef( - ({ value, isInputSubmitted, ...props }: SearchInputProps, ref: ForwardedRef) => { + ( + { value, isInputSubmitted, isTagSearch = false, ...props }: SearchInputProps, + ref: ForwardedRef + ) => { return (
    + {isTagSearch && isInputSubmitted && ( +
    + + {value} + + +
    + )} - {/* divider 컴포넌트 */} -
    -
    -

    꿀!조합 바로가기

    - - }> - - - -
    + <> +
    + + 상품 바로가기 + + + }> + + + +
    +
    +
    + + 꿀!조합 바로가기 + + + }> + + + +
    + ) : ( -
    -

    최근 검색어

    +
    + + 최근 검색어 +
    {recentSearchedKeywords?.map((keyword, index) => ( - ))}
    -

    추천 태그

    + + 추천 태그 +
    {RECOMMENDED_TAGS.map(({ id, name }) => ( -