mango-ui-v3/components/TradeHistoryTable.tsx

413 lines
17 KiB
TypeScript
Raw Normal View History

import { ArrowSmDownIcon } from '@heroicons/react/solid'
2021-07-24 11:12:52 -07:00
import BN from 'bn.js'
2021-04-12 21:40:26 -07:00
import useTradeHistory from '../hooks/useTradeHistory'
import Link from 'next/link'
import { useRouter } from 'next/router'
import SideBadge from './SideBadge'
import { LinkButton } from './Button'
import { useSortableData } from '../hooks/useSortableData'
2021-09-07 21:12:49 -07:00
import { useViewport } from '../hooks/useViewport'
import { breakpoints } from './TradePageGrid'
import { Table, Td, Th, TrBody, TrHead } from './TableElements'
import { ExpandableRow } from './TableElements'
import { formatUsdValue } from '../utils'
import { useTranslation } from 'next-i18next'
import Pagination from './Pagination'
import usePagination from '../hooks/usePagination'
2022-01-19 15:43:50 -08:00
import { useEffect } from 'react'
const renderTradeDateTime = (timestamp: BN | string) => {
let date
// don't compare to BN because of npm maddness
// prototypes can be different due to multiple versions being imported
if (typeof timestamp === 'string') {
date = new Date(timestamp)
} else {
date = new Date(timestamp.toNumber() * 1000)
}
return (
<>
<div>{date.toLocaleDateString()}</div>
<div className="text-xs text-th-fgd-3">{date.toLocaleTimeString()}</div>
</>
)
}
2021-09-13 09:40:28 -07:00
const TradeHistoryTable = ({ numTrades }: { numTrades?: number }) => {
const { t } = useTranslation('common')
const { asPath } = useRouter()
const tradeHistory = useTradeHistory({ excludePerpLiquidations: true })
2021-09-07 21:12:49 -07:00
const { width } = useViewport()
const isMobile = width ? width < breakpoints.md : false
const {
paginatedData,
totalPages,
nextPage,
previousPage,
page,
firstPage,
lastPage,
2022-01-19 15:43:50 -08:00
setData,
data,
} = usePagination(tradeHistory || [], { perPage: 100 })
const { items, requestSort, sortConfig } = useSortableData(paginatedData)
useEffect(() => {
if (tradeHistory?.length && data?.length !== tradeHistory?.length) {
setData(tradeHistory)
}
}, [tradeHistory])
const renderMarketName = (trade: any) => {
2021-12-03 08:48:10 -08:00
if (
trade.marketName.includes('PERP') ||
trade.marketName.includes('USDC')
) {
2022-01-31 09:48:48 -08:00
const location = `/?name=${trade.marketName}`
2021-12-03 08:48:10 -08:00
if (asPath.includes(location)) {
return <span>{trade.marketName}</span>
} else {
return (
<Link href={location} shallow={true}>
<a className="text-th-fgd-1 underline hover:no-underline hover:text-th-fgd-1">
{trade.marketName}
</a>
</Link>
)
}
} else {
return <span>{trade.marketName}</span>
}
}
return (
2021-12-07 20:00:02 -08:00
<div className={`flex flex-col sm:pb-4`}>
<div className={`overflow-x-auto sm:-mx-6 lg:-mx-8`}>
2021-09-20 05:24:42 -07:00
<div className={`align-middle inline-block min-w-full sm:px-6 lg:px-8`}>
2021-04-13 09:57:58 -07:00
{tradeHistory && tradeHistory.length ? (
2021-09-07 21:12:49 -07:00
!isMobile ? (
<>
<Table>
<thead>
<TrHead>
<Th>
<LinkButton
className="flex items-center no-underline font-normal"
onClick={() => requestSort('market')}
>
{t('market')}
<ArrowSmDownIcon
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
sortConfig?.key === 'market'
? sortConfig.direction === 'ascending'
? 'transform rotate-180'
: 'transform rotate-360'
: null
}`}
/>
</LinkButton>
</Th>
<Th>
<LinkButton
className="flex items-center no-underline font-normal"
onClick={() => requestSort('side')}
>
{t('side')}
<ArrowSmDownIcon
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
sortConfig?.key === 'side'
? sortConfig.direction === 'ascending'
? 'transform rotate-180'
: 'transform rotate-360'
: null
}`}
/>
</LinkButton>
</Th>
<Th>
<LinkButton
className="flex items-center no-underline font-normal"
onClick={() => requestSort('size')}
>
{t('size')}
<ArrowSmDownIcon
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
sortConfig?.key === 'size'
? sortConfig.direction === 'ascending'
? 'transform rotate-180'
: 'transform rotate-360'
: null
}`}
/>
</LinkButton>
</Th>
<Th>
<LinkButton
className="flex items-center no-underline font-normal"
onClick={() => requestSort('price')}
>
{t('price')}
<ArrowSmDownIcon
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
sortConfig?.key === 'price'
? sortConfig.direction === 'ascending'
? 'transform rotate-180'
: 'transform rotate-360'
: null
}`}
/>
</LinkButton>
</Th>
<Th>
<LinkButton
className="flex items-center no-underline font-normal"
onClick={() => requestSort('value')}
>
{t('value')}
<ArrowSmDownIcon
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
sortConfig?.key === 'value'
? sortConfig.direction === 'ascending'
? 'transform rotate-180'
: 'transform rotate-360'
: null
}`}
/>
</LinkButton>
</Th>
<Th>
<LinkButton
className="flex items-center no-underline font-normal"
onClick={() => requestSort('liquidity')}
>
{t('liquidity')}
<ArrowSmDownIcon
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
sortConfig?.key === 'liquidity'
? sortConfig.direction === 'ascending'
? 'transform rotate-180'
: 'transform rotate-360'
: null
}`}
/>
</LinkButton>
</Th>
<Th>
<LinkButton
className="flex items-center no-underline font-normal"
onClick={() => requestSort('feeCost')}
>
{t('fee')}
<ArrowSmDownIcon
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
sortConfig?.key === 'feeCost'
? sortConfig.direction === 'ascending'
? 'transform rotate-180'
: 'transform rotate-360'
: null
}`}
/>
</LinkButton>
</Th>
<Th>
<LinkButton
className="flex items-center no-underline font-normal"
onClick={() => requestSort('loadTimestamp')}
>
{t('approximate-time')}
<ArrowSmDownIcon
className={`default-transition flex-shrink-0 h-4 w-4 ml-1 ${
sortConfig?.key === 'loadTimestamp'
? sortConfig.direction === 'ascending'
? 'transform rotate-180'
: 'transform rotate-360'
: null
}`}
/>
</LinkButton>
</Th>
2022-01-19 13:35:53 -08:00
<Th> </Th>
</TrHead>
</thead>
<tbody>
{paginatedData.map((trade: any, index) => {
return (
<TrBody
index={index}
key={`${trade.seqNum}${trade.marketName}`}
>
<Td className="!py-2 ">
<div className="flex items-center">
<img
alt=""
width="20"
height="20"
src={`/assets/icons/${trade.marketName
.split(/-|\//)[0]
.toLowerCase()}.svg`}
className={`mr-2.5`}
/>
{renderMarketName(trade)}
</div>
</Td>
<Td className="!py-2 ">
<SideBadge side={trade.side} />
</Td>
<Td className="!py-2 ">{trade.size}</Td>
<Td className="!py-2 ">
$
{new Intl.NumberFormat('en-US').format(trade.price)}
</Td>
<Td className="!py-2 ">
{formatUsdValue(trade.value)}
</Td>
<Td className="!py-2 ">{trade.liquidity}</Td>
<Td className="!py-2 ">
{formatUsdValue(trade.feeCost)}
</Td>
<Td className="!py-2 w-[0.1%]">
{trade.loadTimestamp || trade.timestamp
? renderTradeDateTime(
trade.loadTimestamp || trade.timestamp
)
: t('recent')}
</Td>
<Td className="!py-2 w-[0.1%]">
2022-01-19 13:35:53 -08:00
{trade.marketName.includes('PERP') ? (
<a
className="text-th-fgd-4 underline text-xs underline-offset-4"
target="_blank"
rel="noopener noreferrer"
href={`/account?pubkey=${
trade.liquidity === 'Taker'
? trade.maker
: trade.taker
}`}
>
View Counterparty
</a>
) : null}
</Td>
</TrBody>
)
})}
</tbody>
</Table>
{numTrades && items.length > numTrades ? (
<div className="flex items-center justify-center mt-4">
<Link href="/account" shallow={true}>
{t('view-all-trades')}
</Link>
</div>
) : (
<div className="flex items-center justify-end">
<Pagination
page={page}
totalPages={totalPages}
nextPage={nextPage}
lastPage={lastPage}
firstPage={firstPage}
previousPage={previousPage}
/>
</div>
)}
</>
2021-09-07 21:12:49 -07:00
) : (
paginatedData.map((trade: any, index) => (
<ExpandableRow
buttonTemplate={
<>
<div className="flex items-center justify-between text-fgd-1 w-full">
2021-11-05 02:55:16 -07:00
<div className="text-left">
{trade.loadTimestamp || trade.timestamp
? renderTradeDateTime(
trade.loadTimestamp || trade.timestamp
)
: t('recent')}
</div>
<div>
<div className="text-right">
<div className="flex items-center mb-0.5 text-left">
<img
alt=""
width="16"
height="16"
src={`/assets/icons/${trade.marketName
.split(/-|\//)[0]
.toLowerCase()}.svg`}
className={`mr-1.5`}
/>
{trade.marketName}
</div>
<div className="text-th-fgd-3 text-xs">
<span
className={`mr-1
2021-09-07 21:12:49 -07:00
${
trade.side === 'buy' || trade.side === 'long'
? 'text-th-green'
: 'text-th-red'
}
`}
>
{trade.side.toUpperCase()}
</span>
2021-11-05 02:55:16 -07:00
{trade.size}
2021-09-07 21:12:49 -07:00
</div>
</div>
</div>
</div>
</>
}
key={`${index}`}
index={index}
panelTemplate={
<div className="grid grid-cols-2 grid-flow-row gap-4">
2021-11-05 02:55:16 -07:00
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('price')}
</div>
{formatUsdValue(trade.price)}
</div>
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('value')}
2021-09-07 21:12:49 -07:00
</div>
{formatUsdValue(trade.value)}
</div>
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('liquidity')}
2021-09-07 21:12:49 -07:00
</div>
{trade.liquidity}
</div>
<div className="text-left">
<div className="pb-0.5 text-th-fgd-3 text-xs">
{t('fee')}
</div>
{formatUsdValue(trade.feeCost)}
</div>
</div>
}
/>
))
2021-09-07 21:12:49 -07:00
)
) : (
2021-07-24 13:15:27 -07:00
<div className="w-full text-center py-6 bg-th-bkg-1 text-th-fgd-3 rounded-md">
{t('no-history')}
{asPath === '/account' ? (
2021-11-14 06:48:09 -08:00
<Link href={'/'} shallow={true}>
<a className="inline-flex ml-2 py-0">{t('make-trade')}</a>
</Link>
) : null}
</div>
)}
</div>
</div>
</div>
)
}
export default TradeHistoryTable