1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-06-26 03:06:49 +02:00
market/src/components/@shared/FormInput/index.tsx
claudiaHash 97744820ac
Display generic info message for file inputs (#1334)
* display generic message

* add helper message

* bold text in json, remove unused css file

* fixes

* different help message displayed as tooltip

* tooltip help not displayed for files/links fields on publish

* conditionally hide/show tooltip

* use same mechanism for edit form

* add prominentHelp file into content pages

* type fix

* remove unused code

* error message position fix

* error doesn't overlap help message

* show validation error message fix

Co-authored-by: ClaudiaHolhos <claudia@oceanprotocol.com>
2022-04-28 15:39:46 +02:00

142 lines
3.7 KiB
TypeScript

import React, {
ChangeEvent,
FormEvent,
KeyboardEvent,
ReactElement,
ReactNode,
useEffect,
useState
} from 'react'
import InputElement from './InputElement'
import Label from './Label'
import styles from './index.module.css'
import { ErrorMessage, FieldInputProps } from 'formik'
import classNames from 'classnames/bind'
import Disclaimer from './Disclaimer'
import Tooltip from '@shared/atoms/Tooltip'
import Markdown from '@shared/Markdown'
import FormHelp from './Help'
const cx = classNames.bind(styles)
export interface InputProps {
name: string
label?: string | ReactNode
placeholder?: string
required?: boolean
help?: string
prominentHelp?: boolean
tag?: string
type?: string
options?: string[]
sortOptions?: boolean
additionalComponent?: ReactElement
value?: string | number
onChange?(
e:
| FormEvent<HTMLInputElement>
| ChangeEvent<HTMLInputElement>
| ChangeEvent<HTMLSelectElement>
| ChangeEvent<HTMLTextAreaElement>
): void
onKeyPress?(
e:
| KeyboardEvent<HTMLInputElement>
| KeyboardEvent<HTMLInputElement>
| KeyboardEvent<HTMLSelectElement>
| KeyboardEvent<HTMLTextAreaElement>
): void
rows?: number
multiple?: boolean
pattern?: string
min?: string
max?: string
disabled?: boolean
readOnly?: boolean
field?: FieldInputProps<any>
form?: any
prefix?: string | ReactElement
postfix?: string | ReactElement
step?: string
defaultChecked?: boolean
size?: 'mini' | 'small' | 'large' | 'default'
className?: string
checked?: boolean
disclaimer?: string
disclaimerValues?: string[]
}
export default function Input(props: Partial<InputProps>): ReactElement {
const {
label,
help,
prominentHelp,
additionalComponent,
size,
form,
field,
disclaimer,
disclaimerValues
} = props
const isFormikField = typeof field !== 'undefined'
const isNestedField = field?.name?.includes('.')
// TODO: this feels hacky as it assumes nested `values` store. But we can't use the
// `useField()` hook in here to get `meta.error` so we have to match against form?.errors?
// handling flat and nested data at same time.
const parsedFieldName =
isFormikField && (isNestedField ? field?.name.split('.') : [field?.name])
// const hasFormikError = !!meta?.touched && !!meta?.error
const hasFormikError =
form?.errors !== {} &&
form?.touched?.[parsedFieldName[0]]?.[parsedFieldName[1]] &&
form?.errors?.[parsedFieldName[0]]?.[parsedFieldName[1]]
const styleClasses = cx({
field: true,
hasError: hasFormikError
})
const [disclaimerVisible, setDisclaimerVisible] = useState(true)
useEffect(() => {
if (!isFormikField) return
if (disclaimer && disclaimerValues) {
setDisclaimerVisible(
disclaimerValues.includes(
props.form?.values[parsedFieldName[0]]?.[parsedFieldName[1]]
)
)
}
}, [isFormikField, props.form?.values])
return (
<div className={styleClasses}>
<Label htmlFor={props.name}>
{label}
{props.required && (
<span title="Required" className={styles.required}>
*
</span>
)}
{help && !prominentHelp && (
<Tooltip content={<Markdown text={help} />} />
)}
</Label>
<InputElement size={size} {...field} {...props} />
{help && prominentHelp && <FormHelp>{help}</FormHelp>}
{isFormikField && hasFormikError && (
<div className={styles.error}>
<ErrorMessage name={field.name} />
</div>
)}
{disclaimer && (
<Disclaimer visible={disclaimerVisible}>{disclaimer}</Disclaimer>
)}
{additionalComponent && additionalComponent}
</div>
)
}