2021-09-13 16:39:32 +02:00
|
|
|
import React, {
|
|
|
|
useContext,
|
|
|
|
useState,
|
|
|
|
useEffect,
|
|
|
|
createContext,
|
|
|
|
ReactElement,
|
|
|
|
useCallback,
|
|
|
|
ReactNode
|
|
|
|
} from 'react'
|
2021-10-18 16:43:32 +02:00
|
|
|
import {
|
|
|
|
getPoolSharesData,
|
|
|
|
getUserSales,
|
|
|
|
getUserTokenOrders
|
2021-10-18 20:44:33 +02:00
|
|
|
} from '@utils/subgraph'
|
2021-09-13 16:39:32 +02:00
|
|
|
import { useUserPreferences } from './UserPreferences'
|
|
|
|
import { PoolShares_poolShares as PoolShare } from '../@types/apollo/PoolShares'
|
|
|
|
import { DDO, Logger } from '@oceanprotocol/lib'
|
2021-10-19 14:06:16 +02:00
|
|
|
import { getDownloadAssets, getPublishedAssets } from '@utils/aquarius'
|
2021-10-18 20:44:33 +02:00
|
|
|
import { useSiteMetadata } from '@hooks/useSiteMetadata'
|
|
|
|
import { accountTruncate } from '@utils/web3'
|
2021-09-13 16:39:32 +02:00
|
|
|
import axios, { CancelToken } from 'axios'
|
|
|
|
import ethereumAddress from 'ethereum-address'
|
2021-10-18 20:44:33 +02:00
|
|
|
import get3BoxProfile from '@utils/profile'
|
2021-09-13 16:39:32 +02:00
|
|
|
import web3 from 'web3'
|
|
|
|
|
|
|
|
interface ProfileProviderValue {
|
|
|
|
profile: Profile
|
|
|
|
poolShares: PoolShare[]
|
|
|
|
isPoolSharesLoading: boolean
|
|
|
|
assets: DDO[]
|
|
|
|
assetsTotal: number
|
|
|
|
isEthAddress: boolean
|
|
|
|
downloads: DownloadedAsset[]
|
|
|
|
downloadsTotal: number
|
|
|
|
isDownloadsLoading: boolean
|
2021-10-18 16:43:32 +02:00
|
|
|
sales: number
|
2021-09-13 16:39:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const ProfileContext = createContext({} as ProfileProviderValue)
|
|
|
|
|
|
|
|
const refreshInterval = 10000 // 10 sec.
|
|
|
|
|
|
|
|
function ProfileProvider({
|
|
|
|
accountId,
|
2021-09-20 13:47:15 +02:00
|
|
|
accountEns,
|
2021-09-13 16:39:32 +02:00
|
|
|
children
|
|
|
|
}: {
|
|
|
|
accountId: string
|
2021-09-20 13:47:15 +02:00
|
|
|
accountEns: string
|
2021-09-13 16:39:32 +02:00
|
|
|
children: ReactNode
|
|
|
|
}): ReactElement {
|
|
|
|
const { chainIds } = useUserPreferences()
|
|
|
|
const { appConfig } = useSiteMetadata()
|
|
|
|
|
|
|
|
const [isEthAddress, setIsEthAddress] = useState<boolean>()
|
|
|
|
|
|
|
|
//
|
|
|
|
// Do nothing in all following effects
|
|
|
|
// when accountId is no ETH address
|
|
|
|
//
|
|
|
|
useEffect(() => {
|
|
|
|
const isEthAddress = ethereumAddress.isAddress(accountId)
|
|
|
|
setIsEthAddress(isEthAddress)
|
|
|
|
}, [accountId])
|
|
|
|
|
|
|
|
//
|
2021-09-20 13:47:15 +02:00
|
|
|
// User profile: ENS + 3Box
|
2021-09-13 16:39:32 +02:00
|
|
|
//
|
2021-09-20 13:47:15 +02:00
|
|
|
const [profile, setProfile] = useState<Profile>()
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!accountEns) return
|
|
|
|
Logger.log(`[profile] ENS name found for ${accountId}:`, accountEns)
|
|
|
|
}, [accountId, accountEns])
|
2021-09-13 16:39:32 +02:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const clearedProfile: Profile = {
|
|
|
|
name: null,
|
2021-09-20 13:47:15 +02:00
|
|
|
accountEns: null,
|
2021-09-13 16:39:32 +02:00
|
|
|
image: null,
|
|
|
|
description: null,
|
|
|
|
links: null
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!accountId || !isEthAddress) {
|
|
|
|
setProfile(clearedProfile)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const cancelTokenSource = axios.CancelToken.source()
|
|
|
|
|
2021-09-20 13:47:15 +02:00
|
|
|
async function getInfo() {
|
|
|
|
setProfile({ name: accountEns || accountTruncate(accountId), accountEns })
|
|
|
|
|
2021-09-13 16:39:32 +02:00
|
|
|
const profile3Box = await get3BoxProfile(
|
|
|
|
accountId,
|
|
|
|
cancelTokenSource.token
|
|
|
|
)
|
|
|
|
if (profile3Box) {
|
|
|
|
const { name, emoji, description, image, links } = profile3Box
|
|
|
|
const newName = `${emoji || ''} ${name || accountTruncate(accountId)}`
|
|
|
|
const newProfile = {
|
|
|
|
name: newName,
|
|
|
|
image,
|
|
|
|
description,
|
|
|
|
links
|
|
|
|
}
|
2021-09-20 13:47:15 +02:00
|
|
|
setProfile((prevState) => ({
|
|
|
|
...prevState,
|
|
|
|
...newProfile
|
|
|
|
}))
|
2021-09-13 16:39:32 +02:00
|
|
|
Logger.log('[profile] Found and set 3box profile.', newProfile)
|
|
|
|
} else {
|
2021-09-20 13:47:15 +02:00
|
|
|
// setProfile(clearedProfile)
|
2021-09-13 16:39:32 +02:00
|
|
|
Logger.log('[profile] No 3box profile found.')
|
|
|
|
}
|
|
|
|
}
|
2021-09-20 13:47:15 +02:00
|
|
|
getInfo()
|
2021-09-13 16:39:32 +02:00
|
|
|
|
|
|
|
return () => {
|
|
|
|
cancelTokenSource.cancel()
|
|
|
|
}
|
2021-09-20 13:47:15 +02:00
|
|
|
}, [accountId, accountEns, isEthAddress])
|
2021-09-13 16:39:32 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// POOL SHARES
|
|
|
|
//
|
|
|
|
const [poolShares, setPoolShares] = useState<PoolShare[]>()
|
|
|
|
const [isPoolSharesLoading, setIsPoolSharesLoading] = useState<boolean>(false)
|
|
|
|
const [poolSharesInterval, setPoolSharesInterval] = useState<NodeJS.Timeout>()
|
|
|
|
|
2021-10-21 09:24:00 +02:00
|
|
|
const fetchPoolShares = useCallback(
|
|
|
|
async (accountId, chainIds, isEthAddress) => {
|
|
|
|
if (!accountId || !chainIds || !isEthAddress) return
|
|
|
|
|
|
|
|
try {
|
|
|
|
setIsPoolSharesLoading(true)
|
|
|
|
const poolShares = await getPoolSharesData(accountId, chainIds)
|
|
|
|
setPoolShares(poolShares)
|
|
|
|
Logger.log(
|
|
|
|
`[profile] Fetched ${poolShares.length} pool shares.`,
|
|
|
|
poolShares
|
|
|
|
)
|
|
|
|
} catch (error) {
|
|
|
|
Logger.error('Error fetching pool shares: ', error.message)
|
|
|
|
} finally {
|
|
|
|
setIsPoolSharesLoading(false)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[]
|
|
|
|
)
|
2021-09-13 16:39:32 +02:00
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
async function init() {
|
2021-10-21 09:24:00 +02:00
|
|
|
await fetchPoolShares(accountId, chainIds, isEthAddress)
|
2021-09-13 16:39:32 +02:00
|
|
|
|
|
|
|
if (poolSharesInterval) return
|
|
|
|
const interval = setInterval(async () => {
|
2021-10-21 09:24:00 +02:00
|
|
|
await fetchPoolShares(accountId, chainIds, isEthAddress)
|
2021-09-13 16:39:32 +02:00
|
|
|
}, refreshInterval)
|
|
|
|
setPoolSharesInterval(interval)
|
|
|
|
}
|
|
|
|
init()
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
clearInterval(poolSharesInterval)
|
|
|
|
}
|
2021-10-21 09:24:00 +02:00
|
|
|
}, [poolSharesInterval, fetchPoolShares, accountId, chainIds, isEthAddress])
|
2021-09-13 16:39:32 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// PUBLISHED ASSETS
|
|
|
|
//
|
|
|
|
const [assets, setAssets] = useState<DDO[]>()
|
|
|
|
const [assetsTotal, setAssetsTotal] = useState(0)
|
|
|
|
// const [assetsWithPrices, setAssetsWithPrices] = useState<AssetListPrices[]>()
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!accountId || !isEthAddress) return
|
|
|
|
|
|
|
|
const cancelTokenSource = axios.CancelToken.source()
|
|
|
|
|
|
|
|
async function getAllPublished() {
|
|
|
|
try {
|
|
|
|
const result = await getPublishedAssets(
|
|
|
|
accountId,
|
|
|
|
chainIds,
|
|
|
|
cancelTokenSource.token
|
|
|
|
)
|
|
|
|
setAssets(result.results)
|
|
|
|
setAssetsTotal(result.totalResults)
|
|
|
|
Logger.log(
|
|
|
|
`[profile] Fetched ${result.totalResults} assets.`,
|
|
|
|
result.results
|
|
|
|
)
|
|
|
|
|
|
|
|
// Hint: this would only make sense if we "search" in all subcomponents
|
|
|
|
// against this provider's state, meaning filtering via js rather then sending
|
|
|
|
// more queries to Aquarius.
|
|
|
|
// const assetsWithPrices = await getAssetsBestPrices(result.results)
|
|
|
|
// setAssetsWithPrices(assetsWithPrices)
|
|
|
|
} catch (error) {
|
|
|
|
Logger.error(error.message)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getAllPublished()
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
cancelTokenSource.cancel()
|
|
|
|
}
|
|
|
|
}, [accountId, appConfig.metadataCacheUri, chainIds, isEthAddress])
|
|
|
|
|
|
|
|
//
|
|
|
|
// DOWNLOADS
|
|
|
|
//
|
|
|
|
const [downloads, setDownloads] = useState<DownloadedAsset[]>()
|
|
|
|
const [downloadsTotal, setDownloadsTotal] = useState(0)
|
|
|
|
const [isDownloadsLoading, setIsDownloadsLoading] = useState<boolean>()
|
|
|
|
const [downloadsInterval, setDownloadsInterval] = useState<NodeJS.Timeout>()
|
|
|
|
|
|
|
|
const fetchDownloads = useCallback(
|
|
|
|
async (cancelToken: CancelToken) => {
|
|
|
|
if (!accountId || !chainIds) return
|
|
|
|
|
|
|
|
const didList: string[] = []
|
|
|
|
const tokenOrders = await getUserTokenOrders(accountId, chainIds)
|
|
|
|
|
|
|
|
for (let i = 0; i < tokenOrders?.length; i++) {
|
|
|
|
const did = web3.utils
|
|
|
|
.toChecksumAddress(tokenOrders[i].datatokenId.address)
|
|
|
|
.replace('0x', 'did:op:')
|
|
|
|
didList.push(did)
|
|
|
|
}
|
|
|
|
|
|
|
|
const downloads = await getDownloadAssets(
|
|
|
|
didList,
|
|
|
|
tokenOrders,
|
|
|
|
chainIds,
|
|
|
|
cancelToken
|
|
|
|
)
|
|
|
|
setDownloads(downloads)
|
|
|
|
setDownloadsTotal(downloads.length)
|
|
|
|
Logger.log(
|
|
|
|
`[profile] Fetched ${downloads.length} download orders.`,
|
|
|
|
downloads
|
|
|
|
)
|
|
|
|
},
|
|
|
|
[accountId, chainIds]
|
|
|
|
)
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
const cancelTokenSource = axios.CancelToken.source()
|
|
|
|
|
|
|
|
async function getDownloadAssets() {
|
|
|
|
if (!appConfig?.metadataCacheUri) return
|
|
|
|
|
|
|
|
try {
|
|
|
|
setIsDownloadsLoading(true)
|
|
|
|
await fetchDownloads(cancelTokenSource.token)
|
|
|
|
} catch (err) {
|
|
|
|
Logger.log(err.message)
|
|
|
|
} finally {
|
|
|
|
setIsDownloadsLoading(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getDownloadAssets()
|
|
|
|
|
|
|
|
if (downloadsInterval) return
|
|
|
|
const interval = setInterval(async () => {
|
|
|
|
await fetchDownloads(cancelTokenSource.token)
|
|
|
|
}, refreshInterval)
|
|
|
|
setDownloadsInterval(interval)
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
cancelTokenSource.cancel()
|
|
|
|
clearInterval(downloadsInterval)
|
|
|
|
}
|
|
|
|
}, [fetchDownloads, appConfig.metadataCacheUri, downloadsInterval])
|
|
|
|
|
2021-10-18 16:43:32 +02:00
|
|
|
//
|
|
|
|
// SALES NUMBER
|
|
|
|
//
|
|
|
|
const [sales, setSales] = useState(0)
|
|
|
|
useEffect(() => {
|
|
|
|
if (!accountId || chainIds.length === 0) {
|
|
|
|
setSales(0)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
async function getUserSalesNumber() {
|
|
|
|
try {
|
|
|
|
const result = await getUserSales(accountId, chainIds)
|
|
|
|
setSales(result)
|
|
|
|
Logger.log(`[profile] Fetched sales number: ${result}.`, result)
|
|
|
|
} catch (error) {
|
|
|
|
Logger.error(error.message)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
getUserSalesNumber()
|
|
|
|
}, [accountId, chainIds])
|
|
|
|
|
2021-09-13 16:39:32 +02:00
|
|
|
return (
|
|
|
|
<ProfileContext.Provider
|
|
|
|
value={{
|
|
|
|
profile,
|
|
|
|
poolShares,
|
|
|
|
isPoolSharesLoading,
|
|
|
|
assets,
|
|
|
|
assetsTotal,
|
|
|
|
isEthAddress,
|
|
|
|
downloads,
|
|
|
|
downloadsTotal,
|
2021-10-18 16:43:32 +02:00
|
|
|
isDownloadsLoading,
|
|
|
|
sales
|
2021-09-13 16:39:32 +02:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</ProfileContext.Provider>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper hook to access the provider values
|
|
|
|
const useProfile = (): ProfileProviderValue => useContext(ProfileContext)
|
|
|
|
|
2021-10-27 12:27:14 +02:00
|
|
|
export { ProfileProvider, useProfile, ProfileContext }
|
2021-09-13 16:39:32 +02:00
|
|
|
export default ProfileProvider
|