Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/components/Send/Send.js
import React, { useState, useEffect } from 'react'; | import React, { useState, useEffect } from 'react'; | ||||
import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||
import { WalletContext } from '@utils/context'; | import { WalletContext } from '@utils/context'; | ||||
import { Form, notification, message, Modal, Alert } from 'antd'; | import { Form, message, Modal, Alert } from 'antd'; | ||||
import { Row, Col } from 'antd'; | import { Row, Col } from 'antd'; | ||||
import Paragraph from 'antd/lib/typography/Paragraph'; | |||||
import PrimaryButton, { | import PrimaryButton, { | ||||
SecondaryButton, | SecondaryButton, | ||||
} from '@components/Common/PrimaryButton'; | } from '@components/Common/PrimaryButton'; | ||||
import { | import { | ||||
SendBchInput, | SendBchInput, | ||||
FormItemWithQRCodeAddon, | FormItemWithQRCodeAddon, | ||||
} from '@components/Common/EnhancedInputs'; | } from '@components/Common/EnhancedInputs'; | ||||
import useBCH from '@hooks/useBCH'; | import useBCH from '@hooks/useBCH'; | ||||
import useWindowDimensions from '@hooks/useWindowDimensions'; | import useWindowDimensions from '@hooks/useWindowDimensions'; | ||||
import { | |||||
sendXecNotification, | |||||
errorNotification, | |||||
} from '@components/Common/Notifications'; | |||||
import { isMobile, isIOS, isSafari } from 'react-device-detect'; | import { isMobile, isIOS, isSafari } from 'react-device-detect'; | ||||
import { | import { | ||||
currency, | currency, | ||||
isValidTokenPrefix, | isValidTokenPrefix, | ||||
parseAddress, | parseAddress, | ||||
toLegacy, | toLegacy, | ||||
} from '@components/Common/Ticker.js'; | } from '@components/Common/Ticker.js'; | ||||
import { Event } from '@utils/GoogleAnalytics'; | import { Event } from '@utils/GoogleAnalytics'; | ||||
import { fiatToCrypto, shouldRejectAmountInput } from '@utils/validation'; | import { fiatToCrypto, shouldRejectAmountInput } from '@utils/validation'; | ||||
import BalanceHeader from '@components/Common/BalanceHeader'; | import BalanceHeader from '@components/Common/BalanceHeader'; | ||||
import BalanceHeaderFiat from '@components/Common/BalanceHeaderFiat'; | import BalanceHeaderFiat from '@components/Common/BalanceHeaderFiat'; | ||||
import { | import { | ||||
ZeroBalanceHeader, | ZeroBalanceHeader, | ||||
ConvertAmount, | ConvertAmount, | ||||
AlertMsg, | AlertMsg, | ||||
} from '@components/Common/Atoms'; | } from '@components/Common/Atoms'; | ||||
import { getWalletState } from '@utils/cashMethods'; | import { getWalletState } from '@utils/cashMethods'; | ||||
import { CashReceivedNotificationIcon } from '@components/Common/CustomIcons'; | |||||
import ApiError from '@components/Common/ApiError'; | import ApiError from '@components/Common/ApiError'; | ||||
// Note jestBCH is only used for unit tests; BCHJS must be mocked for jest | // Note jestBCH is only used for unit tests; BCHJS must be mocked for jest | ||||
const SendBCH = ({ jestBCH, passLoadingStatus }) => { | const SendBCH = ({ jestBCH, passLoadingStatus }) => { | ||||
// use balance parameters from wallet.state object and not legacy balances parameter from walletState, if user has migrated wallet | // use balance parameters from wallet.state object and not legacy balances parameter from walletState, if user has migrated wallet | ||||
// this handles edge case of user with old wallet who has not opened latest Cashtab version yet | // this handles edge case of user with old wallet who has not opened latest Cashtab version yet | ||||
// If the wallet object from ContextValue has a `state key`, then check which keys are in the wallet object | // If the wallet object from ContextValue has a `state key`, then check which keys are in the wallet object | ||||
▲ Show 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | async function submit() { | ||||
const link = await sendBch( | const link = await sendBch( | ||||
BCH, | BCH, | ||||
wallet, | wallet, | ||||
slpBalancesAndUtxos.nonSlpUtxos, | slpBalancesAndUtxos.nonSlpUtxos, | ||||
cleanAddress, | cleanAddress, | ||||
bchValue, | bchValue, | ||||
currency.defaultFee, | currency.defaultFee, | ||||
); | ); | ||||
sendXecNotification(link); | |||||
notification.success({ | |||||
message: 'Success', | |||||
description: ( | |||||
<a href={link} target="_blank" rel="noopener noreferrer"> | |||||
<Paragraph> | |||||
Transaction successful. Click to view in block | |||||
explorer. | |||||
</Paragraph> | |||||
</a> | |||||
), | |||||
duration: 3, | |||||
icon: <CashReceivedNotificationIcon />, | |||||
style: { width: '100%' }, | |||||
}); | |||||
} catch (e) { | } catch (e) { | ||||
// Set loading to false here as well, as balance may not change depending on where error occured in try loop | // Set loading to false here as well, as balance may not change depending on where error occured in try loop | ||||
passLoadingStatus(false); | passLoadingStatus(false); | ||||
let message; | let message; | ||||
if (!e.error && !e.message) { | if (!e.error && !e.message) { | ||||
message = `Transaction failed: no response from ${getRestUrl()}.`; | message = `Transaction failed: no response from ${getRestUrl()}.`; | ||||
} else if ( | } else if ( | ||||
/Could not communicate with full node or other external service/.test( | /Could not communicate with full node or other external service/.test( | ||||
e.error, | e.error, | ||||
) | ) | ||||
) { | ) { | ||||
message = 'Could not communicate with API. Please try again.'; | message = 'Could not communicate with API. Please try again.'; | ||||
} else if ( | } else if ( | ||||
e.error && | e.error && | ||||
e.error.includes( | e.error.includes( | ||||
'too-long-mempool-chain, too many unconfirmed ancestors [limit: 50] (code 64)', | 'too-long-mempool-chain, too many unconfirmed ancestors [limit: 50] (code 64)', | ||||
) | ) | ||||
) { | ) { | ||||
message = `The ${currency.ticker} you are trying to send has too many unconfirmed ancestors to send (limit 50). Sending will be possible after a block confirmation. Try again in about 10 minutes.`; | message = `The ${currency.ticker} you are trying to send has too many unconfirmed ancestors to send (limit 50). Sending will be possible after a block confirmation. Try again in about 10 minutes.`; | ||||
} else { | } else { | ||||
message = e.message || e.error || JSON.stringify(e); | message = e.message || e.error || JSON.stringify(e); | ||||
} | } | ||||
notification.error({ | errorNotification(e, message, 'Sending XEC'); | ||||
message: 'Error', | |||||
description: message, | |||||
duration: 5, | |||||
}); | |||||
console.error(e); | |||||
} | } | ||||
} | } | ||||
const handleAddressChange = e => { | const handleAddressChange = e => { | ||||
const { value, name } = e.target; | const { value, name } = e.target; | ||||
let error = false; | let error = false; | ||||
let addressString = value; | let addressString = value; | ||||
▲ Show 20 Lines • Show All 293 Lines • Show Last 20 Lines |