-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from CHZZK-Study/feat/product-list-markup
Feat: 상품 등록 페이지 마크업 및 Button 공통 컴포넌트 생성
- Loading branch information
Showing
8 changed files
with
388 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import React, { useState } from 'react'; | ||
import classNames from 'classnames'; | ||
import { LuUsers } from 'react-icons/lu'; | ||
import { FaHeart } from 'react-icons/fa'; | ||
import Layout from './ui/Layout'; | ||
import Button from './components/common/Button'; | ||
import ongoingProducts from './mock/data/ongoingData'; | ||
import upcomingProducts from './mock/data/upcomingData'; | ||
|
||
const ProductList = () => { | ||
const [activeTab, setActiveTab] = useState('ongoing'); | ||
const [activeFilter, setActiveFilter] = useState(''); | ||
|
||
return ( | ||
<Layout | ||
header={ | ||
<header className="flex items-center justify-between p-4 border-b"> | ||
<button className="text-gray-500" aria-label="뒤로 가기"> | ||
<svg | ||
className="w-6 h-6" | ||
fill="none" | ||
stroke="currentColor" | ||
viewBox="0 0 24 24" | ||
> | ||
<path | ||
strokeLinecap="round" | ||
strokeLinejoin="round" | ||
strokeWidth="2" | ||
d="M15 19l-7-7 7-7" | ||
/> | ||
</svg> | ||
</button> | ||
<h1 className="text-lg font-semibold">상품 경매 목록</h1> | ||
<div /> | ||
</header> | ||
} | ||
footer={null} | ||
> | ||
<div className="flex justify-center w-full mt-3"> | ||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} | ||
<div | ||
className={classNames( | ||
'flex justify-center items-center w-full py-2 ml-4 cursor-pointer text-sm', | ||
activeTab === 'ongoing' | ||
? 'border-b-2 border-black' | ||
: 'border-b-2 border-gray-300', | ||
)} | ||
onClick={() => setActiveTab('ongoing')} | ||
> | ||
진행 중인 경매 | ||
</div> | ||
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} | ||
<div | ||
className={classNames( | ||
'flex justify-center w-full items-center py-2 mr-4 cursor-pointer text-sm', | ||
activeTab === 'upcoming' | ||
? 'border-b-2 border-black' | ||
: 'border-b-2 border-gray-300', | ||
)} | ||
onClick={() => setActiveTab('upcoming')} | ||
> | ||
사전 등록 경매 | ||
</div> | ||
</div> | ||
<div className="flex h-22px space-x-3 p-4"> | ||
<Button | ||
size="xsmall" | ||
color={classNames(activeFilter === 'popular' ? 'black' : 'white')} | ||
hoverColor="black" | ||
type="button" | ||
className="rounded-full" | ||
onClick={() => setActiveFilter('popular')} | ||
> | ||
인기 | ||
</Button> | ||
<Button | ||
size="xsmall" | ||
color={classNames(activeFilter === 'highPrice' ? 'black' : 'white')} | ||
hoverColor="black" | ||
type="button" | ||
className="rounded-full" | ||
onClick={() => setActiveFilter('highPrice')} | ||
> | ||
높은 가격순 | ||
</Button> | ||
<Button | ||
size="xsmall" | ||
color={classNames(activeFilter === 'lowPrice' ? 'black' : 'white')} | ||
hoverColor="black" | ||
type="button" | ||
className="rounded-full" | ||
onClick={() => setActiveFilter('lowPrice')} | ||
> | ||
낮은 가격순 | ||
</Button> | ||
<Button | ||
size="xsmall" | ||
color={classNames(activeFilter === 'latest' ? 'black' : 'white')} | ||
hoverColor="black" | ||
type="button" | ||
className="rounded-full" | ||
onClick={() => setActiveFilter('latest')} | ||
> | ||
최신순 | ||
</Button> | ||
</div> | ||
<div className="p-4 h-[calc(100vh-100px)] overflow-y-auto"> | ||
{activeTab === 'ongoing' | ||
? ongoingProducts.map((product) => ( | ||
<div key={product.id} className="mb-4"> | ||
<div className="flex h-[96px]"> | ||
<div className="w-[96px] h-full bg-gray-300" /> | ||
<div className="flex flex-col gap-[8px] ml-4"> | ||
<div> | ||
<p className="text-xs">{product.name}</p> | ||
</div> | ||
<div> | ||
<p className="text-xs font-semibold text-gray-500"> | ||
{`시작가 ${product.startPrice}`} | ||
</p> | ||
<div className="flex gap-1"> | ||
<LuUsers /> | ||
<p className="text-xs text-gray-500"> | ||
{`${product.activeUserCount}명 참여 중`} | ||
</p> | ||
</div> | ||
</div> | ||
<Button | ||
color="black" | ||
type="button" | ||
className={`${product.isBidding ? 'bg-gray-700' : 'bg-black'} w-[100px] h-[33px] rounded-md`} | ||
> | ||
{product.isBidding ? '경매 참여 중' : '경매 참여하기'} | ||
</Button> | ||
</div> | ||
</div> | ||
</div> | ||
)) | ||
: upcomingProducts.map((product) => ( | ||
<div key={product.id} className="mb-4"> | ||
<div className="flex h-[96px]"> | ||
<div className="w-[96px] h-full bg-gray-300" /> | ||
<div className="flex flex-col gap-[8px] ml-4"> | ||
<div> | ||
<p className="text-xs">{product.name}</p> | ||
</div> | ||
<div> | ||
<p className="text-xs font-semibold text-gray-500"> | ||
{`시작가 ${product.startPrice}`} | ||
</p> | ||
</div> | ||
<div className="flex items-center gap-1"> | ||
<FaHeart /> | ||
<p className="text-xs text-gray-500">{product.likes}</p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
</Layout> | ||
); | ||
}; | ||
|
||
export default ProductList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import React from 'react'; | ||
import classNames from 'classnames'; | ||
|
||
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { | ||
children: React.ReactNode; | ||
size?: 'xsmall' | 'small' | 'medium' | 'large'; | ||
disabled?: boolean; | ||
color: string; | ||
hoverColor?: string; | ||
} | ||
|
||
const Button: React.FC<ButtonProps> = ({ | ||
className, | ||
children, | ||
size, | ||
color, | ||
hoverColor, | ||
disabled, | ||
onClick, | ||
type, | ||
}) => { | ||
const baseClasses = 'focus:outline-none'; | ||
const colorClasses = classNames({ | ||
'bg-black text-white': color === 'black', | ||
'bg-white text-black border border-black': color === 'white', | ||
[`bg-${color}`]: color !== 'black' && color !== 'white', | ||
}); | ||
const sizeClasses = classNames({ | ||
'px-2 py-0.5 text-xs': size === 'xsmall', | ||
'px-2 py-1 text-sm': size === 'small', | ||
'px-4 py-2 text-base': size === 'medium', | ||
'px-6 py-3 text-lg': size === 'large', | ||
}); | ||
const hoverColorClasses = classNames({ | ||
'hover:bg-black hover:text-white': hoverColor === 'black', | ||
'hover:bg-white hover:text-black border border-black': | ||
hoverColor === 'white', | ||
}); | ||
const combinedClasses = classNames( | ||
colorClasses, | ||
baseClasses, | ||
sizeClasses, | ||
hoverColorClasses, | ||
className, | ||
{ | ||
'opacity-50 cursor-not-allowed': disabled, | ||
}, | ||
); | ||
|
||
return ( | ||
<button | ||
className={combinedClasses} | ||
disabled={disabled} | ||
onClick={onClick} | ||
type={type} | ||
> | ||
{children} | ||
</button> | ||
); | ||
}; | ||
|
||
Button.defaultProps = { | ||
disabled: false, | ||
hoverColor: '', | ||
size: 'small', | ||
}; | ||
|
||
export default Button; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
const ongoingProducts = [ | ||
{ | ||
id: 1, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '16시간 남음', | ||
activeUserCount: '11', | ||
isBidding: false, | ||
}, | ||
{ | ||
id: 2, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '1시간 남음', | ||
activeUserCount: '11', | ||
isBidding: true, | ||
}, | ||
{ | ||
id: 3, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '1시간 남음', | ||
activeUserCount: '11', | ||
isBidding: true, | ||
}, | ||
{ | ||
id: 4, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '4시간 남음', | ||
activeUserCount: '11', | ||
isBidding: true, | ||
}, | ||
{ | ||
id: 5, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '5시간 남음', | ||
activeUserCount: '11', | ||
isBidding: true, | ||
}, | ||
{ | ||
id: 6, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '6시간 남음', | ||
activeUserCount: '11', | ||
isBidding: true, | ||
}, | ||
{ | ||
id: 7, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '7시간 남음', | ||
activeUserCount: '11', | ||
isBidding: true, | ||
}, | ||
{ | ||
id: 8, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '8시간 남음', | ||
activeUserCount: '11', | ||
isBidding: true, | ||
}, | ||
{ | ||
id: 9, | ||
name: '[나이키] 신발', | ||
startPrice: '10,000원', | ||
timeLeft: '9시간 남음', | ||
activeUserCount: '11', | ||
isBidding: true, | ||
}, | ||
]; | ||
|
||
export default ongoingProducts; |
Oops, something went wrong.