@chakra-ui/react#Spinner TypeScript Examples

The following examples show how to use @chakra-ui/react#Spinner. 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: Loader.tsx    From calories-in with MIT License 6 votes vote down vote up
function Loader({ label }: Props) {
  return (
    <Center height="200px" spacing={2}>
      <Flex flexDirection="column" alignItems="center">
        <Spinner size="lg" color="teal" />
        <Text mt={4} fontSize="lg" fontWeight="medium">
          {label}
        </Text>
      </Flex>
    </Center>
  )
}
Example #2
Source File: SpinnerMessage.tsx    From dope-monorepo with GNU General Public License v3.0 6 votes vote down vote up
SpinnerMessage = ({ text }: { text: string }) => {
  return (
    <SpinnerContainer>
      <div>
        <Spinner size="xs" />
      </div>
      <div>{text}</div>
    </SpinnerContainer>
  );
}
Example #3
Source File: create.tsx    From coindrop with GNU General Public License v3.0 6 votes vote down vote up
CreateFirstCoindrop: NextPage = () => {
    const { user } = useUser();
    const [isCreateTriggered, setIsCreateTriggered] = useState(false);
    const [candidatePiggybankPath, setCandidatePiggybankPath] = useState('');
    useCreatePiggybank(candidatePiggybankPath, setCandidatePiggybankPath, user, isCreateTriggered, setIsCreateTriggered);
    useEffect(() => {
        const pendingLoginCreatePiggybankPath = cookies.get('pendingLoginCreatePiggybankPath');
        if (pendingLoginCreatePiggybankPath) {
            setCandidatePiggybankPath(pendingLoginCreatePiggybankPath);
            setIsCreateTriggered(true);
        }
    }, []);
    return (
        <Flex
            direction="column"
            align="center"
            justify="center"
            my={6}
        >
            <Spinner size="lg" mb={3} />
            <Heading size="lg">
                Creating Coindrop...
            </Heading>
        </Flex>
    );
}
Example #4
Source File: EventWelcome.tsx    From dope-monorepo with GNU General Public License v3.0 6 votes vote down vote up
export default function EventWelcome(props: Props) {
    const [ loading, setLoading ] = useState(false);
    
    useEffect(() => {
        props.manager.events.on('game', () => setLoading(true));
    }, []);

    return (
        <ChakraProvider theme={theme}>
            <Center style={{
                height: "100vh",
                backdropFilter: "brightness(50%)",
            }}>
                {loading ? <Spinner size="xl" color="white" /> : <Container style={{
                    padding: "1rem",
                    borderStyle: "solid",
                    boxShadow: "0px 0px 15px rgba(0,0,0,1)",
                    borderColor: "black",
                    borderWidth: "0px",
                    backgroundColor: "white",
                    borderRadius: "7px",
                }}>
                {
                    <Stepper 
                        manager={props.manager} 
                    />
                }
                </Container>}
            </Center>
        </ChakraProvider>
    );
}
Example #5
Source File: FirebaseAuth.tsx    From coindrop with GNU General Public License v3.0 6 votes vote down vote up
FirebaseAuth: FunctionComponent = () => {
  // Do not SSR FirebaseUI, because it is not supported.
  // https://github.com/firebase/firebaseui-web/issues/213
  const [renderAuth, setRenderAuth] = useState(false);
  useEffect(() => {
    if (typeof window !== 'undefined') {
      setRenderAuth(true);
    }
  }, []);
  return (
    <div>
      {renderAuth ? (
        <StyledFirebaseAuth
          uiConfig={firebaseAuthConfig}
          firebaseAuth={firebase.auth()}
        />
      ) : <Spinner />}
    </div>
  );
}
Example #6
Source File: PoolPortal.tsx    From rari-dApp with GNU Affero General Public License v3.0 6 votes vote down vote up
CurrentAPY = () => {
  const { t } = useTranslation();

  const poolType = usePoolType();

  const poolAPY = usePoolAPY(poolType);

  return (
    <Row expand mainAxisAlignment="center" crossAxisAlignment="center">
      <Heading
        mt="5px"
        fontFamily={`'Baloo 2', ${theme.fonts.heading}`}
        fontSize="54px"
        fontWeight="extrabold"
      >
        {poolAPY ? (
          (poolAPY.startsWith("0.") ? poolAPY : poolAPY.slice(0, -1)) + "%"
        ) : (
          <Spinner size="lg" mr={4} />
        )}
      </Heading>
      <Text ml={3} width="65px" fontSize="sm" textTransform="uppercase">
        {t("Current APY")}
      </Text>
    </Row>
  );
}
Example #7
Source File: UI.tsx    From dope-monorepo with GNU General Public License v3.0 5 votes vote down vote up
loadingSpinner = () => <ChakraProvider theme={theme}>
  <Spinner size="xl" color="white" style={{
    position: 'absolute',
    bottom: '5%',
    right: '5%',
    boxShadow: '0px 0px 60px black',
  }} />
</ChakraProvider>
Example #8
Source File: FuseLiquidationsPage.tsx    From rari-dApp with GNU Affero General Public License v3.0 5 votes vote down vote up
LiquidationEventsList = ({
  liquidations,
  totalLiquidations,
  setLiquidationsToShow,
}: {
  liquidations?: LiquidationEvent[];
  totalLiquidations: number;
  setLiquidationsToShow: React.Dispatch<React.SetStateAction<number>>;
}) => {
  const { t } = useTranslation();

  const isMobile = useIsMobile();

  return (
    <Column
      mainAxisAlignment="flex-start"
      crossAxisAlignment="flex-start"
      expand
    >
      <Row
        mainAxisAlignment="flex-start"
        crossAxisAlignment="center"
        height="45px"
        width="100%"
        flexShrink={0}
        pl={4}
        pr={1}
      >
        <Text fontWeight="bold" width={isMobile ? "100%" : "30%"}>
          {t("Recent Liquidations")}
        </Text>

        {isMobile ? null : (
          <>
            <Text fontWeight="bold" textAlign="center" width="23%">
              {t("Collateral Seized")}
            </Text>

            <Text fontWeight="bold" textAlign="center" width="23%">
              {t("Borrow Repaid")}
            </Text>

            <Text fontWeight="bold" textAlign="center" width="25%">
              {t("Timestamp")}
            </Text>
          </>
        )}
      </Row>

      <ModalDivider />

      <Column
        mainAxisAlignment="flex-start"
        crossAxisAlignment="center"
        width="100%"
      >
        {liquidations ? (
          <>
            {liquidations.map((liquidation, index) => {
              return (
                <LiquidationRow
                  key={liquidation.transactionHash}
                  liquidation={liquidation}
                  noBottomDivider={index === liquidations.length - 1}
                />
              );
            })}

            <RowsControl
              totalAmount={totalLiquidations}
              setAmountToShow={setLiquidationsToShow}
            />
          </>
        ) : (
          <Spinner my={8} />
        )}
      </Column>
    </Column>
  );
}
Example #9
Source File: Hustlers.tsx    From dope-monorepo with GNU General Public License v3.0 5 votes vote down vote up
Hustlers = () => {
    const [hustlers, setHustlers] = React.useState<any>();

    useEffect(() => {
        if (!(window.ethereum as any)?.selectedAddress) return;

        fetch(`https://api.dopewars.gg/wallets/${ethers.utils.getAddress(
            (window.ethereum as any).selectedAddress,
          )}/hustlers`).then(res => res.json()).then(res => setHustlers(res));
    }, []);
    
    return (
        <div>
            {hustlers ? <SimpleGrid columns={2} spacing={5} paddingBottom="8">
                {
                    hustlers.map((hustler: any, i: number) =>
                        <VStack key={i}>
                            <Text paddingBottom="0px">
                                {hustler.id} {hustler.name ? " - " + hustler.name : ""}
                            </Text>
                            <object width="70%" type="image/svg+xml" data={hustler.svg} />
                            { localStorage.getItem(`gameSelectedHustler_${(window.ethereum as any).selectedAddress}`) !== hustler.id ? <Popover>
                                <PopoverTrigger>
                                    <Button variant="primary">
                                        Set as selected hustler
                                    </Button>
                                </PopoverTrigger>
                                <PopoverContent>
                                    <PopoverArrow />
                                    <PopoverCloseButton />
                                    <PopoverHeader>Are you sure?</PopoverHeader>
                                    <PopoverBody>The game needs to be reloaded in order to modify your selected hustler</PopoverBody>
                                    <PopoverFooter>
                                        <Button variant="primary" onClick={() => {
                                            localStorage.setItem(`gameSelectedHustler_${(window.ethereum as any).selectedAddress}`, hustler.id);
                                            window.location.reload();
                                        }}>
                                            Confirm
                                        </Button>
                                    </PopoverFooter>
                                </PopoverContent>
                            </Popover> : undefined }
                        </VStack>
                    )
                }
            </SimpleGrid> : <Center padding="4">
                    <Spinner size="lg"/>
                </Center>
            }
            <Center>
                <a href="/inventory">
                    <Button variant="primary">
                        Details
                    </Button>
                </a>
            </Center>
        </div>
    )
}
Example #10
Source File: LoadingSpinner.tsx    From ksana.in with Apache License 2.0 5 votes vote down vote up
export function LoadingSpinner() {
  return (
    <Spinner thickness="4px" speed="0.65s" emptyColor="gray.200" color="orange.400" size="xl" />
  )
}
Example #11
Source File: PiggybankListItem.tsx    From coindrop with GNU General Public License v3.0 5 votes vote down vote up
PiggybankListItem: FunctionComponent<Props> = ({ id }) => {
    const { colors } = useTheme();
    const [isLoading, setIsLoading] = useState(false);
    const hoverBg = useColorModeValue(colors.gray['100'], colors.gray['600']);
    const activeBg = useColorModeValue(colors.gray['200'], colors.gray['700']);
    return (
        <Box
            onClick={() => setIsLoading(true)}
            cursor="pointer"
            mt={3}
            bg={isLoading ? hoverBg : undefined}
            _hover={{
                bg: hoverBg,
                textDecoration: "none",
            }}
            _active={{
                bg: activeBg,
            }}
        >
            <NextLink href={`/${id}`} passHref>
                <a id={`link-to-coindrop-${id}`}>
                    <Box
                        py={5}
                        shadow="md"
                        borderWidth="1px"
                        borderRadius="10px"
                    >
                        {isLoading ? (
                            <Flex align="center" justify="center">
                                <Spinner boxSize="32px" />
                                <Heading ml={2} fontSize="xl">
                                    Loading
                                </Heading>
                            </Flex>
                        ) : (
                            <Flex
                                justify="space-between"
                                align="center"
                                mx={4}
                            >
                                <Heading fontSize="xl" wordBreak="break-word">
                                    coindrop.to/
                                    {id}
                                </Heading>
                                <ChevronRightIcon boxSize="32px" />
                            </Flex>
                        )}
                    </Box>
                </a>
            </NextLink>
        </Box>
    );
}
Example #12
Source File: IRMChart.tsx    From rari-dApp with GNU Affero General Public License v3.0 5 votes vote down vote up
IRMChart = ({
    curves,
    tokenData,
    modal
  }: {
    curves: any;
    tokenData: TokenData;
    modal?: boolean;
  }) => {
    const { t } = useTranslation();
    return (
      <Box
        height="170px"
        width="100%"
        color="#000000"
        overflow="hidden"
        px={modal ? 0 : 3}
        className="hide-bottom-tooltip"
        flexShrink={0}
      >
        {curves ? (
          <Chart
            options={
              {
                ...FuseIRMDemoChartOptions,
                colors: ["#FFFFFF", tokenData.color! ?? "#282727"],
              } as any
            }
            type="line"
            width="100%"
            height="100%"
            series={[
              {
                name: "Borrow Rate",
                data: curves.borrowerRates,
              },
              {
                name: "Deposit Rate",
                data: curves.supplierRates,
              },
            ]}
          />
        ) : curves === undefined ? (
          <Center expand color="#FFF">
            <Spinner my={8} />
          </Center>
        ) : (
          <Center expand color="#FFFFFF">
            <Text>
              {t("No graph is available for this asset's interest curves.")}
            </Text>
          </Center>
        )}
      </Box>
    );
  }
Example #13
Source File: DeleteAccount.tsx    From coindrop with GNU General Public License v3.0 5 votes vote down vote up
DeleteAccount: FC = () => {
    const { user, logout } = useUser();
    const id = user?.id;
    const email = user?.email;
    const [status, setStatus] = useState<Status>('initial');
    const [confirmingInput, setConfirmingInput] = useState('');
    const [isSubmitting, setIsSubmitting] = useState(false);
    const onSubmit = (event: React.FormEvent) => {
        event.preventDefault();
        handleDelete(logout, setIsSubmitting, user, setStatus);
    };
    if (!id || !email) {
        return <Spinner data-testid="no-user-spinner" />;
    }
    if (status === 'initial') {
        return (
            <Box>
                <Button
                    colorScheme="red"
                    variant="outline"
                    onClick={() => setStatus('user-confirmation')}
                >
                    Delete Account
                </Button>
            </Box>
        );
    }
    if (status === 'user-confirmation') {
        return (
            <form
                onSubmit={onSubmit}
            >
                <Text mb={1}>
                    Type your e-mail address to confirm account deletion:
                </Text>
                <Input
                    placeholder={email}
                    onChange={(event: React.ChangeEvent<HTMLInputElement>) => setConfirmingInput(event.target.value)}
                    value={confirmingInput}
                    type="text"
                />
                {confirmingInput === email && (
                    <Text mt={2}>
                        All your Coindrops will be deleted. This cannot be undone!
                    </Text>
                )}
                <Box>
                    <Button
                        type="submit"
                        colorScheme="red"
                        leftIcon={isSubmitting ? <Spinner size="sm" /> : undefined}
                        isDisabled={confirmingInput !== email || isSubmitting}
                        mt={2}
                    >
                        {isSubmitting ? 'Deleting' : 'Delete Account'}
                    </Button>
                </Box>
            </form>
        );
    }
    if (status === 'success') {
        return (
            <Text textAlign="center">
                ✔️ Account deleted. Redirecting to homepage...
            </Text>
        );
    }
    if (status === 'error') {
        return (
            <Text textAlign="center">
                ⚠️ Error deleting account. Please try again and contact support if you continue to receive this error.
            </Text>
        );
    }
    return null;
}
Example #14
Source File: AppDomains.tsx    From ledokku with MIT License 4 votes vote down vote up
AppDomains = ({ appId }: AppDomainProps) => {
  const toast = useToast();
  const { data, loading /* error */ } = useAppByIdQuery({
    variables: {
      appId,
    },
    ssr: false,
    skip: !appId,
  });

  const {
    data: domainsData,
    loading: domainsDataLoading,
    refetch: appDomainsRefetch,
  } = useDomainsQuery({
    variables: {
      appId,
    },
  });

  const [
    removeDomainMutation,
    { loading: removeDomainMutationLoading },
  ] = useRemoveDomainMutation();

  const handleRemoveDomain = async (domain: string) => {
    try {
      await removeDomainMutation({
        variables: {
          input: {
            appId,
            domainName: domain,
          },
        },
        refetchQueries: [{ query: DomainsDocument, variables: { appId } }],
      });
      toast.success('Domain removed successfully');
    } catch (error) {
      toast.error(error.message);
    }
  };

  if (!data) {
    return null;
  }

  // // TODO display error

  if (loading) {
    // TODO nice loading
    return <p>Loading...</p>;
  }

  const { app } = data;

  if (!app) {
    // TODO nice 404
    return <p>App not found.</p>;
  }

  return (
    <>
      <Box py="5">
        <Heading as="h2" size="md">
          Domain management
        </Heading>
        <Text fontSize="sm" color="gray.400">
          List of domains you have added to {app.name} app
        </Text>
      </Box>

      <Grid templateColumns={{ sm: 'repeat(1, 1fr)', md: 'repeat(3, 1fr)' }}>
        <GridItem colSpan={2}>
          <Box mb="8">
            {domainsDataLoading ? <Spinner /> : null}
            {domainsData?.domains.domains.length === 0 ? (
              <Text fontSize="sm" color="gray.400">
                Currently you haven't added any custom domains to your app
              </Text>
            ) : null}
            {domainsData?.domains.domains.map((domain: any) => (
              <Flex
                key={domain}
                justifyContent="space-between"
                alignItems="center"
              >
                <Link
                  href={`http://${domain}`}
                  isExternal
                  display="flex"
                  alignItems="center"
                >
                  {domain} <Icon as={FiExternalLink} mx="2" />
                </Link>

                <IconButton
                  aria-label="Delete"
                  variant="ghost"
                  colorScheme="red"
                  icon={<FiTrash2 />}
                  disabled={removeDomainMutationLoading}
                  onClick={() => handleRemoveDomain(domain)}
                />
              </Flex>
            ))}
          </Box>

          <AddAppDomain appId={appId} appDomainsRefetch={appDomainsRefetch} />
        </GridItem>
      </Grid>
    </>
  );
}
Example #15
Source File: Login.tsx    From dope-monorepo with GNU General Public License v3.0 4 votes vote down vote up
export default function Login(props: Props) {
    const toast = createStandaloneToast(theme);

    const [ loading, setLoading ] = useState(false);
    const [ loggedIn, setLoggedIn ] = useState(false);

    useEffect(() => {
        props.manager.events.on('loggedIn', () => setLoading(true));
    }, []);

    const login = () => {
        if ((window.ethereum as any).chainId !== '0x1') {
            toast({
                title: "Wrong network",
                description: "Please switch to the main Ethereum network",
                status: "error",
                ...toastStyle,
            });
            return;
        }

        props.authenticator.login()
            .then(() => {
                setLoggedIn(true)
                toast({
                    title: "Success",
                    description: "You have successfully logged in!",
                    status: "success",
                    ...toastStyle
                });
            })
            .catch((err) => {
                setLoggedIn(false);
                toast({
                    title: "Error " + (err.code ?? ""),
                    description: err.message ?? err,
                    status: "error",
                    ...toastStyle
                });
            });
    }

    return (
        <ChakraProvider theme={theme}>
            <Center style={{
                height: "100vh",
                backdropFilter: "brightness(50%)",
            }}>
                {loading ? <Spinner size="xl" color="white" /> : <Container style={{
                    padding: "1rem",
                    borderStyle: "solid",
                    boxShadow: "0px 0px 15px rgba(0,0,0,1)",
                    borderColor: "black",
                    borderWidth: "0px",
                    backgroundColor: "white",
                    borderRadius: "7px",
                }}>
                <VStack>
                    <Heading>
                        Please login before accessing the game
                    </Heading>
                    <br />
                    <Text>
                        To login, you need to sign a message using your wallet provider. Our personal favorite is Metamask but you can use any other extension or wallet provider.
                    </Text>
                    <UnorderedList spacing={4} style={{
                        paddingLeft: "1rem",
                    }}>
                        <ListItem>
                            Click on this button to trigger the sign message
                            <br />
                            <Button variant="primary" onClick={login}>
                                Sign
                            </Button>
                        </ListItem>
                        <ListItem>Your wallet provider will popup a dialog and you will need to press `Sign`</ListItem>
                        <ListItem>
                            Wait for this to show as logged in
                            <HStack style={{
                                paddingLeft: "1rem",
                                paddingRight: "1rem",
                            }}>
                                {loggedIn ? <CheckIcon /> : <Spinner color='red.500' />}
                                <Text style={{
                                    paddingTop: "1rem",
                                }}>{loggedIn ? 'Logged in' : 'Not logged in'}</Text>
                            </HStack>
                        </ListItem>
                        <ListItem>Press continue</ListItem>
                    </UnorderedList>
                    <Button 
                        disabled={!loggedIn}
                        onClick={() => props.manager.events.emit('loggedIn')}
                        style={{
                            position: "relative",
                            top: "30px"
                        }}
                        variant="primary"
                    >
                        Continue
                    </Button>
                </VStack>
                </Container>}
            </Center>
        </ChakraProvider>
    );
}
Example #16
Source File: index.tsx    From coindrop with GNU General Public License v3.0 4 votes vote down vote up
UserDataForm: FC<UserDataFormProps> = ({ userData, mutate, userId }) => {
    const [isSubmitting, setIsSubmitting] = useState(false);
    const toast = useToast();
    const { register, handleSubmit, formState: { isDirty }, reset } = useForm();
    const email_lists = userData?.email_lists;
    const onSubmit = async (rawFormData) => {
        setIsSubmitting(true);
        const userDataForDb = {
            email_lists: [],
        };
        Object.keys(optionalEmailLists).forEach(emailListId => {
            if (rawFormData.email_lists[emailListId]) {
                userDataForDb.email_lists.push(emailListId);
            }
        });
        try {
            await updateUserData({ data: userDataForDb, userId });
            mutate(userDataForDb);
            reset();
            toast({
                title: "Account updated",
                status: "success",
                duration: 6000,
                isClosable: true,
            });
        } catch (err) {
            toast({
                title: "Error updating account",
                description: "Please try again or contact support",
                status: "error",
                duration: 9000,
                isClosable: true,
            });
        } finally {
            setIsSubmitting(false);
        }
    };
    return (
        <SectionContainer>
            <form onSubmit={handleSubmit(onSubmit)} data-testid="settings-form">
                <SectionHeading size="md">
                    E-mail
                </SectionHeading>
                <Box
                    id="email-preferences-content"
                    m={4}
                >
                    <FormLabel>Newsletters</FormLabel>
                    <Flex wrap="wrap">
                        {Object.entries(optionalEmailLists).map(([emailListId, emailListDisplayName]: [EmailListIds, string]) => {
                            return (
                                <Checkbox
                                    key={emailListId}
                                    mr={6}
                                    name={`email_lists.${emailListId}`}
                                    colorScheme="orange"
                                    defaultChecked={email_lists?.includes(emailListId)}
                                    ref={register()}
                                >
                                    {emailListDisplayName}
                                </Checkbox>
                            );
                        })}
                        {alwaysEnabledEmailLists.map(listName => (
                            <Checkbox
                                key={listName}
                                mr={6}
                                colorScheme="orange"
                                defaultChecked
                                isDisabled
                            >
                                {listName}
                            </Checkbox>
                        ))}
                    </Flex>
                </Box>
                <Box>
                    <Button
                        colorScheme="green"
                        type="submit"
                        isDisabled={!isDirty || isSubmitting}
                        leftIcon={isSubmitting ? <Spinner size="sm" /> : undefined}
                    >
                        {isSubmitting ? 'Saving' : 'Save'}
                    </Button>
                </Box>
            </form>
        </SectionContainer>
    );
}
Example #17
Source File: AttendeeEdit.tsx    From takeout-app with MIT License 4 votes vote down vote up
AttendeeEdit: React.FC = () => {
  const { data: conferenceData } = Api.useConference();
  const { data: session, error: sessionError } = Api.useSession();
  const history = useHistory();
  const [errorAlert, setErrorAlert] = React.useState<JSX.Element | null>(null);
  const [isRequesting, setIsRequesting] = React.useState<boolean>(false);

  const { register, handleSubmit, reset } = useForm<{
    name: string;
    gravatar_email: string;
  }>({
    defaultValues: {
      name: React.useMemo(() => session?.attendee?.name, [session]),
      gravatar_email: "",
    },
  });

  React.useEffect(() => {
    if (session?.attendee) reset({ name: session.attendee.name, gravatar_email: "" });
  }, [session?.attendee]);

  const onSubmit = handleSubmit(async (data) => {
    //const wasReady = session!.attendee?.is_ready;

    if (isRequesting) return;
    setIsRequesting(true);
    try {
      await Api.updateAttendee(data.name, data.gravatar_email);
      setErrorAlert(null);

      if (conferenceData) {
        history.push(`/tracks/${encodeURIComponent(conferenceData.conference.default_track)}`);
      } else {
        location.href = "/";
      }
    } catch (e) {
      setErrorAlert(
        <Box my={2}>
          <ErrorAlert error={e} />
        </Box>,
      );
    }
    setIsRequesting(false);
  });

  if (!session?.attendee) {
    return (
      <Container maxW={["auto", "auto", "auto", "1000px"]} px="15px" py="22px">
        <VStack>
          {sessionError ? (
            <Box my={2}>
              <ErrorAlert error={sessionError} />
            </Box>
          ) : null}
          <Spinner size="xl" />
        </VStack>
      </Container>
    );
  }

  return (
    <Container maxW={["auto", "auto", "auto", "1000px"]} px="15px" py="22px">
      <VStack justify="start" alignItems="start" spacing="30px">
        <Heading as="h2" color={Colors.main}>
          Settings
        </Heading>
        <HStack spacing="30px">
          <Avatar size="xl" bg={Colors.defaultAvatarBg} src={session.attendee.avatar_url} loading="lazy" />
          <Box maxW="750px">
            <Text mb={2}>
              Confirm your name and avatar used at live chat. These informations may be shared with other attendees once
              submitted.
            </Text>
            <Text>
              Be remember to abide by{" "}
              <Link href="https://rubykaigi.org/2021-takeout/policies" isExternal textDecoration="underline">
                our policies
              </Link>
              .
            </Text>
          </Box>
        </HStack>
        <form onSubmit={onSubmit}>
          <VStack justify="start" alignItems="start" spacing="30px">
            <FormControl id="login_reference" isRequired>
              <FormLabel>Name</FormLabel>
              <FormHelperText my={1}>Feel free to use nicknames, usernames, or handles :)</FormHelperText>
              <Input {...register("name")} maxW="460px" autoFocus />
            </FormControl>

            <FormControl id="login_email">
              <FormLabel>Gravatar Email Address</FormLabel>
              <FormHelperText my={1}>
                We use avatar images registered on{" "}
                <Link href="https://www.gravatar.com" isExternal textDecoration="underline">
                  Gravatar
                </Link>
                . Fill the following field if you desire to choose different email address for your Gravatar image.
              </FormHelperText>
              <Input
                {...register("gravatar_email")}
                type="email"
                maxW="460px"
                placeholder="(leave empty to remain unchanged)"
              />
            </FormControl>

            <Button type="submit" w="160px" h="46px" colorScheme="rk" isLoading={isRequesting}>
              {session.attendee.is_ready ? "Save" : "Continue"}
            </Button>
          </VStack>
        </form>

        {errorAlert}
      </VStack>
    </Container>
  );
}
Example #18
Source File: AccountButton.tsx    From rari-dApp with GNU Affero General Public License v3.0 4 votes vote down vote up
Buttons = ({
  openModal,
  openClaimRGTModal,
  hasClaimableRewards,
}: {
  openModal: () => any;
  openClaimRGTModal: () => any;
  hasClaimableRewards: boolean;
}) => {
  const { address, isAuthed, login, isAttemptingLogin } = useRari();

  const { t } = useTranslation();

  const isMobile = useIsSmallScreen();

  const handleAccountButtonClick = useCallback(() => {
    if (isAuthed) {
      openModal();
    } else login();
  }, [isAuthed, login, openModal]);

  return (
    <Row mainAxisAlignment="center" crossAxisAlignment="center">
      {isMobile ? null : (
        <>
          {hasClaimableRewards ? (
            <DarkGlowingButton
              label={t("Claim")}
              onClick={openClaimRGTModal}
              height="40px"
              flexShrink={0}
              width="95px"
              fontSize="15px"
              fontWeight="bold"
            />
          ) : (
            <DashboardBox
              ml={1}
              as="button"
              height="40px"
              flexShrink={0}
              width="95px"
              fontSize="15px"
              fontWeight="bold"
              onClick={openClaimRGTModal}
            >
              <Center expand>{t("Claim")}</Center>
            </DashboardBox>
          )}
        </>
      )}

      {/* Connect + Account button */}
      <DashboardBox
        ml={isMobile ? 0 : 4}
        as="button"
        height="40px"
        flexShrink={0}
        flexGrow={0}
        width="133px"
        onClick={handleAccountButtonClick}
      >
        <Row
          expand
          mainAxisAlignment="space-around"
          crossAxisAlignment="center"
          px={3}
          py={1}
        >
          {/* Conditionally display Connect button or Account button */}
          {!isAuthed ? (
            isAttemptingLogin ? (
              <Spinner />
            ) : (
              <Text fontWeight="semibold">{t("Connect")}</Text>
            )
          ) : (
            <>
              <Jazzicon diameter={23} seed={jsNumberForAddress(address)} />
              <Text ml={2} fontWeight="semibold">
                {shortAddress(address)}
              </Text>
            </>
          )}
        </Row>
      </DashboardBox>
    </Row>
  );
}
Example #19
Source File: RenderDetail.tsx    From ke with MIT License 4 votes vote down vote up
RenderDetail = (props: RenderDetailProps): JSX.Element => {
  /*
    Entry point for displaying components in https://myspa.com/some-url/100500 route format.

    Here we fetch data from the backend using the url that we specified in a
    admin class.

    After that we mounts the widgets of a particular view type. At the moment there are two:
    - Detail View (see mountDetailFields for detail)
    - Wizard View (see mountWizards for detail)
  */
  const [mainDetailObject, setMainDetailObject] = useState<Model>()
  const [needRefreshDetailObject, setNeedRefreshDetailObject] = useState<boolean>(true)
  const { id } = useParams<{ id: string }>()
  const { resourceName, admin, provider, notifier } = props
  const toast = useToast()
  const detailNotifier = notifier || new ChakraUINotifier(toast)
  const [isLoading, setIsLoading] = useState<boolean>(true)
  const [loadError, setLoadError] = useState<LoadError | null>(null)
  const activeWizardRef = useRef<WizardControl>()

  let title = `${admin.verboseName} # ${id}`
  if (admin.getPageTitle) {
    const pageTitle = admin.getPageTitle(mainDetailObject)
    if (pageTitle) {
      title = pageTitle
    }
  }
  document.title = title

  let favicon = admin.favicon || ''

  if (admin.getPageFavicon) {
    const favIconSource = admin.getPageFavicon(mainDetailObject)
    if (favIconSource) {
      favicon = favIconSource
    }
  }
  setFavicon(favicon)

  const refreshMainDetailObject = (): void => {
    setNeedRefreshDetailObject(true)
  }

  useEffect(() => {
    const backendResourceUrl = admin.getResource(id)
    if (needRefreshDetailObject) {
      provider
        .getObject(backendResourceUrl)
        .then(async (res) => {
          setNeedRefreshDetailObject(false)
          setMainDetailObject(res)
          if (admin?.onDetailObjectLoaded !== undefined) {
            await admin.onDetailObjectLoaded({
              mainDetailObject: res,
              provider,
              context: containerStore,
              setInitialValue,
            })
          }
        })
        .catch((er: LoadError) => {
          setLoadError(er)
        })
        .finally(() => setIsLoading(false))
    }
  }, [id, provider, admin, needRefreshDetailObject, props, mainDetailObject])

  const { getDataTestId } = useCreateTestId({ name: admin.name })

  useEffect(() => {
    admin.onMount()
    return () => admin.onUnmount()
  }, [admin])

  return (
    <SaveEventProvider>
      <Row>
        <Col xs={12} xsOffset={0} md={10} mdOffset={1}>
          <Box padding="8px 0px">
            <ToListViewLink name={resourceName} />
          </Box>
        </Col>
      </Row>
      <Row {...getDataTestId()}>
        <Col xs={12} xsOffset={0} md={10} mdOffset={1}>
          {isLoading ? <Spinner /> : ''}
          {!isLoading && !loadError
            ? Object.entries(getContainersToMount()).map(([elementsKey, container]: [string, Function]) => {
                const elements = admin[elementsKey as keyof typeof admin]
                if (!elements) return []

                return (
                  <ErrorBoundary>
                    {container({
                      mainDetailObject,
                      setMainDetailObject,
                      ViewType,
                      elements,
                      elementsKey,
                      refreshMainDetailObject,
                      activeWizardRef,
                      ...props,
                      notifier: detailNotifier,
                    })}
                  </ErrorBoundary>
                )
              })
            : ''}
          {!isLoading && loadError ? (
            <Alert status="error" {...getDataTestId({ postfix: '--loadingError' })}>
              <AlertIcon />
              <AlertTitle mr={2}>Ошибка при выполнении запроса</AlertTitle>
              <AlertDescription>{loadError.response?.data?.message}</AlertDescription>
            </Alert>
          ) : (
            ''
          )}
        </Col>
      </Row>
    </SaveEventProvider>
  )
}
Example #20
Source File: InterestRatesView.tsx    From rari-dApp with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function InterestRatesView() {
  // name of table in view (current)
  const [tableName, setTableName] = useState<InterestRatesTableOptions>(
    InterestRatesTableOptions.Lending
  );
  // search term in TokenSearch component
  const [tokenSearchValue, setTokenSearchValue] = useState("");
  // information about each token
  const [tokenData, setTokenData] = useState<TokenData[]>([]);

  // Aave
  const aaveReserves = useReserves();
  // Compound
  const compoundMarkets = useCompoundMarkets();
  // Fuse
  const { pools: fusePools, markets: fuseMarkets } = useFuseMarkets();

  useEffect(() => {
    let isUnmounting = false;

    async function getTokenData() {
      // gather list of all tokens
      const allTokens = [
        ...aaveReserves.map((reserve) => reserve.tokenAddress),
        ...compoundMarkets.map((market) => market.tokenAddress),
      ];

      // add fuse pools if available
      if (fusePools)
        allTokens.push(
          ...fusePools.map((pool) => pool.underlyingTokens).flat()
        );

      // isolate unique tokens only
      const tokenAddresses = [...new Set(allTokens)];

      // fetch token data asynchronously
      const tokenDataList: TokenData[] = [];
      await Promise.all(
        tokenAddresses.map(async (address) => {
          tokenDataList.push(await fetchTokenDataWithCache(address));
        })
      );

      // sort token data
      tokenDataList.sort(
        (a, b) =>
          tokenAddresses.indexOf(a.address!) -
          tokenAddresses.indexOf(b.address!)
      );

      // set list in state if conditions are met
      if (!isUnmounting && tokenDataList.length === tokenAddresses.length)
        setTokenData(tokenDataList);
    }

    getTokenData();

    // set isUnmounting to true when unmounting
    return () => {
      isUnmounting = false;
    };
  }, [aaveReserves, compoundMarkets, setTokenData, fusePools]);

  // token list filtered by search term
  const filteredTokenData = useMemo(
    () =>
      tokenSearchValue === ""
        ? tokenData
        : tokenData // filter token by search term
            .filter(
              (token) =>
                token
                  .name!.toLowerCase()
                  .includes(tokenSearchValue.toLowerCase()) ||
                token
                  .symbol!.toLowerCase()
                  .includes(tokenSearchValue.toLowerCase())
            ),
    [tokenSearchValue, tokenData]
  );

  const { t } = useTranslation();

  return (
    <InterestRatesContext.Provider
      value={{
        selectedTable: tableName,
        tokens: filteredTokenData,
        fusePools: fusePools,
        markets: {
          aave: aaveReserves,
          compound: compoundMarkets,
          fuse: fuseMarkets,
        },
        marketDataLoaded: aaveReserves.length > 0 && compoundMarkets.length > 0,
      }}
    >
      <Column
        width="100%"
        mainAxisAlignment="center"
        crossAxisAlignment="flex-start"
        mt="3"
        p={15}
      >
        {/* TODO (Zane): Add i18n */}
        <Heading size="lg" mb="5">
          Interest Rates
        </Heading>
        {tokenData.length === 0 ||
        !fusePools ||
        !fuseMarkets ||
        !aaveReserves ||
        !compoundMarkets ? (
          <Center w="100%" h="100px">
            <Spinner size="xl" />
          </Center>
        ) : (
          <>
            <Flex w="100%">
              <Box flex="3">
                <MultiPicker
                  options={{
                    lending: t("Lending Rates"),
                    borrowing: t("Borrowing Rates"),
                  }}
                  // set table on change
                  onChange={(value) =>
                    setTableName(value as InterestRatesTableOptions)
                  }
                />
              </Box>
              <Spacer flex="2" />
              <Box flex="3">
                <TokenSearch onChange={setTokenSearchValue} />
              </Box>
            </Flex>
            <Box mt="4" w="100%" position="relative">
              <InterestRatesTable />
            </Box>
          </>
        )}
      </Column>
    </InterestRatesContext.Provider>
  );
}