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

Merge branch 'v4' into feature/v4-c2d and fix conflicts

This commit is contained in:
Bogdan Fazakas 2022-03-28 16:20:58 +03:00
commit c05fa7c7b2
34 changed files with 137 additions and 236 deletions

View File

@ -1,9 +1,8 @@
{
"siteTitle": "Ocean Market",
"siteTagline": "A marketplace to find, publish and trade data sets in the Ocean Network.",
"siteUrl": "https://market.oceanprotocol.com",
"siteIcon": "node_modules/@oceanprotocol/art/logo/favicon-white.png",
"siteImage": "../src/@images/share.png",
"siteUrl": "https://v4.market.oceanprotocol.com",
"siteImage": "/share.png",
"copyright": "All Rights Reserved. Powered by [Ocean Protocol](https://oceanprotocol.com)",
"menu": [
{

2
package-lock.json generated
View File

@ -26715,6 +26715,7 @@
"cross-fetch": "^3.1.5",
"crypto-js": "^4.1.1",
"decimal.js": "^10.3.1",
"web3": "^1.7.1",
"web3-core": "^1.7.1",
"web3-eth-contract": "^1.7.1"
}
@ -26817,6 +26818,7 @@
"integrity": "sha512-5vwpq6kbvwkQwKqAoOU3L72GZ3Ta8RRrewKj9OJRolx28KLJJ8Dg9Rf7obRwt5jQA9bkYd8gqzMTrI7H3xLfaw==",
"dev": true,
"requires": {
"@oclif/config": "^1.15.1",
"@oclif/errors": "^1.3.3",
"@oclif/parser": "^3.8.3",
"@oclif/plugin-help": "^3",

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
public/apple-touch-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

1
public/icon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

14
public/site.webmanifest Normal file
View File

@ -0,0 +1,14 @@
{
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

View File

@ -2,7 +2,6 @@ export interface UseSiteMetadata {
siteTitle: string
siteTagline: string
siteUrl: string
siteIcon: string
siteImage: string
copyright: string
menu: {

View File

@ -4,6 +4,7 @@ import { randomIntFromInterval } from './numbers'
export interface WaveProperties {
width?: number
height?: number
viewBox?: string
color?: string
fill?: boolean
layerCount?: number
@ -53,6 +54,7 @@ export class SvgWaves {
return {
width: 99,
height: 99,
viewBox: '0 0 99 99',
color: WaveColors.Pink,
fill: true,
layerCount: 4,
@ -107,8 +109,7 @@ export class SvgWaves {
generateSvg(): Element {
const svg = document.createElementNS(SvgWaves.xmlns, 'svg')
svg.setAttribute('width', this.properties.width.toString())
svg.setAttribute('height', this.properties.height.toString())
svg.setAttribute('viewBox', this.properties.viewBox.toString())
svg.setAttribute('fill', this.properties.fill ? undefined : 'transparent')
svg.setAttribute('xmlns', SvgWaves.xmlns)

View File

@ -11,13 +11,6 @@ export function getOrderFeedback(
}
}
export function getCollectTokensFeedback(
baseTokenSymbol: string,
baseTokenBalance: string
) {
return `Collecting ${baseTokenBalance} ${baseTokenSymbol} from asset `
}
export function getComputeFeedback(
baseTokenSymbol?: string,
datatokenSymbol?: string,

View File

@ -4,7 +4,7 @@ import styles from './index.module.css'
import Loader from '../atoms/Loader'
interface ButtonBuyProps {
action: 'download' | 'compute' | 'collect'
action: 'download' | 'compute'
disabled: boolean
hasPreviousOrder: boolean
hasDatatoken: boolean
@ -148,8 +148,6 @@ export default function ButtonBuy({
? 'Start Compute Job'
: priceType === 'free' && algorithmPriceType === 'free'
? 'Order Compute Job'
: action === 'collect'
? `Collect ${dtBalance} ${dtSymbol}`
: `Buy Compute Job`
return (

View File

@ -17,24 +17,35 @@ export default function Seo({
// Remove trailing slash from all URLs
const canonical = `${siteUrl}${uri}`.replace(/\/$/, '')
const pageTitle = title
? `${title} - ${siteTitle}`
: `${siteTitle}${siteTagline}`
return (
<Head>
<html lang="en" />
<title>{`${siteTitle}${siteTagline}`}</title>
<title>{pageTitle}</title>
{isBrowser &&
window.location &&
window.location.hostname !== 'oceanprotocol.com' && (
<meta name="robots" content="noindex,nofollow" />
)}
{isBrowser && window?.location?.hostname !== 'oceanprotocol.com' && (
<meta name="robots" content="noindex,nofollow" />
)}
<link rel="canonical" href={canonical} />
<link rel="icon" href="/favicon.ico" sizes="any" />
<link rel="icon" href="/icon.svg" type="image/svg+xml" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="/apple-touch-icon.png"
/>
<link rel="manifest" href="/site.webmanifest" />
<meta name="theme-color" content="var(--background-content)" />
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={uri} />
<meta property="og:url" content={canonical} />
<meta name="image" content={`${siteUrl}${siteImage}`} />
<meta property="og:image" content={`${siteUrl}${siteImage}`} />

View File

@ -16,10 +16,3 @@
width: 100%;
margin-top: calc(var(--spacer));
}
.collect {
width: 100%;
justify-content: center;
text-align: center;
margin-top: calc(var(--spacer) / 2);
}

View File

@ -7,37 +7,16 @@ import ButtonBuy from '@shared/ButtonBuy'
import { secondsToString } from '@utils/ddo'
import AlgorithmDatasetsListForCompute from './Compute/AlgorithmDatasetsListForCompute'
import styles from './Download.module.css'
import {
FileMetadata,
LoggerInstance,
ZERO_ADDRESS,
FixedRateExchange
} from '@oceanprotocol/lib'
import { FileMetadata, LoggerInstance, ZERO_ADDRESS } from '@oceanprotocol/lib'
import { order } from '@utils/order'
import { AssetExtended } from 'src/@types/AssetExtended'
import { buyDtFromPool } from '@utils/pool'
import { downloadFile } from '@utils/provider'
import { getCollectTokensFeedback, getOrderFeedback } from '@utils/feedback'
import { getOrderFeedback } from '@utils/feedback'
import { getOrderPriceAndFees } from '@utils/accessDetailsAndPricing'
import { OrderPriceAndFees } from 'src/@types/Price'
import { toast } from 'react-toastify'
import { gql, OperationResult } from 'urql'
import { fetchData, getQueryContext } from '@utils/subgraph'
import { getOceanConfig } from '@utils/ocean'
import { FixedRateExchanges } from 'src/@types/subgraph/FixedRateExchanges'
const FixedRateExchangesQuery = gql`
query FixedRateExchanges($user: String, $exchangeId: String) {
fixedRateExchanges(where: { owner: $user, exchangeId: $exchangeId }) {
id
owner {
id
}
exchangeId
baseTokenBalance
}
}
`
export default function Download({
asset,
file,
@ -61,9 +40,7 @@ export default function Download({
const [isLoading, setIsLoading] = useState(false)
const [isOwned, setIsOwned] = useState(false)
const [validOrderTx, setValidOrderTx] = useState('')
const [isCollectLoading, setIsCollectLoading] = useState(false)
const [baseTokenBalance, setBaseTokenBalance] = useState(0)
const [collectStatusText, setCollectStatusText] = useState('')
const [orderPriceAndFees, setOrderPriceAndFees] =
useState<OrderPriceAndFees>()
useEffect(() => {
@ -108,41 +85,19 @@ export default function Download({
isOwned
])
useEffect(() => {
if (!accountId || asset.nft.owner !== accountId) return
const queryContext = getQueryContext(Number(asset.chainId))
async function getBaseTokenBalance() {
const variables = {
user: accountId.toLowerCase(),
exchangeId: asset?.accessDetails?.addressOrId
}
const result: OperationResult<FixedRateExchanges> = await fetchData(
FixedRateExchangesQuery,
variables,
queryContext
)
result?.data?.fixedRateExchanges[0]?.baseTokenBalance
? setBaseTokenBalance(
parseInt(result?.data?.fixedRateExchanges[0]?.baseTokenBalance)
)
: setBaseTokenBalance(0)
}
getBaseTokenBalance()
}, [accountId, asset?.accessDetails?.addressOrId, asset.chainId, asset.nft])
async function handleOrderOrDownload() {
setIsLoading(true)
if (isOwned) {
setStatusText(
getOrderFeedback(
asset.accessDetails?.baseToken?.symbol,
asset.accessDetails?.datatoken?.symbol
)[3]
)
await downloadFile(web3, asset, accountId, validOrderTx)
} else {
try {
try {
if (isOwned) {
setStatusText(
getOrderFeedback(
asset.accessDetails?.baseToken?.symbol,
asset.accessDetails?.datatoken?.symbol
)[3]
)
await downloadFile(web3, asset, accountId, validOrderTx)
} else {
if (!hasDatatoken && asset.accessDetails.type === 'dynamic') {
setStatusText(
getOrderFeedback(
@ -152,9 +107,7 @@ export default function Download({
)
const tx = await buyDtFromPool(asset.accessDetails, accountId, web3)
if (!tx) {
toast.error('Failed to buy datatoken from pool!')
setIsLoading(false)
return
throw new Error()
}
}
setStatusText(
@ -165,51 +118,19 @@ export default function Download({
)
const orderTx = await order(web3, asset, orderPriceAndFees, accountId)
if (!orderTx) {
toast.error('Failed to buy datatoken from pool!')
setIsLoading(false)
return
throw new Error()
}
setIsOwned(true)
setValidOrderTx(orderTx.transactionHash)
} catch (ex) {
LoggerInstance.log(ex.message)
setIsLoading(false)
}
}
setIsLoading(false)
}
async function handleCollectTokens() {
setIsCollectLoading(true)
const config = getOceanConfig(asset?.chainId)
const fixed = new FixedRateExchange(web3, config.fixedRateExchangeAddress)
try {
setCollectStatusText(
getCollectTokensFeedback(
asset.accessDetails.baseToken?.symbol,
baseTokenBalance.toString()
)
)
const tx = await fixed.collectBT(
accountId,
asset?.accessDetails?.addressOrId,
baseTokenBalance.toString()
)
if (!tx) {
setIsCollectLoading(false)
return
}
setBaseTokenBalance(0)
return tx
} catch (error) {
LoggerInstance.log(error.message)
setIsCollectLoading(false)
} finally {
setIsCollectLoading(false)
LoggerInstance.error(error)
const message = isOwned
? 'Failed to download file!'
: 'Failed to buy datatoken from pool!'
toast.error(message)
}
setIsLoading(false)
}
const PurchaseButton = () => (
@ -234,26 +155,6 @@ export default function Download({
/>
)
const CollectTokensButton = () => (
<ButtonBuy
action="collect"
onClick={handleCollectTokens}
disabled={baseTokenBalance === 0 || !baseTokenBalance}
hasPreviousOrder={false}
hasDatatoken={false}
dtSymbol={asset?.accessDetails?.baseToken.symbol}
dtBalance={baseTokenBalance.toString()}
datasetLowPoolLiquidity={false}
assetType=""
stepText={collectStatusText}
assetTimeout=""
isConsumable={false}
consumableFeedback=""
isBalanceSufficient={false}
isLoading={isCollectLoading}
/>
)
return (
<aside className={styles.consume}>
<div className={styles.info}>
@ -271,13 +172,6 @@ export default function Download({
</div>
</div>
{asset?.accessDetails?.datatoken?.name !== '' &&
asset?.nft.owner === accountId && (
<div className={styles.collect}>
<CollectTokensButton />
</div>
)}
{asset?.metadata?.type === 'algorithm' && (
<AlgorithmDatasetsListForCompute
algorithmDid={asset.id}

View File

@ -6,11 +6,13 @@ import ExplorerLink from '@shared/ExplorerLink'
import SuccessConfetti from '@shared/SuccessConfetti'
import { useWeb3 } from '@context/Web3'
import TokenApproval from '@shared/TokenApproval'
import Decimal from 'decimal.js'
export default function Actions({
isLoading,
loaderMessage,
successMessage,
slippage,
txId,
actionName,
amount,
@ -23,6 +25,7 @@ export default function Actions({
isLoading: boolean
loaderMessage: string
successMessage: string
slippage?: string
txId: string
actionName: string
amount?: string
@ -45,6 +48,18 @@ export default function Actions({
</Button>
)
const applySlippage = (amount: string) => {
if (!amount) return '0'
const newAmount = new Decimal(amount)
.mul(
new Decimal(1)
.plus(new Decimal(slippage).div(new Decimal(100)))
.toString()
)
.toString()
return newAmount
}
return (
<>
<div className={styles.actions}>
@ -53,7 +68,7 @@ export default function Actions({
) : actionName === 'Supply' || actionName === 'Swap' ? (
<TokenApproval
actionButton={actionButton}
amount={amount}
amount={slippage ? applySlippage(amount) : amount}
tokenAddress={tokenAddress}
tokenSymbol={tokenSymbol}
disabled={isDisabled}

View File

@ -193,6 +193,7 @@ export default function FormTrade({
loaderMessage="Swapping tokens..."
successMessage="Successfully swapped tokens."
actionName={content.trade.action}
slippage={values.slippage}
amount={
values.type === 'sell'
? values.datatoken

View File

@ -4,10 +4,13 @@ import {
Field,
FieldInputProps,
FormikContextType,
useFormikContext
useFormikContext,
useField
} from 'formik'
import Input from '@shared/FormInput'
import debounce from 'lodash.debounce'
import Button from '@shared/atoms/Button'
import Input from '@shared/FormInput'
import Error from '@shared/FormInput/Error'
import { FormTradeData, TradeItem } from './_types'
import UserLiquidity from '../UserLiquidity'
import { useWeb3 } from '@context/Web3'
@ -28,11 +31,10 @@ export default function TradeInput({
// Connect with form
const {
handleChange,
setFieldValue,
validateForm,
values
}: FormikContextType<FormTradeData> = useFormikContext()
const [field, meta] = useField(name)
const isTopField =
(name === 'baseToken' && values.type === 'buy') ||
(name === 'datatoken' && values.type === 'sell')
@ -61,11 +63,13 @@ export default function TradeInput({
form={form}
value={`${field.value}`}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
handleValueChange(name, Number(e.target.value))
validateForm()
handleChange(e)
handleValueChange(name, Number(e.target.value))
// debounce needed to avoid validating the wrong (pass) value
debounce(() => validateForm(), 100)
}}
disabled={!accountId || disabled}
additionalComponent={<Error meta={meta} />}
/>
)}
</Field>

View File

@ -149,25 +149,12 @@ export default function AssetActions({
/>
)
const tabs: TabsItem[] = [
{
title: 'Use',
content: UseContent
}
]
const tabs: TabsItem[] = [{ title: 'Use', content: UseContent }]
asset?.accessDetails?.type === 'dynamic' &&
tabs.push(
{
title: 'Pool',
content: <Pool />,
disabled: asset?.accessDetails.datatoken.name === ''
},
{
title: 'Trade',
content: <Trade />,
disabled: asset?.accessDetails.datatoken.name === ''
}
{ title: 'Pool', content: <Pool /> },
{ title: 'Trade', content: <Trade /> }
)
return (

View File

@ -14,14 +14,14 @@ export default function DebugEditMetadata({
const linksTransformed = values.links?.length &&
values.links[0].valid && [values.links[0].url.replace('javascript:', '')]
const newMetadata: Metadata = {
...asset.metadata,
...asset?.metadata,
name: values.name,
description: values.description,
links: linksTransformed,
author: values.author
}
const updatedService: Service = {
...asset.services[0],
...asset?.services[0],
timeout: mapTimeoutStringToSeconds(values.timeout)
}
const updatedAsset: Asset = {

View File

@ -17,7 +17,6 @@ import { mapTimeoutStringToSeconds } from '@utils/ddo'
import styles from './index.module.css'
import content from '../../../../content/pages/edit.json'
import { AssetExtended } from 'src/@types/AssetExtended'
import { setMinterToPublisher, setMinterToDispenser } from '@utils/dispenser'
import { useAbortController } from '@hooks/useAbortController'
import DebugEditMetadata from './DebugEditMetadata'
import { getOceanConfig } from '@utils/ocean'
@ -36,7 +35,6 @@ export default function Edit({
const newAbortController = useAbortController()
const [success, setSuccess] = useState<string>()
const [error, setError] = useState<string>()
const [timeoutStringValue, setTimeoutStringValue] = useState<string>()
const isComputeType = asset?.services[0]?.type === 'compute'
const hasFeedback = error || success
@ -130,7 +128,7 @@ export default function Edit({
await handleSubmit(values, resetForm)
}}
>
{({ isSubmitting, values, initialValues }) =>
{({ isSubmitting, values }) =>
isSubmitting || hasFeedback ? (
<EditFeedback
title="Updating Data Set"
@ -151,8 +149,6 @@ export default function Edit({
<article>
<FormEditMetadata
data={content.form.data}
setTimeoutStringValue={setTimeoutStringValue}
values={initialValues}
showPrice={asset?.accessDetails?.type === 'fixed'}
isComputeDataset={isComputeType}
/>

View File

@ -18,3 +18,15 @@
margin-left: calc(var(--spacer) / 2);
margin-right: calc(var(--spacer) / 2);
}
.actions a {
padding: calc(var(--spacer) / 3);
font-weight: var(--font-weight-bold);
text-transform: uppercase;
transition: 0.2s ease-out;
}
.actions a:hover {
transform: translate3d(0, -0.05rem, 0);
text-decoration: none;
}

View File

@ -3,15 +3,14 @@ import React, { ReactElement } from 'react'
import { useAsset } from '@context/Asset'
import Button from '@shared/atoms/Button'
import styles from './FormActions.module.css'
import Link from 'next/link'
export default function FormActions({
setShowEdit,
handleClick
}: {
setShowEdit: (show: boolean) => void
handleClick?: () => void
}): ReactElement {
const { isAssetNetwork } = useAsset()
const { isAssetNetwork, asset } = useAsset()
const { isValid }: FormikContextType<Partial<any>> = useFormikContext()
return (
@ -23,9 +22,9 @@ export default function FormActions({
>
Submit
</Button>
<Button style="text" onClick={() => setShowEdit(false)}>
<Link href={`/asset/${asset?.id}`} key={asset?.id}>
Cancel
</Button>
</Link>
</footer>
)
}

View File

@ -27,7 +27,6 @@ export default function FormEditComputeDataset({
}): ReactElement {
const { appConfig } = useSiteMetadata()
const { asset } = useAsset()
const [showEditCompute, setShowEditCompute] = useState<boolean>()
const { values }: FormikContextType<ComputePrivacyForm> = useFormikContext()
const [allAlgorithms, setAllAlgorithms] = useState<AssetSelectionAsset[]>()
const newCancelToken = useCancelToken()
@ -83,8 +82,7 @@ export default function FormEditComputeDataset({
/>
))}
{/* <FormActions setShowEdit={setShowEdit} /> */}
<FormActions setShowEdit={setShowEditCompute} />
<FormActions />
</Form>
)
}

View File

@ -53,19 +53,14 @@ function handleTimeoutCustomOption(
export default function FormEditMetadata({
data,
setTimeoutStringValue,
values,
showPrice,
isComputeDataset
}: {
data: InputProps[]
setTimeoutStringValue: (value: string) => void
values: Partial<MetadataEditForm>
showPrice: boolean
isComputeDataset: boolean
}): ReactElement {
const { oceanConfig } = useAsset()
const [showEdit, setShowEdit] = useState<boolean>()
const {
validateField,
setFieldValue
@ -118,10 +113,7 @@ export default function FormEditMetadata({
)
)}
<FormActions
setShowEdit={setShowEdit}
// handleClick={() => setTimeoutStringValue(values?.services[0]?.timeout)}
/>
<FormActions />
</Form>
)
}

View File

@ -32,6 +32,8 @@
.description {
font-size: var(--font-size-large);
margin: calc(var(--spacer) * 0.3 / var(--line-height)) 0
calc(var(--spacer) / var(--line-height)) 0;
}
.title {

View File

@ -11,24 +11,19 @@ import { useWeb3 } from '@context/Web3'
import Alert from '@shared/atoms/Alert'
export default function Edit({ uri }: { uri: string }): ReactElement {
const { asset, error, loading, owner } = useAsset()
const { asset, error, isInPurgatory, owner, title } = useAsset()
const [isCompute, setIsCompute] = useState(false)
const [isOnwer, setIsOwner] = useState(false)
const [pageTitle, setPageTitle] = useState<string>('')
const { accountId } = useWeb3()
// Switch type value upon tab change
function handleTabChange(tabName: string) {
LoggerInstance.log('switched to tab', tabName)
// add store restore from
}
useEffect(() => {
if (!asset || error) {
if (!asset || error || accountId !== owner) {
setPageTitle('Edit action not available')
return
}
setPageTitle(isInPurgatory ? '' : `Edit ${title}`)
setIsCompute(asset?.services[0]?.type === 'compute')
setIsOwner(owner === accountId)
}, [asset, error])
}, [asset, error, isInPurgatory, title])
const tabs = [
{
@ -42,23 +37,14 @@ export default function Edit({ uri }: { uri: string }): ReactElement {
}
].filter((tab) => tab !== undefined)
return asset && !loading && isOnwer ? (
<Page uri={uri}>
<div className={styles.contianer}>
<Tabs
items={tabs}
handleTabChange={handleTabChange}
defaultIndex={0}
className={styles.edit}
/>
return asset && asset?.accessDetails && accountId === owner ? (
<Page title={pageTitle} noPageHeader uri={uri}>
<div className={styles.container}>
<Tabs items={tabs} defaultIndex={0} className={styles.edit} />
</div>
</Page>
) : !isOnwer ? (
<Page
title="Edit action available only to asset owner"
noPageHeader
uri={uri}
>
) : asset && asset?.accessDetails && accountId !== owner ? (
<Page title={pageTitle} noPageHeader uri={uri}>
<Alert
title="Edit action available only to asset owner"
text={error}
@ -66,7 +52,7 @@ export default function Edit({ uri }: { uri: string }): ReactElement {
/>
</Page>
) : (
<Page title={undefined} uri={uri}>
<Page title={pageTitle} noPageHeader uri={uri}>
<Loader />
</Page>
)

View File

@ -4,6 +4,10 @@
margin-bottom: var(--spacer);
margin-left: calc(var(--spacer) / -4);
margin-right: calc(var(--spacer) / -4);
/* Disable all user actions as to not run into unintended
consequences of browsing away from publish. */
pointer-events: none;
}
@media (min-width: 60rem) {

View File

@ -4,7 +4,7 @@ import InputElement from '@shared/FormInput/InputElement'
import Logo from '@images/logo.svg'
import Conversion from '@shared/Price/Conversion'
import { useField } from 'formik'
import Error from './Error'
import Error from '@shared/FormInput/Error'
export default function Coin({
datatokenOptions,

View File

@ -3,7 +3,7 @@ import Tooltip from '@shared/atoms/Tooltip'
import styles from './Fees.module.css'
import { useField } from 'formik'
import Input from '@shared/FormInput'
import Error from './Error'
import Error from '@shared/FormInput/Error'
import { getOpcFees } from '../../../@utils/subgraph'
import { OpcFeesQuery_opc as OpcFeesData } from '../../../@types/subgraph/OpcFeesQuery'
import { useWeb3 } from '@context/Web3'

View File

@ -2,7 +2,7 @@ import Conversion from '@shared/Price/Conversion'
import { Field, useField, useFormikContext } from 'formik'
import React, { ReactElement } from 'react'
import Input from '@shared/FormInput'
import Error from './Error'
import Error from '@shared/FormInput/Error'
import PriceUnit from '@shared/Price/PriceUnit'
import styles from './Price.module.css'
import { FormPublishData } from '../_types'

View File

@ -8,7 +8,7 @@ export default function PageAssetDetails(): ReactElement {
const { did } = router.query
return (
<AssetProvider did={did as string}>
<PageTemplateAssetDetails uri={router.pathname} />
<PageTemplateAssetDetails uri={router.asPath} />
</AssetProvider>
)
}