-
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 #173 from boostcampwm-2024/feature/trade
[FE] 주문 요청 현황 레이아웃 구현 & api 연동
- Loading branch information
Showing
17 changed files
with
400 additions
and
196 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
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
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 useOrders from 'hooks/useOrder'; | ||
import { parseTimestamp } from 'utils/common'; | ||
|
||
export default function Order() { | ||
const { orderQuery, removeOrder } = useOrders(); | ||
|
||
const { data, isLoading, isError } = orderQuery; | ||
|
||
if (isLoading) return <div>loading</div>; | ||
if (!data) return <div>No data</div>; | ||
if (isError) return <div>error</div>; | ||
|
||
const handleCancelOrder = (id: number) => { | ||
removeOrder.mutate(id); | ||
}; | ||
|
||
return ( | ||
<div className='flex flex-col w-full p-4 mx-auto bg-white rounded-md shadow-md'> | ||
<div className='flex pb-2 text-sm font-bold border-b'> | ||
<p className='w-1/3 text-left truncate'>종목</p> | ||
<p className='w-1/4 text-center'>요청 유형</p> | ||
<p className='w-1/4 text-center'>수량</p> | ||
<p className='w-1/4 text-center'>요청 가격</p> | ||
<p className='w-1/4 text-right'>요청 시간</p> | ||
<p className='w-1/6 text-right'></p> | ||
</div> | ||
|
||
<ul className='flex flex-col text-sm divide-y min-h-48'> | ||
{data.map((order) => { | ||
const { | ||
id, | ||
stock_code, | ||
stock_name, | ||
price, | ||
amount, | ||
trade_type, | ||
created_at, | ||
} = order; | ||
|
||
return ( | ||
<li className='flex py-2' key={id}> | ||
<div className='flex w-1/3 gap-2 text-left truncate'> | ||
<p className='font-semibold'>{stock_name}</p> | ||
<p className='text-gray-500'>{stock_code}</p> | ||
</div> | ||
<p className='w-1/4 text-center'> | ||
{trade_type === 'BUY' ? '매수' : '매도'} | ||
</p> | ||
<p className='w-1/4 text-center truncate'>{amount}</p> | ||
<p className='w-1/4 text-center'>{price.toLocaleString()}원</p> | ||
<p className='w-1/4 text-right truncate'> | ||
{parseTimestamp(created_at)} | ||
</p> | ||
<p className='w-1/6 text-right'> | ||
<button | ||
onClick={() => handleCancelOrder(id)} | ||
className='px-2 py-1 text-xs text-white transition rounded-lg bg-juga-red-60 hover:bg-red-600' | ||
> | ||
취소 | ||
</button> | ||
</p> | ||
</li> | ||
); | ||
})} | ||
</ul> | ||
</div> | ||
); | ||
} |
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,145 @@ | ||
import { ChangeEvent, FocusEvent, FormEvent, useRef, useState } from 'react'; | ||
import useTradeAlertModalStore from 'store/tradeAlertModalStore'; | ||
import { StockDetailType } from 'types'; | ||
import { isNumericString } from 'utils/common'; | ||
import TradeAlertModal from './TradeAlertModal'; | ||
const MyAsset = 10000000; | ||
|
||
type BuySectionProps = { | ||
code: string; | ||
data: StockDetailType; | ||
}; | ||
|
||
export default function BuySection({ code, data }: BuySectionProps) { | ||
const { stck_prpr, stck_mxpr, stck_llam } = data; | ||
|
||
const [currPrice, setCurrPrice] = useState<string>(stck_prpr); | ||
|
||
const { isOpen, toggleModal } = useTradeAlertModalStore(); | ||
|
||
const [count, setCount] = useState<number>(0); | ||
|
||
const [upperLimitFlag, setUpperLimitFlag] = useState<boolean>(false); | ||
const [lowerLimitFlag, setLowerLimitFlag] = useState<boolean>(false); | ||
const [lackAssetFlag, setLackAssetFlag] = useState<boolean>(false); | ||
const timerRef = useRef<number | null>(null); | ||
|
||
const handlePriceChange = (e: ChangeEvent<HTMLInputElement>) => { | ||
if (!isNumericString(e.target.value)) return; | ||
|
||
setCurrPrice(e.target.value); | ||
}; | ||
|
||
const handlePriceInputBlur = (e: FocusEvent<HTMLInputElement>) => { | ||
const n = +e.target.value; | ||
if (n > +stck_mxpr) { | ||
if (timerRef.current) { | ||
clearTimeout(timerRef.current); | ||
} | ||
setCurrPrice(stck_mxpr); | ||
|
||
setUpperLimitFlag(true); | ||
timerRef.current = window.setTimeout(() => { | ||
setUpperLimitFlag(false); | ||
}, 2000); | ||
return; | ||
} | ||
|
||
if (n < +stck_llam) { | ||
if (timerRef.current) { | ||
clearTimeout(timerRef.current); | ||
} | ||
setCurrPrice(stck_llam); | ||
|
||
setLowerLimitFlag(true); | ||
timerRef.current = window.setTimeout(() => { | ||
setLowerLimitFlag(false); | ||
}, 2000); | ||
return; | ||
} | ||
}; | ||
|
||
const handleBuy = async (e: FormEvent<HTMLFormElement>) => { | ||
e.preventDefault(); | ||
|
||
const price = +currPrice * count; | ||
|
||
if (price > MyAsset) { | ||
setLackAssetFlag(true); | ||
timerRef.current = window.setTimeout(() => { | ||
setLackAssetFlag(false); | ||
}, 2000); | ||
return; | ||
} | ||
toggleModal(); | ||
}; | ||
|
||
return ( | ||
<> | ||
<form className='flex flex-col' onSubmit={handleBuy}> | ||
<div className='my-4'> | ||
<div className='flex items-center justify-between h-12'> | ||
<p className='mr-3 w-14'>매수 가격</p> | ||
<input | ||
type='text' | ||
value={currPrice} | ||
onChange={handlePriceChange} | ||
onBlur={handlePriceInputBlur} | ||
className='flex-1 py-1 rounded-lg' | ||
/> | ||
</div> | ||
{lowerLimitFlag && ( | ||
<div className='text-sm text-juga-red-60'> | ||
이 주식의 최소 가격은 {(+stck_llam).toLocaleString()}입니다. | ||
</div> | ||
)} | ||
{upperLimitFlag && ( | ||
<div className='text-xs text-juga-red-60'> | ||
이 주식의 최대 가격은 {(+stck_mxpr).toLocaleString()}입니다. | ||
</div> | ||
)} | ||
<div className='flex items-center justify-between h-12'> | ||
<p className='mr-3 w-14'> 수량</p> | ||
<input | ||
type='number' | ||
value={count} | ||
onChange={(e) => setCount(+e.target.value)} | ||
className='flex-1 py-1 rounded-lg' | ||
min={1} | ||
/> | ||
</div> | ||
</div> | ||
|
||
<div className='my-5 h-[0.5px] w-full bg-juga-grayscale-200'></div> | ||
|
||
<div className='flex flex-col gap-2'> | ||
<div className='flex justify-between'> | ||
<p>매수 가능 금액</p> | ||
<p>0원</p> | ||
</div> | ||
<div className='flex justify-between'> | ||
<p>총 주문 금액</p> | ||
<p>{(+currPrice * count).toLocaleString()}원</p> | ||
</div> | ||
</div> | ||
|
||
<div className='flex flex-col justify-center h-10'> | ||
{lackAssetFlag && ( | ||
<p className='text-xs text-juga-red-60'>잔액이 부족해요!</p> | ||
)} | ||
</div> | ||
<button className='py-2 text-white rounded-lg bg-juga-red-60'> | ||
매수하기 | ||
</button> | ||
</form> | ||
{isOpen && ( | ||
<TradeAlertModal | ||
code={code} | ||
stockName={data.hts_kor_isnm} | ||
price={currPrice} | ||
count={count} | ||
/> | ||
)} | ||
</> | ||
); | ||
} |
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,15 @@ | ||
import Lottie from 'lottie-react'; | ||
import emptyAnimation from 'assets/emptyAnimation.json'; | ||
|
||
export default function SellSection() { | ||
return ( | ||
<div className='flex flex-col items-center justify-center h-full'> | ||
<Lottie | ||
animationData={emptyAnimation} | ||
className='w-40 h-40' | ||
loop={false} | ||
/> | ||
<p>매도할 주식이 없어요</p> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.