Skip to content

Commit

Permalink
feat: send modal status step (#7698)
Browse files Browse the repository at this point in the history
  • Loading branch information
gomesalexandre authored Sep 10, 2024
1 parent 01e4739 commit f8cd550
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 24 deletions.
1 change: 0 additions & 1 deletion packages/chain-adapters/src/evm/EvmBaseAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,6 @@ export abstract class EvmBaseAdapter<T extends EvmChainId> implements IChainAdap
throw new Error(`wallet does not support ${this.getDisplayName()}`)
}

await this.assertSwitchChain(wallet)
await verifyLedgerAppOpen(this.chainId, wallet)

const address = await (wallet as ETHWallet).ethGetAddress({
Expand Down
3 changes: 3 additions & 0 deletions src/assets/translations/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,9 @@
"average": "Average",
"fast": "Fast",
"enterAmount": "Enter Amount"
},
"status": {
"pendingBody": "Sending %{amount} %{symbol}"
}
},
"receive": {
Expand Down
16 changes: 15 additions & 1 deletion src/components/Modals/QrCode/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { SendFormFields, SendRoutes } from '../Send/SendCommon'
import { Address } from '../Send/views/Address'
import { Confirm } from '../Send/views/Confirm'
import { Details } from '../Send/views/Details'
import { Status } from '../Send/views/Status'

type QrCodeFormProps = {
assetId?: AssetId
Expand Down Expand Up @@ -71,6 +72,16 @@ export const Form: React.FC<QrCodeFormProps> = ({ accountId }) => {
history.goBack()
}, [history])

const handleSubmit = useCallback(
async (data: SendInput) => {
const txHash = await handleFormSend(data)
if (!txHash) return
methods.setValue(SendFormFields.TxHash, txHash)
history.push(SendRoutes.Status)
},
[handleFormSend, history, methods],
)

const checkKeyDown = useCallback((event: React.KeyboardEvent<HTMLFormElement>) => {
if (event.key === 'Enter') event.preventDefault()
}, [])
Expand Down Expand Up @@ -142,7 +153,7 @@ export const Form: React.FC<QrCodeFormProps> = ({ accountId }) => {
return (
<FormProvider {...methods}>
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}
<form onSubmit={methods.handleSubmit(handleFormSend)} onKeyDown={checkKeyDown}>
<form onSubmit={methods.handleSubmit(handleSubmit)} onKeyDown={checkKeyDown}>
<AnimatePresence mode='wait' initial={false}>
<Switch location={location} key={location.key}>
<Route path={SendRoutes.Select}>
Expand All @@ -164,6 +175,9 @@ export const Form: React.FC<QrCodeFormProps> = ({ accountId }) => {
<Route path={SendRoutes.Confirm}>
<Confirm />
</Route>
<Route path={SendRoutes.Status}>
<Status />
</Route>
<Redirect exact from='/' to={SendRoutes.Scan} />
</Switch>
</AnimatePresence>
Expand Down
18 changes: 17 additions & 1 deletion src/components/Modals/Send/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { SendFormFields, SendRoutes } from './SendCommon'
import { Address } from './views/Address'
import { Confirm } from './views/Confirm'
import { Details } from './views/Details'
import { Status } from './views/Status'

export type SendInput<T extends ChainId = ChainId> = {
[SendFormFields.AccountId]: AccountId
Expand All @@ -37,6 +38,7 @@ export type SendInput<T extends ChainId = ChainId> = {
[SendFormFields.SendMax]: boolean
[SendFormFields.VanityAddress]: string
[SendFormFields.CustomNonce]?: string
[SendFormFields.TxHash]?: string
}

const formStyle = { height: '100%' }
Expand Down Expand Up @@ -67,9 +69,20 @@ export const Form: React.FC<SendFormProps> = ({ initialAssetId, input = '', acco
amountCryptoPrecision: '',
fiatAmount: '',
fiatSymbol: selectedCurrency,
txHash: '',
},
})

const handleSubmit = useCallback(
async (data: SendInput) => {
const txHash = await handleFormSend(data)
if (!txHash) return
methods.setValue(SendFormFields.TxHash, txHash)
history.push(SendRoutes.Status)
},
[handleFormSend, history, methods],
)

const handleAssetSelect = useCallback(
(assetId: AssetId) => {
methods.setValue(SendFormFields.AssetId, assetId)
Expand Down Expand Up @@ -141,7 +154,7 @@ export const Form: React.FC<SendFormProps> = ({ initialAssetId, input = '', acco
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}
<form
style={formStyle}
onSubmit={methods.handleSubmit(handleFormSend)}
onSubmit={methods.handleSubmit(handleSubmit)}
onKeyDown={checkKeyDown}
>
<AnimatePresence mode='wait' initial={false}>
Expand All @@ -165,6 +178,9 @@ export const Form: React.FC<SendFormProps> = ({ initialAssetId, input = '', acco
<Route path={SendRoutes.Confirm}>
<Confirm />
</Route>
<Route path={SendRoutes.Status}>
<Status />
</Route>
<Redirect exact from='/' to={SendRoutes.Select} />
</Switch>
</AnimatePresence>
Expand Down
2 changes: 2 additions & 0 deletions src/components/Modals/Send/SendCommon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum SendRoutes {
Address = '/send/address',
Details = '/send/details',
Confirm = '/send/confirm',
Status = '/send/status',
Select = '/send/select',
Scan = '/send/scan',
}
Expand All @@ -23,4 +24,5 @@ export enum SendFormFields {
AmountFieldError = 'amountFieldError',
SendMax = 'sendMax',
CustomNonce = 'customNonce',
TxHash = 'txHash',
}
13 changes: 4 additions & 9 deletions src/components/Modals/Send/hooks/useFormSend/useFormSend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ExternalLinkIcon } from '@chakra-ui/icons'
import { Link, Text, useToast } from '@chakra-ui/react'
import { useCallback } from 'react'
import { useTranslate } from 'react-polyglot'
import { useModal } from 'hooks/useModal/useModal'
import { useWallet } from 'hooks/useWallet/useWallet'
import { selectAssetById } from 'state/slices/selectors'
import { store } from 'state/store'
Expand All @@ -13,14 +12,12 @@ import { handleSend } from '../../utils'
export const useFormSend = () => {
const toast = useToast()
const translate = useTranslate()
const send = useModal('send')
const qrCode = useModal('qrCode')
const {
state: { wallet },
} = useWallet()

const handleFormSend = useCallback(
async (sendInput: SendInput) => {
async (sendInput: SendInput): Promise<string | undefined> => {
try {
const asset = selectAssetById(store.getState(), sendInput.assetId)
if (!asset) throw new Error(`No asset found for assetId ${sendInput.assetId}`)
Expand Down Expand Up @@ -52,6 +49,8 @@ export const useFormSend = () => {
position: 'top-right',
})
}, 5000)

return broadcastTXID
} catch (e) {
// If we're here, we know asset is defined
const asset = selectAssetById(store.getState(), sendInput.assetId)!
Expand All @@ -66,13 +65,9 @@ export const useFormSend = () => {
isClosable: true,
position: 'top-right',
})
} finally {
// Sends may be done from the context of a QR code modal, or a send modal, which are similar, but effectively diff. modal refs
qrCode.close()
send.close()
}
},
[qrCode, send, toast, translate, wallet],
[toast, translate, wallet],
)

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type { FeeDataEstimate } from '@shapeshiftoss/chain-adapters'
import { useQuery } from '@tanstack/react-query'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { useFormContext, useWatch } from 'react-hook-form'
import { useHistory } from 'react-router-dom'
import { estimateFees } from 'components/Modals/Send/utils'
import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton'
import { useDebounce } from 'hooks/useDebounce/useDebounce'
Expand All @@ -24,15 +23,14 @@ import {
import { useAppSelector } from 'state/store'

import type { SendInput } from '../../Form'
import { SendFormFields, SendRoutes } from '../../SendCommon'
import { SendFormFields } from '../../SendCommon'

type AmountFieldName = SendFormFields.FiatAmount | SendFormFields.AmountCryptoPrecision

type UseSendDetailsReturnType = {
balancesLoading: boolean
fieldName: AmountFieldName
handleInputChange(inputValue: string): void
handleNextClick(): void
handleSendMax(): Promise<void>
isLoading: boolean
toggleIsFiat(): void
Expand All @@ -44,7 +42,6 @@ type UseSendDetailsReturnType = {
// i.e. you don't send from an asset, you send from an account containing an asset
export const useSendDetails = (): UseSendDetailsReturnType => {
const [fieldName, setFieldName] = useState<AmountFieldName>(SendFormFields.AmountCryptoPrecision)
const history = useHistory()
const { setValue } = useFormContext<SendInput>()
const assetId = useWatch<SendInput, SendFormFields.AssetId>({
name: SendFormFields.AssetId,
Expand Down Expand Up @@ -328,8 +325,6 @@ export const useSendDetails = (): UseSendDetailsReturnType => {
setValue(SendFormFields.EstimatedFees, estimatedFees)
}, [estimatedFees, sendMax, setValue])

const handleNextClick = () => history.push(SendRoutes.Confirm)

const handleSendMax = useCallback(async () => {
setValue(SendFormFields.SendMax, true)
// Clear existing amount errors.
Expand Down Expand Up @@ -412,7 +407,6 @@ export const useSendDetails = (): UseSendDetailsReturnType => {
fieldName,
cryptoHumanBalance,
fiatBalance: userCurrencyBalance,
handleNextClick,
handleSendMax,
handleInputChange,
isLoading: isEstimatedFormFeesLoading,
Expand Down
3 changes: 2 additions & 1 deletion src/components/Modals/Send/views/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ export const Details = () => {
const history = useHistory()
const translate = useTranslate()

const handleNextClick = useCallback(() => history.push(SendRoutes.Confirm), [history])

const {
accountId,
amountFieldError,
Expand Down Expand Up @@ -103,7 +105,6 @@ export const Details = () => {
fieldName,
cryptoHumanBalance,
fiatBalance,
handleNextClick,
handleSendMax,
handleInputChange,
isLoading,
Expand Down
111 changes: 111 additions & 0 deletions src/components/Modals/Send/views/Status.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { CheckCircleIcon, WarningIcon } from '@chakra-ui/icons'
import { Card } from '@chakra-ui/react'
import { TxStatus } from '@shapeshiftoss/unchained-client'
import React, { useCallback, useMemo } from 'react'
import { useWatch } from 'react-hook-form'
import { CircularProgress } from 'components/CircularProgress/CircularProgress'
import { useModal } from 'hooks/useModal/useModal'
import { useTxStatus } from 'hooks/useTxStatus/useTxStatus'
import { getTxLink } from 'lib/getTxLink'
import { SharedStatus } from 'pages/RFOX/components/Shared/SharedStatus'
import { selectAssetById } from 'state/slices/selectors'
import { useAppSelector } from 'state/store'

import type { SendInput } from '../Form'
import { SendFormFields } from '../SendCommon'

type BodyContent = {
key: TxStatus
title: string
body: string | [string, Record<string, string | number>]
element: JSX.Element
}

export const Status: React.FC = () => {
const send = useModal('send')
const qrCode = useModal('qrCode')

const handleClose = useCallback(() => {
send.close()
qrCode.close()
}, [qrCode, send])

const txHash = useWatch<SendInput, SendFormFields.TxHash>({ name: SendFormFields.TxHash })
const assetId = useWatch<SendInput, SendFormFields.AssetId>({ name: SendFormFields.AssetId })
const amountCryptoPrecision = useWatch<SendInput, SendFormFields.AmountCryptoPrecision>({
name: SendFormFields.AmountCryptoPrecision,
})
const accountId = useWatch<SendInput, SendFormFields.AccountId>({
name: SendFormFields.AccountId,
})
const asset = useAppSelector(state => selectAssetById(state, assetId ?? ''))

const txStatus = useTxStatus({
accountId,
txHash: txHash || null,
})

const bodyContent: BodyContent | null = useMemo(() => {
if (!asset) return null
switch (txStatus) {
case undefined:
case TxStatus.Pending:
return {
key: TxStatus.Pending,
title: 'pools.waitingForConfirmation',
body: [
'modals.send.status.pendingBody',
{
amount: amountCryptoPrecision,
symbol: asset.symbol,
},
],
element: <CircularProgress size='75px' />,
}
case TxStatus.Confirmed:
return {
key: TxStatus.Confirmed,
title: 'common.success',
body: [
'modals.send.youHaveSent',
{
amount: amountCryptoPrecision,
symbol: asset.symbol,
},
],
element: <CheckCircleIcon color='green.500' boxSize='75px' />,
}
case TxStatus.Failed:
return {
key: TxStatus.Failed,
title: 'transactionRow.failed',
body: 'common.transactionFailedBody',
element: <WarningIcon color='red.500' boxSize='75px' />,
}
default:
return {
key: TxStatus.Pending,
title: 'pools.waitingForConfirmation',
body: [
'modals.send.status.pendingBody',
{
amount: amountCryptoPrecision,
symbol: asset.symbol,
},
],
element: <CircularProgress size='75px' />,
}
}
}, [txStatus, amountCryptoPrecision, asset])

const txLink = useMemo(
() => getTxLink({ txId: txHash ?? '', defaultExplorerBaseUrl: asset?.explorerTxLink ?? '' }),
[asset?.explorerTxLink, txHash],
)

return (
<Card width='full'>
<SharedStatus txLink={txLink} body={bodyContent} onClose={handleClose} />
</Card>
)
}
16 changes: 12 additions & 4 deletions src/pages/RFOX/components/Shared/SharedStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ type SharedStatusProps = {
body: SharedBodyContent | null
txLink?: string
onBack?: () => void
onClose?: () => void
}

export const SharedStatus: React.FC<SharedStatusProps> = ({ body, txLink, onBack }) => {
export const SharedStatus: React.FC<SharedStatusProps> = ({ body, txLink, onBack, onClose }) => {
const translate = useTranslate()
return (
<SlideTransition>
Expand All @@ -43,9 +44,16 @@ export const SharedStatus: React.FC<SharedStatusProps> = ({ body, txLink, onBack
<Button as={Link} href={txLink} size='lg' variant='ghost' isExternal>
{translate('trade.viewTransaction')}
</Button>
<Button size='lg' colorScheme='blue' onClick={onBack}>
{translate('common.goBack')}
</Button>
{onBack && (
<Button size='lg' colorScheme='blue' onClick={onBack}>
{translate('common.goBack')}
</Button>
)}
{onClose && (
<Button size='lg' variant='outline' onClick={onClose}>
{translate('common.close')}
</Button>
)}
</CardFooter>
</SlideTransition>
)
Expand Down

0 comments on commit f8cd550

Please sign in to comment.