Skip to content

Commit

Permalink
feat: parse amounts on QR scan with regular send button (shapeshift#4461
Browse files Browse the repository at this point in the history
)
  • Loading branch information
gomesalexandre authored May 9, 2023
1 parent 9452461 commit 600784e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 15 deletions.
19 changes: 16 additions & 3 deletions src/components/Modals/Send/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import { FormProvider, useForm } from 'react-hook-form'
import { Redirect, Route, Switch, useHistory, useLocation } from 'react-router-dom'
import { QrCodeScanner } from 'components/QrCodeScanner/QrCodeScanner'
import { SelectAssetRouter } from 'components/SelectAssets/SelectAssetRouter'
import { selectSelectedCurrency } from 'state/slices/selectors'
import { useAppSelector } from 'state/store'
import { parseMaybeUrl } from 'lib/address/address'
import { bnOrZero } from 'lib/bignumber/bignumber'
import { selectMarketDataById, selectSelectedCurrency } from 'state/slices/selectors'
import { store, useAppSelector } from 'state/store'

import { useFormSend } from './hooks/useFormSend/useFormSend'
import { SendFormFields, SendRoutes } from './SendCommon'
Expand Down Expand Up @@ -81,8 +83,19 @@ export const Form: React.FC<SendFormProps> = ({ initialAssetId, accountId }) =>
}, [])

const handleQrSuccess = useCallback(
(decodedText: string) => {
async (decodedText: string) => {
methods.setValue(SendFormFields.Input, decodedText.trim())

const maybeUrlResult = await parseMaybeUrl({ value: decodedText })
if (maybeUrlResult.assetId && maybeUrlResult.amountCryptoPrecision) {
const marketData = selectMarketDataById(store.getState(), maybeUrlResult.assetId ?? '')
methods.setValue(SendFormFields.CryptoAmount, maybeUrlResult.amountCryptoPrecision)
methods.setValue(
SendFormFields.FiatAmount,
bnOrZero(maybeUrlResult.amountCryptoPrecision).times(marketData.price).toString(),
)
}

history.push(SendRoutes.Address)
},
[history, methods],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export const useSendDetails = (): UseSendDetailsReturnType => {
name: SendFormFields.AccountId,
})

const cryptoAmount = useWatch<SendInput, SendFormFields.CryptoAmount>({
name: SendFormFields.CryptoAmount,
})

const price = bnOrZero(useAppSelector(state => selectMarketDataById(state, assetId)).price)

const chainAdapterManager = getChainAdapterManager()
Expand Down Expand Up @@ -113,18 +117,17 @@ export const useSendDetails = (): UseSendDetailsReturnType => {
const estimateFormFees = useCallback((): Promise<FeeDataEstimate<ChainId>> => {
if (!asset) throw new Error('No asset found')

const { cryptoAmount, assetId, to, sendMax, accountId } = getValues()
const { assetId, to, sendMax } = getValues()
if (!wallet) throw new Error('No wallet connected')
return estimateFees({ cryptoAmount, assetId, to, sendMax, accountId, contractAddress })
}, [asset, contractAddress, getValues, wallet])
}, [accountId, asset, contractAddress, cryptoAmount, getValues, wallet])

const debouncedSetEstimatedFormFees = useMemo(() => {
return debounce(
async () => {
if (!asset) return
if (!asset || !accountId) return
const estimatedFees = await estimateFormFees()

const { cryptoAmount } = getValues()
const hasValidBalance = cryptoHumanBalance.gte(cryptoAmount)

if (!hasValidBalance) {
Expand Down Expand Up @@ -173,13 +176,14 @@ export const useSendDetails = (): UseSendDetailsReturnType => {
{ leading: true, trailing: true },
)
}, [
accountId,
asset,
assetId,
cryptoAmount,
cryptoHumanBalance,
estimateFormFees,
feeAsset.assetId,
feeAsset.symbol,
getValues,
nativeAssetBalance,
setValue,
])
Expand Down
9 changes: 6 additions & 3 deletions src/components/Modals/Send/hooks/useSendFees/useSendFees.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { FeePrice } from '../../views/Confirm'
export const useSendFees = () => {
const [fees, setFees] = useState<FeePrice | null>(null)
const { control } = useFormContext()
const { assetId, estimatedFees } = useWatch({
const { assetId, estimatedFees, cryptoAmount } = useWatch({
control,
})
const feeAssetId = getChainAdapterManager().get(fromAssetId(assetId).chainId)?.getFeeAssetId()
Expand Down Expand Up @@ -59,9 +59,12 @@ export const useSendFees = () => {
)
setFees(txFees)
}
// We only want this effect to run on mount or when the estimatedFees in state change
// We only want this effect to run on
// - mount
// - when the estimatedFees reference invalidates
// - when cryptoAmount reference invalidates, since this wouldn't invalidate in the context of QR codes with amounts otherwise
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [estimatedFees, assetId])
}, [estimatedFees, cryptoAmount, assetId])

return { fees }
}
16 changes: 12 additions & 4 deletions src/components/Modals/Send/views/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
ModalHeader,
Stack,
Tooltip,
usePrevious,
} from '@chakra-ui/react'
import type { AccountId } from '@shapeshiftoss/caip'
import { fromAssetId } from '@shapeshiftoss/caip'
Expand Down Expand Up @@ -44,7 +45,7 @@ import { SendMaxButton } from '../SendMaxButton/SendMaxButton'
const MAX_COSMOS_SDK_MEMO_LENGTH = 256

export const Details = () => {
const { control, setValue } = useFormContext<SendInput>()
const { control, setValue, trigger } = useFormContext<SendInput>()
const history = useHistory()
const translate = useTranslate()

Expand Down Expand Up @@ -80,11 +81,18 @@ export const Details = () => {
state: { wallet },
} = useWallet()

const previousAccountId = usePrevious(accountId)
useEffect(() => {
// Initial setting of cryptoAmount in case of a QR-code set amount
if (!cryptoAmount) handleInputChange(cryptoAmount ?? '0')
// This component initially mounts without an accountId, because of how <AccountDropdown /> works
// Also turns out we don't handle re-validation in case of changing AccountIds
// This effect takes care of both the initial/account change cases
if (previousAccountId !== accountId) {
const inputAmount = fieldName === SendFormFields.CryptoAmount ? cryptoAmount : fiatAmount
handleInputChange(inputAmount ?? '0')
trigger(fieldName)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [handleInputChange])
}, [accountId])

const asset = useAppSelector(state => selectAssetById(state, assetId ?? ''))

Expand Down

0 comments on commit 600784e

Please sign in to comment.