import { t } from '@lingui/macro' ; import { CheckCircleOutlined , LoadingOutlined } from '@ant-design/icons' ; import { BigNumber } from '@ethersproject/bignumber' ; import { Form } from 'antd' ; import { useCallback , useContext , useEffect , useMemo , useState } from 'react' ; import { ThemeContext } from 'contexts/themeContext' ; import { utils } from 'ethers' ; import useContractReader from 'hooks/ContractReader' ; import { ContractName } from 'models/contract-name' ; import { normalizeHandle } from 'utils/formatHandle' ; import { ProjectHandleInput , ProjectHandleInitialValue , } from './ProjectHandleInput' ; import { FormItemExt } from '../formItemExt' ; /**
 * Custom Form.Item component for project handles.
 */ export default function ProjectHandleFormItem ( { name , hideLabel , formItemProps , onValueChange , requireState , required , returnValue , initialValue , } ) { const { theme : { colors } , } = useContext ( ThemeContext ) ; const [ inputContents , setInputContents ] = useState < string > ( ) ; const [ handleLoading , setHandleLoading ] = useState < boolean > ( false ) ; useEffect ( ( ) => { if ( initialValue ) { setHandleLoading ( true ) ; } } , [ initialValue ] ) ; const handleHex = useMemo ( ( ) => { if ( ! inputContents ) return ; try { return utils . formatBytes32String ( normalizeHandle ( inputContents ) ) ; } catch ( e ) { console . error ( 'Error formatting handle' , inputContents , e ) ; } } , [ inputContents ] ) ; const idForHandle = useContractReader < BigNumber > ( { contract : ContractName . Projects , functionName : 'projectFor' , args : handleHex && requireState ? [ handleHex ] : null , callback : useCallback ( id => { setHandleLoading ( false ) ; if ( returnValue === 'id' ) { onValueChange ?. ( id ?. toHexString ( ) ?? '0x00' ) ; } } , [ onValueChange , returnValue ] ) , } ) ; const handleExists = Boolean ( idForHandle ?. gt ( 0 ) ) ; const validator = useCallback ( ( ) => { if ( handleExists && requireState === 'notExist' ) return Promise . reject ( 'Handle not available' ) ; if ( ! handleExists && requireState === 'exists' ) return Promise . reject ( "Project doesn't exist" ) ; else return Promise . resolve ( ) ; } , [ handleExists , requireState ] ) ; const suffix = useMemo ( ( ) => { const InputCheckIcon = ( < CheckCircleOutlined style = { { color : colors . icon . success } } />); if ( handleLoading ) { return < LoadingOutlined spin / > ; } if ( ! inputContents ) { return '' ; } if ( requireState === 'notExist' ) { const isExistingHandleValid = initialValue !== undefined && inputContents === initialValue ; if ( handleExists && ! isExistingHandleValid ) { return 'Handle already in use' ; } if ( ! handleExists || ( handleExists && isExistingHandleValid ) ) { return InputCheckIcon ; } } if ( requireState === 'exists' ) { return handleExists ? InputCheckIcon : 'Handle not found' ; } return '' ; } , [ inputContents , handleLoading , handleExists , requireState , initialValue , colors . icon . success , ] ) ; const onChange = ( val ) => { setInputContents ( val ) ; if ( val ) { setHandleLoading ( true ) ; } if ( returnValue !== 'id' ) { onValueChange ?. ( val ?? '' ) ; } } ; return ( < Form . Item name = { name } label = { hideLabel ? undefined : formItemProps ?. label ?? t `Project handle` } { ... formItemProps } rules = { [ { required } , { validator } , ... ( formItemProps ?. rules ?? [ ] ) ] } validateTrigger = { false } validateFirst > < ProjectHandleInput onChange = { onChange } initialValue = { initialValue } suffix = { suffix } / > < /Form.Item>); }