/ src / components / transactions / TxActionsWrapper.tsx
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  };