add recent market trades box

This commit is contained in:
Tyler Shipe 2021-04-05 16:48:24 -04:00
parent 45e278e331
commit ac631f1fd5
10 changed files with 138 additions and 79 deletions

View File

@ -135,7 +135,7 @@ export interface SelectedTokenAccounts {
[tokenMint: string]: string
}
export interface ChartType {
export interface ChartTradeType {
market: string
size: number
price: number

View File

@ -8,9 +8,7 @@ const Wrapper = styled.div`
export default function FloatingElement({ css = undefined, children }) {
return (
<Wrapper
css={xw`m-1 px-2 py-4 h-full bg-mango-dark rounded-lg overflow-auto`}
>
<Wrapper css={xw`m-1 p-4 h-full bg-mango-dark rounded-lg overflow-auto`}>
{children}
</Wrapper>
)

View File

@ -154,30 +154,17 @@ export default function MarginInfo() {
return (
<FloatingElement>
<React.Fragment>
{mAccountInfo ? (
mAccountInfo.map((entry, i) => (
<Row key={i} justify="space-between" style={{ padding: '4px' }}>
<Popover content={entry.desc} placement="topLeft" trigger="hover">
<div>
<Text ellipsis={true} style={{ cursor: 'help' }}>
{entry.label}
</Text>
</div>
</Popover>
<div>
<Text strong>
{entry.currency + entry.value}
{entry.unit}
</Text>
</div>
</Row>
))
) : (
<div css={xw`flex align-middle justify-center`}>
{/* <BalanceCol></BalanceCol> */}
Connect Wallet
{mAccountInfo.map((entry, i) => (
<div css={xw`flex justify-between pt-2 pb-3`} key={i}>
<Popover content={entry.desc} placement="topLeft" trigger="hover">
<div css={xw`cursor-help text-gray-300`}>{entry.label}</div>
</Popover>
<div css={xw`text-gray-300 font-light`}>
{entry.currency + entry.value}
{entry.unit}
</div>
</div>
)}
))}
</React.Fragment>
</FloatingElement>
)

View File

@ -8,6 +8,7 @@ import { ArrowUpIcon, ArrowDownIcon } from '@heroicons/react/solid'
import useMarkPrice from '../hooks/useMarkPrice'
import useOrderbook from '../hooks/useOrderbook'
import useMarkets from '../hooks/useMarkets'
import { ElementTitle } from './styles'
const Line = styled.div<any>`
text-align: ${(props) => (props.invert ? 'left' : 'right')};
@ -18,15 +19,7 @@ const Line = styled.div<any>`
props['data-bgcolor'] && `background-color: ${props['data-bgcolor']};`}
`
// const Price = styled.div<any>`
// position: absolute;
// ${(props) => (props.invert ? `left: 5px;` : `right: 15px;`)}
// ${(props) => props['data-color'] && `color: ${props['data-color']};`}
// `
export default function Orderbook({ depth = 7 }) {
// TODO remove smallScreen
const smallScreen = false
const markPrice = useMarkPrice()
const [orderbook] = useOrderbook()
const { baseCurrency, quoteCurrency } = useMarkets()
@ -89,36 +82,34 @@ export default function Orderbook({ depth = 7 }) {
return (
<>
<div css={xw`flex justify-center pb-1 text-lg font-light`}>Orderbook</div>
<>
<div css={xw`text-gray-500 flex justify-between mb-4`}>
<div css={xw`text-left`}>Size ({baseCurrency})</div>
<div css={xw`text-right`}>Price ({quoteCurrency})</div>
</div>
{orderbookData?.asks.map(({ price, size, sizePercent }) => (
<OrderbookRow
key={price + ''}
price={price}
size={size}
side={'sell'}
sizePercent={sizePercent}
onPriceClick={() => alert(`price ${price}`)}
onSizeClick={() => alert(`size ${size}`)}
/>
))}
<MarkPriceComponent markPrice={markPrice} />
{orderbookData?.bids.map(({ price, size, sizePercent }) => (
<OrderbookRow
key={price + ''}
price={price}
size={size}
side={'buy'}
sizePercent={sizePercent}
onPriceClick={() => alert(`price ${price}`)}
onSizeClick={() => alert(`size ${size}`)}
/>
))}
</>
<ElementTitle>Orderbook</ElementTitle>
<div css={xw`text-gray-500 flex justify-between mb-2`}>
<div css={xw`text-left`}>Size ({baseCurrency})</div>
<div css={xw`text-right`}>Price ({quoteCurrency})</div>
</div>
{orderbookData?.asks.map(({ price, size, sizePercent }) => (
<OrderbookRow
key={price + ''}
price={price}
size={size}
side={'sell'}
sizePercent={sizePercent}
onPriceClick={() => alert(`price ${price}`)}
onSizeClick={() => alert(`size ${size}`)}
/>
))}
<MarkPriceComponent markPrice={markPrice} />
{orderbookData?.bids.map(({ price, size, sizePercent }) => (
<OrderbookRow
key={price + ''}
price={price}
size={size}
side={'buy'}
sizePercent={sizePercent}
onPriceClick={() => alert(`price ${price}`)}
onSizeClick={() => alert(`size ${size}`)}
/>
))}
</>
)
}
@ -152,7 +143,7 @@ const OrderbookRow = React.memo<any>(
return (
<div
css={xw`flex justify-between font-light`}
css={xw`flex mb-0.5 justify-between font-light`}
ref={element}
onClick={onSizeClick}
>
@ -176,7 +167,7 @@ const OrderbookRow = React.memo<any>(
</>
) : (
<>
<div css={xw`text-left flex-1`}>{formattedSize}</div>
<div css={xw`text-left flex-1 text-gray-200`}>{formattedSize}</div>
<div css={xw`text-right relative flex-1`}>
<Line
css={xw`absolute inset-y-0 right-0`}
@ -184,7 +175,7 @@ const OrderbookRow = React.memo<any>(
data-bgcolor={side === 'buy' ? '#5b6b16' : '#E54033'}
/>
<div
css={xw`z-30 relative`}
css={xw`z-30 relative text-gray-200`}
data-color={side === 'buy' ? '#ffffff' : 'white'}
onClick={onPriceClick}
>

View File

@ -0,0 +1,60 @@
import { useState } from 'react'
// import styled from '@emotion/styled'
import xw from 'xwind'
import { getDecimalCount } from '../utils'
import { ChartTradeType } from '../@types/types'
import FloatingElement from './FloatingElement'
import useMarkets from '../hooks/useMarkets'
import useInterval from '../hooks/useInterval'
import ChartApi from '../utils/chartDataConnector'
import { ElementTitle } from './styles'
export default function PublicTrades() {
const { baseCurrency, quoteCurrency, market, marketAddress } = useMarkets()
const [trades, setTrades] = useState([])
useInterval(async () => {
const trades = await ChartApi.getRecentTrades(marketAddress)
setTrades(trades)
}, 5000)
return (
<FloatingElement>
<ElementTitle>Recent Market Trades</ElementTitle>
<div css={xw`grid grid-cols-3 text-gray-500 font-light mb-2`}>
<div>Price ({quoteCurrency}) </div>
<div css={xw`text-right`}>Size ({baseCurrency})</div>
<div css={xw`text-right`}>Time</div>
</div>
{!!trades.length && (
<div>
{trades.map((trade: ChartTradeType, i: number) => (
<div key={i} css={xw`mb-2 font-light grid grid-cols-3`}>
<div
style={{
color: trade.side === 'buy' ? '#AFD803' : '#E54033',
}}
>
{market?.tickSize && !isNaN(trade.price)
? Number(trade.price).toFixed(
getDecimalCount(market.tickSize)
)
: trade.price}
</div>
<div css={xw`text-right`}>
{market?.minOrderSize && !isNaN(trade.size)
? Number(trade.size).toFixed(
getDecimalCount(market.minOrderSize)
)
: trade.size}
</div>
<div css={xw`text-right text-gray-500`}>
{trade.time && new Date(trade.time).toLocaleTimeString()}
</div>
</div>
))}
</div>
)}
</FloatingElement>
)
}

View File

@ -11,6 +11,7 @@ import Orderbook from '../components/Orderbook'
import MarginInfo from './MarginInfo'
import TradeForm from './TradeForm'
import UserInfo from './UserInfo'
import RecentMarketTrades from './RecentMarketTrades'
const ResponsiveGridLayout = WidthProvider(Responsive)
@ -20,18 +21,18 @@ const layouts = {
{ i: 'orderbook', x: 3, y: 0, w: 1, h: 17 },
{ i: 'tradeForm', x: 4, y: 0, w: 1, h: 17 },
{ i: 'marginInfo', x: 4, y: 1, w: 1, h: 13 },
{ i: 'useInfo', x: 0, y: 2, w: 3, h: 13 },
{ i: 'balanceInfo', x: 3, y: 2, w: 1, h: 13 },
{ i: 'extraInfo2', x: 4, y: 2, w: 1, h: 13 },
{ i: 'userInfo', x: 0, y: 2, w: 3, h: 13 },
{ i: 'marketTrades', x: 3, y: 2, w: 1, h: 13 },
{ i: 'balanceInfo', x: 4, y: 2, w: 1, h: 13 },
],
lg: [
{ i: 'tvChart', x: 0, y: 0, w: 2, h: 30 },
{ i: 'orderbook', x: 2, y: 0, w: 1, h: 17 },
{ i: 'tradeForm', x: 3, y: 0, w: 1, h: 17 },
{ i: 'marginInfo', x: 3, y: 1, w: 1, h: 13 },
{ i: 'useInfo', x: 0, y: 2, w: 2, h: 13 },
{ i: 'balanceInfo', x: 2, y: 2, w: 1, h: 13 },
{ i: 'extraInfo2', x: 3, y: 2, w: 1, h: 13 },
{ i: 'userInfo', x: 0, y: 2, w: 2, h: 13 },
{ i: 'marketTrades', x: 2, y: 2, w: 1, h: 13 },
{ i: 'balanceInfo', x: 3, y: 2, w: 1, h: 13 },
],
}
@ -60,11 +61,13 @@ const TradePageGrid = () => {
<div key="marginInfo">
<MarginInfo />
</div>
<div key="useInfo">
<div key="userInfo">
<UserInfo />
</div>
<div key="balanceInfo">6</div>
<div key="extraInfo2">7</div>
<div key="marketTrades">
<RecentMarketTrades />
</div>
</ResponsiveGridLayout>
)
}

6
components/styles.tsx Normal file
View File

@ -0,0 +1,6 @@
import styled from '@emotion/styled'
import xw from 'xwind'
export const ElementTitle = styled.div(xw`
flex justify-center mb-4 text-lg tracking-tight
`)

View File

@ -19,6 +19,10 @@ const useMarkets = () => {
const mangoGroupName = useMangoStore((state) => state.selectedMangoGroup.name)
const market = useMangoStore((state) => state.market.current)
const { connection, cluster, programId, dexProgramId } = useConnection()
const marketAddress = useMemo(
() => (market ? market.publicKey.toString() : null),
[market]
)
const spotMarkets = useMemo(
() => IDS[cluster]?.mango_groups[mangoGroupName]?.spot_market_symbols || {},
@ -89,7 +93,14 @@ const useMarkets = () => {
[market, TOKEN_MINTS]
)
return { market, programId, marketList, baseCurrency, quoteCurrency }
return {
market,
marketAddress,
programId,
marketList,
baseCurrency,
quoteCurrency,
}
}
export default useMarkets

View File

@ -5,6 +5,9 @@ module.exports = {
darkMode: 'class',
theme: {
extend: {
cursor: {
help: 'help',
},
fontFamily: {
sans: ['Lato', ...defaultTheme.fontFamily.sans],
},

View File

@ -1,4 +1,4 @@
import { ChartType } from '../@types/types'
import { ChartTradeType } from '../@types/types'
const baseUrl = 'https://serum-history.herokuapp.com'
export default class ChartApi {
@ -19,7 +19,7 @@ export default class ChartApi {
static async getRecentTrades(
marketAddress: string
): Promise<ChartType[] | null> {
): Promise<ChartTradeType[] | null> {
return ChartApi.get(`trades/address/${marketAddress}`)
}
}