Skip to content

Commit

Permalink
feat: limit order book for all chains (#2515)
Browse files Browse the repository at this point in the history
* feat: limit order book for all chains

* remove Map.groupBy by self-implement func

* re-add object type

* responsive for mobile

* chain API endpoint

* fix issue displaying number 0 when change chain

* fix some element tag and make some code easier to understand

* fix floating point issues

* fix bug fetch orders get into error but data doesn't reset

* show loading at lease time for refresh loading

* fix rate logic

* add logic caculate amount due to different chain decimals and refactor format order logic

* fix rate logic in below scope

* remove bracket on table header when maker and taker does not exist

* fix navigate link when click on order in my order page

---------

Co-authored-by: Tien Nguyen <tiennguyen@Nguyens-MacBook-Pro-4.local>
  • Loading branch information
tienkane and Tien Nguyen authored Aug 29, 2024
1 parent c5c0a05 commit 6a6f8de
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'
import styled, { css, keyframes } from 'styled-components'

import useDebounce from 'hooks/useDebounce'
import useShowLoadingAtLeastTime from 'hooks/useShowLoadingAtLeastTime'
import useTheme from 'hooks/useTheme'

const INTERVAL_REFETCH_TIME = 10 // seconds
Expand Down Expand Up @@ -104,11 +105,12 @@ export default function RefreshLoading({
const [countdown, setCountdown] = useState(0)

const debouncedRefetchLoading = useDebounce(refetchLoading, 100)
const showLoadingAtLeastTime = useShowLoadingAtLeastTime(debouncedRefetchLoading, 200)

useEffect(() => {
if (!refetchLoading && !debouncedRefetchLoading) setCountdown(INTERVAL_REFETCH_TIME * 1_000)
else if (refetchLoading && debouncedRefetchLoading) setCountdown(0)
}, [refetchLoading, debouncedRefetchLoading])
if (!refetchLoading && !showLoadingAtLeastTime) setCountdown(INTERVAL_REFETCH_TIME * 1_000)
else if (refetchLoading && showLoadingAtLeastTime) setCountdown(0)
}, [refetchLoading, showLoadingAtLeastTime])

useEffect(() => {
if (countdown > 0) {
Expand Down
50 changes: 45 additions & 5 deletions src/components/swapv2/LimitOrder/OrderBook/OrderItem.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Currency } from '@kyberswap/ks-sdk-core'
import { useMemo } from 'react'
import { useMedia } from 'react-use'
import { Flex, Text } from 'rebass'
import styled, { CSSProperties } from 'styled-components'

import CurrencyLogo from 'components/CurrencyLogo'
import useChainsConfig from 'hooks/useChainsConfig'
import useTheme from 'hooks/useTheme'
import { useLimitState } from 'state/limit/hooks'
import { MEDIA_WIDTHS } from 'theme'
Expand All @@ -14,14 +16,22 @@ export const ItemWrapper = styled.div`
font-size: 14px;
line-height: 20px;
display: grid;
grid-template-columns: 2fr 2fr 2fr 1fr;
grid-template-columns: 1fr 2fr 2fr 2fr 1fr;
padding: 12px;
${({ theme }) => theme.mediaWidth.upToSmall`
grid-template-columns: 1.6fr 2fr 2fr 1fr;
grid-template-columns: 1.2fr 1.8fr 2fr 1fr;
`}
`

export const ChainImage = styled.img`
height: 16px;
width: 16px;
position: relative;
top: 2px;
left: 10px;
`

const Rate = styled.div<{ reverse?: boolean }>`
color: ${({ theme, reverse }) => (reverse ? theme.primary : theme.red)};
`
Expand All @@ -48,20 +58,50 @@ export default function OrderItem({
reverse,
order,
style,
showAmountOut,
}: {
reverse?: boolean
order: LimitOrderFromTokenPairFormatted
style: CSSProperties
showAmountOut: boolean
}) {
const theme = useTheme()
const upToSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToSmall}px)`)
const { currencyIn, currencyOut } = useLimitState()
const { currencyIn: makerCurrency, currencyOut: takerCurrency } = useLimitState()
const { supportedChains } = useChainsConfig()

const chain = useMemo(
() => supportedChains.find(chain => chain.chainId === order.chainId),
[order.chainId, supportedChains],
)

return (
<ItemWrapper style={style}>
<ChainImage src={chain?.icon} alt="Network" />
<Rate reverse={reverse}>{order.rate}</Rate>
<AmountInfo plus={reverse} amount={order.firstAmount} currency={currencyIn} upToSmall={upToSmall} />
<AmountInfo plus={!reverse} amount={order.secondAmount} currency={currencyOut} upToSmall={upToSmall} />
{!upToSmall ? (
<>
<AmountInfo
plus={reverse}
amount={order[!reverse ? 'makerAmount' : 'takerAmount']}
currency={makerCurrency}
upToSmall={upToSmall}
/>
<AmountInfo
plus={!reverse}
amount={order[!reverse ? 'takerAmount' : 'makerAmount']}
currency={takerCurrency}
upToSmall={upToSmall}
/>
</>
) : (
<AmountInfo
plus={showAmountOut ? !reverse : reverse}
amount={(showAmountOut && !reverse) || (!showAmountOut && reverse) ? order.takerAmount : order.makerAmount}
currency={showAmountOut ? takerCurrency : makerCurrency}
upToSmall={upToSmall}
/>
)}
<Text color={theme.subText}>
{!upToSmall && 'Filled '}
{order.filled}%
Expand Down
109 changes: 93 additions & 16 deletions src/components/swapv2/LimitOrder/OrderBook/TableHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Trans } from '@lingui/macro'
import { rgba } from 'polished'
import { useState } from 'react'
import { useMedia } from 'react-use'
import { Text } from 'rebass'
import { Flex, Text } from 'rebass'
import styled from 'styled-components'

import { ReactComponent as DropdownSvg } from 'assets/svg/down.svg'
import { useLimitState } from 'state/limit/hooks'
import { MEDIA_WIDTHS } from 'theme'

Expand All @@ -17,32 +19,107 @@ const Header = styled(ItemWrapper)`
font-weight: 500;
padding: 16px 12px;
cursor: default;
:hover {
/* :hover {
background-color: ${({ theme }) => rgba(theme.primary, 0.2)};
}
} */
`

export default function TableHeader() {
const DropdownIcon = styled(DropdownSvg)<{ open: boolean }>`
color: ${({ theme }) => theme.subText};
transform: rotate(${({ open }) => (open ? '180deg' : '0')});
transition: transform 300ms;
min-width: 24px;
`

const TabWrapper = styled.div`
overflow: hidden;
transition: 0.3s ease-in-out;
position: relative;
left: -14px;
`

const TabContainer = styled.div`
display: flex;
background: ${({ theme }) => theme.buttonBlack};
border: ${({ theme }) => `1px solid ${theme.border}`};
width: fit-content;
border-radius: 999px;
padding: 1px;
margin-top: 12px;
`

const TabItem = styled(Flex)<{ active?: boolean }>`
padding: 4px 8px;
align-items: center;
border-radius: 999px;
background: ${({ theme, active }) => (active ? theme.tabActive : 'transparent')};
color: ${({ theme, active }) => (active ? theme.text : theme.subText)};
transition: 0.2s ease-in-out;
`

export default function TableHeader({
showAmountOut,
setShowAmountOut,
}: {
showAmountOut: boolean
setShowAmountOut: (value: boolean) => void
}) {
const upToSmall = useMedia(`(max-width: ${MEDIA_WIDTHS.upToSmall}px)`)
const { currencyIn, currencyOut } = useLimitState()
const [openDropdown, setOpenDropdown] = useState<boolean>(false)

const onClickDropdown = () => setOpenDropdown(!openDropdown)
const onChangeDisplayedAmount = () => setShowAmountOut(!showAmountOut)

return (
<Header>
<Text>CHAIN</Text>
<Text>
<Trans>RATE</Trans>
{upToSmall ? <br /> : ' '}(<span>{currencyIn?.symbol || ''}/</span>
<span>{currencyOut?.symbol || ''}</span>)
</Text>
<Text>
<Trans>AMOUNT</Trans>
{upToSmall ? <br /> : ' '}
<Trans>({currencyIn?.symbol})</Trans>
</Text>
<Text>
<Trans>AMOUNT</Trans>
{upToSmall ? <br /> : ' '}
<Trans>({currencyOut?.symbol})</Trans>
{!!currencyIn && !!currencyOut && (
<>
{upToSmall ? <br /> : ' '}(<span>{currencyIn?.symbol}/</span>
<span>{currencyOut?.symbol}</span>)
</>
)}
</Text>
{!upToSmall && (
<Text>
<Trans>AMOUNT</Trans>
{!!currencyIn && (
<>
{upToSmall ? <br /> : ' '}
<span>({currencyIn?.symbol})</span>
</>
)}
</Text>
)}
<div>
<Flex>
<Text>
<Trans>AMOUNT</Trans>
{!!currencyIn && !!currencyOut && (
<>
{upToSmall ? <br /> : ' '}
<span>({!upToSmall || showAmountOut ? currencyOut?.symbol : currencyIn?.symbol})</span>
</>
)}
</Text>
{upToSmall && <DropdownIcon open={openDropdown} onClick={onClickDropdown} />}
</Flex>
{upToSmall && (
<TabWrapper style={{ height: openDropdown ? 40 : 0 }}>
<TabContainer>
<TabItem active={!showAmountOut} onClick={onChangeDisplayedAmount}>
{currencyIn?.symbol}
</TabItem>
<TabItem active={showAmountOut} onClick={onChangeDisplayedAmount}>
{currencyOut?.symbol}
</TabItem>{' '}
</TabContainer>
</TabWrapper>
)}
</div>
<Text>
<Trans>ORDER STATUS</Trans>
</Text>
Expand Down
Loading

0 comments on commit 6a6f8de

Please sign in to comment.