@chakra-ui/react#Switch TypeScript Examples

The following examples show how to use @chakra-ui/react#Switch. 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: SwitchControl.tsx    From openchakra with MIT License 6 votes vote down vote up
SwitchControl: React.FC<SwitchControlPropsType> = ({ name, label }) => {
  const { setValue } = useForm()
  const value = usePropsSelector(name)

  return (
    <FormControl label={label} htmlFor={name}>
      <Switch
        name={name}
        id={name}
        size="sm"
        isChecked={value || false}
        onChange={() => setValue(name, !value)}
      />
    </FormControl>
  )
}
Example #2
Source File: Setup.tsx    From bluebubbles-server with Apache License 2.0 5 votes vote down vote up
NavBar = (): JSX.Element => {
    const { colorMode, toggleColorMode } = useColorMode();

    return (
        <Flex
            height="20"
            alignItems="center"
            borderBottomWidth="1px"
            borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
            justifyContent='space-between'
            p={4}
            pl={6}
        >
            <Flex alignItems="center" justifyContent='flex-start'>
                <img src={logo} className="logo" alt="logo" height={48} />
                <Text fontSize="1xl" ml={2}>BlueBubbles</Text>
            </Flex>
            <Flex justifyContent='flex-end'>
                <HStack spacing={{ base: '0', md: '1' }}>
                    <Tooltip label="Website Home" aria-label="website-tip">
                        <Link href="https://bluebubbles.app" style={{ textDecoration: 'none' }} target="_blank">
                            <IconButton size="lg" variant="ghost" aria-label="website" icon={<AiOutlineHome />} />
                        </Link>
                    </Tooltip>
                    <Tooltip label="BlueBubbles Web" aria-label="website-tip">
                        <Link href="https://bluebubbles.app/web" style={{ textDecoration: 'none' }} target="_blank">
                            <IconButton size="lg" variant="ghost" aria-label="bluebubbles web" icon={<FiMessageCircle />} />
                        </Link>
                    </Tooltip>
                    <Tooltip label="Support Us" aria-label="donate-tip">
                        <Link href="https://bluebubbles.app/donate" style={{ textDecoration: 'none' }} target="_blank">
                            <IconButton size="lg" variant="ghost" aria-label="donate" icon={<MdOutlineAttachMoney />} />
                        </Link>
                    </Tooltip>
                    <Tooltip label="Join our Discord" aria-label="discord-tip">
                        <Link href="https://discord.gg/yC4wr38" style={{ textDecoration: 'none' }} target="_blank">
                            <IconButton size="lg" variant="ghost" aria-label="discord" icon={<FaDiscord />} />
                        </Link>
                    </Tooltip>
                    <Tooltip label="Read our Source Code" aria-label="github-tip">
                        <Link href="https://github.com/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
                            <IconButton size="lg" variant="ghost" aria-label="github" icon={<FiGithub />} />
                        </Link>
                    </Tooltip>
                    <Spacer />
                    <Divider orientation="vertical" width={1} height={15} borderColor='gray' />
                    <Spacer />
                    <Spacer />
                    <Spacer />
                    <FormControl display='flex' alignItems='center'>
                        <Box mr={2}><MdOutlineDarkMode size={20} /></Box>
                        <Switch id='theme-mode-toggle' onChange={toggleColorMode} isChecked={colorMode === 'light'} />
                        <Box ml={2}><MdOutlineLightMode size={20} /></Box>
                    </FormControl>
                </HStack>
            </Flex>
        </Flex>
    );
}
Example #3
Source File: index.tsx    From formik-chakra-ui with MIT License 5 votes vote down vote up
SwitchControl: FC<SwitchControlProps> = React.forwardRef(
  (props: SwitchControlProps, ref: React.ForwardedRef<HTMLInputElement>) => {
    const { name, label, switchProps, ...rest } = props;
    const [field, { error, touched }] = useField(name);

    return (
      <Box
        css={css`
          .chakra-form__label {
            margin-bottom: 0;
          }
          .chakra-switch {
            display: flex;
            align-items: center;
            margin-right: 0.75rem;
          }
          .chakra-form__error-message {
            margin-top: 0;
          }
        `}
      >
        <FormControl
          name={name}
          label={label}
          as={Flex}
          alignItems="center"
          {...rest}
        >
          <Switch
            {...field}
            id={name}
            isInvalid={!!error && touched}
            isChecked={field.value}
            ref={ref}
            {...switchProps}
          />
        </FormControl>
      </Box>
    );
  }
)
Example #4
Source File: TrackStreamOptionsSelector.tsx    From takeout-app with MIT License 5 votes vote down vote up
TrackStreamOptionsSelector: React.FC<Props> = ({
  track,
  streamOptionsState: [options, setOptions],
  instance,
}) => {
  const handleOnChange = (key: "caption" | "interpretation") => {
    return (e: React.ChangeEvent<HTMLInputElement>) => {
      const newOptions = { ...options, [`${key}`]: e.target.checked };
      setOptions(newOptions);
    };
  };
  const enAndJa = (track.card?.topic?.labels?.indexOf("EN & JA") ?? -1) !== -1;
  const interpretationLabel = enAndJa ? "English track" : "Japanese to English interpretation";
  return (
    <Box>
      <Stack direction={["row", "row", "row", "column"]} spacing={0}>
        <Tooltip label="Caption (English only)" aria-label="">
          <FormControl display="flex" alignItems="center" h="30px">
            <FormLabel htmlFor={`TrackStreamOptions_${instance}__CC`} aria-hidden="true" m={0} mr={1}>
              <ClosedCaptionIcon w="24px" h="24px" />
            </FormLabel>
            <Switch
              aria-label="Closed Caption"
              id={`TrackStreamOptions_${instance}__CC`}
              isChecked={options.caption}
              onChange={handleOnChange("caption")}
            />
          </FormControl>
        </Tooltip>

        {track.interpretation && track.card?.interpretation ? (
          <Tooltip label={interpretationLabel} aria-label="">
            <FormControl display="flex" alignItems="center" h="30px">
              <FormLabel htmlFor={`TrackStreamOptions_${instance}__interpret`} aria-hidden="true" m={0} mr={1}>
                <TranslateIcon w="24px" h="24px" />
              </FormLabel>
              <Switch
                aria-label={interpretationLabel}
                id={`TrackStreamOptions_${instance}__interpret`}
                isChecked={options.interpretation}
                onChange={handleOnChange("interpretation")}
              />
            </FormControl>
          </Tooltip>
        ) : null}
      </Stack>
    </Box>
  );
}
Example #5
Source File: Navigation.tsx    From bluebubbles-server with Apache License 2.0 4 votes vote down vote up
MobileNav = ({ onOpen, onNotificationOpen, unreadCount, ...rest }: MobileProps) => {
    const { colorMode, toggleColorMode } = useColorMode();

    return (
        <Flex
            ml={{ base: 0, md: 60 }}
            px={{ base: 4, md: 4 }}
            height="20"
            alignItems="center"
            borderBottomWidth="1px"
            borderBottomColor={useColorModeValue('gray.200', 'gray.700')}
            justifyContent={{ base: 'space-between', md: 'flex-end' }}
            {...rest}
        >
            <IconButton
                display={{ base: 'flex', md: 'none' }}
                onClick={onOpen}
                variant="outline"
                aria-label="open menu"
                icon={<FiMenu />}
            />

            <Text display={{ base: 'flex', md: 'none' }} fontSize="2xl" fontFamily="monospace" fontWeight="bold">
                <img src={logo} className="logo-small" alt="logo" />
            </Text>

            <HStack spacing={{ base: '0', md: '1' }}>
                <Tooltip label="Website Home" aria-label="website-tip">
                    <Link href="https://bluebubbles.app" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="website" icon={<AiOutlineHome />} />
                    </Link>
                </Tooltip>
                <Tooltip label="BlueBubbles Web" aria-label="website-tip">
                    <Link href="https://bluebubbles.app/web" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="bluebubbles web" icon={<FiMessageCircle />} />
                    </Link>
                </Tooltip>
                <Tooltip label="Sponsor Us" aria-label="sponsor-tip">
                    <Link href="https://github.com/sponsors/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="donate" icon={<AiOutlineHeart />} />
                    </Link>
                </Tooltip>
                <Tooltip label="Support Us" aria-label="donate-tip">
                    <Link href="https://bluebubbles.app/donate" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="donate" icon={<MdOutlineAttachMoney />} />
                    </Link>
                </Tooltip>
                <Tooltip label="Join our Discord" aria-label="discord-tip">
                    <Link href="https://discord.gg/yC4wr38" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="discord" icon={<FaDiscord />} />
                    </Link>
                </Tooltip>
                <Tooltip label="Read our Source Code" aria-label="github-tip">
                    <Link href="https://github.com/BlueBubblesApp" style={{ textDecoration: 'none' }} target="_blank">
                        <IconButton size="lg" variant="ghost" aria-label="github" icon={<FiGithub />} />
                    </Link>
                </Tooltip>
                <Box position='relative' float='left'>
                    <IconButton
                        size="lg"
                        verticalAlign='middle'
                        zIndex={1}
                        variant="ghost"
                        aria-label="notifications"
                        icon={<FiBell />}
                        onClick={() => onNotificationOpen()}
                    />
                    {(unreadCount > 0) ? (
                        <Badge
                            borderRadius='lg'
                            variant='solid'
                            colorScheme='red'
                            position='absolute'
                            margin={0}
                            top={1}
                            right={1}
                            zIndex={2}
                        >{unreadCount}</Badge>
                    ) : null}
                </Box>
                <Spacer />
                <Divider orientation="vertical" width={1} height={15} borderColor='gray' />
                <Spacer />
                <Spacer />
                <Spacer />
                <FormControl display='flex' alignItems='center'>
                    <Box mr={2}><MdOutlineDarkMode size={20} /></Box>
                    <Switch id='theme-mode-toggle' onChange={toggleColorMode} isChecked={colorMode === 'light'} />
                    <Box ml={2}><MdOutlineLightMode size={20} /></Box>
                </FormControl>
            </HStack>
        </Flex>
    );
}
Example #6
Source File: FusePoolCreatePage.tsx    From rari-dApp with GNU Affero General Public License v3.0 4 votes vote down vote up
PoolConfiguration = () => {
  const { t } = useTranslation();
  const toast = useToast();
  const { fuse, address } = useRari();
  const navigate = useNavigate();

  const { isOpen, onOpen, onClose } = useDisclosure();

  const [name, setName] = useState("");
  const [isWhitelisted, setIsWhitelisted] = useState(false);
  const [whitelist, setWhitelist] = useState<string[]>([]);

  const [closeFactor, setCloseFactor] = useState(50);
  const [liquidationIncentive, setLiquidationIncentive] = useState(8);

  const [isUsingMPO, setIsUsingMPO] = useState(true)
  const [customOracleAddress, setCustomOracleAddress] = useState('')

  const [isCreating, setIsCreating] = useState(false);

  const [activeStep, setActiveStep] = useState<number>(0);

  const increaseActiveStep = (step: string) => {
    setActiveStep(steps.indexOf(step));
  };

  const [needsRetry, setNeedsRetry] = useState<boolean>(false);
  const [retryFlag, setRetryFlag] = useState<number>(1);

  const [deployedPriceOracle, setDeployedPriceOracle] = useState<string>("");

  const postDeploymentHandle = (priceOracle: string) => {
    setDeployedPriceOracle(priceOracle);
  };

  const deployPool = async (
    bigCloseFactor: string,
    bigLiquidationIncentive: string,
    options: any,
    priceOracle: string
  ) => {
    const [poolAddress] = await fuse.deployPool(
      name,
      isWhitelisted,
      bigCloseFactor,
      
      bigLiquidationIncentive,
      priceOracle,
      {},
      options,
      isWhitelisted ? whitelist : null
    );

    return poolAddress;
  };

  const onDeploy = async () => {
    let priceOracle = deployedPriceOracle;

    if (name === "") {
      toast({
        title: "Error!",
        description: "You must specify a name for your Fuse pool!",
        status: "error",
        duration: 2000,
        isClosable: true,
        position: "top-right",
      });

      return;
    }

    if (isWhitelisted && whitelist.length < 2 ) {
      toast({
        title: "Error!",
        description: "You must add an address to your whitelist!",
        status:"error",
        duration: 2000,
        isClosable: true,
        position: "top-right",
      })

      return
    }

    if (!isUsingMPO && !fuse.web3.utils.isAddress(customOracleAddress)) {
      
      toast({
        title: "Error!",
        description: "You must add an address for your oracle or use the default oracle.",
        status:"error",
        duration: 2000,
        isClosable: true,
        position: "top-right",
      })

      return
  }


    setIsCreating(true);
    onOpen();

    // 50% -> 0.5 * 1e18
    const bigCloseFactor = new BigNumber(closeFactor)
      .dividedBy(100)
      .multipliedBy(1e18)
      .toFixed(0);

    // 8% -> 1.08 * 1e8
    const bigLiquidationIncentive = new BigNumber(liquidationIncentive)
      .dividedBy(100)
      .plus(1)
      .multipliedBy(1e18)
      .toFixed(0);

    let _retryFlag = retryFlag;

    try {
      const options = { from: address };

      setNeedsRetry(false);

      if (!isUsingMPO && _retryFlag === 1) {
        _retryFlag = 2;
        priceOracle = customOracleAddress
      }

      if (_retryFlag === 1) {
        priceOracle = await fuse.deployPriceOracle(
          "MasterPriceOracle",
          {
            underlyings: [],
            oracles: [],
            canAdminOverwrite: true,
            defaultOracle:
              Fuse.PUBLIC_PRICE_ORACLE_CONTRACT_ADDRESSES.MasterPriceOracle, // We give the MasterPriceOracle a default "fallback" oracle of the Rari MasterPriceOracle
          },
          options
        );
        postDeploymentHandle(priceOracle);
        increaseActiveStep("Deploying Pool!");
        _retryFlag = 2;
      }

      let poolAddress: string;

      if (_retryFlag === 2) {
        poolAddress = await deployPool(
          bigCloseFactor,
          bigLiquidationIncentive,
          options,
          priceOracle
        );

        const event = (
          await fuse.contracts.FusePoolDirectory.getPastEvents(
            "PoolRegistered",
            {
              fromBlock: (await fuse.web3.eth.getBlockNumber()) - 10,
              toBlock: "latest",
            }
          )
        ).filter(
          (event) =>
            event.returnValues.pool.comptroller.toLowerCase() ===
            poolAddress.toLowerCase()
        )[0];

        LogRocket.track("Fuse-CreatePool");

        toast({
          title: "Your pool has been deployed!",
          description: "You may now add assets to it.",
          status: "success",
          duration: 2000,
          isClosable: true,
          position: "top-right",
        });

        let id = event.returnValues.index;
        onClose();
        navigate(`/fuse/pool/${id}/edit`);
      }
    } catch (e) {
      handleGenericError(e, toast);
      setRetryFlag(_retryFlag);
      setNeedsRetry(true);
    }
  };

  return (
    <>
      <TransactionStepperModal
        handleRetry={onDeploy}
        needsRetry={needsRetry}
        activeStep={activeStep}
        isOpen={isOpen}
        onClose={onClose}
      />
      <DashboardBox width="100%" mt={4}>
        <Column mainAxisAlignment="flex-start" crossAxisAlignment="flex-start">
          <Heading size="sm" px={4} py={4}>
            {t("Create Pool")}
          </Heading>

          <ModalDivider />

          <OptionRow>
            <Text fontWeight="bold" mr={4}>
              {t("Name")}
            </Text>
            <Input
              width="20%"
              value={name}
              onChange={(event) => setName(event.target.value)}
            />
          </OptionRow>

          <ModalDivider />

          <ModalDivider />

          <OptionRow>
            <SimpleTooltip
              label={t(
                "If enabled you will be able to limit the ability to supply to the pool to a select group of addresses. The pool will not show up on the 'all pools' list."
              )}
            >
              <Text fontWeight="bold">
                {t("Whitelisted")} <QuestionIcon ml={1} mb="4px" />
              </Text>
            </SimpleTooltip>

            <Switch
              h="20px"
              isChecked={isWhitelisted}
              onChange={() => {
                setIsWhitelisted((past) => !past);
                // Add the user to the whitelist by default
                if (whitelist.length === 0) {
                  setWhitelist([address]);
                }
              }}
              className="black-switch"
              colorScheme="#121212"
            />
          </OptionRow>

          {isWhitelisted ? (
            <WhitelistInfo
              whitelist={whitelist}
              addToWhitelist={(user) => {
                setWhitelist((past) => [...past, user]);
              }}
              removeFromWhitelist={(user) => {
                setWhitelist((past) =>
                  past.filter(function (item) {
                    return item !== user;
                  })
                );
              }}
            />
          ) : null}

          <ModalDivider />

          <OptionRow>
            <SimpleTooltip
              label={t(
                "The percent, ranging from 0% to 100%, of a liquidatable account's borrow that can be repaid in a single liquidate transaction. If a user has multiple borrowed assets, the closeFactor applies to any single borrowed asset, not the aggregated value of a user’s outstanding borrowing. Compound's close factor is 50%."
              )}
            >
              <Text fontWeight="bold">
                {t("Close Factor")} <QuestionIcon ml={1} mb="4px" />
              </Text>
            </SimpleTooltip>

            <SliderWithLabel
              value={closeFactor}
              setValue={setCloseFactor}
              formatValue={formatPercentage}
              min={5}
              max={90}
            />
          </OptionRow>

          <ModalDivider />

          <OptionRow>
            <SimpleTooltip
              label={t(
                "The additional collateral given to liquidators as an incentive to perform liquidation of underwater accounts. For example, if the liquidation incentive is 10%, liquidators receive an extra 10% of the borrowers collateral for every unit they close. Compound's liquidation incentive is 8%."
              )}
            >
              <Text fontWeight="bold">
                {t("Liquidation Incentive")} <QuestionIcon ml={1} mb="4px" />
              </Text>
            </SimpleTooltip>

            <SliderWithLabel
              value={liquidationIncentive}
              setValue={setLiquidationIncentive}
              formatValue={formatPercentage}
              min={0}
              max={50}
            />
          </OptionRow>

          <ModalDivider />

          <OptionRow>
            <SimpleTooltip
              label={t(
                "We will deploy a price oracle for your pool. This price oracle will contain price feeds for popular ERC20 tokens."
              )}
            >
              <Text fontWeight="bold">
                {isUsingMPO ? t("Default Price Oracle") : t("Custom Price Oracle")} <QuestionIcon ml={1} mb="4px" />
              </Text>
            </SimpleTooltip>

            <Box display="flex" alignItems='flex-end' flexDirection="column"> 
              <Checkbox
                isChecked={isUsingMPO}
                onChange={(e) => setIsUsingMPO(!isUsingMPO)}
                marginBottom={3}
              />
              {
                !isUsingMPO ? (
                  <>
                  <Input 
                    value={customOracleAddress}
                    onChange={(e) => setCustomOracleAddress(e.target.value)}
                  />
                  <Text mt={3} opacity="0.6" fontSize="sm">
                    Please make sure you know what you're doing.
                  </Text>
                  </>
                ) 
                : null
              }
              
            </Box>
          </OptionRow>
        </Column>
      </DashboardBox>

      <DashboardBox
        width="100%"
        height="60px"
        mt={4}
        py={3}
        fontSize="xl"
        as="button"
        onClick={useAuthedCallback(onDeploy)}
      >
        <Center expand fontWeight="bold">
          {isCreating ? <Spinner /> : t("Create")}
        </Center>
      </DashboardBox>
    </>
  );
}
Example #7
Source File: FusePoolPage.tsx    From rari-dApp with GNU Affero General Public License v3.0 4 votes vote down vote up
AssetSupplyRow = ({
  assets,
  index,
  comptrollerAddress,
  supplyIncentives,
  rewardTokensData,
  isPaused,
}: {
  assets: USDPricedFuseAsset[];
  index: number;
  comptrollerAddress: string;
  supplyIncentives: CTokenRewardsDistributorIncentivesWithRates[];
  rewardTokensData: TokensDataMap;
  isPaused: boolean;
}) => {
  const {
    isOpen: isModalOpen,
    onOpen: openModal,
    onClose: closeModal,
  } = useDisclosure();

  const authedOpenModal = useAuthedCallback(openModal);

  const asset = assets[index];

  const { fuse, address } = useRari();

  const tokenData = useTokenData(asset.underlyingToken);

  const supplyAPY = convertMantissaToAPY(asset.supplyRatePerBlock, 365);

  const queryClient = useQueryClient();

  const toast = useToast();

  const onToggleCollateral = async () => {
    const comptroller = createComptroller(comptrollerAddress, fuse);

    let call;
    if (asset.membership) {
      call = comptroller.methods.exitMarket(asset.cToken);
    } else {
      call = comptroller.methods.enterMarkets([asset.cToken]);
    }

    let response = await call.call({ from: address });
    // For some reason `response` will be `["0"]` if no error but otherwise it will return a string number.
    if (response[0] !== "0") {
      if (asset.membership) {
        toast({
          title: "Error! Code: " + response,
          description:
            "You cannot disable this asset as collateral as you would not have enough collateral posted to keep your borrow. Try adding more collateral of another type or paying back some of your debt.",
          status: "error",
          duration: 9000,
          isClosable: true,
          position: "top-right",
        });
      } else {
        toast({
          title: "Error! Code: " + response,
          description:
            "You cannot enable this asset as collateral at this time.",
          status: "error",
          duration: 9000,
          isClosable: true,
          position: "top-right",
        });
      }

      return;
    }

    await call.send({ from: address });

    LogRocket.track("Fuse-ToggleCollateral");

    queryClient.refetchQueries();
  };

  const isStakedOHM =
    asset.underlyingToken.toLowerCase() ===
    "0x04F2694C8fcee23e8Fd0dfEA1d4f5Bb8c352111F".toLowerCase();

  const { data: stakedOHMApyData } = useQuery("sOHM_APY", async () => {
    const data = (
      await fetch("https://api.rari.capital/fuse/pools/18/apy")
    ).json();

    return data as Promise<{ supplyApy: number; supplyWpy: number }>;
  });

  const isMobile = useIsMobile();

  const { t } = useTranslation();

  const hasSupplyIncentives = !!supplyIncentives.length;
  const totalSupplyAPR =
    supplyIncentives?.reduce((prev, incentive) => {
      const apr = incentive.supplyAPR;
      return prev + apr;
    }, 0) ?? 0;

  const [hovered, setHovered] = useState<number>(-1);

  const handleMouseEnter = (index: number) => setHovered(index);
  const handleMouseLeave = () => setHovered(-1);

  const displayedSupplyAPR =
    hovered >= 0 ? supplyIncentives[hovered].supplyAPR : totalSupplyAPR;

  const displayedSupplyAPRLabel =
    hovered >= 0
      ? `${supplyIncentives[hovered].supplyAPR.toFixed(2)} % APR in ${
          rewardTokensData[supplyIncentives[hovered].rewardToken].symbol
        } distributions.`
      : `${displayedSupplyAPR.toFixed(
          2
        )}% total APR distributed in ${supplyIncentives
          .map((incentive) => rewardTokensData[incentive.rewardToken].symbol)
          .join(", ")}
         `;

  const _hovered = hovered > 0 ? hovered : 0;

  const color =
    rewardTokensData[supplyIncentives?.[_hovered]?.rewardToken]?.color ??
    "white";

  const symbol = getSymbol(tokenData, asset);

  return (
    <>
      <PoolModal
        defaultMode={Mode.SUPPLY}
        comptrollerAddress={comptrollerAddress}
        assets={assets}
        index={index}
        isOpen={isModalOpen}
        onClose={closeModal}
        isBorrowPaused={asset.isPaused}
      />

      <Row
        mainAxisAlignment="flex-start"
        crossAxisAlignment="flex-start"
        width="100%"
        px={4}
        py={1.5}
        className="hover-row"
      >
        {/* Underlying Token Data */}
        <Column
          mainAxisAlignment="flex-start"
          crossAxisAlignment="flex-start"
          width="27%"
        >
          <Row
            mainAxisAlignment="flex-start"
            crossAxisAlignment="center"
            width="100%"
            as="button"
            onClick={authedOpenModal}
          >
            <Avatar
              bg="#FFF"
              boxSize="37px"
              name={symbol}
              src={
                tokenData?.logoURL ??
                "https://raw.githubusercontent.com/feathericons/feather/master/icons/help-circle.svg"
              }
            />
            <Text fontWeight="bold" fontSize="lg" ml={2} flexShrink={0}>
              {symbol}
            </Text>
          </Row>
          {/* <Row
            mainAxisAlignment="flex-start"
            crossAxisAlignment="center"
            width="100%"
          >
            <Text fontSize="sm" ml={2} flexShrink={0}>
            {shortUsdFormatter(asset.liquidityUSD)}
            </Text>
          </Row> */}
        </Column>

        {/* APY */}
        {isMobile ? null : (
          <Column
            mainAxisAlignment="flex-start"
            crossAxisAlignment="flex-end"
            width="27%"
            as="button"
            onClick={authedOpenModal}
          >
            <Text
              color={tokenData?.color ?? "#FF"}
              fontWeight="bold"
              fontSize="17px"
            >
              {isStakedOHM
                ? stakedOHMApyData
                  ? (stakedOHMApyData.supplyApy * 100).toFixed(2)
                  : "?"
                : supplyAPY.toFixed(2)}
              %
            </Text>

            {/* Demo Supply Incentives */}
            {hasSupplyIncentives && (
              <Row
                // ml={1}
                // mb={.5}
                crossAxisAlignment="center"
                mainAxisAlignment="flex-end"
                py={2}
              >
                <Text fontWeight="bold" mr={1}>
                  +
                </Text>
                <AvatarGroup size="xs" max={30} ml={2} mr={1} spacing={1}>
                  {supplyIncentives?.map((supplyIncentive, i) => {
                    return (
                      <SimpleTooltip label={displayedSupplyAPRLabel}>
                        <CTokenIcon
                          address={supplyIncentive.rewardToken}
                          boxSize="20px"
                          onMouseEnter={() => handleMouseEnter(i)}
                          onMouseLeave={() => handleMouseLeave()}
                          _hover={{
                            zIndex: 9,
                            border: ".5px solid white",
                            transform: "scale(1.3);",
                          }}
                        />
                      </SimpleTooltip>
                    );
                  })}
                </AvatarGroup>
                <SimpleTooltip label={displayedSupplyAPRLabel}>
                  <Text color={color} fontWeight="bold" pl={1} fontSize="sm">
                    {/* {(supplyIncentive.supplySpeed / 1e18).toString()}%  */}
                    {displayedSupplyAPR.toFixed(2)}% APR
                  </Text>
                </SimpleTooltip>
              </Row>
            )}

            {/* Incentives */}
            {/* {hasSupplyIncentives && (
              <Column
                mainAxisAlignment="flex-start"
                crossAxisAlignment="flex-end"
                py={1}
              >
                {supplyIncentives?.map((supplyIncentive) => {
                  return (
                    <Row
                      ml={1}
                      py={0.5}
                      // mb={.5}
                      crossAxisAlignment="center"
                      mainAxisAlignment="flex-end"
                    >
                      <Text fontWeight="bold" mr={2}>
                        +
                      </Text>
                      <CTokenIcon
                        address={supplyIncentive.rewardToken}
                        boxSize="20px"
                      />
                      <Text fontWeight="bold" mr={2}></Text>
                      <Text
                        color={
                          rewardTokensData[supplyIncentive.rewardToken].color ??
                          "white"
                        }
                        fontWeight="bold"
                      >
                        {(supplyIncentive.supplySpeed / 1e18).toString()}%
                      </Text>
                    </Row>
                  );
                })}
              </Column>
            )} */}

            <SimpleTooltip
              label={t(
                "The Collateral Factor (CF) ratio defines the maximum amount of tokens in the pool that can be borrowed with a specific collateral. It’s expressed in percentage: if in a pool ETH has 75% LTV, for every 1 ETH worth of collateral, borrowers will be able to borrow 0.75 ETH worth of other tokens in the pool."
              )}
            >
              <Text fontSize="sm">{asset.collateralFactor / 1e16}% CF</Text>
            </SimpleTooltip>

            {/* Incentives under APY
            <Column
              mainAxisAlignment="flex-start"
              crossAxisAlignment="flex-end"
              my={1}
            >
              {supplyIncentives?.map((supplyIncentive) => {
                return (
                  <Row
                    mainAxisAlignment="space-between"
                    crossAxisAlignment="center"
                    w="100%"
                  >
                    <Avatar
                      src={
                        rewardTokensData[supplyIncentive.rewardToken].logoURL ?? ""
                      }
                      boxSize="20px"
                    />
                    <Text
                      ml={2}
                      fontWeight="bold"
                      color={
                        rewardTokensData[supplyIncentive.rewardToken].color ?? ""
                      }
                    >
                      {(supplyIncentive.supplySpeed / 1e18).toString()}%
                    </Text>
                  </Row>
                );
              })}
            </Column>
             */}
          </Column>
        )}

        {/* Incentives */}
        {/* <Column mainAxisAlignment="flex-start" crossAxisAlignment="flex-start">
          {supplyIncentives?.map((supplyIncentive) => {
            return (
              <Row mainAxisAlignment="flex-start" crossAxisAlignment="center">
                <Avatar
                  src={rewardTokensData[supplyIncentive.rewardToken].logoURL}
                  boxSize="15px"
                />
                <Box>
                  {(supplyIncentive.supplySpeed / 1e18).toString()}% APY
                </Box>
              </Row>
            );
          })}
        </Column> */}

        <Column
          mainAxisAlignment="flex-start"
          crossAxisAlignment="flex-end"
          width={isMobile ? "40%" : "27%"}
          as="button"
          onClick={authedOpenModal}
        >
          <Text
            color={tokenData?.color ?? "#FFF"}
            fontWeight="bold"
            fontSize="17px"
          >
            {smallUsdFormatter(asset.supplyBalanceUSD)}
          </Text>

          <Text fontSize="sm">
            {smallUsdFormatter(
              asset.supplyBalance / 10 ** asset.underlyingDecimals
            ).replace("$", "")}{" "}
            {symbol}
          </Text>
        </Column>

        {/* Set As Collateral  */}
        <Row
          width={isMobile ? "34%" : "20%"}
          mainAxisAlignment="flex-end"
          crossAxisAlignment="center"
        >
          <SwitchCSS symbol={symbol} color={tokenData?.color} />
          <Switch
            isChecked={asset.membership}
            className={symbol + "-switch"}
            onChange={onToggleCollateral}
            size="md"
            mt={1}
            mr={5}
          />
        </Row>
      </Row>
    </>
  );
}
Example #8
Source File: AmountSelect.tsx    From rari-dApp with GNU Affero General Public License v3.0 4 votes vote down vote up
AmountSelect = ({
  onClose,
  assets,
  index,
  mode,
  setMode,

  comptrollerAddress,
  isBorrowPaused = false
}: {
  onClose: () => any;
  assets: USDPricedFuseAsset[];
  index: number;
  mode: Mode;
  setMode: (mode: Mode) => any;
  comptrollerAddress: string;
  isBorrowPaused?: boolean;
}) => {
  const asset = assets[index];

  const { address, fuse } = useRari();

  const toast = useToast();

  const queryClient = useQueryClient();

  const tokenData = useTokenData(asset.underlyingToken);

  const [userAction, setUserAction] = useState(UserAction.NO_ACTION);

  const [userEnteredAmount, _setUserEnteredAmount] = useState("");

  const [amount, _setAmount] = useState<BigNumber | null>(
    () => new BigNumber(0)
  );

  const showEnableAsCollateral = !asset.membership && mode === Mode.SUPPLY;
  const [enableAsCollateral, setEnableAsCollateral] = useState(
    showEnableAsCollateral
  );

  const { t } = useTranslation();

  const updateAmount = (newAmount: string) => {
    if (newAmount.startsWith("-")) {
      return;
    }

    _setUserEnteredAmount(newAmount);

    try {
      BigNumber.DEBUG = true;

      // Try to set the amount to BigNumber(newAmount):
      const bigAmount = new BigNumber(newAmount);
      _setAmount(bigAmount.multipliedBy(10 ** asset.underlyingDecimals));
    } catch (e) {
      // If the number was invalid, set the amount to null to disable confirming:
      _setAmount(null);
    }

    setUserAction(UserAction.NO_ACTION);
  };

  const { data: amountIsValid } = useQuery(
    (amount?.toString() ?? "null") + " " + mode + " isValid",
    async () => {
      if (amount === null || amount.isZero()) {
        return false;
      }

      try {
        const max = await fetchMaxAmount(mode, fuse, address, asset);

        return amount.lte(max!.toString());
      } catch (e) {
        handleGenericError(e, toast);
        return false;
      }
    }
  );

  let depositOrWithdrawAlert = null;

  if (mode === Mode.BORROW && isBorrowPaused) {
    depositOrWithdrawAlert = t("Borrowing is disabled for this asset.");
  }
  else if (amount === null || amount.isZero()) {
    if (mode === Mode.SUPPLY) {
      depositOrWithdrawAlert = t("Enter a valid amount to supply.");
    } else if (mode === Mode.BORROW) {
      depositOrWithdrawAlert = t("Enter a valid amount to borrow.");
    } else if (mode === Mode.WITHDRAW) {
      depositOrWithdrawAlert = t("Enter a valid amount to withdraw.");
    } else {
      depositOrWithdrawAlert = t("Enter a valid amount to repay.");
    }
  } else if (amountIsValid === undefined) {
    depositOrWithdrawAlert = t("Loading your balance of {{token}}...", {
      token: asset.underlyingSymbol,
    });
  } else if (!amountIsValid) {
    if (mode === Mode.SUPPLY) {
      depositOrWithdrawAlert = t("You don't have enough {{token}}!", {
        token: asset.underlyingSymbol,
      });
    } else if (mode === Mode.REPAY) {
      depositOrWithdrawAlert = t(
        "You don't have enough {{token}} or are over-repaying!",
        {
          token: asset.underlyingSymbol,
        }
      );
    } else if (mode === Mode.WITHDRAW) {
      depositOrWithdrawAlert = t("You cannot withdraw this much!");
    } else if (mode === Mode.BORROW) {
      depositOrWithdrawAlert = t("You cannot borrow this much!");
    }
  } else {
    depositOrWithdrawAlert = null;
  }

  const isMobile = useIsMobile();

  const length = depositOrWithdrawAlert?.length ?? 0;
  let depositOrWithdrawAlertFontSize;
  if (length < 40) {
    depositOrWithdrawAlertFontSize = !isMobile ? "xl" : "17px";
  } else if (length < 50) {
    depositOrWithdrawAlertFontSize = !isMobile ? "15px" : "11px";
  } else if (length < 60) {
    depositOrWithdrawAlertFontSize = !isMobile ? "14px" : "10px";
  }

  const onConfirm = async () => {
    try {
      setUserAction(UserAction.WAITING_FOR_TRANSACTIONS);

      const isETH = asset.underlyingToken === ETH_TOKEN_DATA.address;
      const isRepayingMax =
        amount!.eq(asset.borrowBalance) && !isETH && mode === Mode.REPAY;

      isRepayingMax && console.log("Using max repay!");

      const max = new BigNumber(2).pow(256).minus(1).toFixed(0);

      const amountBN = fuse.web3.utils.toBN(amount!.toFixed(0));

      const cToken = new fuse.web3.eth.Contract(
        isETH
          ? JSON.parse(
            fuse.compoundContracts[
              "contracts/CEtherDelegate.sol:CEtherDelegate"
            ].abi
          )
          : JSON.parse(
            fuse.compoundContracts[
              "contracts/CErc20Delegate.sol:CErc20Delegate"
            ].abi
          ),
        asset.cToken
      );

      if (mode === Mode.SUPPLY || mode === Mode.REPAY) {
        if (!isETH) {
          const token = new fuse.web3.eth.Contract(
            JSON.parse(
              fuse.compoundContracts[
                "contracts/EIP20Interface.sol:EIP20Interface"
              ].abi
            ),
            asset.underlyingToken
          );

          const hasApprovedEnough = fuse.web3.utils
            .toBN(
              await token.methods
                .allowance(address, cToken.options.address)
                .call()
            )
            .gte(amountBN);

          if (!hasApprovedEnough) {
            await token.methods
              .approve(cToken.options.address, max)
              .send({ from: address });
          }

          LogRocket.track("Fuse-Approve");
        }

        if (mode === Mode.SUPPLY) {
          // If they want to enable as collateral now, enter the market:
          if (enableAsCollateral) {
            const comptroller = createComptroller(comptrollerAddress, fuse);
            // Don't await this, we don't care if it gets executed first!
            comptroller.methods
              .enterMarkets([asset.cToken])
              .send({ from: address });

            LogRocket.track("Fuse-ToggleCollateral");
          }

          if (isETH) {
            const call = cToken.methods.mint();

            if (
              // If they are supplying their whole balance:
              amountBN.toString() === (await fuse.web3.eth.getBalance(address))
            ) {
              // Subtract gas for max ETH

              const { gasWEI, gasPrice, estimatedGas } = await fetchGasForCall(
                call,
                amountBN,
                fuse,
                address
              );

              await call.send({
                from: address,
                value: amountBN.sub(gasWEI),

                gasPrice,
                gas: estimatedGas,
              });
            } else {
              await call.send({
                from: address,
                value: amountBN,
              });
            }
          } else {
            await testForCTokenErrorAndSend(
              cToken.methods.mint(amountBN),
              address,
              "Cannot deposit this amount right now!"
            );
          }

          LogRocket.track("Fuse-Supply");
        } else if (mode === Mode.REPAY) {
          if (isETH) {
            const call = cToken.methods.repayBorrow();

            if (
              // If they are repaying their whole balance:
              amountBN.toString() === (await fuse.web3.eth.getBalance(address))
            ) {
              // Subtract gas for max ETH

              const { gasWEI, gasPrice, estimatedGas } = await fetchGasForCall(
                call,
                amountBN,
                fuse,
                address
              );

              await call.send({
                from: address,
                value: amountBN.sub(gasWEI),

                gasPrice,
                gas: estimatedGas,
              });
            } else {
              await call.send({
                from: address,
                value: amountBN,
              });
            }
          } else {
            await testForCTokenErrorAndSend(
              cToken.methods.repayBorrow(isRepayingMax ? max : amountBN),
              address,
              "Cannot repay this amount right now!"
            );
          }

          LogRocket.track("Fuse-Repay");
        }
      } else if (mode === Mode.BORROW) {
        await testForCTokenErrorAndSend(
          cToken.methods.borrow(amountBN),
          address,
          "Cannot borrow this amount right now!"
        );

        LogRocket.track("Fuse-Borrow");
      } else if (mode === Mode.WITHDRAW) {
        await testForCTokenErrorAndSend(
          cToken.methods.redeemUnderlying(amountBN),
          address,
          "Cannot withdraw this amount right now!"
        );

        LogRocket.track("Fuse-Withdraw");
      }

      queryClient.refetchQueries();

      // Wait 2 seconds for refetch and then close modal.
      // We do this instead of waiting the refetch because some refetches take a while or error out and we want to close now.
      await new Promise((resolve) => setTimeout(resolve, 2000));

      onClose();
    } catch (e) {
      handleGenericError(e, toast);
      setUserAction(UserAction.NO_ACTION);
    }
  };

  const symbol = getSymbol(tokenData, asset);

  return (
    <Column
      mainAxisAlignment="flex-start"
      crossAxisAlignment="flex-start"
      height={showEnableAsCollateral ? "575px" : "500px"}
    >
      {userAction === UserAction.WAITING_FOR_TRANSACTIONS ? (
        <Column
          expand
          mainAxisAlignment="center"
          crossAxisAlignment="center"
          p={4}
        >
          <HashLoader size={70} color={tokenData?.color ?? "#FFF"} loading />
          <Heading mt="30px" textAlign="center" size="md">
            {t("Check your wallet to submit the transactions")}
          </Heading>
          <Text fontSize="sm" mt="15px" textAlign="center">
            {t("Do not close this tab until you submit all transactions!")}
          </Text>
        </Column>
      ) : (
        <>
          <Row
            width="100%"
            mainAxisAlignment="center"
            crossAxisAlignment="center"
            p={4}
            height="72px"
            flexShrink={0}
          >
            <Box height="35px" width="35px">
              <Image
                width="100%"
                height="100%"
                borderRadius="50%"
                src={
                  tokenData?.logoURL ??
                  "https://raw.githubusercontent.com/feathericons/feather/master/icons/help-circle.svg"
                }
                alt=""
              />
            </Box>

            <Heading fontSize="27px" ml={3}>
              {!isMobile && asset.underlyingName.length < 25
                ? asset.underlyingName
                : symbol}
            </Heading>
          </Row>

          <ModalDivider />

          <Column
            mainAxisAlignment="flex-start"
            crossAxisAlignment="center"
            px={4}
            pb={4}
            pt={1}
            height="100%"
          >
            <Column
              mainAxisAlignment="flex-start"
              crossAxisAlignment="flex-start"
              width="100%"
            >
              <TabBar color={tokenData?.color} mode={mode} setMode={setMode} />

              <DashboardBox width="100%" height="70px">
                <Row
                  p={4}
                  mainAxisAlignment="space-between"
                  crossAxisAlignment="center"
                  expand
                >
                  <AmountInput
                    color={tokenData?.color ?? "#FFF"}
                    displayAmount={userEnteredAmount}
                    updateAmount={updateAmount}
                    disabled={mode === Mode.BORROW && isBorrowPaused}
                  />
                  <TokenNameAndMaxButton
                    comptrollerAddress={comptrollerAddress}
                    mode={mode}
                    symbol={symbol}
                    logoURL={
                      tokenData?.logoURL ??
                      "https://raw.githubusercontent.com/feathericons/feather/master/icons/help-circle.svg"
                    }
                    asset={asset}
                    updateAmount={updateAmount}
                  />
                </Row>
              </DashboardBox>
            </Column>

            <StatsColumn
              symbol={symbol}
              amount={parseInt(amount?.toFixed(0) ?? "0") ?? 0}
              color={tokenData?.color ?? "#FFF"}
              assets={assets}
              index={index}
              mode={mode}
              enableAsCollateral={enableAsCollateral}
            />

            {showEnableAsCollateral ? (
              <DashboardBox p={4} width="100%" mt={4}>
                <Row
                  mainAxisAlignment="space-between"
                  crossAxisAlignment="center"
                  width="100%"
                >
                  <Text fontWeight="bold">{t("Enable As Collateral")}:</Text>
                  <SwitchCSS
                    symbol={asset.underlyingSymbol}
                    color={tokenData?.color}
                  />
                  <Switch
                    h="20px"
                    className={asset.underlyingSymbol + "-switch"}
                    isChecked={enableAsCollateral}
                    onChange={() => {
                      setEnableAsCollateral((past) => !past);
                    }}
                  />
                </Row>
              </DashboardBox>
            ) : null}

            <Button
              mt={4}
              fontWeight="bold"
              fontSize={
                depositOrWithdrawAlert ? depositOrWithdrawAlertFontSize : "2xl"
              }
              borderRadius="10px"
              width="100%"
              height="70px"
              bg={tokenData?.color ?? "#FFF"}
              color={tokenData?.overlayTextColor ?? "#000"}
              // If the size is small, this means the text is large and we don't want the font size scale animation.
              className={
                isMobile ||
                  depositOrWithdrawAlertFontSize === "14px" ||
                  depositOrWithdrawAlertFontSize === "15px"
                  ? "confirm-button-disable-font-size-scale"
                  : ""
              }
              _hover={{ transform: "scale(1.02)" }}
              _active={{ transform: "scale(0.95)" }}
              onClick={onConfirm}
              isDisabled={!amountIsValid}
            >
              {depositOrWithdrawAlert ?? t("Confirm")}
            </Button>
          </Column>
        </>
      )}
    </Column>
  );
}
Example #9
Source File: index.tsx    From ksana.in with Apache License 2.0 4 votes vote down vote up
export function UrlForm({ user, onSuccess }: IUrlFormProps) {
  const { showAlert, hideAlert } = useAlertContext()

  const [url, setUrl] = useState<string>('')
  const [slug, setSlug] = useState<string>('')
  const [isCheckPass, setIsCheckPass] = useState<boolean>(false)
  const [isDynamic, setIsDynamic] = useState<boolean>(false)
  const [errorUrl, setErrorUrl] = useState<boolean | string>(false)
  const [errorSlug, setErrorSlug] = useState<boolean | string>(false)
  const [loading, setLoading] = useState<boolean>(false)

  const handleChangeUrl = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setUrl(value)
    setErrorUrl('')
  }

  const handleChangeSlug = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.value
    setSlug(value)
    setErrorSlug('')
  }

  const handleChangeIsDynamic = (e: ChangeEvent<HTMLInputElement>) => {
    const value = e.target.checked
    setIsDynamic(value)
  }

  const resetErrorMessage = () => {
    setErrorUrl('')
    setErrorSlug('')
  }

  const checkIsEmpty = () => {
    if (url === '') {
      setErrorUrl('URL dan slug tidak bisa dikosongkan')
      return true
    }

    if (url.indexOf('http://') === -1 && url.indexOf('https://') === -1) {
      setErrorUrl('Pastikan URL dimulai dengan http:// atau https://')
      return true
    }

    if (slug === '') {
      setErrorSlug('URL dan slug tidak bisa dikosongkan')
      return true
    }

    return false
  }

  const checkParamRequired = () => {
    const params = url.match(/{param}/g) || []

    if (isDynamic && !params.length) {
      setErrorUrl('Tautan dinamis membutuhkan teks {param} di dalamnya')
      return false
    }

    if (isDynamic && params.length > 1) {
      setErrorUrl('Teks {param} cukup satu saja')
      return false
    }

    return true
  }

  const handleCheckAvailability = async () => {
    setLoading(true)
    resetErrorMessage()
    const isEmpty = checkIsEmpty()
    const hasParam = checkParamRequired()
    if (!isEmpty && hasParam) {
      const response = await checkSlug({ slug: sanitizeSlug(slug) })
      if (response.error) {
        setIsCheckPass(true)
        resetErrorMessage()
      } else {
        setErrorSlug(`Slug ${slug} telah digunakan, coba slug lain`)
      }
    }
    setLoading(false)
  }

  const handleSaveNew = async () => {
    setLoading(true)
    const isEmpty = checkIsEmpty()
    if (!isEmpty) {
      const { error: errorInsert } = await saveUrl({
        url: url,
        slug: sanitizeSlug(slug),
        is_dynamic: isDynamic,
        userId: user?.id
      })

      if (!errorInsert) {
        showAlert({
          title: 'Sukses menyimpan tautan baru',
          message: 'Tautan telah disimpan dalam basis data kami, silahkan mulai bagikan',
          onClose: () => {
            hideAlert()
            mutate(apiUrlsGet(user?.id))
            setUrl('')
            setSlug('')
            setIsCheckPass(false)
            resetErrorMessage()
            onSuccess()
          }
        })
      } else {
        showAlert({
          title: 'Terjadi galat pada saat berusaha menyimpan data',
          message: `Pesan: ${errorInsert.message}`,
          onClose: () => {
            hideAlert()
            setIsCheckPass(false)
            resetErrorMessage()
          }
        })
      }
    }
    setLoading(false)
  }

  return (
    <Box width={{ base: '100%' }}>
      <Stack spacing={4} direction={{ base: 'column' }}>
        <FormControl id="url" isRequired>
          <Input
            isRequired
            isInvalid={Boolean(errorUrl)}
            size="lg"
            name="url"
            placeholder={'Tautan yang akan dipercantik'}
            variant="filled"
            value={url}
            onChange={handleChangeUrl}
          />
          {errorUrl && <FormHelperText color="red.500">Error: {errorUrl}</FormHelperText>}
          <FormHelperText>
            Membutuhkan tautan dalam bentuk utuh, termasuk awalan https://
          </FormHelperText>
          {isDynamic && (
            <FormHelperText>
              Sisipkan teks <code>{'{param}'}</code> pada tautan
            </FormHelperText>
          )}
        </FormControl>

        <FormControl display="flex" alignItems="center">
          <FormLabel htmlFor="is-dynamic" mb="0" display="flex">
            Tautan dinamis{' '}
            <Tooltip
              label="Kamu bisa membuat tautan dinamis macam: https://mazipan.space/{param}"
              placement="bottom"
            >
              <i>
                <HiQuestionMarkCircle />
              </i>
            </Tooltip>
          </FormLabel>
          <Switch id="is-dynamic" onChange={handleChangeIsDynamic} />
        </FormControl>

        <FormControl id="slug" isRequired>
          <InputGroup size="lg">
            <InputLeftAddon
              color={'orange.400'}
              fontWeight="bold"
              px={2}
              children={HOME?.replace('https://', '').replace('http://', '')}
              fontSize="xs"
            />
            <Input
              isRequired
              isInvalid={Boolean(errorSlug)}
              size="lg"
              name="slug"
              placeholder={'Slug cantik dambaanmu'}
              variant="filled"
              value={slug}
              onChange={handleChangeSlug}
            />
          </InputGroup>
          {errorSlug && <FormHelperText color="red.500">Error: {errorSlug}</FormHelperText>}
          <FormHelperText>
            Hanya diperbolehkan menggunakan huruf, angka, karakter titik dan strip saja
          </FormHelperText>
        </FormControl>

        {isCheckPass ? (
          <Button
            isLoading={loading}
            loadingText="Processing"
            size="lg"
            px={6}
            mt="4"
            color={'white'}
            bg={'green.400'}
            _hover={{
              bg: 'green.500'
            }}
            _focus={{
              bg: 'green.500'
            }}
            onClick={handleSaveNew}
          >
            Simpan sekarang
          </Button>
        ) : (
          <Button
            isLoading={loading}
            loadingText="Processing"
            size="lg"
            px={6}
            my="4"
            color={'white'}
            bg={'orange.400'}
            _hover={{
              bg: 'orange.500'
            }}
            _focus={{
              bg: 'orange.500'
            }}
            onClick={handleCheckAvailability}
          >
            Cek ketersediaan
          </Button>
        )}
      </Stack>
    </Box>
  )
}
Example #10
Source File: Header.tsx    From openchakra with MIT License 4 votes vote down vote up
Header = () => {
  const showLayout = useSelector(getShowLayout)
  const showCode = useSelector(getShowCode)
  const dispatch = useDispatch()

  return (
    <DarkMode>
      <Flex
        justifyContent="space-between"
        bg="#1a202c"
        as="header"
        height="3rem"
        px="1rem"
      >
        <Flex
          width="14rem"
          height="100%"
          backgroundColor="#1a202c"
          color="white"
          as="a"
          fontSize="xl"
          flexDirection="row"
          alignItems="center"
          aria-label="Chakra UI, Back to homepage"
        >
          <Box fontSize="2xl" as={AiFillThunderbolt} mr={1} color="teal.100" />{' '}
          <Box fontWeight="bold">open</Box>chakra
        </Flex>

        <Flex flexGrow={1} justifyContent="space-between" alignItems="center">
          <HStack spacing={4} justify="center" align="center">
            <Box>
              <HeaderMenu />
            </Box>
            <FormControl flexDirection="row" display="flex" alignItems="center">
              <Tooltip
                zIndex={100}
                hasArrow
                bg="yellow.100"
                aria-label="Builder mode help"
                label="Builder mode adds extra padding/borders"
              >
                <FormLabel
                  cursor="help"
                  color="gray.200"
                  fontSize="xs"
                  htmlFor="preview"
                  pb={0}
                  mb={0}
                  mr={2}
                  whiteSpace="nowrap"
                >
                  Builder mode
                </FormLabel>
              </Tooltip>
              <LightMode>
                <Switch
                  isChecked={showLayout}
                  colorScheme="teal"
                  size="sm"
                  onChange={() => dispatch.app.toggleBuilderMode()}
                  id="preview"
                />
              </LightMode>
            </FormControl>

            <FormControl display="flex" flexDirection="row" alignItems="center">
              <FormLabel
                color="gray.200"
                fontSize="xs"
                mr={2}
                mb={0}
                htmlFor="code"
                pb={0}
                whiteSpace="nowrap"
              >
                Code panel
              </FormLabel>
              <LightMode>
                <Switch
                  isChecked={showCode}
                  id="code"
                  colorScheme="teal"
                  onChange={() => dispatch.app.toggleCodePanel()}
                  size="sm"
                />
              </LightMode>
            </FormControl>
          </HStack>

          <Stack direction="row">
            <CodeSandboxButton />
            <Popover>
              {({ onClose }) => (
                <>
                  <PopoverTrigger>
                    <Button
                      ml={4}
                      rightIcon={<SmallCloseIcon path="" />}
                      size="xs"
                      variant="ghost"
                    >
                      Clear
                    </Button>
                  </PopoverTrigger>
                  <LightMode>
                    <PopoverContent zIndex={100} bg="white">
                      <PopoverArrow />
                      <PopoverCloseButton />
                      <PopoverHeader>Are you sure?</PopoverHeader>
                      <PopoverBody fontSize="sm">
                        Do you really want to remove all components on the
                        editor?
                      </PopoverBody>
                      <PopoverFooter display="flex" justifyContent="flex-end">
                        <Button
                          size="sm"
                          variant="ghost"
                          colorScheme="red"
                          rightIcon={<CheckIcon path="" />}
                          onClick={() => {
                            dispatch.components.reset()
                            if (onClose) {
                              onClose()
                            }
                          }}
                        >
                          Yes, clear
                        </Button>
                      </PopoverFooter>
                    </PopoverContent>
                  </LightMode>
                </>
              )}
            </Popover>
          </Stack>
        </Flex>

        <Stack
          justifyContent="flex-end"
          width="13rem"
          align="center"
          direction="row"
          spacing="2"
        >
          <Link isExternal href="https://github.com/premieroctet/openchakra">
            <Box as={DiGithubBadge} size={32} color="gray.200" />
          </Link>
          <Box lineHeight="shorter" color="white" fontSize="xs">
            by{' '}
            <Link isExternal href="https://premieroctet.com" color="teal.100">
              Premier Octet
            </Link>
          </Box>
        </Stack>
      </Flex>
    </DarkMode>
  )
}
Example #11
Source File: ChatForm.tsx    From takeout-app with MIT License 4 votes vote down vote up
ChatForm: React.FC<Props> = ({ track, channel }) => {
  const chat = useChat();

  const { data: session } = Api.useSession();
  const isStaff = session?.attendee?.is_staff;

  const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
  const [isRequesting, setIsRequesting] = React.useState<boolean>(false);

  const { register, handleSubmit, reset, setFocus, watch } = useForm<{
    message: string;
    asAdmin: boolean;
  }>({
    defaultValues: {
      message: "",
      asAdmin: false,
    },
  });

  const asAdmin = watch("asAdmin");

  const onSubmit = handleSubmit(async (data) => {
    if (!chat.session || !channel) return;
    if (isRequesting) return;
    setIsRequesting(true);
    setErrorAlert(null);

    try {
      if (data.asAdmin && isStaff) {
        await Api.sendChatMessage(track.slug, data.message, true);
      } else {
        // Workaround: aws-sdk-v3 sigv4 fails to generate correct signature for payload containing emoji...
        if (/\p{Extended_Pictographic}/u.test(data.message)) {
          await Api.sendChatMessage(track.slug, data.message, false);
        } else {
          await chat.session.postMessage(channel, data.message);
        }
      }
      reset({ message: "", asAdmin: false });
    } catch (e) {
      setErrorAlert(
        <Box my={2}>
          <ErrorAlert error={e} />
        </Box>,
      );
    }
    setFocus("message");
    setIsRequesting(false);
  });

  const shouldDisable = !session?.attendee || !chat.session || !channel;

  // TODO: errorAlert to toast

  return (
    <Box p="16px" bgColor="#ffffff" borderTop="1px solid" borderColor={Colors.chatBorder}>
      {errorAlert}
      <form onSubmit={onSubmit}>
        <VStack w="100%">
          {session && !session.attendee?.is_ready ? (
            <Box w="100%">
              <Alert status="warning">
                <AlertIcon />
                <Text as="span">
                  Set your name at{" "}
                  <Link as={RouterLink} to="/attendee" textDecoration="underline">
                    Settings
                  </Link>{" "}
                  page
                </Text>
              </Alert>
            </Box>
          ) : null}
          <Box w="100%">
            <Textarea
              as={TextareaAutoSize}
              {...register("message")}
              size="sm"
              placeholder={asAdmin ? "SAY SOMETHING AS ADMIN..." : "Send a message"}
              isRequired
              isDisabled={shouldDisable}
              autoComplete="off"
              rows={1}
              minRows={1}
              maxRows={4}
              onKeyPress={(e) => {
                if (e.key == "Enter") {
                  e.preventDefault();
                  onSubmit();
                }
              }}
              css={{ resize: "none" }}
            />
          </Box>
          <Flex w="100%" alignItems="flex-end" direction="row-reverse" justifyContent="space-between">
            <IconButton
              icon={<SendIcon boxSize="14px" />}
              minW="30px"
              w="30px"
              h="30px"
              aria-label="Send"
              type="submit"
              isLoading={isRequesting}
              isDisabled={shouldDisable}
            />
            {isStaff ? (
              <Tooltip label="Send as an official announcement" aria-label="">
                <FormControl display="flex" alignSelf="center" h="30px">
                  <FormLabel htmlFor="ChatForm__asAdmin" aria-hidden="true" m={0} mr={1}>
                    <CampaignIcon w="24px" h="24px" />
                  </FormLabel>
                  <Switch
                    aria-label="Send as an official announcement"
                    id="ChatForm__asAdmin"
                    size="sm"
                    isChecked={asAdmin}
                    isDisabled={shouldDisable}
                    {...register("asAdmin")}
                  />
                </FormControl>
              </Tooltip>
            ) : null}
          </Flex>
        </VStack>
      </form>
    </Box>
  );
}