TxActionsWrapper.tsx
1 import { CheckIcon } from '@heroicons/react/solid'; 2 import { Trans } from '@lingui/macro'; 3 import { Box, BoxProps, Button, CircularProgress, SvgIcon, Typography } from '@mui/material'; 4 import { ReactNode } from 'react'; 5 import { TxStateType, useModalContext } from 'src/hooks/useModal'; 6 import { useWeb3Context } from 'src/libs/hooks/useWeb3Context'; 7 import { TrackEventProps } from 'src/store/analyticsSlice'; 8 import { TxAction } from 'src/ui-config/errorMapping'; 9 10 import { ApprovalTooltip } from '../infoTooltips/ApprovalTooltip'; 11 import { RightHelperText } from './FlowCommons/RightHelperText'; 12 13 interface TxActionsWrapperProps extends BoxProps { 14 actionInProgressText: ReactNode; 15 actionText: ReactNode; 16 amount?: string; 17 approvalTxState?: TxStateType; 18 handleApproval?: () => Promise<void>; 19 handleAction: () => Promise<void>; 20 isWrongNetwork: boolean; 21 mainTxState: TxStateType; 22 preparingTransactions: boolean; 23 requiresAmount?: boolean; 24 requiresApproval: boolean; 25 symbol?: string; 26 blocked?: boolean; 27 fetchingData?: boolean; 28 errorParams?: { 29 loading: boolean; 30 disabled: boolean; 31 content: ReactNode; 32 handleClick: () => Promise<void>; 33 }; 34 tryPermit?: boolean; 35 event?: TrackEventProps; 36 } 37 38 export const TxActionsWrapper = ({ 39 actionInProgressText, 40 actionText, 41 amount, 42 approvalTxState, 43 handleApproval, 44 handleAction, 45 isWrongNetwork, 46 mainTxState, 47 preparingTransactions, 48 requiresAmount, 49 requiresApproval, 50 sx, 51 symbol, 52 blocked, 53 fetchingData = false, 54 errorParams, 55 tryPermit, 56 event, 57 ...rest 58 }: TxActionsWrapperProps) => { 59 const { txError } = useModalContext(); 60 const { readOnlyModeAddress } = useWeb3Context(); 61 const hasApprovalError = 62 requiresApproval && txError?.txAction === TxAction.APPROVAL && txError?.actionBlocked; 63 const isAmountMissing = requiresAmount && requiresAmount && Number(amount) === 0; 64 65 function getMainParams() { 66 if (blocked) return { disabled: true, content: actionText }; 67 if ( 68 (txError?.txAction === TxAction.GAS_ESTIMATION || 69 txError?.txAction === TxAction.MAIN_ACTION) && 70 txError?.actionBlocked 71 ) { 72 if (errorParams) return errorParams; 73 return { loading: false, disabled: true, content: actionText }; 74 } 75 if (isWrongNetwork) return { disabled: true, content: <Trans>Wrong Network</Trans> }; 76 if (fetchingData) return { disabled: true, content: <Trans>Fetching data...</Trans> }; 77 if (isAmountMissing) return { disabled: true, content: <Trans>Enter an amount</Trans> }; 78 if (preparingTransactions) return { disabled: true, loading: true }; 79 // if (hasApprovalError && handleRetry) 80 // return { content: <Trans>Retry with approval</Trans>, handleClick: handleRetry }; 81 if (mainTxState?.loading) 82 return { loading: true, disabled: true, content: actionInProgressText }; 83 if (requiresApproval && !approvalTxState?.success) 84 return { disabled: true, content: actionText }; 85 return { content: actionText, handleClick: handleAction }; 86 } 87 88 function getApprovalParams() { 89 if ( 90 !requiresApproval || 91 isWrongNetwork || 92 isAmountMissing || 93 preparingTransactions || 94 hasApprovalError 95 ) 96 return null; 97 if (approvalTxState?.loading) 98 return { loading: true, disabled: true, content: <Trans>Approving {symbol}...</Trans> }; 99 if (approvalTxState?.success) 100 return { 101 disabled: true, 102 content: ( 103 <> 104 <Trans>Approve Confirmed</Trans> 105 <SvgIcon sx={{ fontSize: 20, ml: 2 }}> 106 <CheckIcon /> 107 </SvgIcon> 108 </> 109 ), 110 }; 111 112 return { 113 content: ( 114 <ApprovalTooltip 115 variant="buttonL" 116 iconSize={20} 117 iconMargin={2} 118 color="white" 119 text={<Trans>Approve {symbol} to continue</Trans>} 120 /> 121 ), 122 handleClick: handleApproval, 123 }; 124 } 125 126 const { content, disabled, loading, handleClick } = getMainParams(); 127 const approvalParams = getApprovalParams(); 128 return ( 129 <Box sx={{ display: 'flex', flexDirection: 'column', mt: 12, ...sx }} {...rest}> 130 {approvalParams && !readOnlyModeAddress && ( 131 <Box sx={{ display: 'flex', justifyContent: 'end', alignItems: 'center' }}> 132 <RightHelperText approvalHash={approvalTxState?.txHash} tryPermit={tryPermit} /> 133 </Box> 134 )} 135 136 {approvalParams && !readOnlyModeAddress && ( 137 <Button 138 variant="contained" 139 disabled={approvalParams.disabled || blocked} 140 onClick={() => approvalParams.handleClick && approvalParams.handleClick()} 141 size="large" 142 sx={{ minHeight: '44px' }} 143 data-cy="approvalButton" 144 > 145 {approvalParams.loading && ( 146 <CircularProgress color="inherit" size="16px" sx={{ mr: 2 }} /> 147 )} 148 {approvalParams.content} 149 </Button> 150 )} 151 152 <Button 153 variant="contained" 154 disabled={disabled || blocked || readOnlyModeAddress !== undefined} 155 onClick={handleClick} 156 size="large" 157 sx={{ minHeight: '44px', ...(approvalParams ? { mt: 2 } : {}) }} 158 data-cy="actionButton" 159 > 160 {loading && <CircularProgress color="inherit" size="16px" sx={{ mr: 2 }} />} 161 {content} 162 </Button> 163 {readOnlyModeAddress && ( 164 <Typography variant="helperText" color="warning.main" sx={{ textAlign: 'center', mt: 2 }}> 165 <Trans>Read-only mode. Connect to a wallet to perform transactions.</Trans> 166 </Typography> 167 )} 168 </Box> 169 ); 170 };