mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
Merge remote-tracking branch 'origin/main' into feature/1400-shared-components-stories
This commit is contained in:
commit
e71695fed5
@ -18,7 +18,7 @@ import { getAccessDetails } from '@utils/accessDetailsAndPricing'
|
|||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
import { useMarketMetadata } from './MarketMetadata'
|
import { useMarketMetadata } from './MarketMetadata'
|
||||||
|
|
||||||
interface AssetProviderValue {
|
export interface AssetProviderValue {
|
||||||
isInPurgatory: boolean
|
isInPurgatory: boolean
|
||||||
purgatoryData: Purgatory
|
purgatoryData: Purgatory
|
||||||
asset: AssetExtended
|
asset: AssetExtended
|
||||||
|
@ -5,7 +5,9 @@ export const opcQuery = gql`
|
|||||||
opc(id: 1) {
|
opc(id: 1) {
|
||||||
swapOceanFee
|
swapOceanFee
|
||||||
swapNonOceanFee
|
swapNonOceanFee
|
||||||
approvedTokens
|
approvedTokens {
|
||||||
|
id
|
||||||
|
}
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ function MarketMetadataProvider({
|
|||||||
|
|
||||||
opcData.push({
|
opcData.push({
|
||||||
chainId: appConfig.chainIdsSupported[i],
|
chainId: appConfig.chainIdsSupported[i],
|
||||||
approvedTokens: response.data?.opc.approvedTokens,
|
approvedTokens: response.data?.opc.approvedTokens?.map((x) => x.id),
|
||||||
swapApprovedFee: response.data?.opc.swapOceanFee,
|
swapApprovedFee: response.data?.opc.swapOceanFee,
|
||||||
swapNotApprovedFee: response.data?.opc.swapNonOceanFee
|
swapNotApprovedFee: response.data?.opc.swapNonOceanFee
|
||||||
} as OpcFee)
|
} as OpcFee)
|
||||||
|
@ -9,7 +9,7 @@ import Web3 from 'web3'
|
|||||||
|
|
||||||
// TODO: Why do we have these one line functions ?!?!?!
|
// TODO: Why do we have these one line functions ?!?!?!
|
||||||
export async function getEncryptedFiles(
|
export async function getEncryptedFiles(
|
||||||
files: FileMetadata[],
|
files: any,
|
||||||
providerUrl: string
|
providerUrl: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
try {
|
try {
|
||||||
|
@ -20,15 +20,6 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
min-width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:hover,
|
.button:hover,
|
||||||
.button:focus {
|
.button:focus {
|
||||||
color: var(--brand-white);
|
color: var(--brand-white);
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
margin-left: calc(var(--spacer) / 4);
|
margin-left: calc(var(--spacer) / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loader.white {
|
||||||
|
border-color: rgba(255 255 255 / 0.3);
|
||||||
|
border-top-color: var(--brand-white);
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes loader {
|
@keyframes loader {
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
|
@ -3,12 +3,13 @@ import styles from './index.module.css'
|
|||||||
|
|
||||||
export interface LoaderProps {
|
export interface LoaderProps {
|
||||||
message?: string
|
message?: string
|
||||||
|
white?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Loader({ message }: LoaderProps): ReactElement {
|
export default function Loader({ message, white }: LoaderProps): ReactElement {
|
||||||
return (
|
return (
|
||||||
<div className={styles.loaderWrap}>
|
<div className={styles.loaderWrap}>
|
||||||
<span className={styles.loader} />
|
<span className={`${styles.loader} ${white ? styles.white : ''}`} />
|
||||||
{message && <span className={styles.message}>{message}</span>}
|
{message && <span className={styles.message}>{message}</span>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -5,13 +5,14 @@ import AddToken from '@shared/AddToken'
|
|||||||
import ExplorerLink from '@shared/ExplorerLink'
|
import ExplorerLink from '@shared/ExplorerLink'
|
||||||
import Publisher from '@shared/Publisher'
|
import Publisher from '@shared/Publisher'
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import styles from './MetaAsset.module.css'
|
import styles from './MetaAsset.module.css'
|
||||||
|
|
||||||
export default function MetaAsset({
|
export default function MetaAsset({
|
||||||
asset,
|
asset,
|
||||||
isBlockscoutExplorer
|
isBlockscoutExplorer
|
||||||
}: {
|
}: {
|
||||||
asset: Asset
|
asset: AssetExtended
|
||||||
isBlockscoutExplorer: boolean
|
isBlockscoutExplorer: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { isAssetNetwork } = useAsset()
|
const { isAssetNetwork } = useAsset()
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import { Asset } from '@oceanprotocol/lib'
|
import { useAsset } from '@context/Asset'
|
||||||
import AssetType from '@shared/AssetType'
|
import AssetType from '@shared/AssetType'
|
||||||
import Time from '@shared/atoms/Time'
|
import Time from '@shared/atoms/Time'
|
||||||
import Publisher from '@shared/Publisher'
|
import Publisher from '@shared/Publisher'
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import styles from './MetaInfo.module.css'
|
import styles from './MetaInfo.module.css'
|
||||||
|
|
||||||
export default function MetaInfo({
|
export default function MetaInfo({
|
||||||
asset,
|
asset,
|
||||||
nftPublisher
|
nftPublisher
|
||||||
}: {
|
}: {
|
||||||
asset: Asset
|
asset: AssetExtended
|
||||||
nftPublisher: string
|
nftPublisher: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const isCompute = Boolean(getServiceByName(asset, 'compute'))
|
const isCompute = Boolean(getServiceByName(asset, 'compute'))
|
||||||
|
@ -13,32 +13,3 @@
|
|||||||
height: calc(var(--spacer) * 2);
|
height: calc(var(--spacer) * 2);
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-bottom: 1px solid var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nftImage {
|
|
||||||
position: relative;
|
|
||||||
margin: 0;
|
|
||||||
border-right: 1px solid var(--border-color);
|
|
||||||
width: calc(var(--spacer) * 2);
|
|
||||||
height: calc(var(--spacer) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nftImage img,
|
|
||||||
.nftImage > svg:first-of-type {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nftImage > svg:first-of-type {
|
|
||||||
transform: scale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nftImage .tooltip {
|
|
||||||
position: absolute;
|
|
||||||
padding: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nftImage .tooltip svg {
|
|
||||||
fill: var(--font-color-text);
|
|
||||||
}
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { AssetExtended } from 'src/@types/AssetExtended'
|
|
||||||
import { decodeTokenURI } from '@utils/nft'
|
|
||||||
import MetaAsset from './MetaAsset'
|
import MetaAsset from './MetaAsset'
|
||||||
import MetaInfo from './MetaInfo'
|
import MetaInfo from './MetaInfo'
|
||||||
import Tooltip from '@shared/atoms/Tooltip'
|
import Nft from '../Nft'
|
||||||
import NftTooltip from './NftTooltip'
|
import { AssetExtended } from 'src/@types/AssetExtended'
|
||||||
import Logo from '@shared/atoms/Logo'
|
|
||||||
import { FormPublishData } from '../../../Publish/_types'
|
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
|
||||||
import { useFormikContext } from 'formik'
|
|
||||||
|
|
||||||
export default function MetaMain({
|
export default function MetaMain({
|
||||||
asset,
|
asset,
|
||||||
@ -17,51 +14,12 @@ export default function MetaMain({
|
|||||||
asset: AssetExtended
|
asset: AssetExtended
|
||||||
nftPublisher: string
|
nftPublisher: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const nftMetadata = decodeTokenURI(asset?.nft?.tokenURI)
|
|
||||||
|
|
||||||
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
|
|
||||||
const isBlockscoutExplorer = blockscoutNetworks.includes(asset?.chainId)
|
const isBlockscoutExplorer = blockscoutNetworks.includes(asset?.chainId)
|
||||||
|
|
||||||
// TODO: using this for the publish preview works fine, but produces a console warning
|
|
||||||
// on asset details page as there is no formik context there:
|
|
||||||
// Warning: Formik context is undefined, please verify you are calling useFormikContext()
|
|
||||||
// as child of a <Formik> component.
|
|
||||||
const formikState = useFormikContext<FormPublishData>()
|
|
||||||
|
|
||||||
// checking if the NFT has an image associated (tokenURI)
|
|
||||||
// if tokenURI is undefined, then we are in Preview
|
|
||||||
// for Preview we need to show accessDetails.dataImage
|
|
||||||
// as this is where the NFT's SVG (during publish) is stored
|
|
||||||
const nftImage = nftMetadata?.image_data
|
|
||||||
? nftMetadata.image_data
|
|
||||||
: formikState?.values?.metadata?.nft?.image_data
|
|
||||||
? formikState.values.metadata.nft.image_data
|
|
||||||
: null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.meta}>
|
<aside className={styles.meta}>
|
||||||
<header className={styles.asset}>
|
<header className={styles.asset}>
|
||||||
<div className={styles.nftImage}>
|
<Nft isBlockscoutExplorer={isBlockscoutExplorer} />
|
||||||
{nftImage ? (
|
|
||||||
<img src={nftImage} alt={asset?.nft?.name} />
|
|
||||||
) : (
|
|
||||||
<Logo noWordmark />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{(nftMetadata || asset?.nftAddress) && (
|
|
||||||
<Tooltip
|
|
||||||
className={styles.tooltip}
|
|
||||||
content={
|
|
||||||
<NftTooltip
|
|
||||||
nft={nftMetadata}
|
|
||||||
address={asset?.nftAddress}
|
|
||||||
chainId={asset?.chainId}
|
|
||||||
isBlockscoutExplorer={isBlockscoutExplorer}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<MetaAsset asset={asset} isBlockscoutExplorer={isBlockscoutExplorer} />
|
<MetaAsset asset={asset} isBlockscoutExplorer={isBlockscoutExplorer} />
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
@ -7,6 +7,11 @@ import styles from './NftTooltip.module.css'
|
|||||||
import explorerLinkStyles from '@shared/ExplorerLink/index.module.css'
|
import explorerLinkStyles from '@shared/ExplorerLink/index.module.css'
|
||||||
import { accountTruncate } from '@utils/web3'
|
import { accountTruncate } from '@utils/web3'
|
||||||
|
|
||||||
|
// Supported OpenSea networks:
|
||||||
|
// https://support.opensea.io/hc/en-us/articles/4404027708051-Which-blockchains-does-OpenSea-support-
|
||||||
|
const openSeaNetworks = [1, 137]
|
||||||
|
const openSeaTestNetworks = [4]
|
||||||
|
|
||||||
export default function NftTooltip({
|
export default function NftTooltip({
|
||||||
nft,
|
nft,
|
||||||
address,
|
address,
|
||||||
@ -18,26 +23,23 @@ export default function NftTooltip({
|
|||||||
chainId: number
|
chainId: number
|
||||||
isBlockscoutExplorer: boolean
|
isBlockscoutExplorer: boolean
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
// Currently Ocean NFTs are not displayed correctly on OpenSea
|
const openSeaSupported = openSeaNetworks
|
||||||
// Code prepared to easily integrate this feature once this is fixed
|
.concat(openSeaTestNetworks)
|
||||||
//
|
|
||||||
// Supported OpeanSea networks:
|
|
||||||
// https://support.opensea.io/hc/en-us/articles/4404027708051-Which-blockchains-does-OpenSea-support-
|
|
||||||
const openseaNetworks = [1, 137]
|
|
||||||
const openseaTestNetworks = [4]
|
|
||||||
const openSeaSupported = openseaNetworks
|
|
||||||
.concat(openseaTestNetworks)
|
|
||||||
.includes(chainId)
|
.includes(chainId)
|
||||||
|
|
||||||
const openSeaBaseUri = openSeaSupported
|
const openSeaBaseUri = openSeaSupported
|
||||||
? openseaTestNetworks.includes(chainId)
|
? openSeaTestNetworks.includes(chainId)
|
||||||
? 'https://testnets.opensea.io'
|
? 'https://testnets.opensea.io'
|
||||||
: 'https://opensea.io'
|
: 'https://opensea.io'
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
|
const openSeaUrl = `${openSeaBaseUri}/assets/${
|
||||||
|
chainId === 137 ? 'matic' : ''
|
||||||
|
}/${address}/1`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
{nft && <img src={nft.image_data} alt={nft?.name} />}
|
{nft && <img src={nft.image_data || nft.image} alt={nft?.name} />}
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
{nft && <h5>{nft.name}</h5>}
|
{nft && <h5>{nft.name}</h5>}
|
||||||
{address && (
|
{address && (
|
||||||
@ -53,25 +55,23 @@ export default function NftTooltip({
|
|||||||
isBlockscoutExplorer ? `tokens/${address}` : `token/${address}`
|
isBlockscoutExplorer ? `tokens/${address}` : `token/${address}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
View on explorer
|
View on Explorer
|
||||||
</ExplorerLink>
|
</ExplorerLink>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{openSeaSupported && nft && address && (
|
{openSeaSupported && address && (
|
||||||
<a
|
<a
|
||||||
href={`${openSeaBaseUri}/assets/${address}/1`}
|
href={openSeaUrl}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
className={explorerLinkStyles.link}
|
className={explorerLinkStyles.link}
|
||||||
>
|
>
|
||||||
View on OpeanSea <External />
|
View on OpenSea <External />
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!nft?.image_data && (
|
{!nft?.image_data && !nft?.image && (
|
||||||
<p className={styles.fallback}>
|
<p className={styles.fallback}>This Data NFT has no image set.</p>
|
||||||
This Data NFT was not created on Ocean Market
|
|
||||||
</p>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
28
src/components/Asset/AssetContent/Nft/index.module.css
Normal file
28
src/components/Asset/AssetContent/Nft/index.module.css
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
.nftImage {
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
border-right: 1px solid var(--border-color);
|
||||||
|
width: calc(var(--spacer) * 2);
|
||||||
|
height: calc(var(--spacer) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nftImage img,
|
||||||
|
.nftImage > svg:first-of-type {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nftImage > svg:first-of-type {
|
||||||
|
transform: scale(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nftImage .tooltip {
|
||||||
|
position: absolute;
|
||||||
|
padding: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nftImage .tooltip svg {
|
||||||
|
fill: var(--font-color-text);
|
||||||
|
}
|
60
src/components/Asset/AssetContent/Nft/index.tsx
Normal file
60
src/components/Asset/AssetContent/Nft/index.tsx
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { useAsset } from '@context/Asset'
|
||||||
|
import Tooltip from '@shared/atoms/Tooltip'
|
||||||
|
import { decodeTokenURI } from '@utils/nft'
|
||||||
|
import { useFormikContext } from 'formik'
|
||||||
|
import React from 'react'
|
||||||
|
import { FormPublishData } from 'src/components/Publish/_types'
|
||||||
|
import Logo from '@shared/atoms/Logo'
|
||||||
|
import NftTooltip from './NftTooltip'
|
||||||
|
import styles from './index.module.css'
|
||||||
|
|
||||||
|
export default function Nft({
|
||||||
|
isBlockscoutExplorer
|
||||||
|
}: {
|
||||||
|
isBlockscoutExplorer: boolean
|
||||||
|
}) {
|
||||||
|
const { asset } = useAsset()
|
||||||
|
const nftMetadata = decodeTokenURI(asset?.nft?.tokenURI)
|
||||||
|
|
||||||
|
// TODO: using this for the publish preview works fine, but produces a console warning
|
||||||
|
// on asset details page as there is no formik context there:
|
||||||
|
// Warning: Formik context is undefined, please verify you are calling useFormikContext()
|
||||||
|
// as child of a <Formik> component.
|
||||||
|
const formikState = useFormikContext<FormPublishData>()
|
||||||
|
|
||||||
|
// checking if the NFT has an image associated (tokenURI)
|
||||||
|
// if tokenURI is undefined, then we are in Preview
|
||||||
|
// for Preview we need to show accessDetails.dataImage
|
||||||
|
// as this is where the NFT's SVG (during publish) is stored
|
||||||
|
const nftImage = nftMetadata?.image_data
|
||||||
|
? nftMetadata.image_data
|
||||||
|
: nftMetadata?.image
|
||||||
|
? nftMetadata.image
|
||||||
|
: formikState?.values?.metadata?.nft?.image_data
|
||||||
|
? formikState.values.metadata.nft.image_data
|
||||||
|
: null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.nftImage}>
|
||||||
|
{nftImage ? (
|
||||||
|
<img src={nftImage} alt={asset?.nft?.name} />
|
||||||
|
) : (
|
||||||
|
<Logo noWordmark />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{(nftMetadata || asset?.nftAddress) && (
|
||||||
|
<Tooltip
|
||||||
|
className={styles.tooltip}
|
||||||
|
content={
|
||||||
|
<NftTooltip
|
||||||
|
nft={nftMetadata}
|
||||||
|
address={asset?.nftAddress}
|
||||||
|
chainId={asset?.chainId}
|
||||||
|
isBlockscoutExplorer={isBlockscoutExplorer}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -61,7 +61,9 @@ export default function MarketStats(): ReactElement {
|
|||||||
//
|
//
|
||||||
const getMarketStats = useCallback(async () => {
|
const getMarketStats = useCallback(async () => {
|
||||||
if (!mainChainIds?.length) return
|
if (!mainChainIds?.length) return
|
||||||
|
const newData: {
|
||||||
|
[chainId: number]: FooterStatsValuesGlobalStatistics
|
||||||
|
} = {}
|
||||||
for (const chainId of mainChainIds) {
|
for (const chainId of mainChainIds) {
|
||||||
const context: OperationContext = {
|
const context: OperationContext = {
|
||||||
url: `${getSubgraphUri(
|
url: `${getSubgraphUri(
|
||||||
@ -73,15 +75,12 @@ export default function MarketStats(): ReactElement {
|
|||||||
try {
|
try {
|
||||||
const response = await fetchData(queryGlobalStatistics, null, context)
|
const response = await fetchData(queryGlobalStatistics, null, context)
|
||||||
if (!response?.data?.globalStatistics) return
|
if (!response?.data?.globalStatistics) return
|
||||||
|
newData[chainId] = response.data.globalStatistics[0]
|
||||||
setData((prevState) => ({
|
|
||||||
...prevState,
|
|
||||||
[chainId]: response.data.globalStatistics[0]
|
|
||||||
}))
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LoggerInstance.error('Error fetching global stats: ', error.message)
|
LoggerInstance.error('Error fetching global stats: ', error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setData(newData)
|
||||||
}, [mainChainIds])
|
}, [mainChainIds])
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -96,10 +95,12 @@ export default function MarketStats(): ReactElement {
|
|||||||
//
|
//
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data || !mainChainIds?.length) return
|
if (!data || !mainChainIds?.length) return
|
||||||
|
|
||||||
const newTotal: StatsTotal = {
|
const newTotal: StatsTotal = {
|
||||||
...initialTotal // always start calculating beginning from initial 0 values
|
...initialTotal // always start calculating beginning from initial 0 values
|
||||||
}
|
}
|
||||||
|
const newTVLInOcean: StatsValue = {}
|
||||||
|
const newTotalLiquidity: StatsValue = {}
|
||||||
|
const newPoolCount: StatsValue = {}
|
||||||
|
|
||||||
for (const chainId of mainChainIds) {
|
for (const chainId of mainChainIds) {
|
||||||
const baseTokenValue = data[chainId]?.totalLiquidity[0]?.value
|
const baseTokenValue = data[chainId]?.totalLiquidity[0]?.value
|
||||||
@ -109,25 +110,15 @@ export default function MarketStats(): ReactElement {
|
|||||||
? new Decimal(baseTokenValue).mul(2)
|
? new Decimal(baseTokenValue).mul(2)
|
||||||
: new Decimal(0)
|
: new Decimal(0)
|
||||||
|
|
||||||
setTotalValueLockedInOcean((prevState) => ({
|
newTVLInOcean[chainId] = `${totalValueLockedInOcean}`
|
||||||
...prevState,
|
|
||||||
[chainId]: `${totalValueLockedInOcean}`
|
|
||||||
}))
|
|
||||||
|
|
||||||
const totalOceanLiquidity = Number(baseTokenValue) || 0
|
const totalOceanLiquidity = Number(baseTokenValue) || 0
|
||||||
|
|
||||||
setTotalOceanLiquidity((prevState) => ({
|
newTotalLiquidity[chainId] = `${totalOceanLiquidity}`
|
||||||
...prevState,
|
|
||||||
[chainId]: `${totalOceanLiquidity}`
|
|
||||||
}))
|
|
||||||
|
|
||||||
const poolCount = data[chainId]?.poolCount || 0
|
const poolCount = data[chainId]?.poolCount || 0
|
||||||
|
|
||||||
setPoolCount((prevState) => ({
|
newPoolCount[chainId] = `${poolCount}`
|
||||||
...prevState,
|
|
||||||
[chainId]: `${poolCount}`
|
|
||||||
}))
|
|
||||||
|
|
||||||
const nftCount = data[chainId]?.nftCount || 0
|
const nftCount = data[chainId]?.nftCount || 0
|
||||||
const datatokenCount = data[chainId]?.datatokenCount || 0
|
const datatokenCount = data[chainId]?.datatokenCount || 0
|
||||||
const orderCount = data[chainId]?.orderCount || 0
|
const orderCount = data[chainId]?.orderCount || 0
|
||||||
@ -142,7 +133,9 @@ export default function MarketStats(): ReactElement {
|
|||||||
LoggerInstance.error('Error data manipulation: ', error.message)
|
LoggerInstance.error('Error data manipulation: ', error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setTotalValueLockedInOcean(newTVLInOcean)
|
||||||
|
setTotalOceanLiquidity(newTotalLiquidity)
|
||||||
|
setPoolCount(newPoolCount)
|
||||||
setTotal(newTotal)
|
setTotal(newTotal)
|
||||||
}, [data, mainChainIds, prices, currency])
|
}, [data, mainChainIds, prices, currency])
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
.actions button {
|
.actions button {
|
||||||
margin: 0 calc(var(--spacer) / 2);
|
margin: 0 calc(var(--spacer) / 2);
|
||||||
|
min-height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.infoIcon {
|
.infoIcon {
|
||||||
|
@ -10,6 +10,7 @@ import { useRouter } from 'next/router'
|
|||||||
import Tooltip from '@shared/atoms/Tooltip'
|
import Tooltip from '@shared/atoms/Tooltip'
|
||||||
import AvailableNetworks from 'src/components/Publish/AvailableNetworks'
|
import AvailableNetworks from 'src/components/Publish/AvailableNetworks'
|
||||||
import Info from '@images/info.svg'
|
import Info from '@images/info.svg'
|
||||||
|
import Loader from '@shared/atoms/Loader'
|
||||||
|
|
||||||
export default function Actions({
|
export default function Actions({
|
||||||
scrollToRef,
|
scrollToRef,
|
||||||
@ -59,6 +60,11 @@ export default function Actions({
|
|||||||
(values.user.stepCurrent === 2 && errors.services !== undefined) ||
|
(values.user.stepCurrent === 2 && errors.services !== undefined) ||
|
||||||
(values.user.stepCurrent === 3 && errors.pricing !== undefined)
|
(values.user.stepCurrent === 3 && errors.pricing !== undefined)
|
||||||
|
|
||||||
|
const hasSubmitError =
|
||||||
|
values.feedback?.[1].status === 'error' ||
|
||||||
|
values.feedback?.[2].status === 'error' ||
|
||||||
|
values.feedback?.[3].status === 'error'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className={styles.actions}>
|
<footer className={styles.actions}>
|
||||||
{did ? (
|
{did ? (
|
||||||
@ -107,7 +113,13 @@ export default function Actions({
|
|||||||
style="primary"
|
style="primary"
|
||||||
disabled={isSubmitting || !isValid}
|
disabled={isSubmitting || !isValid}
|
||||||
>
|
>
|
||||||
Submit
|
{isSubmitting ? (
|
||||||
|
<Loader white />
|
||||||
|
) : hasSubmitError ? (
|
||||||
|
'Retry'
|
||||||
|
) : (
|
||||||
|
'Submit'
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -143,13 +143,18 @@ export async function transformPublishFormToDdo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this is the default format hardcoded
|
// this is the default format hardcoded
|
||||||
const file = [
|
const file = {
|
||||||
|
nftAddress,
|
||||||
|
datatokenAddress,
|
||||||
|
files: [
|
||||||
{
|
{
|
||||||
type: 'url',
|
type: 'url',
|
||||||
|
index: 0,
|
||||||
url: files[0].url,
|
url: files[0].url,
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
const filesEncrypted =
|
const filesEncrypted =
|
||||||
!isPreview &&
|
!isPreview &&
|
||||||
files?.length &&
|
files?.length &&
|
||||||
@ -172,7 +177,7 @@ export async function transformPublishFormToDdo(
|
|||||||
'@context': ['https://w3id.org/did/v1'],
|
'@context': ['https://w3id.org/did/v1'],
|
||||||
id: did,
|
id: did,
|
||||||
nftAddress,
|
nftAddress,
|
||||||
version: '4.0.0',
|
version: '4.1.0',
|
||||||
chainId,
|
chainId,
|
||||||
metadata: newMetadata,
|
metadata: newMetadata,
|
||||||
services: [newService],
|
services: [newService],
|
||||||
|
@ -11,7 +11,7 @@ import Actions from './Actions'
|
|||||||
import Debug from './Debug'
|
import Debug from './Debug'
|
||||||
import Navigation from './Navigation'
|
import Navigation from './Navigation'
|
||||||
import { Steps } from './Steps'
|
import { Steps } from './Steps'
|
||||||
import { FormPublishData, PublishFeedback } from './_types'
|
import { FormPublishData } from './_types'
|
||||||
import { useUserPreferences } from '@context/UserPreferences'
|
import { useUserPreferences } from '@context/UserPreferences'
|
||||||
import useNftFactory from '@hooks/contracts/useNftFactory'
|
import useNftFactory from '@hooks/contracts/useNftFactory'
|
||||||
import { ProviderInstance, LoggerInstance, DDO } from '@oceanprotocol/lib'
|
import { ProviderInstance, LoggerInstance, DDO } from '@oceanprotocol/lib'
|
||||||
@ -35,36 +35,34 @@ export default function PublishPage({
|
|||||||
const nftFactory = useNftFactory()
|
const nftFactory = useNftFactory()
|
||||||
const newAbortController = useAbortController()
|
const newAbortController = useAbortController()
|
||||||
|
|
||||||
const [feedback, setFeedback] = useState<PublishFeedback>(
|
// This `feedback` state is auto-synced into Formik context under `values.feedback`
|
||||||
initialPublishFeedback
|
// for use in other components. Syncing defined in ./Steps.tsx child component.
|
||||||
)
|
const [feedback, setFeedback] = useState(initialPublishFeedback)
|
||||||
|
|
||||||
|
// Collecting output of each publish step, enabling retry of failed steps
|
||||||
const [erc721Address, setErc721Address] = useState<string>()
|
const [erc721Address, setErc721Address] = useState<string>()
|
||||||
const [datatokenAddress, setDatatokenAddress] = useState<string>()
|
const [datatokenAddress, setDatatokenAddress] = useState<string>()
|
||||||
const [ddo, setDdo] = useState<DDO>()
|
const [ddo, setDdo] = useState<DDO>()
|
||||||
const [ddoEncrypted, setDdoEncrypted] = useState<string>()
|
const [ddoEncrypted, setDdoEncrypted] = useState<string>()
|
||||||
const [did, setDid] = useState<string>()
|
const [did, setDid] = useState<string>()
|
||||||
|
|
||||||
async function handleSubmit(values: FormPublishData) {
|
|
||||||
// reset all feedback state
|
|
||||||
setFeedback(initialPublishFeedback)
|
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// 1. Create NFT & datatokens & create pricing schema
|
// 1. Create NFT & datatokens & create pricing schema
|
||||||
// Wrapped in conditional allowing method to run
|
|
||||||
// multiple times.
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
if (!erc721Address && !datatokenAddress) {
|
async function create(values: FormPublishData): Promise<{
|
||||||
try {
|
erc721Address: string
|
||||||
|
datatokenAddress: string
|
||||||
|
}> {
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
'1': {
|
'1': {
|
||||||
...prevState['1'],
|
...prevState['1'],
|
||||||
status: 'active',
|
status: 'active',
|
||||||
txCount: values.pricing.type === 'dynamic' ? 2 : 1,
|
errorMessage: null
|
||||||
description: prevState['1'].description
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
try {
|
||||||
const config = getOceanConfig(chainId)
|
const config = getOceanConfig(chainId)
|
||||||
LoggerInstance.log('[publish] using config: ', config)
|
LoggerInstance.log('[publish] using config: ', config)
|
||||||
|
|
||||||
@ -78,8 +76,7 @@ export default function PublishPage({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const isSuccess = Boolean(erc721Address && datatokenAddress && txHash)
|
const isSuccess = Boolean(erc721Address && datatokenAddress && txHash)
|
||||||
setErc721Address(erc721Address)
|
if (!isSuccess) throw new Error('No Token created. Please try again.')
|
||||||
setDatatokenAddress(datatokenAddress)
|
|
||||||
|
|
||||||
LoggerInstance.log('[publish] createTokensAndPricing tx', txHash)
|
LoggerInstance.log('[publish] createTokensAndPricing tx', txHash)
|
||||||
LoggerInstance.log('[publish] erc721Address', erc721Address)
|
LoggerInstance.log('[publish] erc721Address', erc721Address)
|
||||||
@ -89,14 +86,16 @@ export default function PublishPage({
|
|||||||
...prevState,
|
...prevState,
|
||||||
'1': {
|
'1': {
|
||||||
...prevState['1'],
|
...prevState['1'],
|
||||||
status: isSuccess ? 'success' : 'error',
|
status: 'success',
|
||||||
txHash
|
txHash
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
return { erc721Address, datatokenAddress }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LoggerInstance.error('[publish] error', error.message)
|
LoggerInstance.error('[publish] error', error.message)
|
||||||
if (error.message.length > 65) {
|
if (error.message.length > 65) {
|
||||||
error.message = 'No Token created.'
|
error.message = 'No Token created. Please try again.'
|
||||||
}
|
}
|
||||||
|
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
@ -104,14 +103,7 @@ export default function PublishPage({
|
|||||||
'1': {
|
'1': {
|
||||||
...prevState['1'],
|
...prevState['1'],
|
||||||
status: 'error',
|
status: 'error',
|
||||||
errorMessage: error.message,
|
errorMessage: error.message
|
||||||
description:
|
|
||||||
values.pricing.type === 'dynamic'
|
|
||||||
? prevState['1'].description.replace(
|
|
||||||
'a single transaction',
|
|
||||||
'a single transaction, after an initial approve transaction'
|
|
||||||
)
|
|
||||||
: prevState['1'].description
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -119,21 +111,24 @@ export default function PublishPage({
|
|||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// 2. Construct and encrypt DDO
|
// 2. Construct and encrypt DDO
|
||||||
// Wrapped in conditional allowing method to run
|
|
||||||
// multiple times.
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
if (!ddoEncrypted) {
|
async function encrypt(
|
||||||
try {
|
values: FormPublishData,
|
||||||
|
erc721Address: string,
|
||||||
|
datatokenAddress: string
|
||||||
|
): Promise<{ ddo: DDO; ddoEncrypted: string }> {
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
'2': {
|
'2': {
|
||||||
...prevState['2'],
|
...prevState['2'],
|
||||||
status: 'active'
|
status: 'active',
|
||||||
|
errorMessage: null
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
try {
|
||||||
if (!datatokenAddress || !erc721Address)
|
if (!datatokenAddress || !erc721Address)
|
||||||
throw new Error('No NFT or Datatoken received.')
|
throw new Error('No NFT or Datatoken received. Please try again.')
|
||||||
|
|
||||||
const ddo = await transformPublishFormToDdo(
|
const ddo = await transformPublishFormToDdo(
|
||||||
values,
|
values,
|
||||||
@ -141,15 +136,20 @@ export default function PublishPage({
|
|||||||
erc721Address
|
erc721Address
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!ddo) throw new Error('No DDO received. Please try again.')
|
||||||
|
|
||||||
setDdo(ddo)
|
setDdo(ddo)
|
||||||
LoggerInstance.log('[publish] Got new DDO', ddo)
|
LoggerInstance.log('[publish] Got new DDO', ddo)
|
||||||
|
|
||||||
const encryptedResponse = await ProviderInstance.encrypt(
|
const ddoEncrypted = await ProviderInstance.encrypt(
|
||||||
ddo,
|
ddo,
|
||||||
values.services[0].providerUrl.url,
|
values.services[0].providerUrl.url,
|
||||||
newAbortController()
|
newAbortController()
|
||||||
)
|
)
|
||||||
const ddoEncrypted = encryptedResponse
|
|
||||||
|
if (!ddoEncrypted)
|
||||||
|
throw new Error('No encrypted DDO received. Please try again.')
|
||||||
|
|
||||||
setDdoEncrypted(ddoEncrypted)
|
setDdoEncrypted(ddoEncrypted)
|
||||||
LoggerInstance.log('[publish] Got encrypted DDO', ddoEncrypted)
|
LoggerInstance.log('[publish] Got encrypted DDO', ddoEncrypted)
|
||||||
|
|
||||||
@ -157,9 +157,11 @@ export default function PublishPage({
|
|||||||
...prevState,
|
...prevState,
|
||||||
'2': {
|
'2': {
|
||||||
...prevState['2'],
|
...prevState['2'],
|
||||||
status: ddoEncrypted ? 'success' : 'error'
|
status: 'success'
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
return { ddo, ddoEncrypted }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LoggerInstance.error('[publish] error', error.message)
|
LoggerInstance.error('[publish] error', error.message)
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
@ -176,16 +178,23 @@ export default function PublishPage({
|
|||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
// 3. Write DDO into NFT metadata
|
// 3. Write DDO into NFT metadata
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
try {
|
async function publish(
|
||||||
|
values: FormPublishData,
|
||||||
|
ddo: DDO,
|
||||||
|
ddoEncrypted: string
|
||||||
|
): Promise<{ did: string }> {
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
...prevState,
|
...prevState,
|
||||||
'3': {
|
'3': {
|
||||||
...prevState['3'],
|
...prevState['3'],
|
||||||
status: 'active'
|
status: 'active',
|
||||||
|
errorMessage: null
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (!ddo || !ddoEncrypted) throw new Error('No DDO received.')
|
try {
|
||||||
|
if (!ddo || !ddoEncrypted)
|
||||||
|
throw new Error('No DDO received. Please try again.')
|
||||||
|
|
||||||
const res = await setNFTMetadataAndTokenURI(
|
const res = await setNFTMetadataAndTokenURI(
|
||||||
ddo,
|
ddo,
|
||||||
@ -196,7 +205,7 @@ export default function PublishPage({
|
|||||||
)
|
)
|
||||||
if (!res?.transactionHash)
|
if (!res?.transactionHash)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Metadata could not be written into the NFT. Please hit Submit again to retry.'
|
'Metadata could not be written into the NFT. Please try again.'
|
||||||
)
|
)
|
||||||
|
|
||||||
LoggerInstance.log('[publish] setMetadata result', res)
|
LoggerInstance.log('[publish] setMetadata result', res)
|
||||||
@ -210,7 +219,7 @@ export default function PublishPage({
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
setDid(ddo.id)
|
return { did: ddo.id }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LoggerInstance.error('[publish] error', error.message)
|
LoggerInstance.error('[publish] error', error.message)
|
||||||
setFeedback((prevState) => ({
|
setFeedback((prevState) => ({
|
||||||
@ -224,6 +233,44 @@ export default function PublishPage({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------
|
||||||
|
// Orchestrate publishing
|
||||||
|
// --------------------------------------------------
|
||||||
|
async function handleSubmit(values: FormPublishData) {
|
||||||
|
// Syncing variables with state, enabling retry of failed steps
|
||||||
|
let _erc721Address = erc721Address
|
||||||
|
let _datatokenAddress = datatokenAddress
|
||||||
|
let _ddo = ddo
|
||||||
|
let _ddoEncrypted = ddoEncrypted
|
||||||
|
let _did = did
|
||||||
|
|
||||||
|
if (!_erc721Address || !_datatokenAddress) {
|
||||||
|
const { erc721Address, datatokenAddress } = await create(values)
|
||||||
|
_erc721Address = erc721Address
|
||||||
|
_datatokenAddress = datatokenAddress
|
||||||
|
setErc721Address(erc721Address)
|
||||||
|
setDatatokenAddress(datatokenAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_ddo || !_ddoEncrypted) {
|
||||||
|
const { ddo, ddoEncrypted } = await encrypt(
|
||||||
|
values,
|
||||||
|
_erc721Address,
|
||||||
|
_datatokenAddress
|
||||||
|
)
|
||||||
|
_ddo = ddo
|
||||||
|
_ddoEncrypted = ddoEncrypted
|
||||||
|
setDdo(ddo)
|
||||||
|
setDdoEncrypted(ddoEncrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_did) {
|
||||||
|
const { did } = await publish(values, _ddo, _ddoEncrypted)
|
||||||
|
_did = did
|
||||||
|
setDid(did)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return isInPurgatory && purgatoryData ? null : (
|
return isInPurgatory && purgatoryData ? null : (
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
@ -233,8 +280,7 @@ export default function PublishPage({
|
|||||||
await handleSubmit(values)
|
await handleSubmit(values)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{({ values }) => {
|
{({ values }) => (
|
||||||
return (
|
|
||||||
<>
|
<>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title={<Title networkId={values.user.chainId} />}
|
title={<Title networkId={values.user.chainId} />}
|
||||||
@ -247,8 +293,7 @@ export default function PublishPage({
|
|||||||
</Form>
|
</Form>
|
||||||
{debug && <Debug />}
|
{debug && <Debug />}
|
||||||
</>
|
</>
|
||||||
)
|
)}
|
||||||
}}
|
|
||||||
</Formik>
|
</Formik>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user