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

refactor all the URL inputs

* only act on user action, we were firing events left and right on every keystroke
* remove all local state management, the field has the value already
* add success state for provider input
This commit is contained in:
Matthias Kretschmann 2021-11-24 12:29:14 +00:00
parent 5fd97b11e4
commit 5bf8543150
Signed by: m
GPG Key ID: 606EEEF3C479A91F
6 changed files with 68 additions and 72 deletions

View File

@ -1,56 +1,41 @@
import React, { ReactElement, useState, useEffect } from 'react'
import React, { ReactElement, useState } from 'react'
import { useField } from 'formik'
import { toast } from 'react-toastify'
import CustomInput from './URLInput/Input'
import UrlInput from './URLInput'
import { useOcean } from '@context/Ocean'
import { InputProps } from '@shared/FormInput'
export default function CustomProvider(props: InputProps): ReactElement {
const [field, meta, helpers] = useField(props.name)
const [isLoading, setIsLoading] = useState(false)
const [providerUrl, setProviderUrl] = useState<string>()
const [isValid, setIsValid] = useState(false)
const { ocean, config } = useOcean()
function loadProvider() {
if (!providerUrl) return
async function validateProvider() {
let valid: boolean
try {
setIsLoading(true)
valid = await ocean.provider.isValidProvider(providerUrl)
} catch (error) {
valid = false
console.error(error.message)
} finally {
valid
? toast.success('Perfect! That provider URL looks good 🐳')
: toast.error(
'Could not validate provider. Please check URL and try again'
)
async function validateProvider(url: string) {
setIsLoading(true)
setIsLoading(false)
}
try {
const isValid = await ocean.provider.isValidProvider(url)
setIsValid(isValid)
helpers.setError(undefined)
} catch (error) {
setIsValid(false)
helpers.setError(
'Could not validate provider. Please check URL and try again'
)
} finally {
setIsLoading(false)
}
validateProvider()
}
useEffect(() => {
loadProvider()
}, [providerUrl, config?.providerUri])
async function handleButtonClick(e: React.SyntheticEvent, url: string) {
helpers.setTouched(false)
e.preventDefault()
if (providerUrl === url) {
loadProvider()
}
setProviderUrl(url)
validateProvider(url)
}
return (
<CustomInput
<UrlInput
submitText="Validate"
isValid={isValid}
{...props}
{...field}
isLoading={isLoading}

View File

@ -1,8 +1,8 @@
import React, { ReactElement, useState, useEffect } from 'react'
import React, { ReactElement, useState } from 'react'
import { useField } from 'formik'
import { toast } from 'react-toastify'
import FileInfo from './Info'
import UrlInput from '../URLInput/Input'
import UrlInput from '../URLInput'
import { InputProps } from '@shared/FormInput'
import { getFileInfo } from '@utils/provider'
import { useWeb3 } from '@context/Web3'
@ -12,22 +12,21 @@ import { useCancelToken } from '@hooks/useCancelToken'
export default function FilesInput(props: InputProps): ReactElement {
const [field, meta, helpers] = useField(props.name)
const [isLoading, setIsLoading] = useState(false)
const [fileUrl, setFileUrl] = useState<string>()
const { chainId } = useWeb3()
const newCancelToken = useCancelToken()
function loadFileInfo() {
function loadFileInfo(url: string) {
const config = getOceanConfig(chainId || 1)
async function validateUrl() {
try {
setIsLoading(true)
const checkedFile = await getFileInfo(
fileUrl,
url,
config?.providerUri,
newCancelToken()
)
checkedFile && helpers.setValue([{ url: fileUrl, ...checkedFile[0] }])
checkedFile && helpers.setValue([{ url, ...checkedFile[0] }])
} catch (error) {
toast.error('Could not fetch file info. Please check URL and try again')
console.error(error.message)
@ -36,27 +35,13 @@ export default function FilesInput(props: InputProps): ReactElement {
}
}
fileUrl && validateUrl()
validateUrl()
}
useEffect(() => {
loadFileInfo()
}, [fileUrl])
async function handleButtonClick(e: React.SyntheticEvent, url: string) {
// hack so the onBlur-triggered validation does not show,
// like when this field is required
helpers.setTouched(false)
// File example 'https://oceanprotocol.com/tech-whitepaper.pdf'
e.preventDefault()
// In the case when the user re-add the same URL after it was removed (by accident or intentionally)
if (fileUrl === url) {
loadFileInfo()
}
setFileUrl(url)
loadFileInfo(url)
}
return (

View File

@ -10,3 +10,8 @@
.error {
composes: error from '@shared/FormInput/index.module.css';
}
.success {
background: var(--brand-alert-green);
opacity: 1 !important;
}

View File

@ -1,8 +1,8 @@
import React, { ReactElement } from 'react'
import Button from '@shared/atoms/Button'
import { ErrorMessage, FieldInputProps, useField } from 'formik'
import { ErrorMessage, useField } from 'formik'
import Loader from '@shared/atoms/Loader'
import styles from './Input.module.css'
import styles from './index.module.css'
import InputGroup from '@shared/FormInput/InputGroup'
import InputElement from '@shared/FormInput/InputElement'
@ -12,6 +12,7 @@ export default function URLInput({
isLoading,
name,
value,
isValid,
...props
}: {
submitText: string
@ -19,6 +20,7 @@ export default function URLInput({
isLoading: boolean
name: string
value: string
isValid?: boolean
}): ReactElement {
const [field, meta] = useField(name)
const isButtonDisabled =
@ -36,17 +38,24 @@ export default function URLInput({
value={value}
type="url"
/>
<Button
style="primary"
size="small"
onClick={(e: React.SyntheticEvent) => {
e.preventDefault()
handleButtonClick(e, field.value)
}}
disabled={isButtonDisabled}
>
{isLoading ? <Loader /> : submitText}
</Button>
{isValid ? (
<Button size="small" disabled className={styles.success}>
Valid
</Button>
) : (
<Button
style="primary"
size="small"
onClick={(e: React.SyntheticEvent) => {
e.preventDefault()
handleButtonClick(e, field.value)
}}
disabled={isButtonDisabled}
>
{isLoading ? <Loader /> : submitText}
</Button>
)}
</InputGroup>
{meta.touched && meta.error && (

View File

@ -6,6 +6,8 @@ import IconCompute from '@images/compute.svg'
import content from '../../../../content/publish/form.json'
import { getFieldContent } from '../_utils'
import { FormPublishData } from '../_types'
import { useWeb3 } from '@context/Web3'
import { getOceanConfig } from '@utils/ocean'
const accessTypeOptionsTitles = getFieldContent(
'access',
@ -14,7 +16,8 @@ const accessTypeOptionsTitles = getFieldContent(
export default function ServicesFields(): ReactElement {
// connect with Form state, use for conditional field rendering
const { values, setFieldValue } = useFormikContext<FormPublishData>()
const { values, setFieldValue, setTouched } =
useFormikContext<FormPublishData>()
const accessTypeOptions = [
{
@ -44,7 +47,16 @@ export default function ServicesFields(): ReactElement {
'services[0].access',
values.services[0].algorithmPrivacy === true ? 'compute' : 'download'
)
}, [values.services[0].algorithmPrivacy])
}, [values.services[0].algorithmPrivacy, setFieldValue])
// Auto-change default providerUrl on user network change
useEffect(() => {
if (!values?.user?.chainId) return
const config = getOceanConfig(values.user.chainId)
config && setFieldValue('services[0].providerUrl', config.providerUri)
setTouched({ services: [{ providerUrl: true }] })
}, [values.user.chainId, setFieldValue, setTouched])
return (
<>

View File

@ -56,7 +56,7 @@ export const initialValues: FormPublishData = {
dataTokenOptions: { name: '', symbol: '' },
timeout: '',
access: '',
providerUrl: 'https://provider.oceanprotocol.com'
providerUrl: 'https://provider.mainnet.oceanprotocol.com'
}
],
pricing: {