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

The following examples show how to use @fortawesome/free-solid-svg-icons#faExclamationTriangle. 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: AlertPanel.jsx    From ashteki with GNU Affero General Public License v3.0 6 votes vote down vote up
AlertPanel = ({ type = AlertType.Info, title, message, noIcon = false, children }) => {
    let icon;
    /**
     * @type {AlertType}
     */
    let alertType;

    switch (type) {
        case AlertType.Warning:
            icon = faExclamationTriangle;
            alertType = 'warning';
            break;
        case AlertType.Danger:
            icon = faExclamationCircle;
            alertType = 'danger';
            break;
        case AlertType.Info:
            icon = faInfoCircle;
            alertType = 'info';
            break;
        case AlertType.Success:
            icon = faCheckCircle;
            alertType = 'success';
            break;
    }

    return (
        <Alert variant={alertType}>
            {title && <Alert.Heading>{title}</Alert.Heading>}
            {!noIcon && <FontAwesomeIcon icon={icon} />}
            {message && <span id='alert-message'>&nbsp;{getMessageWithLinks(message)}</span>}
            {children && <span>&nbsp;{children}</span>}
        </Alert>
    );
}
Example #2
Source File: Icon.js    From mailmask with GNU Affero General Public License v3.0 6 votes vote down vote up
ICONS = {
  bars: faBars,
  'check-circle': faCheckCircle,
  'chevron-down': faChevronDown,
  'chevron-right': faChevronRight,
  'exchange-alt': faExchangeAlt,
  exclamation: faExclamation,
  'exclamation-triangle': faExclamationTriangle,
  info: faInfo,
  moon: faMoon,
  question: faQuestion,
  rss: faRss,
  'sign-in-alt': faSignInAlt,
  sun: faSun,
  snowflake: faSnowflake,
  star: faStar,
  'times-circle': faTimesCircle,
  user: faUser,
}
Example #3
Source File: index.jsx    From loopring-swap with GNU General Public License v3.0 6 votes vote down vote up
InvalidChainId = () => {
    const [chainName, setChainName] = useState("");

    useEffect(() => {
        let chainName;
        switch (CHAIN_ID) {
            case 1: {
                chainName = "mainnet";
                break;
            }
            case 5: {
                chainName = "Goerli";
                break;
            }
            default: {
                chainName = "unknown";
            }
        }
        setChainName(chainName);
    }, []);

    return (
        <Flex flexDirection="column" alignItems="center">
            <Box mb="20px">
                <StyledFontAwesomeIcon icon={faExclamationTriangle} />
            </Box>
            <Box textAlign="center">
                <Text>
                    <FormattedMessage
                        id="invalid.chain.id.message"
                        values={{ chainName }}
                    />
                </Text>
            </Box>
        </Flex>
    );
}
Example #4
Source File: Alert.jsx    From frontend-app-support-tools with GNU Affero General Public License v3.0 6 votes vote down vote up
function getAlertIcon(type) {
  if (type === 'error') {
    return faExclamationTriangle;
  }
  if (type === 'danger') {
    return faMinusCircle;
  }
  if (type === 'success') {
    return faCheckCircle;
  }
  return faInfoCircle;
}
Example #5
Source File: Demo404.jsx    From react-lte with MIT License 6 votes vote down vote up
Demo404 = () => {
  return (
    <>
      <LteContentHeader title='404 Error Page' />
      <LteContent>
        <div className='error-page'>
          <LteText tag='h2' color='warning' className='headline'>
            404
          </LteText>

          <div className='error-content'>
            <h3>
              <FontAwesomeIcon icon={faExclamationTriangle} className='text-warning' />
              <span> Oops! Page not found.</span>
            </h3>
            <p>
              <span>We could not find the page you were looking for. Meanwhile, you may </span>
              <Link to='/'>may return to dashboard</Link>
              <span> or try using the search form.</span>
            </p>

            <Form className='search-form'>
              <InputGroup>
                <Input type='text' placeholder='Search' />
                <InputGroupAddon addonType='append'>
                  <Button type='submit' name='submit' color='warning'>
                    <FontAwesomeIcon icon={faSearch} />
                  </Button>
                </InputGroupAddon>
              </InputGroup>
            </Form>
          </div>
        </div>
      </LteContent>
    </>
  );
}
Example #6
Source File: fontawesome.js    From xmrig-workers with GNU General Public License v3.0 5 votes vote down vote up
export default function () {
  library.add(faGithub, faWindows, faLinux, faTwitter, faReddit, faTelegram, faCheckCircle, faMicrochip, faTrashAlt,
    faPaperPlane, faSpinner, faFlask, faInfoCircle, faPen, faTools, faCheck, faPlus, faCog, faExclamationTriangle,
    faQuestionCircle, faSyncAlt, faInfinity, faDownload, faCopy, faPlug, faTimesCircle);
}
Example #7
Source File: details.js    From amazon-next with MIT License 4 votes vote down vote up
export default function Details({ product, error }) {
    const dispatch = useDispatch();
    const isSelected = useSelector(state =>
        state.cart.products.find(
            selectedProduct => selectedProduct.id === product.id
        )
    );

    const stars = useMemo(() => {
        const initial = [];
        for (let i = 1; i < product.stars; i += 1) {
            initial.push(
                <FontAwesomeIcon
                    key={i}
                    size="lg"
                    className="w-5"
                    icon={faStar}
                    color="#e69d3f"
                />
            );
        }

        return initial;
    }, [product.stars]);

    const liked = useSelector(state =>
        state.user.likedProducts.find(
            likedProduct => likedProduct.id === product.id
        )
    );

    function handleCart() {
        if (isSelected) return dispatch(removeFromCartRequest(product.id));
        return dispatch(addToCartRequest(product));
    }

    function handleLike() {
        dispatch(likeProductRequest(product));
    }

    return (
        <Layout>
            <motion.div
                className={`product-details h-screen px-12 py-8 flex flex-col ${error &&
                    'justify-center items-center'}`}
                exit={{ opacity: 0 }}
                initial={{ opacity: 0 }}
                animate={{ opacity: 1 }}
            >
                {error ? (
                    <span className="text-xl text-center">
                        {' '}
                        <FontAwesomeIcon
                            icon={faExclamationTriangle}
                            color="red"
                        />{' '}
                        There was an error while consulting the products{' '}
                    </span>
                ) : (
                    <motion.div className="flex flex-col lg:grid grid-cols-2 h-full py-12 lg:py-0">
                        <div className="h-full flex flex-col">
                            <Link href="/">
                                <div className="cursor-pointer transition-shadows duration-300 hover:shadow shadow-lg mb-5 lg:mb-0  rounded-full text-gray-500 w-12 h-12 flex items-center justify-center p-8">
                                    <FontAwesomeIcon
                                        icon={faArrowLeft}
                                        size="lg"
                                    />
                                </div>
                            </Link>
                            <motion.img
                                src={product.image}
                                alt={product.name}
                                aria-label={product.name}
                                title={product.name}
                                initial={{ opacity: 0, x: -40 }}
                                animate={{ opacity: 1, x: 0 }}
                                exit={{ opacity: 0, x: -40 }}
                                transition={{ delay: 0.2 }}
                                className="lg:my-12 mx-0 h-300 max-w-480 self-center"
                            />
                        </div>
                        <motion.div
                            variants={stagger}
                            className="h-full flex flex-col justify-between pr-8"
                        >
                            <motion.header
                                initial="fadeup"
                                animate="normal"
                                exit="exit"
                            >
                                <motion.h1
                                    variants={fadeUp}
                                    className="text-2xl mb-2 text-gray-800 font-bold"
                                >
                                    {product.name}
                                </motion.h1>
                                <motion.div
                                    variants={fadeUp}
                                    className="flex flex-row"
                                >
                                    {stars}{' '}
                                    <span className="ml-2 font-light text-yellow-burn">
                                        1540 reviews
                                    </span>
                                </motion.div>
                                <motion.p
                                    variants={fadeUp}
                                    className="text-md text-gray-500 mt-8"
                                >
                                    <DangerousHTML html={product.description} />
                                </motion.p>
                            </motion.header>
                            <motion.footer
                                variants={fadeUp}
                                initial="fadeup"
                                animate="normal"
                                exit="exit"
                                className="flex flex-col lg:flex-row w-full justify-between  pt-5 pb-8"
                            >
                                <div className="flex flex-col">
                                    <span className="text-gray-500">
                                        Best price
                                    </span>
                                    <strong className="text-3xl text-gray-800">
                                        ${product.price / 100}
                                    </strong>
                                </div>

                                <div className="flex flex-row items-center mt-5 lg:mt-0">
                                    <Button
                                        className="font-bold text-xl px-12 flex items-center justify-center lg:w-300 box-border"
                                        title="Add to cart"
                                        handleClick={handleCart}
                                    >
                                        {' '}
                                        {isSelected
                                            ? 'Remove from cart'
                                            : 'Add to cart'}
                                    </Button>
                                    <motion.button
                                        className="ml-5 border-none bg-none outline-none"
                                        type="button"
                                        title="Save to my list"
                                        onClick={handleLike}
                                        whileTap={{ y: -10 }}
                                    >
                                        {liked ? (
                                            <FontAwesomeIcon
                                                size="lg"
                                                icon={faHeart}
                                                className="text-blue-500 hover:text-blue-600 transition-colors duration-500"
                                            />
                                        ) : (
                                            <FontAwesomeIcon
                                                size="lg"
                                                icon={faHeartRegular}
                                                className="text-blue-500 hover:text-blue-600 transition-colors duration-500"
                                            />
                                        )}
                                    </motion.button>
                                </div>
                            </motion.footer>
                        </motion.div>
                    </motion.div>
                )}
            </motion.div>
        </Layout>
    );
}
Example #8
Source File: index.js    From amazon-next with MIT License 4 votes vote down vote up
function Home({ productList, error }) {
    return (
        <Layout>
            {!error && Object.keys(productList).length > 0 ? (
                <motion.div
                    initial={{ opacity: 0 }}
                    animate={{
                        opacity: 1,
                        transition: { staggerChildren: 5 },
                    }}
                    exit={{ opacity: 1 }}
                    className="w-full py-16 px-5 lg:py-0 lg:px-0"
                >
                    <motion.div
                        variants={slide}
                        initial="initial"
                        animate="slidein"
                        exit="slideout"
                        key="technology"
                        className="mb-8 w-full"
                    >
                        <motion.h2
                            variants={slide}
                            initial="initial"
                            animate="slidein"
                            exit="slideout"
                            className="text-2xl mb-2 lg:pr-8 pr-0 text-gray-800 font-bold"
                        >
                            {' '}
                            Computers and Accessories{' '}
                        </motion.h2>
                        <ProductList
                            type="computersAndAccessories"
                            productList={productList}
                        />
                    </motion.div>
                    <motion.div
                        variants={slide}
                        initial="initial"
                        animate="slidein"
                        exit="slideout"
                        key="videogames"
                        className="w-full my-8"
                    >
                        <motion.h2
                            variants={slide}
                            initial="initial"
                            animate="slidein"
                            exit="slideout"
                            className="text-2xl mb-2 lg:pr-8 pr-0 text-gray-800 font-bold"
                        >
                            {' '}
                            Video Games{' '}
                        </motion.h2>
                        <ProductList
                            type="videoGames"
                            productList={productList}
                        />
                    </motion.div>

                    <motion.div
                        variants={slide}
                        initial="initial"
                        animate="slidein"
                        exit="slideout"
                        key="topsellers"
                        transition="transition"
                        className="w-full pb-5"
                    >
                        <motion.h2
                            variants={slide}
                            initial="initial"
                            animate="slidein"
                            exit="slideout"
                            className="text-2xl mb-2 lg:pr-8 pr-0 text-gray-800 font-bold"
                        >
                            {' '}
                            Amazon Top Sellers{' '}
                        </motion.h2>
                        <ProductList
                            type="topSellers"
                            productList={productList}
                        />
                    </motion.div>
                </motion.div>
            ) : (
                <span className="text-xl text-center">
                    {' '}
                    <FontAwesomeIcon
                        icon={faExclamationTriangle}
                        color="red"
                    />{' '}
                    There was an error while consulting the products{' '}
                </span>
            )}
        </Layout>
    );
}
Example #9
Source File: index.jsx    From loopring-swap with GNU General Public License v3.0 4 votes vote down vote up
TokenModal = ({
    loading,
    open,
    onClose,
    onRefresh,
    onChange,
    supportedTokens,
    balances,
    selected,
    loggedIn,
}) => {
    const { formatMessage, formatNumber } = useIntl();
    const contentRef = useRef(null);

    const [searchTerm, setSearchTerm] = useState("");
    const [tokenDataset, setTokenDataset] = useState(supportedTokens);

    useEffect(() => {
        let dataset = supportedTokens;
        if (searchTerm) {
            dataset = dataset.filter(({ symbol, name, address }) => {
                const lowerCasedSearchTerm = searchTerm.toLowerCase();
                return (
                    symbol.toLowerCase().includes(lowerCasedSearchTerm) ||
                    name.toLowerCase().includes(lowerCasedSearchTerm) ||
                    address.toLowerCase().includes(lowerCasedSearchTerm)
                );
            });
        }
        if (balances) {
            dataset = dataset.sort(
                ({ address: firstAddress }, { address: secondAddress }) => {
                    const wrappedFirstTokenBalance = balances.find(
                        (balance) => balance.address === firstAddress
                    );
                    const wrappedSecondTokenBalance = balances.find(
                        (balance) => balance.address === secondAddress
                    );
                    const firstTokenBalance = new BigNumber(
                        wrappedFirstTokenBalance &&
                        wrappedFirstTokenBalance.balance
                            ? wrappedFirstTokenBalance.balance
                            : "0"
                    );
                    const secondTokenBalance = new BigNumber(
                        wrappedSecondTokenBalance &&
                        wrappedSecondTokenBalance.balance
                            ? wrappedSecondTokenBalance.balance
                            : "0"
                    );
                    return secondTokenBalance
                        .minus(firstTokenBalance)
                        .toNumber();
                }
            );
        }
        setTokenDataset(dataset);
    }, [searchTerm, supportedTokens, balances]);

    const getClickHandler = (token) => () => {
        onChange(token);
        handleLocalClose();
    };

    const handleLocalClose = useCallback(() => {
        onClose();
        setTimeout(() => {
            setTokenDataset(supportedTokens);
            setSearchTerm("");
        }, OPEN_CLOSE_ANIMATION_DURATION);
    }, [onClose, supportedTokens]);

    const handleLocalCloseOnOutsideClick = useCallback(
        (event) => {
            if (!contentRef.current.contains(event.target)) {
                handleLocalClose();
            }
        },
        [handleLocalClose]
    );

    const handleSearchTermChange = useCallback((event) => {
        setSearchTerm(event.target.value);
    }, []);

    return (
        <>
            <FullScreenOverlay open={open} />
            <RootFlex open={open} onClick={handleLocalCloseOnOutsideClick}>
                <ContentFlex
                    ref={contentRef}
                    maxWidth="440px"
                    flexDirection="column"
                >
                    <SearchFlex mt="4px">
                        <Box mr={3}>
                            <FontAwesomeIcon icon={faSearch} />
                        </Box>
                        <Box flex={1}>
                            <Input
                                value={searchTerm}
                                onChange={handleSearchTermChange}
                                placeholder={formatMessage({
                                    id: "token.modal.searchbar.placeholder",
                                })}
                            />
                        </Box>
                        {loggedIn && (
                            <PointableBox ml={3} p={2} minWidth="auto">
                                <FontAwesomeIcon
                                    icon={faSync}
                                    onClick={onRefresh}
                                />
                            </PointableBox>
                        )}
                        <PointableBox ml={3} p={2}>
                            <FontAwesomeIcon
                                icon={faTimes}
                                onClick={handleLocalClose}
                            />
                        </PointableBox>
                    </SearchFlex>
                    {loading ? (
                        <Flex justifyContent="center" mb={4} mt={2}>
                            <Box>
                                <Spinner size={40} />
                            </Box>
                        </Flex>
                    ) : (
                        <>
                            <ListFlex
                                flexDirection="column"
                                px="12px"
                                py="12px"
                            >
                                {tokenDataset.length > 0 ? (
                                    tokenDataset.map((token) => {
                                        const { address, symbol, name } = token;
                                        const currentlySelected =
                                            selected === token;
                                        const wrappedBalance = balances.find(
                                            (balance) =>
                                                balance.address === address
                                        );
                                        const etherBalance = new BigNumber(
                                            wrappedBalance &&
                                            wrappedBalance.balance
                                                ? wrappedBalance.balance
                                                : "0"
                                        );
                                        return (
                                            <RowFlex
                                                key={address}
                                                alignItems="center"
                                                py={16}
                                                pl="12px"
                                                pr="16px"
                                                onClick={getClickHandler(token)}
                                                selected={currentlySelected}
                                            >
                                                <Box mr={3}>
                                                    <TokenIcon
                                                        address={address}
                                                        size={32}
                                                    />
                                                </Box>
                                                <Flex
                                                    alignItems="center"
                                                    justifyContent="space-between"
                                                    flex={1}
                                                >
                                                    <Flex flexDirection="column">
                                                        <PrimaryTextBox
                                                            mb="2px"
                                                            selected={
                                                                currentlySelected
                                                            }
                                                        >
                                                            {symbol}
                                                        </PrimaryTextBox>
                                                        <SecondaryTextBox
                                                            selected={
                                                                currentlySelected
                                                            }
                                                        >
                                                            {name}
                                                        </SecondaryTextBox>
                                                    </Flex>
                                                    <Box>
                                                        {etherBalance.isZero()
                                                            ? "-"
                                                            : formatNumber(
                                                                  etherBalance,
                                                                  {
                                                                      style:
                                                                          "decimal",
                                                                      maximumSignificantDigits: 4,
                                                                  }
                                                              )}
                                                    </Box>
                                                </Flex>
                                            </RowFlex>
                                        );
                                    })
                                ) : (
                                    <Flex
                                        flexDirection="column"
                                        alignItems="center"
                                        my={3}
                                        px={3}
                                    >
                                        <Box mb={3}>
                                            <EmptyIcon
                                                icon={faExclamationTriangle}
                                            />
                                        </Box>
                                        <EmptyTextBox textAlign="center" mb={3}>
                                            <FormattedMessage id="token.modal.empty" />
                                        </EmptyTextBox>
                                    </Flex>
                                )}
                            </ListFlex>
                        </>
                    )}
                </ContentFlex>
            </RootFlex>
        </>
    );
}
Example #10
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 #11
Source File: SearchResult.js    From covid-19-mask-map with MIT License 4 votes vote down vote up
function SearchResult() {
    const { t, i18n } = useTranslation();

    const {
        mapObj,
        maskStores,
        setMaskStores,
        centerCoord,
        setCenterCoord,
    } = useMaskData();
    const { addColorIndicatorMarkers, resetMarker } = useNaverMapsMarkers();

    const [isLoading, setIsLoading] = useState(false);
    const [dataError, setDataError] = useState(false);
    const [showBetaAlert, setShowBetaAlert] = useState(true);

    const [markerFilter, setMarkerFilter] = useState({
        plenty: true,
        some: true,
        few: true,
        empty: false,
    });

    const setNewMaskStores = useCallback(
        (data) => {
            const priority = [
                "plenty",
                "some",
                "few",
                "empty",
                "break",
                null,
                undefined,
            ];
            data.sort(
                (a, b) =>
                    priority.indexOf(a.remain_stat) -
                    priority.indexOf(b.remain_stat)
            );
            setMaskStores(data);
        },
        [setMaskStores]
    );

    const markerFilterCheckboxHandler = (e) => {
        let target = e.target;
        console.log(target);
        setMarkerFilter((prev) => {
            return {
                ...prev,
                [target.name]: target.checked,
            };
        });
    };

    useEffect(() => {
        console.log(markerFilter);
    }, [markerFilter]);

    useEffect(() => {
        const fetchStoresByGeo = async (loc, range) => {
            const serverUrl = `https://8oi9s0nnth.apigw.ntruss.com/corona19-masks/v1/storesByGeo/json?lat=${loc.lat}&lng=${loc.lng}&m=${range}`;

            let result;
            try {
                setIsLoading(true);
                result = await axios(serverUrl);
                setIsLoading(false);
            } catch (error) {
                console.error("An error occurred in fetchStoresByGeo:", error);
                setDataError(true);
                setIsLoading(false);
                throw Error("Failed");
            }
            return result.data.stores;
        };

        const fn = async () => {
            resetMarker();
            console.log("Fetching store data...");
            let data;
            try {
                data = await fetchStoresByGeo(centerCoord, 5000);
                console.log(`New store data fetched`);
                console.log(data);
                resetMarker();
                setNewMaskStores(data);
            } catch {
                console.error("Failed to fetch data");
            }
        };

        fn();
    }, [centerCoord, setNewMaskStores]);

    useEffect(() => {
        if (mapObj) {
            mapObj.setCenter(centerCoord);
            mapObj.setZoom(14);
        }
    }, [mapObj, centerCoord]);

    useEffect(() => {
        if (!mapObj) {
            return;
        }

        addColorIndicatorMarkers(mapObj, maskStores);
    }, [maskStores, mapObj, addColorIndicatorMarkers]);

    const onClickMapRelocate = () => {
        const newCenter = mapObj.getCenter();
        setCenterCoord({
            lat: newCenter.y,
            lng: newCenter.x,
        });
    };

    const getAlternateMaskText = useCallback(() => {
        const today = new Date();
        const day = today.getDay();

        if (day === 0 || day === 6) {
            // Weekend
            return t("maskBuyAlertWeekend");
        } else {
            // Weekday
            return t("maskBuyAlertWeekday", {
                dayOfWeek: t(`dayOfWeek.${alternateMaskDays[day].weekday}`),
                digits: alternateMaskDays[day].availableDigits.join(", "),
            });
        }
    }, [i18n]);

    return (
        <>
            <main>
                <Container id="mainContainer">
                    <Row>
                        <Col sm={12}>
                            {showBetaAlert && (
                                <Alert
                                    variant="warning"
                                    onClose={() => setShowBetaAlert(false)}
                                    dismissible>
                                    <FontAwesomeIcon
                                        icon={faExclamationTriangle}
                                    />{" "}
                                    {t("notice.publicMaskShutdown")}
                                </Alert>
                            )}
                        </Col>
                    </Row>
                    <Row>
                        <Col md={6}>
                            {/* <Card style={{ marginBottom: "5px" }}>
                                <Card.Body className="p-1">
                                    {getAlternateMaskText()}
                                </Card.Body>
                            </Card> */}
                            <MapPanel />
                            <Button
                                variant="outline-primary"
                                className="mt-1 mb-1"
                                block
                                onClick={onClickMapRelocate}>
                                <FontAwesomeIcon icon={faLocationArrow} />{" "}
                                {t("refreshMapStores")}
                            </Button>
                        </Col>
                        <Col md={6}>
                            {dataError && (
                                <Alert variant="danger" className="mt-1">
                                    <FontAwesomeIcon
                                        icon={faExclamationTriangle}
                                    />{" "}
                                    {t("error.failedToLoadData")}
                                </Alert>
                            )}
                            <div className="border p-1 mb-1 d-flex flex-row justify-content-between">
                                <div class="form-check">
                                    <input
                                        type="checkbox"
                                        disabled
                                        class="form-check-input"
                                        id="showPlentyStores"
                                        name="plenty"
                                        defaultChecked={markerFilter.plenty}
                                        value={markerFilter.plenty}
                                        onChange={markerFilterCheckboxHandler}
                                    />
                                    <label
                                        class="form-check-label"
                                        htmlFor="showPlentyStores">
                                        <RemainingStockBadge remainingStockStr="plenty" />{" "}
                                        100개 +
                                    </label>
                                </div>
                                <div class="form-check">
                                    <input
                                        type="checkbox"
                                        disabled
                                        class="form-check-input"
                                        id="showSomeStores"
                                        name="some"
                                        defaultChecked={markerFilter.some}
                                        value={markerFilter.some}
                                        onChange={markerFilterCheckboxHandler}
                                    />
                                    <label
                                        class="form-check-label"
                                        for="showSomeStores">
                                        <RemainingStockBadge remainingStockStr="some" />{" "}
                                        30-100
                                    </label>
                                </div>
                                <div class="form-check">
                                    <input
                                        type="checkbox"
                                        disabled
                                        class="form-check-input"
                                        id="showFewStores"
                                        name="few"
                                        defaultChecked={markerFilter.few}
                                        value={markerFilter.few}
                                        onChange={markerFilterCheckboxHandler}
                                    />
                                    <label
                                        class="form-check-label"
                                        for="showFewStores">
                                        <RemainingStockBadge remainingStockStr="few" />{" "}
                                        2-30
                                    </label>
                                </div>
                                <div class="form-check">
                                    <input
                                        type="checkbox"
                                        disabled
                                        class="form-check-input"
                                        id="showEmptyStores"
                                        name="empty"
                                        defaultChecked={markerFilter.empty}
                                        value={markerFilter.empty}
                                        onChange={markerFilterCheckboxHandler}
                                    />
                                    <label
                                        class="form-check-label"
                                        for="showEmptyStores">
                                        <RemainingStockBadge remainingStockStr="empty" />{" "}
                                        0개
                                    </label>
                                </div>
                            </div>

                            {isLoading ? (
                                <Spinner animation="border" role="status">
                                    <span className="sr-only">Loading...</span>
                                </Spinner>
                            ) : maskStores && maskStores.length ? (
                                <>
                                    <MaskStoreTable
                                        style={{
                                            overflow: "auto",
                                            maxHeight: "100px",
                                        }}
                                    />
                                </>
                            ) : (
                                <Alert variant="danger">
                                    주변에 마스크 판매처가 없습니다. 지도를
                                    이동한 후 지도 아래의 재검색 버튼을 이용해
                                    주세요.
                                </Alert>
                            )}
                        </Col>
                    </Row>
                </Container>
            </main>
        </>
    );
}