Merge pull request #296 from XRPLF/feat/account-ui
Extend transactions Account UI.
This commit is contained in:
		@@ -3,13 +3,11 @@ import { mauve, mauveDark, purple, purpleDark } from '@radix-ui/colors'
 | 
			
		||||
import { useTheme } from 'next-themes'
 | 
			
		||||
import { styled } from '../stitches.config'
 | 
			
		||||
import dynamic from 'next/dynamic'
 | 
			
		||||
import type { Props } from 'react-select'
 | 
			
		||||
import type { Props, StylesConfig } from 'react-select'
 | 
			
		||||
const SelectInput = dynamic(() => import('react-select'), { ssr: false })
 | 
			
		||||
const CreatableSelectInput = dynamic(() => import('react-select/creatable'), { ssr: false })
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line react/display-name
 | 
			
		||||
const Select = forwardRef<any, Props>((props, ref) => {
 | 
			
		||||
  const { theme } = useTheme()
 | 
			
		||||
  const isDark = theme === 'dark'
 | 
			
		||||
const getColors = (isDark: boolean) => {
 | 
			
		||||
  const colors: any = {
 | 
			
		||||
    // primary: pink.pink9,
 | 
			
		||||
    active: isDark ? purpleDark.purple9 : purple.purple9,
 | 
			
		||||
@@ -30,16 +28,17 @@ const Select = forwardRef<any, Props>((props, ref) => {
 | 
			
		||||
  }
 | 
			
		||||
  colors.outline = colors.background
 | 
			
		||||
  colors.selected = colors.secondary
 | 
			
		||||
  return (
 | 
			
		||||
    <SelectInput
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      menuPosition={props.menuPosition || 'fixed'}
 | 
			
		||||
      styles={{
 | 
			
		||||
  return colors
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const getStyles = (isDark: boolean) => {
 | 
			
		||||
  const colors = getColors(isDark)
 | 
			
		||||
  const styles: StylesConfig = {
 | 
			
		||||
    container: provided => {
 | 
			
		||||
      return {
 | 
			
		||||
        ...provided,
 | 
			
		||||
        position: 'relative',
 | 
			
		||||
            width: '100%',
 | 
			
		||||
        width: '100%'
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    singleValue: provided => ({
 | 
			
		||||
@@ -111,14 +110,54 @@ const Select = forwardRef<any, Props>((props, ref) => {
 | 
			
		||||
        padding: 6,
 | 
			
		||||
        color: state.isFocused ? colors.border : colors.secondary,
 | 
			
		||||
        ':hover': {
 | 
			
		||||
              color: colors.border,
 | 
			
		||||
          color: colors.border
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    clearIndicator: provided => {
 | 
			
		||||
      return {
 | 
			
		||||
        ...provided,
 | 
			
		||||
        padding: 6,
 | 
			
		||||
        color: colors.secondary,
 | 
			
		||||
        ':hover': {
 | 
			
		||||
          color: colors.border
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
      }}
 | 
			
		||||
  }
 | 
			
		||||
  return styles
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line react/display-name
 | 
			
		||||
const Select = forwardRef<any, Props>((props, ref) => {
 | 
			
		||||
  const { theme } = useTheme()
 | 
			
		||||
  const isDark = theme === 'dark'
 | 
			
		||||
  const styles = getStyles(isDark)
 | 
			
		||||
  return (
 | 
			
		||||
    <SelectInput
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      menuPosition={props.menuPosition || 'fixed'}
 | 
			
		||||
      styles={styles}
 | 
			
		||||
      {...props}
 | 
			
		||||
    />
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line react/display-name
 | 
			
		||||
const Creatable = forwardRef<any, Props>((props, ref) => {
 | 
			
		||||
  const { theme } = useTheme()
 | 
			
		||||
  const isDark = theme === 'dark'
 | 
			
		||||
  const styles = getStyles(isDark)
 | 
			
		||||
  return (
 | 
			
		||||
    <CreatableSelectInput
 | 
			
		||||
      ref={ref}
 | 
			
		||||
      formatCreateLabel={label => `Enter "${label}"`}
 | 
			
		||||
      menuPosition={props.menuPosition || 'fixed'}
 | 
			
		||||
      styles={styles}
 | 
			
		||||
      {...props}
 | 
			
		||||
    />
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export default styled(Select, {})
 | 
			
		||||
export const CreatableSelect = styled(Creatable, {})
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,6 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
    (state: Partial<TransactionState> = txState) => {
 | 
			
		||||
      const {
 | 
			
		||||
        selectedTransaction,
 | 
			
		||||
        selectedDestAccount,
 | 
			
		||||
        selectedAccount,
 | 
			
		||||
        txFields,
 | 
			
		||||
        selectedFlags,
 | 
			
		||||
@@ -52,7 +51,6 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
      } = state
 | 
			
		||||
 | 
			
		||||
      const TransactionType = selectedTransaction?.value || null
 | 
			
		||||
      const Destination = selectedDestAccount?.value || txFields?.Destination
 | 
			
		||||
      const Account = selectedAccount?.value || null
 | 
			
		||||
      const Flags = combineFlags(selectedFlags?.map(flag => flag.value)) || txFields?.Flags
 | 
			
		||||
      const HookParameters = Object.entries(hookParameters || {}).reduce<
 | 
			
		||||
@@ -75,7 +73,6 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
        HookParameters,
 | 
			
		||||
        Flags,
 | 
			
		||||
        TransactionType,
 | 
			
		||||
        Destination,
 | 
			
		||||
        Account,
 | 
			
		||||
        Memos
 | 
			
		||||
      })
 | 
			
		||||
@@ -128,11 +125,12 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
        throw Error('Account must be selected from imported accounts!')
 | 
			
		||||
      }
 | 
			
		||||
      const options = prepareOptions(st)
 | 
			
		||||
 | 
			
		||||
      const fields = getTxFields(options.TransactionType)
 | 
			
		||||
      if (fields.Destination && !options.Destination) {
 | 
			
		||||
        throw Error('Destination account is required!')
 | 
			
		||||
      // delete unnecessary fields
 | 
			
		||||
      Object.keys(options).forEach(field => {
 | 
			
		||||
        if (!options[field]) {
 | 
			
		||||
          delete options[field]
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      await sendTransaction(account, options, { logPrefix })
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
@@ -167,13 +165,6 @@ const Transaction: FC<TransactionProps> = ({ header, state: txState, ...props })
 | 
			
		||||
        selectedTransaction: transactionType
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (fields.Destination !== undefined) {
 | 
			
		||||
        nwState.selectedDestAccount = null
 | 
			
		||||
        fields.Destination = ''
 | 
			
		||||
      } else {
 | 
			
		||||
        fields.Destination = undefined
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (transactionType?.value && transactionFlags[transactionType?.value] && fields.Flags) {
 | 
			
		||||
        nwState.selectedFlags = extractFlags(transactionType.value, fields.Flags)
 | 
			
		||||
        fields.Flags = undefined
 | 
			
		||||
 
 | 
			
		||||
@@ -1,15 +1,14 @@
 | 
			
		||||
import { FC, ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
 | 
			
		||||
import { FC, ReactNode, useCallback, useEffect, useState } from 'react'
 | 
			
		||||
import Container from '../Container'
 | 
			
		||||
import Flex from '../Flex'
 | 
			
		||||
import Input from '../Input'
 | 
			
		||||
import Select from '../Select'
 | 
			
		||||
import Select, { CreatableSelect } from '../Select'
 | 
			
		||||
import Text from '../Text'
 | 
			
		||||
import {
 | 
			
		||||
  SelectOption,
 | 
			
		||||
  TransactionState,
 | 
			
		||||
  transactionsOptions,
 | 
			
		||||
  TxFields,
 | 
			
		||||
  getTxFields,
 | 
			
		||||
  defaultTransactionType
 | 
			
		||||
} from '../../state/transactions'
 | 
			
		||||
import { useSnapshot } from 'valtio'
 | 
			
		||||
@@ -20,7 +19,7 @@ import Textarea from '../Textarea'
 | 
			
		||||
import { getFlags } from '../../state/constants/flags'
 | 
			
		||||
import { Plus, Trash } from 'phosphor-react'
 | 
			
		||||
import AccountSequence from '../Sequence'
 | 
			
		||||
import { typeIs } from '../../utils/helpers'
 | 
			
		||||
import { capitalize, typeIs } from '../../utils/helpers'
 | 
			
		||||
 | 
			
		||||
interface UIProps {
 | 
			
		||||
  setState: (pTx?: Partial<TransactionState> | undefined) => TransactionState | undefined
 | 
			
		||||
@@ -38,28 +37,14 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
  switchToJson
 | 
			
		||||
}) => {
 | 
			
		||||
  const { accounts } = useSnapshot(state)
 | 
			
		||||
  const {
 | 
			
		||||
    selectedAccount,
 | 
			
		||||
    selectedDestAccount,
 | 
			
		||||
    selectedTransaction,
 | 
			
		||||
    txFields,
 | 
			
		||||
    selectedFlags,
 | 
			
		||||
    hookParameters,
 | 
			
		||||
    memos
 | 
			
		||||
  } = txState
 | 
			
		||||
  const { selectedAccount, selectedTransaction, txFields, selectedFlags, hookParameters, memos } =
 | 
			
		||||
    txState
 | 
			
		||||
 | 
			
		||||
  const accountOptions: SelectOption[] = accounts.map(acc => ({
 | 
			
		||||
    label: acc.name,
 | 
			
		||||
    value: acc.address
 | 
			
		||||
  }))
 | 
			
		||||
 | 
			
		||||
  const destAccountOptions: SelectOption[] = accounts
 | 
			
		||||
    .map(acc => ({
 | 
			
		||||
      label: acc.name,
 | 
			
		||||
      value: acc.address
 | 
			
		||||
    }))
 | 
			
		||||
    .filter(acc => acc.value !== selectedAccount?.value)
 | 
			
		||||
 | 
			
		||||
  const flagsOptions: SelectOption[] = Object.entries(
 | 
			
		||||
    getFlags(selectedTransaction?.value) || {}
 | 
			
		||||
  ).map(([label, value]) => ({
 | 
			
		||||
@@ -136,15 +121,7 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
    }
 | 
			
		||||
  }, [handleChangeTxType, selectedTransaction?.value])
 | 
			
		||||
 | 
			
		||||
  const fields = useMemo(
 | 
			
		||||
    () => getTxFields(selectedTransaction?.value),
 | 
			
		||||
    [selectedTransaction?.value]
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  const richFields = ['TransactionType', 'Account', 'HookParameters', 'Memos']
 | 
			
		||||
  if (fields.Destination !== undefined) {
 | 
			
		||||
    richFields.push('Destination')
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (flagsOptions.length) {
 | 
			
		||||
    richFields.push('Flags')
 | 
			
		||||
@@ -192,18 +169,6 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
        <TxField label="Sequence">
 | 
			
		||||
          <AccountSequence address={selectedAccount?.value} />
 | 
			
		||||
        </TxField>
 | 
			
		||||
        {richFields.includes('Destination') && (
 | 
			
		||||
          <TxField label="Destination account">
 | 
			
		||||
            <Select
 | 
			
		||||
              instanceId="to-account"
 | 
			
		||||
              placeholder="Select the destination account"
 | 
			
		||||
              options={destAccountOptions}
 | 
			
		||||
              value={selectedDestAccount}
 | 
			
		||||
              isClearable
 | 
			
		||||
              onChange={(acc: any) => setState({ selectedDestAccount: acc })}
 | 
			
		||||
            />
 | 
			
		||||
          </TxField>
 | 
			
		||||
        )}
 | 
			
		||||
        {richFields.includes('Flags') && (
 | 
			
		||||
          <TxField label="Flags">
 | 
			
		||||
            <Select
 | 
			
		||||
@@ -235,6 +200,7 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
            value = _value?.toString()
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          const isAccount = typeIs(_value, 'object') && _value.$type === 'account'
 | 
			
		||||
          const isXrpAmount = typeIs(_value, 'object') && _value.$type === 'amount.xrp'
 | 
			
		||||
          const isTokenAmount = typeIs(_value, 'object') && _value.$type === 'amount.token'
 | 
			
		||||
          const isJson = typeof _value === 'object' && _value.$type === 'json'
 | 
			
		||||
@@ -255,8 +221,14 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
              <TxField key={field} label={field}>
 | 
			
		||||
                <Flex fluid css={{ alignItems: 'center' }}>
 | 
			
		||||
                  {isTokenAmount ? (
 | 
			
		||||
                    <Flex fluid row align="center" justify="space-between">
 | 
			
		||||
                      <Input
 | 
			
		||||
                    <Flex
 | 
			
		||||
                      fluid
 | 
			
		||||
                      row
 | 
			
		||||
                      align="center"
 | 
			
		||||
                      justify="space-between"
 | 
			
		||||
                      css={{ position: 'relative' }}
 | 
			
		||||
                    >
 | 
			
		||||
                      {/*  <Input
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        placeholder="Issuer"
 | 
			
		||||
                        value={tokenAmount.issuer}
 | 
			
		||||
@@ -266,9 +238,8 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
                            issuer: e.target.value
 | 
			
		||||
                          })
 | 
			
		||||
                        }
 | 
			
		||||
                      />
 | 
			
		||||
                      /> */}
 | 
			
		||||
                      <Input
 | 
			
		||||
                        css={{ mx: '$1' }}
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        value={tokenAmount.currency}
 | 
			
		||||
                        placeholder="Currency"
 | 
			
		||||
@@ -280,6 +251,7 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
                        }}
 | 
			
		||||
                      />
 | 
			
		||||
                      <Input
 | 
			
		||||
                        css={{ mx: '$1' }}
 | 
			
		||||
                        type="number"
 | 
			
		||||
                        value={tokenAmount.value}
 | 
			
		||||
                        placeholder="Value"
 | 
			
		||||
@@ -290,6 +262,19 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
                          })
 | 
			
		||||
                        }}
 | 
			
		||||
                      />
 | 
			
		||||
                      <Box css={{ width: '50%' }}>
 | 
			
		||||
                        <CreatableAccount
 | 
			
		||||
                          value={tokenAmount.issuer}
 | 
			
		||||
                          field={'Issuer' as any}
 | 
			
		||||
                          placeholder="Issuer"
 | 
			
		||||
                          setField={(_, value = '') => {
 | 
			
		||||
                            setRawField(field, 'amount.token', {
 | 
			
		||||
                              ...tokenAmount,
 | 
			
		||||
                              issuer: value
 | 
			
		||||
                            })
 | 
			
		||||
                          }}
 | 
			
		||||
                        />
 | 
			
		||||
                      </Box>
 | 
			
		||||
                    </Flex>
 | 
			
		||||
                  ) : (
 | 
			
		||||
                    <Input
 | 
			
		||||
@@ -323,6 +308,13 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
              </TxField>
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
          if (isAccount) {
 | 
			
		||||
            return (
 | 
			
		||||
              <TxField key={field} label={field}>
 | 
			
		||||
                <CreatableAccount value={value} field={field} setField={handleSetField} />
 | 
			
		||||
              </TxField>
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
          return (
 | 
			
		||||
            <TxField key={field} label={field}>
 | 
			
		||||
              {isJson ? (
 | 
			
		||||
@@ -535,6 +527,35 @@ export const TxUI: FC<UIProps> = ({
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const CreatableAccount: FC<{
 | 
			
		||||
  value: string | undefined
 | 
			
		||||
  field: keyof TxFields
 | 
			
		||||
  placeholder?: string
 | 
			
		||||
  setField: (field: keyof TxFields, value: string, opFields?: TxFields) => void
 | 
			
		||||
}> = ({ value, field, setField, placeholder }) => {
 | 
			
		||||
  const { accounts } = useSnapshot(state)
 | 
			
		||||
  const accountOptions: SelectOption[] = accounts.map(acc => ({
 | 
			
		||||
    label: acc.name,
 | 
			
		||||
    value: acc.address
 | 
			
		||||
  }))
 | 
			
		||||
  const label = accountOptions.find(a => a.value === value)?.label || value
 | 
			
		||||
  const val = {
 | 
			
		||||
    value,
 | 
			
		||||
    label
 | 
			
		||||
  }
 | 
			
		||||
  placeholder = placeholder || `${capitalize(field)} account`
 | 
			
		||||
  return (
 | 
			
		||||
    <CreatableSelect
 | 
			
		||||
      isClearable
 | 
			
		||||
      instanceId={field}
 | 
			
		||||
      placeholder={placeholder}
 | 
			
		||||
      options={accountOptions}
 | 
			
		||||
      value={value ? val : undefined}
 | 
			
		||||
      onChange={(acc: any) => setField(field, acc?.value)}
 | 
			
		||||
    />
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const TxField: FC<{ label: string; children: ReactNode; multiLine?: boolean }> = ({
 | 
			
		||||
  label,
 | 
			
		||||
  children,
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,10 @@
 | 
			
		||||
  {
 | 
			
		||||
    "TransactionType": "AccountDelete",
 | 
			
		||||
    "Account": "rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm",
 | 
			
		||||
    "Destination": "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe",
 | 
			
		||||
    "Destination": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "DestinationTag": 13,
 | 
			
		||||
    "Fee": "2000000",
 | 
			
		||||
    "Sequence": 2470665,
 | 
			
		||||
@@ -40,7 +43,10 @@
 | 
			
		||||
  {
 | 
			
		||||
    "TransactionType": "CheckCreate",
 | 
			
		||||
    "Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
 | 
			
		||||
    "Destination": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
 | 
			
		||||
    "Destination": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "SendMax": "100000000",
 | 
			
		||||
    "Expiration": 570113521,
 | 
			
		||||
    "InvoiceID": "6F1DFD1D0FE8A32E40E1F2C05CF1C15545BAB56B617F9C6C2D63A6B704BEF59B",
 | 
			
		||||
@@ -58,7 +64,10 @@
 | 
			
		||||
  {
 | 
			
		||||
    "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
 | 
			
		||||
    "TransactionType": "EscrowCancel",
 | 
			
		||||
    "Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
 | 
			
		||||
    "Owner": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "OfferSequence": 7,
 | 
			
		||||
    "Fee": "10"
 | 
			
		||||
  },
 | 
			
		||||
@@ -69,7 +78,10 @@
 | 
			
		||||
      "$value": "100",
 | 
			
		||||
      "$type": "amount.xrp"
 | 
			
		||||
    },
 | 
			
		||||
    "Destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
 | 
			
		||||
    "Destination": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "CancelAfter": 533257958,
 | 
			
		||||
    "FinishAfter": 533171558,
 | 
			
		||||
    "Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
 | 
			
		||||
@@ -80,7 +92,10 @@
 | 
			
		||||
  {
 | 
			
		||||
    "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
 | 
			
		||||
    "TransactionType": "EscrowFinish",
 | 
			
		||||
    "Owner": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
 | 
			
		||||
    "Owner": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "OfferSequence": 7,
 | 
			
		||||
    "Condition": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100",
 | 
			
		||||
    "Fulfillment": "A0028000",
 | 
			
		||||
@@ -127,7 +142,14 @@
 | 
			
		||||
      "$type": "amount.xrp"
 | 
			
		||||
    },
 | 
			
		||||
    "Flags": "1",
 | 
			
		||||
    "Destination": "",
 | 
			
		||||
    "Destination": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "Owner": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "Fee": "10"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
@@ -162,7 +184,10 @@
 | 
			
		||||
  {
 | 
			
		||||
    "TransactionType": "Payment",
 | 
			
		||||
    "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
 | 
			
		||||
    "Destination": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
 | 
			
		||||
    "Destination": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "Amount": {
 | 
			
		||||
      "$value": "100",
 | 
			
		||||
      "$type": "amount.xrp"
 | 
			
		||||
@@ -178,7 +203,10 @@
 | 
			
		||||
      "$value": "100",
 | 
			
		||||
      "$type": "amount.xrp"
 | 
			
		||||
    },
 | 
			
		||||
    "Destination": "rsA2LpzuawewSBQXkiju3YQTMzW13pAAdW",
 | 
			
		||||
    "Destination": {
 | 
			
		||||
      "$type": "account",
 | 
			
		||||
      "$value": ""
 | 
			
		||||
    },
 | 
			
		||||
    "SettleDelay": 86400,
 | 
			
		||||
    "PublicKey": "32D2471DB72B27E3310F355BB33E339BF26F8392D5A93D3BC0FC3B566612DA0F0A",
 | 
			
		||||
    "CancelAfter": 533171558,
 | 
			
		||||
 
 | 
			
		||||
@@ -14,11 +14,4 @@ export const deleteAccount = (addr?: string) => {
 | 
			
		||||
      if (!acc) return
 | 
			
		||||
      acc.label = acc.value
 | 
			
		||||
    })
 | 
			
		||||
  transactionsState.transactions
 | 
			
		||||
    .filter(t => t.state.selectedDestAccount?.value === addr)
 | 
			
		||||
    .forEach(t => {
 | 
			
		||||
      const acc = t.state.selectedDestAccount
 | 
			
		||||
      if (!acc) return
 | 
			
		||||
      acc.label = acc.value
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@ interface TransactionOptions {
 | 
			
		||||
  TransactionType: string
 | 
			
		||||
  Account?: string
 | 
			
		||||
  Fee?: string
 | 
			
		||||
  Destination?: string
 | 
			
		||||
  [index: string]: any
 | 
			
		||||
}
 | 
			
		||||
interface OtherOptions {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@ export type Memos = {
 | 
			
		||||
export interface TransactionState {
 | 
			
		||||
  selectedTransaction: SelectOption | null
 | 
			
		||||
  selectedAccount: SelectOption | null
 | 
			
		||||
  selectedDestAccount: SelectOption | null
 | 
			
		||||
  selectedFlags: SelectOption[] | null
 | 
			
		||||
  hookParameters: HookParameters
 | 
			
		||||
  memos: Memos
 | 
			
		||||
@@ -51,7 +50,6 @@ export type TxFields = Omit<
 | 
			
		||||
export const defaultTransaction: TransactionState = {
 | 
			
		||||
  selectedTransaction: null,
 | 
			
		||||
  selectedAccount: null,
 | 
			
		||||
  selectedDestAccount: null,
 | 
			
		||||
  selectedFlags: null,
 | 
			
		||||
  hookParameters: {},
 | 
			
		||||
  memos: {},
 | 
			
		||||
@@ -131,7 +129,6 @@ export const modifyTxState = (
 | 
			
		||||
  return tx.state
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// state to tx options
 | 
			
		||||
export const prepareTransaction = (data: any) => {
 | 
			
		||||
  let options = { ...data }
 | 
			
		||||
 | 
			
		||||
@@ -143,10 +140,9 @@ export const prepareTransaction = (data: any) => {
 | 
			
		||||
      if (_value.$value) {
 | 
			
		||||
        options[field] = (+(_value as any).$value * 1000000 + '')
 | 
			
		||||
      } else {
 | 
			
		||||
        options[field] = undefined
 | 
			
		||||
        options[field] = ""
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // amount.token
 | 
			
		||||
    if (_value.$type === 'amount.token') {
 | 
			
		||||
      if (typeIs(_value.$value, 'string')) {
 | 
			
		||||
@@ -157,7 +153,10 @@ export const prepareTransaction = (data: any) => {
 | 
			
		||||
        options[field] = undefined
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // account
 | 
			
		||||
    if (_value.$type === 'account') {
 | 
			
		||||
      options[field] = (_value.$value as any)?.toString() || ""
 | 
			
		||||
    }
 | 
			
		||||
    // json
 | 
			
		||||
    if (_value.$type === 'json') {
 | 
			
		||||
      const val = _value.$value;
 | 
			
		||||
@@ -172,17 +171,9 @@ export const prepareTransaction = (data: any) => {
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  // delete unnecessary fields
 | 
			
		||||
  Object.keys(options).forEach(field => {
 | 
			
		||||
    if (!options[field]) {
 | 
			
		||||
      delete options[field]
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  return options
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// editor value to state
 | 
			
		||||
export const prepareState = (value: string, transactionType?: string) => {
 | 
			
		||||
  const options = parseJSON(value)
 | 
			
		||||
  if (!options) {
 | 
			
		||||
@@ -192,7 +183,7 @@ export const prepareState = (value: string, transactionType?: string) => {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const { Account, TransactionType, Destination, HookParameters, Memos, ...rest } = options
 | 
			
		||||
  const { Account, TransactionType, HookParameters, Memos, ...rest } = options
 | 
			
		||||
  let tx: Partial<TransactionState> = {}
 | 
			
		||||
  const schema = getTxFields(transactionType)
 | 
			
		||||
 | 
			
		||||
@@ -238,24 +229,6 @@ export const prepareState = (value: string, transactionType?: string) => {
 | 
			
		||||
    }, {})
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (schema.Destination !== undefined) {
 | 
			
		||||
    const dest = state.accounts.find(acc => acc.address === Destination)
 | 
			
		||||
    if (dest) {
 | 
			
		||||
      tx.selectedDestAccount = {
 | 
			
		||||
        label: dest.name,
 | 
			
		||||
        value: dest.address
 | 
			
		||||
      }
 | 
			
		||||
    } else if (Destination) {
 | 
			
		||||
      tx.selectedDestAccount = {
 | 
			
		||||
        label: Destination,
 | 
			
		||||
        value: Destination
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      tx.selectedDestAccount = null
 | 
			
		||||
    }
 | 
			
		||||
  } else if (Destination) {
 | 
			
		||||
    rest.Destination = Destination
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (getFlags(TransactionType) && rest.Flags) {
 | 
			
		||||
    const flags = extractFlags(TransactionType, rest.Flags)
 | 
			
		||||
@@ -271,19 +244,27 @@ export const prepareState = (value: string, transactionType?: string) => {
 | 
			
		||||
    const isAmount = schemaVal &&
 | 
			
		||||
      typeIs(schemaVal, "object") &&
 | 
			
		||||
      schemaVal.$type.startsWith('amount.');
 | 
			
		||||
    const isAccount = schemaVal &&
 | 
			
		||||
      typeIs(schemaVal, "object") &&
 | 
			
		||||
      schemaVal.$type.startsWith("account");
 | 
			
		||||
 | 
			
		||||
    if (isAmount && ["number", "string"].includes(typeof value)) {
 | 
			
		||||
      rest[field] = {
 | 
			
		||||
        $type: 'amount.xrp', // Maybe have $type map or something
 | 
			
		||||
        $type: 'amount.xrp', // TODO narrow typed $type.
 | 
			
		||||
        $value: +value / 1000000 // ! maybe use bigint?
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if (isAmount && typeof value === 'object') {
 | 
			
		||||
    } else if (isAmount && typeof value === 'object') {
 | 
			
		||||
      rest[field] = {
 | 
			
		||||
        $type: 'amount.token',
 | 
			
		||||
        $value: value
 | 
			
		||||
      }
 | 
			
		||||
    } else if (typeof value === 'object') {
 | 
			
		||||
    } else if (isAccount) {
 | 
			
		||||
      rest[field] = {
 | 
			
		||||
        $type: "account",
 | 
			
		||||
        $value: value?.toString() || ""
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if (typeof value === 'object') {
 | 
			
		||||
      rest[field] = {
 | 
			
		||||
        $type: 'json',
 | 
			
		||||
        $value: value
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user