@fortawesome/free-solid-svg-icons#faArrowDown JavaScript Examples

The following examples show how to use @fortawesome/free-solid-svg-icons#faArrowDown. 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: Tables.js    From volt-react-dashboard with MIT License 5 votes vote down vote up
PageVisitsTable = () => {
  const TableRow = (props) => {
    const { pageName, views, returnValue, bounceRate } = props;
    const bounceIcon = bounceRate < 0 ? faArrowDown : faArrowUp;
    const bounceTxtColor = bounceRate < 0 ? "text-danger" : "text-success";

    return (
      <tr>
        <th scope="row">{pageName}</th>
        <td>{views}</td>
        <td>${returnValue}</td>
        <td>
          <FontAwesomeIcon icon={bounceIcon} className={`${bounceTxtColor} me-3`} />
          {Math.abs(bounceRate)}%
        </td>
      </tr>
    );
  };

  return (
    <Card border="light" className="shadow-sm">
      <Card.Header>
        <Row className="align-items-center">
          <Col>
            <h5>Page visits</h5>
          </Col>
          <Col className="text-end">
            <Button variant="secondary" size="sm">See all</Button>
          </Col>
        </Row>
      </Card.Header>
      <Table responsive className="align-items-center table-flush">
        <thead className="thead-light">
          <tr>
            <th scope="col">Page name</th>
            <th scope="col">Page Views</th>
            <th scope="col">Page Value</th>
            <th scope="col">Bounce rate</th>
          </tr>
        </thead>
        <tbody>
          {pageVisits.map(pv => <TableRow key={`page-visit-${pv.id}`} {...pv} />)}
        </tbody>
      </Table>
    </Card>
  );
}
Example #2
Source File: previewlayout.js    From ActiveLearningStudio-react-client with GNU Affero General Public License v3.0 4 votes vote down vote up
PreviewLayout = (props) => {
  const { changeScreenHandler } = props;
  return (
    <div className="preview-layout-form">
      {/* <div className="preview-layout-back">
        <Link
          className="back-link"
          onClick={() => changeScreenHandler("addactivity")}
        >
          <FontAwesomeIcon icon="chevron-left" className="icon-link" />
          Back
        </Link>
      </div> */}
      <div className="preview-layout-tabs">
        <Tabs text="1. Select an activity" tabActive={true} />
        <Tabs text="2. Add activities to Layout" className="ml-10 mt-10" tabActive={true} />
        <Tabs text="3. Preview Activity" className="ml-10" tabActive={true} />
      </div>
      <div className="preview-layout-title-select">
        <div className="preview-layout-title">
          <HeadingTwo text="Interactive Video" color="#084892" />
        </div>

        {/* <div className="preview-layout-change-layout">
          <select>
            <option>Change Layout</option>
            <option>Interactive video</option>
            <option>Column layout</option>
            <option>Interactive book</option>
            <option>Course presentation</option>
            <option>Quiz</option>
            <option>Single activity</option>
          </select>
        </div> */}
      </div>
      <div className="preview-layout-card-project">
        <div className="preview-layout-dialogcard">
          <div className="dialogcard-subtitle">
            <HeadingThree text="Activity title" color="#084892" />
          </div>
          <div>
            <HeadingText text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam." />
          </div>
          <div className="preview-layout-panel">
            <div className="layout-panel">
              <HeadingThree text="First panel " color="#084892" />
              <FontAwesomeIcon icon="chevron-down" color="#084892" />
            </div>
            <div className="layout-panel mt-8">
              <HeadingThree text="Second panel " color="#084892" />
              <FontAwesomeIcon icon="chevron-down" color="#084892" />
            </div>
          </div>
          <div className="preview-layout-footer">
            <div className="footer-dowload">
              <p>
                <FontAwesomeIcon icon={faArrowDown} /> Download
              </p>
            </div>
            <div>
              <p>
                <FontAwesomeIcon icon={faAngleLeft} /> <FontAwesomeIcon icon={faAngleRight} />
                Embed
              </p>
            </div>
            <div>
              <img src={ExplanatoryH5P} />
            </div>
          </div>
          {/* <div className="dialogcard-subtitle">
            <HeadingText
              text="Dialog Card"
              color="#084892"
              className="subtitle-text"
            />
          </div>
          <div className="dialogcard-title">
            <HeadingTwo
              text="Activity Title"
              color="#084892"
              className="title-heading"
            />
            <HeadingThree
              text="Heading"
              color="#084892"
              className="sub-heading"
            />
          </div>
          <div className="detail-dialogcard">
            <div className="card-actvity">
              <img src={CarDImage} alt="" />
              <div>
                <FontAwesomeIcon
                  icon="volume-up"
                  className="card-actvity-icon"
                />
              </div>
              <HeadingThree
                text="Activity Title"
                className="card-actvity-title"
              />
              <Buttons
                icon="sync-alt"
                text="Turn"
                primary={true}
                width="96px"
                height="35px"
                className="card-actvity-btn"
              />
            </div>
          </div>
          <div className="card-pagination">
            <div className="pagination-text">
              <HeadingText text="Card 1 of 5" />
            </div>
            <div className="pagination-icon">
              <FontAwesomeIcon icon="angle-right" className="icon-next" />
            </div>
          </div> */}
        </div>
        <div className="preview-layout-project">
          <div className="project-title-link">
            <div className="project-title">
              <HeadingTwo text="Project: " color="#084892" className="project-heading" />
              <HeadingText text="Project title here" color="#515151" />
              <HeadingTwo text="Playlist:" color="#084892" className="playlist-heading" />
              <HeadingText text="Playlist name here" color="#515151" />
            </div>
            <div className="project-link">
              <Link className="get-link">
                {/* <FontAwesomeIcon icon="link" className="icon-link" />*/}
                Get link
              </Link>
            </div>
          </div>
          <div className="dialog-card-box">
            <img src={DialogCardImage} alt="" />
            <HeadingText text="Dialog Cards" color="#084892" className="ml-15" />
          </div>
          {/* <div className="add-more-activity">
            <div className="more-activity-icon">
              <FontAwesomeIcon icon="link" className="icon-link" />
            </div>
            <Link className="more-activity-link" to="/">
              Add More Activity
            </Link>
          </div> */}
          <div className="project-link-button">
            <Buttons text="Back to Editor" primary={true} width="126px" height="43px" hover={true} onClick={() => changeScreenHandler('addactivity')} />
            <Buttons text="Finish Layout" secondary={true} width="126px" height="43px" hover={true} onClick={() => changeScreenHandler('')} />
          </div>
        </div>
      </div>
    </div>
  );
}
Example #3
Source File: Popup.js    From gophie-web with MIT License 4 votes vote down vote up
render() {
    const { server } = this.props;

    return (
      <Modal
        show={this.props.show}
        onHide={() => this.props.onHide()}
        size="lg"
        aria-labelledby="contained-modal-title-vcenter"
        dialogClassName="dialog-theme"
        data-tour="my-fifth-step"
        centered
      >
        <Modal.Body className="gophie-modal">
          <section className="gophie-modal__img">
            <img
              src={
                this.props.movie.cover_photo_link === ""
                  ? "No image"
                  : this.props.movie.cover_photo_link
              }
              alt={this.props.movie.name}
            />

            {/* Video Stream Play Icon */}
            {this.state.play ? (
              <a
                id="stop-video"
                className="video-stop-button"
                href="/"
                onClick={this.handleStopRequest.bind(this)}
              >
                <span></span>{" "}
              </a>
            ) : (
              <div>
                {greekFromEnglish(server) === "Server2" ? null : (
                  <a
                    id="play-video"
                    className="video-play-button"
                    href="/"
                    onClick={this.handlePlayRequest.bind(this)}
                  >
                    <span> </span>{" "}
                  </a>
                )}
              </div>
            )}
            {/* Video Stream Play Icon */}
          </section>

          <section className="gophie-modal__body">
            <Modal.Header className="gophie-modal__body--header" closeButton>
              <Modal.Title id="contained-modal-title-vcenter">
                {this.props.movie.name}
              </Modal.Title>
            </Modal.Header>
            {this.state.play ? (
              <div>
                <div className="player-wrapper">
                  <ReactPlayer
                    url={this.props.movie.download_link}
                    className="react-player"
                    playing
                    playsinline
                    pip
                    controls
                    width="100%"
                    height="90%"
                  />
                </div>
                {greekFromEnglish(this.props.movie.engine) === "Alpha" ? (
                  <div className="player-error-alert">
                    <p className="player-error-message">
                      Streaming from alpha is problematic, suggest{" "}
                      <a
                        className="gophie-link"
                        href={this.props.movie.download_link}
                        target="_blank"
                        rel="noopener noreferrer"
                      >
                        downloading
                      </a>{" "}
                      instead
                    </p>
                  </div>
                ) : null}
                {isIOS ? (
                  <div className="player-error-alert">
                    <p className="player-error-message">
                      {" "}
                      iOS 10+ users might have to disable{" "}
                      <i>
                        <em>Low Power Mode</em>
                      </i>{" "}
                      to stream
                    </p>
                  </div>
                ) : null}
              </div>
            ) : (
              <section className="gophie-modal__body--body">
                <div className="gophie-modal-rating-container">
                  <div
                    className="gophie-modal-rating-container__average"
                    data-tour="my-seventh-step"
                  >
                    <div className="gophie-modal-rating-container__average--container">
                      <div className="gophie-modal-rating-container__average--container-item-1">
                        <p>
                          {this.state.ratings.average_ratings
                            ? Math.round(
                                this.state.ratings.average_ratings * 10
                              ) / 10
                            : 0}
                        </p>
                        <p>/5</p>
                      </div>

                      <p className="em-rate">
                        <span className="em-span">by</span>

                        {this.state.ratings.by
                          ? Math.round(this.state.ratings.by)
                          : 0}
                      </p>
                    </div>
                  </div>

                  <div
                    className="gophie-modal-rating-container__rate"
                    data-tour="my-sixth-step"
                  >
                    <p>Rate Movie</p>
                    <Rating
                      value={this.state.ip_rating}
                      max={5}
                      onChange={(value) => this.rateMovie(value)}
                    />
                  </div>
                </div>

                <div className="gophie-modal__body--description scollable-container">
                  {this.props.movie.description === ""
                    ? "Seems like the description for this movie is missing"
                    : this.props.movie.description}
                </div>
                <div>
                  <div></div>
                  {this.props.movie.name !== "AnimeOut" ? null : (
                    <div>
                      <div className="d-flex justify-content-between align-items-center w-100 mt-3">
                        <div>Episodes</div>
                        <FontAwesomeIcon icon={faArrowDown} />
                      </div>
                      <div className="scollable-container d-flex flex-column">
                        {this.state.episodeLink}
                      </div>
                    </div>
                  )}
                </div>
              </section>
            )}
          </section>
        </Modal.Body>
      </Modal>
    );
  }
Example #4
Source File: index.js    From Website with Apache License 2.0 4 votes vote down vote up
export default function Downloads() {
  const [releases, setReleases] = useState([]);

  useEffect(() => {
    async function getReleases() {
      const response = await fetch(
        "https://api.github.com/repos/PGMDev/PGM/releases"
      );

      return setReleases(await response.json());
    }

    getReleases();
  }, []);

  return (
    <Layout title="Downloads">
      <div className={classnames("container", styles.downloads_container)}>
        <h1 className={styles.downloads_title}>Downloads</h1>
        {releases.length === 0 ? (
          <div className={classnames("hero", styles.spinner_hero)}>
            <div className={styles.lds_ripple}>
              <div></div>
              <div></div>
            </div>
          </div>
        ) : (
          <div
            className={classnames(
              "hero",
              styles.downloads_hero,
              styles.appearing
            )}
          >
            <div className="container row">
              <div className="col">
                <div className="row">
                  <img src="/img/shield.png" className={styles.pgm_logo} />
                  <div className={styles.pgm}>
                    <h1>PGM {releases[0].name}</h1>
                    <p>
                      <label>
                        {" "}
                        {format(
                          new Date(releases[0].published_at),
                          "LLLL do, yyyy"
                        )}{" "}
                      </label>
                    </p>
                    <a href={releases[0].html_url}>
                      Changelog <FontAwesomeIcon icon={faAngleRight} />
                    </a>
                  </div>
                </div>
                <div className={styles.description}>
                  <p>
                    Minecraft multiplayer game-server suite for managing PvP
                    matches across various gamemodes
                  </p>
                </div>
              </div>
              <div className={classnames("col col--4", styles.col_border)}>
                <h2>Download PGM</h2>
                <p>
                  PvP Game Manager (PGM) is a plugin that manages running and
                  instancing multiple PvP maps across various gamemodes for
                  Minecraft multiplayer.
                </p>
                <a
                  className={classnames(
                    "button button--primary",
                    styles.download_button
                  )}
                  href={releases[0].assets[0].browser_download_url}
                >
                  Download <FontAwesomeIcon icon={faArrowDown} />
                </a>
              </div>
              <div className={classnames("col col--4", styles.col_margin_left)}>
                <h2>Download SportPaper</h2>
                <p>
                  SportPaper is a Minecraft server jar based on Paper 1.8 tuned
                  for maximum performance and high intensity PvP. It is
                  mandatory and should run alongside PGM.
                </p>
                <a
                  className={classnames(
                    "button button--primary",
                    styles.download_button
                  )}
                  href={releases[0].assets[1].browser_download_url}
                >
                  Download <FontAwesomeIcon icon={faArrowDown} />
                </a>
              </div>
            </div>
          </div>
        )}
        <div className={styles.others}>
          <h2 style={{ marginBottom: "-15px" }}>Other Resources</h2>
          <div className="row">
            <div className={classnames("col col--6", styles.column)}>
              <div className={classnames("hero", styles.others_hero)}>
                <div className="col">
                  <div className="row">
                    <div className="col col--6">
                      <div className="row">
                        <h1 className={styles.others_icon}>
                          <FontAwesomeIcon icon={faCalendarAlt} />
                        </h1>
                        <div className={styles.others_header}>
                          <h2>Events</h2>
                          <a href="https://github.com/PGMDev/Events/">
                            <label>GitHub</label>
                          </a>
                        </div>
                      </div>
                    </div>
                    <div className="col col--6">
                      <a
                        className={classnames(
                          "button button--primary",
                          styles.others_button
                        )}
                        href="https://github.com/PGMDev/Events/releases/latest"
                      >
                        Download <FontAwesomeIcon icon={faArrowDown} />
                      </a>
                    </div>
                  </div>
                  <div className={styles.others_description}>
                    <p>
                      Events is the official PGM plugin for managing PvP matches
                      in a competitive setting. Upon joining or cycling, all
                      team members are forced onto their respective teams.
                    </p>
                  </div>
                </div>
              </div>
            </div>
            <div className={classnames("col col--6", styles.column)}>
              <div className={classnames("hero", styles.others_hero)}>
                <div className="col">
                  <div className="row">
                    <div className="col col--6">
                      <div className="row">
                        <h1 className={styles.others_icon}>
                          <FontAwesomeIcon icon={faUsers} />
                        </h1>
                        <div className={styles.others_header}>
                          <h2>Community</h2>
                          <a href="https://github.com/PGMDev/Community/">
                            <label>GitHub</label>
                          </a>
                        </div>
                      </div>
                    </div>
                    <div className="col col--6">
                      <button
                        className={classnames(
                          "button disabled button--primary",
                          styles.others_button
                        )}
                      >
                        Coming Soon <FontAwesomeIcon icon={faArrowDown} />
                      </button>
                    </div>
                  </div>
                  <div className={styles.others_description}>
                    <p>
                      Community is a standalone plugin for managing PGM servers.
                      It includes various PGM features, such as punishments,
                      moderation, freezing and other aspects.
                    </p>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <hr style={{ marginTop: "40px", marginBottom: "10px" }} />
          <div className="row">
            <div className={classnames("col col--6", styles.column)}>
              <div className={classnames("hero", styles.others_hero)}>
                <div className="col">
                  <div className="row">
                    <div className="col col--6">
                      <div className="row">
                        <h1 className={styles.others_icon}>
                          <FontAwesomeIcon icon={faFolderOpen} />
                        </h1>
                        <div className={styles.others_header}>
                          <h2>ResourcePile</h2>
                          <a href="https://github.com/MCResourcePile">
                            <label>GitHub</label>
                          </a>
                        </div>
                      </div>
                    </div>
                    <div className="col col--6">
                      <a
                        className={classnames(
                          "button button--primary",
                          styles.others_button
                        )}
                        href="https://mcresourcepile.github.io"
                      >
                        Visit <FontAwesomeIcon icon={faFolderOpen} />
                      </a>
                    </div>
                  </div>
                  <div className={styles.others_description}>
                    <p>
                      ResourcePile is a community project which aims to provide
                      various collections of resources, such as maps or
                      statistics, for users with backgrounds in Overcast and
                      similar networks.
                    </p>
                  </div>
                </div>
              </div>
            </div>
            <div className={classnames("col col--6", styles.column)}>
              <div className={classnames("hero", styles.others_hero)}>
                <div className="col">
                  <div className="row">
                    <div className="col col--6">
                      <div className="row">
                        <h1 className={styles.others_icon}>
                          <FontAwesomeIcon icon={faCompass} />
                        </h1>
                        <div className={styles.others_header}>
                          <h2>PGM Tracker</h2>
                          <a href="https://pgm.fyi">
                            <label>Website</label>
                          </a>
                        </div>
                      </div>
                    </div>
                    <div className="col col--6">
                      <a
                        className={classnames(
                          "button button--primary",
                          styles.others_button
                        )}
                        href="https://pgm.fyi"
                      >
                        Visit <FontAwesomeIcon icon={faCompass} />
                      </a>
                    </div>
                  </div>
                  <div className={styles.others_description}>
                    <p>
                      PGM Tracker is a community tool made by{" "}
                      <a href="https://github.com/applenick">applenick</a> that
                      tracks public PGM servers. Take a look at it, play a
                      variety of Minecraft PvP maps and get involved with
                      development!
                    </p>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </Layout>
  );
}
Example #5
Source File: index.jsx    From loopring-swap with GNU General Public License v3.0 4 votes vote down vote up
Swapper = ({ onConnectWalletClick }) => {
    const { formatNumber } = useIntl();
    const dispatch = useDispatch();

    const {
        loopringAccount,
        loopringExchange,
        loopringWallet,
        supportedTokens,
        loadingSupportedTokens,
        loadingBalances,
        supportedMarkets,
        balances,
        loggedIn,
        swapData,
        loadingSwapData,
        loadingSwapSubmission,
    } = useSelector((state) => ({
        loopringAccount: state.loopring.account,
        loopringExchange: state.loopring.exchange,
        loopringWallet: state.loopring.wallet,
        supportedTokens: state.loopring.supportedTokens.data,
        loadingSupportedTokens: !!state.loopring.supportedTokens.loadings,
        loadingBalances: !!state.loopring.balances.loadings,
        supportedMarkets: state.loopring.supportedMarkets.data,
        balances: state.loopring.balances.data,
        loggedIn: !!state.loopring.account,
        swapData: state.loopring.swap.data,
        loadingSwapData: !!state.loopring.swap.loadings,
        loadingSwapSubmission: !!state.loopring.swapSubmission.loadings,
    }));

    const [fromToken, setFromToken] = useState(null);
    const [fromAmount, setFromAmount] = useState("");
    const [liquidityError, setLiquidityError] = useState(null);
    const [balanceError, setBalanceError] = useState(null);
    const [lessThanMinimumOrderError, setLessThanMinimumOrderError] = useState(
        null
    );
    const [moreThanMaximumOrderError, setMoreThanMaximumOrderError] = useState(
        null
    );
    const [toToken, setToToken] = useState(null);
    const [toAmount, setToAmount] = useState("");
    const [feeAmount, setFeeAmount] = useState("");
    const [filteredToTokens, setFilteredToTokens] = useState([]);
    const [compatibleMarkets, setCompatibleMarkets] = useState([]);
    const [changingToAmount, setChangingToAmount] = useState(false);
    const [changingFromAmount, setChangingFromAmount] = useState(false);
    const [selling, setSelling] = useState(false);
    const [flippedPriceNotation, setFlippedPriceNotation] = useState(false);

    const [debouncedGetSwapData] = useDebouncedCallback(
        (
            wallet,
            account,
            fromToken,
            toToken,
            fromAmount,
            supportedTokens,
            selling
        ) => {
            dispatch(
                getSwapData(
                    wallet,
                    account,
                    fromToken,
                    toToken,
                    fromAmount,
                    supportedTokens,
                    selling
                )
            );
        },
        500
    );

    useEffect(() => {
        if (loggedIn) {
            setFromAmount("");
            setToAmount("");
            dispatch(resetSwapData());
            setLiquidityError(false);
            setBalanceError(false);
            setLessThanMinimumOrderError(false);
            setMoreThanMaximumOrderError(false);
        }
    }, [dispatch, loggedIn]);

    // set ether as the default "from" token
    useEffect(() => {
        if (supportedTokens && supportedTokens.length > 0 && !fromToken) {
            setFromToken(
                supportedTokens.find((token) => token.symbol === "ETH")
            );
        }
    }, [fromToken, supportedTokens]);

    // on "from" token change, find out the compatible markets
    useEffect(() => {
        if (supportedMarkets && supportedMarkets.length > 0 && fromToken) {
            setCompatibleMarkets(
                supportedMarkets.filter(
                    (market) =>
                        market.quoteTokenId === fromToken.tokenId ||
                        market.baseTokenId === fromToken.tokenId
                )
            );
        }
    }, [fromToken, supportedMarkets]);

    // on "from" token change, we need to find the compatible "to" tokens based on available markets.
    // Plus, we reset the currently selected "to" token if it's not compatible with the current "from" one.
    useEffect(() => {
        if (supportedMarkets && supportedMarkets.length > 0 && fromToken) {
            const filteredToTokens = supportedTokens.filter(
                (token) =>
                    token.tokenId !== fromToken.tokenId &&
                    compatibleMarkets.find(
                        (market) =>
                            market.baseTokenId === token.tokenId ||
                            market.quoteTokenId === token.tokenId
                    )
            );
            if (
                filteredToTokens &&
                filteredToTokens.length > 0 &&
                toToken &&
                !filteredToTokens.find(
                    (token) => token.tokenId === toToken.tokenId
                )
            ) {
                setToToken(filteredToTokens[0]);
                setToAmount("");
            }
            setFilteredToTokens(filteredToTokens);
        }
    }, [
        compatibleMarkets,
        fromToken,
        supportedMarkets,
        supportedTokens,
        toToken,
    ]);

    // on valid "from" and "to" tokens setting, we need to find their current exchange rate
    useEffect(() => {
        if (
            supportedTokens &&
            supportedTokens.length > 0 &&
            fromToken &&
            toToken &&
            !liquidityError &&
            // when the exchange rate is used to calculate the expected to or from token amount,
            // and that is enforced on the component's state, this effect is invoked again and again
            // until the currently fetched exchange rate is the same as the previous.
            // In particularly traded markets, where the order book changes often, this produces an
            // annoying flickering effect. We avoid it by calculating from and to amounts only if
            // an actual user interacted with the form (NOT when the app updates the to and
            // from amounts after swap-details-related calculations)
            ((!changingFromAmount &&
                !changingToAmount &&
                fromAmount &&
                toAmount) ||
                (changingFromAmount && fromAmount) ||
                (changingToAmount && toAmount))
        ) {
            const tradedMarket = compatibleMarkets.find(
                (market) =>
                    (market.baseTokenId === toToken.tokenId &&
                        market.quoteTokenId === fromToken.tokenId) ||
                    (market.baseTokenId === fromToken.tokenId &&
                        market.quoteTokenId === toToken.tokenId)
            );
            if (!tradedMarket) {
                return;
            }
            debouncedGetSwapData(
                loopringWallet,
                loopringAccount,
                supportedTokens.find(
                    (token) => token.tokenId === tradedMarket.baseTokenId
                ),
                supportedTokens.find(
                    (token) => token.tokenId === tradedMarket.quoteTokenId
                ),
                fromAmount,
                supportedTokens,
                selling
            );
        }
    }, [
        loopringWallet,
        loopringAccount,
        changingFromAmount,
        changingToAmount,
        compatibleMarkets,
        debouncedGetSwapData,
        liquidityError,
        fromAmount,
        fromToken,
        selling,
        supportedTokens,
        toAmount,
        toToken,
    ]);

    // when the exchange rate is fetched, we need to calculate the expected
    // token amount to receive based on it
    useEffect(() => {
        if (
            swapData &&
            swapData.averageFillPrice &&
            fromToken &&
            toToken &&
            ((!changingFromAmount &&
                !changingToAmount &&
                fromAmount &&
                toAmount) ||
                (changingFromAmount && fromAmount) ||
                (changingToAmount && toAmount))
        ) {
            const referenceAmount = changingToAmount ? toAmount : fromAmount;
            let partialAmount = new BigNumber(referenceAmount);
            if (changingToAmount) {
                partialAmount = selling
                    ? partialAmount.dividedBy(swapData.averageFillPrice)
                    : partialAmount.multipliedBy(swapData.averageFillPrice);
            } else {
                partialAmount = selling
                    ? partialAmount.multipliedBy(swapData.averageFillPrice)
                    : partialAmount.dividedBy(swapData.averageFillPrice);
            }
            const newAmount = partialAmount.toFixed();
            let newFromAmount = fromAmount;
            let newToAmount = toAmount;
            if (changingToAmount && newAmount !== fromAmount) {
                // if the updated to amount is more than the maximum one based on
                // the order book, the maximum possible value is set
                newFromAmount = newAmount;
                setLiquidityError(
                    !!(
                        swapData.maximumAmount &&
                        new BigNumber(newAmount)
                            .dividedBy(swapData.averageFillPrice)
                            .isGreaterThan(swapData.maximumAmount)
                    )
                );
            } else if (!changingToAmount && newAmount !== toAmount) {
                // If the new from amount would bring, based on the current average
                // fill price, the to token amount to be bigger than the maximum allowed
                // quantity, the from amount is adjusted accordingly
                newToAmount = newAmount;
                setLiquidityError(
                    !!(
                        swapData.maximumAmount &&
                        swapData.maximumAmount.isLessThan(newAmount)
                    )
                );
            }
            setFromAmount(newFromAmount);
            const feeAmount = new BigNumber(newToAmount).multipliedBy(
                swapData.feePercentage
            );
            setToAmount(new BigNumber(newToAmount).minus(feeAmount).toFixed());
            setFeeAmount(feeAmount);
            setChangingFromAmount(false);
            setChangingToAmount(false);
        }
    }, [
        changingFromAmount,
        changingToAmount,
        fromAmount,
        fromToken,
        selling,
        swapData,
        toAmount,
        toToken,
    ]);

    // on "from" or "to" token changes, we need to determine if the user is buying or selling a given market.
    // We do this by checking if the corresponding market has the "from" token as a base or quote currency.
    // If the "from" token is a quote currency, the user is buying, and vice-versa.
    useEffect(() => {
        if (fromToken && toToken) {
            setSelling(
                !!compatibleMarkets.find(
                    (market) =>
                        market.baseTokenId === fromToken.tokenId &&
                        market.quoteTokenId === toToken.tokenId
                )
            );
        }
    }, [compatibleMarkets, fromToken, toToken]);

    useEffect(() => {
        if (
            (!fromAmount && toAmount && changingFromAmount) ||
            (!toAmount && fromAmount && changingToAmount)
        ) {
            setToAmount("");
            dispatch(resetSwapData());
            setLiquidityError(false);
            setBalanceError(false);
            setLessThanMinimumOrderError(false);
            setMoreThanMaximumOrderError(false);
        }
    }, [changingFromAmount, dispatch, changingToAmount, fromAmount, toAmount]);

    useEffect(() => {
        if (!fromToken || !toToken) {
            return;
        }
        const wrappedBalance = balances.find(
            (balance) => balance.id === fromToken.tokenId
        );
        const tokenMaximumExchangeBalance =
            wrappedBalance && wrappedBalance.balance;
        const bigNumberFromAmount = new BigNumber(fromAmount);
        const bigNumberToAmount = new BigNumber(toAmount);
        setBalanceError(
            !!(
                tokenMaximumExchangeBalance &&
                bigNumberFromAmount.isGreaterThan(tokenMaximumExchangeBalance)
            )
        );
        const fromTokenMinimumTradeVolume = weiToEther(
            new BigNumber(fromToken.minOrderAmount),
            fromToken.decimals
        );
        const toTokenMinimumTradeVolume = weiToEther(
            new BigNumber(toToken.minOrderAmount),
            toToken.decimals
        );
        setLessThanMinimumOrderError(
            !!(
                !bigNumberFromAmount.isZero() &&
                !bigNumberToAmount.isZero() &&
                (bigNumberFromAmount.isLessThan(fromTokenMinimumTradeVolume) ||
                    bigNumberToAmount.isLessThan(toTokenMinimumTradeVolume))
            )
        );
        const fromTokenMaximumTradeVolume = weiToEther(
            new BigNumber(fromToken.maxOrderAmount),
            fromToken.decimals
        );
        const toTokenMaximumTradeVolume = weiToEther(
            new BigNumber(toToken.maxOrderAmount),
            toToken.decimals
        );
        setMoreThanMaximumOrderError(
            !!(
                !bigNumberFromAmount.isZero() &&
                !bigNumberToAmount.isZero() &&
                (bigNumberFromAmount.isGreaterThan(
                    fromTokenMaximumTradeVolume
                ) ||
                    bigNumberToAmount.isGreaterThan(toTokenMaximumTradeVolume))
            )
        );
    }, [balances, fromAmount, fromToken, toAmount, toToken]);

    const handleFromAmountChange = useCallback((amount) => {
        setChangingToAmount(false);
        setChangingFromAmount(true);
        setFromAmount(amount);
    }, []);

    const handleToAmountChange = useCallback((weiAmount) => {
        setChangingToAmount(true);
        setChangingFromAmount(false);
        setToAmount(weiAmount);
    }, []);

    const handleSwap = useCallback(() => {
        dispatch(
            postSwap(
                loopringAccount,
                loopringWallet,
                loopringExchange,
                fromToken,
                fromAmount,
                toToken,
                toAmount,
                supportedTokens,
                selling
            )
        );
    }, [
        dispatch,
        fromAmount,
        fromToken,
        loopringAccount,
        loopringExchange,
        loopringWallet,
        selling,
        supportedTokens,
        toAmount,
        toToken,
    ]);

    const handleBalancesRefresh = useCallback(() => {
        if (
            loggedIn &&
            loopringAccount &&
            loopringWallet &&
            supportedTokens &&
            supportedTokens.length > 0
        ) {
            dispatch(
                getUserBalances(
                    loopringAccount,
                    loopringWallet,
                    supportedTokens
                )
            );
        }
    }, [dispatch, loggedIn, loopringAccount, loopringWallet, supportedTokens]);

    const handleAssetsInversion = useCallback(() => {
        if (fromToken && toToken) {
            setFromAmount("");
            setToAmount("");
            setFromToken(toToken);
            setToToken(fromToken);
            setLiquidityError(false);
            setBalanceError(false);
            setLessThanMinimumOrderError(false);
            setMoreThanMaximumOrderError(false);
            dispatch(resetSwapData());
        }
    }, [fromToken, toToken, dispatch]);

    const getErrorCause = () => {
        if (moreThanMaximumOrderError) {
            return "maximum";
        }
        if (liquidityError) {
            return "liquidity";
        }
        if (balanceError) {
            return "balance";
        }
        if (lessThanMinimumOrderError) {
            return "minimum";
        }
        return null;
    };

    const getPriceNotation = () => {
        let price;
        const priceFromToken = flippedPriceNotation ? fromToken : toToken;
        const priceToToken = flippedPriceNotation ? toToken : fromToken;
        if (selling) {
            price = flippedPriceNotation
                ? new BigNumber("1").dividedBy(swapData.averageFillPrice)
                : swapData.averageFillPrice;
        } else {
            price = flippedPriceNotation
                ? swapData.averageFillPrice
                : new BigNumber("1").dividedBy(swapData.averageFillPrice);
        }
        return `${formatNumber(price, {
            style: "decimal",
            maximumSignificantDigits: 4,
        })} ${priceFromToken.symbol} per ${priceToToken.symbol}`;
    };

    const handlePriceFlip = useCallback(() => {
        setFlippedPriceNotation(!flippedPriceNotation);
    }, [flippedPriceNotation]);

    return (
        <Flex flexDirection="column">
            <BackgroundFlex flexDirection="column" alignItems="center" mb={4}>
                <Box>
                    <TokenSpecifier
                        variant="from"
                        amount={fromAmount}
                        token={fromToken}
                        onAmountChange={handleFromAmountChange}
                        onBalancesRefresh={handleBalancesRefresh}
                        onTokenChange={setFromToken}
                        supportedTokens={supportedTokens}
                        balances={balances}
                        loadingSupportedTokens={loadingSupportedTokens}
                        loadingBalances={loadingBalances}
                        loggedIn={loggedIn}
                    />
                </Box>
                <PointableBox
                    display="flex"
                    justifyContent="center"
                    alignItems="center"
                    height={36}
                    p={2}
                    onClick={handleAssetsInversion}
                >
                    <ArrowIcon icon={faArrowDown} />
                </PointableBox>
                <Box mb="12px">
                    <TokenSpecifier
                        variant="to"
                        amount={toAmount}
                        token={toToken}
                        onAmountChange={handleToAmountChange}
                        onBalancesRefresh={handleBalancesRefresh}
                        onTokenChange={setToToken}
                        supportedTokens={filteredToTokens}
                        balances={balances}
                        loadingSupportedTokens={loadingSupportedTokens}
                        loadingBalances={loadingBalances}
                        loggedIn={loggedIn}
                    />
                </Box>
                <Flex
                    mb="8px"
                    justifyContent="space-between"
                    alignItems="center"
                    px={2}
                    height="12px"
                    width="100%"
                >
                    {(liquidityError ||
                        balanceError ||
                        lessThanMinimumOrderError ||
                        moreThanMaximumOrderError) && (
                        <>
                            <ErrorTextBox>
                                <FormattedMessage
                                    id={`swapper.error.amount.${getErrorCause()}`}
                                />
                            </ErrorTextBox>
                            <ErrorTextBox>
                                <FontAwesomeIcon icon={faExclamationTriangle} />
                            </ErrorTextBox>
                        </>
                    )}
                </Flex>
                <Flex
                    mb="8px"
                    justifyContent="space-between"
                    alignItems="center"
                    px={2}
                    width="100%"
                >
                    <Box>
                        <FormattedMessage id="swapper.price" />
                    </Box>
                    <Box>
                        {loadingSwapData ? (
                            <Spinner size={12} />
                        ) : swapData && swapData.averageFillPrice ? (
                            <Flex>
                                <Box mr="4px">{getPriceNotation()}</Box>
                                <PointableBox onClick={handlePriceFlip}>
                                    <PriceFlipIcon icon={faRandom} />
                                </PointableBox>
                            </Flex>
                        ) : (
                            "-"
                        )}
                    </Box>
                </Flex>
                <Flex
                    mb="8px"
                    justifyContent="space-between"
                    alignItems="center"
                    px={2}
                    width="100%"
                >
                    <Box>
                        <FormattedMessage id="swapper.slippage" />
                    </Box>
                    <Box>
                        {loadingSwapData ? (
                            <Spinner size={12} />
                        ) : swapData && swapData.slippagePercentage ? (
                            <SlippageText>
                                {formatNumber(swapData.slippagePercentage, {
                                    style: "decimal",
                                    maximumSignificantDigits: 4,
                                })}
                                %
                            </SlippageText>
                        ) : (
                            "-"
                        )}
                    </Box>
                </Flex>
                <Flex
                    justifyContent="space-between"
                    alignItems="center"
                    px={2}
                    width="100%"
                >
                    <Box>
                        <FormattedMessage id="swapper.fee" />
                    </Box>
                    <Box>
                        {feeAmount && feeAmount.isGreaterThan("0")
                            ? `${formatNumber(feeAmount, {
                                  style: "decimal",
                                  maximumSignificantDigits: 4,
                              })} ${toToken.symbol}`
                            : "-"}
                    </Box>
                </Flex>
            </BackgroundFlex>
            <Box display="flex" justifyContent="center" mb={4}>
                <Button
                    faIcon={loggedIn ? faExchangeAlt : faLockOpen}
                    size="large"
                    loading={loggedIn && loadingSwapSubmission}
                    disabled={
                        loggedIn &&
                        (liquidityError ||
                            balanceError ||
                            lessThanMinimumOrderError ||
                            moreThanMaximumOrderError ||
                            !fromToken ||
                            !fromAmount ||
                            fromAmount === "0" ||
                            !toToken ||
                            !toAmount ||
                            toAmount === "0")
                    }
                    onClick={loggedIn ? handleSwap : onConnectWalletClick}
                >
                    <FormattedMessage
                        id={`swapper.action.${loggedIn ? "swap" : "connect"}`}
                    />
                </Button>
            </Box>
        </Flex>
    );
}
Example #6
Source File: Navigation.jsx    From jitsi-party with MIT License 4 votes vote down vote up
render() {
    const onClick = this.props.onClick;
    const { north, south, east, west } = this.props.directions || {};

    const mapButtonClass = this.props.showMapTooltip
      ? "map-button animated"
      : "map-button";
    const pokeButtonClass = this.state.showPokeOptions
      ? "poke-button focused"
      : "poke-button";

    const room = this.props.currentRoom.room;
    const audio = this.props.rooms[room].audio;
    const roomType = this.props.rooms[room].type;
    const events = this.props.events;
    const users = _.flatten(Object.values(this.props.users));

    const handleClickMap = () => this.props.handleOpenModal("map");
    const handleClickEvents = () => this.props.handleOpenModal("events");
    const handleClickEmail = () => this.props.handleOpenModal("email");

    return (
      <div className="navigation-container">
        <div className="column settings-container">
          <div className="map-button-container">
            {this.props.showMapButton && !this.props.hideSettings && (
              <button
                className={mapButtonClass}
                title={Config.tooltips.map}
                disabled={false}
                onClick={handleClickMap}
              >
                <FontAwesomeIcon icon={faMap} />
              </button>
            )}
            {/* {this.props.showMapTooltip &&
                            <div className="map-tooltip">you have unlocked the party map!</div>
                        } */}
          </div>
          <div className="events-button-container">
            {events && events.length > 0 && !this.props.hideSettings && (
              <button
                className="events-button"
                title={Config.tooltips.events}
                onClick={handleClickEvents}
              >
                <FontAwesomeIcon icon={faCalendar} />
              </button>
            )}
          </div>
          <div className="email-button-container">
            {Config.moderation &&
              !_.isEmpty(Config.moderation.moderatorEmails) && (
                <button
                  className="email-button"
                  title={Config.tooltips.moderator}
                  onClick={handleClickEmail}
                >
                  <FontAwesomeIcon icon={faEnvelope} />
                </button>
              )}
          </div>
          {roomType.toUpperCase() === "CHATSTREAM" &&
          this.props.currentRoom.entered &&
          !this.props.hideSettings ? (
            <div className="chat-button-container">
              <button
                className={mapButtonClass}
                title={Config.tooltips.chat}
                disabled={false}
                onClick={() =>
                  this.setState({ hideChat: !this.state.hideChat })
                }
              >
                <FontAwesomeIcon icon={faCommentAlt} />
              </button>
            </div>
          ) : null}
          <div className="poke-button-container">
            {Config.poke &&
              this.props.isPokingUnlocked &&
              !this.props.hideSettings && (
                <button
                  className={pokeButtonClass}
                  title={Config.tooltips.poke}
                  onClick={this.handleClickPokeButton.bind(this)}
                >
                  <FontAwesomeIcon icon={Config.poke.fontAwesomeIcon} />
                </button>
              )}
            {this.state.showPokeOptions && (
              <PokeOptions
                users={users}
                handlePoke={this.handlePoke.bind(this)}
              />
            )}
          </div>
          <div className="audio-button-container">
            {audio && (
              <AudioPlayer
                src={audio.path}
                autoPlay={audio.autoPlay}
                hide={audio.hideControls}
                onChange={this.handleAudioChanged.bind(this)}
              ></AudioPlayer>
            )}
          </div>
        </div>
        <div className="column">
          <button
            className="west"
            disabled={!west}
            onClick={() => onClick(west)}
          >
            <FontAwesomeIcon icon={faArrowLeft} />
            <span className="navigation-room-name">
              {_.get(this.props.rooms[west], "name")}
            </span>
          </button>
        </div>
        <div className="column">
          <button
            className="north"
            disabled={!north}
            onClick={() => onClick(north)}
          >
            <FontAwesomeIcon icon={faArrowUp} />
            <span className="navigation-room-name">
              {_.get(this.props.rooms[north], "name")}
            </span>
          </button>
          <button
            className="south"
            disabled={!south}
            onClick={() => onClick(south)}
          >
            <FontAwesomeIcon icon={faArrowDown} />
            <span className="navigation-room-name">
              {_.get(this.props.rooms[south], "name")}
            </span>
          </button>
        </div>
        <div className="column">
          <button
            className="east"
            disabled={!east}
            onClick={() => onClick(east)}
          >
            <FontAwesomeIcon icon={faArrowRight} />
            <span className="navigation-room-name">
              {_.get(this.props.rooms[east], "name")}
            </span>
          </button>
        </div>
        <div className="column column-avatar">
          <div className="puck-wrapper">
            <img
              src={
                Config.avatars[this.props.user.avatar.type].images[
                  this.props.user.avatar.color
                ]
              }
            />
          </div>
        </div>
      </div>
    );
  }