cyb/src/pages/teleport/components/actionBarPingTxs.tsx

import { ActionBar as ActionBarContainer } from '@cybercongress/gravity';
import { useEffect, useRef, useState } from 'react';
import { useQueryClient } from 'src/contexts/queryClient';
import { Option } from 'src/types';
import {
  ActionBarContentText,
  Confirmed,
  Dots,
  TransactionError,
  TransactionSubmitted,
} from '../../../components';
import { LEDGER } from '../../../utils/config';
import { friendlyErrorMessage } from 'src/utils/errorMessages';

const { STAGE_ERROR, STAGE_SUBMITTED, STAGE_CONFIRMING, STAGE_CONFIRMED } = LEDGER;

function ActionBarPingTxs({ stageActionBarStaps }) {
  const queryClient = useQueryClient();
  const [txHeight, setTxHeight] = useState<Option<number>>(undefined);
  const [errorMessage, setErrorMessage] = useState<Option<string | JSX.Element>>(undefined);

  const { stage, setStage, clearState, txHash, errorMessageProps, updateFunc } =
    stageActionBarStaps;

  // Use ref for updateFunc to avoid restarting the polling loop when it changes
  const updateFuncRef = useRef(updateFunc);
  useEffect(() => {
    updateFuncRef.current = updateFunc;
  }, [updateFunc]);

  useEffect(() => {
    let retries = 0;
    let cancelled = false;
    const MAX_RETRIES = 20;

    const confirmTx = async () => {
      if (cancelled || !queryClient || !txHash) return;

      setStage(STAGE_CONFIRMING);
      try {
        const response = await queryClient.getTx(txHash);
        if (cancelled) return;
        if (response !== null) {
          if (response.code === 0) {
            setStage(STAGE_CONFIRMED);
            setTxHeight(response.height);
            if (updateFuncRef.current) {
              updateFuncRef.current();
            }
            return;
          }
          if (response.code) {
            setStage(STAGE_ERROR);
            setTxHeight(response.height);
            setErrorMessage(friendlyErrorMessage(response.rawLog));
            return;
          }
        }
      } catch (error) {
        console.error('getTx error:', error);
      }

      if (cancelled) return;
      retries += 1;
      if (retries >= MAX_RETRIES) {
        setStage(STAGE_ERROR);
        setErrorMessage(`transaction confirmation timed out after ${MAX_RETRIES * 1.5}s โ€” check tx ${txHash} manually`);
        return;
      }
      setTimeout(confirmTx, 1500);
    };
    confirmTx();

    return () => {
      cancelled = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [queryClient, txHash, setStage]);

  if (stage === STAGE_SUBMITTED) {
    return (
      <ActionBarContainer>
        <ActionBarContentText>
          check the transaction <Dots big />
        </ActionBarContentText>
      </ActionBarContainer>
    );
  }

  if (stage === STAGE_CONFIRMING) {
    return <TransactionSubmitted />;
  }

  if (stage === STAGE_CONFIRMED) {
    return <Confirmed txHash={txHash} txHeight={txHeight} onClickBtnClose={() => clearState()} />;
  }

  if ((stage === STAGE_ERROR && errorMessage !== null) || errorMessageProps) {
    return (
      <TransactionError
        errorMessage={errorMessage || errorMessageProps}
        onClickBtn={() => clearState()}
      />
    );
  }

  return null;
}

export default ActionBarPingTxs;

Synonyms

pussy-ts/src/pages/teleport/components/actionBarPingTxs.tsx

Neighbours