diff --git a/content/pages/publish.json b/content/pages/publish.json index af3d784a8..bc1b6ebc2 100644 --- a/content/pages/publish.json +++ b/content/pages/publish.json @@ -35,11 +35,9 @@ "required": true }, { - "name": "cost", + "name": "price", "label": "Price", - "help": "Set your price for accessing this data set in Ocean Tokens.", "type": "price", - "min": 1, "required": true }, { diff --git a/src/@types/MetaData.d.ts b/src/@types/MetaData.d.ts index 766651bb0..8d75484ee 100644 --- a/src/@types/MetaData.d.ts +++ b/src/@types/MetaData.d.ts @@ -5,12 +5,9 @@ import { ServiceMetadata } from '@oceanprotocol/lib' -export declare type AccessType = 'Download' | 'Compute' - export interface AdditionalInformationMarket extends AdditionalInformation { links?: File[] termsAndConditions: boolean - access: AccessType | string } export interface MetadataMarket extends Metadata { @@ -24,7 +21,10 @@ export interface MetadataPublishForm { files: string | File[] author: string license: string - cost: string + price: { + cost: number + tokensToMint: number + } access: 'Download' | 'Compute' | string termsAndConditions: boolean // ---- optional fields ---- diff --git a/src/components/atoms/Input/Help.tsx b/src/components/atoms/Input/Help.tsx index 99d98ea90..9152b1fd0 100644 --- a/src/components/atoms/Input/Help.tsx +++ b/src/components/atoms/Input/Help.tsx @@ -1,9 +1,23 @@ import React, { ReactElement } from 'react' import styles from './Help.module.css' import Markdown from '../Markdown' +import classNames from 'classnames/bind' -const FormHelp = ({ children }: { children: string }): ReactElement => ( - -) +const cx = classNames.bind(styles) + +const FormHelp = ({ + children, + className +}: { + children: string + className?: string +}): ReactElement => { + const styleClasses = cx({ + help: true, + [className]: className + }) + + return +} export default FormHelp diff --git a/src/components/atoms/Input/InputElement.module.css b/src/components/atoms/Input/InputElement.module.css index d468b5dc9..fc21df932 100644 --- a/src/components/atoms/Input/InputElement.module.css +++ b/src/components/atoms/Input/InputElement.module.css @@ -12,6 +12,7 @@ border-radius: var(--border-radius); transition: 0.2s ease-out; min-height: 43px; + min-width: 0; appearance: none; display: block; } @@ -33,7 +34,8 @@ .input[readonly], .input[disabled] { - background-color: var(--brand-grey-lighter); + background-color: var(--brand-grey-dimmed); + color: var(--brand-grey-light); cursor: not-allowed; pointer-events: none; } @@ -84,6 +86,52 @@ padding-left: 0.5rem; } +.prefixGroup, +.postfixGroup { + display: inline-flex; + align-items: center; +} + +.prefixGroup input { + border-left: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.postfixGroup input { + border-right: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.prefix, +.postfix { + border: 1px solid var(--brand-grey-lighter); + min-height: 43px; + display: flex; + align-items: center; + padding-left: calc(var(--spacer) / 4); + padding-right: calc(var(--spacer) / 4); + color: var(--color-secondary); + font-size: var(--font-size-small); + transition: border 0.2s ease-out; + white-space: nowrap; +} + +.prefix { + border-top-left-radius: var(--border-radius); + border-bottom-left-radius: var(--border-radius); +} + +.postfix { + border-top-right-radius: var(--border-radius); + border-bottom-right-radius: var(--border-radius); +} + +.input:focus + .postfix { + border-color: var(--brand-grey); +} + /* Size modifiers */ .small { diff --git a/src/components/atoms/Input/InputElement.tsx b/src/components/atoms/Input/InputElement.tsx index ec780206d..78a0b4d1d 100644 --- a/src/components/atoms/Input/InputElement.tsx +++ b/src/components/atoms/Input/InputElement.tsx @@ -4,9 +4,23 @@ import styles from './InputElement.module.css' import { InputProps } from '.' import FilesInput from '../../molecules/FormFields/FilesInput' import Terms from '../../molecules/FormFields/Terms' +import Price from '../../molecules/FormFields/Price' + +const DefaultInput = ( + { name, type }: { name: string; type?: string }, + props: InputProps +) => ( + +) export default function InputElement(props: InputProps): ReactElement { - const { type, options, rows, name, value } = props + const { type, options, rows, name, prefix, postfix } = props switch (type) { case 'select': @@ -56,18 +70,19 @@ export default function InputElement(props: InputProps): ReactElement { ) case 'files': return + case 'price': + return case 'terms': return default: - return ( - + return prefix || postfix ? ( +
+ {prefix &&
{prefix}
} + + {postfix &&
{postfix}
} +
+ ) : ( + ) } } diff --git a/src/components/atoms/Input/index.tsx b/src/components/atoms/Input/index.tsx index c20d58d98..bdedc1670 100644 --- a/src/components/atoms/Input/index.tsx +++ b/src/components/atoms/Input/index.tsx @@ -1,4 +1,4 @@ -import React, { FormEvent, ChangeEvent, ReactElement } from 'react' +import React, { FormEvent, ChangeEvent, ReactElement, ReactNode } from 'react' import InputElement from './InputElement' import Help from './Help' import Label from './Label' @@ -31,8 +31,12 @@ export interface InputProps { pattern?: string min?: string disabled?: boolean + readOnly?: boolean field?: any form?: any + prefix?: string + postfix?: string + step?: string } export default function Input(props: Partial): ReactElement { diff --git a/src/components/atoms/Price/Conversion.module.css b/src/components/atoms/Price/Conversion.module.css index 1dedb014e..21c71782d 100644 --- a/src/components/atoms/Price/Conversion.module.css +++ b/src/components/atoms/Price/Conversion.module.css @@ -1,6 +1,6 @@ .conversion { display: inline-block; - font-size: var(--font-size-mini); + font-size: var(--font-size-small); margin-left: calc(var(--spacer) / 6); color: var(--color-secondary); } diff --git a/src/components/atoms/Price/Conversion.tsx b/src/components/atoms/Price/Conversion.tsx index 66a0e9267..2c85b5580 100644 --- a/src/components/atoms/Price/Conversion.tsx +++ b/src/components/atoms/Price/Conversion.tsx @@ -2,19 +2,29 @@ import React, { useEffect, useState, ReactElement } from 'react' import useSWR from 'swr' import { fetchData, isBrowser } from '../../../utils' import styles from './Conversion.module.css' +import classNames from 'classnames/bind' + +const cx = classNames.bind(styles) const currencies = 'EUR' // comma-separated list const url = `https://api.coingecko.com/api/v3/simple/price?ids=ocean-protocol&vs_currencies=${currencies}&include_24hr_change=true` export default function Conversion({ price, - update = true + update = true, + className }: { price: string // expects price in OCEAN, not wei update?: boolean + className?: string }): ReactElement { const [priceEur, setPriceEur] = useState('0.00') + const styleClasses = cx({ + conversion: true, + [className]: className + }) + const onSuccess = async (data: { 'ocean-protocol': { eur: number } }) => { if (!data) return if (!price || price === '' || price === '0') { @@ -45,5 +55,12 @@ export default function Conversion({ }) } - return ≈ EUR {priceEur} + return ( + + ≈ EUR {priceEur} + + ) } diff --git a/src/components/atoms/Table/index.tsx b/src/components/atoms/Table/index.tsx index 08fd14c82..0a2fe5e38 100644 --- a/src/components/atoms/Table/index.tsx +++ b/src/components/atoms/Table/index.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { ReactElement } from 'react' import DataTable from 'react-data-table-component' export declare type AssetTablePagination = { diff --git a/src/components/atoms/Tabs.module.css b/src/components/atoms/Tabs.module.css new file mode 100644 index 000000000..cc5215d74 --- /dev/null +++ b/src/components/atoms/Tabs.module.css @@ -0,0 +1,26 @@ +.tabList { + text-align: center; + border-bottom: 1px solid var(--brand-grey-lighter); + padding-top: calc(var(--spacer) / 2); + padding-bottom: calc(var(--spacer) / 2); +} + +.tab { + display: inline-block; + padding: calc(var(--spacer) / 12) var(--spacer); + border-radius: var(--border-radius); + font-weight: var(--font-weight-bold); + font-size: var(--font-size-small); + text-transform: uppercase; + cursor: pointer; + color: var(--brand-grey-light); +} + +.tab[aria-selected='true'] { + background: var(--brand-black); + color: var(--brand-white); +} + +.tabContent { + padding: var(--spacer); +} diff --git a/src/components/atoms/Tabs.tsx b/src/components/atoms/Tabs.tsx new file mode 100644 index 000000000..88f2f0878 --- /dev/null +++ b/src/components/atoms/Tabs.tsx @@ -0,0 +1,33 @@ +import React, { ReactElement, ReactNode } from 'react' +import { Tab, Tabs as ReactTabs, TabList, TabPanel } from 'react-tabs' +import styles from './Tabs.module.css' + +interface TabsItem { + title: string + content: ReactNode +} + +export default function Tabs({ + items, + className +}: { + items: TabsItem[] + className?: string +}): ReactElement { + return ( + + + {items.map((item) => ( + + {item.title} + + ))} + +
+ {items.map((item) => ( + {item.content} + ))} +
+
+ ) +} diff --git a/src/components/molecules/FormFields/FilesInput/index.tsx b/src/components/molecules/FormFields/FilesInput/index.tsx index 06b9297bc..555a451cd 100644 --- a/src/components/molecules/FormFields/FilesInput/index.tsx +++ b/src/components/molecules/FormFields/FilesInput/index.tsx @@ -36,7 +36,7 @@ export default function FilesInput(props: InputProps): ReactElement { return ( <> - {typeof field.value === 'object' ? ( + {field && typeof field.value === 'object' ? ( ) : ( ) => void +}): ReactElement { + const { appConfig } = useSiteMetadata() + const { account, balance, chainId } = useOcean() + + const [error, setError] = useState() + const correctNetwork = isCorrectNetwork(chainId) + const desiredNetworkName = appConfig.network.replace(/^\w/, (c: string) => + c.toUpperCase() + ) + + // Check: account, network & insuffciant balance + useEffect(() => { + if (!account) { + setError(`No account connected. Please connect your Web3 wallet.`) + } else if (!correctNetwork) { + setError(`Wrong Network. Please connect to ${desiredNetworkName}.`) + } else if (balance.ocean < ocean) { + setError(`Insufficiant balance. You need at least ${ocean} OCEAN`) + } else { + setError(undefined) + } + }, [ocean]) + + return ( +
+
+ + {`Let's create a decentralized, automated market for your data set. A Data Token contract for this data set worth the entered amount of OCEAN will be created. Additionally, you will provide liquidity into a Data Token/OCEAN + liquidity pool with Balancer.`} + + + + +

Data Token Liquidity Pool

+ +
+ + +
+ + {error && ( +
+ +
+ )} +
+
+ ) +} diff --git a/src/components/molecules/FormFields/Price/Coin.module.css b/src/components/molecules/FormFields/Price/Coin.module.css new file mode 100644 index 000000000..6e04ccf8e --- /dev/null +++ b/src/components/molecules/FormFields/Price/Coin.module.css @@ -0,0 +1,59 @@ +.coin { + padding: var(--spacer) calc(var(--spacer) / 2); + border-top: 1px solid var(--brand-grey-lighter); +} + +.coin:last-child { + border-left: 1px solid var(--brand-grey-lighter); +} + +.icon { + composes: box from '../../../atoms/Box.module.css'; + padding: calc(var(--spacer) / 1.5); + width: 6rem; + height: 6rem; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid var(--brand-grey-lighter); + border-radius: 50%; + background-color: var(--brand-white); + margin-bottom: var(--spacer); +} + +.coin:last-child .icon path { + fill: var(--brand-grey-dimmed); + stroke: var(--brand-black); + stroke-width: 5px; + stroke-linejoin: round; +} + +.data { + position: relative; + width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: center; + text-align: center; + max-width: 12rem; + margin: auto; +} + +.max { + position: absolute; + right: var(--spacer); + top: calc(var(--spacer) / 2.5); +} + +.weight { + width: 100%; + margin-top: var(--spacer); + text-transform: uppercase; + font-size: var(--font-size-small); + color: var(--color-secondary); +} + +.weight strong { + color: var(--brand-grey); + font-size: var(--font-size-base); +} diff --git a/src/components/molecules/FormFields/Price/Coin.tsx b/src/components/molecules/FormFields/Price/Coin.tsx new file mode 100644 index 000000000..93fd344ef --- /dev/null +++ b/src/components/molecules/FormFields/Price/Coin.tsx @@ -0,0 +1,46 @@ +import React, { ReactElement, ChangeEvent } from 'react' +import stylesIndex from './index.module.css' +import styles from './Coin.module.css' +import InputElement from '../../../atoms/Input/InputElement' +import { ReactComponent as Logo } from '../../../../images/logo.svg' +import Conversion from '../../../atoms/Price/Conversion' + +export default function Coin({ + symbol, + name, + value, + weight, + onChange, + readOnly +}: { + symbol: string + name: string + value: string + weight: string + onChange?: (event: ChangeEvent) => void + readOnly?: boolean +}): ReactElement { + return ( +
+
+ +
+ +
+ + + +
+ Weight {weight} +
+
+
+ ) +} diff --git a/src/components/molecules/FormFields/Price/Simple.module.css b/src/components/molecules/FormFields/Price/Simple.module.css new file mode 100644 index 000000000..59027445a --- /dev/null +++ b/src/components/molecules/FormFields/Price/Simple.module.css @@ -0,0 +1,8 @@ +.form { + max-width: 12rem; + margin: 0 auto; +} + +.simple label { + display: none; +} diff --git a/src/components/molecules/FormFields/Price/Simple.tsx b/src/components/molecules/FormFields/Price/Simple.tsx new file mode 100644 index 000000000..c5ef99512 --- /dev/null +++ b/src/components/molecules/FormFields/Price/Simple.tsx @@ -0,0 +1,40 @@ +import React, { ReactElement, ChangeEvent } from 'react' +import stylesIndex from './index.module.css' +import styles from './Simple.module.css' +import FormHelp from '../../../atoms/Input/Help' +import Label from '../../../atoms/Input/Label' +import InputElement from '../../../atoms/Input/InputElement' +import Conversion from '../../../atoms/Price/Conversion' + +export default function Simple({ + ocean, + onChange +}: { + ocean: string + onChange: (event: ChangeEvent) => void +}): ReactElement { + return ( +
+
+ + Set your price for accessing this data set. A Data Token contract for + this data set, worth the entered amount of OCEAN will be created. + + +
+ + + + + + +
+
+ ) +} diff --git a/src/components/molecules/FormFields/Price/index.module.css b/src/components/molecules/FormFields/Price/index.module.css new file mode 100644 index 000000000..0ccfe68e3 --- /dev/null +++ b/src/components/molecules/FormFields/Price/index.module.css @@ -0,0 +1,33 @@ +.price { + border: 1px solid var(--brand-grey-lighter); + background: var(--brand-grey-dimmed); + border-radius: var(--border-radius); +} + +.content { + padding: 0 calc(var(--spacer) / 2); +} + +.content label { + color: var(--color-secondary); +} + +.content input { + text-align: center; +} + +.content p { + margin-bottom: 0; +} + +.conversion { + width: 100%; + display: block; + text-align: center; + margin-top: calc(var(--spacer) / 6); +} + +.help { + text-align: center; + margin-bottom: calc(var(--spacer) / 1.5); +} diff --git a/src/components/molecules/FormFields/Price/index.tsx b/src/components/molecules/FormFields/Price/index.tsx new file mode 100644 index 000000000..c07761eb9 --- /dev/null +++ b/src/components/molecules/FormFields/Price/index.tsx @@ -0,0 +1,54 @@ +import React, { ReactElement, useState, ChangeEvent, useEffect } from 'react' +import { InputProps } from '../../../atoms/Input' +import styles from './index.module.css' +import Tabs from '../../../atoms/Tabs' +import Simple from './Simple' +import Advanced from './Advanced' +import { useField } from 'formik' + +export default function Price(props: InputProps): ReactElement { + const [field, meta, helpers] = useField(props) + + const cost = 1 + const weightOnDataToken = '90' // in % + const [ocean, setOcean] = useState('1') + const [tokensToMint, setTokensToMint] = useState() + + function handleOceanChange(event: ChangeEvent) { + setOcean(event.target.value) + } + + // Always update everything when ocean changes + useEffect(() => { + const tokensToMint = Number(ocean) * (Number(weightOnDataToken) / 10) + setTokensToMint(tokensToMint) + helpers.setValue({ cost, tokensToMint }) + }, [ocean]) + + const tabs = [ + { + title: 'Simple: Fixed', + content: + }, + { + title: 'Advanced: Dynamic', + content: ( + + ) + } + ] + + return ( +
+ +
+        {JSON.stringify(field.value)}
+      
+
+ ) +} diff --git a/src/components/molecules/Menu.module.css b/src/components/molecules/Menu.module.css index 37c279a23..5b8ff2083 100644 --- a/src/components/molecules/Menu.module.css +++ b/src/components/molecules/Menu.module.css @@ -66,7 +66,7 @@ padding: calc(var(--spacer) / 2); margin-left: var(--spacer); text-transform: uppercase; - color: var(--brand-grey); + color: var(--brand-grey-light); font-weight: var(--font-weight-bold); font-size: var(--font-size-base); position: relative; @@ -82,13 +82,13 @@ .link:hover, .link:focus, .link:active { - color: var(--brand-pink); + color: var(--brand-grey); } .link[aria-current], .link[aria-current]:hover, .link[aria-current]:focus { - color: var(--brand-pink); + color: var(--brand-black); } .link:last-child { diff --git a/src/components/molecules/Wallet/Account.module.css b/src/components/molecules/Wallet/Account.module.css index 8952d5ed2..62ea614a9 100644 --- a/src/components/molecules/Wallet/Account.module.css +++ b/src/components/molecules/Wallet/Account.module.css @@ -8,12 +8,16 @@ padding: calc(var(--spacer) / 4); white-space: nowrap; background: none; - color: var(--brand-grey); margin: 0; transition: border 0.2s ease-out; cursor: pointer; } +.button, +.address { + color: var(--brand-grey); +} + .button:hover, .button:focus { transform: none; @@ -21,6 +25,10 @@ border-color: var(--brand-grey-light); } +.button.initial { + color: var(--brand-pink); +} + .blockies { width: var(--font-size-large); height: var(--font-size-large); diff --git a/src/components/molecules/Wallet/Account.tsx b/src/components/molecules/Wallet/Account.tsx index fd277021d..8f706e81d 100644 --- a/src/components/molecules/Wallet/Account.tsx +++ b/src/components/molecules/Wallet/Account.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { FormEvent } from 'react' import styles from './Account.module.css' import { useOcean } from '@oceanprotocol/react' import { toDataUrl } from 'ethereum-blockies' @@ -26,8 +26,20 @@ const Account = React.forwardRef((props, ref: any) => { const { accountId, status, connect, chainId } = useOcean() const hasSuccess = status === 1 && isCorrectNetwork(chainId) + async function handleActivation(e: FormEvent) { + // prevent accidentially submitting a form the button might be in + e.preventDefault() + await connect() + } + return accountId ? ( - ) : ( ) }) diff --git a/src/components/molecules/Wallet/Feedback.tsx b/src/components/molecules/Wallet/Feedback.tsx index f139ccdf8..17402b682 100644 --- a/src/components/molecules/Wallet/Feedback.tsx +++ b/src/components/molecules/Wallet/Feedback.tsx @@ -21,7 +21,7 @@ export default function Web3Feedback({ const isOceanConnectionError = status === -1 const correctNetwork = isCorrectNetwork(chainId) const showFeedback = !account || isOceanConnectionError || !correctNetwork - const networkName = appConfig.network.replace(/^\w/, (c: string) => + const desiredNetworkName = appConfig.network.replace(/^\w/, (c: string) => c.toUpperCase() ) @@ -50,7 +50,7 @@ export default function Web3Feedback({ : isOceanConnectionError ? 'Please try again.' : !correctNetwork - ? `Please connect to ${networkName}.` + ? `Please connect to ${desiredNetworkName}.` : isBalanceInsufficient === true ? 'You do not have enough OCEAN in your wallet to purchase this asset.' : 'Something went wrong.' diff --git a/src/components/organisms/AssetActions/index.module.css b/src/components/organisms/AssetActions/index.module.css index 6acd2decb..343af92ec 100644 --- a/src/components/organisms/AssetActions/index.module.css +++ b/src/components/organisms/AssetActions/index.module.css @@ -4,29 +4,3 @@ margin: auto; padding: 0; } - -.tabList { - text-align: center; - border-bottom: 1px solid var(--brand-grey-lighter); - padding-top: calc(var(--spacer) / 2); - padding-bottom: calc(var(--spacer) / 2); -} - -.tab { - display: inline-block; - padding: calc(var(--spacer) / 12) var(--spacer); - border-radius: var(--border-radius); - font-weight: var(--font-weight-bold); - text-transform: uppercase; - cursor: pointer; - color: var(--brand-grey-light); -} - -.tab[aria-selected='true'] { - background: var(--brand-black); - color: var(--brand-white); -} - -.tabContent { - padding: var(--spacer); -} diff --git a/src/components/organisms/AssetActions/index.tsx b/src/components/organisms/AssetActions/index.tsx index e8716f496..e64213981 100644 --- a/src/components/organisms/AssetActions/index.tsx +++ b/src/components/organisms/AssetActions/index.tsx @@ -1,10 +1,10 @@ import React, { ReactElement } from 'react' -import { Tab, Tabs, TabList, TabPanel } from 'react-tabs' import styles from './index.module.css' import Compute from './Compute' import Consume from './Consume' import { MetadataMarket } from '../../../@types/Metadata' import { DDO } from '@oceanprotocol/lib' +import Tabs from '../../atoms/Tabs' export default function AssetActions({ metadata, @@ -15,23 +15,22 @@ export default function AssetActions({ }): ReactElement { const { access } = metadata.additionalInformation const isCompute = access && access === 'Compute' - - return ( - - - Use - Trade - -
- - {isCompute ? ( - - ) : ( - - )} - - Trade Me -
-
+ const UseContent = isCompute ? ( + + ) : ( + ) + + const tabs = [ + { + title: 'Use', + content: UseContent + }, + { + title: 'Trade', + content: 'Trade Me' + } + ] + + return } diff --git a/src/components/organisms/AssetContent/index.tsx b/src/components/organisms/AssetContent/index.tsx index c9a34b623..46c197a9a 100644 --- a/src/components/organisms/AssetContent/index.tsx +++ b/src/components/organisms/AssetContent/index.tsx @@ -51,6 +51,10 @@ export default function AssetContent({ /> */} {/* */} + +
+          {JSON.stringify(ddo, null, 2)}
+        
diff --git a/src/components/pages/Publish/Preview.tsx b/src/components/pages/Publish/Preview.tsx index 212f8370a..f89e9e80a 100644 --- a/src/components/pages/Publish/Preview.tsx +++ b/src/components/pages/Publish/Preview.tsx @@ -38,6 +38,7 @@ export default function Preview({ key.includes('tags') || key.includes('files') || key.includes('termsAndConditions') || + key.includes('price') || value === undefined || value === '' ) diff --git a/src/components/pages/Publish/PublishForm.tsx b/src/components/pages/Publish/PublishForm.tsx index 96a3180da..2c5d2c329 100644 --- a/src/components/pages/Publish/PublishForm.tsx +++ b/src/components/pages/Publish/PublishForm.tsx @@ -19,7 +19,6 @@ export default function PublishForm({ status, setStatus, isValid, - touched, setErrors, setTouched, resetForm, @@ -42,7 +41,6 @@ export default function PublishForm({ {content.data.map((field: FormFieldProps) => ( ))} - {isLoading ? ( ) : ( diff --git a/src/components/pages/Publish/index.tsx b/src/components/pages/Publish/index.tsx index 669e1a03c..eac998386 100644 --- a/src/components/pages/Publish/index.tsx +++ b/src/components/pages/Publish/index.tsx @@ -7,7 +7,7 @@ import styles from './index.module.css' import PublishForm from './PublishForm' import Web3Feedback from '../../molecules/Wallet/Feedback' import { FormContent } from '../../../@types/Form' -import { initialValues, validationSchema } from './validation' +import { initialValues, validationSchema } from '../../../models/FormPublish' import { MetadataPublishForm } from '../../../@types/Metadata' import { transformPublishFormToMetadata } from './utils' import Preview from './Preview' @@ -28,20 +28,20 @@ export default function PublishPage({ `) const metadata = transformPublishFormToMetadata(values) - const tokensToMint = '4' // how to know this? + const { cost, tokensToMint } = values.price const serviceType = values.access === 'Download' ? 'access' : 'compute' console.log(` Transformed metadata values: ---------------------- ${JSON.stringify(metadata, null, 2)} - Cost: 1 + Cost: ${cost} Tokens to mint: ${tokensToMint} `) try { - const ddo = await publish(metadata as any, tokensToMint, [ - { serviceType, cost: '1' } + const ddo = await publish(metadata as any, tokensToMint.toString(), [ + { serviceType, cost: cost.toString() } ]) if (publishError) { @@ -82,6 +82,26 @@ export default function PublishPage({
+ +
+
Collected Form Values
+
+                {JSON.stringify(values, null, 2)}
+              
+
+ +
+
Transformed Values
+
+                
+                  {JSON.stringify(
+                    transformPublishFormToMetadata(values),
+                    null,
+                    2
+                  )}
+                
+              
+
)} diff --git a/src/components/pages/Publish/utils.ts b/src/components/pages/Publish/utils.ts index 02649893a..5edad4ca4 100644 --- a/src/components/pages/Publish/utils.ts +++ b/src/components/pages/Publish/utils.ts @@ -16,8 +16,7 @@ export function transformPublishFormToMetadata( tags, links, termsAndConditions, - files, - access + files } = data const metadata: MetadataMarket = { @@ -38,8 +37,7 @@ export function transformPublishFormToMetadata( // links: { // url: links // }, - termsAndConditions, - access: access || 'Download' + termsAndConditions }, curation: AssetModel.curation } diff --git a/src/global/_code.css b/src/global/_code.css index af5a0467c..bfe882ed9 100644 --- a/src/global/_code.css +++ b/src/global/_code.css @@ -1,7 +1,7 @@ code { font-family: var(--font-family-monospace); font-size: var(--font-size-small); - color: var(--brand-grey-light); + color: var(--brand-grey); text-shadow: none; } @@ -14,13 +14,22 @@ code { pre { display: block; margin: calc(var(--spacer) / 2) 0; - padding: 0; - border: 1px solid var(--brand-grey-dark); + padding: calc(var(--spacer) / 2); + background-color: var(--brand-grey-dimmed) !important; border-radius: var(--border-radius); + overflow: auto; + -webkit-overflow-scrolling: touch; + max-height: 800px; + width: 100%; + position: relative; } pre code { - padding: calc(var(--spacer) / 2); + padding: 0; + white-space: pre; display: block; - white-space: pre-wrap; + overflow-wrap: normal; + word-wrap: normal; + word-break: normal; + width: 100%; } diff --git a/src/global/styles.css b/src/global/styles.css index a63445413..b372381f2 100644 --- a/src/global/styles.css +++ b/src/global/styles.css @@ -132,6 +132,28 @@ fieldset { margin: 0; } +table { + width: 100%; + border-collapse: collapse; + display: block; + overflow: auto; + -webkit-overflow-scrolling: touch; +} + +table th, +table td { + border: 0; + margin: 0; + padding: calc(var(--spacer) / 2); + border-bottom: 1px solid var(--brand-grey-lighter); + text-align: left; + font-size: 90%; +} + +table th { + font-weight: var(--font-weight-bold); +} + @import '_code.css'; @import '_toast.css'; @import '_web3modal.css'; diff --git a/src/images/logo.svg b/src/images/logo.svg new file mode 100644 index 000000000..c5099c095 --- /dev/null +++ b/src/images/logo.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/models/Asset.ts b/src/models/Asset.ts index 998c65f36..ce1478ee5 100644 --- a/src/models/Asset.ts +++ b/src/models/Asset.ts @@ -5,21 +5,20 @@ const AssetModel: MetadataMarket = { // https://github.com/oceanprotocol/OEPs/tree/master/8 main: { type: 'dataset', - name: '', - dateCreated: '', - author: '', - license: '', + name: undefined, + dateCreated: undefined, + author: undefined, + license: undefined, files: [] }, additionalInformation: { - description: '', - copyrightHolder: '', - tags: [], - links: [], + description: undefined, + copyrightHolder: undefined, + tags: undefined, + links: undefined, // custom items - termsAndConditions: false, - access: 'Download' + termsAndConditions: false }, curation: { rating: 0, diff --git a/src/components/pages/Publish/validation.ts b/src/models/FormPublish.ts similarity index 64% rename from src/components/pages/Publish/validation.ts rename to src/models/FormPublish.ts index 6e629adec..d4cfc3a9f 100644 --- a/src/components/pages/Publish/validation.ts +++ b/src/models/FormPublish.ts @@ -1,4 +1,4 @@ -import { MetadataPublishForm } from '../../../@types/Metadata' +import { MetadataPublishForm } from '../@types/Metadata' import { File as FileMetadata } from '@oceanprotocol/lib' import * as Yup from 'yup' @@ -6,7 +6,10 @@ export const validationSchema = Yup.object().shape({ // ---- required fields ---- name: Yup.string().required('Required'), author: Yup.string().required('Required'), - cost: Yup.string().required('Required'), + price: Yup.object().shape({ + cost: Yup.number().required('Required'), + tokensToMint: Yup.number().required('Required') + }), files: Yup.array().required('Required').nullable(), description: Yup.string().required('Required'), license: Yup.string().required('Required'), @@ -22,15 +25,18 @@ export const validationSchema = Yup.object().shape({ }) export const initialValues: MetadataPublishForm = { - name: '', - author: '', - cost: '', - files: '', - description: '', - license: '', - access: '', + name: undefined, + author: undefined, + price: { + cost: 1, + tokensToMint: 1 + }, + files: undefined, + description: undefined, + license: undefined, + access: undefined, termsAndConditions: false, - copyrightHolder: '', - tags: '', - links: '' + copyrightHolder: undefined, + tags: undefined, + links: undefined } diff --git a/src/pages/publish.tsx b/src/pages/publish.tsx index 0ed58d5af..b8ffd4736 100644 --- a/src/pages/publish.tsx +++ b/src/pages/publish.tsx @@ -32,7 +32,6 @@ export const contentQuery = graphql` type required options - min } success }