1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

Statistics footer (#746)

* display multiple chains statistics

* fetching stats data from multiple subgraphs

* design changes

* display one combined stat for all main networks

* tooltip updates

* added Loader component

* refactoring

* refactor for better fallback, remove loader

* tooltip styling and refactor

Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
Norbi 2021-07-22 14:07:52 +03:00 committed by GitHub
parent fddd5ff144
commit 7368c9cc68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 189 additions and 40 deletions

View File

@ -28,9 +28,7 @@ export default function Tooltip({
trigger, trigger,
disabled, disabled,
className, className,
placement, placement
link,
reference
}: { }: {
content: ReactNode content: ReactNode
children?: ReactNode children?: ReactNode
@ -38,8 +36,6 @@ export default function Tooltip({
disabled?: boolean disabled?: boolean
className?: string className?: string
placement?: Placement placement?: Placement
link?: string
reference?: string
}): ReactElement { }): ReactElement {
const [props, setSpring] = useSpring(() => animation.from) const [props, setSpring] = useSpring(() => animation.from)
@ -76,7 +72,6 @@ export default function Tooltip({
<animated.div style={props}> <animated.div style={props}>
<div className={styles.content} {...attrs}> <div className={styles.content} {...attrs}>
{content} {content}
{link && <a href={link}>{reference}</a>}
<div className={styles.arrow} data-popper-arrow /> <div className={styles.arrow} data-popper-arrow />
</div> </div>
</animated.div> </animated.div>

View File

@ -1,18 +1,42 @@
.stats { .stats {
margin-bottom: calc(var(--spacer) * 2); margin-bottom: calc(var(--spacer) * 2);
}
/* specificity sledgehammer override without !important */
.stats,
.stats *,
.statsList * {
font-size: var(--font-size-small); font-size: var(--font-size-small);
line-height: 2; color: var(--color-secondary);
margin-left: 0;
} }
.stats > div > div { .tooltipStats {
display: inline-block; margin-bottom: calc(var(--spacer) / 3);
padding-bottom: calc(var(--spacer) / 3);
border-bottom: 1px solid var(--border-color);
} }
.total { .network {
color: var(--color-secondary) !important; font-weight: var(--font-weight-bold);
font-size: var(--font-size-small) !important;
} }
.info { .info {
width: 0.85rem; width: 0.85rem;
} }
.statsList,
.note {
padding: calc(var(--spacer) / 4);
}
.statsList {
padding-bottom: 0;
}
.note {
margin-bottom: 0;
padding-top: 0;
font-size: var(--font-size-mini);
color: var(--color-secondary);
}

View File

@ -1,9 +1,15 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import styles from './MarketStats.module.css' import { gql, OperationContext } from 'urql'
import { gql, useQuery } from 'urql'
import Conversion from '../atoms/Price/Conversion' import Conversion from '../atoms/Price/Conversion'
import PriceUnit from '../atoms/Price/PriceUnit' import PriceUnit from '../atoms/Price/PriceUnit'
import Tooltip from '../atoms/Tooltip' import Tooltip from '../atoms/Tooltip'
import NetworkName from '../atoms/NetworkName'
import { fetchData, getSubgrahUri } from '../../utils/subgraph'
import { filterNetworksByType } from './UserPreferences/Networks/index'
import { useSiteMetadata } from '../../hooks/useSiteMetadata'
import useNetworkMetadata from '../../hooks/useNetworkMetadata'
import { Logger } from '@oceanprotocol/lib'
import styles from './MarketStats.module.css'
const getTotalPoolsValues = gql` const getTotalPoolsValues = gql`
query PoolsData { query PoolsData {
@ -15,36 +21,160 @@ const getTotalPoolsValues = gql`
} }
` `
interface Value {
[chainId: number]: string
}
function MarketNetworkStats({
totalValueLocked,
poolCount,
totalOceanLiquidity
}: {
totalValueLocked: string
poolCount: string
totalOceanLiquidity: string
}): ReactElement {
return (
<>
<Conversion price={totalValueLocked} hideApproximateSymbol />{' '}
<abbr title="Total Value Locked">TVL</abbr> across{' '}
<strong>{poolCount}</strong> asset pools that contain{' '}
<PriceUnit price={totalOceanLiquidity} small className={styles.total} />,
plus datatokens for each pool.
</>
)
}
function MarketNetworkStatsTooltip({
totalValueLocked,
poolCount,
totalOceanLiquidity,
mainChainIds
}: {
totalValueLocked: Value
poolCount: Value
totalOceanLiquidity: Value
mainChainIds: number[]
}): ReactElement {
return (
<>
<ul className={styles.statsList}>
{totalValueLocked &&
totalOceanLiquidity &&
poolCount &&
mainChainIds?.map((chainId, key) => (
<li className={styles.tooltipStats} key={key}>
<NetworkName networkId={chainId} className={styles.network} />
<br />
<Conversion
price={totalValueLocked[chainId] || '0'}
hideApproximateSymbol
/>{' '}
<abbr title="Total Value Locked">TVL</abbr>
{' | '}
<strong>{poolCount[chainId] || '0'}</strong> pools
{' | '}
<PriceUnit price={totalOceanLiquidity[chainId] || '0'} small />
</li>
))}
</ul>
<p className={styles.note}>
Counted on-chain from our pool factory. Does not filter out assets in{' '}
<a href="https://github.com/oceanprotocol/list-purgatory">
list-purgatory
</a>
</p>
</>
)
}
export default function MarketStats(): ReactElement { export default function MarketStats(): ReactElement {
const [totalValueLocked, setTotalValueLocked] = useState<string>() const [totalValueLocked, setTotalValueLocked] = useState<Value>()
const [totalOceanLiquidity, setTotalOceanLiquidity] = useState<string>() const [totalOceanLiquidity, setTotalOceanLiquidity] = useState<Value>()
const [poolCount, setPoolCount] = useState<number>() const [poolCount, setPoolCount] = useState<Value>()
const [result] = useQuery({ const [totalValueLockedSum, setTotalValueLockedSum] = useState<string>()
query: getTotalPoolsValues const [totalOceanLiquiditySum, setTotalOceanLiquiditySum] = useState<string>()
// pollInterval: 20000 const [poolCountSum, setPoolCountSum] = useState<string>()
}) const [mainChainIds, setMainChainIds] = useState<number[]>()
const { data } = result const { appConfig } = useSiteMetadata()
const { networksList } = useNetworkMetadata()
async function getMarketStats() {
const mainChainIdsList = await filterNetworksByType(
'mainnet',
appConfig.chainIdsSupported,
networksList
)
setMainChainIds(mainChainIdsList)
let newTotalValueLockedSum = 0
let newTotalOceanLiquiditySum = 0
let newPoolCountSum = 0
for (const chainId of mainChainIdsList) {
const context: OperationContext = {
url: `${getSubgrahUri(
chainId
)}/subgraphs/name/oceanprotocol/ocean-subgraph`,
requestPolicy: 'network-only'
}
try {
const response = await fetchData(getTotalPoolsValues, null, context)
if (!response) continue
const { totalValueLocked, totalOceanLiquidity, finalizedPoolCount } =
response?.data?.poolFactories[0]
await setTotalValueLocked((prevState) => ({
...prevState,
[chainId]: totalValueLocked
}))
await setTotalOceanLiquidity((prevState) => ({
...prevState,
[chainId]: totalOceanLiquidity
}))
await setPoolCount((prevState) => ({
...prevState,
[chainId]: finalizedPoolCount
}))
newTotalValueLockedSum += parseInt(totalValueLocked)
newTotalOceanLiquiditySum += parseInt(totalOceanLiquidity)
newPoolCountSum += parseInt(finalizedPoolCount)
} catch (error) {
Logger.error('Error fetchData: ', error.message)
}
}
setTotalValueLockedSum(`${newTotalValueLockedSum}`)
setTotalOceanLiquiditySum(`${newTotalOceanLiquiditySum}`)
setPoolCountSum(`${newPoolCountSum}`)
}
useEffect(() => { useEffect(() => {
if (!data || !data.poolFactories || data.poolFactories.length === 0) return getMarketStats()
setTotalValueLocked(data.poolFactories[0].totalValueLocked) }, [])
setTotalOceanLiquidity(data.poolFactories[0].totalOceanLiquidity)
setPoolCount(data.poolFactories[0].finalizedPoolCount)
}, [data])
return ( return (
<div className={styles.stats}> <div className={styles.stats}>
<Conversion price={`${totalValueLocked}`} hideApproximateSymbol />{' '} <>
<abbr title="Total Value Locked">TVL</abbr> across{' '} <MarketNetworkStats
<strong>{poolCount}</strong> data set pools that contain{' '} totalValueLocked={totalValueLockedSum || '0'}
<PriceUnit price={totalOceanLiquidity} small className={styles.total} />, totalOceanLiquidity={totalOceanLiquiditySum || '0'}
plus datatokens for each pool. poolCount={poolCountSum || '0'}
<Tooltip />{' '}
className={styles.info} <Tooltip
content="Counted on-chain from our pool factory. Does not filter out data sets in " className={styles.info}
reference="list-purgatory" content={
link="https://github.com/oceanprotocol/list-purgatory" <MarketNetworkStatsTooltip
/> totalValueLocked={totalValueLocked}
poolCount={poolCount}
totalOceanLiquidity={totalOceanLiquidity}
mainChainIds={mainChainIds}
/>
}
/>
</>
</div> </div>
) )
} }

View File

@ -11,7 +11,7 @@ import stylesIndex from '../index.module.css'
import styles from './index.module.css' import styles from './index.module.css'
import useNetworkMetadata from '../../../../hooks/useNetworkMetadata' import useNetworkMetadata from '../../../../hooks/useNetworkMetadata'
function filterNetworksByType( export function filterNetworksByType(
type: 'mainnet' | 'testnet', type: 'mainnet' | 'testnet',
chainIds: number[], chainIds: number[],
networksList: { node: EthereumListsChain }[] networksList: { node: EthereumListsChain }[]

View File

@ -150,7 +150,7 @@ export async function fetchData(
query: TypedDocumentNode, query: TypedDocumentNode,
variables: any, variables: any,
context: OperationContext context: OperationContext
): Promise<OperationResult> { ): Promise<any> {
try { try {
const client = getUrqlClientInstance() const client = getUrqlClientInstance()
const response = await client.query(query, variables, context).toPromise() const response = await client.query(query, variables, context).toPromise()