import React, { useContext, useState, useEffect, createContext, ReactElement, useCallback, ReactNode } from 'react' import { Logger, DDO, MetadataMain } from '@oceanprotocol/lib' import { PurgatoryData } from '@oceanprotocol/lib/dist/node/ddo/interfaces/PurgatoryData' import getAssetPurgatoryData from '@utils/purgatory' import { CancelToken } from 'axios' import { retrieveDDO } from '@utils/aquarius' import { getPrice } from '@utils/subgraph' import { useWeb3 } from './Web3' import { useSiteMetadata } from '@hooks/useSiteMetadata' import { useCancelToken } from '@hooks/useCancelToken' interface AssetProviderValue { isInPurgatory: boolean purgatoryData: PurgatoryData ddo: DDO did: string metadata: MetadataMarket title: string owner: string price: BestPrice type: MetadataMain['type'] error?: string refreshInterval: number isAssetNetwork: boolean loading: boolean refreshDdo: (token?: CancelToken) => Promise } const AssetContext = createContext({} as AssetProviderValue) const refreshInterval = 10000 // 10 sec. function AssetProvider({ asset, children }: { asset: string | DDO children: ReactNode }): ReactElement { const { appConfig } = useSiteMetadata() const { networkId } = useWeb3() const [isInPurgatory, setIsInPurgatory] = useState(false) const [purgatoryData, setPurgatoryData] = useState() const [ddo, setDDO] = useState() const [did, setDID] = useState() const [metadata, setMetadata] = useState() const [title, setTitle] = useState() const [price, setPrice] = useState() const [owner, setOwner] = useState() const [error, setError] = useState() const [type, setType] = useState() const [loading, setLoading] = useState(false) const [isAssetNetwork, setIsAssetNetwork] = useState() const newCancelToken = useCancelToken() const fetchDdo = async (token?: CancelToken) => { Logger.log('[asset] Init asset, get DDO') setLoading(true) const ddo = await retrieveDDO(asset as string, token) if (!ddo) { setError( `[asset] The DDO for ${asset} was not found in MetadataCache. If you just published a new data set, wait some seconds and refresh this page.` ) } else { setError(undefined) } setLoading(false) return ddo } const refreshDdo = async (token?: CancelToken) => { setLoading(true) const ddo = await fetchDdo(token) Logger.debug('[asset] Got DDO', ddo) setDDO(ddo) setLoading(false) } // // Get and set DDO based on passed DDO or DID // useEffect(() => { if (!asset || !appConfig.metadataCacheUri) return let isMounted = true async function init() { const ddo = await fetchDdo(newCancelToken()) if (!isMounted) return Logger.debug('[asset] Got DDO', ddo) setDDO(ddo) setDID(asset as string) } init() return () => { isMounted = false } }, [asset, appConfig.metadataCacheUri]) const setPurgatory = useCallback(async (did: string): Promise => { if (!did) return try { const result = await getAssetPurgatoryData(did) const isInPurgatory = result?.did !== undefined setIsInPurgatory(isInPurgatory) isInPurgatory && setPurgatoryData(result) } catch (error) { Logger.error(error) } }, []) const initMetadata = useCallback(async (ddo: DDO): Promise => { if (!ddo) return setLoading(true) const returnedPrice = await getPrice(ddo) setPrice({ ...returnedPrice }) // Get metadata from DDO const { attributes } = ddo.findServiceByType('metadata') setMetadata(attributes as unknown as MetadataMarket) setTitle(attributes?.main.name) setType(attributes.main.type) setOwner(ddo.publicKey[0].owner) Logger.log('[asset] Got Metadata from DDO', attributes) setIsInPurgatory(ddo.isInPurgatory === 'true') await setPurgatory(ddo.id) setLoading(false) }, []) useEffect(() => { if (!ddo) return initMetadata(ddo) }, [ddo, initMetadata]) // Check user network against asset network useEffect(() => { if (!networkId || !ddo) return const isAssetNetwork = networkId === ddo?.chainId setIsAssetNetwork(isAssetNetwork) }, [networkId, ddo]) return ( {children} ) } // Helper hook to access the provider values const useAsset = (): AssetProviderValue => useContext(AssetContext) export { AssetProvider, useAsset, AssetContext } export default AssetProvider