@chakra-ui/react#ModalOverlay TypeScript Examples

The following examples show how to use @chakra-ui/react#ModalOverlay. 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: receiving-call-modal.tsx    From video-chat with MIT License 6 votes vote down vote up
export function ReceivingCallOverlay(props: Props){
  if (!props.calling) return <></>

  return(
    <Modal isOpen={props.calling} isCentered onClose={() => {}}>
      <ModalOverlay>
        <ModalContent
          p="16"
          backgroundColor="gray.800"
          alignItems="center"
          justifyContent="center"
          display="flex"
          flexDirection="column"
          >
          <ModalHeader color="white">{props.caller} is calling you</ModalHeader>
          <ModalBody display="flex" alignItems="center" justifyContent="space-evenly" w="full">
            <Button colorScheme="green" onClick={props.answer}>Answer call</Button>
            <Button colorScheme="red" onClick={props.refuse}>Refuse call</Button>
          </ModalBody>
        </ModalContent>
      </ModalOverlay>
    </Modal>
  )
}
Example #2
Source File: index.tsx    From calories-in with MIT License 6 votes vote down vote up
function VariantNameModal({ onClose, isOpen, variantFormIndex }: Props) {
  const initialRef = useRef<HTMLInputElement>(null)
  const finalFocusRef = useRef(null)

  return (
    <Modal
      isOpen={isOpen}
      preserveScrollBarGap={true}
      onClose={onClose}
      initialFocusRef={initialRef}
      finalFocusRef={finalFocusRef}
      size="sm"
    >
      <ModalOverlay />
      <VariantNameFormProvider variantFormIndex={variantFormIndex}>
        <Content
          title="Rename Day"
          onClose={onClose}
          initialRef={initialRef}
          variantFormIndex={variantFormIndex}
        />
      </VariantNameFormProvider>
    </Modal>
  )
}
Example #3
Source File: index.tsx    From calories-in with MIT License 6 votes vote down vote up
function VariantsDetailsModal({ onClose, isOpen, initialVariantForm }: Props) {
  return (
    <Modal
      isOpen={isOpen}
      preserveScrollBarGap={true}
      onClose={onClose}
      scrollBehavior="inside"
      size="md"
    >
      <ModalOverlay />

      <Content onClose={onClose} initialVariantForm={initialVariantForm} />
    </Modal>
  )
}
Example #4
Source File: index.tsx    From calories-in with MIT License 6 votes vote down vote up
function EditNotesModal({
  onClose,
  isOpen,
  notes,
  onEditNotes,
  fieldId,
  ownerName,
  textAreaHeight,
  ...rest
}: Props) {
  const initialRef = useRef<HTMLInputElement>(null)
  const finalFocusRef = useRef(null)

  return (
    <Modal
      isOpen={isOpen}
      preserveScrollBarGap={true}
      onClose={onClose}
      initialFocusRef={initialRef}
      finalFocusRef={finalFocusRef}
      {...rest}
    >
      <ModalOverlay />

      <Content
        onClose={onClose}
        onEditNotes={onEditNotes}
        initialRef={initialRef}
        fieldId={fieldId}
        notes={notes}
        ownerName={ownerName}
        textAreaHeight={textAreaHeight}
      />
    </Modal>
  )
}
Example #5
Source File: Modal.tsx    From calories-in with MIT License 6 votes vote down vote up
function Modal({ isOpen, onClose }: Props) {
  const selectRef = useRef<HTMLSelectElement>(null)

  return (
    <ModalBase isOpen={isOpen} onClose={onClose}>
      <ModalOverlay />

      <ModalContent>
        <ModalHeader>Filters</ModalHeader>
        <ModalCloseButton />
        <ModalBody>
          <Content selectRef={selectRef} />
        </ModalBody>

        <ModalFooter>
          <Footer onClose={onClose} />
        </ModalFooter>
      </ModalContent>
    </ModalBase>
  )
}
Example #6
Source File: MissingFoodsModal.tsx    From calories-in with MIT License 6 votes vote down vote up
function MissingFoodsModal({ isOpen, onClose, onImport }: Props) {
  return (
    <Modal isOpen={isOpen} onClose={onClose} size="md" isCentered>
      <ModalOverlay />
      <ModalContent>
        <ModalHeader>Missing foods</ModalHeader>
        <ModalCloseButton />
        <ModalBody>
          <Text fontWeight="medium">
            The meal plan you contains foods that are not part of your list.
          </Text>
          <br />
          <Text>
            You can try to import the missing foods or continue without them.
          </Text>
        </ModalBody>

        <ModalFooter>
          <Button onClick={onClose} mr={3}>
            Continue
          </Button>

          <Button
            variant="solid"
            colorScheme="teal"
            onClick={() => {
              onImport()
              onClose()
            }}
          >
            Import foods
          </Button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  )
}
Example #7
Source File: index.tsx    From calories-in with MIT License 6 votes vote down vote up
function FoodModal({
  onClose,
  isOpen,
  food,
  onFoodCreatedOrUpdated,
  onFoodDeleted,
}: Props) {
  const nameInputRef = useRef<HTMLInputElement>(null)
  const title = food ? 'Food Details' : 'Create Food'

  return (
    <Modal
      isOpen={isOpen}
      preserveScrollBarGap={true}
      initialFocusRef={!food ? nameInputRef : undefined}
      onClose={onClose}
      scrollBehavior="inside"
      size={food ? 'md' : 'lg'}
    >
      <ModalOverlay />

      <Content
        nameInputRef={nameInputRef}
        onClose={onClose}
        title={title}
        food={food}
        onFoodCreatedOrUpdated={onFoodCreatedOrUpdated}
        onFoodDeleted={onFoodDeleted}
      />
    </Modal>
  )
}
Example #8
Source File: DeleteConfirmationModal.tsx    From calories-in with MIT License 6 votes vote down vote up
function DeleteConfirmationModal({
  isOpen,
  onCancel,
  onConfirm,
  text,
  confirmButtonLabel,
}: Props) {
  return (
    <Modal isOpen={isOpen} onClose={onCancel} size="xs" isCentered>
      <ModalOverlay />
      <ModalContent>
        <ModalHeader>Delete food</ModalHeader>
        <ModalCloseButton />
        <ModalBody>
          <Text>{text}</Text>
          <br />
          <Text fontWeight="medium">This action cannot be undone.</Text>
        </ModalBody>

        <ModalFooter>
          <Button variant="outline" onClick={onCancel}>
            Cancel
          </Button>
          <Button colorScheme="red" ml={3} onClick={onConfirm}>
            {confirmButtonLabel}
          </Button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  )
}
Example #9
Source File: index.tsx    From rari-dApp with GNU Affero General Public License v3.0 6 votes vote down vote up
DepositModal = (props: Props) => {
  return (
    <Modal
      motionPreset="slideInBottom"
      isOpen={props.isOpen}
      onClose={props.onClose}
      isCentered
    >
      <ModalOverlay />
      <ModalContent
        {...MODAL_PROPS}
        height={{
          md: requiresSFIStaking(props.trancheRating) ? "380px" : "295px",
          base: requiresSFIStaking(props.trancheRating) ? "390px" : "310px",
        }}
      >
        <AmountSelect
          onClose={props.onClose}
          tranchePool={props.tranchePool}
          trancheRating={props.trancheRating}
        />
      </ModalContent>
    </Modal>
  );
}
Example #10
Source File: index.tsx    From rari-dApp with GNU Affero General Public License v3.0 6 votes vote down vote up
DepositModal = (props: Props) => {
  const [currentScreen, setCurrentScreen] = useState(CurrentScreen.MAIN);

  const [mode, setMode] = useState(Mode.DEPOSIT);

  return (
    <Modal
      motionPreset="slideInBottom"
      isOpen={props.isOpen}
      onClose={props.onClose}
      isCentered
    >
      <ModalOverlay />
      <ModalContent {...MODAL_PROPS} height="300px">
        {currentScreen === CurrentScreen.MAIN ? (
          <AmountSelect
            onClose={props.onClose}
            openOptions={() => setCurrentScreen(CurrentScreen.OPTIONS)}
            mode={mode}
          />
        ) : (
          <OptionsMenu
            onClose={() => setCurrentScreen(CurrentScreen.MAIN)}
            onSetMode={setMode}
            mode={mode}
          />
        )}
      </ModalContent>
    </Modal>
  );
}
Example #11
Source File: index.tsx    From rari-dApp with GNU Affero General Public License v3.0 6 votes vote down vote up
DepositModal = (props: Props) => {
  const [mode, setMode] = useState(props.defaultMode);

  useEffect(() => {
    setMode(props.defaultMode);
  }, [props.isOpen, props.defaultMode]);

  return (
    <Modal
      motionPreset="slideInBottom"
      isOpen={props.isOpen}
      onClose={props.onClose}
      isCentered
    >
      <ModalOverlay />
      <ModalContent {...MODAL_PROPS}>
        <AmountSelect
          comptrollerAddress={props.comptrollerAddress}
          onClose={props.onClose}
          assets={props.assets}
          index={props.index}
          mode={mode}
          setMode={setMode}
          isBorrowPaused={props.isBorrowPaused}
        />
      </ModalContent>
    </Modal>
  );
}
Example #12
Source File: note-modal.tsx    From notebook with MIT License 6 votes vote down vote up
NoteModal: React.SFC<NoteFormProps> = ({
  isOpen,
  onClose,
  selectedNote
}) => {
  return (
    <AnimatePresence>
      <motion.div layoutId={selectedNote?.id}>
        <Modal
          isOpen={isOpen}
          onClose={onClose}
          scrollBehavior={"inside"}
          isCentered
          motionPreset="slideInBottom"
        >
          <ModalOverlay />
          <ModalContent>
            <motion.div>
              <ModalHeader isTruncated paddingRight="10">
                {selectedNote?.title}
              </ModalHeader>
            </motion.div>
            <ModalCloseButton />
            <motion.div>
              <ModalBody pb={6}>{selectedNote?.body}</ModalBody>
            </motion.div>
          </ModalContent>
        </Modal>
      </motion.div>
    </AnimatePresence>
  );
}
Example #13
Source File: loading-overlay.tsx    From video-chat with MIT License 5 votes vote down vote up
export function LoadingOverlay(props: Props) {
  if (!props.loading) return <></>;

  return (
    <Modal isOpen={props.loading} isCentered onClose={() => {}}>
      <ModalOverlay>
        <ModalContent
          p="16"
          backgroundColor="gray.800"
          flexDirection="row"
          justifyContent="space-between"
          alignItems="center"
        >
          <Text color="purple.600" fontWeight="bold" fontSize="2rem">Calling</Text>
          <motion.div
            style={loadingContainer}
            variants={loadingContainerVariants}
            initial="start"
            animate="end"
          >
            <motion.span
              style={loadingCircle}
              variants={loadingCircleVariants}
              transition={loadingCircleTransition}
            />
            <motion.span
              style={loadingCircle}
              variants={loadingCircleVariants}
              transition={loadingCircleTransition}
            />
            <motion.span
              style={loadingCircle}
              variants={loadingCircleVariants}
              transition={loadingCircleTransition}
            />
          </motion.div>
        </ModalContent>
      </ModalOverlay>
    </Modal>
  );
}
Example #14
Source File: index.tsx    From rari-dApp with GNU Affero General Public License v3.0 5 votes vote down vote up
DepositModal = (props: Props) => {
  const [mode, setMode] = useState(Mode.DEPOSIT);

  const [currentScreen, setCurrentScreen] = useState(CurrentScreen.MAIN);

  useEffect(() => {
    // When the modal closes return to the main screen.
    if (!props.isOpen) {
      setCurrentScreen(CurrentScreen.MAIN);
    }
  }, [props.isOpen]);

  const poolType = usePoolType();

  const [selectedToken, setSelectedToken] = useState(() => {
    if (poolType === Pool.ETH) {
      return "ETH";
    } else {
      return "USDC";
    }
  });

  return (
    <Modal
      motionPreset="slideInBottom"
      isOpen={props.isOpen}
      onClose={props.onClose}
      isCentered
    >
      <ModalOverlay />
      <ModalContent
        {...MODAL_PROPS}
        height={{
          md: poolHasDivergenceRisk(poolType) ? "320px" : "295px",
          base: poolHasDivergenceRisk(poolType) ? "350px" : "310px",
        }}
      >
        {currentScreen === CurrentScreen.MAIN ? (
          <AmountSelect
            onClose={props.onClose}
            openCoinSelect={() => setCurrentScreen(CurrentScreen.COIN_SELECT)}
            openOptions={() => setCurrentScreen(CurrentScreen.OPTIONS)}
            selectedToken={selectedToken}
            mode={mode}
          />
        ) : currentScreen === CurrentScreen.COIN_SELECT ? (
          <TokenSelect
            onClose={() => setCurrentScreen(CurrentScreen.MAIN)}
            onSelectToken={setSelectedToken}
            mode={mode}
          />
        ) : (
          <OptionsMenu
            onClose={() => setCurrentScreen(CurrentScreen.MAIN)}
            onSetMode={setMode}
            mode={mode}
          />
        )}
      </ModalContent>
    </Modal>
  );
}
Example #15
Source File: ClaimRGTModal.tsx    From rari-dApp with GNU Affero General Public License v3.0 5 votes vote down vote up
ClaimRGTModal = ({
  isOpen,
  onClose,
  defaultMode,
}: {
  isOpen: boolean;
  onClose: () => any;
  defaultMode?: ClaimMode;
}) => {
  const { t } = useTranslation();

  const [amount, setAmount] = useState(0);

  const { fuse } = useRari();

  // pool2
  // private
  // yieldagg
  const [showPrivate, setShowPrivate] = useState<boolean>(true);

  // If user presses meta key or control key + slash they will toggle the private allocation claim mode.
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.code === "Slash") {
        e.preventDefault();
        setShowPrivate(true);
      }
    };

    document.addEventListener("keydown", handler);

    return () => document.removeEventListener("keydown", handler);
  }, []);

  return (
    <Modal
      motionPreset="slideInBottom"
      isOpen={isOpen}
      onClose={onClose}
      isCentered
    >
      <ModalOverlay />
      <ModalContent {...MODAL_PROPS}>
        <ModalTitleWithCloseButton
          text={t("Claim Rewards")}
          onClose={onClose}
        />

        <ModalDivider />

        <Column
          width="100%"
          mainAxisAlignment="flex-start"
          crossAxisAlignment="flex-start"
          p={3}
        >
          <ClaimRewards showPrivate={showPrivate} />
        </Column>
      </ModalContent>
    </Modal>
  );
}
Example #16
Source File: index.tsx    From calories-in with MIT License 5 votes vote down vote up
function FoodsListModal({ onClose, isOpen, foodsToImport }: Props) {
  const title = foodsToImport ? 'Import Foods' : 'Export Foods'
  const { userFoods } = useFoods()
  const foodsActions = useFoodsActions()
  const toast = useToast()
  const foods = foodsToImport || userFoods

  function onImport() {
    if (foodsToImport) {
      foodsActions.setFoods(foodsToImport)
      toast({
        position: 'top',
        status: 'success',
        title: 'Foods imported',
        isClosable: true,
      })
      onClose()
    }
  }

  return (
    <Modal
      isOpen={isOpen}
      preserveScrollBarGap={true}
      onClose={onClose}
      scrollBehavior="inside"
    >
      <ModalOverlay />

      <FoodsFilterStoreProvider
        initialFilter={{ ...DEFAULT_FILTER, onlyFoodsAddedByUser: true }}
        shouldSaveFilter={false}
      >
        <FoodsStoreProvider initialFoods={foods}>
          <Content
            onClose={onClose}
            title={title}
            onImport={onImport}
            action={foodsToImport ? 'import' : 'export'}
          />
        </FoodsStoreProvider>
      </FoodsFilterStoreProvider>
    </Modal>
  )
}
Example #17
Source File: AuthModal.tsx    From coindrop with GNU General Public License v3.0 5 votes vote down vote up
AuthModal: FunctionComponent<Props> = ({ isOpen }) => {
    const router = useRouter();
    const onClose = () => router.push('/', undefined, { shallow: true });
    return (
        <Modal
            id="auth-modal"
            isOpen={isOpen}
            onClose={onClose}
        >
            <ModalOverlay />
            <ModalContent>
                <ModalHeader textAlign="center" mb={-3}>Sign in to continue</ModalHeader>
                <ModalCloseButton />
                <ModalBody>
                    <FirebaseAuth />
                    <Text textAlign="center" fontSize="xs" mb={2}>
                        {'If you\'re having trouble logging in, please try again with '}
                        <Link
                            href="https://www.google.com/chrome/"
                            target="_blank"
                            rel="noreferrer"
                            textDecoration="underline"
                        >
                            Chrome
                        </Link>
                        {' or '}
                        <Link
                            href="https://www.mozilla.org/firefox"
                            target="_blank"
                            rel="noreferrer"
                            textDecoration="underline"
                        >
                            Firefox
                        </Link>
                        .
                    </Text>
                </ModalBody>
            </ModalContent>
        </Modal>
    );
}
Example #18
Source File: index.tsx    From calories-in with MIT License 5 votes vote down vote up
function ExportModal({ isOpen, onClose }: Props) {
  return (
    <Modal size="sm" isOpen={isOpen} onClose={onClose}>
      <ModalOverlay />
      <Content onClose={onClose} />
    </Modal>
  )
}
Example #19
Source File: ShareButtonModal.tsx    From coindrop with GNU General Public License v3.0 5 votes vote down vote up
ShareButtonModal: FunctionComponent<Props> = ({ buttonColor }) => {
    const { isOpen, onClose, onOpen } = useDisclosure();
    const { query: { piggybankName: piggybankNameQuery }} = useRouter();
    const piggybankName = Array.isArray(piggybankNameQuery) ? piggybankNameQuery[0] : piggybankNameQuery;
    const publicUrl = `coindrop.to/${piggybankName}`;
    const fullPublicUrl = `https://${publicUrl}`;
    return (
        <>
        <Button
            leftIcon={<ShareIcon />}
            onClick={onOpen}
            colorScheme={buttonColor}
            isDisabled={isOpen}
        >
            Share
        </Button>
        <Modal isOpen={isOpen} onClose={onClose}>
            <ModalOverlay />
            <ModalContent>
                <ModalCloseButton />
                <Heading
                    mt={4}
                    as="h2"
                    size="md"
                    mx={12}
                    textAlign="center"
                >
                    {publicUrl}
                </Heading>
                <ModalBody>
                    <Box mb={4}>
                        <Box>
                            <Heading as="h2" size="lg">
                                Link
                            </Heading>
                        </Box>
                        <Center mt={2}>
                            <CopyLinkShareButton textToCopy={publicUrl} />
                        </Center>
                    </Box>
                    <ShareEmbedButton
                        fullPublicUrl={fullPublicUrl}
                    />
                    <PiggybankQRCode
                        fullPublicUrl={fullPublicUrl}
                        publicUrl={publicUrl}
                    />
                    <TipCards />
                </ModalBody>
                <ModalFooter />
            </ModalContent>
        </Modal>
        </>
    );
}
Example #20
Source File: PaymentMethodButtonModal.tsx    From coindrop with GNU General Public License v3.0 5 votes vote down vote up
PaymentMethodButtonModal: FunctionComponent<Props> = ({ isOpen, onClose, paymentMethod, paymentMethodDisplayName, paymentMethodValue }) => {
    const { onCopy, hasCopied } = useClipboard(paymentMethodValue);
    const { piggybankDbData } = useContext(PublicPiggybankDataContext);
    const { name } = piggybankDbData;
    const Icon = paymentMethodIcons[paymentMethod];
    const addressIsUrl = isUrl(paymentMethodValue, {
        require_protocol: true,
        require_valid_protocol: true,
        protocols: ['http', 'https'],
        allow_protocol_relative_urls: false,
    });
    return (
        <Modal isOpen={isOpen} onClose={onClose}>
            <ModalOverlay />
            <ModalContent mx={6}>
                <ModalHeader
                    textAlign="center"
                    mt={3}
                    mx="auto"
                >
                    {name}
                    {"'s "}
                    {paymentMethodDisplayName}
                    {' address'}
                </ModalHeader>
                <ModalCloseButton />
                <ModalBody
                    pt={0}
                    mb={3}
                    mx="auto"
                >
                    <Flex justify="center" align="center">
                        <Icon
                            mr={2}
                            boxSize="48px"
                        />
                        <Text
                            wordBreak="break-all"
                            textAlign="center"
                        >
                            {paymentMethodValue}
                        </Text>
                    </Flex>
                    <Flex
                        my={2}
                        align="center"
                        justify="center"
                    >
                        {addressIsUrl ? (
                            <Link href={paymentMethodValue} isExternal>
                                <Button
                                    leftIcon={<ExternalLinkIcon />}
                                    href={paymentMethodValue}
                                    mr={2}
                                >
                                    Open
                                </Button>
                            </Link>
                        ) : (
                            <Button
                                leftIcon={hasCopied ? <CheckIcon /> : <CopyIcon />}
                                onClick={onCopy}
                            >
                                {hasCopied ? "Copied" : "Copy"}
                            </Button>
                        )}
                    </Flex>
                    <Text mb={2} textAlign="center">or scan QR Code:</Text>
                    <Flex justify="center">
                        <QRCode
                            id="payment-method-qr-code"
                            value={paymentMethodValue}
                            size={225}
                        />
                    </Flex>
                </ModalBody>
            </ModalContent>
        </Modal>
    );
}
Example #21
Source File: EditPiggybankModal.tsx    From coindrop with GNU General Public License v3.0 4 votes vote down vote up
EditPiggybankModal: FunctionComponent<Props> = ({ isOpen, onClose }) => {
    const [isSubmitting, setIsSubmitting] = useState(false);
    const { colors } = useTheme();
    const { user } = useUser();
    const { colorMode } = useColorMode();
    const accentColorLevelInitial = getAccentColorLevelInitial(colorMode);
    const accentColorLevelHover = getAccentColorLevelHover(colorMode);
    const { push: routerPush, query: { piggybankName } } = useRouter();
    const initialPiggybankId = Array.isArray(piggybankName) ? piggybankName[0] : piggybankName;
    const { piggybankDbData } = useContext(PublicPiggybankDataContext);
    const { avatar_storage_id: currentAvatarStorageId } = piggybankDbData;
    const initialPaymentMethodsDataFieldArray = convertPaymentMethodsDataToFieldArray(piggybankDbData.paymentMethods);
    const initialAccentColor = piggybankDbData.accentColor ?? 'orange';
    const {
        register,
        handleSubmit,
        setValue,
        watch,
        control,
        formState: { isDirty },
    } = useForm({
        defaultValues: {
            piggybankId: initialPiggybankId,
            accentColor: initialAccentColor,
            website: piggybankDbData.website ?? '',
            name: piggybankDbData.name ?? '',
            verb: piggybankDbData.verb ?? 'pay',
            paymentMethods: sortByIsPreferredThenAlphabetical(initialPaymentMethodsDataFieldArray),
        },
    });
    const paymentMethodsFieldArrayName = "paymentMethods";
    const { fields, append, remove } = useFieldArray({
        control,
        name: paymentMethodsFieldArrayName,
    });
    const {
        accentColor: watchedAccentColor,
        piggybankId: watchedPiggybankId,
    } = watch(["accentColor", "piggybankId"]);
    const isAccentColorDirty = initialAccentColor !== watchedAccentColor;
    const isUrlUnchanged = initialPiggybankId === watchedPiggybankId;
    const { isPiggybankIdAvailable, setIsAddressTouched } = useContext(AdditionalValidation);
    const onSubmit = async (formData) => {
        try {
            setIsSubmitting(true);
            const dataToSubmit = {
                ...formData,
                paymentMethods: convertPaymentMethodsFieldArrayToDbMap(formData.paymentMethods ?? []),
                owner_uid: user.id,
                avatar_storage_id: currentAvatarStorageId ?? null,
            };
            if (isUrlUnchanged) {
                await db.collection('piggybanks').doc(initialPiggybankId).set(dataToSubmit);
                mutate(['publicPiggybankData', initialPiggybankId], dataToSubmit);
            } else {
                await axios.post(
                    '/api/createPiggybank',
                    {
                        oldPiggybankName: initialPiggybankId,
                        newPiggybankName: formData.piggybankId,
                        piggybankData: dataToSubmit,
                    },
                    {
                        headers: {
                            token: user.token,
                        },
                    },
                );
                try {
                    await db.collection('piggybanks').doc(initialPiggybankId).delete();
                } catch (err) {
                    console.log('error deleting old Coindrop page');
                }
                routerPush(`/${formData.piggybankId}`);
            }
            fetch(`/${initialPiggybankId}`, { headers: { isToForceStaticRegeneration: "true" }});
            onClose();
        } catch (error) {
            setIsSubmitting(false);
            // TODO: handle errors
            throw error;
        }
    };
    const handleAccentColorChange = (e) => {
        e.preventDefault();
        setValue("accentColor", e.target.dataset.colorname);
    };
    useEffect(() => {
        register("accentColor");
    }, [register]);
    const formControlTopMargin = 2;
    return (
        <Modal
            isOpen={isOpen}
            onClose={onClose}
            size="xl"
            closeOnOverlayClick={false}
        >
            <ModalOverlay />
            <ModalContent>
                <ModalHeader>Configure</ModalHeader>
                <ModalCloseButton />
                <form id="configure-coindrop-form" onSubmit={handleSubmit(onSubmit)}>
                    <ModalBody>
                        <AvatarInput />
                        <FormControl
                            isRequired
                            mt={formControlTopMargin}
                        >
                            <FormLabel htmlFor="input-piggybankId">URL</FormLabel>
                            <EditUrlInput
                                register={register}
                                value={watchedPiggybankId}
                            />
                        </FormControl>
                        <FormControl
                            mt={formControlTopMargin}
                        >
                            <FormLabel
                                htmlFor="input-accentColor"
                            >
                                Theme
                            </FormLabel>
                            <Flex wrap="wrap" justify="center">
                                {themeColorOptions.map(colorName => {
                                    const isColorSelected = watchedAccentColor === colorName;
                                    const accentColorInitial = colors[colorName][accentColorLevelInitial];
                                    const accentColorHover = colors[colorName][accentColorLevelHover];
                                    return (
                                    <Box
                                        key={colorName}
                                        as="button"
                                        bg={isColorSelected ? accentColorHover : accentColorInitial}
                                        _hover={{
                                            bg: accentColorHover,
                                        }}
                                        w="36px"
                                        h="36px"
                                        borderRadius="50%"
                                        mx={1}
                                        my={1}
                                        onClick={handleAccentColorChange}
                                        data-colorname={colorName}
                                    >
                                        {isColorSelected && (
                                            <CheckIcon color="#FFF" />
                                        )}
                                    </Box>
                                    );
                                })}
                            </Flex>
                        </FormControl>
                        <FormControl
                            isRequired
                            mt={formControlTopMargin}
                        >
                            <FormLabel
                                htmlFor="input-name"
                            >
                                Name
                            </FormLabel>
                            <Input
                                id="input-name"
                                name="name"
                                ref={register}
                            />
                        </FormControl>
                        <FormControl
                            isRequired
                            mt={formControlTopMargin}
                        >
                            <FormLabel
                                htmlFor="input-verb"
                            >
                                Payment action name
                            </FormLabel>
                            <Select
                                id="input-verb"
                                name="verb"
                                ref={register}
                            >
                                <option value="pay">Pay</option>
                                <option value="donate to">Donate to</option>
                                <option value="support">Support</option>
                                <option value="tip">Tip</option>
                            </Select>
                        </FormControl>
                        <FormControl
                            mt={formControlTopMargin}
                        >
                            <FormLabel
                                htmlFor="input-website"
                            >
                                Website
                            </FormLabel>
                            <Input
                                id="input-website"
                                name="website"
                                ref={register}
                                placeholder="http://"
                                type="url"
                            />
                        </FormControl>
                        <FormControl
                            mt={formControlTopMargin}
                        >
                            <FormLabel
                                htmlFor="input-paymentmethods"
                            >
                                Payment Methods
                            </FormLabel>
                            <PaymentMethodsInput
                                fields={fields}
                                control={control}
                                register={register}
                                remove={remove}
                                append={append}
                                fieldArrayName={paymentMethodsFieldArrayName}
                            />
                        </FormControl>
                    </ModalBody>
                    <Flex
                        id="modal-footer"
                        justify="space-between"
                        m={6}
                    >
                        <DeleteButton
                            piggybankName={initialPiggybankId}
                        />
                        <Flex>
                            <Button
                                variant="ghost"
                                onClick={onClose}
                            >
                                Cancel
                            </Button>
                            <Button
                                id="save-configuration-btn"
                                colorScheme="green"
                                mx={1}
                                type="submit"
                                isLoading={isSubmitting}
                                loadingText="Saving"
                                isDisabled={
                                    (
                                        !isDirty
                                        && !isAccentColorDirty // controlled accentColor field is not showing up in formState.dirtyFields
                                    )
                                    || !isPiggybankIdAvailable
                                    || !initialPiggybankId
                                }
                                onClick={() => setIsAddressTouched(true)}
                            >
                                Save
                            </Button>
                        </Flex>
                    </Flex>
                </form>
            </ModalContent>
        </Modal>
    );
}
Example #22
Source File: carousel.tsx    From notebook with MIT License 4 votes vote down vote up
Carousel: React.SFC<CarouselProps> = ({
  onOpen,
  onClose,
  isOpen,
  repoId
}) => {
  const [[page, direction], setPage] = React.useState([0, 0]);
  const [imageIndex, setImageIndex] = React.useState<number>(0);

  const paginate = (newDirection: number) => {
    setPage([page + newDirection, newDirection]);
  };

  React.useEffect(() => {
    setImageIndex(repoId);
  }, [repoId]);

  const nextImage = (newDirection: number) => {
    paginate(newDirection);
    setImageIndex(imageIndex + 1 < coverImages.length ? imageIndex + 1 : 0);
  };

  const prevImage = (newDirection: number) => {
    paginate(newDirection);
    setImageIndex(
      0 === imageIndex ? coverImages.length - 1 : imageIndex - 1
    );
  };

  return (
    <Modal isCentered onClose={onClose} size={"6xl"} isOpen={isOpen}>
      <ModalOverlay />
      <ModalContent>
        <ModalBody padding="0">
          <div className="carousel-container">
            <AnimatePresence initial={false} custom={direction}>
              <motion.img
                key={page}
                src={coverImages[imageIndex]}
                custom={direction}
                variants={variants}
                initial="enter"
                animate="center"
                exit="exit"
                transition={{
                  x: { type: "spring", stiffness: 300, damping: 30 },
                  opacity: { duration: 0.2 }
                }}
                drag="x"
                dragConstraints={{ left: 0, right: 0 }}
                dragElastic={1}
                onDragEnd={(e, { offset, velocity }) => {
                  const swipe = swipePower(offset.x, velocity.x);

                  if (swipe < -swipeConfidenceThreshold) {
                    paginate(1);
                  } else if (swipe > swipeConfidenceThreshold) {
                    paginate(-1);
                  }
                }}
              />
            </AnimatePresence>
            <div className="next" onClick={() => nextImage(1)}>
              <IconButton
                aria-label="left image"
                icon={<ChevronLeftIcon />}
                cursor="pointer"
                as={ChevronRightIcon}
                size="md"
                colorScheme="teal"
                borderRadius="full"
              />
            </div>

            <div className="prev" onClick={() => prevImage(-1)}>
              <IconButton
                aria-label="right image"
                icon={<ChevronRightIcon />}
                cursor="pointer"
                as={ChevronLeftIcon}
                size="md"
                colorScheme="teal"
                borderRadius="full"
              />
            </div>
          </div>
        </ModalBody>
      </ModalContent>
    </Modal>
  );
}
Example #23
Source File: note-form.tsx    From notebook with MIT License 4 votes vote down vote up
NoteForm: React.SFC<NoteFormProps> = ({
  isOpen,
  onClose,
  selectedNote,
  handleNoteCreate,
  handleNoteUpdate
}) => {
  const { register, handleSubmit, formState, errors } = useForm<FormInputs>({
    mode: "onChange"
  });

  const onSubmit: SubmitHandler<FormInputs> = data => {
    let newNote: note = {
      id: "",
      title: data.title,
      body: data.body
    };
    if (handleNoteCreate) {
      newNote.id = nanoid();
      if (handleNoteCreate) handleNoteCreate(newNote);
    } else {
      newNote.id = selectedNote ? selectedNote.id : "";
      if (handleNoteUpdate) handleNoteUpdate(newNote);
    }
    onClose();
  };

  const validateTitle = (value: string) => {
    if (!value) {
      return "Title is required";
    } else return true;
  };

  const validateBody = (value: string) => {
    if (!value) {
      return "Body is required";
    } else return true;
  };

  return (
    <Modal
      isOpen={isOpen}
      onClose={onClose}
      size="lg"
      isCentered
      motionPreset="slideInBottom"
    >
      <ModalOverlay />
      <ModalContent>
        <form onSubmit={handleSubmit(onSubmit)}>
          <ModalHeader>{selectedNote ? "Edit" : "Create"} a Note</ModalHeader>
          <ModalCloseButton />
          <ModalBody pb={6}>
            <FormControl isInvalid={!!errors?.title} isRequired>
              <FormLabel>Title</FormLabel>
              <Input
                name="title"
                placeholder="Title"
                defaultValue={selectedNote?.title}
                ref={register({ validate: validateTitle })}
              />
              <FormErrorMessage>
                {!!errors?.title && errors?.title?.message}
              </FormErrorMessage>
            </FormControl>
            <FormControl size="lg" mt={4} isInvalid={!!errors?.body} isRequired>
              <FormLabel>Body</FormLabel>
              <Textarea
                name="body"
                placeholder="Body"
                size="md"
                borderRadius="5px"
                defaultValue={selectedNote?.body}
                ref={register({ validate: validateBody })}
              />
              <FormErrorMessage>
                {!!errors?.body && errors?.body?.message}
              </FormErrorMessage>
            </FormControl>
          </ModalBody>
          <ModalFooter>
            <Button
              type="submit"
              colorScheme="blue"
              isLoading={formState.isSubmitting}
              mr={3}
            >
              Save
            </Button>
            <Button onClick={onClose}>Cancel</Button>
          </ModalFooter>
        </form>
      </ModalContent>
    </Modal>
  );
}
Example #24
Source File: offline-data-card.tsx    From portfolio with MIT License 4 votes vote down vote up
RepositoryCard = (props: RepositoryCardProps) => {
  const {
    key,
    title,
    description,
    cover,
    blurHash,
    technologies,
    url,
    live,
    stars,
    fork,
  } = props;
  const { isOpen, onOpen, onClose } = useDisclosure();

  const handleClick = () => {
    onOpen();
    // window.open(link);
    // if (type == "link" || type == "article") {
    //   window.open(link);
    // } else {
    //   onOpen();
    // }
  };

  const handleLinkClick = (
    e: React.MouseEvent<HTMLParagraphElement, MouseEvent>,
    link: string
  ) => {
    window.open(link);
    e.stopPropagation();
  };

  const transition = { duration: 0.5, ease: [0.43, 0.13, 0.23, 0.96] };

  const thumbnailVariants = {
    initial: { scale: 0.9, opacity: 0 },
    enter: { scale: 1, opacity: 1, transition },
    exit: {
      scale: 0.5,
      opacity: 0,
      transition: { duration: 1.5, ...transition }
    }
  };

  const imageVariants = {
    hover: { scale: 1.1 }
  };

  return (
    <CardTransition>
      <Box onClick={handleClick} cursor="pointer" size="xl">
        <VStack
          //   w="100%"
          rounded="xl"
          borderWidth="1px"
          bg={useColorModeValue("white", "gray.800")}
          borderColor={useColorModeValue("gray.100", "gray.700")}
          _hover={{
            shadow: "lg",
            textDecoration: "none"
          }}
          overflow="hidden"
          align="start"
          spacing={0}
        >
          <Box position="relative" w="100%">
            <MotionBox variants={thumbnailVariants}>
              <MotionBox
                whileHover="hover"
                variants={imageVariants}
                transition={transition}
              >
                <AspectRatio
                  ratio={1.85 / 1}
                  maxW="400px"
                  w="100%"
                  borderBottomWidth="1px"
                  borderColor={useColorModeValue("gray.100", "gray.700")}
                >
                  {/* <Image
                    src={cover}
                    fallback={<Skeleton />}
                    objectFit="cover"
                  /> */}
                  <LazyImage
                    src={cover}
                    blurHash={blurHash}
                  />
                </AspectRatio>
              </MotionBox>
            </MotionBox>
          </Box>

          <VStack py={2} px={[2, 4]} spacing={1} align="start" w="100%">
            <Flex justifyContent={"space-between"} width="100%">
              <Tooltip hasArrow label="Github link" placement="top">
                <HStack>
                  <Icon as={FiGithub} boxSize="0.9em" mt={"1px"} />
                  {/* <Link href={url} isExternal> */}
                  <Text
                    fontSize="sm"
                    noOfLines={1}
                    fontWeight="600"
                    align="left"
                    onClick={e => handleLinkClick(e, url)}
                  >
                    {title}
                  </Text>
                </HStack>
              </Tooltip>
              {/* </Link> */}
              <Flex>
                <Icon as={AiOutlineStar} boxSize="0.9em" mt={"1px"} />
                <Box as="span" ml="1" fontSize="sm">
                  {stars}
                </Box>
              </Flex>
            </Flex>
            <Flex justifyContent={"space-between"} width="100%">
              <Box>
                <HStack spacing="1">
                  {technologies.map(tech => (
                    <Tag size="sm" colorScheme={getTagColor(tech)}>
                      <Text fontSize={["0.55rem", "inherit", "inherit"]}>
                        {tech}
                      </Text>
                    </Tag>
                  ))}
                </HStack>
              </Box>
            </Flex>
            {/* <Flex justifyContent={"space-between"} width="100%">
              <Flex>
                <AiOutlineStar color="teal.300" />
                <Box as="span" ml="1" fontSize="sm">
                  {stars}
                </Box>
              </Flex>
              <Box >
              <Text
                fontSize="xs"
                fontWeight="400"
                color={useColorModeValue("gray.400", "gray.500")}
              >
                {created}
              </Text>
            </Box>
            </Flex> */}
          </VStack>
        </VStack>
        <Modal isOpen={isOpen} onClose={onClose} isCentered allowPinchZoom>
          <ModalOverlay />
          <ModalContent bg="none" maxW={"28rem"} w="auto">
            <ModalBody p={0} rounded="lg" overflow="hidden" bg="none">
              <Center>
                <Image src={cover} rounded="lg" />
                {/* {type == "image" ? (
                <Image src={cover} rounded="lg" />
              ) : (
                <ReactPlayer url={link} controls playing />
              )} */}
              </Center>
            </ModalBody>
          </ModalContent>
        </Modal>
      </Box>
    </CardTransition>
  );
}
Example #25
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
SchemaArray: React.FunctionComponent<SchemaArrayProps> = (
	props: React.PropsWithChildren<SchemaArrayProps>
) => {
	const { schemaState, isReadOnly } = props;

	const state = useState(schemaState.items as JSONSchema7);
	const isReadOnlyState = useState(isReadOnly);

	const { length } = state.path.filter((name) => name !== "properties");
	const tagPaddingLeftStyle = {
		paddingLeft: `${20 * (length + 1)}px`,
	};

	const onCloseAdvanced = (): void => {
		localState.isAdvancedOpen.set(false);
	};

	const showadvanced = (): void => {
		localState.isAdvancedOpen.set(true);
	};

	const focusRef = React.createRef<HTMLElement>();

	const localState = useState({
		isAdvancedOpen: false,
	});

	return (
		<>
			<Flex
				direction="row"
				wrap="nowrap"
				className="array-item"
				mt={2}
				mr={5}
				style={tagPaddingLeftStyle}
			>
				<Input
					key="Items"
					isDisabled
					value="Items"
					size="sm"
					flexShrink={1}
					margin={2}
					variant="outline"
				/>
				<Checkbox isDisabled margin={2} colorScheme="blue" />
				<Select
					variant="outline"
					isDisabled={isReadOnlyState.value}
					value={state.type.value as JSONSchema7TypeName}
					size="sm"
					margin={2}
					placeholder="Choose data type"
					onChange={(evt: React.ChangeEvent<HTMLSelectElement>) => {
						const newSchema = handleTypeChange(
							evt.target.value as JSONSchema7TypeName,
							false
						);
						state.set(newSchema as JSONSchema7);
					}}
				>
					{SchemaTypes.map((item, index) => {
						return (
							<option key={String(index)} value={item}>
								{item}
							</option>
						);
					})}
				</Select>
				<Input
					value={state.title.value}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Title"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.title.set(evt.target.value);
					}}
				/>
				<Input
					value={state.description.value}
					isDisabled={isReadOnlyState.value}
					size="sm"
					margin={2}
					variant="outline"
					placeholder="Add Description"
					onChange={(evt: React.ChangeEvent<HTMLInputElement>) => {
						state.description.set(evt.target.value);
					}}
				/>
				<Tooltip
					hasArrow
					aria-label="Advanced Settings"
					label="Advanced Settings"
					placement="top"
				>
					<IconButton
						isRound
						isDisabled={isReadOnlyState.value}
						size="sm"
						mt={2}
						mb={2}
						ml={1}
						variant="link"
						colorScheme="blue"
						fontSize="16px"
						icon={<FiSettings />}
						aria-label="Advanced Settings"
						onClick={() => {
							showadvanced();
						}}
					/>
				</Tooltip>

				{state.type.value === "object" && (
					<Tooltip
						hasArrow
						aria-label="Add Child Node"
						label="Add Child Node"
						placement="top"
					>
						<IconButton
							isRound
							isDisabled={isReadOnlyState.value}
							size="sm"
							mt={2}
							mb={2}
							mr={2}
							variant="link"
							colorScheme="green"
							fontSize="16px"
							icon={<IoIosAddCircleOutline />}
							aria-label="Add Child Node"
							onClick={() => {
								const fieldName = `field_${random()}`;
								(state.properties as State<{
									[key: string]: JSONSchema7;
								}>)[fieldName].set(getDefaultSchema(DataType.string));
							}}
						/>
					</Tooltip>
				)}
			</Flex>
			{state.type?.value === "object" && (
				<SchemaObject isReadOnly={isReadOnlyState} schemaState={state} />
			)}
			{state.type?.value === "array" && (
				<SchemaArray isReadOnly={isReadOnlyState} schemaState={state} />
			)}
			<Modal
				isOpen={localState.isAdvancedOpen.get()}
				finalFocusRef={focusRef}
				size="lg"
				onClose={onCloseAdvanced}
			>
				<ModalOverlay />
				<ModalContent>
					<ModalHeader textAlign="center">Advanced Schema Settings</ModalHeader>

					<ModalBody>
						<AdvancedSettings itemStateProp={state} />
					</ModalBody>

					<ModalFooter>
						<Button
							colorScheme="blue"
							variant="ghost"
							mr={3}
							onClick={onCloseAdvanced}
						>
							Close
						</Button>
					</ModalFooter>
				</ModalContent>
			</Modal>
		</>
	);
}
Example #26
Source File: index.tsx    From jsonschema-editor-react with Apache License 2.0 4 votes vote down vote up
SchemaObject: React.FunctionComponent<SchemaObjectProps> = (
	props: React.PropsWithChildren<SchemaObjectProps>
) => {
	const { schemaState, isReadOnly } = props;
	const schema = useState(schemaState);
	const properties = useState(schema.properties);

	const propertiesOrNull:
		| State<{
				[key: string]: JSONSchema7Definition;
		  }>
		| undefined = properties.ornull;

	const isReadOnlyState = useState(isReadOnly);

	const onCloseAdvanced = (): void => {
		localState.isAdvancedOpen.set(false);
	};

	const showadvanced = (item: string): void => {
		localState.isAdvancedOpen.set(true);
		localState.item.set(item);
	};

	const focusRef = React.createRef<HTMLElement>();

	const localState = useState({
		isAdvancedOpen: false,
		item: "",
	});

	if (!propertiesOrNull) {
		return <></>;
	} else {
		return (
			<div className="object-style">
				{propertiesOrNull?.keys?.map((name) => {
					return (
						<SchemaItem
							key={String(name)}
							itemStateProp={
								propertiesOrNull.nested(name as string) as State<JSONSchema7>
							}
							parentStateProp={schema}
							name={name as string}
							showadvanced={showadvanced}
							required={schema.required.value as string[]}
							isReadOnly={isReadOnlyState}
						/>
					);
				})}
				<Modal
					isOpen={localState.isAdvancedOpen.get()}
					finalFocusRef={focusRef}
					size="lg"
					onClose={onCloseAdvanced}
				>
					<ModalOverlay />
					<ModalContent>
						<ModalHeader textAlign="center">
							Advanced Schema Settings
						</ModalHeader>

						<ModalBody>
							<AdvancedSettings
								itemStateProp={
									propertiesOrNull.nested(
										localState.item.value as string
									) as State<JSONSchema7>
								}
							/>
						</ModalBody>

						<ModalFooter>
							<Button
								colorScheme="blue"
								variant="ghost"
								mr={3}
								onClick={onCloseAdvanced}
							>
								Close
							</Button>
						</ModalFooter>
					</ModalContent>
				</Modal>
			</div>
		);
	}
}
Example #27
Source File: About.tsx    From calories-in with MIT License 4 votes vote down vote up
function About({ isOpen, onClose }: Props) {
  function onContact() {
    window.location.href = 'mailto:[email protected]'
  }

  return (
    <Modal isOpen={isOpen} onClose={onClose} size="2xl" scrollBehavior="inside">
      <ModalOverlay />
      <ModalContent>
        <ModalHeader>About </ModalHeader>
        <ModalCloseButton />
        <ModalBody>
          <Text fontSize="lg">
            <Text>Hi, I'm Vladimir, the person behind this project.</Text>
            <br />
            <Text>
              <Text fontWeight="semibold" as="span" textColor="teal.600">
                Calories-In
              </Text>{' '}
              is made for people who follow meal plans that involve preparing
              everything by yourself and gives them full control to fine tune
              the nutritional values.
            </Text>
            <br />
            <Text>
              The idea was born out of my experience of trying to find a better
              alternative to Google Sheets for calculating the macros of my own
              meal plans. I wanted to be able to do this on desktop as it's more
              convenient but nothing really felt fast and simple enough.
            </Text>
            <br />
            <Text>The main differences to other apps in this space are:</Text>
            <br />
            <List ml={8}>
              <ListItem>
                <ListIcon as={CheckCircle} color="teal.600" />
                <Text fontWeight="semibold" as="span" textColor="teal.600">
                  Faster search
                </Text>{' '}
                : There are actually not that many foods you need when you
                prepare everything yourself. This means all of the food data can
                be downloaded beforehand which makes the search super fast. Of
                course you can add your own foods if you'd like.{' '}
              </ListItem>
              <br />
              <ListItem>
                <ListIcon as={CheckCircle} color="teal.600" />
                <Text fontWeight="semibold" as="span" textColor="teal.600">
                  Undo/Redo
                </Text>{' '}
                : Building a plan from scratch or updating an existing one
                involves some back and forth choosing the right foods and
                adjusting their amounts. This is especially true if you want to
                be as close as possible to a specific calorie limit and have
                your macros be a certain percentages split.
              </ListItem>
              <br />
              <ListItem>
                <ListIcon as={CheckCircle} color="teal.600" />
                <Text fontWeight="semibold" as="span" textColor="teal.600">
                  Faster export
                </Text>{' '}
                : Creating the PDF file for your meal plan is done entirely
                inside the browser. It does not involve generating and
                downloading it from a server. This means I can keep the cost of
                running the website low and you get your file in just a few
                seconds.
              </ListItem>
              <br />
              <ListItem>
                <ListIcon as={CheckCircle} color="teal.600" />
                <Text fontWeight="semibold" as="span" textColor="teal.600">
                  Simpler
                </Text>{' '}
                : There are no other pages except the editor. Most of the other
                tools are bloated with additional features for professionals,
                such as managing clients, creating invoices, etc.
              </ListItem>
              <br />
              <ListItem>
                <ListIcon as={CheckCircle} color="teal.600" />
                <Text fontWeight="semibold" as="span" textColor="teal.600">
                  Fully mobile
                </Text>{' '}
                : You can use your phone or tablet to build your meal plans
                right from your browser. If you add the app to your home screen
                it will look and feel almost like a native one.
              </ListItem>
            </List>
            <Text>
              <br />
              Let me know if you found it useful or have any comments in
              general:
            </Text>
            <br />

            <Button size="lg" colorScheme="teal" onClick={onContact}>
              Contact me directly
            </Button>

            <br />
            <br />
            <Text>No email will go unanswered, I promise :)</Text>
          </Text>
        </ModalBody>

        <ModalFooter>
          <Button size="lg" onClick={onClose}>
            Close
          </Button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  )
}
Example #28
Source File: EditRewardsDistributorModal.tsx    From rari-dApp with GNU Affero General Public License v3.0 4 votes vote down vote up
EditRewardsDistributorModal = ({
  rewardsDistributor,
  pool,
  isOpen,
  onClose,
}: {
  rewardsDistributor: RewardsDistributor;
  pool: FusePoolData;
  isOpen: boolean;
  onClose: () => any;
}) => {
  const { t } = useTranslation();

  const { address, fuse } = useRari();
  const rewardsDistributorInstance = useRewardsDistributorInstance(
    rewardsDistributor.address
  );
  const tokenData = useTokenData(rewardsDistributor.rewardToken);
  const isAdmin = address === rewardsDistributor.admin;

  //   Balances
  const { data: balanceERC20 } = useTokenBalance(
    rewardsDistributor.rewardToken,
    rewardsDistributor.address
  );

  const { data: myBalance } = useTokenBalance(rewardsDistributor.rewardToken);

  const toast = useToast();

  // Inputs
  const [sendAmt, setSendAmt] = useState<number>(0);

  const [supplySpeed, setSupplySpeed] = useState<number>(0.001);
  const [borrowSpeed, setBorrowSpeed] = useState<number>(0.001);

  //  Loading states
  const [fundingDistributor, setFundingDistributor] = useState(false);
  const [seizing, setSeizing] = useState(false);
  const [changingSpeed, setChangingSpeed] = useState(false);
  const [changingBorrowSpeed, setChangingBorrowSpeed] = useState(false);
  const [selectedAsset, setSelectedAsset] = useState<
    USDPricedFuseAsset | undefined
  >(pool?.assets[0] ?? undefined);

  //   RewardsSpeeds
  const [supplySpeedForCToken, borrowSpeedForCToken] = useRewardSpeedsOfCToken(
    rewardsDistributor.address,
    selectedAsset?.cToken
  );

  const { hasCopied, onCopy } = useClipboard(rewardsDistributor?.address ?? "");

  // Sends tokens to distributor
  const fundDistributor = async () => {
    // Create ERC20 instance of rewardToken
    const token = new fuse.web3.eth.Contract(
      JSON.parse(
        fuse.compoundContracts["contracts/EIP20Interface.sol:EIP20Interface"]
          .abi
      ),
      rewardsDistributor.rewardToken
    );

    setFundingDistributor(true);
    try {
      await token.methods
        .transfer(
          rewardsDistributor.address,
          Fuse.Web3.utils
            .toBN(sendAmt)
            .mul(
              Fuse.Web3.utils
                .toBN(10)
                .pow(Fuse.Web3.utils.toBN(tokenData?.decimals ?? 18))
            )
        )
        .send({
          from: address,
        });

      setFundingDistributor(false);
    } catch (err) {
      handleGenericError(err, toast);
      setFundingDistributor(false);
    }
  };

  //   Adds LM to supply side of a CToken in this fuse pool
  const changeSupplySpeed = async () => {
    try {
      if (!isAdmin) throw new Error("User is not admin of this Distributor!");

      setChangingSpeed(true);

      await rewardsDistributorInstance.methods
        ._setCompSupplySpeed(
          selectedAsset?.cToken,
          Fuse.Web3.utils.toBN(supplySpeed * 10 ** (tokenData?.decimals ?? 18)) // set supplySpeed to 0.001e18 for now
        )
        .send({ from: address });

      setChangingSpeed(false);
    } catch (err) {
      handleGenericError(err, toast);
      setChangingSpeed(false);
    }
  };

  //   Adds LM to supply side of a CToken in this fuse pool
  const changeBorrowSpeed = async () => {
    try {
      if (!isAdmin) throw new Error("User is not admin of this Distributor!");

      setChangingBorrowSpeed(true);

      await rewardsDistributorInstance.methods
        ._setCompBorrowSpeed(
          selectedAsset?.cToken,
          Fuse.Web3.utils.toBN(borrowSpeed * 10 ** (tokenData?.decimals ?? 18)) // set supplySpeed to 0.001e18 for now
        )
        .send({ from: address });

      setChangingBorrowSpeed(false);
    } catch (err) {
      handleGenericError(err, toast);
      setChangingBorrowSpeed(false);
    }
  };

  const handleSeizeTokens = async () => {
    setSeizing(true);
    if (isAdmin) {
      await rewardsDistributorInstance.methods._grantComp(
        address,
        balanceERC20
      );
    } else {
      toast({
        title: "Admin Only!",
        description: "Only admin can seize tokens!",
        status: "error",
        duration: 9000,
        isClosable: true,
        position: "top-right",
      });
    }
    setSeizing(false);
  };

  return (
    <Modal
      motionPreset="slideInBottom"
      isOpen={isOpen}
      onClose={onClose}
      isCentered
    >
      <ModalOverlay />
      <ModalContent {...MODAL_PROPS}>
        <Heading fontSize="27px" my={4} textAlign="center">
          {t("Edit Rewards Distributor")}
        </Heading>

        <ModalDivider />

        {/*  RewardToken data */}
        <Column
          mainAxisAlignment="flex-start"
          crossAxisAlignment="center"
          p={4}
        >
          <>
            {tokenData?.logoURL ? (
              <Image
                mt={4}
                src={tokenData.logoURL}
                boxSize="50px"
                borderRadius="50%"
                backgroundImage={`url(${SmallWhiteCircle})`}
                backgroundSize="100% auto"
              />
            ) : null}
            <Heading
              my={tokenData?.symbol ? 3 : 6}
              fontSize="22px"
              color={tokenData?.color ?? "#FFF"}
            >
              {tokenData ? tokenData.name ?? "Invalid Address!" : "Loading..."}
            </Heading>
            <Text>
              {balanceERC20 && tokenData && tokenData.decimals
                ? (
                    parseFloat(balanceERC20?.toString()) /
                    10 ** tokenData.decimals
                  ).toFixed(3)
                : 0}{" "}
              {tokenData?.symbol}
            </Text>
            <Text onClick={onCopy}>
              Contract: {shortAddress(rewardsDistributor.address)}{" "}
              {hasCopied && "Copied!"}
            </Text>
          </>
        </Column>

        <AdminAlert
          isAdmin={isAdmin}
          mt={2}
          isNotAdminText="You are not the admin of this RewardsDistributor. Only the admin can configure rewards."
        />

        {/* Basic Info  */}
        <Column
          mainAxisAlignment="flex-start"
          crossAxisAlignment="flex-start"
          py={4}
        >
          {/* <Row mainAxisAlignment="flex-start" crossAxisAlignment="center">
            <Text>Address: {rewardsDistributor.address}</Text>
          </Row>
          <Row mainAxisAlignment="flex-start" crossAxisAlignment="center">
            <Text>Admin: {rewardsDistributor.admin}</Text>
          </Row>
          <Row mainAxisAlignment="flex-start" crossAxisAlignment="center">
            <Text>
              Balance:{" "}
              {balanceERC20 ? parseFloat(balanceERC20?.toString()) / 1e18 : 0}{" "}
              {tokenData?.symbol}
            </Text>
          </Row> */}

          <ModalDivider />

          {/* Fund distributor */}
          <Column
            mainAxisAlignment="flex-start"
            crossAxisAlignment="flex-start"
            p={4}
          >
            <Heading fontSize={"lg"}> Fund Distributor </Heading>
            <Row
              mainAxisAlignment="flex-start"
              crossAxisAlignment="center"
              mt={1}
            >
              <NumberInput
                step={0.1}
                min={0}
                onChange={(valueString) => {
                  console.log({ valueString });
                  setSendAmt(parseFloat(valueString));
                }}
              >
                <NumberInputField
                  width="100%"
                  textAlign="center"
                  placeholder={"0 " + tokenData?.symbol}
                />
                <NumberInputStepper>
                  <NumberIncrementStepper />
                  <NumberDecrementStepper />
                </NumberInputStepper>
              </NumberInput>
              <Button
                onClick={fundDistributor}
                bg="black"
                disabled={fundingDistributor}
              >
                {fundingDistributor ? <Spinner /> : "Send"}
              </Button>
              {isAdmin && (!balanceERC20?.isZero() ?? false) && (
                <Button onClick={handleSeizeTokens} bg="red" disabled={seizing}>
                  {seizing ? <Spinner /> : "Withdraw Tokens"}
                </Button>
              )}
            </Row>
            <Text mt={1}>
              Your balance:{" "}
              {myBalance
                ? (
                    parseFloat(myBalance?.toString()) /
                    10 ** (tokenData?.decimals ?? 18)
                  ).toFixed(2)
                : 0}{" "}
              {tokenData?.symbol}
            </Text>
          </Column>

          {/* Add or Edit a CToken to the Distributor */}

          {pool.assets.length ? (
            <Column
              mainAxisAlignment="flex-start"
              crossAxisAlignment="flex-start"
              p={4}
            >
              <Heading fontSize={"lg"}> Manage CToken Rewards </Heading>
              {/* Select Asset */}
              <Row
                mainAxisAlignment="flex-start"
                crossAxisAlignment="center"
                mt={1}
              >
                {pool.assets.map(
                  (asset: USDPricedFuseAsset, index: number, array: any[]) => {
                    return (
                      <Box
                        pr={index === array.length - 1 ? 4 : 2}
                        key={asset.cToken}
                        flexShrink={0}
                      >
                        <DashboardBox
                          as="button"
                          onClick={() => setSelectedAsset(asset)}
                          {...(asset.cToken === selectedAsset?.cToken
                            ? activeStyle
                            : noop)}
                        >
                          <Center expand px={4} py={1} fontWeight="bold">
                            {asset.underlyingSymbol}
                          </Center>
                        </DashboardBox>
                      </Box>
                    );
                  }
                )}
              </Row>

              {/* Change Supply Speed */}
              <Column
                mainAxisAlignment="flex-start"
                crossAxisAlignment="flex-start"
                py={3}
              >
                <Row
                  mainAxisAlignment="flex-start"
                  crossAxisAlignment="flex-start"
                >
                  <NumberInput
                    step={0.1}
                    min={0}
                    onChange={(supplySpeed) => {
                      console.log({ supplySpeed });
                      setSupplySpeed(parseFloat(supplySpeed));
                    }}
                  >
                    <NumberInputField
                      width="100%"
                      textAlign="center"
                      placeholder={"0 " + tokenData?.symbol}
                    />
                    <NumberInputStepper>
                      <NumberIncrementStepper />
                      <NumberDecrementStepper />
                    </NumberInputStepper>
                  </NumberInput>
                  <Button
                    onClick={changeSupplySpeed}
                    bg="black"
                    disabled={changingSpeed || !isAdmin}
                  >
                    {changingSpeed ? <Spinner /> : "Set"}
                  </Button>
                </Row>
                <Row
                  mainAxisAlignment="flex-start"
                  crossAxisAlignment="flex-start"
                >
                  <Text>
                    Supply Speed:{" "}
                    {(parseFloat(supplySpeedForCToken) / 1e18).toFixed(4)}
                  </Text>
                </Row>
              </Column>

              {/* Change Borrow Speed */}
              <Column
                mainAxisAlignment="flex-start"
                crossAxisAlignment="flex-start"
                py={3}
              >
                <Row
                  mainAxisAlignment="flex-start"
                  crossAxisAlignment="flex-start"
                >
                  <NumberInput
                    step={0.1}
                    min={0}
                    onChange={(borrowSpeed) => {
                      console.log({ borrowSpeed });
                      setBorrowSpeed(parseFloat(borrowSpeed));
                    }}
                  >
                    <NumberInputField
                      width="100%"
                      textAlign="center"
                      placeholder={"0 " + tokenData?.symbol}
                    />
                    <NumberInputStepper>
                      <NumberIncrementStepper />
                      <NumberDecrementStepper />
                    </NumberInputStepper>
                  </NumberInput>

                  <Button
                    onClick={changeBorrowSpeed}
                    bg="black"
                    disabled={changingBorrowSpeed || !isAdmin}
                  >
                    {changingBorrowSpeed ? <Spinner /> : "Set"}
                  </Button>
                </Row>
                <Row
                  mainAxisAlignment="flex-start"
                  crossAxisAlignment="flex-start"
                >
                  <Text>
                    Borrow Speed:{" "}
                    {(parseFloat(borrowSpeedForCToken) / 1e18).toFixed(2)}
                  </Text>
                </Row>
              </Column>
            </Column>
          ) : (
            <Center p={4}>
              <Text fontWeight="bold">
                Add CTokens to this pool to configure their rewards.
              </Text>
            </Center>
          )}
        </Column>
      </ModalContent>
    </Modal>
  );
}
Example #29
Source File: Inspector.tsx    From openchakra with MIT License 4 votes vote down vote up
Inspector = () => {
  const dispatch = useDispatch()
  const component = useSelector(getSelectedComponent)
  const { isOpen, onOpen, onClose } = useDisclosure()
  const [componentName, onChangeComponentName] = useState('')
  const componentsNames = useSelector(getComponentNames)

  const { clearActiveProps } = useInspectorUpdate()

  const saveComponent = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    dispatch.components.setComponentName({
      componentId: component.id,
      name: componentName,
    })
    onClose()
    onChangeComponentName('')
  }
  const isValidComponentName = useMemo(() => {
    return (
      !!componentName.match(/^[A-Z]\w*$/g) &&
      !componentsNames.includes(componentName) &&
      // @ts-ignore
      !componentsList.includes(componentName)
    )
  }, [componentName, componentsNames])

  const { type, rootParentType, id, children } = component

  const isRoot = id === 'root'
  const parentIsRoot = component.parent === 'root'

  const docType = rootParentType || type
  const componentHasChildren = children.length > 0

  useEffect(() => {
    clearActiveProps()
  }, [clearActiveProps])

  return (
    <>
      <Box bg="white">
        <Box
          fontWeight="semibold"
          fontSize="md"
          color="yellow.900"
          py={2}
          px={2}
          boxShadow="sm"
          bg="yellow.100"
          display="flex"
          justifyContent="space-between"
          flexDir="column"
        >
          {isRoot ? 'Document' : type}
          {!!component.componentName && (
            <Text fontSize="xs" fontWeight="light">
              {component.componentName}
            </Text>
          )}
        </Box>
        {!isRoot && (
          <Stack
            direction="row"
            py={2}
            spacing={2}
            align="center"
            zIndex={99}
            px={2}
            flexWrap="wrap"
            justify="flex-end"
          >
            <CodeActionButton />
            {!component.componentName && (
              <ActionButton
                label="Name component"
                icon={<EditIcon path="" />}
                onClick={onOpen}
              />
            )}
            <ActionButton
              label="Duplicate"
              onClick={() => dispatch.components.duplicate()}
              icon={<CopyIcon path="" />}
            />
            <ActionButton
              label="Reset props"
              icon={<IoMdRefresh />}
              onClick={() => dispatch.components.resetProps(component.id)}
            />
            <ActionButton
              label="Chakra UI Doc"
              as={Link}
              onClick={() => {
                window.open(
                  `https://chakra-ui.com/${docType.toLowerCase()}`,
                  '_blank',
                )
              }}
              icon={<GoRepo />}
            />
            <ActionButton
              bg="red.500"
              label="Remove"
              onClick={() => dispatch.components.deleteComponent(component.id)}
              icon={<FiTrash2 />}
            />
          </Stack>
        )}
      </Box>

      <Box pb={1} bg="white" px={3}>
        <Panels component={component} isRoot={isRoot} />
      </Box>

      <StylesPanel
        isRoot={isRoot}
        showChildren={componentHasChildren}
        parentIsRoot={parentIsRoot}
      />
      <Modal onClose={onClose} isOpen={isOpen} isCentered>
        <ModalOverlay>
          <ModalContent>
            <form onSubmit={saveComponent}>
              <ModalHeader>Save this component</ModalHeader>
              <ModalCloseButton />
              <ModalBody>
                <FormControl isInvalid={!isValidComponentName}>
                  <FormLabel>Component name</FormLabel>
                  <Input
                    size="md"
                    autoFocus
                    variant="outline"
                    isFullWidth
                    focusBorderColor="blue.500"
                    errorBorderColor="red.500"
                    value={componentName}
                    onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
                      onChangeComponentName(e.target.value)
                    }
                  />
                  {!isValidComponentName && (
                    <FormErrorMessage>
                      Component name must start with a capital character and
                      must not contain space or special character, and name
                      should not be already taken (including existing chakra-ui
                      components).
                    </FormErrorMessage>
                  )}
                  <FormHelperText>
                    This will name your component that you will see in the code
                    panel as a separated component.
                  </FormHelperText>
                </FormControl>
              </ModalBody>
              <ModalFooter>
                <Button
                  colorScheme="blue"
                  mr={3}
                  type="submit"
                  isDisabled={!isValidComponentName}
                >
                  Save
                </Button>
                <Button onClick={onClose}>Cancel</Button>
              </ModalFooter>
            </form>
          </ModalContent>
        </ModalOverlay>
      </Modal>
    </>
  )
}