From a2fe2fdee026d8bfe8a5decc665e49c766993f9e Mon Sep 17 00:00:00 2001 From: Norby <37236152+KatunaNorbert@users.noreply.github.com> Date: Fri, 22 Jan 2021 18:12:48 +0200 Subject: [PATCH] Set, edit, and display timeout (#324) * added timeout to publish asset * add timeout to edit asses(wip) * added timout to edit metadata form * fixed wrong constant name * fix options autosorting Signed-off-by: mihaisc * Fixed autosorting in edit form * Added "1 day" to timeout options * Changed ternary operators to switch * Feature/asset timeout (#325) * Compute asset timeout * Code styled * Deleted unused import * Display timeout for buy/download * Switch case for timeout values * Moved mapping function to /utils/metadata * display timeout option not matching defined ones, map seconds to string * handle update with no predefined timeout value, add weeks to map method * Display timeout on button * consume button text logic change * whoops, revert wrong change * small millisecondsToStr refactor * copy tweaks * template literal logic restore * keep tweaking help text logic * abstract into method * change whole condition logic * tweak hasDatatoken/hasPreviousOrder combination condition * Unified seconds to string conversion methods * getHelpText tweaks, small refactor * copy editing, limit hardcoded timeout list * fix mixup of map & filter * use Timeout as label and be done with it Co-authored-by: mihaisc Co-authored-by: claudiaHash <49017601+claudiaHash@users.noreply.github.com> Co-authored-by: Matthias Kretschmann Co-authored-by: Claudia Holhos --- content/pages/edit.json | 9 +++ content/pages/publish.json | 9 +++ src/@types/Form.d.ts | 1 + src/@types/MetaData.d.ts | 1 + .../organisms/AssetActions/Consume.module.css | 4 ++ .../organisms/AssetActions/Consume.tsx | 54 +++++++++++++----- .../AssetActions/Edit/FormEditMetadata.tsx | 52 ++++++++++++++++- .../organisms/AssetActions/Edit/index.tsx | 50 +++++++++++++---- src/components/pages/Publish/index.tsx | 10 +++- src/global/_variables.css | 1 + src/models/FormEditMetadata.ts | 10 +++- src/models/FormPublish.ts | 5 +- src/pages/publish.tsx | 1 + src/utils/checkPreviousOrder.ts | 2 +- src/utils/metadata.ts | 56 +++++++++++++++++++ tests/unit/__fixtures__/testFormData.ts | 1 + 16 files changed, 234 insertions(+), 32 deletions(-) diff --git a/content/pages/edit.json b/content/pages/edit.json index 989be0e34..0928a3721 100644 --- a/content/pages/edit.json +++ b/content/pages/edit.json @@ -19,6 +19,15 @@ "type": "textarea", "rows": 10, "required": true + }, + { + "name": "timeout", + "label": "Timeout", + "help": "Define how long buyers should be able to download the data set again after the initial purchase.", + "type": "select", + "options": ["Forever", "1 day", "1 week", "1 month", "1 year"], + "sortOptions": false, + "required": true } ] } diff --git a/content/pages/publish.json b/content/pages/publish.json index 27ef135eb..8da56c3a0 100644 --- a/content/pages/publish.json +++ b/content/pages/publish.json @@ -42,6 +42,15 @@ "options": ["Download"], "required": true }, + { + "name": "timeout", + "label": "Timeout", + "help": "Define how long buyers should be able to download the data set again after the initial purchase.", + "type": "select", + "options": ["Forever", "1 day", "1 week", "1 month", "1 year"], + "sortOptions": false, + "required": true + }, { "name": "dataTokenOptions", "label": "Datatoken Name & Symbol", diff --git a/src/@types/Form.d.ts b/src/@types/Form.d.ts index 4a88b4128..107289ca0 100644 --- a/src/@types/Form.d.ts +++ b/src/@types/Form.d.ts @@ -3,6 +3,7 @@ export interface FormFieldProps { name: string type?: string options?: string[] + sortOptions?: boolean required?: boolean help?: string placeholder?: string diff --git a/src/@types/MetaData.d.ts b/src/@types/MetaData.d.ts index 1b4718bfd..6e3a48dea 100644 --- a/src/@types/MetaData.d.ts +++ b/src/@types/MetaData.d.ts @@ -30,6 +30,7 @@ export interface MetadataPublishForm { description: string files: string | File[] author: string + timeout: string dataTokenOptions: DataTokenOptions access: 'Download' | 'Compute' | string termsAndConditions: boolean diff --git a/src/components/organisms/AssetActions/Consume.module.css b/src/components/organisms/AssetActions/Consume.module.css index 56f289c9a..01979ae81 100644 --- a/src/components/organisms/AssetActions/Consume.module.css +++ b/src/components/organisms/AssetActions/Consume.module.css @@ -21,6 +21,10 @@ composes: help from './index.module.css'; } +.help:not(:empty) { + margin-top: calc(var(--spacer) / 2); +} + .feedback { width: 100%; } diff --git a/src/components/organisms/AssetActions/Consume.tsx b/src/components/organisms/AssetActions/Consume.tsx index 3bf67dc6d..42b4b4bdb 100644 --- a/src/components/organisms/AssetActions/Consume.tsx +++ b/src/components/organisms/AssetActions/Consume.tsx @@ -11,6 +11,27 @@ import { useOcean, useConsume, usePricing } from '@oceanprotocol/react' import { useSiteMetadata } from '../../../hooks/useSiteMetadata' import checkPreviousOrder from '../../../utils/checkPreviousOrder' import { useAsset } from '../../../providers/Asset' +import { secondsToString } from '../../../utils/metadata' + +function getHelpText( + token: { + dtBalance: string + dtSymbol: string + }, + hasDatatoken: boolean, + hasPreviousOrder: boolean, + timeout: string +) { + const { dtBalance, dtSymbol } = token + const assetTimeout = timeout === 'Forever' ? '' : ` for ${timeout}` + const text = hasPreviousOrder + ? `You bought this data set already allowing you to download it without paying again${assetTimeout}.` + : hasDatatoken + ? `You own ${dtBalance} ${dtSymbol} allowing you to use this data set by spending 1 ${dtSymbol}, but without paying OCEAN again.` + : `For using this data set, you will buy 1 ${dtSymbol} and immediately spend it back to the publisher and pool.` + + return text +} export default function Consume({ ddo, @@ -35,6 +56,12 @@ export default function Consume({ const [isDisabled, setIsDisabled] = useState(true) const [hasDatatoken, setHasDatatoken] = useState(false) const [isConsumable, setIsConsumable] = useState(true) + const [assetTimeout, setAssetTimeout] = useState('') + + useEffect(() => { + const { timeout } = ddo.findServiceByType('access').attributes.main + setAssetTimeout(secondsToString(timeout)) + }, [ddo]) useEffect(() => { if (!price) return @@ -72,6 +99,7 @@ export default function Consume({ if (!ocean || !accountId) return async function checkOrders() { + // HEADS UP! checkPreviousOrder() also checks for expiration of possible set timeout. const orderId = await checkPreviousOrder(ocean, accountId, ddo, 'access') setPreviousOrderId(orderId) setHasPreviousOrder(!!orderId) @@ -104,20 +132,20 @@ export default function Consume({ ) : ( <> - {hasDatatoken && ( -
- You own {dtBalance} {ddo.dataTokenInfo.symbol} allowing you to use - this data set without paying again. -
- )} - {(!hasDatatoken || !hasPreviousOrder) && ( -
- For using this data set, you will buy 1 {ddo.dataTokenInfo.symbol}{' '} - and immediately spend it back to the publisher and pool. -
- )} +
+ {getHelpText( + { dtBalance, dtSymbol: ddo.dataTokenInfo.symbol }, + hasDatatoken, + hasPreviousOrder, + assetTimeout + )} +
)} diff --git a/src/components/organisms/AssetActions/Edit/FormEditMetadata.tsx b/src/components/organisms/AssetActions/Edit/FormEditMetadata.tsx index 342c5276e..238b4cd24 100644 --- a/src/components/organisms/AssetActions/Edit/FormEditMetadata.tsx +++ b/src/components/organisms/AssetActions/Edit/FormEditMetadata.tsx @@ -6,13 +6,52 @@ import Input from '../../../atoms/Input' import { useOcean } from '@oceanprotocol/react' import { FormFieldProps } from '../../../../@types/Form' import { MetadataPublishForm } from '../../../../@types/MetaData' +import { checkIfTimeoutInPredefinedValues } from '../../../../utils/metadata' + +function handleTimeoutCustomOption( + data: FormFieldProps[], + values: Partial +) { + const timeoutFieldContent = data.filter( + (field) => field.name === 'timeout' + )[0] + const timeoutInputIndex = data.findIndex( + (element) => element.name === 'timeout' + ) + if ( + data[timeoutInputIndex].options.length < 6 && + !checkIfTimeoutInPredefinedValues( + values.timeout, + timeoutFieldContent.options + ) + ) { + data[timeoutInputIndex].options.push(values.timeout) + } else if ( + data[timeoutInputIndex].options.length === 6 && + checkIfTimeoutInPredefinedValues( + values.timeout, + timeoutFieldContent.options + ) + ) { + data[timeoutInputIndex].options.pop() + } else if ( + data[timeoutInputIndex].options.length === 6 && + data[timeoutInputIndex].options[5] !== values.timeout + ) { + data[timeoutInputIndex].options[5] = values.timeout + } +} export default function FormEditMetadata({ data, - setShowEdit + setShowEdit, + setTimeoutStringValue, + values }: { data: FormFieldProps[] setShowEdit: (show: boolean) => void + setTimeoutStringValue: (value: string) => void + values: Partial }): ReactElement { const { ocean, accountId } = useOcean() const { @@ -31,6 +70,11 @@ export default function FormEditMetadata({ setFieldValue(field.name, e.target.value) } + // This component is handled by Formik so it's not rendered like a "normal" react component, + // so handleTimeoutCustomOption is called only once. + // https://github.com/oceanprotocol/market/pull/324#discussion_r561132310 + if (data && values) handleTimeoutCustomOption(data, values) + return (
{data.map((field: FormFieldProps) => ( @@ -45,7 +89,11 @@ export default function FormEditMetadata({ ))}