Skip to content

Commit

Permalink
Merge pull request #102 from SOPT-all/develop
Browse files Browse the repository at this point in the history
merge to main
  • Loading branch information
seong-hui authored Nov 29, 2024
2 parents df17a55 + 8cd0456 commit c627fd8
Show file tree
Hide file tree
Showing 16 changed files with 167 additions and 96 deletions.
19 changes: 8 additions & 11 deletions src/apis/productPage/product/getProduct.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import instance from '@apis/instance';

interface ProductResponse {
interface ProductInfoType {
productId: number;
productImage: string;
detail: string;
priceOriginal: number;
percent: number;
priceDiscount: number;
percent: number;
isCoupon: boolean;
categoryName: string;
reviewCount: number;
rating: number;
}

interface RelatedProductsResponse {
interface ProductResponse {
success: boolean;
data: {
products: ProductResponse[];
};
data: ProductInfoType;
error: string | null;
}

const fetchRelatedProducts = async (productId: number): Promise<ProductResponse[]> => {
const response = await instance.get<RelatedProductsResponse>(`/api/products/${productId}/related`);
return response.data.data.products;
const fetchProduct = async (productId: number): Promise<ProductResponse> => {
const response = await instance.get<ProductResponse>(`/api/products/${productId}`);
return response.data;
};

export default fetchRelatedProducts;
export default fetchProduct;
29 changes: 29 additions & 0 deletions src/apis/productPage/product/getRelatedProducts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import instance from '@apis/instance';

interface ProductResponse {
productId: number;
productImage: string;
detail: string;
priceOriginal: number;
percent: number;
priceDiscount: number;
isCoupon: boolean;
categoryName: string;
reviewCount: number;
rating: number;
}

interface RelatedProductsResponse {
success: boolean;
data: {
products: ProductResponse[];
};
error: string | null;
}

const fetchRelatedProducts = async (productId: number): Promise<ProductResponse[]> => {
const response = await instance.get<RelatedProductsResponse>(`/api/products/${productId}/related`);
return response.data.data.products;
};

export default fetchRelatedProducts;
16 changes: 8 additions & 8 deletions src/apis/productPage/product/productQueries.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import fetchProduct from '@apis/productPage/product/getProduct';
import dummyProductResponse from '@constants/dummyProductResponse';
import { useQuery } from '@tanstack/react-query';
import fetchRelatedProducts from './getProduct';

const useRelatedProducts = (productId: number) => {
return useQuery({
queryKey: ['relatedProducts', productId],
queryFn: () => fetchRelatedProducts(productId),
initialData: [],
const useProductDetail = (productId: number) =>
useQuery({
queryKey: ['product', productId],
queryFn: () => fetchProduct(productId),
initialData: dummyProductResponse, // 더미데이터를 initialData로 설정해 서버 요청 실패시에도 해당 데이터로 유지하도록 설정
});
};

export default useRelatedProducts;
export default useProductDetail;
12 changes: 12 additions & 0 deletions src/apis/productPage/product/relatedProductsQueries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useQuery } from '@tanstack/react-query';
import fetchRelatedProducts from './getRelatedProducts';

const useRelatedProducts = (productId: number) => {
return useQuery({
queryKey: ['relatedProducts', productId],
queryFn: () => fetchRelatedProducts(productId),
initialData: [],
});
};

export default useRelatedProducts;
114 changes: 63 additions & 51 deletions src/components/ProductInfo/ProductInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import useProductDetail from '@apis/productPage/product/productQueries';
import { IcInfoGray14, IcWarningBrandYellow16, IcDot } from '@assets/icons';
import bannerRewordImg from '@assets/images/img_banner_reward.png';
import productSubImg1 from '@assets/images/img_product_sub1.png';
import { productOptionImages, productSubImages } from '@assets/images/productDetailImages';
import StarBtn from '@components/button/starBtn/StarBtn';
import {
Expand Down Expand Up @@ -29,61 +29,73 @@ import {
reivewBoxStyle,
} from '@components/ProductInfo/ProductInfoStyle';

const ProductInfo = () => (
<div css={columnflexStyle}>
<article css={productInfoContainerStyle}>
<section css={proudctImgLayoutStyle}>
<div css={detailImgBoxStyle}>
{productSubImages.map((imgSrc) => (
<img key={imgSrc} src={imgSrc} alt="상품 상세 이미지" />
))}
</div>
<img css={productImgStyle} src={productSubImg1} alt="상품 대표 이미지" />
</section>
<section css={productDetailLayoutStyle}>
<img src={bannerRewordImg} alt="상품 리워드 배너" />
<div css={productDetaiWrapperStyle}>
<div>
<div css={priceBoxStyle}>
<div css={priceDiscountStyle}>₩7.52</div>
<div css={priceOriginalStyle}>₩43.20</div>
<div css={discountPercentStyle}>82% 할인</div>
<div css={endSaleTiemStyle}>할인 종료시간: 12월 8일 16:59</div>
interface ProductInfoProps {
productId: number;
}

const ProductInfo = ({ productId }: ProductInfoProps) => {
const { data, error } = useProductDetail(productId);

if (error || !data) {
console.error(error);
return null;
}

const { productImage, detail, priceOriginal, priceDiscount, percent, rating, reviewCount } = data.data;

return (
<div css={columnflexStyle}>
<article css={productInfoContainerStyle}>
<section css={proudctImgLayoutStyle}>
<div css={detailImgBoxStyle}>
{productSubImages.map((imgSrc) => (
<img key={imgSrc} src={imgSrc} alt="상품 상세 이미지" />
))}
</div>
<img css={productImgStyle} src={productImage} alt="상품 대표 이미지" />
</section>
<section css={productDetailLayoutStyle}>
<img src={bannerRewordImg} alt="상품 리워드 배너" />
<div css={productDetaiWrapperStyle}>
<div>
<div css={priceBoxStyle}>
<div css={priceDiscountStyle}>{priceDiscount.toLocaleString()}</div>
<div css={priceOriginalStyle}>{priceOriginal.toLocaleString()}</div>
<div css={discountPercentStyle}>{percent}% 할인</div>
<div css={endSaleTiemStyle}>할인 종료시간: 12월 8일 16:59</div>
</div>
<div css={priceDescriptionStyle}>VAT가 포함된 가격 | 1% 추가 할인</div>
</div>
<div css={priceDescriptionStyle}>VAT가 포함된 가격 | 1% 추가 할인</div>
<div css={productNameStyle}>{detail}</div>
</div>
<div css={productNameStyle}>
Toocki GaN USB C 충전기, 맥쿡 아이폰 15, 14, 13, 12 프로 맥스, 삼성, 샤오미 포코용, 멀티 컬러, 고속 충전,
67W
<div css={reivewBoxStyle}>
<StarBtn rating={rating} reviewCount={reviewCount} />
<IcDot />
<div css={reviewBoxStyle}>5,000+개 판매</div>
</div>
<div css={mediumDividerStyle} />
<div css={optionStyle}>색상: 검정</div>
<section css={optionImgStyle}>
{productOptionImages.map((imgSrc, index) => (
<img key={`${imgSrc + index}`} src={imgSrc} alt="상품 옵션" />
))}
</section>
<div css={mediumDividerStyle} />
<div css={extraInfoStyle}>
<p>가격 정보 더보기</p>
<IcInfoGray14 />
</div>
</div>
<div css={reivewBoxStyle}>
<StarBtn rating={4.8} reviewCount={123} />
<IcDot />
<div css={reviewBoxStyle}>5,000+개 판매</div>
</div>
<div css={mediumDividerStyle} />
<div css={optionStyle}>색상: 검정</div>
<section css={optionImgStyle}>
{productOptionImages.map((imgSrc, index) => (
<img key={`${imgSrc + index}`} src={imgSrc} alt="상품 옵션" />
))}
</section>
<div css={mediumDividerStyle} />
<div css={extraInfoStyle}>
<p>가격 정보 더보기</p>
<IcInfoGray14 />
</article>
<section css={warnLayoutStyle}>
<h1 css={warnTitleStyle}>경고 / 면책 조항</h1>
<div css={warnDescriptionStyle}>
<IcWarningBrandYellow16 />
충전 및 보관 시 잠재적인 화재 위험을 유의하시고, 반드시 사용 설명서를 엄격히 준수해 주세요.
</div>
</section>
</article>
<section css={warnLayoutStyle}>
<h1 css={warnTitleStyle}>경고 / 면책 조항</h1>
<div css={warnDescriptionStyle}>
<IcWarningBrandYellow16 />
충전 및 보관 시 잠재적인 화재 위험을 유의하시고, 반드시 사용 설명서를 엄격히 준수해 주세요.
</div>
</section>
</div>
);
</div>
);
};

export default ProductInfo;
6 changes: 6 additions & 0 deletions src/components/footer/FooterStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ export const footerStyle = (theme: Theme) => css`
`;

export const subtitleStyle = (theme: Theme) => css`
display: flex;
flex-direction: column;
gap: 1rem;
${theme.fonts.kor.bodyBold13}
color: ${theme.colors.gray10};
`;

export const desc = (theme: Theme) => css`
${theme.fonts.kor.captionMedium11};
color: ${theme.colors.gray7};
`;
6 changes: 6 additions & 0 deletions src/components/header/productHeader/CategoryStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ export const CategoryLayout = css`
gap: 0;
align-items: center;
justify-content: center;
box-shadow:
0 0.6rem 1.2rem 0 rgb(0 0 0 / 12%),
0 0.4rem 0.8rem 0 rgb(0 0 0 / 8%),
0 0 0.4rem 0 rgb(0 0 0 / 8%);
border-radius: 12px;
`;

export const CategoryContainerStyle = (theme: Theme) => css`
Expand Down
6 changes: 6 additions & 0 deletions src/components/header/productHeader/MyListStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ export const MyLayoutStyle = css`
gap: 0;
align-items: center;
justify-content: center;
box-shadow:
0 0.6rem 1.2rem 0 rgb(0 0 0 / 12%),
0 0.4rem 0.8rem 0 rgb(0 0 0 / 8%),
0 0 0.4rem 0 rgb(0 0 0 / 8%);
border-radius: 12px;
`;

export const MyContainerStyle = (theme: Theme) => css`
Expand Down
2 changes: 1 addition & 1 deletion src/components/product/ProductCardList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import useRelatedProducts from '@apis/productPage/product/productQueries';
import useRelatedProducts from '@apis/productPage/product/relatedProductsQueries';
import ProductCard from './ProductCard';
import {
productListContainer,
Expand Down
2 changes: 1 addition & 1 deletion src/components/productOrderBox/ProductOrderBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const ProductOrderBoxContainer = css`

const ProductOrderBox = () => (
<div css={ProductOrderBoxContainer}>
<ProductInfo />
<ProductInfo productId={1} />
<OrderBox />
</div>
);
Expand Down
3 changes: 2 additions & 1 deletion src/components/productPage/review/review/FilterBtn.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IcArrowbottomGray12 } from '@assets/icons/index';
import {
relativeStyle,
fontStyle,
FilterBtnContainer,
dropDownLayoutStyle,
Expand All @@ -11,7 +12,7 @@ const FilterBtn = () => {
const [isHovered, setIsHovered] = useState(false);

return (
<div css={fontStyle}>
<div css={[fontStyle, relativeStyle]}>
<div css={FilterBtnContainer} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
<p>최근 작성된 리뷰</p>
<IcArrowbottomGray12 />
Expand Down
7 changes: 5 additions & 2 deletions src/components/productPage/review/review/FilterBtnStyle.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Theme, css } from '@emotion/react';

export const FilterBtnContainer = (theme: Theme) => css`
export const relativeStyle = css`
position: relative;
`;

export const FilterBtnContainer = (theme: Theme) => css`
display: flex;
align-items: center;
justify-content: space-between;
Expand All @@ -20,7 +23,7 @@ export const fontStyle = (theme: Theme) => css`

export const dropDownLayoutStyle = (theme: Theme) => css`
position: absolute;
top: 5rem;
top: 3.2rem;
width: 15.4rem;
background-color: ${theme.colors.gray1};
Expand Down
3 changes: 1 addition & 2 deletions src/components/productPage/review/reviewTop/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
titleContainer,
fontKoStyle,
fontEnStyle,
alignStyle,
toolStyle,
} from '@components/productPage/review/reviewTop/TitleStyle';
import { useState } from 'react';
Expand All @@ -20,7 +19,7 @@ const Title = () => {
<div css={[titleContainer, relativeStyle]}>
<p css={fontKoStyle}>리뷰</p>
<p css={fontEnStyle}>(497)</p>
<IcHelpGray20 css={alignStyle} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} />
<IcHelpGray20 onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} />
{isHovered && <div css={toolStyle}>{TOOL_MSG}</div>}
</div>
);
Expand Down
5 changes: 0 additions & 5 deletions src/components/productPage/review/reviewTop/TitleStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ export const fontEnStyle = (theme: Theme) => css`
${theme.fonts.eng.titleBold20}
`;

export const alignStyle = css`
margin-top: 0.2rem;
cursor: pointer;
`;
export const toolStyle = (theme: Theme) => css`
position: absolute;
top: 2.8rem;
Expand Down
19 changes: 19 additions & 0 deletions src/constants/dummyProductResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const dummyProductResponse = {
success: true,
data: {
productId: 1,
productImage: 'https://ae01.alicdn.com/kf/S709d4d4778ea430c87c0bf0a6574fa8dz.jpg_220x220q75.jpg_.webp',
detail:
'Toocki C타입 to C타입 케이블, 100W PD 고속 충전 충전기, USB C to USB C 디스플레이 케이블, 샤오미 POCO F3 리얼미 맥북 아이패드용',
priceOriginal: 6812,
percent: 60,
priceDiscount: 2700,
isCoupon: true,
categoryName: 'Electronics',
reviewCount: 8,
rating: 3.25,
},
error: null,
};

export default dummyProductResponse;
14 changes: 0 additions & 14 deletions src/types/ProductInfoType.ts

This file was deleted.

0 comments on commit c627fd8

Please sign in to comment.