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

prototype feedback data structure & flow

This commit is contained in:
Matthias Kretschmann 2022-01-11 23:11:15 +00:00
parent 453458814e
commit 245a604a99
Signed by: m
GPG Key ID: 606EEEF3C479A91F
5 changed files with 189 additions and 75 deletions

View File

@ -2,12 +2,17 @@ import { ReactElement, useEffect } from 'react'
import { useFormikContext } from 'formik'
import { wizardSteps } from './_constants'
import { useWeb3 } from '@context/Web3'
import { FormPublishData } from './_types'
import { FormPublishData, PublishFeedback } from './_types'
export function Steps(): ReactElement {
export function Steps({
feedback
}: {
feedback: PublishFeedback
}): ReactElement {
const { chainId, accountId } = useWeb3()
const { values, setFieldValue } = useFormikContext<FormPublishData>()
// auto-sync user chainId & account into form data values
useEffect(() => {
if (!chainId || !accountId) return
@ -15,6 +20,11 @@ export function Steps(): ReactElement {
setFieldValue('user.accountId', accountId)
}, [chainId, accountId, setFieldValue])
// auto-sync publish feedback into form data values
useEffect(() => {
setFieldValue('feedback', feedback)
}, [feedback, setFieldValue])
const { component } = wizardSteps.filter(
(stepContent) => stepContent.step === values.user.stepCurrent
)[0]

View File

@ -0,0 +1,18 @@
import { ListItem } from '@shared/atoms/Lists'
import { useFormikContext } from 'formik'
import React, { ReactElement } from 'react'
import { FormPublishData } from '../_types'
export function Feedback(): ReactElement {
const { values } = useFormikContext<FormPublishData>()
const items = Object.entries(values.feedback).map(([key, value], index) => {
return (
<ListItem ol key={index}>
{value.name}
</ListItem>
)
})
return <ol>{items}</ol>
}

View File

@ -2,6 +2,7 @@ import React, { ReactElement } from 'react'
import styles from './index.module.css'
import { FormPublishData } from '../_types'
import { useFormikContext } from 'formik'
import { Feedback } from './Feedback'
export default function Submission(): ReactElement {
const { values, handleSubmit } = useFormikContext<FormPublishData>()
@ -12,6 +13,7 @@ export default function Submission(): ReactElement {
Place to teach about what happens next, output all the steps in background
in some list, after submission continously update this list with the
status of the submission.
<Feedback />
</div>
)
}

View File

@ -43,6 +43,7 @@ export interface FormPublishData {
}
services: FormPublishService[]
pricing: PriceOptions
feedback?: PublishFeedback
}
export interface StepContent {
@ -50,3 +51,11 @@ export interface StepContent {
title: string
component: ReactElement
}
export interface PublishFeedback {
[key: number]: {
name: string
status: 'success' | 'error' | 'pending'
message?: string
}
}

View File

@ -11,7 +11,7 @@ import Actions from './Actions'
import Debug from './Debug'
import Navigation from './Navigation'
import { Steps } from './Steps'
import { FormPublishData } from './_types'
import { FormPublishData, PublishFeedback } from './_types'
import { useUserPreferences } from '@context/UserPreferences'
import useNftFactory from '@hooks/contracts/useNftFactory'
import { Nft, getHash, ProviderInstance } from '@oceanprotocol/lib'
@ -32,22 +32,33 @@ export default function PublishPage({
const { debug } = useUserPreferences()
const { accountId, web3, chainId } = useWeb3()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
// TODO: success & error states need to be handled for each step we want to display
// most likely with a nested data structure.
const [success, setSuccess] = useState<string>()
const [error, setError] = useState<string>()
const scrollToRef = useRef()
const { appConfig } = useSiteMetadata()
const nftFactory = useNftFactory()
const newCancelToken = useCancelToken()
async function handleSubmit(values: FormPublishData) {
try {
// --------------------------------------------------
// 1. Create NFT & datatokens & create pricing schema
// --------------------------------------------------
const [feedback, setFeedback] = useState<PublishFeedback>({
1: {
name: 'Create Tokens & Pricing',
status: 'pending'
},
2: {
name: 'Encrypt DDO',
status: 'pending'
},
3: {
name: 'Publish DDO',
status: 'pending'
}
})
async function handleSubmit(values: FormPublishData) {
let _erc721Address, _datatokenAddress, _ddo, _encryptedDdo
// --------------------------------------------------
// 1. Create NFT & datatokens & create pricing schema
// --------------------------------------------------
try {
const config = getOceanConfig(chainId)
console.log('config', config)
@ -60,16 +71,41 @@ export default function PublishPage({
web3
)
// --------------------------------------------------
// 2. Construct and publish DDO
// --------------------------------------------------
const isSuccess = erc721Address && datatokenAddress
_erc721Address = erc721Address
_datatokenAddress = datatokenAddress
setFeedback({
...feedback,
1: {
...feedback[1],
status: isSuccess ? 'success' : 'error'
}
})
} catch (error) {
console.error('error', error.message)
setFeedback({
...feedback,
1: {
...feedback[1],
status: 'error',
message: error.message
}
})
}
// --------------------------------------------------
// 2. Construct and encypt DDO
// --------------------------------------------------
try {
const ddo = await transformPublishFormToDdo(
values,
datatokenAddress,
erc721Address
_datatokenAddress,
_erc721Address
)
_ddo = ddo
const encryptedResponse = await ProviderInstance.encrypt(
ddo,
values.services[0].providerUrl.url,
@ -82,84 +118,123 @@ export default function PublishPage({
})
}
)
const encryptedDddo = encryptedResponse.data
const encryptedDdo = encryptedResponse.data
_encryptedDdo = encryptedDdo
console.log('ddo', JSON.stringify(ddo))
setFeedback({
...feedback,
2: {
...feedback[2],
status: encryptedDdo ? 'success' : 'error'
}
})
} catch (error) {
console.error('error', error.message)
setFeedback({
...feedback,
2: {
...feedback[2],
status: 'error',
message: error.message
}
})
}
// --------------------------------------------------
// 3. Publish DDO
// --------------------------------------------------
try {
// TODO: this whole setMetadata needs to go in a function ,too many hardcoded/calculated params
// TODO: hash generation : this needs to be moved in a function (probably on ocean.js) after we figure out what is going on in provider, leave it here for now
const metadataHash = getHash(JSON.stringify(ddo))
const metadataHash = getHash(JSON.stringify(_ddo))
const nft = new Nft(web3)
// theoretically used by aquarius or provider, not implemented yet, will remain hardcoded
const flags = '0x2'
const res = await nft.setMetadata(
erc721Address,
_erc721Address,
accountId,
0,
config.providerUri,
values.services[0].providerUrl.url,
'',
flags,
encryptedDddo,
_encryptedDdo,
'0x' + metadataHash
)
console.log('result', res)
// --------------------------------------------------
// 3. Integrity check of DDO before & after publishing
// --------------------------------------------------
// TODO: not sure we want to do this at this step, seems overkill
// if we want to do this we just need to fetch it from aquarius. If we want to fetch from chain and decrypt, we would have more metamask pop-ups (not UX friendly)
// decrypt also validates the checksum
// TODO: remove the commented lines of code until `setSuccess`, didn't remove them yet because maybe i missed something
// --------------------------------------------------
// 1. Mint NFT & datatokens & put in pool
// --------------------------------------------------
// const nftOptions = values.metadata.nft
// const nftCreateData = generateNftCreateData(nftOptions)
// figure out syntax of ercParams we most likely need to pass
// to createNftWithErc() as we need to pass options for the datatoken.
// const ercParams = {}
// const priceOptions = {
// // swapFee is tricky: to get 0.1% you need to send 0.001 as value
// swapFee: `${values.pricing.swapFee / 100}`
// }
// const txMint = await createNftWithErc(accountId, nftCreateData)
// figure out how to get nftAddress & datatokenAddress from tx log.
// const { nftAddress, datatokenAddress } = txMint.logs[0].args
// if (!nftAddress || !datatokenAddress) { throw new Error() }
//
// --------------------------------------------------
// 2. Construct and publish DDO
// --------------------------------------------------
// const did = sha256(`${nftAddress}${chainId}`)
// const ddo = transformPublishFormToDdo(values, datatokenAddress, nftAddress)
// const txPublish = await publish(ddo)
//
// --------------------------------------------------
// 3. Integrity check of DDO before & after publishing
// --------------------------------------------------
// const checksumBefore = sha256(ddo)
// const ddoFromChain = await getDdoFromChain(ddo.id)
// const ddoFromChainDecrypted = await decryptDdo(ddoFromChain)
// const checksumAfter = sha256(ddoFromChainDecrypted)
// if (checksumBefore !== checksumAfter) {
// throw new Error('DDO integrity check failed!')
// }
setSuccess('Your DDO was published successfully!')
setFeedback({
...feedback,
3: {
...feedback[3],
status: res ? 'success' : 'error'
}
})
} catch (error) {
setError(error.message)
console.log('err', error)
console.error('error', error.message)
setFeedback({
...feedback,
3: {
...feedback[3],
status: 'error',
message: error.message
}
})
}
// --------------------------------------------------
// 3. Integrity check of DDO before & after publishing
// --------------------------------------------------
// TODO: not sure we want to do this at this step, seems overkill
// if we want to do this we just need to fetch it from aquarius. If we want to fetch from chain and decrypt, we would have more metamask pop-ups (not UX friendly)
// decrypt also validates the checksum
// TODO: remove the commented lines of code until `setSuccess`, didn't remove them yet because maybe i missed something
// --------------------------------------------------
// 1. Mint NFT & datatokens & put in pool
// --------------------------------------------------
// const nftOptions = values.metadata.nft
// const nftCreateData = generateNftCreateData(nftOptions)
// figure out syntax of ercParams we most likely need to pass
// to createNftWithErc() as we need to pass options for the datatoken.
// const ercParams = {}
// const priceOptions = {
// // swapFee is tricky: to get 0.1% you need to send 0.001 as value
// swapFee: `${values.pricing.swapFee / 100}`
// }
// const txMint = await createNftWithErc(accountId, nftCreateData)
// figure out how to get nftAddress & datatokenAddress from tx log.
// const { nftAddress, datatokenAddress } = txMint.logs[0].args
// if (!nftAddress || !datatokenAddress) { throw new Error() }
//
// --------------------------------------------------
// 2. Construct and publish DDO
// --------------------------------------------------
// const did = sha256(`${nftAddress}${chainId}`)
// const ddo = transformPublishFormToDdo(values, datatokenAddress, nftAddress)
// const txPublish = await publish(ddo)
//
// --------------------------------------------------
// 3. Integrity check of DDO before & after publishing
// --------------------------------------------------
// const checksumBefore = sha256(ddo)
// const ddoFromChain = await getDdoFromChain(ddo.id)
// const ddoFromChainDecrypted = await decryptDdo(ddoFromChain)
// const checksumAfter = sha256(ddoFromChainDecrypted)
// if (checksumBefore !== checksumAfter) {
// throw new Error('DDO integrity check failed!')
// }
}
return isInPurgatory && purgatoryData ? null : (
@ -179,7 +254,7 @@ export default function PublishPage({
/>
<Form className={styles.form} ref={scrollToRef}>
<Navigation />
<Steps />
<Steps feedback={feedback} />
<Actions scrollToRef={scrollToRef} />
</Form>
{debug && <Debug />}