utils#usePrevious TypeScript Examples

The following examples show how to use utils#usePrevious. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: WalletModal.tsx    From dxvote with GNU Affero General Public License v3.0 4 votes vote down vote up
WalletModal: React.FC<WalletModalProps> = ({ isOpen, onClose }) => {
  const { active, connector, error, activate, account, chainId } =
    useWeb3React();
  const rpcUrls = useRpcUrls();
  const [walletView, setWalletView] = useState(WALLET_VIEWS.ACCOUNT);
  const [connectionErrorMessage, setConnectionErrorMessage] = useState(false);
  const { transactions, clearAllTransactions } = useTransactions();

  // always reset to account view
  useEffect(() => {
    if (isOpen) {
      setConnectionErrorMessage(false);
      setWalletView(WALLET_VIEWS.ACCOUNT);
    }
  }, [isOpen]);

  // close modal when a connection is successful
  const activePrevious = usePrevious(active);
  const connectorPrevious = usePrevious(connector);
  useEffect(() => {
    if (
      isOpen &&
      ((active && !activePrevious) ||
        (connector && connector !== connectorPrevious && !error))
    ) {
      setWalletView(WALLET_VIEWS.ACCOUNT);
    }
  }, [
    setWalletView,
    active,
    error,
    connector,
    activePrevious,
    connectorPrevious,
    isOpen,
  ]);

  const tryActivation = async connector => {
    setWalletView(WALLET_VIEWS.PENDING);
    activate(connector, undefined, true).catch(e => {
      setConnectionErrorMessage(e);
      console.debug('[Activation Error]', e);
    });
  };

  // get wallets user can switch too, depending on device/browser
  function getOptions() {
    if (!rpcUrls) return [];

    const isMetamask = window.ethereum && window.ethereum.isMetaMask;
    const wallets = getWallets(rpcUrls);
    return Object.keys(wallets).map(key => {
      const option = wallets[key];
      // check for mobile options
      if (isMobile) {
        if (!window.ethereum && option.mobile) {
          return (
            <Option
              onClick={() => {
                option.connector !== connector &&
                  !option.href &&
                  tryActivation(option.connector);
              }}
              key={key}
              icon={option.icon}
              active={option.connector && option.connector === connector}
              link={option.href}
              header={option.name}
            />
          );
        }
        return null;
      }

      // overwrite injected when needed
      if (option.connector === injected) {
        // don't show injected if there's no injected provider
        if (!window.ethereum) {
          if (option.name === 'MetaMask') {
            return (
              <Option
                key={key}
                icon={option.icon}
                header={'Install Metamask'}
                link={'https://metamask.io/'}
              />
            );
          } else {
            return null; //dont want to return install twice
          }
        }
        // don't return metamask if injected provider isn't metamask
        else if (option.name === 'MetaMask' && !isMetamask) {
          return null;
        }
        // likewise for generic
        else if (option.name === 'Injected' && isMetamask) {
          return null;
        }
      }

      // return rest of options
      return (
        !isMobile &&
        !option.mobileOnly && (
          <Option
            onClick={() => {
              option.connector === connector
                ? setWalletView(WALLET_VIEWS.ACCOUNT)
                : !option.href && tryActivation(option.connector);
            }}
            key={key}
            active={option.connector === connector}
            icon={option.icon}
            link={option.href}
            header={option.name}
          />
        )
      );
    });
  }

  function getModalContent() {
    if (connectionErrorMessage) {
      const isUnsupportedChain =
        connectionErrorMessage.toString().indexOf('UnsupportedChainIdError') >=
        0;
      return (
        <Container>
          <ErrorHeading size={2}>
            {isUnsupportedChain ? 'Wrong Network' : 'Error connecting'}
          </ErrorHeading>
          <div>
            {isUnsupportedChain
              ? 'Please connect to a valid ethereum network.'
              : 'Error connecting. Try refreshing the page.'}
          </div>
        </Container>
      );
    }

    if (
      account &&
      !isChainIdSupported(chainId) &&
      walletView === WALLET_VIEWS.ACCOUNT
    ) {
      return (
        <Container>
          <ErrorHeading size={2}>Wrong Network</ErrorHeading>
          <div>Please connect to a valid ethereum network.</div>
        </Container>
      );
    }

    if (account && walletView === WALLET_VIEWS.ACCOUNT) {
      const recentTransactions = transactions
        .sort((tx1, tx2) => tx2.addedTime - tx1.addedTime)
        .slice(0, 5);
      return (
        <>
          <WalletInfoBox
            openOptions={() => setWalletView(WALLET_VIEWS.OPTIONS)}
          />
          <Divider />
          <TransactionsList>
            {recentTransactions.length === 0 ? (
              <TransactionsListHeading>
                Your transactions will appear here...
              </TransactionsListHeading>
            ) : (
              <>
                <TransactionsListHeading>
                  Recent Transactions
                </TransactionsListHeading>
                <GreyDivider />
                {recentTransactions.map(transaction => (
                  <Transaction transaction={transaction} />
                ))}
                {recentTransactions.length > 0 && (
                  <ButtonContainer>
                    <Button onClick={clearAllTransactions}>Clear all</Button>
                  </ButtonContainer>
                )}
              </>
            )}
          </TransactionsList>
        </>
      );
    }

    return <Container>{getOptions()}</Container>;
  }

  const getHeader = () => {
    if (walletView !== WALLET_VIEWS.ACCOUNT) {
      return (
        <BackIcon
          onClick={() => {
            setWalletView(WALLET_VIEWS.ACCOUNT);
          }}
        />
      );
    }

    if (walletView === WALLET_VIEWS.ACCOUNT) return 'Account';

    return 'Connect to a wallet';
  };

  return (
    <Modal
      header={getHeader()}
      isOpen={isOpen}
      onDismiss={onClose}
      maxWidth={380}
    >
      {getModalContent()}
    </Modal>
  );
}
Example #2
Source File: index.tsx    From dxvote with GNU Affero General Public License v3.0 4 votes vote down vote up
WalletModal = observer(() => {
  const {
    context: { modalStore },
  } = useContext();
  const { active, connector, error, activate, account, chainId } =
    useWeb3React();
  const rpcUrls = useRpcUrls();
  const [walletView, setWalletView] = useState(WALLET_VIEWS.ACCOUNT);
  const [connectionErrorMessage, setConnectionErrorMessage] = useState(false);

  const walletModalOpen = modalStore.walletModalVisible;

  const toggleWalletModal = () => {
    modalStore.toggleWalletModal();
  };

  // always reset to account view
  useEffect(() => {
    if (walletModalOpen) {
      setConnectionErrorMessage(false);
      setWalletView(WALLET_VIEWS.ACCOUNT);
    }
  }, [walletModalOpen]);

  // close modal when a connection is successful
  const activePrevious = usePrevious(active);
  const connectorPrevious = usePrevious(connector);
  useEffect(() => {
    if (
      walletModalOpen &&
      ((active && !activePrevious) ||
        (connector && connector !== connectorPrevious && !error))
    ) {
      setWalletView(WALLET_VIEWS.ACCOUNT);
    }
  }, [
    setWalletView,
    active,
    error,
    connector,
    walletModalOpen,
    activePrevious,
    connectorPrevious,
  ]);

  const tryActivation = async connector => {
    setWalletView(WALLET_VIEWS.PENDING);
    activate(connector, undefined, true).catch(e => {
      setConnectionErrorMessage(e);
      console.debug('[Activation Error]', e);
    });
  };

  // get wallets user can switch too, depending on device/browser
  function getOptions() {
    if (!rpcUrls) return [];

    const isMetamask = window.ethereum && window.ethereum.isMetaMask;
    const wallets = getWallets(rpcUrls);
    return Object.keys(wallets).map(key => {
      const option = wallets[key];
      // check for mobile options
      if (isMobile) {
        if (!window.ethereum && option.mobile) {
          return (
            <Option
              onClick={() => {
                option.connector !== connector &&
                  !option.href &&
                  tryActivation(option.connector);
              }}
              key={key}
              icon={option.icon}
              active={option.connector && option.connector === connector}
              color={option.color}
              link={option.href}
              header={option.name}
              subheader={null}
            />
          );
        }
        return null;
      }

      // overwrite injected when needed
      if (option.connector === injected) {
        // don't show injected if there's no injected provider
        if (!window.ethereum) {
          if (option.name === 'MetaMask') {
            return (
              <Option
                key={key}
                color={'#E8831D'}
                icon={option.icon}
                header={'Install Metamask'}
                subheader={null}
                link={'https://metamask.io/'}
              />
            );
          } else {
            return null; //dont want to return install twice
          }
        }
        // don't return metamask if injected provider isn't metamask
        else if (option.name === 'MetaMask' && !isMetamask) {
          return null;
        }
        // likewise for generic
        else if (option.name === 'Injected' && isMetamask) {
          return null;
        }
      }

      // return rest of options
      return (
        !isMobile &&
        !option.mobileOnly && (
          <Option
            onClick={() => {
              option.connector === connector
                ? setWalletView(WALLET_VIEWS.ACCOUNT)
                : !option.href && tryActivation(option.connector);
            }}
            key={key}
            active={option.connector === connector}
            color={option.color}
            icon={option.icon}
            link={option.href}
            header={option.name}
            subheader={null} //use option.descriptio to bring back multi-line
          />
        )
      );
    });
  }

  function getModalContent() {
    if (connectionErrorMessage) {
      return (
        <UpperSection>
          <HeaderRow>
            {connectionErrorMessage
              .toString()
              .indexOf('UnsupportedChainIdError') >= 0
              ? 'Wrong Network'
              : 'Error connecting'}
          </HeaderRow>
          <ContentWrapper>
            {connectionErrorMessage
              .toString()
              .indexOf('UnsupportedChainIdError') >= 0 ? (
              <h5> Please connect to a valid ethereum network. </h5>
            ) : (
              'Error connecting. Try refreshing the page.'
            )}
          </ContentWrapper>
        </UpperSection>
      );
    }
    if (
      account &&
      !isChainIdSupported(chainId) &&
      walletView === WALLET_VIEWS.ACCOUNT
    ) {
      return (
        <UpperSection>
          <HeaderRow>{'Wrong Network'}</HeaderRow>
          <ContentWrapper>
            <h5>Please connect to a valid ethereum network.</h5>
          </ContentWrapper>
        </UpperSection>
      );
    }
    if (account && walletView === WALLET_VIEWS.ACCOUNT) {
      return (
        <AccountDetails
          openOptions={() => setWalletView(WALLET_VIEWS.OPTIONS)}
        />
      );
    }
    return (
      <UpperSection>
        <ContentWrapper>
          <OptionGrid>{getOptions()}</OptionGrid>
          {walletView !== WALLET_VIEWS.PENDING && (
            <Blurb>
              <span style={{ color: '#90a4ae' }}>New to Ethereum? &nbsp;</span>{' '}
              <Link href="https://ethereum.org/use/#3-what-is-a-wallet-and-which-one-should-i-use">
                Learn more about wallets
              </Link>
            </Blurb>
          )}
        </ContentWrapper>
      </UpperSection>
    );
  }

  const Header = (
    <div>
      {walletView !== WALLET_VIEWS.ACCOUNT ? (
        <HoverText
          onClick={() => {
            setWalletView(WALLET_VIEWS.ACCOUNT);
          }}
        >
          Back
        </HoverText>
      ) : walletView === WALLET_VIEWS.ACCOUNT ? (
        'Account'
      ) : (
        'Connect to a wallet'
      )}
    </div>
  );

  return (
    <Modal
      header={Header}
      isOpen={walletModalOpen}
      onDismiss={toggleWalletModal}
    >
      <Wrapper>{getModalContent()}</Wrapper>
    </Modal>
  );
})
Example #3
Source File: index.tsx    From dxvote with GNU Affero General Public License v3.0 4 votes vote down vote up
Web3ReactManager = ({ children }) => {
  const { context } = useContext();
  const { providerStore, blockchainStore } = context;

  const location = useLocation();
  const history = useHistory();
  const rpcUrls = useRpcUrls();

  // Overriding default fetch to check for RPC url and setting correct headers if matched
  const originalFetch = window.fetch;
  window.fetch = (url, opts): Promise<Response> => {
    if (rpcUrls && Object.values(rpcUrls).includes(url.toString()) && opts) {
      opts.headers = opts.headers || {
        'Content-Type': 'application/json',
      };
    }
    return originalFetch(url, opts);
  };

  const web3Context = useWeb3React();
  const {
    active: networkActive,
    error: networkError,
    chainId,
    account,
    connector,
    activate,
  } = web3Context;

  console.debug('[Web3ReactManager] Start of render', {
    web3Context,
  });

  // Make sure providerStore is synchronized with web3-react
  useEffect(() => {
    providerStore.setWeb3Context(web3Context);
  }, [web3Context]);

  // try to eagerly connect to a provider if possible
  const { triedEager, tryConnecting } = useEagerConnect();

  // If eager-connect failed, try to connect to network in the URL
  // If no chain in the URL, fallback to default chain
  useEffect(() => {
    if (triedEager && !networkActive && rpcUrls) {
      const chains = getChains(rpcUrls);
      const urlNetworkName = location.pathname.split('/')[1];
      const chainId =
        chains.find(chain => chain.name == urlNetworkName)?.id ||
        DEFAULT_CHAIN_ID;
      const networkConnector = getNetworkConnector(rpcUrls, chainId);

      activate(networkConnector, undefined, true).catch(e => {
        console.error(
          '[Web3ReactManager] Unable to activate network connector.',
          e
        );
      });
    }
  }, [triedEager, networkActive, activate, rpcUrls, location]);

  const prevChainId = usePrevious(chainId);
  const prevAccount = usePrevious(account);
  useEffect(() => {
    // Listen to chain / account changes and reset the app
    if (prevChainId !== chainId || prevAccount !== account) {
      try {
        providerStore.setWeb3Context(web3Context);
        context.reset();
        if (location.pathname !== '/cache') {
          blockchainStore.fetchData(web3Context, true);
        }
      } catch (e) {
        // Fallback if something goes wrong
        window.location.reload();
      }
    }
  }, [chainId, prevChainId, account, prevAccount]);

  // Setup listener to handle injected wallet events
  useEffect(() => {
    if (!window.ethereum) return () => {};

    const handleChainChange = (chainId: string) => {
      const chains = getChains();
      const chain = chains.find(
        chain => `0x${chain.id.toString(16)}` == chainId
      );

      // If currently connected to an injected wallet, keep synced with it
      if (connector instanceof InjectedConnector) {
        history.push(`/${chain.name}/proposals`);
      } else if (connector instanceof NetworkConnector) {
        const urlNetworkName = location.pathname.split('/')[1];
        if (urlNetworkName == chain.name) {
          tryConnecting();
        }
      }
    };

    window.ethereum.on('chainChanged', handleChainChange);

    return () => {
      window.ethereum?.removeListener('accountsChanged', handleChainChange);
    };
  }, [location, connector]);

  const urlNetworkName = useMemo(
    () => location.pathname.split('/')[1],
    [location]
  );
  const prevUrlNetworkName = usePrevious(urlNetworkName);
  if (
    urlNetworkName &&
    prevUrlNetworkName &&
    urlNetworkName !== prevUrlNetworkName
  ) {
    tryConnecting();
  }

  // Fetch user blockchain data on an interval using current params
  useInterval(
    async () => {
      if (networkActive) {
        if (location.pathname !== '/cache') {
          blockchainStore.fetchData(providerStore.getActiveWeb3React(), false);
        }
      }
    },
    networkActive ? BLOKCHAIN_FETCH_INTERVAL : 10
  );

  const Content = styled.div`
    margin: auto;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    width: 85%;
  `;

  // on page load, do nothing until we've tried to connect to the injected connector
  if (!triedEager) {
    console.debug('[Web3ReactManager] Render: Eager load not tried');
    return (
      <ThemeProvider>
        <GlobalStyle />
        <Content>
          <LoadingNetworkHeader />
          <LoadingBox>
            <div className="loader">
              <PulsingIcon size={80} inactive={false} />
            </div>
          </LoadingBox>
        </Content>
      </ThemeProvider>
    );
  } else if (networkError) {
    console.debug(
      '[Web3ReactManager] Render: Network error, showing modal error.'
    );
    return null;
  } else {
    console.debug('[Web3ReactManager] Render: Render children', {
      networkActive,
    });
    return children;
  }
}