market/src/components/@shared/PoolTransactions/index.tsx

265 lines
6.7 KiB
TypeScript

import React, { ReactElement, useCallback, useEffect, useState } from 'react'
import Time from '@shared/atoms/Time'
import Table, { TableOceanColumn } from '@shared/atoms/Table'
import AssetTitle from '@shared/AssetList/AssetListTitle'
import { useUserPreferences } from '@context/UserPreferences'
import { gql } from 'urql'
import { TransactionHistory_poolTransactions as TransactionHistoryPoolTransactions } from '../../../@types/subgraph/TransactionHistory'
import { fetchDataForMultipleChains } from '@utils/subgraph'
import NetworkName from '@shared/NetworkName'
import { getAssetsFromDtList } from '@utils/aquarius'
import { getAsset } from '../../Profile/History/PoolShares/_utils'
import { CancelToken } from 'axios'
import Title from './Title'
import styles from './index.module.css'
import { Asset, LoggerInstance } from '@oceanprotocol/lib'
import { useCancelToken } from '@hooks/useCancelToken'
import { useMarketMetadata } from '@context/MarketMetadata'
const REFETCH_INTERVAL = 20000
const txHistoryQueryByPool = gql`
query TransactionHistoryByPool($user: String, $pool: String) {
poolTransactions(
orderBy: timestamp
orderDirection: desc
where: { pool: $pool, user: $user }
first: 1000
) {
baseToken {
symbol
address
}
baseTokenValue
datatoken {
symbol
address
}
datatokenValue
type
tx
timestamp
pool {
datatoken {
id
}
id
}
}
}
`
const txHistoryQuery = gql`
query TransactionHistory($user: String) {
poolTransactions(
orderBy: timestamp
orderDirection: desc
where: { user: $user }
first: 1000
) {
baseToken {
symbol
address
}
baseTokenValue
datatoken {
symbol
address
}
datatokenValue
type
tx
timestamp
pool {
datatoken {
id
}
id
}
}
}
`
export interface PoolTransaction extends TransactionHistoryPoolTransactions {
networkId: number
asset: Asset
}
const columns: TableOceanColumn<PoolTransaction>[] = [
{
name: 'Title',
selector: (row) => <Title row={row} />
},
{
name: 'Data Set',
selector: (row) => <AssetTitle asset={row.asset} />
},
{
name: 'Network',
selector: (row) => <NetworkName networkId={row.networkId} />,
maxWidth: '12rem'
},
{
name: 'Time',
selector: (row) => (
<Time
className={styles.time}
date={row.timestamp.toString()}
relative
isUnix
/>
),
maxWidth: '10rem'
}
]
// hack! if we use a function to omit one field this will display a strange refresh to the enduser for each row
const columnsMinimal = [columns[0], columns[3]]
export default function PoolTransactions({
poolAddress,
poolChainId,
minimal,
accountId
}: {
poolAddress?: string
poolChainId?: number
minimal?: boolean
accountId: string
}): ReactElement {
const { chainIds } = useUserPreferences()
const { appConfig } = useMarketMetadata()
const cancelToken = useCancelToken()
const [transactions, setTransactions] = useState<PoolTransaction[]>()
const [isLoading, setIsLoading] = useState<boolean>(false)
const [dataFetchInterval, setDataFetchInterval] = useState<NodeJS.Timeout>()
const [data, setData] = useState<PoolTransaction[]>()
const getPoolTransactionData = useCallback(async () => {
const variables = {
user: accountId?.toLowerCase(),
pool: poolAddress?.toLowerCase()
}
const transactions: PoolTransaction[] = []
const result = await fetchDataForMultipleChains(
poolAddress ? txHistoryQueryByPool : txHistoryQuery,
variables,
poolAddress ? [poolChainId] : chainIds
)
for (let i = 0; i < result.length; i++) {
result[i].poolTransactions.forEach((poolTransaction: PoolTransaction) => {
transactions.push(poolTransaction)
})
}
if (JSON.stringify(data) !== JSON.stringify(transactions)) {
setData(transactions)
}
}, [accountId, chainIds, data, poolAddress, poolChainId])
const getPoolTransactions = useCallback(
async (cancelToken: CancelToken) => {
if (!data) {
return
}
const poolTransactions: PoolTransaction[] = []
let dtList: string[] = []
dtList = [...new Set(data.map((item) => item.pool.datatoken.id))]
if (dtList.length === 0) {
setTransactions([])
setIsLoading(false)
return
}
const ddoList = !minimal
? await getAssetsFromDtList(dtList, chainIds, cancelToken)
: []
for (let i = 0; i < data.length; i++) {
poolTransactions.push({
...data[i],
networkId: !minimal
? getAsset(ddoList, data[i].pool.datatoken.id)?.chainId
: poolChainId,
asset: !minimal ? getAsset(ddoList, data[i].pool.datatoken.id) : null
})
}
const sortedTransactions = poolTransactions.sort(
(a, b) => b.timestamp - a.timestamp
)
setTransactions(sortedTransactions)
setIsLoading(false)
},
[data, minimal, chainIds, poolChainId]
)
//
// Get data, periodically
//
useEffect(() => {
if (!appConfig?.metadataCacheUri) return
async function getTransactions() {
try {
await getPoolTransactionData()
if (dataFetchInterval) return
const interval = setInterval(async () => {
await getPoolTransactionData()
}, REFETCH_INTERVAL)
setDataFetchInterval(interval)
} catch (error) {
LoggerInstance.error(
'Error fetching pool transactions: ',
error.message
)
}
}
getTransactions()
return () => {
clearInterval(dataFetchInterval)
}
}, [getPoolTransactionData, dataFetchInterval, appConfig.metadataCacheUri])
//
// Transform to final transactions
//
useEffect(() => {
if (!cancelToken()) return
async function transformData() {
try {
setIsLoading(true)
await getPoolTransactions(cancelToken())
} catch (error) {
LoggerInstance.error(
'Error fetching pool transactions: ',
error.message
)
}
}
transformData()
return () => {
cancelToken()
}
}, [cancelToken, getPoolTransactions])
return accountId ? (
<Table
columns={minimal ? columnsMinimal : columns}
data={transactions}
isLoading={isLoading}
noTableHead={minimal}
dense={minimal}
pagination={
minimal ? transactions?.length >= 4 : transactions?.length >= 9
}
paginationPerPage={minimal ? 5 : 10}
emptyMessage={chainIds.length === 0 ? 'No network selected' : null}
/>
) : (
<div>Please connect your Web3 wallet.</div>
)
}