Skip to content

Commit

Permalink
v1.0.2 업데이트 (#160)
Browse files Browse the repository at this point in the history
## 💡 이슈
resolve #158 

## 🤩 개요
v1.0.2 업데이트

## 🧑‍💻 작업 사항
- shop 페이지에 추천 api 연결 및 UI 추가

## 📖 참고 사항
공유할 내용, 레퍼런스, 추가로 발생할 것으로 예상되는 이슈, 스크린샷 등을 넣어 주세요.
  • Loading branch information
kingyong9169 authored Nov 13, 2022
2 parents a9f2900 + 5c315e0 commit 261efcb
Show file tree
Hide file tree
Showing 19 changed files with 327 additions and 114 deletions.
13 changes: 11 additions & 2 deletions src/api/shop/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,18 @@ const getProductItemList = async (
return response;
};

const getRecommendItemList = async (
queryString: string,
): Promise<res.RecommendFeed> => {
const response = await Axios.get(
`/api/recommend?${decodeURIComponent(queryString)}`,
);
return response;
};

type GetInfiniteParams = {
queryStringObj: { [key: string]: string };
apiFunc: (queryString: string) => Promise<res.ShopFeed>;
apiFunc: (queryString: string) => Promise<res.ShopFeed | res.RecommendFeed>;
};

const getInfiniteProducts =
Expand Down Expand Up @@ -40,4 +49,4 @@ export type GetInfiniteProducts = () => ReturnType<
ReturnType<typeof getInfiniteProducts>
>;

export { getInfiniteProducts, getProductItemList };
export { getInfiniteProducts, getProductItemList, getRecommendItemList };
2 changes: 1 addition & 1 deletion src/components/Search/organisms/SearchBody/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function SearchBody(bodyProps: Props) {
);

return value ? (
<ProductItemList paddingTop="120px" isSearch {...{ queryStringObj }} />
<ProductItemList paddingTop="120px" type="search" {...{ queryStringObj }} />
) : (
<section className={$['search-body']}>
<Keywords {...{ keywords, removeKeyword, queryFunc }} />
Expand Down
52 changes: 52 additions & 0 deletions src/components/Shop/Organisms/ProductItemList/ProductList.view.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { memo } from 'react';

import ShopSkeleton from '@templates/Skeleton/shop';
import classnames from 'classnames';
import ProductItem from 'src/components/Shop/molecules/ProductItem';

import RecommendItem from './RecommendItem.view';
import $ from './style.module.scss';

type Props = {
isFetching: boolean;
intersectRef: React.RefObject<HTMLDivElement>;
noProducts: React.ReactNode;
isRecommend: boolean;
itemList?: (res.ProductSummary | res.RecommendProduct)[];
};

const isRecommendProduct = (
item: res.ProductSummary | res.RecommendProduct,
): item is res.RecommendProduct => {
return 'product' in item;
};

function ProductListView(viewProps: Props) {
const { isFetching, itemList, intersectRef, noProducts, isRecommend } =
viewProps;
// TODO: 윈도우 사이즈에 따라 스켈레톤 아이템 개수 다르게 하기

return (
<>
{itemList && (
<article
className={classnames($['product-list'], {
[$['recommend-list']]: isRecommend,
})}
>
{itemList.map((item) => {
if (isRecommendProduct(item)) {
return <RecommendItem key={item.id} {...{ item }} />;
}
return <ProductItem key={item.id} {...item} />;
})}
</article>
)}
{noProducts}
<div ref={intersectRef} />
{isFetching && <ShopSkeleton itemNum={12} {...{ isRecommend }} />}
</>
);
}

export default memo(ProductListView);
34 changes: 0 additions & 34 deletions src/components/Shop/Organisms/ProductItemList/ProductListView.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { memo } from 'react';

import ProductItem from 'src/components/Shop/molecules/ProductItem';

import $ from './style.module.scss';

type Props = {
item: res.RecommendProduct;
};

function RecommendItem(viewProps: Props) {
const { item } = viewProps;
const { product, associatedProduct } = item;
// TODO: 윈도우 사이즈에 따라 스켈레톤 아이템 개수 다르게 하기

return (
<div className={$['recommend-item']}>
<ProductItem {...product} />
<ProductItem {...associatedProduct} />
</div>
);
}

export default memo(RecommendItem);
37 changes: 21 additions & 16 deletions src/components/Shop/Organisms/ProductItemList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@ import PullToRefresh from '@templates/PullToRefresh';
import ShopSkeleton from '@templates/Skeleton/shop';
import { useIntersect } from 'src/hooks';
import { useSearchingItemListQuery } from 'src/hooks/api/search';
import { useProductItemListQuery } from 'src/hooks/api/shop';
import {
useProductItemListQuery,
useRecommendItemListQuery,
} from 'src/hooks/api/shop';

import NoProductView from './NoProductView';
import ProductListView from './ProductListView';
import ProductListWrapperView from './ProductListWrapperView';
import NoProductView from './NoProduct.view';
import ProductListView from './ProductList.view';
import ProductListWrapperView from './ProductListWrapper.view';

export type ProductItemListType = 'shop' | 'mypage' | 'recommend' | 'search';

type Props = {
type: ProductItemListType;
isRecommend?: boolean;
isSearch?: boolean;
queryStringObj?: Omit<req.ShopFeed, 'page' | 'size'>;
paddingTop?: string;
Expand All @@ -21,17 +28,18 @@ type Props = {

type ProductList = Props['queryStringObj'];

const useProductItemQuery = (isSearch?: boolean) => {
if (isSearch) return useSearchingItemListQuery;
const useProductItemQuery = (type: ProductItemListType) => {
if (type === 'search') return useSearchingItemListQuery;
if (type === 'recommend') return useRecommendItemListQuery;
return useProductItemListQuery;
};

function ProductItemList(listProps: Props) {
const { isSearch, paddingTop, paddingBottom } = listProps;
const { type, paddingTop, paddingBottom } = listProps;
const { needPullToRefresh, queryStringObj } = listProps;

const productList: ProductList = { ...queryStringObj };
const useProductItem = useProductItemQuery(isSearch);
const useProductItem = useProductItemQuery(type);

const {
data,
Expand All @@ -57,13 +65,9 @@ function ProductItemList(listProps: Props) {
}
});

const items = data?.pages;

const itemList = items?.reduce((acc: res.ProductSummary[], cur) => {
acc.push(...cur.items);
return acc;
}, []);

const pages = data?.pages;
const isRecommend = type === 'recommend';
const itemList = pages?.map(({ items }) => items).flat();
const isNoProducts = (itemList && !itemList.length) || false;

const noProducts = (
Expand All @@ -82,11 +86,12 @@ function ProductItemList(listProps: Props) {
const maxPullDownDistance = 90;

const commonProducts = isLoading ? (
<ShopSkeleton itemNum={12} />
<ShopSkeleton itemNum={12} {...{ isRecommend }} />
) : (
// TODO: 윈도우 사이즈에 따라 스켈레톤 아이템 개수 다르게 하기
<ProductListView
{...{ intersectRef, isFetching, noProducts }}
isRecommend={isRecommend}
itemList={itemList}
/>
);
Expand Down
12 changes: 12 additions & 0 deletions src/components/Shop/Organisms/ProductItemList/style.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@
}
}

.recommend-list {
@include tablet() {
grid-template-columns: repeat(2, 50%);
}
}

.recommend-item {
width: 100%;
display: flex;
justify-content: center;
}

.no-products {
width: 100%;
height: calc(var(--vh, 1vh) * 100 - 185px);
Expand Down
23 changes: 21 additions & 2 deletions src/components/Shop/molecules/ProductItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { memo } from 'react';
import { StyleProps } from '#types/props';
import ResponsiveImg from '@atoms/ResponsiveImg';
import Span from '@atoms/Span';
import classnames from 'classnames';
import { useTimeForToday } from 'src/hooks';

import SoldoutBox from '../SoldoutBox';
Expand All @@ -13,12 +14,21 @@ import $ from './style.module.scss';
type Props = res.ProductSummary & StyleProps;

function ProductItem(itemProps: Props) {
const { id, img, title, size, like, price, isSoldOut, updatedAt } = itemProps;
const { id, img, title, size, like, price } = itemProps;
const { isSoldOut, updatedAt, type } = itemProps;
const isRecommend = !!type;
const isTop = type === 'top';
const clothesText = isTop ? '상의' : '하의';
const date = useTimeForToday(updatedAt);

return (
<Link href={`/shop/${id}`}>
<div className={$['product-item']}>
<div
className={classnames($['common-item'], {
[$['recommend-item']]: isRecommend,
[$['product-item']]: !isRecommend,
})}
>
<ResponsiveImg
width={200}
height={200}
Expand All @@ -27,6 +37,15 @@ function ProductItem(itemProps: Props) {
className={$['product-img']}
>
<SoldoutBox {...{ isSoldOut }} />
{isRecommend && (
<Span
fontSize={12}
fontWeight={700}
className={classnames($['clothes-tag'], { [$.top]: isTop })}
>
{clothesText}
</Span>
)}
</ResponsiveImg>

<div className={$['text-box']}>
Expand Down
Loading

0 comments on commit 261efcb

Please sign in to comment.