import { FC, ReactNode, useCallback, useEffect, useState } from 'react' import Container from '../Container' import Flex from '../Flex' import Input from '../Input' import Select, { CreatableSelect } from '../Select' import Text from '../Text' import { SelectOption, TransactionState, transactionsOptions, TxFields, defaultTransactionType } from '../../state/transactions' import { useSnapshot } from 'valtio' import state from '../../state' import { streamState } from '../DebugStream' import { Box, Button } from '..' import Textarea from '../Textarea' import { getFlags } from '../../state/constants/flags' import { Plus, Trash } from 'phosphor-react' import AccountSequence from '../Sequence' import { capitalize, typeIs } from '../../utils/helpers' interface UIProps { setState: (pTx?: Partial | undefined) => TransactionState | undefined resetState: (tt?: SelectOption) => TransactionState | undefined state: TransactionState estimateFee?: (...arg: any) => Promise switchToJson: () => void } export const TxUI: FC = ({ state: txState, setState, resetState, estimateFee, switchToJson }) => { const { accounts } = useSnapshot(state) const { selectedAccount, selectedTransaction, txFields, selectedFlags, hookParameters, memos } = txState const accountOptions: SelectOption[] = accounts.map(acc => ({ label: acc.name, value: acc.address })) const flagsOptions: SelectOption[] = Object.entries( getFlags(selectedTransaction?.value) || {} ).map(([label, value]) => ({ label, value })) const [feeLoading, setFeeLoading] = useState(false) const handleSetAccount = (acc: SelectOption) => { setState({ selectedAccount: acc }) streamState.selectedAccount = acc } const handleSetField = useCallback( (field: keyof TxFields, value: string, opFields?: TxFields) => { const fields = opFields || txFields const obj = fields[field] setState({ txFields: { ...fields, [field]: typeof obj === 'object' ? { ...obj, $value: value } : value } }) }, [setState, txFields] ) const setRawField = useCallback( (field: keyof TxFields, type: string, value: any) => { // TODO $type should be a narrowed type setState({ txFields: { ...txFields, [field]: { $type: type, $value: value } } }) }, [setState, txFields] ) const handleEstimateFee = useCallback( async (state?: TransactionState, silent?: boolean) => { setFeeLoading(true) const fee = await estimateFee?.(state, { silent }) if (fee) handleSetField('Fee', fee, state?.txFields) setFeeLoading(false) }, [estimateFee, handleSetField] ) const handleChangeTxType = useCallback( (tt: SelectOption) => { setState({ selectedTransaction: tt }) const newState = resetState(tt) handleEstimateFee(newState, true) }, [handleEstimateFee, resetState, setState] ) // default tx useEffect(() => { if (selectedTransaction?.value) return if (defaultTransactionType) { handleChangeTxType(defaultTransactionType) } }, [handleChangeTxType, selectedTransaction?.value]) const richFields = ['TransactionType', 'Account', 'HookParameters', 'Memos'] if (flagsOptions.length) { richFields.push('Flags') } const otherFields = Object.keys(txFields).filter(k => !richFields.includes(k)) as [keyof TxFields] const amountOptions = [ { label: 'XRP', value: 'xrp' }, { label: 'Token', value: 'token' } ] as const const defaultTokenAmount = { value: '0', currency: '', issuer: '' } return ( handleSetAccount(acc)} // TODO make react-select have correct types for acc /> {richFields.includes('Flags') && ( setRawField(field, 'amount.token', { ...tokenAmount, issuer: e.target.value }) } /> */} { setRawField(field, 'amount.token', { ...tokenAmount, currency: e.target.value }) }} /> { setRawField(field, 'amount.token', { ...tokenAmount, value: e.target.value }) }} /> { setRawField(field, 'amount.token', { ...tokenAmount, issuer: value }) }} /> ) : ( handleSetField(field, e.target.value)} /> )}