import React from 'react'; import { Dropdown, DropdownItemProps, DropdownProps } from 'semantic-ui-react'; import { FormikProps, Field } from 'formik'; import * as JoyForms from '@polkadot/joy-utils/forms'; import { SubmittableResult } from '@polkadot/api'; import { TxFailedCallback, TxCallback } from '@polkadot/react-components/Status/types'; import { OnTxButtonClick } from '@polkadot/joy-utils/TxButton'; import isEqual from 'lodash/isEqual'; import { componentName } from '@polkadot/joy-utils/react/helpers'; export type FormCallbacks = { onSubmit: OnTxButtonClick; onTxSuccess: TxCallback; onTxFailed: TxFailedCallback; }; export type GenericEasyProp = { id: keyof FormValues; type: string; name: string; description?: string; required?: boolean; minItems?: number; maxItems?: number; minTextLength?: number; maxTextLength?: number; classId?: any; }; type BaseFieldProps = OuterProps & FormikProps & { field: GenericEasyProp; }; type EasyTextProps = BaseFieldProps & JoyForms.LabelledProps; type EasyFieldProps = BaseFieldProps & JoyForms.LabelledProps & { fieldProps: any; } type EasyDropdownProps = BaseFieldProps & { options: DropdownItemProps[]; }; type FormFields = { LabelledText: React.FunctionComponent>; LabelledField: React.FunctionComponent>; EasyText: React.FunctionComponent>; EasyField: React.FunctionComponent>; EasyDropdown: React.FunctionComponent>; }; export type EasyFormProps = OuterProps & FormikProps & FormFields & FormCallbacks & { isFieldChanged: (field: keyof FormValues | GenericEasyProp) => boolean; }; export function withEasyForm (Component: React.ComponentType>) { type FieldName = keyof FormValues type FieldObject = GenericEasyProp const LabelledText = JoyForms.LabelledText(); const LabelledField = JoyForms.LabelledField(); function EasyText (props: EasyTextProps) { const { field: f } = props; return !f ? null : ; } const EasyField = (props: EasyFieldProps) => { const { field: f, fieldProps = {}, placeholder, className, style, ...otherProps } = props; const { id } = f; const allFieldProps = { name: id, id, placeholder, className, style, disabled: otherProps.isSubmitting, ...fieldProps }; return !f ? null : ( ); }; const EasyDropdown = (props: EasyDropdownProps) => { const { field: f, options = [] } = props; const id = f.id as string; const value = (props.values as any)[id] || ''; return { props.setFieldTouched(id, true); }, onChange: (_event: any, data: DropdownProps) => { props.setFieldValue(id, data.value); } }} />; }; const ResultComponent: React.FunctionComponent> = (props: EasyFormProps) => { const { initialValues, values, dirty, touched, errors, isValid, setSubmitting } = props; const isFieldChanged = (field: FieldName | FieldObject): boolean => { const fieldName = typeof field === 'string' ? field : (field as FieldObject).id; return ( dirty && touched[fieldName] === true && !isEqual(values[fieldName], initialValues[fieldName]) ); }; const onSubmit = (sendTx: () => void) => { if (isValid) { sendTx(); } else { console.log('Form is invalid. Errors:', errors); } }; const onTxSuccess: TxCallback = (_txResult: SubmittableResult) => { setSubmitting(false); }; const onTxFailed: TxFailedCallback = (txResult: SubmittableResult | null) => { setSubmitting(false); if (txResult === null) { // Tx cancelled } }; const allProps = { ...props, // Callbacks: onSubmit, onTxSuccess, onTxFailed, // Components: LabelledText, LabelledField, EasyText, EasyField, EasyDropdown, // Other isFieldChanged }; return ; }; ResultComponent.displayName = `withEasyForm(${componentName(Component)})`; return ResultComponent; }