From 80fa5af430da2f60afdde91d3327142d03d83384 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Wed, 8 Feb 2023 11:28:38 -0500 Subject: [PATCH] wip --- .storybook/storybook.requires.js | 12 +- src/AppNavigator.tsx | 3 + src/Send/AddressReaderQR/index.ts | 1 - .../AssetSelectorScreen.stories.tsx | 17 -- src/Send/AssetSelectorScreen/index.tsx | 1 - src/Send/ConfirmScreen/index.ts | 1 - src/Send/Context/SendContext.tsx | 144 ---------- src/Send/SendScreen/AvailableAmountBanner.tsx | 25 -- .../SendScreen/BalanceAfterTransaction.tsx | 55 ---- src/Send/SendScreen/Fee.tsx | 45 --- src/Send/SendScreen/SendAllWarning.tsx | 50 ---- src/Send/SendScreen/SendScreen.stories.tsx | 30 -- src/Send/SendScreen/SendScreen.tsx | 263 ------------------ src/Send/SendScreen/index.ts | 1 - src/Send/{ => shared}/AmountField.tsx | 4 +- src/Send/{ => shared}/ScannerButton.tsx | 16 +- src/Send/shared/SendContext.tsx | 213 ++++++++++++++ src/Send/shared/hooks.ts | 47 ++++ src/Send/{SendScreen => shared}/strings.ts | 41 ++- src/Send/{SendScreen => shared}/utils.ts | 47 +--- .../ConfirmTx/ConfirmTxScreen.stories.tsx} | 14 +- .../ConfirmTx/ConfirmTxScreen.tsx} | 46 +-- src/Send/useCases/ConfirmTx/index.ts | 1 + .../AddToken/AddToken.stories.tsx | 12 + .../ListSelectedTokens/AddToken/AddToken.tsx | 57 ++++ .../AddToken/InputSearch.tsx | 25 ++ .../SelectTokenFromListScreen.stories.tsx | 17 ++ .../AddToken/SelectTokenScreen.tsx} | 97 +++---- .../DeleteToken.stories.tsx | 47 ++++ .../ListSelectedTokens/DeleteToken.tsx | 47 ++++ .../EditAmountScreen.stories.tsx | 89 ++++++ .../ListSelectedTokens/EditAmountScreen.tsx | 158 +++++++++++ .../ListSelectedTokensScreen.stories.tsx | 26 ++ .../ListSelectedTokensScreen.tsx | 136 +++++++++ .../useCases/ListSelectedTokens/index.tsx | 2 + .../StartTx/InputMemo.tsx} | 4 +- .../StartTx/InputReceiver/InputReceiver.tsx | 31 +++ .../ReadQRCodeScreen.stories.tsx} | 11 +- .../InputReceiver/ReadQRCodeScreen.tsx} | 10 +- .../StartTx/InputReceiver/ResolveAddress.tsx | 114 ++++++++ .../StartTx/ShowErrors.tsx} | 10 +- .../StartTx/StartTxScreen.stories.tsx | 30 ++ src/Send/useCases/StartTx/StartTxScreen.tsx | 107 +++++++ src/TxHistory/ActionsBanner.tsx | 4 +- src/TxHistory/AssetList/AssetList.tsx | 6 +- src/TxHistory/PairedBalance.tsx | 5 +- src/TxHistory/TxHistory.stories.tsx | 17 +- src/TxHistory/TxHistoryNavigator.tsx | 85 ++++-- .../AssetItem/AssetItem.stories.tsx | 8 +- src/components/AssetItem/AssetItem.tsx | 10 +- src/components/TextInput/TextInput.tsx | 6 +- src/i18n/global-messages.ts | 8 + src/i18n/locales/en-US.json | 8 + src/navigation.ts | 10 +- src/yoroi-wallets/cardano/api/utils.ts | 2 +- src/yoroi-wallets/hooks/index.ts | 2 - src/yoroi-wallets/mocks/wallet.ts | 45 +++ src/yoroi-wallets/utils/amountUtils.test.ts | 8 - src/yoroi-wallets/utils/amountUtils.ts | 2 - src/yoroi-wallets/utils/utils.test.ts | 65 ++++- src/yoroi-wallets/utils/utils.ts | 24 ++ src/yoroi-wallets/utils/validators.ts | 50 +--- 62 files changed, 1555 insertions(+), 917 deletions(-) delete mode 100644 src/Send/AddressReaderQR/index.ts delete mode 100644 src/Send/AssetSelectorScreen/AssetSelectorScreen.stories.tsx delete mode 100644 src/Send/AssetSelectorScreen/index.tsx delete mode 100644 src/Send/ConfirmScreen/index.ts delete mode 100644 src/Send/Context/SendContext.tsx delete mode 100644 src/Send/SendScreen/AvailableAmountBanner.tsx delete mode 100644 src/Send/SendScreen/BalanceAfterTransaction.tsx delete mode 100644 src/Send/SendScreen/Fee.tsx delete mode 100644 src/Send/SendScreen/SendAllWarning.tsx delete mode 100644 src/Send/SendScreen/SendScreen.stories.tsx delete mode 100644 src/Send/SendScreen/SendScreen.tsx delete mode 100644 src/Send/SendScreen/index.ts rename src/Send/{ => shared}/AmountField.tsx (90%) rename src/Send/{ => shared}/ScannerButton.tsx (56%) create mode 100644 src/Send/shared/SendContext.tsx create mode 100644 src/Send/shared/hooks.ts rename src/Send/{SendScreen => shared}/strings.ts (86%) rename src/Send/{SendScreen => shared}/utils.ts (76%) rename src/Send/{ConfirmScreen/ConfirmScreen.stories.tsx => useCases/ConfirmTx/ConfirmTxScreen.stories.tsx} (58%) rename src/Send/{ConfirmScreen/ConfirmScreen.tsx => useCases/ConfirmTx/ConfirmTxScreen.tsx} (86%) create mode 100644 src/Send/useCases/ConfirmTx/index.ts create mode 100644 src/Send/useCases/ListSelectedTokens/AddToken/AddToken.stories.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/AddToken/AddToken.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/AddToken/InputSearch.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/AddToken/SelectTokenFromListScreen.stories.tsx rename src/Send/{AssetSelectorScreen/AssetSelectorScreen.tsx => useCases/ListSelectedTokens/AddToken/SelectTokenScreen.tsx} (56%) create mode 100644 src/Send/useCases/ListSelectedTokens/DeleteToken.stories.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/DeleteToken.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/EditAmountScreen.stories.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/EditAmountScreen.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/ListSelectedTokensScreen.stories.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/ListSelectedTokensScreen.tsx create mode 100644 src/Send/useCases/ListSelectedTokens/index.tsx rename src/Send/{Memo.tsx => useCases/StartTx/InputMemo.tsx} (94%) create mode 100644 src/Send/useCases/StartTx/InputReceiver/InputReceiver.tsx rename src/Send/{AddressReaderQR/AddressReaderQR.stories.tsx => useCases/StartTx/InputReceiver/ReadQRCodeScreen.stories.tsx} (54%) rename src/Send/{AddressReaderQR/AddressReaderQR.tsx => useCases/StartTx/InputReceiver/ReadQRCodeScreen.tsx} (82%) create mode 100644 src/Send/useCases/StartTx/InputReceiver/ResolveAddress.tsx rename src/Send/{SendScreen/ErrorBanners.tsx => useCases/StartTx/ShowErrors.tsx} (63%) create mode 100644 src/Send/useCases/StartTx/StartTxScreen.stories.tsx create mode 100644 src/Send/useCases/StartTx/StartTxScreen.tsx diff --git a/.storybook/storybook.requires.js b/.storybook/storybook.requires.js index d0b73c2708..5c3554576f 100644 --- a/.storybook/storybook.requires.js +++ b/.storybook/storybook.requires.js @@ -111,10 +111,14 @@ const getStories = () => { "./src/Receive/ReceiveScreen.stories.tsx": require("../src/Receive/ReceiveScreen.stories.tsx"), "./src/Search/SearchBar.stories.tsx": require("../src/Search/SearchBar.stories.tsx"), "./src/SelectedWallet/WalletSelection/WalletSelectionScreen.stories.tsx": require("../src/SelectedWallet/WalletSelection/WalletSelectionScreen.stories.tsx"), - "./src/Send/AddressReaderQR/AddressReaderQR.stories.tsx": require("../src/Send/AddressReaderQR/AddressReaderQR.stories.tsx"), - "./src/Send/AssetSelectorScreen/AssetSelectorScreen.stories.tsx": require("../src/Send/AssetSelectorScreen/AssetSelectorScreen.stories.tsx"), - "./src/Send/ConfirmScreen/ConfirmScreen.stories.tsx": require("../src/Send/ConfirmScreen/ConfirmScreen.stories.tsx"), - "./src/Send/SendScreen/SendScreen.stories.tsx": require("../src/Send/SendScreen/SendScreen.stories.tsx"), + "./src/Send/useCases/ConfirmTx/ConfirmTxScreen.stories.tsx": require("../src/Send/useCases/ConfirmTx/ConfirmTxScreen.stories.tsx"), + "./src/Send/useCases/ListSelectedTokens/AddToken/AddToken.stories.tsx": require("../src/Send/useCases/ListSelectedTokens/AddToken/AddToken.stories.tsx"), + "./src/Send/useCases/ListSelectedTokens/AddToken/SelectTokenFromListScreen.stories.tsx": require("../src/Send/useCases/ListSelectedTokens/AddToken/SelectTokenFromListScreen.stories.tsx"), + "./src/Send/useCases/ListSelectedTokens/DeleteToken.stories.tsx": require("../src/Send/useCases/ListSelectedTokens/DeleteToken.stories.tsx"), + "./src/Send/useCases/ListSelectedTokens/EditAmountScreen.stories.tsx": require("../src/Send/useCases/ListSelectedTokens/EditAmountScreen.stories.tsx"), + "./src/Send/useCases/ListSelectedTokens/ListSelectedTokensScreen.stories.tsx": require("../src/Send/useCases/ListSelectedTokens/ListSelectedTokensScreen.stories.tsx"), + "./src/Send/useCases/StartTx/InputReceiver/ReadQRCodeScreen.stories.tsx": require("../src/Send/useCases/StartTx/InputReceiver/ReadQRCodeScreen.stories.tsx"), + "./src/Send/useCases/StartTx/StartTxScreen.stories.tsx": require("../src/Send/useCases/StartTx/StartTxScreen.stories.tsx"), "./src/Settings/ApplicationSettings/ApplicationSettingsScreen.stories.tsx": require("../src/Settings/ApplicationSettings/ApplicationSettingsScreen.stories.tsx"), "./src/Settings/ChangeLanguage/ChangeLanguageScreen.stories.tsx": require("../src/Settings/ChangeLanguage/ChangeLanguageScreen.stories.tsx"), "./src/Settings/ChangePassword/ChangePasswordScreen.stories.tsx": require("../src/Settings/ChangePassword/ChangePasswordScreen.stories.tsx"), diff --git a/src/AppNavigator.tsx b/src/AppNavigator.tsx index 31e663d29a..e8dc9a1c74 100644 --- a/src/AppNavigator.tsx +++ b/src/AppNavigator.tsx @@ -43,6 +43,9 @@ export const AppNavigator = () => { } } + // RNBootSplash.hide({fade: true}) + // return + return ( { - return ( - - - - - - ) -}) diff --git a/src/Send/AssetSelectorScreen/index.tsx b/src/Send/AssetSelectorScreen/index.tsx deleted file mode 100644 index 64c8cdf31f..0000000000 --- a/src/Send/AssetSelectorScreen/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export * from './AssetSelectorScreen' diff --git a/src/Send/ConfirmScreen/index.ts b/src/Send/ConfirmScreen/index.ts deleted file mode 100644 index 5d6943c31e..0000000000 --- a/src/Send/ConfirmScreen/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './ConfirmScreen' diff --git a/src/Send/Context/SendContext.tsx b/src/Send/Context/SendContext.tsx deleted file mode 100644 index 374a5e3435..0000000000 --- a/src/Send/Context/SendContext.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import * as React from 'react' - -import {YoroiWallet} from '../../yoroi-wallets' -import {TokenId} from '../../yoroi-wallets/types' - -type SendState = { - tokenId: TokenId - receiver: string - amount: string - sendAll: boolean - memo: string -} - -type SendActions = { - receiverChanged: (receiver: SendState['receiver']) => void - amountChanged: (amount: SendState['amount']) => void - tokenSelected: (tokenId: SendState['tokenId']) => void - memoChanged: (memo: SendState['memo']) => void - sendAllChanged: () => void - allTokensSelected: () => void - resetForm: () => void -} - -const SendContext = React.createContext(undefined) -export const SendProvider = ({ - children, - wallet, - ...props -}: { - wallet: YoroiWallet - initialState?: Partial - children: React.ReactNode -}) => { - const [state, dispatch] = React.useReducer(sendReducer, { - ...initialState(wallet.primaryToken.identifier), - ...props.initialState, - }) - - const actions = React.useRef({ - receiverChanged: (receiver) => dispatch({type: 'receiverChanged', receiver}), - amountChanged: (amount) => dispatch({type: 'amountChanged', amount}), - tokenSelected: (tokenId) => dispatch({type: 'tokenSelected', tokenId}), - memoChanged: (memo) => dispatch({type: 'memoChanged', memo}), - sendAllChanged: () => dispatch({type: 'sendAllChanged'}), - allTokensSelected: () => dispatch({type: 'allTokensSelected', primaryTokenId: wallet.primaryTokenInfo.id}), - resetForm: () => dispatch({type: 'resetForm', primaryTokenId: wallet.primaryTokenInfo.id}), - }).current - - const context = React.useMemo(() => ({...state, ...actions}), [actions, state]) - - return {children} -} - -type SendAction = - | { - type: 'receiverChanged' - receiver: string - } - | { - type: 'amountChanged' - amount: string - } - | { - type: 'memoChanged' - memo: SendState['memo'] - } - | { - type: 'sendAllChanged' - } - | { - type: 'allTokensSelected' - primaryTokenId: TokenId - } - | { - type: 'resetForm' - primaryTokenId: TokenId - } - | { - type: 'tokenSelected' - tokenId: SendState['tokenId'] - } - -const sendReducer = (state: SendState, action: SendAction) => { - switch (action.type) { - case 'receiverChanged': - return { - ...state, - receiver: action.receiver, - } - - case 'amountChanged': - return { - ...state, - amount: action.amount, - } - - case 'sendAllChanged': - return { - ...state, - sendAll: !state.sendAll, - } - - case 'tokenSelected': - return { - ...state, - sendAll: false, - tokenId: action.tokenId, - } - - case 'allTokensSelected': - return { - ...state, - sendAll: true, - tokenId: action.primaryTokenId, - } - - case 'memoChanged': - return { - ...state, - memo: action.memo, - } - - case 'resetForm': - return initialState(action.primaryTokenId) - - default: - // eslint-disable-next-line @typescript-eslint/no-explicit-any - throw new Error(`sendReducer: action type ${(action as any).type} not supported`) - } -} - -export const useSend = () => React.useContext(SendContext) || missingProvider() - -const missingProvider = () => { - throw new Error('SendProvider is missing') -} - -const initialState = (primaryTokenId: TokenId) => ({ - tokenId: primaryTokenId, - receiver: '', - amount: '', - sendAll: false, - memo: '', -}) diff --git a/src/Send/SendScreen/AvailableAmountBanner.tsx b/src/Send/SendScreen/AvailableAmountBanner.tsx deleted file mode 100644 index 77662c6a06..0000000000 --- a/src/Send/SendScreen/AvailableAmountBanner.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react' - -import {Banner} from '../../components' -import {formatTokenWithText} from '../../legacy/format' -import {useSelectedWallet} from '../../SelectedWallet' -import {useBalances} from '../../yoroi-wallets' -import {Amounts} from '../../yoroi-wallets/utils' -import {useStrings} from './strings' - -export const AvailableAmountBanner = () => { - const strings = useStrings() - const wallet = useSelectedWallet() - const balances = useBalances(wallet) - - return ( - - ) -} diff --git a/src/Send/SendScreen/BalanceAfterTransaction.tsx b/src/Send/SendScreen/BalanceAfterTransaction.tsx deleted file mode 100644 index 2751e1cf5c..0000000000 --- a/src/Send/SendScreen/BalanceAfterTransaction.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from 'react' -import {StyleSheet} from 'react-native' - -import {Text} from '../../components' -import {formatTokenWithSymbol} from '../../legacy/format' -import {useSelectedWallet} from '../../SelectedWallet' -import {useBalances} from '../../yoroi-wallets' -import {YoroiUnsignedTx} from '../../yoroi-wallets/types' -import {Amounts} from '../../yoroi-wallets/utils' -import {useStrings} from './strings' - -export const BalanceAfterTransaction = ({yoroiUnsignedTx}: {yoroiUnsignedTx: YoroiUnsignedTx | null}) => { - const strings = useStrings() - const wallet = useSelectedWallet() - const balances = useBalances(wallet) - - if (!yoroiUnsignedTx) { - return ( - - {strings.balanceAfterLabel} - - {': '} - - {strings.balanceAfterNotAvailable} - - ) - } - - // prettier-ignore - const balancesAfter = Amounts.diff( - balances, - Amounts.sum([ - yoroiUnsignedTx.amounts, - yoroiUnsignedTx.fee, - ]), - ) - const primaryAmountAfter = Amounts.getAmount(balancesAfter, wallet.primaryToken.identifier) - - return ( - - {strings.balanceAfterLabel} - - {': '} - - {formatTokenWithSymbol(primaryAmountAfter.quantity, wallet.primaryToken)} - - ) -} - -const styles = StyleSheet.create({ - info: { - fontSize: 14, - lineHeight: 22, - }, -}) diff --git a/src/Send/SendScreen/Fee.tsx b/src/Send/SendScreen/Fee.tsx deleted file mode 100644 index a881ccbc2c..0000000000 --- a/src/Send/SendScreen/Fee.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react' -import {StyleSheet} from 'react-native' - -import {Text} from '../../components' -import {formatTokenWithSymbol} from '../../legacy/format' -import {useSelectedWallet} from '../../SelectedWallet' -import {YoroiUnsignedTx} from '../../yoroi-wallets/types' -import {Amounts} from '../../yoroi-wallets/utils' -import {useStrings} from './strings' - -export const Fee = ({yoroiUnsignedTx}: {yoroiUnsignedTx: YoroiUnsignedTx | null}) => { - const strings = useStrings() - const wallet = useSelectedWallet() - - if (yoroiUnsignedTx == null) { - return ( - - {strings.feeLabel} - - {': '} - - {strings.feeNotAvailable} - - ) - } - - const primaryAmount = Amounts.getAmount(yoroiUnsignedTx.fee, wallet.primaryToken.identifier) - - return ( - - {strings.feeLabel} - - {': '} - - {formatTokenWithSymbol(primaryAmount.quantity, wallet.primaryToken)} - - ) -} - -const styles = StyleSheet.create({ - info: { - fontSize: 14, - lineHeight: 22, - }, -}) diff --git a/src/Send/SendScreen/SendAllWarning.tsx b/src/Send/SendScreen/SendAllWarning.tsx deleted file mode 100644 index f988cce167..0000000000 --- a/src/Send/SendScreen/SendAllWarning.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react' - -import {DangerousActionModal, Text} from '../../components' -import {truncateWithEllipsis} from '../../legacy/format' -import {useSelectedWallet} from '../../SelectedWallet' -import {useTokenInfo} from '../../yoroi-wallets' -import {useStrings} from './strings' - -type SendAllWarningProps = { - selectedTokenIdentifier: string - onConfirm: () => void - onCancel: () => void - showSendAllWarning: boolean -} -export const SendAllWarning = ({ - showSendAllWarning, - selectedTokenIdentifier, - onCancel, - onConfirm, -}: SendAllWarningProps) => { - const strings = useStrings() - const wallet = useSelectedWallet() - const tokenInfo = useTokenInfo({wallet, tokenId: selectedTokenIdentifier}) - const isPrimaryToken = tokenInfo.id === wallet.primaryTokenInfo.id - const assetNameOrId = truncateWithEllipsis(tokenInfo.ticker ?? tokenInfo.name ?? tokenInfo.fingerprint, 20) - const alertBoxContent = { - content: isPrimaryToken - ? [strings.sendAllWarningAlert1({assetNameOrId}), strings.sendAllWarningAlert2, strings.sendAllWarningAlert3] - : [strings.sendAllWarningAlert1({assetNameOrId})], - } - return ( - - {strings.sendAllWarningText} - - ) -} diff --git a/src/Send/SendScreen/SendScreen.stories.tsx b/src/Send/SendScreen/SendScreen.stories.tsx deleted file mode 100644 index 869d584eec..0000000000 --- a/src/Send/SendScreen/SendScreen.stories.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import {storiesOf} from '@storybook/react-native' -import * as React from 'react' - -import {QueryProvider} from '../../../.storybook/decorators' -import {Boundary} from '../../components' -import {SelectedWalletProvider} from '../../SelectedWallet' -import {YoroiWallet} from '../../yoroi-wallets' -import {mocks} from '../../yoroi-wallets/mocks' -import {SendProvider} from '../Context/SendContext' -import {SendScreen} from './SendScreen' - -storiesOf('SendScreen', module) - .add('Default', () => ) - .add('SendAll', () => ) - -const SendScreenTest = ({isSendAll}: {isSendAll?: boolean}) => { - const wallet: YoroiWallet = mocks.wallet - - return ( - - - - - - - - - - ) -} diff --git a/src/Send/SendScreen/SendScreen.tsx b/src/Send/SendScreen/SendScreen.tsx deleted file mode 100644 index 0793edd592..0000000000 --- a/src/Send/SendScreen/SendScreen.tsx +++ /dev/null @@ -1,263 +0,0 @@ -import {useNavigation} from '@react-navigation/native' -import _ from 'lodash' -import React from 'react' -import {useIntl} from 'react-intl' -import {ActivityIndicator, Image, ScrollView, StyleSheet, View} from 'react-native' -import {TouchableOpacity} from 'react-native-gesture-handler' -import {SafeAreaView} from 'react-native-safe-area-context' - -import {Button, Checkbox, Spacer, StatusBar, Text, TextInput} from '../../components' -import {debugWalletInfo, features} from '../../features' -import {formatTokenAmount, truncateWithEllipsis} from '../../legacy/format' -import {useSelectedWallet} from '../../SelectedWallet' -import {COLORS} from '../../theme' -import {toToken, useBalances, useHasPendingTx, useIsOnline, useTokenInfo, useUtxos} from '../../yoroi-wallets' -import {YoroiUnsignedTx} from '../../yoroi-wallets/types' -import {Amounts, Quantities} from '../../yoroi-wallets/utils' -import type { - AddressValidationErrors, - AmountValidationErrors, - BalanceValidationErrors, -} from '../../yoroi-wallets/utils/validators' -import {useSend} from '../Context/SendContext' -import {maxMemoLength, MemoInput} from '../Memo' -import {ScannerButton} from '../ScannerButton' -import {AmountField} from './../AmountField' -import {AvailableAmountBanner} from './AvailableAmountBanner' -import {BalanceAfterTransaction} from './BalanceAfterTransaction' -import {ErrorBanners} from './ErrorBanners' -import {Fee} from './Fee' -import {SendAllWarning} from './SendAllWarning' -import {useStrings} from './strings' -import {getAddressErrorText, getAmountErrorText, hasDomainErrors, isDomain, recomputeAll} from './utils' - -export const SendScreen = () => { - const intl = useIntl() - const strings = useStrings() - const navigation = useNavigation() - const wallet = useSelectedWallet() - const balances = useBalances(wallet) - - const utxos = useUtxos(wallet) - const hasPendingTx = useHasPendingTx(wallet) - const isOnline = useIsOnline(wallet) - - const { - tokenId, - resetForm, - receiverChanged, - amountChanged, - receiver, - amount, - sendAll, - sendAllChanged, - memo, - memoChanged, - } = useSend() - - const selectedAssetAvailableAmount = Amounts.getAmount(balances, tokenId).quantity - const defaultAssetAvailableAmount = Amounts.getAmount(balances, wallet.primaryToken.identifier).quantity - - React.useEffect(() => { - if (wallet.primaryToken.identifier !== tokenId && !Quantities.isGreaterThan(selectedAssetAvailableAmount, '0')) { - resetForm() - } - }, [wallet.primaryToken.identifier, tokenId, resetForm, selectedAssetAvailableAmount]) - - const [address, setAddress] = React.useState('') - const [addressErrors, setAddressErrors] = React.useState({addressIsRequired: true}) - const [amountErrors, setAmountErrors] = React.useState({amountIsRequired: true}) - const [balanceErrors, setBalanceErrors] = React.useState({}) - const [yoroiUnsignedTx, setYoroiUnsignedTx] = React.useState(null) - const [recomputing, setRecomputing] = React.useState(false) - const [showSendAllWarning, setShowSendAllWarning] = React.useState(false) - - const tokenInfo = useTokenInfo({wallet, tokenId}) - const isPrimaryToken = tokenInfo.id === wallet.primaryTokenInfo.id - const token = toToken({wallet, tokenInfo}) - const assetDenomination = truncateWithEllipsis(tokenInfo.ticker ?? tokenInfo.name ?? tokenInfo.fingerprint, 20) - const amountErrorText = getAmountErrorText(intl, amountErrors, balanceErrors, wallet.primaryToken) - - const isValid = - isOnline && - !hasPendingTx && - _.isEmpty(addressErrors) && - _.isEmpty(amountErrors) && - _.isEmpty(balanceErrors) && - !!yoroiUnsignedTx && - memo.length <= maxMemoLength - - React.useEffect(() => { - if (features.prefillWalletInfo) { - if (!__DEV__) throw new Error('using debug data in non-dev env') - receiverChanged(debugWalletInfo.SEND_ADDRESS) - amountChanged(debugWalletInfo.SEND_AMOUNT) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - const promiseRef = React.useRef>() - React.useEffect(() => { - setYoroiUnsignedTx(null) - setBalanceErrors({}) - setAmountErrors({}) - setRecomputing(true) - - const promise = recomputeAll({ - wallet, - utxos, - addressInput: receiver, - amount, - sendAll, - selectedToken: token, - defaultAssetAvailableAmount, - selectedAssetAvailableAmount, - }) - - promiseRef.current = promise - - promise.then((newState) => { - if (promise !== promiseRef.current) return // abort if newer promise - - setAddress(newState.address) - setAddressErrors(newState.addressErrors) - amountChanged(newState.amount) - setAmountErrors(newState.amountErrors) - setBalanceErrors(newState.balanceErrors) - setYoroiUnsignedTx(newState.yoroiUnsignedTx) - setRecomputing(false) - }) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [receiver, amount, tokenId, sendAll]) - - const onConfirm = () => { - if (sendAll) { - setShowSendAllWarning(true) - return - } - handleConfirm() - } - - const handleConfirm = () => { - if (isValid == false || recomputing || yoroiUnsignedTx == null) return - - setShowSendAllWarning(false) - - navigation.navigate('app-root', { - screen: 'main-wallet-routes', - params: { - screen: 'history', - params: { - screen: 'send-confirm', - params: {yoroiUnsignedTx}, - }, - }, - }) - } - - return ( - - - - - - - - - - - - - - - } - multiline - errorOnMount - onChangeText={receiverChanged} - label={strings.addressInputLabel} - errorText={getAddressErrorText(intl, addressErrors)} - autoComplete={false} - testID="addressInput" - /> - - {!recomputing && - isDomain(receiver) && - !hasDomainErrors(addressErrors) && - !receiver.includes(address) /* HACK */ && ( - - {`Resolves to: ${address}`} - - )} - - - - { - navigation.navigate('app-root', { - screen: 'main-wallet-routes', - params: { - screen: 'history', - params: { - screen: 'select-asset', - }, - }, - }) - }} - > - } - editable={false} - label={strings.asset} - value={`${assetDenomination}: ${formatTokenAmount(selectedAssetAvailableAmount, token)}`} - autoComplete={false} - /> - - - - - - - {recomputing && ( - - - - )} - - - -