Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: trident analytics #848

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/components/Header/useMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,27 @@ const useMenu: UseMenu = () => {
}

if (featureEnabled(Feature.ANALYTICS, chainId)) {
if (featureEnabled(Feature.TRIDENT, chainId)) {
analyticsMenu.items.push({
key: 'trident',
title: 'Trident',
link: `/analytics/trident`,
})
}
menu.push(analyticsMenu)
} else if (featureEnabled(Feature.TRIDENT, chainId)) {
menu.push({
key: 'analytics',
title: i18n._(t`Analytics`),
icon: <TrendingUpIcon width={20} />,
items: [
{
key: 'trident',
title: 'Trident',
link: `/analytics/trident`,
},
],
})
}

if (account) {
Expand Down
124 changes: 124 additions & 0 deletions src/features/analytics/trident/SearchResultTokens.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { ArrowDownIcon, ArrowUpIcon } from '@heroicons/react/solid'
import { TablePageToggler } from 'app/features/transactions/TablePageToggler'
import {
TABLE_TABLE_CLASSNAME,
TABLE_TBODY_TD_CLASSNAME,
TABLE_TBODY_TR_CLASSNAME,
TABLE_TR_TH_CLASSNAME,
TABLE_WRAPPER_DIV_CLASSNAME,
} from 'app/features/trident/constants'
import Link from 'next/link'
import React, { FC } from 'react'
// @ts-ignore TYPE NEEDS FIXING
import { useFilters, useFlexLayout, usePagination, useSortBy, useTable } from 'react-table'

import { SearchCategoryLabel } from '../tokens/SearchCategoryLabel'
import { useInstantiateTableFeatures } from './useInstantiateTableFeatures'
import { useTokensTableConfig } from './useTokensTableConfig'

const SearchResultTokens: FC<{ chainId: number }> = ({ chainId }) => {
const { config } = useTokensTableConfig(chainId)

const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
// @ts-ignore TYPE NEEDS FIXING
page,
// @ts-ignore TYPE NEEDS FIXING
gotoPage,
// @ts-ignore TYPE NEEDS FIXING
canPreviousPage,
// @ts-ignore TYPE NEEDS FIXING
canNextPage,
// @ts-ignore TYPE NEEDS FIXING
prepareRow,
// @ts-ignore TYPE NEEDS FIXING
setFilter,
// @ts-ignore TYPE NEEDS FIXING
// toggleSortBy,
// @ts-ignore TYPE NEEDS FIXING
state: { pageIndex, pageSize },
// @ts-ignore TYPE NEEDS FIXING
} = useTable(config, useFlexLayout, useFilters, useSortBy, useFlexLayout, usePagination)
useInstantiateTableFeatures(setFilter)
return (
<div className="flex flex-col gap-2">
<SearchCategoryLabel />
<div className={TABLE_WRAPPER_DIV_CLASSNAME}>
<table {...getTableProps()} className={TABLE_TABLE_CLASSNAME}>
<thead>
{headerGroups.map((headerGroup, i) => (
<tr {...headerGroup.getHeaderGroupProps()} key={i}>
{headerGroup.headers.map((column, i) => (
<th
// @ts-ignore TYPE NEEDS FIXING
{...column.getHeaderProps(column.getSortByToggleProps())}
key={i}
className={TABLE_TR_TH_CLASSNAME(i, headerGroup.headers.length)}
>
{column.render('Header')}
<span className="inline-block ml-1 align-middle">
{/*@ts-ignore TYPE NEEDS FIXING*/}
{column.isSorted ? (
// @ts-ignore TYPE NEEDS FIXING
column.isSortedDesc ? (
<ArrowDownIcon width={12} />
) : (
<ArrowUpIcon width={12} />
)
) : (
''
)}
</span>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{/*@ts-ignore TYPE NEEDS FIXING*/}
{page.map((row, i) => {
prepareRow(row)
return (
<Link
href={{
pathname: `/analytics/trident/tokens/${row.original.id}`,
query: {
chainId,
},
}}
key={i}
passHref
>
<tr {...row.getRowProps()} key={i} className={TABLE_TBODY_TR_CLASSNAME}>
{/*@ts-ignore TYPE NEEDS FIXING*/}
{row.cells.map((cell, i) => {
return (
<td key={i} {...cell.getCellProps()} className={TABLE_TBODY_TD_CLASSNAME(i, row.cells.length)}>
{cell.render('Cell')}
</td>
)
})}
</tr>
</Link>
)
})}
</tbody>
</table>
</div>
<TablePageToggler
pageIndex={pageIndex}
pageSize={pageSize}
totalItems={rows.length}
gotoPage={gotoPage}
canPreviousPage={canPreviousPage}
canNextPage={canNextPage}
loading={!rows.length}
/>
</div>
)
}

export default SearchResultTokens
12 changes: 12 additions & 0 deletions src/features/analytics/trident/tokenTableFilters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// import { Fee } from '@sushiswap/trident-sdk'

type FilterSymbolsFunc<T> = (arg0: { original: { name: string; symbol: string } }[], arg1: string[], arg2: T) => any[]

export const filterForSearchQuery: FilterSymbolsFunc<{ searchQuery: string }> = (rows, id, filterValue) => {
return rows.filter(({ original }) => {
// Allow searching for symbol (LINK) or name (chainlink)
const searchableText = original?.name?.concat(original?.symbol)?.toLowerCase()
// return true
return !filterValue.searchQuery.length || searchableText.includes(filterValue.searchQuery.toLowerCase())
})
}
81 changes: 81 additions & 0 deletions src/features/analytics/trident/tokens/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { getAddress } from '@ethersproject/address'
import { LinkIcon } from '@heroicons/react/outline'
import { useLingui } from '@lingui/react'
import { ChainId, Token } from '@sushiswap/core-sdk'
import CopyHelper from 'app/components/AccountDetails/Copy'
import { CurrencyLogo } from 'app/components/CurrencyLogo'
import Typography from 'app/components/Typography'
import { formatNumber, getExplorerLink, shortenAddress } from 'app/functions'
import { useAllTokens } from 'app/hooks/Tokens'
import useDesktopMediaQuery from 'app/hooks/useDesktopMediaQuery'
import Link from 'next/link'
import { FC, useMemo } from 'react'

interface HeaderProps {
chainId: ChainId
token?: any
}

export const Header: FC<HeaderProps> = ({ token, chainId }) => {
const { i18n } = useLingui()
const isDesktop = useDesktopMediaQuery()
const allTokens = useAllTokens()
const currency = useMemo(() => {
const address = getAddress(token.id)
return address in allTokens
? allTokens[address]
: new Token(chainId, address, Number(token.decimals), token.symbol, token.name)
}, [token, allTokens, chainId])
return (
<div className="flex justify-between">
<div className="flex flex-col gap-2 lg:gap-5">
<div className="lg:flex lg:flex-row lg:gap-3 lg:order-0 lg:items-center">
<CurrencyLogo currency={currency} size={64} />
</div>
<div className="flex flex-row items-center gap-2 lg:order-2">
<div className="flex flex-col">
{token && (
<Link href={getExplorerLink(chainId, token.id, 'address')} passHref={true}>
<a target="_blank">
<Typography
id={`token-title-${token.id}`}
variant={isDesktop ? 'h3' : 'h2'}
className="flex gap-1 text-high-emphesis hover:text-blue-100"
weight={700}
>
{token.symbol} <LinkIcon width={20} />
</Typography>
</a>
</Link>
)}
{token && (
<CopyHelper toCopy={token.id} className="opacity-100 text-primary">
{shortenAddress(token.id)}
</CopyHelper>
)}
</div>
</div>
</div>
<div className="text-right mt-[-54px] lg:mt-0">
<div>
<Typography variant="sm" weight={700}>
{i18n._('Price')}
</Typography>
<Typography variant="h3" className="text-high-emphesis" weight={700}>
{formatNumber(token.price.derivedUSD, true)}
</Typography>
</div>
<div className="mt-2">
<Typography variant="sm" weight={700}>
{i18n._('Liquidity')}
</Typography>
<Typography variant="h3" className="text-high-emphesis" weight={700}>
{formatNumber(token.kpi.liquidityUSD, true)}
</Typography>
</div>
</div>
</div>
)
}

export default Header
83 changes: 83 additions & 0 deletions src/features/analytics/trident/tokens/TokenStats.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { t } from '@lingui/macro'
import { useLingui } from '@lingui/react'
import { ChainId } from '@sushiswap/core-sdk'
import Typography from 'app/components/Typography'
import { classNames, formatPercent } from 'app/functions'
import useDesktopMediaQuery from 'app/hooks/useDesktopMediaQuery'
import { useTridentRollingTokenStats } from 'app/services/graph'
import { FC } from 'react'

interface TokenStatsProps {
chainId: ChainId
token?: any
}

const TokenStats: FC<TokenStatsProps> = ({ chainId, token }) => {
const { i18n } = useLingui()
const isDesktop = useDesktopMediaQuery()

const { data: stats } = useTridentRollingTokenStats({
chainId,
variables: { where: { id: token.id.toLowerCase() } },
shouldFetch: !!chainId && !!token && !!token.id.toLowerCase(),
})

const items = [
{
label: i18n._(t`Volume (24H)`),
value: 'volume',
change: 'volume24hChange',
},
{
label: i18n._(t`Fees (24H)`),
value: 'fees',
change: 'fees24hChange',
},
{
label: i18n._(t`Utilization (24H)`),
value: 'liquidity',
change: 'liquidity24hChange',
},
{
label: i18n._(t`Transactions (24H)`),
value: 'transactions',
change: 'transactions24hChange',
},
]

return (
<div className="flex flex-col gap-3 lg:grid lg:grid-cols-4">
{items.map(({ label, value, change }, index) => (
<div
className="flex flex-row justify-between p-3 border rounded lg:flex-col lg:gap-1 bg-dark-900 border-dark-800 lg:bg-dark-800 lg:border-dark-700"
key={index}
>
<Typography variant={isDesktop ? 'xs' : 'sm'} weight={700}>
{label}
</Typography>
<div className="flex flex-row gap-2 lg:flex-col lg:gap-0">
<Typography weight={700} variant={isDesktop ? 'lg' : 'base'} className="text-high-emphesis">
{/*@ts-ignore TYPE NEEDS FIXING*/}
{stats?.[0]?.[value]}
</Typography>
<Typography
weight={400}
variant={isDesktop ? 'xs' : 'sm'}
// @ts-ignore TYPE NEEDS FIXING
className={classNames(
stats?.[0]?.[change] > 0 && 'text-green',
stats?.[0]?.[change] < 0 && 'text-red',
'text-inherit'
)}
>
{/*@ts-ignore TYPE NEEDS FIXING*/}
{formatPercent(stats?.[0]?.[change])}
</Typography>
</div>
</div>
))}
</div>
)
}

export default TokenStats
Loading