1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00
Bogdan Fazakas f8ffcbac75
Account metadata header (#776)
* get all neded data for the header from 3box, aqua and subgraph

* fix tvl display error

* WIP metadata header styling

* added more styling for the header

* make page title optional so we can remove it on account page

* stroke change for svg images and default values

* more styling added to the header

* fixed linter

* added ocean balance to tvl

* update styling for statistcs

* fixed eror for go to my account from another account page

* updated styling for mobile use

* wip show more on explorer links and description

* properly display read more for explorer links and description

* replaced show more with 3box redirect on description

* change accounts default picture and check links length before display element

* use optional on links

* grid cleanup, new number unit, split up stats

* rename all the things, more profile header styling

* visual hierarchy, improve image loading experience

* layout flow & visual tweaks

* more description

* replaced account route  with profile when accesing a profile by the eth address

* use account id from url if exists when fetching data

* bump @oceanprotocol/art to v3.2.0

* styling, fallbacks, edge case fixes

* clean up Publisher atom, link to profile page

* fixed issue when switching to my profile from another profile

* output accountId, make it copyable, remove stats icons

* render tweaks, markup cleanup

* add 3box reference

* mobile tabs spacing tweaks

* text flow and spacing tweaks

Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
2021-09-01 13:56:34 +02:00

255 lines
6.7 KiB
TypeScript

import React, { ReactElement, useEffect, useState } from 'react'
import Table from '../../../atoms/Table'
import Conversion from '../../../atoms/Price/Conversion'
import styles from './PoolShares.module.css'
import AssetTitle from '../../../molecules/AssetListTitle'
import { gql } from 'urql'
import {
PoolShares_poolShares as PoolShare,
PoolShares_poolShares_poolId_tokens as PoolSharePoolIdTokens
} from '../../../../@types/apollo/PoolShares'
import web3 from 'web3'
import Token from '../../../organisms/AssetActions/Pool/Token'
import { useUserPreferences } from '../../../../providers/UserPreferences'
import {
fetchDataForMultipleChains,
calculateUserLiquidity
} from '../../../../utils/subgraph'
import NetworkName from '../../../atoms/NetworkName'
import axios from 'axios'
import { retrieveDDO } from '../../../../utils/aquarius'
import { isValidNumber } from '../../../../utils/numberValidations'
import Decimal from 'decimal.js'
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
const REFETCH_INTERVAL = 20000
const poolSharesQuery = gql`
query PoolShares($user: String) {
poolShares(where: { userAddress: $user, balance_gt: 0.001 }, first: 1000) {
id
balance
userAddress {
id
}
poolId {
id
datatokenAddress
valueLocked
tokens {
tokenId {
symbol
}
}
oceanReserve
datatokenReserve
totalShares
consumePrice
spotPrice
createTime
}
}
}
`
interface Asset {
userLiquidity: number
poolShare: PoolShare
networkId: number
createTime: number
}
function findValidToken(tokens: PoolSharePoolIdTokens[]) {
const symbol = tokens.find((token) => token.tokenId !== null)
return symbol.tokenId.symbol
}
function Symbol({ tokens }: { tokens: PoolSharePoolIdTokens[] }) {
return <>{findValidToken(tokens)}</>
}
function Liquidity({ row, type }: { row: Asset; type: string }) {
let price = ``
let oceanTokenBalance = ''
let dataTokenBalance = ''
if (type === 'user') {
price = `${row.userLiquidity}`
const userShare = row.poolShare.balance / row.poolShare.poolId.totalShares
oceanTokenBalance = (
userShare * row.poolShare.poolId.oceanReserve
).toString()
dataTokenBalance = (
userShare * row.poolShare.poolId.datatokenReserve
).toString()
}
if (type === 'pool') {
price =
isValidNumber(row.poolShare.poolId.oceanReserve) &&
isValidNumber(row.poolShare.poolId.datatokenReserve) &&
isValidNumber(row.poolShare.poolId.consumePrice)
? new Decimal(row.poolShare.poolId.datatokenReserve)
.mul(new Decimal(row.poolShare.poolId.consumePrice))
.plus(row.poolShare.poolId.oceanReserve)
.toString()
: '0'
oceanTokenBalance = row.poolShare.poolId.oceanReserve.toString()
dataTokenBalance = row.poolShare.poolId.datatokenReserve.toString()
}
return (
<div className={styles.yourLiquidity}>
<Conversion
price={price}
className={styles.totalLiquidity}
hideApproximateSymbol
/>
<Token symbol="OCEAN" balance={oceanTokenBalance} noIcon />
<Token
symbol={findValidToken(row.poolShare.poolId.tokens)}
balance={dataTokenBalance}
noIcon
/>
</div>
)
}
const columns = [
{
name: 'Data Set',
selector: function getAssetRow(row: Asset) {
const did = web3.utils
.toChecksumAddress(row.poolShare.poolId.datatokenAddress)
.replace('0x', 'did:op:')
return <AssetTitle did={did} />
},
grow: 2
},
{
name: 'Network',
selector: function getNetwork(row: Asset) {
return <NetworkName networkId={row.networkId} />
}
},
{
name: 'Datatoken',
selector: function getSymbol(row: Asset) {
return <Symbol tokens={row.poolShare.poolId.tokens} />
}
},
{
name: 'Your Liquidity',
selector: function getAssetRow(row: Asset) {
return <Liquidity row={row} type="user" />
},
right: true
},
{
name: 'Pool Liquidity',
selector: function getAssetRow(row: Asset) {
return <Liquidity row={row} type="pool" />
},
right: true
}
]
export default function PoolShares({
accountId
}: {
accountId: string
}): ReactElement {
const [assets, setAssets] = useState<Asset[]>()
const [loading, setLoading] = useState<boolean>(false)
const [data, setData] = useState<PoolShare[]>()
const [dataFetchInterval, setDataFetchInterval] = useState<NodeJS.Timeout>()
const { chainIds } = useUserPreferences()
async function fetchPoolSharesData() {
const variables = { user: accountId?.toLowerCase() }
const shares: PoolShare[] = []
const result = await fetchDataForMultipleChains(
poolSharesQuery,
variables,
chainIds
)
for (let i = 0; i < result.length; i++) {
result[i].poolShares.forEach((poolShare: PoolShare) => {
shares.push(poolShare)
})
}
if (JSON.stringify(data) !== JSON.stringify(shares)) {
setData(shares)
}
}
function refetchPoolShares() {
if (!dataFetchInterval) {
setDataFetchInterval(
setInterval(function () {
fetchPoolSharesData()
}, REFETCH_INTERVAL)
)
}
}
useEffect(() => {
return () => {
clearInterval(dataFetchInterval)
}
}, [dataFetchInterval])
useEffect(() => {
async function getShares() {
const assetList: Asset[] = []
const source = axios.CancelToken.source()
try {
setLoading(true)
if (!data) {
await fetchPoolSharesData()
return
}
for (let i = 0; i < data.length; i++) {
const did = web3.utils
.toChecksumAddress(data[i].poolId.datatokenAddress)
.replace('0x', 'did:op:')
const ddo = await retrieveDDO(did, source.token)
const userLiquidity = calculateUserLiquidity(data[i])
assetList.push({
poolShare: data[i],
userLiquidity: userLiquidity,
networkId: ddo.chainId,
createTime: data[i].poolId.createTime
})
}
const orderedAssets = assetList.sort(
(a, b) => b.createTime - a.createTime
)
setAssets(orderedAssets)
refetchPoolShares()
} catch (error) {
console.error('Error fetching pool shares: ', error.message)
} finally {
setLoading(false)
}
}
getShares()
}, [accountId, chainIds, data])
return accountId ? (
<Table
columns={columns}
className={styles.poolSharesTable}
data={assets}
pagination
paginationPerPage={5}
isLoading={loading}
sortField="userLiquidity"
sortAsc={false}
/>
) : (
<div>Please connect your Web3 wallet.</div>
)
}