1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

Fetching prices from Aquarius in AssetList component (#1774)

* Fetching prices from Aquarius in AssetList component

* Removing unused imports

* Removing fetching logic from AssetList

* Using Asset Price from Aquarius

* removing unused code for loader

* Updating ocean.js

* Updating price format in tests

* removing console logs

* Fixing build issues

* Updating condition for showing free price

* Fixing tests

* Removing logs

* Showing No pricing schema available on asset teaser

* Showing No pricing schema available on asset detail page

* Adding additional tests

* Removing console logs

* Avoiding getInitialPaymentCollector failure (#1816)

* early return is no web3 or ddo

* Creating test for MetaFull

* adding test: src/components/Asset/AssetContent/MetaSecondary.test.tsx

* Adding test for bookmarks

* Adding test for displaying payment collector

* Removing comments

* Renaming assetAquarius

* Renaming assetWithAccessDetails

* Ensuring that the payment collector is shown even without a wallet connected

* Removing broken test

* Using getDummyWeb3 for fetching the payment collector address

* google validation (#1835)

* Updating validation to exclude any google link

* Updating Yup validation

* Checking if domain includes google.com

* Updating isGoogleUrl function

* Moving isGoogleUrl into @utils/url/index file

* isGoogleUrl function

* Updating tests

* Adding additional tests for other google domains

* Updating tests

* Updating isGoogleUrl file path

* Updating pricing message (#1842)

* Bump @storybook/addon-essentials from 6.5.13 to 6.5.15 (#1841)

Bumps [@storybook/addon-essentials](https://github.com/storybookjs/storybook/tree/HEAD/addons/essentials) from 6.5.13 to 6.5.15.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/v6.5.15/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.5.15/addons/essentials)

---
updated-dependencies:
- dependency-name: "@storybook/addon-essentials"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump @types/jest from 29.2.3 to 29.2.5 (#1840)

Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.2.3 to 29.2.5.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump prettier from 2.8.0 to 2.8.1 (#1837)

Bumps [prettier](https://github.com/prettier/prettier) from 2.8.0 to 2.8.1.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/2.8.0...2.8.1)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump react-select from 5.6.1 to 5.7.0 (#1839)

Bumps [react-select](https://github.com/JedWatson/react-select) from 5.6.1 to 5.7.0.
- [Release notes](https://github.com/JedWatson/react-select/releases)
- [Changelog](https://github.com/JedWatson/react-select/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/JedWatson/react-select/compare/react-select@5.6.1...react-select@5.7.0)

---
updated-dependencies:
- dependency-name: react-select
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump react-tabs from 5.1.0 to 6.0.0 (#1838)

Bumps [react-tabs](https://github.com/reactjs/react-tabs) from 5.1.0 to 6.0.0.
- [Release notes](https://github.com/reactjs/react-tabs/releases)
- [Commits](https://github.com/reactjs/react-tabs/compare/v5.1.0...v6.0.0)

---
updated-dependencies:
- dependency-name: react-tabs
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix asset route (#1836)

* updating the buy button message for free assets

* Updating pricing text for compute and algorithms

* Updating tests

* Adding a seperate sentence about paying gas fees for network charges with free assets

* Fixing tests

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* Showing hosting type in File Info (#1846)

* Bump @storybook/addon-essentials from 6.5.13 to 6.5.15 (#1841)

Bumps [@storybook/addon-essentials](https://github.com/storybookjs/storybook/tree/HEAD/addons/essentials) from 6.5.13 to 6.5.15.
- [Release notes](https://github.com/storybookjs/storybook/releases)
- [Changelog](https://github.com/storybookjs/storybook/blob/v6.5.15/CHANGELOG.md)
- [Commits](https://github.com/storybookjs/storybook/commits/v6.5.15/addons/essentials)

---
updated-dependencies:
- dependency-name: "@storybook/addon-essentials"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump @types/jest from 29.2.3 to 29.2.5 (#1840)

Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.2.3 to 29.2.5.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump prettier from 2.8.0 to 2.8.1 (#1837)

Bumps [prettier](https://github.com/prettier/prettier) from 2.8.0 to 2.8.1.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/2.8.0...2.8.1)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump react-select from 5.6.1 to 5.7.0 (#1839)

Bumps [react-select](https://github.com/JedWatson/react-select) from 5.6.1 to 5.7.0.
- [Release notes](https://github.com/JedWatson/react-select/releases)
- [Changelog](https://github.com/JedWatson/react-select/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/JedWatson/react-select/compare/react-select@5.6.1...react-select@5.7.0)

---
updated-dependencies:
- dependency-name: react-select
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump react-tabs from 5.1.0 to 6.0.0 (#1838)

Bumps [react-tabs](https://github.com/reactjs/react-tabs) from 5.1.0 to 6.0.0.
- [Release notes](https://github.com/reactjs/react-tabs/releases)
- [Commits](https://github.com/reactjs/react-tabs/compare/v5.1.0...v6.0.0)

---
updated-dependencies:
- dependency-name: react-tabs
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix asset route (#1836)

* Adding hosting type to the file info component

* Writting smart contract hosting type across two lines

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* add initial price value for not supported price assets (#1851)

* Updating test

* Updating accessDetailsAndPricing

* Adding orderPriceAndFees back in to show the price with fees on the asset detail page

* Using price with fees for compute assets

* Fixing conversions by ensuring that the symbol is always sent through

* Removing unwanted changes in package-lock.json

* Updating use of isUnsupportedPricing variable

* Getting rid of getAccessDetailsForAssets completely

* Removing unused imports and query

* Fixing test

* Removing unused import

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mihaisc <mihai.scarlat@smartcontrol.ro>
Co-authored-by: Bogdan Fazakas <bogdan.fazakas@gmail.com>
This commit is contained in:
Jamie Hewitt 2023-02-09 12:25:15 +03:00 committed by GitHub
parent 5a935fcd48
commit ed4645e13c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 77 additions and 245 deletions

View File

@ -1,3 +0,0 @@
import { assets } from '../../__fixtures__/datasetsWithAccessDetails'
export const getAccessDetailsForAssets = jest.fn().mockResolvedValue(assets)

View File

@ -5,11 +5,6 @@ import {
TokenPriceQuery_token as TokenPrice TokenPriceQuery_token as TokenPrice
} from '../@types/subgraph/TokenPriceQuery' } from '../@types/subgraph/TokenPriceQuery'
import { import {
TokensPriceQuery,
TokensPriceQuery_tokens as TokensPrice
} from '../@types/subgraph/TokensPriceQuery'
import {
Asset,
LoggerInstance, LoggerInstance,
ProviderFees, ProviderFees,
ProviderInstance ProviderInstance
@ -21,64 +16,6 @@ import {
publisherMarketOrderFee publisherMarketOrderFee
} from '../../app.config' } from '../../app.config'
const tokensPriceQuery = gql`
query TokensPriceQuery($datatokenIds: [ID!], $account: String) {
tokens(first: 1000, where: { id_in: $datatokenIds }) {
id
symbol
name
publishMarketFeeAddress
publishMarketFeeToken
publishMarketFeeAmount
templateId
orders(
where: { payer: $account }
orderBy: createdTimestamp
orderDirection: desc
) {
tx
serviceIndex
createdTimestamp
reuses(orderBy: createdTimestamp, orderDirection: desc) {
id
caller
createdTimestamp
tx
block
}
}
dispensers {
id
active
isMinter
maxBalance
token {
id
name
symbol
}
}
fixedRateExchanges {
id
exchangeId
price
publishMarketSwapFee
baseToken {
symbol
name
address
decimals
}
datatoken {
symbol
name
address
}
active
}
}
}
`
const tokenPriceQuery = gql` const tokenPriceQuery = gql`
query TokenPriceQuery($datatokenId: ID!, $account: String) { query TokenPriceQuery($datatokenId: ID!, $account: String) {
token(id: $datatokenId) { token(id: $datatokenId) {
@ -139,7 +76,7 @@ const tokenPriceQuery = gql`
` `
function getAccessDetailsFromTokenPrice( function getAccessDetailsFromTokenPrice(
tokenPrice: TokenPrice | TokensPrice, tokenPrice: TokenPrice,
timeout?: number timeout?: number
): AccessDetails { ): AccessDetails {
const accessDetails = {} as AccessDetails const accessDetails = {} as AccessDetails
@ -216,7 +153,7 @@ export async function getOrderPriceAndFees(
providerFees?: ProviderFees providerFees?: ProviderFees
): Promise<OrderPriceAndFees> { ): Promise<OrderPriceAndFees> {
const orderPriceAndFee = { const orderPriceAndFee = {
price: '0', price: String(asset?.stats?.price?.value || '0'),
publisherMarketOrderFee: publisherMarketOrderFee || '0', publisherMarketOrderFee: publisherMarketOrderFee || '0',
publisherMarketFixedSwapFee: '0', publisherMarketFixedSwapFee: '0',
consumeMarketOrderFee: consumeMarketOrderFee || '0', consumeMarketOrderFee: consumeMarketOrderFee || '0',
@ -291,56 +228,3 @@ export async function getAccessDetails(
LoggerInstance.error('Error getting access details: ', error.message) LoggerInstance.error('Error getting access details: ', error.message)
} }
} }
export async function getAccessDetailsForAssets(
assets: Asset[],
account = ''
): Promise<AssetExtended[]> {
const assetsExtended: AssetExtended[] = assets
const chainAssetLists: { [key: number]: string[] } = {}
try {
for (const asset of assets) {
if (chainAssetLists[asset.chainId]) {
chainAssetLists[asset.chainId].push(
asset.services[0].datatokenAddress.toLowerCase()
)
} else {
chainAssetLists[asset.chainId] = []
chainAssetLists[asset.chainId].push(
asset.services[0].datatokenAddress.toLowerCase()
)
}
}
for (const chainKey in chainAssetLists) {
const queryContext = getQueryContext(Number(chainKey))
const tokenQueryResult: OperationResult<
TokensPriceQuery,
{ datatokenIds: [string]; account: string }
> = await fetchData(
tokensPriceQuery,
{
datatokenIds: chainAssetLists[chainKey],
account: account?.toLowerCase()
},
queryContext
)
tokenQueryResult?.data?.tokens?.forEach((token) => {
const currentAsset = assetsExtended.find(
(asset) =>
asset.services[0].datatokenAddress.toLowerCase() === token.id
)
const accessDetails = getAccessDetailsFromTokenPrice(
token,
currentAsset?.services[0]?.timeout
)
currentAsset.accessDetails = accessDetails
})
}
return assetsExtended
} catch (error) {
LoggerInstance.error('Error getting access details: ', error.message)
}
}

View File

@ -1,4 +1,3 @@
import { getAccessDetailsForAssets } from './accessDetailsAndPricing'
import { PublisherTrustedAlgorithm, Asset } from '@oceanprotocol/lib' import { PublisherTrustedAlgorithm, Asset } from '@oceanprotocol/lib'
import { AssetSelectionAsset } from '@shared/FormInput/InputElement/AssetSelection' import { AssetSelectionAsset } from '@shared/FormInput/InputElement/AssetSelection'
import { getServiceByName } from './ddo' import { getServiceByName } from './ddo'
@ -8,17 +7,14 @@ export async function transformAssetToAssetSelection(
assets: Asset[], assets: Asset[],
selectedAlgorithms?: PublisherTrustedAlgorithm[] selectedAlgorithms?: PublisherTrustedAlgorithm[]
): Promise<AssetSelectionAsset[]> { ): Promise<AssetSelectionAsset[]> {
const extendedAssets: AssetExtended[] = await getAccessDetailsForAssets(
assets
)
const algorithmList: AssetSelectionAsset[] = [] const algorithmList: AssetSelectionAsset[] = []
for (const asset of extendedAssets) { for (const asset of assets) {
const algoService = const algoService =
getServiceByName(asset, 'compute') || getServiceByName(asset, 'access') getServiceByName(asset, 'compute') || getServiceByName(asset, 'access')
if ( if (
asset?.accessDetails?.price && asset?.stats?.price?.value &&
algoService?.serviceEndpoint === datasetProviderEndpoint algoService?.serviceEndpoint === datasetProviderEndpoint
) { ) {
let selected = false let selected = false
@ -30,7 +26,7 @@ export async function transformAssetToAssetSelection(
const algorithmAsset: AssetSelectionAsset = { const algorithmAsset: AssetSelectionAsset = {
did: asset.id, did: asset.id,
name: asset.metadata.name, name: asset.metadata.name,
price: asset.accessDetails.price, price: asset.stats.price.value,
checked: selected, checked: selected,
symbol: asset.datatokens[0].symbol symbol: asset.datatokens[0].symbol
} }

View File

@ -1,19 +1,7 @@
import AssetTeaser from '@shared/AssetTeaser' import AssetTeaser from '@shared/AssetTeaser'
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement } from 'react'
import Pagination from '@shared/Pagination' import Pagination from '@shared/Pagination'
import styles from './index.module.css' import styles from './index.module.css'
import Loader from '@shared/atoms/Loader'
import { useIsMounted } from '@hooks/useIsMounted'
import { getAccessDetailsForAssets } from '@utils/accessDetailsAndPricing'
import { useWeb3 } from '@context/Web3'
function LoaderArea() {
return (
<div className={styles.loaderWrap}>
<Loader />
</div>
)
}
export declare type AssetListProps = { export declare type AssetListProps = {
assets: AssetExtended[] assets: AssetExtended[]
@ -33,52 +21,27 @@ export default function AssetList({
showPagination, showPagination,
page, page,
totalPages, totalPages,
isLoading,
onPageChange, onPageChange,
className, className,
noPublisher, noPublisher,
noDescription, noDescription,
noPrice noPrice
}: AssetListProps): ReactElement { }: AssetListProps): ReactElement {
const { accountId } = useWeb3() // This changes the page field inside the query
const [assetsWithPrices, setAssetsWithPrices] =
useState<AssetExtended[]>(assets)
const [loading, setLoading] = useState<boolean>(isLoading)
const isMounted = useIsMounted()
useEffect(() => {
if (!assets || !assets.length) return
setAssetsWithPrices(assets as AssetExtended[])
setLoading(false)
async function fetchPrices() {
const assetsWithPrices = await getAccessDetailsForAssets(
assets,
accountId || ''
)
if (!isMounted() || !assetsWithPrices) return
setAssetsWithPrices([...assetsWithPrices])
}
fetchPrices()
}, [assets, isMounted, accountId])
// // This changes the page field inside the query
function handlePageChange(selected: number) { function handlePageChange(selected: number) {
onPageChange(selected + 1) onPageChange(selected + 1)
} }
const styleClasses = `${styles.assetList} ${className || ''}` const styleClasses = `${styles.assetList} ${className || ''}`
return loading ? ( return (
<LoaderArea />
) : (
<> <>
<div className={styleClasses}> <div className={styleClasses}>
{assetsWithPrices?.length > 0 ? ( {assets?.length > 0 ? (
assetsWithPrices?.map((assetWithPrice) => ( assets?.map((asset) => (
<AssetTeaser <AssetTeaser
asset={assetWithPrice} asset={asset}
key={assetWithPrice.id} key={asset.id}
noPublisher={noPublisher} noPublisher={noPublisher}
noDescription={noDescription} noDescription={noDescription}
noPrice={noPrice} noPrice={noPrice}

View File

@ -1,8 +1,23 @@
import React from 'react' import React from 'react'
import { render, screen } from '@testing-library/react'
import testRender from '../../../../.jest/testRender' import testRender from '../../../../.jest/testRender'
import AssetTeaser from './index' import AssetTeaser from './index'
import { asset } from '../../../../.jest/__fixtures__/datasetWithAccessDetails' import { asset } from '../../../../.jest/__fixtures__/datasetWithAccessDetails'
describe('@shared/AssetTeaser', () => { describe('@shared/AssetTeaser', () => {
testRender(<AssetTeaser asset={asset} />) testRender(<AssetTeaser asset={asset} />)
it('renders no pricing schema available', () => {
asset.stats.price = null
render(<AssetTeaser asset={asset} />)
expect(screen.getByText('No pricing schema available')).toBeInTheDocument()
expect(screen.getByText('This is a test.')).toBeInTheDocument()
})
it('renders asset teaser with no description', () => {
asset.metadata.description = null
render(<AssetTeaser asset={asset} />)
expect(
screen.queryByText('This is a test description')
).not.toBeInTheDocument()
})
}) })

View File

@ -21,16 +21,18 @@ export declare type AssetTeaserProps = {
export default function AssetTeaser({ export default function AssetTeaser({
asset, asset,
noPublisher, noPublisher,
noDescription, noDescription
noPrice
}: AssetTeaserProps): ReactElement { }: AssetTeaserProps): ReactElement {
const { name, type, description } = asset.metadata const { name, type, description } = asset.metadata
const { datatokens } = asset const { datatokens } = asset
const isCompute = Boolean(getServiceByName(asset, 'compute')) const isCompute = Boolean(getServiceByName(asset, 'compute'))
const accessType = isCompute ? 'compute' : 'access' const accessType = isCompute ? 'compute' : 'access'
const { owner } = asset.nft const { owner } = asset.nft
const { orders, allocated } = asset.stats const { orders, allocated, price } = asset.stats
const isUnsupportedPricing = asset?.accessDetails?.type === 'NOT_SUPPORTED' const isUnsupportedPricing =
!asset.services.length ||
asset?.stats?.price?.value === undefined ||
asset?.accessDetails?.type === 'NOT_SUPPORTED'
const { locale } = useUserPreferences() const { locale } = useUserPreferences()
return ( return (
@ -60,15 +62,13 @@ export default function AssetTeaser({
</Dotdotdot> </Dotdotdot>
</div> </div>
)} )}
{!noPrice && (
<div className={styles.price}> <div className={styles.price}>
{isUnsupportedPricing || !asset.services.length ? ( {isUnsupportedPricing ? (
<strong>No pricing schema available</strong> <strong>No pricing schema available</strong>
) : ( ) : (
<Price accessDetails={asset.accessDetails} size="small" /> <Price price={price} assetId={asset.id} size="small" />
)} )}
</div> </div>
)}
<footer className={styles.footer}> <footer className={styles.footer}>
{allocated && allocated > 0 ? ( {allocated && allocated > 0 ? (
<span className={styles.typeLabel}> <span className={styles.typeLabel}>

View File

@ -7,21 +7,21 @@ describe('@shared/FormInput/InputElement/AssetSelection', () => {
{ {
did: 'did:op:xxx', did: 'did:op:xxx',
name: 'Asset', name: 'Asset',
price: '10', price: 10,
checked: false, checked: false,
symbol: 'OCEAN' symbol: 'OCEAN'
}, },
{ {
did: 'did:op:yyy', did: 'did:op:yyy',
name: 'Asset', name: 'Asset',
price: '10', price: 10,
checked: true, checked: true,
symbol: 'OCEAN' symbol: 'OCEAN'
}, },
{ {
did: 'did:op:zzz', did: 'did:op:zzz',
name: 'Asset', name: 'Asset',
price: '0', price: 0,
checked: false, checked: false,
symbol: 'OCEAN' symbol: 'OCEAN'
} }

View File

@ -10,7 +10,7 @@ import styles from './index.module.css'
export interface AssetSelectionAsset { export interface AssetSelectionAsset {
did: string did: string
name: string name: string
price: string price: number
checked: boolean checked: boolean
symbol: string symbol: string
} }
@ -106,8 +106,7 @@ export default function AssetSelection({
</label> </label>
<PriceUnit <PriceUnit
price={Number(asset.price)} price={asset.price}
type={asset.price === '0' ? 'free' : undefined}
size="small" size="small"
className={styles.price} className={styles.price}
/> />

View File

@ -59,14 +59,14 @@ describe('@shared/FormInput', () => {
{ {
did: 'did:op:xxx', did: 'did:op:xxx',
name: 'Asset', name: 'Asset',
price: '10', price: 10,
checked: false, checked: false,
symbol: 'OCEAN' symbol: 'OCEAN'
}, },
{ {
did: 'did:op:yyy', did: 'did:op:yyy',
name: 'Asset', name: 'Asset',
price: '10', price: 10,
checked: true, checked: true,
symbol: 'OCEAN' symbol: 'OCEAN'
} }

View File

@ -10,11 +10,9 @@ export default function PriceUnit({
size = 'small', size = 'small',
conversion, conversion,
symbol, symbol,
type,
decimals decimals
}: { }: {
price: number price: number
type?: string
className?: string className?: string
size?: 'small' | 'mini' | 'large' size?: 'small' | 'mini' | 'large'
conversion?: boolean conversion?: boolean
@ -25,12 +23,14 @@ export default function PriceUnit({
return ( return (
<div className={`${styles.price} ${styles[size]} ${className}`}> <div className={`${styles.price} ${styles[size]} ${className}`}>
{type === 'free' ? ( {price === 0 ? (
<div>Free</div> <div>Free</div>
) : !price || Number.isNaN(price) ? (
<div>-</div>
) : ( ) : (
<> <>
<div> <div>
{Number.isNaN(price) ? '-' : formatNumber(price, locale, decimals)}{' '} {formatNumber(price, locale, decimals)}
<span className={styles.symbol}>{symbol}</span> <span className={styles.symbol}>{symbol}</span>
</div> </div>
{conversion && <Conversion price={price} symbol={symbol} />} {conversion && <Conversion price={price} symbol={symbol} />}

View File

@ -13,39 +13,25 @@ describe('@shared/Price', () => {
it('renders fixed price', () => { it('renders fixed price', () => {
render( render(
<Price <Price
accessDetails={{ ...asset.accessDetails, type: 'fixed', price: '10' }} price={{ value: 10, tokenSymbol: 'OCEAN', tokenAddress: '0x123' }}
/> />
) )
expect(screen.getByText('10')).toBeInTheDocument() expect(screen.getByText('10')).toBeInTheDocument()
}) })
it('renders free price', () => { it('renders free price', () => {
render(<Price accessDetails={{ ...asset.accessDetails, type: 'free' }} />) render(<Price price={{ value: 0 }} />)
expect(screen.getByText('Free')).toBeInTheDocument() expect(screen.getByText('Free')).toBeInTheDocument()
}) })
it('renders null price', () => { it('renders null price', () => {
render(<Price accessDetails={{ ...asset.accessDetails, price: null }} />) render(<Price price={{ value: null }} />)
expect(screen.getByText('-')).toBeInTheDocument() expect(screen.getByText('-')).toBeInTheDocument()
}) })
it('renders conversion', async () => { it('renders conversion', async () => {
render( render(<Price price={asset.stats.price} conversion />)
<Price
accessDetails={{ ...asset.accessDetails, price: '10' }}
conversion
/>
)
expect(await screen.findByText('≈')).toBeInTheDocument() expect(await screen.findByText('≈')).toBeInTheDocument()
}) })
it('renders no conversion when no price defined', async () => { it('renders no conversion when no price defined', async () => {
render( render(<Price price={{ value: null, tokenSymbol: 'TEST' }} conversion />)
<Price
accessDetails={{ ...asset.accessDetails, price: null }}
conversion
/>
)
expect(screen.queryByText('≈')).not.toBeInTheDocument() expect(screen.queryByText('≈')).not.toBeInTheDocument()
}) })
}) })

View File

@ -1,32 +1,30 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { AssetPrice } from '@oceanprotocol/lib'
import PriceUnit from './PriceUnit' import PriceUnit from './PriceUnit'
export default function Price({ export default function Price({
accessDetails, price,
orderPriceAndFees, orderPriceAndFees,
className, className,
size, size,
conversion conversion
}: { }: {
accessDetails: AccessDetails price: AssetPrice
orderPriceAndFees?: OrderPriceAndFees orderPriceAndFees?: OrderPriceAndFees
assetId?: string
className?: string className?: string
conversion?: boolean conversion?: boolean
size?: 'small' | 'mini' | 'large' size?: 'small' | 'mini' | 'large'
}): ReactElement { }): ReactElement {
const isSupported = if (!price && !orderPriceAndFees) return
accessDetails?.type === 'free' ||
(accessDetails?.type === 'fixed' && accessDetails?.baseToken?.symbol)
const price = `${orderPriceAndFees?.price || accessDetails?.price}`
return isSupported ? ( return (
<PriceUnit <PriceUnit
price={Number(price)} price={Number(orderPriceAndFees?.price) || price?.value}
symbol={accessDetails?.baseToken?.symbol} symbol={price?.tokenSymbol}
className={className} className={className}
size={size} size={size}
conversion={conversion} conversion={conversion}
type={accessDetails?.type}
/> />
) : null )
} }

View File

@ -433,7 +433,7 @@ export default function Compute({
/> />
) : ( ) : (
<Price <Price
accessDetails={asset?.accessDetails} price={asset.stats?.price}
orderPriceAndFees={datasetOrderPriceAndFees} orderPriceAndFees={datasetOrderPriceAndFees}
conversion conversion
size="large" size="large"

View File

@ -51,6 +51,9 @@ export default function Download({
const [retry, setRetry] = useState<boolean>(false) const [retry, setRetry] = useState<boolean>(false)
const isUnsupportedPricing = const isUnsupportedPricing =
!asset?.accessDetails ||
!asset.services.length ||
asset?.stats?.price?.value === undefined ||
asset?.accessDetails?.type === 'NOT_SUPPORTED' || asset?.accessDetails?.type === 'NOT_SUPPORTED' ||
(asset?.accessDetails?.type === 'fixed' && (asset?.accessDetails?.type === 'fixed' &&
!asset?.accessDetails?.baseToken?.symbol) !asset?.accessDetails?.baseToken?.symbol)
@ -60,7 +63,7 @@ export default function Download({
}, [asset?.nft.state]) }, [asset?.nft.state])
useEffect(() => { useEffect(() => {
if (!asset?.accessDetails || isUnsupportedPricing) return if (isUnsupportedPricing) return
setIsOwned(asset?.accessDetails?.isOwned || false) setIsOwned(asset?.accessDetails?.isOwned || false)
setValidOrderTx(asset?.accessDetails?.validOrderTx || '') setValidOrderTx(asset?.accessDetails?.validOrderTx || '')
@ -100,7 +103,6 @@ export default function Download({
(asset?.accessDetails?.type === 'fixed' && !orderPriceAndFees) || (asset?.accessDetails?.type === 'fixed' && !orderPriceAndFees) ||
!isMounted || !isMounted ||
!accountId || !accountId ||
!asset?.accessDetails ||
isUnsupportedPricing isUnsupportedPricing
) )
return return
@ -202,7 +204,7 @@ export default function Download({
/> />
) : ( ) : (
<> <>
{isUnsupportedPricing || !asset.services.length ? ( {isUnsupportedPricing ? (
<Alert <Alert
className={styles.fieldWarning} className={styles.fieldWarning}
state="info" state="info"
@ -214,7 +216,7 @@ export default function Download({
<Loader message="Calculating full price (including fees)" /> <Loader message="Calculating full price (including fees)" />
) : ( ) : (
<Price <Price
accessDetails={asset.accessDetails} price={asset.stats?.price}
orderPriceAndFees={orderPriceAndFees} orderPriceAndFees={orderPriceAndFees}
conversion conversion
size="large" size="large"

View File

@ -7,7 +7,6 @@ import Tooltip from '@shared/atoms/Tooltip'
import AssetTitle from '@shared/AssetListTitle' import AssetTitle from '@shared/AssetListTitle'
import { getAssetsFromDids } from '@utils/aquarius' import { getAssetsFromDids } from '@utils/aquarius'
import { useCancelToken } from '@hooks/useCancelToken' import { useCancelToken } from '@hooks/useCancelToken'
import { getAccessDetailsForAssets } from '@utils/accessDetailsAndPricing'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { useMarketMetadata } from '@context/MarketMetadata' import { useMarketMetadata } from '@context/MarketMetadata'
@ -32,7 +31,7 @@ const columns: TableOceanColumn<AssetExtended>[] = [
}, },
{ {
name: 'Price', name: 'Price',
selector: (row) => <Price accessDetails={row.accessDetails} size="small" />, selector: (row) => <Price price={row.stats.price} size="small" />,
right: true right: true
} }
] ]
@ -66,11 +65,7 @@ export default function Bookmarks(): ReactElement {
) )
if (!result?.length) return if (!result?.length) return
const pinnedAssets: AssetExtended[] = await getAccessDetailsForAssets( setPinned(result)
result,
accountId
)
setPinned(pinnedAssets)
} catch (error) { } catch (error) {
LoggerInstance.error(`Bookmarks error:`, error.message) LoggerInstance.error(`Bookmarks error:`, error.message)
} finally { } finally {

View File

@ -5,7 +5,6 @@ import Conversion from '@shared/Price/Conversion'
import NumberUnit from './NumberUnit' import NumberUnit from './NumberUnit'
import styles from './Stats.module.css' import styles from './Stats.module.css'
import { useProfile } from '@context/Profile' import { useProfile } from '@context/Profile'
import { getAccessDetailsForAssets } from '@utils/accessDetailsAndPricing'
import { getLocked } from '@utils/veAllocation' import { getLocked } from '@utils/veAllocation'
import PriceUnit from '@shared/Price/PriceUnit' import PriceUnit from '@shared/Price/PriceUnit'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
@ -37,12 +36,10 @@ export default function Stats({
async function getPublisherTotalSales() { async function getPublisherTotalSales() {
try { try {
const assetsPrices = await getAccessDetailsForAssets(assets)
let count = 0 let count = 0
for (const priceInfo of assetsPrices) { for (const priceInfo of assets) {
if (priceInfo?.accessDetails?.price && priceInfo.stats.orders > 0) { if (priceInfo?.stats?.price?.value && priceInfo.stats.orders > 0) {
count += count += priceInfo.stats.price.value * priceInfo.stats.orders
parseInt(priceInfo.accessDetails.price) * priceInfo.stats.orders
} }
} }
setTotalSales(count) setTotalSales(count)