more wizard refactors, functional navigation steps
This commit is contained in:
parent
9b5cd8b8ed
commit
f4eab6e09a
|
@ -15,7 +15,7 @@ import classNames from 'classnames/bind'
|
|||
import Disclaimer from './Disclaimer'
|
||||
import Tooltip from '@shared/atoms/Tooltip'
|
||||
import Markdown from '@shared/Markdown'
|
||||
import MetadataFields from 'src/components/Publish/FormPublish/Metadata'
|
||||
import MetadataFields from 'src/components/Publish/Metadata'
|
||||
import toPath from 'lodash/toPath'
|
||||
|
||||
const cx = classNames.bind(styles)
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import React, { FormEvent, ReactElement } from 'react'
|
||||
import { useOcean } from '@context/Ocean'
|
||||
import Button from '@shared/atoms/Button'
|
||||
import styles from './index.module.css'
|
||||
import { FormikContextType, useFormikContext } from 'formik'
|
||||
import { FormPublishData } from '../_types'
|
||||
import { wizardSteps } from '../_constants'
|
||||
|
||||
export default function Actions(): ReactElement {
|
||||
const { ocean, account } = useOcean()
|
||||
const {
|
||||
status,
|
||||
values,
|
||||
isValid,
|
||||
setFieldValue
|
||||
}: FormikContextType<FormPublishData> = useFormikContext()
|
||||
|
||||
function handleNext(e: FormEvent) {
|
||||
e.preventDefault()
|
||||
setFieldValue('step', values.step + 1)
|
||||
}
|
||||
|
||||
function handlePrevious(e: FormEvent) {
|
||||
e.preventDefault()
|
||||
setFieldValue('step', values.step - 1)
|
||||
}
|
||||
|
||||
return (
|
||||
<footer className={styles.actions}>
|
||||
<Button onClick={handlePrevious}>Back</Button>
|
||||
|
||||
{values.step < wizardSteps.length ? (
|
||||
<Button style="primary" onClick={handleNext}>
|
||||
Continue
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
type="submit"
|
||||
style="primary"
|
||||
disabled={!ocean || !account || !isValid}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
)}
|
||||
</footer>
|
||||
)
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
import React, { ReactElement } from 'react'
|
||||
import { useOcean } from '@context/Ocean'
|
||||
import Button from '@shared/atoms/Button'
|
||||
import styles from './FormActions.module.css'
|
||||
import { FormikContextType, useFormikContext } from 'formik'
|
||||
import { FormPublishData } from '../_types'
|
||||
|
||||
export default function FormActions({ step }: { step: number }): ReactElement {
|
||||
const { ocean, account } = useOcean()
|
||||
const { status, isValid, setFieldValue }: FormikContextType<FormPublishData> =
|
||||
useFormikContext()
|
||||
|
||||
function handleNext() {
|
||||
setFieldValue('step', step + 1)
|
||||
}
|
||||
|
||||
function handlePrevious() {
|
||||
setFieldValue('step', step - 1)
|
||||
}
|
||||
|
||||
return (
|
||||
<footer className={styles.actions}>
|
||||
<Button onClick={handlePrevious}>Back</Button>
|
||||
|
||||
<Button style="primary" onClick={() => handleNext()}>
|
||||
Continue
|
||||
</Button>
|
||||
|
||||
{/* <Button
|
||||
type="submit"
|
||||
style="primary"
|
||||
disabled={!ocean || !account || !isValid}
|
||||
>
|
||||
Submit
|
||||
</Button> */}
|
||||
</footer>
|
||||
)
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
.form {
|
||||
composes: box from '@shared/atoms/Box.module.css';
|
||||
margin-bottom: var(--spacer);
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
import React, { ReactElement } from 'react'
|
||||
import { useFormikContext, Form, FormikContextType } from 'formik'
|
||||
import FormActions from './FormActions'
|
||||
import { FormPublishData } from '../_types'
|
||||
import styles from './index.module.css'
|
||||
import PricingFields from './Pricing'
|
||||
import Debug from '../Debug'
|
||||
import MetadataFields from './Metadata'
|
||||
import ServicesFields from './Services'
|
||||
import content from '../../../../content/publish/form.json'
|
||||
import Preview from './Preview'
|
||||
|
||||
function Steps({ step }: { step: number }) {
|
||||
switch (step) {
|
||||
case 1:
|
||||
return <MetadataFields />
|
||||
case 2:
|
||||
return <ServicesFields />
|
||||
case 3:
|
||||
return <PricingFields />
|
||||
case 4:
|
||||
return <Preview />
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
export default function FormPublish(): ReactElement {
|
||||
const { isValid, values, resetForm }: FormikContextType<FormPublishData> =
|
||||
useFormikContext()
|
||||
|
||||
// reset form validation on every mount
|
||||
// useEffect(() => {
|
||||
// setErrors({})
|
||||
// setTouched({})
|
||||
|
||||
// // setSubmitting(false)
|
||||
// }, [setErrors, setTouched])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form className={styles.form}>
|
||||
<Steps step={values.step} />
|
||||
<FormActions step={values.step} />
|
||||
</Form>
|
||||
<Debug values={values} />
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -1,9 +1,25 @@
|
|||
import Input from '@shared/Form/Input'
|
||||
import { Field, useFormikContext } from 'formik'
|
||||
import React, { ReactElement } from 'react'
|
||||
import content from '../../../../../content/publish/form.json'
|
||||
import { FormPublishData } from '../../_types'
|
||||
import { getFieldContent } from '../../_utils'
|
||||
import content from '../../../../content/publish/form.json'
|
||||
import { FormPublishData } from '../_types'
|
||||
import { getFieldContent } from '../_utils'
|
||||
|
||||
const assetTypeOptionsTitles = getFieldContent(
|
||||
'type',
|
||||
content.services.fields
|
||||
).options
|
||||
|
||||
const assetTypeOptions = [
|
||||
{
|
||||
name: assetTypeOptionsTitles[0].toLowerCase(),
|
||||
title: assetTypeOptionsTitles[0]
|
||||
},
|
||||
{
|
||||
name: assetTypeOptionsTitles[1].toLowerCase(),
|
||||
title: assetTypeOptionsTitles[1]
|
||||
}
|
||||
]
|
||||
|
||||
export default function MetadataFields(): ReactElement {
|
||||
// connect with Form state, use for conditional field rendering
|
||||
|
@ -11,6 +27,12 @@ export default function MetadataFields(): ReactElement {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Field
|
||||
{...getFieldContent('type', content.services.fields)}
|
||||
component={Input}
|
||||
name="type"
|
||||
options={assetTypeOptions}
|
||||
/>
|
||||
<Field
|
||||
{...getFieldContent('name', content.metadata.fields)}
|
||||
component={Input}
|
|
@ -0,0 +1,11 @@
|
|||
.navigation {
|
||||
background: red;
|
||||
}
|
||||
|
||||
.navigation li {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.current {
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import { FormikContextType, useFormikContext } from 'formik'
|
||||
import React, { FormEvent, ReactElement } from 'react'
|
||||
import { FormPublishData } from '../_types'
|
||||
import { wizardSteps } from '../_constants'
|
||||
import styles from './index.module.css'
|
||||
|
||||
export default function Navigation(): ReactElement {
|
||||
const {
|
||||
isValid,
|
||||
values,
|
||||
resetForm,
|
||||
setFieldValue
|
||||
}: FormikContextType<FormPublishData> = useFormikContext()
|
||||
|
||||
function handleStepClick(step: number) {
|
||||
setFieldValue('step', step)
|
||||
}
|
||||
|
||||
return (
|
||||
<nav className={styles.navigation}>
|
||||
<ol>
|
||||
{wizardSteps.map((step) => (
|
||||
<li
|
||||
key={step.title}
|
||||
onClick={() => handleStepClick(step.step)}
|
||||
className={values.step === step.step ? styles.current : null}
|
||||
>
|
||||
{step.title}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</nav>
|
||||
)
|
||||
}
|
|
@ -2,7 +2,7 @@ import React, { FormEvent, ReactElement, useState } from 'react'
|
|||
import { File as FileMetadata } from '@oceanprotocol/lib/dist/node/ddo/interfaces/File'
|
||||
import Markdown from '@shared/Markdown'
|
||||
import Tags from '@shared/atoms/Tags'
|
||||
import MetaItem from '../../../Asset/AssetContent/MetaItem'
|
||||
import MetaItem from '../../Asset/AssetContent/MetaItem'
|
||||
import FileIcon from '@shared/FileIcon'
|
||||
import Button from '@shared/atoms/Button'
|
||||
import { transformTags } from '@utils/ddo'
|
||||
|
@ -11,7 +11,7 @@ import { useWeb3 } from '@context/Web3'
|
|||
import styles from './index.module.css'
|
||||
import Web3Feedback from '@shared/Web3Feedback'
|
||||
import { useAsset } from '@context/Asset'
|
||||
import { FormPublishData } from '../../_types'
|
||||
import { FormPublishData } from '../_types'
|
||||
import { useFormikContext } from 'formik'
|
||||
|
||||
function Description({ description }: { description: string }) {
|
|
@ -3,7 +3,7 @@ import React, { ReactElement, useEffect, useState } from 'react'
|
|||
import Alert from '@shared/atoms/Alert'
|
||||
import FormHelp from '@shared/Form/Input/Help'
|
||||
import Tooltip from '@shared/atoms/Tooltip'
|
||||
import Wallet from '../../../Header/Wallet'
|
||||
import Wallet from '../../Header/Wallet'
|
||||
import Coin from './Coin'
|
||||
import styles from './Dynamic.module.css'
|
||||
import Fees from './Fees'
|
||||
|
@ -12,7 +12,7 @@ import Price from './Price'
|
|||
import Decimal from 'decimal.js'
|
||||
import { useOcean } from '@context/Ocean'
|
||||
import { useWeb3 } from '@context/Web3'
|
||||
import { FormPublishData } from '../../_types'
|
||||
import { FormPublishData } from '../_types'
|
||||
|
||||
export default function Dynamic({ content }: { content: any }): ReactElement {
|
||||
const { networkId, balance } = useWeb3()
|
|
@ -5,7 +5,7 @@ import Input from '@shared/Form/Input'
|
|||
import Error from './Error'
|
||||
import PriceUnit from '@shared/Price/PriceUnit'
|
||||
import styles from './Price.module.css'
|
||||
import { FormPublishData } from '../../_types'
|
||||
import { FormPublishData } from '../_types'
|
||||
|
||||
export default function Price({
|
||||
firstPrice,
|
|
@ -5,11 +5,11 @@ import { useSiteMetadata } from '@hooks/useSiteMetadata'
|
|||
import Tabs from '@shared/atoms/Tabs'
|
||||
import { isValidNumber } from '@utils/numbers'
|
||||
import Decimal from 'decimal.js'
|
||||
import { FormPublishData } from '../../_types'
|
||||
import { FormPublishData } from '../_types'
|
||||
import Dynamic from './Dynamic'
|
||||
import Fixed from './Fixed'
|
||||
import Free from './Free'
|
||||
import content from '../../../../../content/price.json'
|
||||
import content from '../../../../content/price.json'
|
||||
import styles from './index.module.css'
|
||||
|
||||
export default function PricingFields(): ReactElement {
|
|
@ -3,9 +3,9 @@ import { Field, useFormikContext } from 'formik'
|
|||
import React, { ReactElement } from 'react'
|
||||
import IconDownload from '@images/download.svg'
|
||||
import IconCompute from '@images/compute.svg'
|
||||
import content from '../../../../../content/publish/form.json'
|
||||
import { getFieldContent } from '../../_utils'
|
||||
import { FormPublishData } from '../../_types'
|
||||
import content from '../../../../content/publish/form.json'
|
||||
import { getFieldContent } from '../_utils'
|
||||
import { FormPublishData } from '../_types'
|
||||
|
||||
const accessTypeOptionsTitles = getFieldContent(
|
||||
'access',
|
||||
|
@ -25,34 +25,12 @@ const accessTypeOptions = [
|
|||
}
|
||||
]
|
||||
|
||||
const assetTypeOptionsTitles = getFieldContent(
|
||||
'type',
|
||||
content.services.fields
|
||||
).options
|
||||
|
||||
const assetTypeOptions = [
|
||||
{
|
||||
name: assetTypeOptionsTitles[0].toLowerCase(),
|
||||
title: assetTypeOptionsTitles[0]
|
||||
},
|
||||
{
|
||||
name: assetTypeOptionsTitles[1].toLowerCase(),
|
||||
title: assetTypeOptionsTitles[1]
|
||||
}
|
||||
]
|
||||
|
||||
export default function ServicesFields(): ReactElement {
|
||||
// connect with Form state, use for conditional field rendering
|
||||
const { values } = useFormikContext<FormPublishData>()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Field
|
||||
{...getFieldContent('type', content.services.fields)}
|
||||
component={Input}
|
||||
name="type"
|
||||
options={assetTypeOptions}
|
||||
/>
|
||||
<Field
|
||||
{...getFieldContent('dataTokenOptions', content.services.fields)}
|
||||
component={Input}
|
|
@ -2,8 +2,8 @@ import React, { ReactElement } from 'react'
|
|||
import NetworkName from '@shared/NetworkName'
|
||||
import Tooltip from '@shared/atoms/Tooltip'
|
||||
import { useWeb3 } from '@context/Web3'
|
||||
import styles from './Title.module.css'
|
||||
import content from '../../../content/publish/index.json'
|
||||
import styles from './index.module.css'
|
||||
import content from '../../../../content/publish/index.json'
|
||||
|
||||
export default function Title(): ReactElement {
|
||||
const { networkId } = useWeb3()
|
|
@ -1,7 +1,36 @@
|
|||
import React from 'react'
|
||||
import { File as FileMetadata } from '@oceanprotocol/lib'
|
||||
import * as Yup from 'yup'
|
||||
import { allowDynamicPricing, allowFixedPricing } from '../../../app.config.js'
|
||||
import { FormPublishData } from './_types'
|
||||
import { FormPublishData, StepContent } from './_types'
|
||||
import content from '../../../content/publish/form.json'
|
||||
import PricingFields from './Pricing'
|
||||
import MetadataFields from './Metadata'
|
||||
import ServicesFields from './Services'
|
||||
import Preview from './Preview'
|
||||
|
||||
export const wizardSteps: StepContent[] = [
|
||||
{
|
||||
step: 1,
|
||||
title: content.metadata.title,
|
||||
component: <MetadataFields />
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
title: content.services.title,
|
||||
component: <ServicesFields />
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
title: content.pricing.title,
|
||||
component: <PricingFields />
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
title: content.preview.title,
|
||||
component: <Preview />
|
||||
}
|
||||
]
|
||||
|
||||
export const initialValues: Partial<FormPublishData> = {
|
||||
step: 1,
|
|
@ -1,5 +1,6 @@
|
|||
import { DataTokenOptions } from '@hooks/usePublish'
|
||||
import { EditableMetadataLinks, File } from '@oceanprotocol/lib'
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
export interface FormPublishService {
|
||||
files: string | File[]
|
||||
|
@ -15,6 +16,7 @@ export interface FormPublishService {
|
|||
|
||||
export interface FormPublishData {
|
||||
step: number
|
||||
steps: number
|
||||
type: 'dataset' | 'algorithm'
|
||||
metadata: {
|
||||
name: string
|
||||
|
@ -26,3 +28,9 @@ export interface FormPublishData {
|
|||
services: FormPublishService[]
|
||||
pricing: PriceOptions
|
||||
}
|
||||
|
||||
export interface StepContent {
|
||||
step: number
|
||||
title: string
|
||||
component: ReactElement
|
||||
}
|
||||
|
|
|
@ -1,41 +1,4 @@
|
|||
.tabs ul[class*='tabList'] {
|
||||
background-color: var(--background-content);
|
||||
border: 1px solid var(--border-color);
|
||||
border-top-left-radius: var(--border-radius);
|
||||
border-top-right-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.tabs div[class*='tabContent'] {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: calc(var(--spacer) * 1.5);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.alert,
|
||||
div.alert {
|
||||
.form {
|
||||
composes: box from '@shared/atoms/Box.module.css';
|
||||
margin-bottom: var(--spacer);
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 55rem) {
|
||||
.grid {
|
||||
/* lazy golden ratio */
|
||||
grid-template-columns: 1.618fr 1fr;
|
||||
}
|
||||
|
||||
.tabs ul[class*='tabList'] {
|
||||
/* fake the above 1.618fr column */
|
||||
max-width: calc((100% / 1.618) - calc(var(--spacer) / 1.075));
|
||||
}
|
||||
|
||||
.sticky {
|
||||
position: sticky;
|
||||
top: calc(var(--spacer) / 2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { ReactElement, useState, useEffect } from 'react'
|
||||
import { Formik, FormikState } from 'formik'
|
||||
import { Form, Formik, FormikState } from 'formik'
|
||||
import { usePublish } from '@hooks/usePublish'
|
||||
import { initialValues, validationSchema } from './_constants'
|
||||
import { initialValues, validationSchema, wizardSteps } from './_constants'
|
||||
import { validateDockerImage } from '@utils/docker'
|
||||
import { Logger, Metadata } from '@oceanprotocol/lib'
|
||||
import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
|
||||
|
@ -11,10 +11,20 @@ import { transformPublishFormToDdo } from './_utils'
|
|||
import PageHeader from '@shared/Page/PageHeader'
|
||||
import Title from './Title'
|
||||
import styles from './index.module.css'
|
||||
import FormPublish from './FormPublish'
|
||||
import Actions from './Actions'
|
||||
import Debug from './Debug'
|
||||
import Navigation from './Navigation'
|
||||
|
||||
const formName = 'ocean-publish-form'
|
||||
|
||||
function Steps({ step }: { step: number }) {
|
||||
const { component } = wizardSteps.filter(
|
||||
(stepContent) => stepContent.step === step
|
||||
)[0]
|
||||
|
||||
return component
|
||||
}
|
||||
|
||||
export default function PublishPage({
|
||||
content
|
||||
}: {
|
||||
|
@ -84,14 +94,24 @@ export default function PublishPage({
|
|||
{isInPurgatory && purgatoryData ? null : (
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
initialStatus="empty"
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={async (values, { resetForm }) => {
|
||||
// kick off publishing
|
||||
// await handleSubmit(values, resetForm)
|
||||
}}
|
||||
>
|
||||
<FormPublish />
|
||||
{({ values }) => {
|
||||
return (
|
||||
<>
|
||||
<Form className={styles.form}>
|
||||
<Navigation />
|
||||
<Steps step={values.step} />
|
||||
<Actions />
|
||||
</Form>
|
||||
<Debug values={values} />
|
||||
</>
|
||||
)
|
||||
}}
|
||||
</Formik>
|
||||
)}
|
||||
</>
|
||||
|
|
Loading…
Reference in New Issue