utils#shortenAddress JavaScript Examples

The following examples show how to use utils#shortenAddress. 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: index.jsx    From Artion-Client with GNU General Public License v3.0 6 votes vote down vote up
OwnersModal = ({ visible, onClose, holders }) => {
  return (
    <Modal visible={visible} title="Owned by" onClose={onClose}>
      {holders.map((holder, idx) => (
        <Holder key={idx} holder={holder}>
          <div className={styles.holderInfo}>
            <div className={styles.avatarWrapper}>
              {holder.imageHash ? (
                <img
                  src={`https://cloudflare-ipfs.com/ipfs/${holder.imageHash}`}
                  width={40}
                  height={40}
                />
              ) : (
                <Identicon
                  account={holder.address}
                  size={40}
                  className={styles.avatar}
                />
              )}
            </div>
            <div className={styles.info}>
              <div className={styles.alias}>{holder.alias || 'Unnamed'}</div>
              <div className={styles.address}>
                {shortenAddress(holder.address)}
              </div>
            </div>
          </div>
          <div className={styles.holdCount}>
            {`${formatNumber(holder.supply)} item${
              holder.supply !== 1 ? 's' : ''
            }`}
          </div>
        </Holder>
      ))}
    </Modal>
  );
}
Example #2
Source File: index.jsx    From Artion-Client with GNU General Public License v3.0 5 votes vote down vote up
FollowersModal = ({ visible, onClose, title, users }) => {
  return (
    <Modal visible={visible} title={title} onClose={onClose}>
      {users.map((user, idx) => (
        <Follower key={idx} user={user} onClose={onClose}>
          <div className={styles.holderInfo}>
            <div className={styles.avatarWrapper}>
              {!user ? (
                <Skeleton width={40} height={40} />
              ) : user.imageHash ? (
                <img
                  src={`https://cloudflare-ipfs.com/ipfs/${user.imageHash}`}
                  width={40}
                  height={40}
                />
              ) : (
                <Identicon
                  account={user.address}
                  size={40}
                  className={styles.avatar}
                />
              )}
            </div>
            <div className={styles.info}>
              <div className={styles.alias}>
                {user ? (
                  user.alias || 'Unnamed'
                ) : (
                  <Skeleton width={100} height={20} />
                )}
              </div>
              <div className={styles.address}>
                {user ? (
                  shortenAddress(user.address)
                ) : (
                  <Skeleton width={100} height={20} />
                )}
              </div>
            </div>
          </div>
          <div className={styles.followers}>
            {user ? (
              `${formatFollowers(user.followers)} follower${
                user.followers !== 1 ? 's' : ''
              }`
            ) : (
              <Skeleton width={80} height={24} />
            )}
          </div>
        </Follower>
      ))}
    </Modal>
  );
}
Example #3
Source File: index.jsx    From Artion-Client with GNU General Public License v3.0 5 votes vote down vote up
LikesModal = ({ visible, onClose, users }) => {
  return (
    <Modal visible={visible} title="Liked by" onClose={onClose}>
      {users.map((user, idx) => (
        <User key={idx} user={user} onClose={onClose}>
          <div className={styles.holderInfo}>
            <div className={styles.avatarWrapper}>
              {!user ? (
                <Skeleton width={40} height={40} />
              ) : user.imageHash ? (
                <img
                  src={`https://cloudflare-ipfs.com/ipfs/${user.imageHash}`}
                  width={40}
                  height={40}
                />
              ) : (
                <Identicon
                  account={user.address}
                  size={40}
                  className={styles.avatar}
                />
              )}
            </div>
            <div className={styles.info}>
              <div className={styles.alias}>
                {user ? (
                  user.alias || 'Unnamed'
                ) : (
                  <Skeleton width={100} height={20} />
                )}
              </div>
              <div className={styles.address}>
                {user ? (
                  shortenAddress(user.address)
                ) : (
                  <Skeleton width={100} height={20} />
                )}
              </div>
            </div>
          </div>
        </User>
      ))}
    </Modal>
  );
}
Example #4
Source File: index.js    From Artion-Client with GNU General Public License v3.0 4 votes vote down vote up
Header = () => {
  const dispatch = useDispatch();

  const { getAuthToken, getAccountDetails, getIsModerator } = useApi();
  const { account, chainId, deactivate } = useWeb3React();

  const { user } = useSelector(state => state.Auth);

  const [anchorEl, setAnchorEl] = useState(null);
  const [loading, setLoading] = useState(false);
  const [connectWalletModalVisible, setConnectWalletModalVisible] = useState(
    false
  );

  const isMenuOpen = Boolean(anchorEl);

  const login = async () => {
    try {
      setLoading(true);
      const token = await getAuthToken(account);
      const isModerator = await getIsModerator(account);

      dispatch(WalletConnectActions.connectWallet(token, isModerator));
      dispatch(AuthActions.fetchStart());
      try {
        const { data } = await getAccountDetails(token);
        dispatch(AuthActions.fetchSuccess(data));
      } catch {
        dispatch(AuthActions.fetchFailed());
      }
      setLoading(false);
    } catch {
      setLoading(false);
    }
  };

  const init = () => {
    login();
  };

  useEffect(() => {
    if (account) {
      init();
    } else {
      handleSignOut();
    }
  }, [account, chainId]);

  const handleConnectWallet = () => {
    setConnectWalletModalVisible(true);
  };

  const handleSignOut = () => {
    deactivate();
    dispatch(WalletConnectActions.disconnectWallet());
    dispatch(AuthActions.signOut());
    handleMenuClose();
  };

  const handleProfileMenuOpen = e => {
    setAnchorEl(e.currentTarget);
  };

  const handleMenuClose = () => {
    setAnchorEl(null);
  };

  const renderMenu = (
    <Menu
      anchorEl={anchorEl}
      anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
      keepMounted
      transformOrigin={{ vertical: 'top', horizontal: 'right' }}
      open={isMenuOpen}
      onClose={handleMenuClose}
      classes={{
        paper: styles.profilemenu,
        list: styles.menuList,
      }}
    >
      <div className={styles.signOut} onClick={handleSignOut}>
        Sign Out
      </div>
    </Menu>
  );

  return (
    <div className={styles.header}>
      <div className={styles.left}>
        <Link to="/" className={styles.logo}>
          <img src={logo} alt="logo" />
        </Link>
      </div>
      <div className={styles.menu}>
        {account ? (
          <div
            className={cx(styles.account, styles.menuLink)}
            onClick={handleProfileMenuOpen}
          >
            {loading ? (
              <Skeleton className={styles.avatar} />
            ) : user?.imageHash ? (
              <img
                src={`https://cloudflare-ipfs.com/ipfs/${user?.imageHash}`}
                width="24"
                height="24"
                className={styles.avatar}
              />
            ) : (
              <Identicon
                account={account}
                size={36}
                className={styles.avatar}
              />
            )}
            <div className={styles.profile}>
              <div className={styles.address}>
                {loading ? (
                  <Skeleton width={120} />
                ) : (
                  user?.alias || shortenAddress(account)
                )}
              </div>
              <div className={styles.network}>
                {loading ? <Skeleton width={80} /> : NETWORK_LABEL[chainId]}
              </div>
            </div>

            <ExpandMore
              className={cx(styles.expand, isMenuOpen && styles.expanded)}
            />
          </div>
        ) : (
          <div
            className={cx(styles.connect, styles.menuLink)}
            onClick={handleConnectWallet}
          >
            Connect Wallet
          </div>
        )}
      </div>
      {renderMenu}
      <ConnectWalletModal
        visible={connectWalletModalVisible}
        onClose={() => setConnectWalletModalVisible(false)}
      />
    </div>
  );
}
Example #5
Source File: index.js    From Artion-Client with GNU General Public License v3.0 4 votes vote down vote up
Header = ({ border }) => {
  const history = useHistory();
  const dispatch = useDispatch();

  const {
    apiUrl,
    storageUrl,
    getAuthToken,
    getAccountDetails,
    getIsModerator,
  } = useApi();
  const { account, chainId, deactivate } = useWeb3React();

  const { user } = useSelector(state => state.Auth);
  let isSearchbarShown = useSelector(state => state.HeaderOptions.isShown);
  const { isModerator } = useSelector(state => state.ConnectWallet);
  const { wftmModalVisible, connectWalletModalVisible } = useSelector(
    state => state.Modal
  );

  const [anchorEl, setAnchorEl] = useState(null);
  const [loading, setLoading] = useState(false);
  const [searchBarActive, setSearchBarActive] = useState(false);
  const [isAdding, setIsAdding] = useState(false);
  const [modModalVisible, setModModalVisible] = useState(false);
  const [isBan, setIsBan] = useState(false);
  const [banCollectionModalVisible, setBanCollectionModalVisible] = useState(
    false
  );
  const [banItemModalVisible, setBanItemModalVisible] = useState(false);
  const [banUserModalVisible, setBanUserModalVisible] = useState(false);
  const [unbanUserModalVisible, setUnbanUserModalVisible] = useState(false);
  const [
    boostCollectionModalVisible,
    setBoostCollectionModalVisible,
  ] = useState(false);

  const [keyword, setKeyword] = useState('');
  const [cancelSource, setCancelSource] = useState(null);
  const [accounts, setAccounts] = useState([]);
  const [collections, setCollections] = useState([]);
  const [tokens, setTokens] = useState([]);
  const [bundles, setBundles] = useState([]);
  const [tokenDetailsLoading, setTokenDetailsLoading] = useState(false);
  const timer = useRef(null);

  const isMenuOpen = Boolean(anchorEl);

  const login = async () => {
    try {
      setLoading(true);
      const token = await getAuthToken(account);
      const isModerator = await getIsModerator(account);

      dispatch(WalletConnectActions.connectWallet(token, isModerator));
      dispatch(AuthActions.fetchStart());
      try {
        const { data } = await getAccountDetails(token);
        dispatch(AuthActions.fetchSuccess(data));
      } catch {
        dispatch(AuthActions.fetchFailed());
      }
      setLoading(false);
    } catch {
      setLoading(false);
    }
  };

  const init = () => {
    login();
  };

  useEffect(() => {
    if (account) {
      init();
    } else {
      handleSignOut();
    }
  }, [account, chainId]);

  const handleConnectWallet = () => {
    dispatch(ModalActions.showConnectWalletModal());
  };

  const resetResults = () => {
    setAccounts([]);
    setCollections([]);
    setTokens([]);
    setBundles([]);
  };

  useEffect(() => {
    resetResults();
  }, [isSearchbarShown]);

  const search = async word => {
    setKeyword(word);

    if (cancelSource) {
      cancelSource.cancel();
    }

    if (word.length === 0) {
      resetResults();

      return;
    }

    try {
      const cancelTokenSource = axios.CancelToken.source();
      setCancelSource(cancelTokenSource);

      const {
        data: {
          data: { accounts, collections, tokens, bundles },
        },
      } = await axios({
        method: 'post',
        url: `${apiUrl}/info/searchNames`,
        data: JSON.stringify({ name: word }),
        headers: {
          'Content-Type': 'application/json',
        },
        cancelToken: cancelTokenSource.token,
      });

      Promise.all(
        tokens.map(async token => {
          if (token.imageURL) {
            token.imageURL = getRandomIPFS(token.imageURL);
          }

          if (token.imageURL === '-') {
            const {
              data: { image },
            } = await axios.get(token.tokenURI);

            if (image) {
              // eslint-disable-next-line require-atomic-updates
              token.imageURL = getRandomIPFS(token.imageURL);
            }
          }
        })
      );

      setAccounts(accounts);
      setCollections(collections);
      setTokenDetailsLoading(true);
      setTokens(tokens);
      setBundles(bundles);
      setTokenDetailsLoading(false);
    } catch (err) {
      console.log(err);
    } finally {
      setCancelSource(null);
    }
  };

  const handleSelectCollection = addr => {
    dispatch(FilterActions.updateCollectionsFilter([addr]));
  };

  const handleSearch = word => {
    if (timer.current) {
      clearTimeout(timer.current);
    }

    timer.current = setTimeout(() => search(word), 500);
  };

  const handleSignOut = () => {
    deactivate();
    dispatch(WalletConnectActions.disconnectWallet());
    dispatch(AuthActions.signOut());
    handleMenuClose();
  };

  const handleProfileMenuOpen = e => {
    setAnchorEl(e.currentTarget);
  };

  const handleMenuClose = () => {
    setAnchorEl(null);
  };

  const goToMyProfile = () => {
    history.push(`/account/${account}`);
    handleMenuClose();
  };

  const goToNotificationSettings = () => {
    history.push(`/settings/notification`);
    handleMenuClose();
  };

  // const handleCreateCollection = () => {
  //   history.push('/collection/create');
  //   handleMenuClose();
  // };

  const handleRegisterCollection = () => {
    history.push('/collection/register');
    handleMenuClose();
  };

  const openWrapStation = () => {
    dispatch(ModalActions.showWFTMModal());
    handleMenuClose();
  };

  const addMod = () => {
    setIsAdding(true);
    setModModalVisible(true);
    handleMenuClose();
  };

  const removeMod = () => {
    setIsAdding(false);
    setModModalVisible(true);
    handleMenuClose();
  };

  const reviewCollections = () => {
    history.push('/collection/review');
    handleMenuClose();
  };

  const banCollection = () => {
    setIsBan(true);
    setBanCollectionModalVisible(true);
    handleMenuClose();
  };

  const unbanCollection = () => {
    setIsBan(false);
    setBanCollectionModalVisible(true);
    handleMenuClose();
  };

  const banItems = () => {
    setBanItemModalVisible(true);
    handleMenuClose();
  };

  const banUser = () => {
    setBanUserModalVisible(true);
    handleMenuClose();
  };

  const unbanUser = () => {
    setUnbanUserModalVisible(true);
    handleMenuClose();
  };

  const boostCollection = () => {
    setBoostCollectionModalVisible(true);
    handleMenuClose();
  };

  const renderMenu = (
    <Menu
      anchorEl={anchorEl}
      anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
      keepMounted
      transformOrigin={{ vertical: 'top', horizontal: 'right' }}
      open={isMenuOpen}
      onClose={handleMenuClose}
      classes={{
        paper: styles.profilemenu,
        list: styles.menuList,
      }}
    >
      {account && (
        <div
          className={cx(styles.menuItem, styles.topItem)}
          onClick={goToMyProfile}
        >
          <img src={iconUser} className={styles.menuIcon} />
          My Profile
        </div>
      )}
      <div className={styles.menuItem} onClick={goToNotificationSettings}>
        <img src={iconNotification} className={styles.menuIcon} />
        Notification Settings
      </div>
      {/* <div className={styles.menuItem} onClick={handleCreateCollection}>
        <img src={iconAdd} className={styles.menuIcon} />
        Create New Collection
      </div> */}
      <div className={styles.menuItem} onClick={handleRegisterCollection}>
        <img src={iconEdit} className={styles.menuIcon} />
        Register Existing Collection
      </div>
      <div className={styles.menuItem} onClick={openWrapStation}>
        <img src={iconSwap} className={styles.menuIcon} />
        FTM / WFTM Station
      </div>

      <div className={styles.menuSeparator} />
      {account?.toLowerCase() === ADMIN_ADDRESS.toLowerCase()
        ? [
            <div key={0} className={styles.menuItem} onClick={addMod}>
              Add Mod
            </div>,
            <div key={1} className={styles.menuItem} onClick={removeMod}>
              Remove Mod
            </div>,
            <div
              key={2}
              className={styles.menuItem}
              onClick={reviewCollections}
            >
              Review Collections
            </div>,
            <div key={3} className={styles.menuItem} onClick={banCollection}>
              Ban Collection
            </div>,
            <div key={4} className={styles.menuItem} onClick={unbanCollection}>
              Unban Collection
            </div>,
            <div key={5} className={styles.menuItem} onClick={banItems}>
              Ban Items
            </div>,
            <div key={6} className={styles.menuItem} onClick={banUser}>
              Ban a user
            </div>,
            <div key={6} className={styles.menuItem} onClick={unbanUser}>
              Unban a user
            </div>,
            <div key={7} className={styles.menuItem} onClick={boostCollection}>
              Boost Collection
            </div>,
            <div key={8} className={styles.menuSeparator} />,
          ]
        : isModerator
        ? [
            <div key={1} className={styles.menuItem} onClick={banCollection}>
              Ban Collection
            </div>,
            <div key={2} className={styles.menuItem} onClick={banItems}>
              Ban Items
            </div>,
            <div key={3} className={styles.menuItem} onClick={banUser}>
              Ban a user
            </div>,
            <div key={6} className={styles.menuItem} onClick={unbanUser}>
              Unban a user
            </div>,
            <div key={4} className={styles.menuSeparator} />,
          ]
        : null}
      <div className={styles.signOut} onClick={handleSignOut}>
        Sign Out
      </div>
    </Menu>
  );

  const renderSearchBox = () => (
    <div className={cx(styles.searchcont, searchBarActive && styles.active)}>
      <div className={styles.searchcontinner}>
        <div className={styles.searchbar}>
          <SearchIcon className={styles.searchicon} />
          <input
            placeholder="Search items, collections and accounts"
            className={styles.searchinput}
            onChange={e => handleSearch(e.target.value)}
            onFocus={() => setSearchBarActive(true)}
            onBlur={() => setTimeout(() => setSearchBarActive(false), 200)}
          />
        </div>
        {searchBarActive && (
          <div className={styles.resultcont}>
            {collections.length > 0 && (
              <div className={styles.resultsection}>
                <div className={styles.resultsectiontitle}>Collections</div>
                <div className={styles.separator} />
                <div className={styles.resultlist}>
                  {collections.map((collection, idx) => (
                    <div
                      key={idx}
                      className={styles.result}
                      onClick={() =>
                        handleSelectCollection(collection.erc721Address)
                      }
                    >
                      <img
                        className={styles.resultimg}
                        src={`${getRandomIPFS('', true)}${
                          collection.logoImageHash
                        }`}
                      />
                      <div className={styles.resulttitle}>
                        {collection.collectionName}
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            )}
            {accounts.length > 0 && (
              <div className={styles.resultsection}>
                <div className={styles.resultsectiontitle}>Accounts</div>
                <div className={styles.separator} />
                <div className={styles.resultlist}>
                  {accounts.map((account, idx) => (
                    <Link
                      to={`/account/${account.address}`}
                      key={idx}
                      className={styles.result}
                    >
                      {account.imageHash ? (
                        <img
                          className={styles.resultimg}
                          src={`https://cloudflare-ipfs.com/ipfs/${account.imageHash}`}
                        />
                      ) : (
                        <Identicon
                          className={styles.resultimg}
                          account={account.address}
                          size={40}
                        />
                      )}
                      <div className={styles.resulttitle}>{account.alias}</div>
                    </Link>
                  ))}
                </div>
              </div>
            )}
            {tokens.length > 0 && (
              <div className={styles.resultsection}>
                <div className={styles.resultsectiontitle}>Items</div>
                <div className={styles.separator} />
                <div className={styles.resultlist}>
                  {tokens.map((tk, idx) => (
                    <Link
                      to={`/explore/${tk.contractAddress}/${tk.tokenID}`}
                      key={idx}
                      className={styles.result}
                    >
                      <div className={styles.resultimg}>
                        {tokenDetailsLoading ? (
                          <Skeleton width={40} height={40} />
                        ) : (
                          tk.thumbnailPath &&
                          (tk.thumbnailPath.length > 10 ? (
                            <img
                              src={`${storageUrl}/image/${tk.thumbnailPath}`}
                            />
                          ) : tk.thumbnailPath === '.' ? (
                            <img src={tk.imageURL} />
                          ) : null)
                        )}
                      </div>
                      <div className={styles.resulttitle}>{tk.name}</div>
                    </Link>
                  ))}
                </div>
              </div>
            )}
            {bundles.length > 0 && (
              <div className={styles.resultsection}>
                <div className={styles.resultsectiontitle}>Bundles</div>
                <div className={styles.separator} />
                <div className={styles.resultlist}>
                  {bundles.map((bundle, idx) => (
                    <Link
                      to={`/bundle/${bundle._id}`}
                      key={idx}
                      className={styles.result}
                    >
                      <div className={styles.resultimg}></div>
                      <div className={styles.resulttitle}>{bundle.name}</div>
                    </Link>
                  ))}
                </div>
              </div>
            )}
            {keyword.length > 0 &&
              collections.length === 0 &&
              accounts.length === 0 &&
              tokens.length === 0 &&
              bundles.length === 0 && (
                <div className={styles.noResults}>No Results</div>
              )}
          </div>
        )}
      </div>
    </div>
  );

  return (
    <div className={cx(styles.header, border && styles.hasBorder)}>
      <div className={styles.left}>
        <Link to="/" className={styles.logo}>
          <img src={logoSmallBlue} alt="logo" />
        </Link>
        {isSearchbarShown && renderSearchBox()}
        <div className={styles.secondmenu}>
          <NavLink
            to="/explore"
            className={cx(styles.menuLink, styles.link)}
            activeClassName={styles.active}
          >
            Explore
          </NavLink>
          <NavLink
            to="/create"
            className={cx(styles.menuLink, styles.link)}
            activeClassName={styles.active}
          >
            Create
          </NavLink>
        </div>
      </div>
      <div className={styles.menu}>
        {isSearchbarShown && renderSearchBox()}
        <NavLink
          to="/explore"
          className={cx(styles.menuLink, styles.link)}
          activeClassName={styles.active}
          style={{ color: '#fff' }}
        >
          Explore
        </NavLink>
        <NavLink
          to="/create"
          className={cx(styles.menuLink, styles.link)}
          activeClassName={styles.active}
          style={{ color: '#fff' }}
        >
          Create
        </NavLink>
        {account ? (
          <div
            className={cx(styles.account, styles.menuLink)}
            onClick={handleProfileMenuOpen}
          >
            {loading ? (
              <Skeleton className={styles.avatar} />
            ) : user?.imageHash ? (
              <img
                src={`https://cloudflare-ipfs.com/ipfs/${user?.imageHash}`}
                width="24"
                height="24"
                className={styles.avatar}
              />
            ) : (
              <Identicon
                account={account}
                size={36}
                className={styles.avatar}
              />
            )}
            <div className={styles.profile}>
              <div className={styles.address}>
                {loading ? (
                  <Skeleton width={120} />
                ) : (
                  user?.alias || shortenAddress(account)
                )}
              </div>
              <div className={styles.network}>
                {loading ? <Skeleton width={80} /> : NETWORK_LABEL[chainId]}
              </div>
            </div>

            <ExpandMore
              className={cx(styles.expand, isMenuOpen && styles.expanded)}
            />
          </div>
        ) : (
          <div
            className={cx(styles.connect, styles.menuLink)}
            onClick={handleConnectWallet}
          >
            Connect Wallet
          </div>
        )}
      </div>
      {renderMenu}
      <WFTMModal
        visible={wftmModalVisible}
        onClose={() => dispatch(ModalActions.hideWFTMModal())}
      />
      <ModModal
        isAdding={isAdding}
        visible={modModalVisible}
        onClose={() => setModModalVisible(false)}
      />
      <BanCollectionModal
        visible={banCollectionModalVisible}
        isBan={isBan}
        onClose={() => setBanCollectionModalVisible(false)}
      />
      <BanItemModal
        visible={banItemModalVisible}
        onClose={() => setBanItemModalVisible(false)}
      />
      <BanUserModal
        visible={banUserModalVisible}
        onClose={() => setBanUserModalVisible(false)}
        isForBanning={true}
      />
      <BanUserModal
        visible={unbanUserModalVisible}
        onClose={() => setUnbanUserModalVisible(false)}
        isForBanning={false}
      />
      <BoostCollectionModal
        visible={boostCollectionModalVisible}
        onClose={() => setBoostCollectionModalVisible(false)}
      />
      <ConnectWalletModal
        visible={connectWalletModalVisible}
        onClose={() => dispatch(ModalActions.hideConnectWalletModal())}
      />
    </div>
  );
}
Example #6
Source File: index.js    From Artion-Client with GNU General Public License v3.0 4 votes vote down vote up
AccountDetails = () => {
  const dispatch = useDispatch();

  const {
    storageUrl,
    getUserAccountDetails,
    getUserFigures,
    fetchCollections,
    fetchTokens,
    updateBanner,
    getAccountActivity,
    getActivityFromOthers,
    getMyOffers,
    getFollowing,
    followUser: _followUser,
    getFollowers,
    getFollowings,
    getMyLikes,
    getItemsLiked,
  } = useApi();
  const { getTokenByAddress } = useTokens();
  const { account, chainId } = useWeb3React();
  const { width, ref } = useResizeDetector();

  const { uid } = useParams();

  const { authToken } = useSelector(state => state.ConnectWallet);
  const { user: me } = useSelector(state => state.Auth);

  const fileInput = useRef();

  const [anchorEl, setAnchorEl] = useState(null);
  const [prevUID, setPrevUID] = useState(null);
  const [bundleModalVisible, setBundleModalVisible] = useState(false);
  const [followingsModalVisible, setFollowingsModalVisible] = useState(false);
  const [followersModalVisible, setFollowersModalVisible] = useState(false);
  const [fetching, setFetching] = useState(false);
  const [bundleFetching, setBundleFetching] = useState(false);
  const [favFetching, setFavFetching] = useState(false);
  const [fguresFetching, setFiguresFetching] = useState(false);
  const tokens = useRef([]);
  const bundles = useRef([]);
  const likes = useRef([]);
  const [followersLoading, setFollowersLoading] = useState(false);
  const followers = useRef([]);
  const followings = useRef([]);
  const [following, setFollowing] = useState(false);
  const [followingInProgress, setFollowingInProgress] = useState(false);
  const [count, setCount] = useState(0);
  const [bundleCount, setBundleCount] = useState(0);
  const [favCount, setFavCount] = useState(0);
  const [now, setNow] = useState(new Date());
  const [page, setPage] = useState(0);
  const [bannerHash, setBannerHash] = useState();
  const [loading, setLoading] = useState(true);
  const [user, setUser] = useState({});
  const [copied, setCopied] = useState(false);
  const [tooltipOpen, setTooltipOpen] = useState(false);
  const [tab, setTab] = useState(0);
  const [activityLoading, setActivityLoading] = useState(false);
  const [activities, setActivities] = useState([]);
  const [bidsLoading, setBidsLoading] = useState(false);
  const [bids, setBids] = useState([]);
  const [offersLoading, setOffersLoading] = useState(false);
  const [offers, setOffers] = useState([]);
  const [fetchInterval, setFetchInterval] = useState(null);
  const [likeCancelSource, setLikeCancelSource] = useState(null);
  const [prevNumPerRow, setPrevNumPerRow] = useState(null);
  const prevAuthToken = usePrevious(authToken);

  const numPerRow = Math.floor(width / 240);
  const fetchCount = numPerRow <= 3 ? 18 : numPerRow === 4 ? 16 : numPerRow * 3;

  const getUserDetails = async _account => {
    setLoading(true);
    try {
      const { data } = await getUserAccountDetails(_account);
      setUser(data);
    } catch {
      setUser({});
    }
    try {
      const { data: isFollowing } = await getFollowing(account, _account);

      if (account === undefined) {
        setFollowing(false);
      } else {
        setFollowing(isFollowing);
      }
    } catch {
      setFollowing(false);
    }
    setLoading(false);
  };

  const getFigures = async _account => {
    setFiguresFetching(true);

    try {
      const {
        data: { single, bundle, fav },
      } = await getUserFigures(_account);
      setCount(single);
      setBundleCount(bundle);
      setFavCount(fav);
    } catch {
      setCount(0);
      setBundleCount(0);
      setFavCount(0);
    }

    setFiguresFetching(false);
  };

  const fetchNFTs = async () => {
    if (tab === 0) {
      if (fetching) return;
      setFetching(true);
    } else {
      if (bundleFetching) return;
      setBundleFetching(true);
    }

    try {
      const start = tab === 0 ? tokens.current.length : bundles.current.length;
      const _count =
        fetchCount -
        ((tab === 0 ? tokens.current : bundles.current).length % numPerRow);
      const { data } = await fetchTokens(
        start,
        _count,
        tab === 0 ? 'single' : 'bundle',
        [],
        null,
        'createdAt',
        [],
        uid
      );

      if (tab === 0) {
        // eslint-disable-next-line require-atomic-updates
        tokens.current = [...tokens.current, ...data.tokens];
        setCount(data.total);
        if (authToken) {
          updateItems(tokens.current)
            .then(_tokens => (tokens.current = _tokens))
            .catch();
        }
      } else {
        // eslint-disable-next-line require-atomic-updates
        bundles.current = [...bundles.current, ...data.tokens];
        setBundleCount(data.total);
        if (authToken) {
          updateItems(bundles.current)
            .then(_bundles => (bundles.current = _bundles))
            .catch();
        }
      }

      setFetching(false);
      setBundleFetching(false);
    } catch {
      setFetching(false);
      setBundleFetching(false);
    }
  };

  const fetchLikes = async step => {
    if (fetching) return;

    setFavFetching(true);

    try {
      const { data } = await getMyLikes(step, uid);
      setFavFetching(false);
      likes.current = [...likes.current, ...data.tokens];
      setFavCount(data.total);
      if (authToken) {
        updateItems(likes.current)
          .then(_likes => (likes.current = _likes))
          .catch();
      }
      setPage(step);
    } catch {
      setFavFetching(false);
    }
  };

  useEffect(() => {
    setPrevNumPerRow(numPerRow);
    if (isNaN(numPerRow) || (prevNumPerRow && prevNumPerRow !== numPerRow))
      return;

    if (prevUID !== uid) {
      setPrevUID(uid);
      getUserDetails(uid);
      getFigures(uid);
      setTab(0);
      if (tab === 0) {
        init();
      }
    } else {
      init();
    }
  }, [uid, tab, chainId, numPerRow]);

  useEffect(() => {
    if (me && user && me.address?.toLowerCase() === uid.toLowerCase()) {
      setUser({ ...user, ...me });
    }

    if (account === undefined) {
      setFollowing(false);
    }
  }, [me, uid, account]);

  const updateCollections = async () => {
    try {
      dispatch(CollectionsActions.fetchStart());
      const res = await fetchCollections();
      if (res.status === 'success') {
        const verified = [];
        const unverified = [];
        res.data.map(item => {
          if (item.isVerified) verified.push(item);
          else unverified.push(item);
        });
        dispatch(CollectionsActions.fetchSuccess([...verified, ...unverified]));
      }
    } catch {
      dispatch(CollectionsActions.fetchFailed());
    }
  };

  useEffect(() => {
    if (fetchInterval) {
      clearInterval(fetchInterval);
    }

    updateCollections();
    setFetchInterval(setInterval(updateCollections, 1000 * 60 * 10));
  }, [chainId]);

  const isMe = account?.toLowerCase() === uid.toLowerCase();

  useEffect(() => {
    dispatch(HeaderActions.toggleSearchbar(true));
    setInterval(() => setNow(new Date()), 1000);
  }, []);

  const updateItems = async _tokens => {
    return new Promise((resolve, reject) => {
      if (!authToken) {
        return resolve(
          _tokens.map(tk => ({
            ...tk,
            isLiked: false,
          }))
        );
      }
      let missingTokens = _tokens.map((tk, index) =>
        tk.items
          ? {
              index,
              isLiked: tk.isLiked,
              bundleID: tk._id,
            }
          : {
              index,
              isLiked: tk.isLiked,
              contractAddress: tk.contractAddress,
              tokenID: tk.tokenID,
            }
      );
      if (prevAuthToken) {
        missingTokens = missingTokens.filter(tk => tk.isLiked === undefined);
      }

      if (missingTokens.length === 0) {
        reject();
        return;
      }

      const cancelTokenSource = axios.CancelToken.source();
      setLikeCancelSource(cancelTokenSource);
      getItemsLiked(missingTokens, authToken, cancelTokenSource.token)
        .then(({ data, status }) => {
          setLikeCancelSource(null);
          if (status === 'success') {
            const newTokens = [...tokens.current];
            missingTokens.map((tk, idx) => {
              newTokens[tk.index].isLiked = data[idx].isLiked;
            });
            resolve(newTokens);
          }
        })
        .catch(() => {
          reject();
        });
    });
  };

  useEffect(() => {
    if (likeCancelSource) {
      likeCancelSource.cancel();
    }

    if (tokens.current.length) {
      updateItems(tokens.current)
        .then(_tokens => (tokens.current = _tokens))
        .catch();
    }
    if (bundles.current.length) {
      updateItems(bundles.current)
        .then(_bundles => (bundles.current = _bundles))
        .catch();
    }
    if (likes.current.length) {
      updateItems(likes.current)
        .then(_likes => (likes.current = _likes))
        .catch();
    }
  }, [authToken]);

  const loadNextPage = () => {
    if (fetching || bundleFetching) return;

    if (tab === 0 && tokens.current.length === count) return;
    if (tab === 1 && bundles.current.length === bundleCount) return;
    if (tab === 2 && likes.current.length === favCount) return;

    if (tab === 0 || tab === 1) {
      fetchNFTs();
    } else {
      fetchLikes(page + 1);
    }
  };

  const handleScroll = e => {
    if (tab > 2) return;

    const obj = e.currentTarget;
    if (obj.scrollHeight - obj.clientHeight - obj.scrollTop < 100) {
      loadNextPage();
    }
  };

  const init = () => {
    if (tab === 0) {
      tokens.current = [];
      setCount(0);
      fetchNFTs();
    } else if (tab === 1) {
      bundles.current = [];
      setBundleCount(0);
      fetchNFTs();
    } else if (tab === 2) {
      likes.current = [];
      setFavCount(0);
      fetchLikes(0);
    } else if (tab === 3) {
      getActivity();
    } else if (tab === 4) {
      getOffersFromOthers();
    } else if (tab === 5) {
      getOffers();
    }
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  const handleCopyLink = () => {
    handleClose();
    toast('success', 'Link copied to clipboard!');
  };

  const handleShareOnFacebook = () => {
    handleClose();
    window.open(
      `https://www.facebook.com/sharer/sharer.php?u=${window.location.href}`,
      '_blank'
    );
  };

  const handleShareToTwitter = () => {
    handleClose();
    window.open(
      `https://twitter.com/intent/tweet?text=Check%20out%20this%20account%20on%20Artion&url=${window.location.href}`,
      '_blank'
    );
  };

  const goToTab = _tab => {
    tokens.current = [];
    bundles.current = [];
    likes.current = [];

    setTab(_tab);
  };

  const getActivity = async () => {
    try {
      setActivityLoading(true);
      const { data } = await getAccountActivity(uid);
      const _activities = [];

      data.bids.map(bActivity => _activities.push(bActivity));
      data.listings.map(lActivity => _activities.push(lActivity));
      data.offers.map(oActivity => _activities.push(oActivity));
      data.sold.map(sActivity => _activities.push(sActivity));

      _activities.sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1));
      _activities.map(item => {
        item.token = getTokenByAddress(item.paymentToken);
      });
      setActivities(_activities);
      setActivityLoading(false);
    } catch {
      setActivityLoading(false);
    }
  };

  const getOffersFromOthers = async () => {
    try {
      setOffersLoading(true);
      const { data } = await getActivityFromOthers(uid);
      data.sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1));
      data.map(item => {
        item.token = getTokenByAddress(item.paymentToken);
      });
      setOffers(data);
      setOffersLoading(false);
    } catch {
      setOffersLoading(false);
    }
  };

  const getOffers = async () => {
    try {
      setBidsLoading(true);
      const { data } = await getMyOffers(uid);
      data.sort((a, b) => (a.createdAt < b.createdAt ? 1 : -1));
      data.map(item => {
        item.token = getTokenByAddress(item.paymentToken);
      });
      setBids(data);
      setBidsLoading(false);
    } catch {
      setBidsLoading(false);
    }
  };

  const handleCopyAddress = () => {
    setCopied(true);
    setTimeout(() => {
      setCopied(false);
    }, 3000);
  };

  const handleMouseOver = () => {
    setTooltipOpen(true);
  };

  const handleMouseLeave = () => {
    setTooltipOpen(false);
    setCopied(false);
  };

  const selectBanner = () => {
    fileInput.current?.click();
  };

  const handleSelectFile = e => {
    if (e.target.files.length > 0) {
      const file = e.target.files[0];

      const reader = new FileReader();

      reader.onload = async function(e) {
        const { data } = await updateBanner(e.target.result, authToken);
        setBannerHash(data);
      };

      reader.readAsDataURL(file);
    }
    e.target.value = null;
  };

  const openAccountSettings = () => {
    dispatch(ModalActions.showAccountModal());
  };

  // const handleCreateBundle = () => {
  //   setBundleModalVisible(true);
  // };

  const fetchFollowers = async () => {
    setFollowersLoading(true);
    try {
      const { data } = await getFollowers(uid);
      followers.current = data;
    } catch {
      followers.current = [];
    }
    setFollowersLoading(false);
  };

  const fetchFollowings = async () => {
    setFollowersLoading(true);
    try {
      const { data } = await getFollowings(uid);
      followings.current = data;
    } catch {
      followings.current = [];
    }
    setFollowersLoading(false);
  };

  const showFollowers = () => {
    if (loading || !user.followers || user.followers === 0) return;

    setFollowersModalVisible(true);
    fetchFollowers();
  };

  const showFollowings = () => {
    if (loading || !user.followings || user.followings === 0) return;

    setFollowingsModalVisible(true);
    fetchFollowings();
  };

  const followUser = async () => {
    if (followingInProgress) return;

    if (account === undefined) {
      toast('error', 'Please connect your wallet!');
      return;
    }

    setFollowingInProgress(true);
    try {
      const { status, data } = await _followUser(uid, !following, authToken);
      if (status === 'success') {
        const { data } = await getUserAccountDetails(uid);
        setUser(data);
        setFollowing(!following);
      } else {
        toast('error', data);
      }
    } catch (e) {
      console.log(e);
    }
    setFollowingInProgress(false);
  };

  const formatDate = _date => {
    const date = new Date(_date);
    const diff = Math.floor((now - date.getTime()) / 1000);
    if (diff >= ONE_MONTH) {
      const m = Math.ceil(diff / ONE_MONTH);
      return `${m} Month${m > 1 ? 's' : ''} Ago`;
    }
    if (diff >= ONE_DAY) {
      const d = Math.ceil(diff / ONE_DAY);
      return `${d} Day${d > 1 ? 's' : ''} Ago`;
    }
    if (diff >= ONE_HOUR) {
      const h = Math.ceil(diff / ONE_HOUR);
      return `${h} Hour${h > 1 ? 's' : ''} Ago`;
    }
    if (diff >= ONE_MIN) {
      const h = Math.ceil(diff / ONE_MIN);
      return `${h} Min${h > 1 ? 's' : ''} Ago`;
    }
    return `${diff} Second${diff > 1 ? 's' : ''} Ago`;
  };

  if (!isAddress(uid)) {
    return <Redirect to="/404" />;
  }

  const renderMedia = image => {
    if (image?.includes('youtube')) {
      return (
        <ReactPlayer
          className={styles.mediaInner}
          url={image}
          controls={true}
          width="100%"
          height="100%"
        />
      );
    } else {
      return (
        <Suspense
          fallback={
            <Loader type="Oval" color="#007BFF" height={32} width={32} />
          }
        >
          <SuspenseImg className={styles.mediaInner} src={image} />
        </Suspense>
      );
    }
  };

  const renderTab = (label, Icon, idx, count, countLoading) => (
    <div
      className={cx(styles.tab, idx === tab && styles.selected)}
      onClick={() => goToTab(idx)}
    >
      <Icon className={styles.tabIcon} />
      <div className={styles.tabLabel}>{label}</div>
      <div className={styles.tabCount}>
        {countLoading ? (
          <Skeleton className={styles.tabCountLoading} width={40} height={22} />
        ) : (
          count
        )}
      </div>
    </div>
  );

  return (
    <div className={styles.container}>
      <Header border />
      <div className={styles.profile}>
        <div className={styles.banner}>
          {loading ? (
            <Skeleton width="100%" height={200} />
          ) : bannerHash || user.bannerHash ? (
            <img
              src={`https://cloudflare-ipfs.com/ipfs/${bannerHash ||
                user.bannerHash}`}
              className={styles.bannerImg}
            />
          ) : (
            <div className={styles.bannerPlaceholder} />
          )}
          {isMe && (
            <div className={styles.editBanner} onClick={selectBanner}>
              <input
                ref={fileInput}
                hidden
                type="file"
                onChange={handleSelectFile}
                accept="image/*"
              />
              <EditIcon className={styles.editIcon} />
            </div>
          )}
        </div>
        <div className={styles.buttonsWrapper}>
          {isMe && (
            <div className={styles.settings} onClick={openAccountSettings}>
              <img src={iconSettings} className={styles.settingsIcon} />
            </div>
          )}
          <div
            className={styles.settings}
            onClick={e => setAnchorEl(e.currentTarget)}
          >
            <img src={iconShare} className={styles.settingsIcon} />
          </div>
        </div>
        <div className={styles.wrapper}>
          <div className={styles.avatarWrapper}>
            {loading ? (
              <Skeleton width={160} height={160} className={styles.avatar} />
            ) : user.imageHash ? (
              <img
                src={`https://cloudflare-ipfs.com/ipfs/${user.imageHash}`}
                className={styles.avatar}
              />
            ) : (
              <Identicon className={styles.avatar} account={uid} size={160} />
            )}
          </div>
          <div className={styles.usernameWrapper}>
            {loading ? (
              <Skeleton width={120} height={24} />
            ) : (
              <div className={styles.username}>{user.alias || 'Unnamed'}</div>
            )}
            {isMe ? null : loading ? (
              <Skeleton width={80} height={26} style={{ marginLeft: 16 }} />
            ) : (
              <div
                className={cx(
                  styles.followBtn,
                  followingInProgress && styles.disabled
                )}
                onClick={followUser}
              >
                {followingInProgress ? (
                  <ClipLoader color="#FFF" size={14} />
                ) : following ? (
                  'Unfollow'
                ) : (
                  'Follow'
                )}
              </div>
            )}
          </div>
          <div className={styles.bio}>{user.bio || ''}</div>
          <div className={styles.bottomWrapper}>
            <div className={styles.addressWrapper}>
              {loading ? (
                <Skeleton width={120} height={20} />
              ) : (
                <Tooltip
                  title={copied ? 'Copied!' : 'Copy'}
                  open={tooltipOpen}
                  arrow
                  classes={{ tooltip: styles.tooltip }}
                >
                  <div className={styles.address}>{shortenAddress(uid)}</div>
                </Tooltip>
              )}
              <CopyToClipboard text={uid} onCopy={handleCopyAddress}>
                <div className={styles.copyIcon}>
                  <img
                    src={iconCopy}
                    onMouseOver={handleMouseOver}
                    onMouseLeave={handleMouseLeave}
                  />
                </div>
              </CopyToClipboard>
            </div>
            <div className={styles.followers} onClick={showFollowers}>
              {loading ? (
                <Skeleton width={100} height={24} />
              ) : (
                <>
                  <b>{formatFollowers(user.followers || 0)}</b> Followers
                </>
              )}
            </div>
            <div className={styles.followers} onClick={showFollowings}>
              {loading ? (
                <Skeleton width={100} height={24} />
              ) : (
                <>
                  <b>{formatFollowers(user.followings || 0)}</b> Following
                </>
              )}
            </div>
          </div>
        </div>
      </div>
      <div className={styles.content}>
        <div className={styles.contentSidebar}>
          <div className={styles.tabsGroup}>
            <div className={styles.groupTitle}>My Items</div>
            {renderTab(
              'Single Items',
              IconList,
              0,
              count,
              fetching || fguresFetching
            )}
            {/* {renderTab(
              'Bundles',
              IconBundle,
              1,
              bundleCount,
              bundleFetching || fguresFetching
            )} */}
            {renderTab(
              'Favorited',
              IconHeart,
              2,
              favCount,
              favFetching || fguresFetching
            )}
          </div>
          <div className={styles.tabsGroup}>
            <div className={styles.groupTitle}>Account</div>
            {renderTab('Activity', IconClock, 3)}
            {renderTab('Offers', IconList, 4)}
            {renderTab('My Offers', IconList, 5)}
          </div>
        </div>
        <div ref={ref} className={styles.contentBody} onScroll={handleScroll}>
          {tab === 0 ? (
            <NFTsGrid
              items={tokens.current}
              numPerRow={numPerRow}
              loading={fetching}
            />
          ) : // tab === 1 ? (
          //   <NFTsGrid
          //     items={bundles.current}
          //     numPerRow={numPerRow}
          //     loading={fetching}
          //     showCreate={isMe}
          //     onCreate={handleCreateBundle}
          //   />
          // ) :
          tab === 2 ? (
            <NFTsGrid
              items={likes.current}
              numPerRow={numPerRow}
              loading={fetching}
              onLike={() => {
                likes.current = [];
                fetchLikes(0);
              }}
            />
          ) : tab === 3 ? (
            <div className={styles.tableWapper}>
              <div className={styles.activityHeader}>
                <div className={styles.event}>Event</div>
                <div className={styles.name}>Item</div>
                <div className={styles.price}>Price</div>
                <div className={styles.quantity}>Quantity</div>
                <div className={styles.owner}>Owner</div>
                <div className={styles.date}>Date</div>
              </div>
              <div className={styles.activityList}>
                {(activityLoading ? new Array(5).fill(null) : activities).map(
                  (activity, idx) => (
                    <div key={idx} className={styles.activity}>
                      <div className={styles.event}>
                        {activity ? (
                          activity.event
                        ) : (
                          <Skeleton width={100} height={20} />
                        )}
                      </div>
                      {activity ? (
                        <Link
                          to={`/explore/${activity.contractAddress}/${activity.tokenID}`}
                          className={styles.name}
                        >
                          <div className={styles.media}>
                            {renderMedia(
                              activity.thumbnailPath.length > 10
                                ? `${storageUrl}/image/${activity.thumbnailPath}`
                                : activity.imageURL
                            )}
                          </div>
                          {activity.name}
                        </Link>
                      ) : (
                        <div className={styles.name}>
                          <Skeleton width={120} height={20} />
                        </div>
                      )}
                      <div className={styles.price}>
                        {activity ? (
                          <>
                            <div className={styles.tokenLogo}>
                              <img src={activity.token?.icon} />
                            </div>
                            {activity.price}
                          </>
                        ) : (
                          <Skeleton width={100} height={20} />
                        )}
                      </div>
                      <div className={styles.quantity}>
                        {activity ? (
                          activity.quantity
                        ) : (
                          <Skeleton width={80} height={20} />
                        )}
                      </div>
                      {activity ? (
                        activity.to ? (
                          <Link
                            to={`/account/${activity.to}`}
                            className={styles.owner}
                          >
                            <div className={styles.ownerAvatarWrapper}>
                              {activity.image ? (
                                <img
                                  src={`https://cloudflare-ipfs.com/ipfs/${activity.image}`}
                                  className={styles.ownerAvatar}
                                />
                              ) : (
                                <Identicon
                                  account={activity.to}
                                  size={24}
                                  className={styles.ownerAvatar}
                                />
                              )}
                            </div>
                            {activity.alias || shortenAddress(activity.to)}
                          </Link>
                        ) : (
                          <div className={styles.owner} />
                        )
                      ) : (
                        <div className={styles.owner}>
                          <Skeleton width={130} height={20} />
                        </div>
                      )}
                      <div className={styles.date}>
                        {activity ? (
                          formatDate(activity.createdAt)
                        ) : (
                          <Skeleton width={120} height={20} />
                        )}
                      </div>
                    </div>
                  )
                )}
              </div>
            </div>
          ) : tab === 4 ? (
            <>
              <div className={styles.activityHeader}>
                <div className={styles.name}>Item</div>
                <div className={styles.owner}>From</div>
                <div className={styles.price}>Price</div>
                <div className={styles.quantity}>Quantity</div>
                <div className={styles.date}>Date</div>
              </div>
              <div className={styles.activityList}>
                {(offersLoading
                  ? new Array(5).fill(null)
                  : offers.filter(
                      offer => offer.deadline * 1000 > now.getTime()
                    )
                ).map((offer, idx) => (
                  <div key={idx} className={styles.activity}>
                    {offer ? (
                      <Link
                        to={`/explore/${offer.contractAddress}/${offer.tokenID}`}
                        className={styles.name}
                      >
                        <div className={styles.media}>
                          {renderMedia(
                            offer.thumbnailPath.length > 10
                              ? `${storageUrl}/image/${offer.thumbnailPath}`
                              : offer.imageURL
                          )}
                        </div>
                        {offer.name}
                      </Link>
                    ) : (
                      <div className={styles.name}>
                        <Skeleton width={120} height={20} />
                      </div>
                    )}
                    {offer ? (
                      <Link
                        to={`/account/${offer.creator}`}
                        className={styles.owner}
                      >
                        <div className={styles.ownerAvatarWrapper}>
                          {offer.image ? (
                            <img
                              src={`https://cloudflare-ipfs.com/ipfs/${offer.image}`}
                              className={styles.ownerAvatar}
                            />
                          ) : (
                            <Identicon
                              account={offer.creator}
                              size={24}
                              className={styles.ownerAvatar}
                            />
                          )}
                        </div>
                        {offer.alias || shortenAddress(offer.creator)}
                      </Link>
                    ) : (
                      <div className={styles.owner}>
                        <Skeleton width={130} height={20} />
                      </div>
                    )}
                    <div className={styles.price}>
                      {offer ? (
                        <>
                          <div className={styles.tokenLogo}>
                            <img src={offer.token?.icon} />
                          </div>
                          {offer.pricePerItem}
                        </>
                      ) : (
                        <Skeleton width={100} height={20} />
                      )}
                    </div>
                    <div className={styles.quantity}>
                      {offer ? (
                        offer.quantity
                      ) : (
                        <Skeleton width={80} height={20} />
                      )}
                    </div>
                    <div className={styles.date}>
                      {offer ? (
                        formatDate(offer.createdAt)
                      ) : (
                        <Skeleton width={120} height={20} />
                      )}
                    </div>
                  </div>
                ))}
              </div>
            </>
          ) : (
            <>
              <div className={styles.activityHeader}>
                <div className={styles.name}>Item</div>
                <div className={styles.price}>Price</div>
                <div className={styles.quantity}>Quantity</div>
                <div className={styles.date}>Date</div>
              </div>
              <div className={styles.activityList}>
                {(bidsLoading
                  ? new Array(5).fill(null)
                  : bids.filter(bid => bid.deadline * 1000 > now.getTime())
                ).map((bid, idx) => (
                  <div key={idx} className={styles.activity}>
                    {bid ? (
                      <Link
                        to={`/explore/${bid.contractAddress}/${bid.tokenID}`}
                        className={styles.name}
                      >
                        <div className={styles.media}>
                          {renderMedia(
                            bid.thumbnailPath.length > 10
                              ? `${storageUrl}/image/${bid.thumbnailPath}`
                              : bid.imageURL
                          )}
                        </div>
                        {bid.name}
                      </Link>
                    ) : (
                      <div className={styles.name}>
                        <Skeleton width={120} height={20} />
                      </div>
                    )}
                    <div className={styles.price}>
                      {bid ? (
                        <>
                          <div className={styles.tokenLogo}>
                            <img src={bid.token?.icon} />
                          </div>
                          {bid.pricePerItem}
                        </>
                      ) : (
                        <Skeleton width={100} height={20} />
                      )}
                    </div>
                    <div className={styles.quantity}>
                      {bid ? bid.quantity : <Skeleton width={80} height={20} />}
                    </div>
                    <div className={styles.date}>
                      {bid ? (
                        formatDate(bid.createdAt)
                      ) : (
                        <Skeleton width={120} height={20} />
                      )}
                    </div>
                  </div>
                ))}
              </div>
            </>
          )}
        </div>
      </div>
      <Menu
        id="simple-menu"
        anchorEl={anchorEl}
        keepMounted
        open={Boolean(anchorEl)}
        onClose={handleClose}
        classes={{ paper: styles.shareMenu, list: styles.shareMenuList }}
        anchorOrigin={{
          vertical: 'bottom',
          horizontal: 'right',
        }}
        transformOrigin={{
          vertical: 'top',
          horizontal: 'right',
        }}
      >
        <CopyToClipboard text={window.location.href} onCopy={handleCopyLink}>
          <MenuItem classes={{ root: styles.menuItem }}>
            <img src={iconArtion} />
            Copy Link
          </MenuItem>
        </CopyToClipboard>
        <MenuItem
          classes={{ root: styles.menuItem }}
          onClick={handleShareOnFacebook}
        >
          <img src={iconFacebook} />
          Share on Facebook
        </MenuItem>
        <MenuItem
          classes={{ root: styles.menuItem }}
          onClick={handleShareToTwitter}
        >
          <img src={iconTwitter} />
          Share to Twitter
        </MenuItem>
      </Menu>
      <NewBundleModal
        visible={bundleModalVisible}
        onClose={() => setBundleModalVisible(false)}
        onCreateSuccess={() => {
          bundles.current = [];
          fetchNFTs();
        }}
      />
      <FollowersModal
        visible={followersModalVisible || followingsModalVisible}
        onClose={() => {
          setFollowersModalVisible(false);
          setFollowingsModalVisible(false);
        }}
        title={followersModalVisible ? 'Followers' : 'Followings'}
        users={
          followersLoading
            ? new Array(5).fill(null)
            : followersModalVisible
            ? followers.current
            : followings.current
        }
      />
    </div>
  );
}