Whitelist.js 3.66 KiB
Newer Older
Amaury Martiny's avatar
Amaury Martiny committed
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
Amaury Martiny's avatar
Amaury Martiny committed
// SPDX-License-Identifier: BSD-3-Clause
Amaury Martiny's avatar
Amaury Martiny committed

Amaury Martiny's avatar
Amaury Martiny committed
import React, { Component } from "react";
import { chainName$ } from "@parity/light.js";
import debounce from "lodash/debounce";
import { Header } from "fether-ui";
import light from "@parity/light.js-react";

import Health from "../Health";
import NewTokenItem from "./NewTokenItem";
Amaury Martiny's avatar
Amaury Martiny committed
import withAccount from "../utils/withAccount";
import withTokens from "../utils/withTokens";
@withAccount
Amaury Martiny's avatar
Amaury Martiny committed
@withTokens
  chainName: () => chainName$({ withoutLoading: true })
class Whitelist extends Component {
  state = {
    db: null,
    dbMap: null,
    matches: [],
Amaury Martiny's avatar
Amaury Martiny committed
    search: ""
  };

  calculateMatches = debounce(() => {
    const { db, search } = this.state;

    if (search.length <= 1) {
      this.setState({ matches: [] });
      return;
    }

    const matches = db
      ? db.filter(
Amaury Martiny's avatar
Amaury Martiny committed
          ({ name, symbol }) =>
            name.toLowerCase().includes(search.toLowerCase()) ||
            symbol.toLowerCase().includes(search.toLowerCase())
Amaury Martiny's avatar
Amaury Martiny committed
        )
      : [];
    this.setState({ matches });
  }, 500);

Amaury Martiny's avatar
Amaury Martiny committed
  componentDidMount() {
    if (this.props.chainName) {
      this.fetchTokensDb();
    }
  }

Amaury Martiny's avatar
Amaury Martiny committed
  componentDidUpdate(prevProps) {
    if (this.props.chainName && !prevProps.chainName) {
      this.fetchTokensDb();
    }
  }

  fetchTokensDb = async () => {
    if (this.state.db) {
      // Don't fetch again if it's already fetched
      return;
    }

    // We only fetch this huge json if the user visits this NewToken page. We
    // try to avoid it as much as possible. All other tokens info (used in the
    // homepage) are stored in localStorage.
    let db;
    try {
      db = await import(`../assets/tokens/${this.props.chainName}.json`);
    } catch (e) {
      this.setState({ db: [], dbMap: {} });
      return;
    }

    // We create a address=>token mapping here
    const dbMap = {};
    db.forEach(token => (dbMap[token.address] = token));

    // Commit this into the state
    this.setState({ db, dbMap });
  };

  handleSearch = ({ target: { value } }) => {
    this.setState({ search: value });
    this.calculateMatches();
  };

  handleClear = () => {
Amaury Martiny's avatar
Amaury Martiny committed
    this.setState({ search: "" });
    this.calculateMatches();
  };
Amaury Martiny's avatar
Amaury Martiny committed

Amaury Martiny's avatar
Amaury Martiny committed
  render() {
    const { history } = this.props;
    const { matches, search } = this.state;

    const displayedTokens = search ? matches : this.props.tokensArrayWithoutEth;

Amaury Martiny's avatar
Amaury Martiny committed
    return (
      <div>
        <Header
          left={
Amaury Martiny's avatar
Amaury Martiny committed
            <a to="/tokens" className="icon -close" onClick={history.goBack}>
          title={<h1>Search tokens</h1>}
Amaury Martiny's avatar
Amaury Martiny committed
        <div className="window_content">
          <div className="box -padded">
            <div className="search-form">
              <input
                onChange={this.handleSearch}
Amaury Martiny's avatar
Amaury Martiny committed
                placeholder="Find token by name or symbol"
                value={search}
Amaury Martiny's avatar
Amaury Martiny committed
                type="text"
              />
              <button
                onClick={this.handleClear}
Amaury Martiny's avatar
Amaury Martiny committed
                className="button -icon -clear"
Brian Flanagan's avatar
Brian Flanagan committed
                disabled={!search.length}
              >
                Clear
              </button>
            </div>
          </div>
Amaury Martiny's avatar
Amaury Martiny committed
          <div className="box -scroller">
            <ul className="list -tokens">
              {displayedTokens.map(token => (
                <NewTokenItem key={token.address} token={token} />
          </div>
Amaury Martiny's avatar
Amaury Martiny committed
        <nav className="footer-nav">
          <div className="footer-nav_status">
            <Health />
          </div>
        </nav>
export default Whitelist;