Skip to content

Commit 55c58e3

Browse files
committed
Merge branch 'develop' of https://github.com/IT-Cotato/12th-OnGil-FE into develop
2 parents dd5c909 + ce51d70 commit 55c58e3

26 files changed

+256
-249
lines changed

public/icons/Arrow-up.svg

Lines changed: 3 additions & 0 deletions
Loading

public/icons/chevron.left.svg

Lines changed: 3 additions & 0 deletions
Loading

public/icons/review-empty.svg

Lines changed: 3 additions & 0 deletions
Loading

src/components/product/compact-product-header.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default function CompactProductHeader({ product }: CompactProductHeaderPr
3333
{product.name}
3434
</span>
3535
<div className="flex items-center gap-1 text-xs">
36-
{product.discountRate && (
36+
{product.discountRate > 0 && (
3737
<span className="font-bold text-red-600">
3838
{product.discountRate}%
3939
</span>

src/components/product/descriptions/product-description.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button';
77
import { ProductNotice } from './product-notice';
88
import { RecommendedProductsCarousel } from './recommended-products-carousel';
99
import { PRODUCTS } from '@/mocks/product-data';
10+
import { ChevronDown, ChevronUp } from 'lucide-react';
1011

1112
// 상품 설명 섹션 컴포넌트, 상세 이미지, 펼치기
1213

@@ -41,22 +42,25 @@ export function ProductDescription({ product }: { product: Product }) {
4142
</div>
4243

4344
{/* 8.4.1.1 펼치기 버튼 */}
44-
{!isExpanded && (
45-
<Button
46-
variant="ghost"
47-
onClick={() => setIsExpanded(true)}
48-
className="flex w-full items-center justify-center gap-2 rounded-none border-y border-gray-200 py-6 text-sm font-bold text-gray-600 hover:bg-gray-50"
49-
>
50-
펼치기 <span className="text-xs"></span>
51-
</Button>
52-
)}
45+
46+
<Button
47+
variant="outline"
48+
className="bg-ongil-teal mt-6 w-full rounded-xl border-gray-300 py-7 text-base font-bold text-white hover:bg-[#00252a] hover:text-white"
49+
onClick={() => setIsExpanded(!isExpanded)}
50+
aria-expanded={isExpanded}
51+
>
52+
{isExpanded ? '접기' : '자세히 보기'}
53+
{isExpanded ? (
54+
<ChevronUp className="ml-2 h-4 w-4" />
55+
) : (
56+
<ChevronDown className="ml-2 h-4 w-4" />
57+
)}
58+
</Button>
5359

5460
{/* 하단 공통 영역 */}
55-
<div className="space-y-12 border-t border-gray-100 pt-10">
61+
<div className="space-y-12 border-gray-100">
5662
<ProductNotice />
57-
<div className="pt-4">
58-
<RecommendedProductsCarousel products={recommendedProducts} />
59-
</div>
63+
<RecommendedProductsCarousel products={recommendedProducts} />
6064
</div>
6165
</div>
6266
);

src/components/product/descriptions/product-notice.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22

33
import { useState } from 'react';
4-
import { ChevronDown, ChevronUp } from 'lucide-react';
4+
import Image from 'next/image';
55
import { cn } from '@/lib/utils';
66

77
// 추후 펼치기 컴퍼넌트로 분리 가능.
@@ -15,16 +15,29 @@ function NoticeItem({
1515
const [isOpen, setIsOpen] = useState(false);
1616

1717
return (
18-
<div className="border-b border-gray-200 last:border-0">
18+
<div className="border-b border-[#D9D9D9] px-2 last:border-0">
1919
<button
2020
onClick={() => setIsOpen(!isOpen)}
21-
className="flex w-full items-center justify-between py-5 text-left transition-colors hover:bg-gray-50"
21+
className="flex w-full items-center justify-between py-[10px] text-left"
2222
>
23-
<span className="text-sm font-bold text-gray-900">{title}</span>
23+
<span className="px-1 py-[10px] text-2xl leading-6 font-bold not-italic">
24+
{title}
25+
</span>
2426
{isOpen ? (
25-
<ChevronUp className="h-4 w-4 text-gray-500" />
27+
<Image
28+
src="/icons/chevron.left.svg"
29+
alt="펼치기 아이콘"
30+
width={12}
31+
height={20}
32+
className="rotate-90"
33+
/>
2634
) : (
27-
<ChevronDown className="h-4 w-4 text-gray-500" />
35+
<Image
36+
src="/icons/chevron.left.svg"
37+
alt="펼치기 아이콘"
38+
width={12}
39+
height={20}
40+
/>
2841
)}
2942
</button>
3043
<div
@@ -41,7 +54,7 @@ function NoticeItem({
4154

4255
export function ProductNotice() {
4356
return (
44-
<div className="mt-10 border-t border-gray-200">
57+
<div className="border-y border-[#D9D9D9]">
4558
{/* 1. 상품정보 제공 고시 */}
4659
<NoticeItem title="상품정보 제공 고시">
4760
<div className="space-y-1.5 leading-relaxed">

src/components/product/product-card.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import Link from 'next/link';
22
import { Product } from '@/types/domain/product';
33

4+
// 카드 UI 컴포넌트, 클릭 시 상세 페이지로 이동함.
45
interface ProductCardProps {
56
product: Product;
67
}
78

8-
/**
9-
* 상품 카드 컴포넌트, 클릭 시 상세 페이지로 이동
10-
* @param {ProductCardProps} props - 컴포넌트 props
11-
* @param {Product} props.product - 상품 정보
12-
* @returns {JSX.Element} 상품 카드 컴포넌트
13-
*/
149
export default function ProductCard({ product }: ProductCardProps) {
1510
return (
1611
<Link href={`/product/${product.id}`} className="block">
@@ -27,7 +22,7 @@ export default function ProductCard({ product }: ProductCardProps) {
2722
{product.name}
2823
</span>
2924
<div className="flex w-full gap-2 text-xl font-bold">
30-
{product.discountRate > 0 && (
25+
{product.discountRate !== undefined && product.discountRate > 0 && (
3126
<span className="text-ongil-teal">{product.discountRate}%</span>
3227
)}
3328
<span>{product.finalPrice.toLocaleString()}</span>

src/components/product/product-header.tsx

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import Link from 'next/link';
44
import Image from 'next/image';
5+
import { useParams } from 'next/navigation';
6+
import { CloseButton } from '../ui/close-button';
57

68
interface ProductHeaderProps {
79
categoryID: string | number | undefined;
@@ -17,44 +19,39 @@ export default function ProductHeader({ categoryID }: ProductHeaderProps) {
1719
const backLink = categoryID ? `/products/${categoryID}` : '/products/top-all';
1820

1921
return (
20-
<header className="sticky top-0 z-50 flex h-14 w-full items-center justify-between border-b border-gray-100 bg-white px-4">
21-
<Link
22-
href={backLink}
23-
className="flex h-10 w-10 items-center justify-start transition-opacity hover:opacity-70"
24-
aria-label="목록으로 돌아가기"
25-
>
26-
<Image src="/icons/arrow.svg" width={24} height={24} alt="뒤로가기" />
27-
</Link>
28-
29-
<span className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-lg font-bold text-black">
22+
<header className="sticky top-0 z-50 flex h-[90px] w-full items-center justify-between bg-white px-[18px]">
23+
<CloseButton />
24+
<span className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-3xl font-semibold">
3025
상품 정보
3126
</span>
3227

33-
<div className="flex items-center gap-2">
28+
<div className="flex items-center gap-[15px]">
3429
<Link
3530
href="/search"
36-
className="flex h-10 w-10 items-center justify-center transition-opacity hover:opacity-70"
31+
className="flex items-center justify-center transition-opacity hover:opacity-70"
3732
aria-label="검색 열기"
3833
>
3934
<Image
4035
src="/icons/search-black.svg"
41-
width={24}
42-
height={24}
36+
width={30}
37+
height={30}
4338
alt="검색"
4439
/>
4540
</Link>
46-
4741
<Link
4842
href="/cart-list"
49-
className="flex h-10 w-10 items-center justify-center transition-opacity hover:opacity-70"
43+
className="flex flex-col items-center justify-center pt-3 transition-opacity hover:opacity-70"
5044
aria-label="장바구니 리스트"
5145
>
5246
<Image
5347
src="/icons/cart.svg"
54-
width={24}
55-
height={24}
48+
width={30}
49+
height={30}
5650
alt="장바구니 리스트"
5751
/>
52+
<span className="text-right text-xs leading-normal font-semibold not-italic">
53+
장바구니
54+
</span>
5855
</Link>
5956
</div>
6057
</header>

src/components/product/product-info.tsx

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { type Ref } from 'react';
44
import { Product } from '@/types/domain/product';
55
import { Button } from '@/components/ui/button';
6-
import { Bell } from 'lucide-react';
6+
import StarRating from '../ui/star-rating';
77

88
interface ProductInfoProps {
99
product: Product;
@@ -17,63 +17,61 @@ interface ProductInfoProps {
1717
* @param {Ref<HTMLButtonElement | null>} [props.discountRef] - 할인 알림 버튼에 대한 ref
1818
* @returns {JSX.Element} 상품 정보 컴포넌트
1919
*/
20-
export default function ProductInfo({ product, discountRef }: ProductInfoProps) {
20+
export default function ProductInfo({
21+
product,
22+
discountRef,
23+
}: ProductInfoProps) {
2124
const hasDiscount = !!product.discountRate;
2225
return (
23-
<div className="font-pretendard px-4 py-6">
26+
<div className="font-pretendard p-[22px] leading-[18px] not-italic">
2427
{/* 8.1.1 (1) 브랜드 */}
25-
<div className="mb-1 text-xl font-bold text-gray-500">
26-
{product.brandName}
27-
</div>
28+
<div className="mb-6 text-xl font-extrabold">{product.brandName}</div>
2829
{/* 8.1.1 (3) 상품명 */}
29-
<h1 className="line-clamp-2 text-2xl leading-tight font-bold break-keep text-gray-900">
30+
<h1 className="mb-6 px-2 text-2xl leading-tight font-medium">
3031
{product.name}
3132
</h1>
32-
{/* 가격 정보 */}
33-
<div className="mt-4">
34-
{hasDiscount ? (
35-
<div className="flex flex-col">
36-
<div className="flex items-end gap-2">
37-
{/* 할인가 (현재 판매가) */}
38-
<span className="text-4xl font-bold text-black">
39-
<span className="sr-only">할인 판매가</span>
40-
{product.finalPrice.toLocaleString()}
41-
<span className="text-2xl font-normal"></span>
42-
</span>
43-
44-
{/* 할인율 */}
45-
<span className="mb-1 text-xl font-bold text-red-600">
46-
<span className="sr-only">할인율</span>
47-
{product.discountRate}%
48-
</span>
49-
</div>
50-
33+
{hasDiscount ? (
34+
<div className="flex flex-col gap-4">
35+
<div className="flex items-center gap-3">
36+
{/* 할인가 (현재 판매가) */}
37+
<span className="text-4xl font-bold">
38+
<span className="sr-only">할인 판매가</span>
39+
<span>{product.finalPrice.toLocaleString()}</span>
40+
</span>
5141
{/* 원가 (취소선)*/}
52-
<del className="mt-1 text-xl text-gray-400">
42+
<del className="text-xl text-[#0000004F]">
5343
<span className="sr-only">정상가</span>
5444
{product.price.toLocaleString()}
5545
</del>
5646
</div>
57-
) : (
58-
<span className="text-2xl font-bold text-black">
59-
<span className="sr-only">판매가</span>
60-
{product.price.toLocaleString()}
47+
<span className="mb-1 text-xl font-bold text-red-600">
48+
<span className="sr-only">할인율</span>
49+
{product.discountRate}%
6150
</span>
62-
)}
51+
</div>
52+
) : (
53+
<span className="text-4xl font-bold">
54+
<span className="sr-only">판매가</span>
55+
{product.price.toLocaleString()}
56+
</span>
57+
)}
58+
<div className="mt-2 flex items-center gap-2">
59+
<StarRating rating={product.reviewRating} size={24} />
60+
<span className="font-Poppins text-sm leading-5 font-semibold not-italic">
61+
({product.reviewCount})
62+
</span>
6363
</div>
64-
{/* 리뷰 별점 정보 추가해야함. */}
65-
<h1 className="mt-3 text-gray-600">리뷰 별점 ★★★★☆</h1>
66-
6764
{/* 8.2 할인 알림 받기 버튼, 추후 알림 로직 구현 해야함. */}
68-
<Button
69-
ref={discountRef}
70-
variant="outline"
71-
className="mt-6 w-full rounded-xl border-gray-300 bg-[#00363D] py-7 text-base font-bold text-white hover:bg-[#00252a] hover:text-white"
72-
onClick={() => alert('할인가 알림 신청 완료!')}
73-
>
74-
<Bell className="mr-2 h-5 w-5" />
75-
할인 알림 받기
76-
</Button>
65+
<div className="flex justify-center">
66+
<Button
67+
ref={discountRef}
68+
variant="outline"
69+
className="bg-ongil-teal mt-6 h-[66px] w-[232px] justify-center rounded-3xl py-5 text-center text-xl leading-normal font-bold text-white"
70+
onClick={() => alert('할인가 알림 신청 완료!')}
71+
>
72+
할인 알림
73+
</Button>
74+
</div>
7775
</div>
7876
);
7977
}

src/components/product/product-interaction-context.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { createContext, useContext, useState, ReactNode } from 'react';
3+
import { createContext, use, useState, ReactNode } from 'react';
44

55
interface ProductContextType {
66
shouldScrollToTab: boolean; // 스크롤 이동 여부
@@ -48,7 +48,7 @@ export function ProductInteractionProvider({
4848
* @throws Error if used outside of ProductInteractionProvider
4949
*/
5050
export function useProductInteraction() {
51-
const context = useContext(ProductContext);
51+
const context = use(ProductContext);
5252
if (!context) {
5353
throw new Error(
5454
'useProductInteraction must be used within a ProductInteractionProvider',

0 commit comments

Comments
 (0)