@chakra-ui/react#Center JavaScript Examples

The following examples show how to use @chakra-ui/react#Center. 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: BuilderListSkeleton.jsx    From scaffold-directory with MIT License 6 votes vote down vote up
BuilderListSkeleton = () => (
  <Box overflowX="auto">
    <Center mb={5}>
      <chakra.strong mr={2}>Total builders:</chakra.strong> <SkeletonText noOfLines={1} w={5} />
    </Center>
    <Table>
      <Thead>
        <Tr>
          <Th>Builder</Th>
          <Th>Challenges</Th>
          <Th>Socials</Th>
          <Th>Last Activity</Th>
        </Tr>
      </Thead>
      <Tbody>
        {[1, 2].map(lineNumber => {
          return (
            <Tr key={lineNumber}>
              <Td>
                <SkeletonAddress w="12.5" fontSize="16" />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} py={2} />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} py={2} />
              </Td>
              <Td>
                <SkeletonText noOfLines={1} py={2} />
              </Td>
            </Tr>
          );
        })}
      </Tbody>
    </Table>
  </Box>
)
Example #2
Source File: saved-blobs.js    From blobs.app with MIT License 6 votes vote down vote up
SecondPage = () => (
  <Layout>
    <SEO
      title="Save blobs locally and access them anytime even when in offline"
      description="Customizable blobs as SVG and Flutter Widget. Create random or fixed blobs, loop, animate, clip them with ease"
    />
    <Box my="10" textAlign="center">
      <Logo />
      <Heading
        size="xl"
        display="flex"
        alignItems="center"
        justifyContent="center"
        variant="main"
      >
        Browse saved blobs
      </Heading>
      <Text my="2" variant="subtle">
        Click on the any blob card to navigate to edit screen
      </Text>
    </Box>
    <SavedBlobs />
    <Center>
      <Link to="/">
        {' '}
        <ArrowBackIcon />
        Go back to the homepage
      </Link>
    </Center>
  </Layout>
)
Example #3
Source File: UrlInput.js    From blobs.app with MIT License 6 votes vote down vote up
UrlInput = ({ value, onEnter }) => {
  const [error, setError] = useState(null);
  const urlRegex = /([\w+]+\:\/\/)?([\w\d-]+\.)*[\w-]+[\.\:]\w+([\/\?\=\&\#\.]?[\w-]+)*\/?/gm;

  return (
    <Box key={value}>
      <ChakInput
        variant="outline"
        placeholder="https://someurl.png"
        bg="white"
        _dark={{ bg: 'gray.600' }}
        defaultValue={value}
        _focus={{ borderColor: 'primary', boxShadow: '0 0 0 1px #d7819b' }}
        onKeyDown={(e) => {
          if (e.key !== 'Enter') return;
          const url = e.target.value;
          if (!urlRegex.test(url)) {
            setError('Invalid URL');
            return;
          }
          setError(null);
          onEnter(url);
        }}
      />
      {error && (
        <Center>
          <Text mt="2" fontSize="sm" color="red.600" fontWeight="600">
            {error}
          </Text>
        </Center>
      )}
    </Box>
  );
}
Example #4
Source File: components.js    From idena-web with MIT License 6 votes vote down vote up
export function DrawerPromotion(props) {
  const [, setDrawerPromotion] = React.useContext(DrawerPromotionContext)

  return (
    <Center
      ref={setDrawerPromotion}
      position="absolute"
      top="50%"
      left="50%"
      transform="translate(-50%,-50%)"
      zIndex="modal"
      {...props}
    />
  )
}
Example #5
Source File: components.js    From idena-web with MIT License 6 votes vote down vote up
export function EmptyAdList({children}) {
  const {t} = useTranslation()

  return (
    <Center color="muted" flex={1} w="full">
      <Stack spacing="4" align="center">
        <Text>{children}</Text>
        <NextLink href="/adn/new">
          <Button variant="outline">{t('Create a new ad')}</Button>
        </NextLink>
      </Stack>
    </Center>
  )
}
Example #6
Source File: offers.js    From idena-web with MIT License 5 votes vote down vote up
export default function AdOfferList() {
  const {t} = useTranslation()

  const queryClient = useQueryClient()

  const {data: burntCoins, status: burntCoinsStatus} = useApprovedBurntCoins()

  const isFetched = burntCoinsStatus === 'success'

  const isEmpty = isFetched && burntCoins.length === 0

  const [selectedAd, setSelectedAd] = React.useState({})

  const burnDisclosure = useDisclosure()
  const {
    onOpen: onOpenBurnDisclosure,
    onClose: onCloseBurnDisclosure,
  } = burnDisclosure

  const handlePreviewBurn = React.useCallback(
    ad => {
      setSelectedAd(ad)
      onOpenBurnDisclosure()
    },
    [onOpenBurnDisclosure]
  )

  const handleBurn = React.useCallback(() => {
    onCloseBurnDisclosure()
    queryClient.invalidateQueries(['bcn_burntCoins', []])
  }, [onCloseBurnDisclosure, queryClient])

  return (
    <Layout skipBanner>
      <Page>
        <PageHeader>
          <PageTitle mb={4}>{t('All offers')}</PageTitle>
          <PageCloseButton href="/adn/list" />
        </PageHeader>
        <Table>
          <Thead>
            <Tr>
              <RoundedTh isLeft>{t('Banner/author')}</RoundedTh>
              <RoundedTh>{t('Website')}</RoundedTh>
              <RoundedTh>{t('Target')}</RoundedTh>
              <RoundedTh>{t('Burn')}</RoundedTh>
              <RoundedTh isRight />
            </Tr>
          </Thead>
          <Tbody>
            {isFetched &&
              burntCoins.map(burn => (
                <AdOfferListItem
                  key={burn.key}
                  burn={burn}
                  onBurn={handlePreviewBurn}
                />
              ))}
          </Tbody>
        </Table>

        {isEmpty && (
          <Center color="muted" mt="4" w="full">
            {t('No active offers')}
          </Center>
        )}

        <BurnDrawer ad={selectedAd} onBurn={handleBurn} {...burnDisclosure} />
      </Page>
    </Layout>
  )
}
Example #7
Source File: containers.js    From idena-web with MIT License 5 votes vote down vote up
export function AdMediaInput({
  name,
  value,
  label,
  description,
  fallbackSrc,
  maybeError,
  onChange,
  ...props
}) {
  const src = React.useMemo(
    () =>
      isValidImage(value) ? URL.createObjectURL(value) : value ?? adFallbackSrc,
    [value]
  )

  return (
    <FormControl isInvalid={Boolean(maybeError)}>
      <FormLabel htmlFor={name} m={0} p={0}>
        <VisuallyHiddenInput
          id={name}
          name={name}
          type="file"
          accept="image/png,image/jpg,image/jpeg"
          onChange={async e => {
            if (onChange) {
              const {files} = e.target
              if (files.length) {
                const [file] = files
                if (hasImageType(file)) {
                  onChange(file)
                }
              }
            }
          }}
          {...props}
        />
        <HStack spacing={4} align="center" cursor="pointer">
          <Box flexShrink={0}>
            {src !== adFallbackSrc ? (
              <AdImage src={src} width={70} />
            ) : (
              <Center
                bg="gray.50"
                borderWidth={1}
                borderColor="gray.016"
                rounded="lg"
                p="3"
              >
                <Image src={fallbackSrc} ignoreFallback boxSize="44px" />
              </Center>
            )}
          </Box>
          <Stack>
            <HStack>
              <LaptopIcon boxSize="5" color="blue.500" />
              <Text color="blue.500" fontWeight={500}>
                {label}
              </Text>
            </HStack>
            <SmallText>{description}</SmallText>
          </Stack>
        </HStack>
        <AdFormError>{maybeError}</AdFormError>
      </FormLabel>
    </FormControl>
  )
}
Example #8
Source File: components.js    From idena-web with MIT License 5 votes vote down vote up
export function PublishFlipDrawer({isPending, flip, onSubmit, ...props}) {
  const {t} = useTranslation()

  return (
    <AdDrawer isMining={isPending} {...props}>
      <DrawerHeader>
        <Stack spacing={4}>
          <Center
            alignSelf="flex-start"
            bg="blue.012"
            w={12}
            minH={12}
            rounded="xl"
          >
            <PublishFlipIcon boxSize={6} color="blue.500" />
          </Center>
          <Heading color="gray.500" fontSize="lg" fontWeight={500}>
            {t('Submit flip')}
          </Heading>
        </Stack>
      </DrawerHeader>
      <DrawerBody overflowY="auto" mx={-6} mt="3" mb={10}>
        <Stack spacing={6} fontSize="md" px={6} align="center">
          <HStack spacing="3">
            <FlipImageList>
              {flip.originalOrder.map((num, idx) => (
                <FlipImageListItem
                  key={num}
                  src={flip?.images[num]}
                  isFirst={idx === 0}
                  isLast={idx === flip?.images.length - 1}
                  w="24"
                />
              ))}
            </FlipImageList>
            <FlipImageList>
              {flip.order.map((num, idx) => (
                <FlipImageListItem
                  key={num}
                  src={flip?.images[num]}
                  isFirst={idx === 0}
                  isLast={idx === flip?.images.length - 1}
                  w="24"
                />
              ))}
            </FlipImageList>
          </HStack>
          <FlipKeywordPanel w="full">
            <Stack spacing="4">
              {flip.keywords.map(word => (
                <FlipKeyword key={word.id}>
                  <FlipKeywordName>{word.name}</FlipKeywordName>
                  <FlipKeywordDescription>{word.desc}</FlipKeywordDescription>
                </FlipKeyword>
              ))}
            </Stack>
          </FlipKeywordPanel>
        </Stack>
      </DrawerBody>
      <DrawerFooter>
        <HStack>
          {/* eslint-disable-next-line react/destructuring-assignment */}
          <SecondaryButton onClick={props.onClose}>
            {t('Not now')}
          </SecondaryButton>
          <PrimaryButton
            isLoading={isPending}
            loadingText={t('Mining...')}
            onClick={onSubmit}
          >
            {t('Submit')}
          </PrimaryButton>
        </HStack>
      </DrawerFooter>
    </AdDrawer>
  )
}
Example #9
Source File: components.js    From idena-web with MIT License 5 votes vote down vote up
export function SpoilInviteDrawer({onSuccess, onFail, ...props}) {
  const {t} = useTranslation()

  return (
    <Drawer {...props}>
      <DrawerHeader mb={0}>
        <Center flexDirection="column">
          <Avatar address={dummyAddress} />
          <Heading
            fontSize="lg"
            fontWeight={500}
            color="gray.500"
            mt="4"
            mb={0}
          >
            {t('Spoil invitation code')}
          </Heading>
        </Center>
      </DrawerHeader>
      <DrawerBody mt="6">
        <Text fontSize="md" mb={6}>
          {t(
            `Spoil invitations that are shared publicly. This will encourage people to share invitations privately and prevent bots from collecting invitation codes.`
          )}
        </Text>
        <Stack spacing="6">
          <form
            id="spoilInvite"
            onSubmit={async e => {
              e.preventDefault()

              const code = new FormData(e.target).get('code').trim()

              const randomPrivateKey = generatePrivateKey()

              try {
                const hash = await sendRawTx(
                  new Transaction()
                    .fromHex(
                      await getRawTx(
                        TxType.ActivationTx,
                        privateKeyToAddress(code),
                        privateKeyToAddress(randomPrivateKey),
                        0,
                        0,
                        privateKeyToPublicKey(randomPrivateKey)
                      )
                    )
                    .sign(code)
                    .toHex(true)
                )

                // eslint-disable-next-line no-unused-expressions
                onSuccess?.(hash)
              } catch (error) {
                // eslint-disable-next-line no-unused-expressions
                onFail?.(error)
              }
            }}
          >
            <FormControl>
              <FormLabel>{t('Invitation code')}</FormLabel>
              <Input name="code" placeholder={t('Invitation code to spoil')} />
            </FormControl>
          </form>
          <Text fontSize="md">
            {t(
              `When you click 'Spoil' the invitation code will be activated by a random address and wasted.`
            )}
          </Text>
        </Stack>
      </DrawerBody>
      <DrawerFooter>
        <PrimaryButton type="submit" form="spoilInvite">
          {t('Spoil invite')}
        </PrimaryButton>
      </DrawerFooter>
    </Drawer>
  )
}
Example #10
Source File: ProductDetails.js    From react-sample-projects with MIT License 5 votes vote down vote up
ProductDetails = () => {
  const { product } = useSelector(state => state.product);
  const dispatch = useDispatch();
  const { state } = useLocation() || {};

  const params = useParams();

  const addItemToCartHandler = e => {
    e.stopPropagation();
    e.preventDefault();
    dispatch(addItemToCart(product));
  };

  useEffect(() => {
    if (!params.id) return;
    if (state?.item) {
      dispatch(setProductDetails(state?.item));
    } else {
      dispatch(fetchProductDetails(params.id));
    }
    return () => {};
  }, [params.id, dispatch, state?.item]);

  if (!product) return <Box m="3">loading...</Box>;

  return (
    <Box
      m="3"
      boxShadow="base"
      borderWidth="1px"
      borderRadius="lg"
      overflow="hidden"
    >
      <SimpleGrid columns={{ sm: 1, md: 2, lg: 2 }} spacing="40px">
        <Center>
          <Box p="6">
            <Image src={product.image} alt={product.title} maxH="400" />
          </Box>
        </Center>
        <Box p="6">
          <Box d="flex" alignItems="baseline">
            <Box
              color="gray.500"
              fontWeight="semibold"
              letterSpacing="wide"
              fontSize="xs"
              textTransform="uppercase"
            >
              {product.category}
            </Box>
          </Box>

          <Box textAlign="left">${product.price}</Box>
          <Box fontWeight="semibold" mt="1" as="h2" textAlign="left">
            Product Info:
          </Box>
          <Box textAlign="left" fontSize="md">
            {product.description}
          </Box>
          <Button
            onClick={addItemToCartHandler}
            m={3}
            variant={'solid'}
            colorScheme={'teal'}
            size={'sm'}
          >
            Add to Cart
          </Button>
        </Box>
      </SimpleGrid>
    </Box>
  );
}
Example #11
Source File: Item.js    From react-sample-projects with MIT License 5 votes vote down vote up
Item = ({ item }) => {
  const dispatch = useDispatch();

  const addItemToCartHandler = e => {
    e.stopPropagation();
    e.preventDefault();
    dispatch(addItemToCart(item));
  };

  return (
    <Link to={{ pathname: `/product/${item.id}`, state: { item } }}>
      <Box
        boxShadow="base"
        maxW="sm"
        borderWidth="1px"
        borderRadius="lg"
        overflow="hidden"
      >
        <Box p="6">
          <Center>
            <Image
              _hover={{ transform: `scale(1.1)` }}
              src={item.image}
              alt={item.title}
              maxH="400"
              height="400"
            />
          </Center>
        </Box>

        <Box p="6">
          <Box d="flex" alignItems="baseline">
            <Box
              color="gray.500"
              fontWeight="semibold"
              letterSpacing="wide"
              fontSize="xs"
              textTransform="uppercase"
            >
              {item.category}
            </Box>
          </Box>

          <Box
            mt="1"
            fontWeight="semibold"
            as="h4"
            lineHeight="tight"
            isTruncated
            whiteSpace="wrap"
            textAlign="left"
          >
            {item.title}
          </Box>
          <Flex justifyContent="space-between">
            <Box textAlign="left">${item.price}</Box>
            <Tooltip label="Add to Cart" fontSize="md">
              <Button variant="ghost" p={2} onClick={addItemToCartHandler}>
                <Icon as={MdShoppingCart} w={6} h={6} />
              </Button>
            </Tooltip>
          </Flex>
        </Box>
      </Box>
    </Link>
  );
}
Example #12
Source File: Footer.js    From blobs.app with MIT License 5 votes vote down vote up
Footer = ({ toggleSound, playSound }) => (
  <Center my="6">
    <HStack
      spacing="10px"
      fontSize="sm"
      flexDirection={{ base: 'column-reverse', lg: 'row' }}
    >
      <Button
        variant="silent"
        leftIcon={<CopyrightIcon fontSize="lg" />}
        aria-label="Toggle Theme"
      >
        Copyright 2021
      </Button>

      <Modal
        title="Source code & Libraries"
        size="md"
        src={
          <Button
            variant="silent"
            leftIcon={<GithubIcon fontSize="lg" />}
            aria-label="Source code"
          >
            Source code
          </Button>
        }
      >
        <Box>
          <SourceCode />
        </Box>
      </Modal>

      <Modal
        title="Credits"
        size="md"
        src={
          <Button
            variant="silent"
            leftIcon={<CreditsIcon fontSize="lg" />}
            aria-label="Credits"
          >
            Credits
          </Button>
        }
      >
        <Box>
          <Credits />
        </Box>
      </Modal>
      <LoIcon />
      <Button
        variant="silent"
        leftIcon={<UserIcon fontSize="lg" />}
        aria-label="Lokesh Rajendran"
        target="_blank"
        as={Link}
        href="https://twitter.com/lokesh_coder"
      >
        lokesh_coder
      </Button>
      <Button
        variant="silent"
        leftIcon={(() => {
          if (!playSound) return <SoundOffIcon fontSize="lg" />;
          return <SoundIcon fontSize="lg" />;
        })()}
        aria-label="Toggle Theme"
        onClick={toggleSound}
      >
        Toggle sound
      </Button>
      <Box as={Text}>
        <ThemeSwitch />
      </Box>
    </HStack>
  </Center>
)
Example #13
Source File: NavLinks.js    From blobs.app with MIT License 5 votes vote down vote up
NavLinks = ({ saveBlob }) => {
  const toast = useToast();
  return (
    <Box px="10" pt="3">
      <Center>
        <HStack spacing="2px" fontSize="sm">
          <Box as={Text}>
            <Button
              variant="heavy"
              leftIcon={<BookmarkIcon fontSize="18px" />}
              aria-label="Save blob"
              onClick={() => {
                saveBlob();
                toast({
                  render: () => (
                    <Box
                      bg="primary"
                      my="10"
                      py="3"
                      px="5"
                      rounded="lg"
                      color="white"
                      textAlign="center"
                      fontWeight="500"
                      shadow="xl"
                    >
                      Blob Saved!
                    </Box>
                  ),
                  duration: 2000,
                });
              }}
            >
              Save
            </Button>
          </Box>

          <Box as={Text}>
            <Button
              href="/saved-blobs/"
              as={GatbsyLink}
              to="/saved-blobs"
              variant="heavy"
              leftIcon={<SavedIcon fontSize="18px" />}
              aria-label="Saved blobs"
            >
              Saved blobs
            </Button>
          </Box>
          <Box as={Text}>
            <Button
              href="http://www.twitter.com/intent/tweet?url=https://lokesh-coder.github.io/blobs.app/&text=Generate%20beautiful%20blob%20shapes%20for%20web%20and%20flutter%20apps"
              target="_blank"
              as={Link}
              variant="heavy"
              leftIcon={<TwitterIcon fontSize="18px" />}
              aria-label="Share"
            >
              Share
            </Button>
          </Box>
        </HStack>
      </Center>
    </Box>
  );
}
Example #14
Source File: BuilderListView.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
export default function BuilderListView({ serverUrl, mainnetProvider, userRole }) {
  const [builders, setBuilders] = useState([]);
  const [isLoadingBuilders, setIsLoadingBuilders] = useState(false);
  const { secondaryFontColor } = useCustomColorModes();
  const isAdmin = userRole === USER_ROLES.admin;

  const columns = useMemo(
    () => [
      {
        Header: "Builder",
        accessor: "builder",
        disableSortBy: true,
        Cell: ({ value }) => <BuilderAddressCell builderId={value} mainnetProvider={mainnetProvider} />,
      },
      {
        Header: "Challenges",
        accessor: "challenges",
        sortDescFirst: true,
      },
      {
        Header: "Socials",
        accessor: "socials",
        disableSortBy: true,
        Cell: ({ value }) => <BuilderSocialLinksCell builder={value} isAdmin={isAdmin} />,
      },
      {
        Header: "Last Activity",
        accessor: "lastActivity",
        sortDescFirst: true,
        Cell: ({ value }) => <DateWithTooltip timestamp={value} />,
      },
    ],
    // eslint-disable-next-line
    [userRole],
  );

  useEffect(() => {
    async function fetchBuilders() {
      setIsLoadingBuilders(true);
      const fetchedBuilders = await axios.get(serverUrl + serverPath);

      const processedBuilders = fetchedBuilders.data.map(builder => ({
        builder: builder.id,
        challenges: getAcceptedChallenges(builder?.challenges)?.length ?? 0,
        socials: builder,
        lastActivity: builderLastActivity(builder),
      }));

      setBuilders(processedBuilders);
      setIsLoadingBuilders(false);
    }

    fetchBuilders();
  }, [serverUrl]);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    prepareRow,
    page,
    canPreviousPage,
    canNextPage,
    pageOptions,
    pageCount,
    gotoPage,
    nextPage,
    previousPage,
    setPageSize,
    state: { pageIndex, pageSize },
  } = useTable(
    {
      columns,
      data: builders,
      initialState: { pageIndex: 0, pageSize: 25, sortBy: useMemo(() => [{ id: "lastActivity", desc: true }], []) },
    },
    useSortBy,
    usePagination,
  );

  return (
    <Container maxW="container.lg">
      <Container maxW="container.md" centerContent>
        <Heading as="h1" mb="4">
          All Builders
        </Heading>
        <Text color={secondaryFontColor} textAlign="center" mb="10">
          List of Ethereum builders creating products, prototypes, and tutorials with{" "}
          <Link href="https://github.com/scaffold-eth/scaffold-eth" color="teal.500" isExternal>
            scaffold-eth
          </Link>
          .
        </Text>
      </Container>
      {isLoadingBuilders ? (
        <BuilderListSkeleton />
      ) : (
        <Box overflowX="auto" mb={8}>
          <Center mb={5}>
            <chakra.strong mr={2}>Total builders:</chakra.strong> {builders.length}
          </Center>
          <Table {...getTableProps()}>
            <Thead>
              {headerGroups.map(headerGroup => (
                <Tr {...headerGroup.getHeaderGroupProps()}>
                  {headerGroup.headers.map(column => (
                    <Th {...column.getHeaderProps(column.getSortByToggleProps())}>
                      {column.render("Header")}
                      <chakra.span pl="4">
                        {column.isSorted ? (
                          column.isSortedDesc ? (
                            <TriangleDownIcon aria-label="sorted descending" />
                          ) : (
                            <TriangleUpIcon aria-label="sorted ascending" />
                          )
                        ) : null}
                      </chakra.span>
                    </Th>
                  ))}
                </Tr>
              ))}
            </Thead>
            <Tbody {...getTableBodyProps()}>
              {page.map(row => {
                prepareRow(row);
                return (
                  <Tr {...row.getRowProps()}>
                    {row.cells.map(cell => (
                      <Td {...cell.getCellProps()}>{cell.render("Cell")}</Td>
                    ))}
                  </Tr>
                );
              })}
            </Tbody>
          </Table>

          <Center mt={4}>
            <ButtonGroup>
              <Button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
                {"<<"}
              </Button>
              <Button onClick={() => previousPage()} disabled={!canPreviousPage}>
                {"<"}
              </Button>
              <Button onClick={() => nextPage()} disabled={!canNextPage}>
                {">"}
              </Button>
              <Button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
                {">>"}
              </Button>
            </ButtonGroup>
          </Center>
          <Center mt={4}>
            <Text mr={4}>
              Page{" "}
              <strong>
                {pageIndex + 1} of {pageOptions.length}
              </strong>{" "}
            </Text>
            <Box>
              <Select
                isFullWidth={false}
                value={pageSize}
                onChange={e => {
                  setPageSize(Number(e.target.value));
                }}
              >
                {[25, 50, 100].map(pageSizeOption => (
                  <option key={pageSizeOption} value={pageSizeOption}>
                    Show {pageSizeOption}
                  </option>
                ))}
              </Select>
            </Box>
          </Center>
        </Box>
      )}
    </Container>
  );
}
Example #15
Source File: components.js    From idena-web with MIT License 4 votes vote down vote up
export function AdCarousel() {
  const {t} = useTranslation()

  const {lng} = useLanguage()

  const {ads, currentIndex, setCurrentIndex, prev, next} = useRotateAds()

  const currentAd = ads[currentIndex]

  const {data: burntCoins} = useBurntCoins()

  const orderedBurntCoins =
    burntCoins
      ?.sort((a, b) => b.amount - a.amount)
      .map(burn => ({...burn, ...AdBurnKey.fromHex(burn?.key)})) ?? []

  const maybeBurn = orderedBurntCoins.find(burn => burn.cid === currentAd?.cid)

  const formatDna = useFormatDna()

  const swipeProps = useSwipeable({
    onSwipedLeft: next,
    onSwipedRight: prev,
    preventDefaultTouchmoveEvent: true,
    trackMouse: true,
  })

  return (
    <Stack>
      <Box
        bg="white"
        borderRadius="lg"
        boxShadow="0 3px 12px 0 rgba(83, 86, 92, 0.1), 0 2px 3px 0 rgba(83, 86, 92, 0.2)"
        pt="6"
        px="28px"
        pb="4"
        {...swipeProps}
      >
        <Heading as="h3" fontSize="lg" fontWeight={500} isTruncated>
          {currentAd?.title}
        </Heading>
        <Text color="muted" fontSize="mdx" mt="2">
          {currentAd?.desc}
        </Text>
        <Box mt="3">
          <ExternalLink
            href={currentAd?.url}
            fontSize="base"
            fontWeight={500}
            justifyContent="start"
            maxW="64"
          >
            {currentAd?.url}
          </ExternalLink>
        </Box>
        <LinkBox mt="5">
          <LinkOverlay href={currentAd?.url} isExternal>
            <AdImage src={currentAd?.media} w="full" />
          </LinkOverlay>
        </LinkBox>
        <Stack spacing="1" mt="4" fontSize="base" divider={<HDivider />}>
          <Stack spacing="1" pt="2" pb="2.5">
            <Text fontWeight={500}>{t('Sponsored by')}</Text>
            <HStack spacing="1" align="center">
              <Avatar
                address={currentAd?.author}
                boxSize="6"
                borderRadius="lg"
              />
              <Text as="span" color="muted" isTruncated lineHeight="22px">
                {currentAd?.author}
              </Text>
            </HStack>
          </Stack>
          <Stack spacing="1" pt="2" pb="2.5">
            <Text fontWeight={500}>
              {t('Burnt, {{time}}', {
                time: new Intl.RelativeTimeFormat(lng, {
                  style: 'short',
                }).format(24, 'hour'),
              })}
            </Text>
            <Text color="muted">{formatDna(maybeBurn?.amount ?? 0)}</Text>
          </Stack>
        </Stack>
      </Box>
      <Center as={HStack} spacing="0.5" h="6">
        {ads.map((_, idx) => (
          <Box
            w="6"
            h="0.5"
            bg={idx === currentIndex ? 'gray.500' : 'gray.030'}
            borderRadius={1}
            onClick={() => {
              setCurrentIndex(idx)
            }}
          />
        ))}
      </Center>
      <Box>
        <SuccessAlert
          icon={<InfoIcon color="green.500" boxSize={5} mr={3} />}
          fontSize="md"
        >
          {t('Watching ads makes your coin valuable!')}
        </SuccessAlert>
      </Box>
    </Stack>
  )
}
Example #16
Source File: ChallengeExpandedCard.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
ChallengeExpandedCard = ({ challengeId, challenge, builderAttemptedChallenges }) => {
  const { borderColor, secondaryFontColor } = useCustomColorModes();

  const builderHasCompletedDependenciesChallenges = challenge.dependencies?.every(id => {
    if (!builderAttemptedChallenges[id]) {
      return false;
    }
    if (!(builderAttemptedChallenges[id].status === CHALLENGE_SUBMISSION_STATUS.ACCEPTED)) {
      return false;
    }
    if (challenge.lockedTimestamp) {
      return (
        new Date().getTime() - builderAttemptedChallenges[id].submittedTimestamp > challenge.lockedTimestamp * 60 * 1000
      );
    }

    return true;
  });

  const pendingDependenciesChallenges = challenge.dependencies?.filter(dependency => {
    return (
      !builderAttemptedChallenges[dependency] ||
      builderAttemptedChallenges[dependency].status !== CHALLENGE_SUBMISSION_STATUS.ACCEPTED
    );
  });

  const lockReasonToolTip = "The following challenges are not completed: " + pendingDependenciesChallenges.join(", ");

  const isRampUpChallenge = challenge.dependencies?.length === 0;
  const challengeStatus = builderAttemptedChallenges[challengeId]?.status;

  let colorScheme;
  let label;
  switch (challengeStatus) {
    case CHALLENGE_SUBMISSION_STATUS.ACCEPTED: {
      colorScheme = "green";
      label = "Accepted";
      break;
    }
    case CHALLENGE_SUBMISSION_STATUS.REJECTED: {
      colorScheme = "red";
      label = "Rejected";
      break;
    }
    case CHALLENGE_SUBMISSION_STATUS.SUBMITTED: {
      label = "Submitted";
      break;
    }
    default:
    // do nothing
  }

  const isChallengeLocked = challenge.disabled || !builderHasCompletedDependenciesChallenges;

  if (challenge.checkpoint) {
    return (
      <Box bg="#f9f9f9">
        <Flex maxW={500} overflow="hidden" m="0 auto 24px" opacity={isChallengeLocked ? "0.5" : "1"}>
          <Flex pt={6} pb={4} px={4} direction="column" grow={1}>
            <Flex alignItems="center" pb={4} direction="column">
              <Text fontWeight="bold" fontSize="lg" mb={2}>
                {challenge.label}
              </Text>
              <Center borderBottom="1px" borderColor={borderColor} w="200px" flexShrink={0} p={1}>
                <Image src={challenge.previewImage} objectFit="cover" />
              </Center>
            </Flex>
            <Text color={secondaryFontColor} mb={4} textAlign="center">
              {challenge.description}
            </Text>
            <Spacer />
            <ButtonGroup>
              <Button
                as={isChallengeLocked ? Button : Link}
                href={isChallengeLocked ? null : challenge.externalLink?.link}
                isDisabled={isChallengeLocked}
                variant={isChallengeLocked ? "outline" : "solid"}
                isFullWidth
                isExternal
              >
                {builderHasCompletedDependenciesChallenges ? (
                  <chakra.span>{challenge.externalLink.claim}</chakra.span>
                ) : (
                  <>
                    <span role="img" aria-label="lock icon">
                      ?
                    </span>
                    <chakra.span ml={1}>Locked</chakra.span>
                  </>
                )}
              </Button>
              {!builderHasCompletedDependenciesChallenges && (
                <Tooltip label={lockReasonToolTip}>
                  <IconButton icon={<QuestionOutlineIcon />} />
                </Tooltip>
              )}
            </ButtonGroup>
          </Flex>
        </Flex>
      </Box>
    );
  }

  return (
    <Flex maxW={880} borderWidth="1px" borderRadius="lg" borderColor={borderColor} overflow="hidden" mb={6}>
      <Center borderBottom="1px" borderColor={borderColor} w="200px" flexShrink={0} p={1}>
        {challenge.previewImage ? (
          <Image src={challenge.previewImage} objectFit="cover" />
        ) : (
          <Text p={3} textAlign="center">
            {challengeId} image
          </Text>
        )}
      </Center>
      <Flex pt={6} pb={4} px={4} direction="column" grow={1}>
        <Flex justify="space-between" pb={4}>
          <Text fontWeight="bold">{challenge.label}</Text>
          {isRampUpChallenge && challengeStatus && (
            <Badge borderRadius="xl" colorScheme={colorScheme} textTransform="none" py={0.5} px={2.5}>
              {label}
            </Badge>
          )}
        </Flex>
        <Text color={secondaryFontColor} mb={4}>
          {challenge.description}
        </Text>
        <Spacer />
        {challenge.externalLink?.link ? (
          // Redirect to externalLink if set (instead of challenge detail view)
          <ButtonGroup>
            <Button
              as={isChallengeLocked ? Button : Link}
              href={isChallengeLocked ? null : challenge.externalLink?.link}
              isDisabled={isChallengeLocked}
              variant={isChallengeLocked ? "outline" : "solid"}
              isFullWidth
              isExternal
            >
              {builderHasCompletedDependenciesChallenges ? (
                <chakra.span>{challenge.externalLink.claim}</chakra.span>
              ) : (
                <>
                  <span role="img" aria-label="lock icon">
                    ?
                  </span>
                  <chakra.span ml={1}>Locked</chakra.span>
                </>
              )}
            </Button>
            {!builderHasCompletedDependenciesChallenges && (
              <Tooltip label={lockReasonToolTip}>
                <IconButton icon={<QuestionOutlineIcon />} />
              </Tooltip>
            )}
          </ButtonGroup>
        ) : (
          <ButtonGroup>
            <Button
              as={RouteLink}
              to={!isChallengeLocked && `/challenge/${challengeId}`}
              isDisabled={isChallengeLocked}
              variant={isChallengeLocked ? "outline" : "solid"}
              isFullWidth
            >
              {!isChallengeLocked ? (
                <>
                  {" "}
                  <span role="img" aria-label="castle icon">
                    ⚔️
                  </span>
                  <chakra.span ml={1}>Quest</chakra.span>
                </>
              ) : (
                <>
                  <span role="img" aria-label="lock icon">
                    ?
                  </span>
                  <chakra.span ml={1}>Locked</chakra.span>
                </>
              )}
            </Button>
            {!builderHasCompletedDependenciesChallenges && (
              <Tooltip label={lockReasonToolTip}>
                <IconButton icon={<QuestionOutlineIcon />} />
              </Tooltip>
            )}
          </ButtonGroup>
        )}
      </Flex>
    </Flex>
  );
}
Example #17
Source File: BuilderProfileCard.jsx    From scaffold-directory with MIT License 4 votes vote down vote up
BuilderProfileCard = ({ builder, mainnetProvider, isMyProfile, userProvider, fetchBuilder, userRole }) => {
  const address = useUserAddress(userProvider);
  const ens = useDisplayAddress(mainnetProvider, builder?.id);
  const [updatedSocials, setUpdatedSocials] = useState({});
  const [isUpdatingReachedOutFlag, setIsUpdatingReachedOutFlag] = useState(false);
  const [isUpdatingSocials, setIsUpdatingSocials] = useState(false);
  const { isOpen, onOpen, onClose } = useDisclosure();
  const { hasCopied, onCopy } = useClipboard(builder?.id);
  const { borderColor, secondaryFontColor } = useCustomColorModes();
  const shortAddress = ellipsizedAddress(builder?.id);
  const hasEns = ens !== shortAddress;

  const toast = useToast({ position: "top", isClosable: true });
  const toastVariant = useColorModeValue("subtle", "solid");

  const joinedDate = new Date(builder?.creationTimestamp);
  const joinedDateDisplay = joinedDate.toLocaleString("default", { month: "long" }) + " " + joinedDate.getFullYear();

  // INFO: conditional chaining and coalescing didn't work when also checking the length
  const hasProfileLinks = builder?.socialLinks ? Object.keys(builder.socialLinks).length !== 0 : false;

  const isAdmin = userRole === USER_ROLES.admin;

  useEffect(() => {
    if (builder) {
      setUpdatedSocials(builder.socialLinks ?? {});
    }
  }, [builder]);

  const handleUpdateSocials = async () => {
    setIsUpdatingSocials(true);

    // Avoid sending socials with empty strings.
    const socialLinkCleaned = Object.fromEntries(Object.entries(updatedSocials).filter(([_, value]) => !!value));

    const invalidSocials = validateSocials(socialLinkCleaned);
    if (invalidSocials.length !== 0) {
      toast({
        description: `The usernames for the following socials are not correct: ${invalidSocials
          .map(([social]) => social)
          .join(", ")}`,
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    let signMessage;
    try {
      signMessage = await getUpdateSocialsSignMessage(address);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    let signature;
    try {
      signature = await userProvider.send("personal_sign", [signMessage, address]);
    } catch (error) {
      toast({
        description: "Couldn't get a signature from the Wallet",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    try {
      await postUpdateSocials(address, signature, socialLinkCleaned);
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Access error",
          variant: toastVariant,
        });
        setIsUpdatingSocials(false);
        return;
      }
      toast({
        status: "error",
        description: "Can't update your socials. Please try again.",
        variant: toastVariant,
      });
      setIsUpdatingSocials(false);
      return;
    }

    toast({
      description: "Your social links have been updated",
      status: "success",
      variant: toastVariant,
    });
    fetchBuilder();
    setIsUpdatingSocials(false);
    onClose();
  };

  const handleUpdateReachedOutFlag = async reachedOut => {
    setIsUpdatingReachedOutFlag(true);

    let signMessage;
    try {
      signMessage = await getUpdateReachedOutFlagSignMessage(builder.id, reachedOut);
    } catch (error) {
      toast({
        description: " Sorry, the server is overloaded. ???",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    let signature;
    try {
      signature = await userProvider.send("personal_sign", [signMessage, address]);
    } catch (error) {
      toast({
        description: "Couldn't get a signature from the Wallet",
        status: "error",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    try {
      await postUpdateReachedOutFlag(address, builder.id, reachedOut, signature);
    } catch (error) {
      if (error.status === 401) {
        toast({
          status: "error",
          description: "Access error",
          variant: toastVariant,
        });
        setIsUpdatingReachedOutFlag(false);
        return;
      }
      toast({
        status: "error",
        description: "Can't update the reached out flag. Please try again.",
        variant: toastVariant,
      });
      setIsUpdatingReachedOutFlag(false);
      return;
    }

    toast({
      description: 'Updated "reached out" flag successfully',
      status: "success",
      variant: toastVariant,
    });
    fetchBuilder();
    setIsUpdatingReachedOutFlag(false);
  };

  return (
    <>
      <BuilderProfileCardSkeleton isLoaded={!!builder}>
        {() => (
          /* delay execution */
          <Flex
            borderRadius="lg"
            borderColor={borderColor}
            borderWidth={1}
            justify={{ base: "space-around", xl: "center" }}
            direction={{ base: "row", xl: "column" }}
            p={4}
            pb={6}
            maxW={{ base: "full", lg: "50%", xl: 60 }}
            margin="auto"
          >
            <Link as={RouteLink} to={`/builders/${builder.id}`}>
              <QRPunkBlockie
                withQr={false}
                address={builder.id?.toLowerCase()}
                w={52}
                borderRadius="lg"
                margin="auto"
              />
            </Link>
            <Flex alignContent="center" direction="column" mt={4}>
              {hasEns ? (
                <>
                  <Text fontSize="2xl" fontWeight="bold" textAlign="center">
                    {ens}
                  </Text>
                  <Text textAlign="center" mb={4} color={secondaryFontColor}>
                    {shortAddress}{" "}
                    <Tooltip label={hasCopied ? "Copied!" : "Copy"} closeOnClick={false}>
                      <CopyIcon cursor="pointer" onClick={onCopy} />
                    </Tooltip>
                  </Text>
                </>
              ) : (
                <Text fontSize="2xl" fontWeight="bold" textAlign="center" mb={8}>
                  {shortAddress}{" "}
                  <Tooltip label={hasCopied ? "Copied!" : "Copy"} closeOnClick={false}>
                    <CopyIcon cursor="pointer" onClick={onCopy} />
                  </Tooltip>
                </Text>
              )}
              {isAdmin && (
                <Center mb={4}>
                  {builder.reachedOut ? (
                    <Badge variant="outline" colorScheme="green" alignSelf="center">
                      Reached Out
                    </Badge>
                  ) : (
                    <Button
                      colorScheme="green"
                      size="xs"
                      onClick={() => handleUpdateReachedOutFlag(true)}
                      isLoading={isUpdatingReachedOutFlag}
                      alignSelf="center"
                    >
                      Mark as reached out
                    </Button>
                  )}
                </Center>
              )}
              <Divider mb={6} />
              {hasProfileLinks ? (
                <Flex mb={4} justifyContent="space-evenly" alignItems="center">
                  {Object.entries(builder.socialLinks)
                    .sort(bySocialWeight)
                    .map(([socialId, socialValue]) => (
                      <SocialLink id={socialId} value={socialValue} />
                    ))}
                </Flex>
              ) : (
                isMyProfile && (
                  <Alert mb={3} status="warning">
                    <Text style={{ fontSize: 11 }}>
                      You haven't set your socials{" "}
                      <Tooltip label="It's our way of reaching out to you. We could sponsor you an ENS, offer to be part of a build or set up an ETH stream for you.">
                        <QuestionOutlineIcon />
                      </Tooltip>
                    </Text>
                  </Alert>
                )
              )}
              {isMyProfile && (
                <Button mb={3} size="xs" variant="outline" onClick={onOpen}>
                  Update socials
                </Button>
              )}
              <Text textAlign="center" color={secondaryFontColor}>
                Joined {joinedDateDisplay}
              </Text>
            </Flex>
          </Flex>
        )}
      </BuilderProfileCardSkeleton>
      <Modal isOpen={isOpen} onClose={onClose}>
        <ModalOverlay />
        <ModalContent>
          <ModalHeader>Update your socials</ModalHeader>
          <ModalCloseButton />
          <ModalBody p={6}>
            {Object.entries(socials).map(([socialId, socialData]) => (
              <FormControl id="socialId" key={socialId} mb={3}>
                <FormLabel htmlFor={socialId} mb={0}>
                  <strong>{socialData.label}:</strong>
                </FormLabel>
                <Input
                  type="text"
                  name={socialId}
                  value={updatedSocials[socialId] ?? ""}
                  placeholder={socialData.placeholder}
                  onChange={e => {
                    const value = e.target.value;
                    setUpdatedSocials(prevSocials => ({
                      ...prevSocials,
                      [socialId]: value,
                    }));
                  }}
                />
              </FormControl>
            ))}
            <Button colorScheme="blue" onClick={handleUpdateSocials} isLoading={isUpdatingSocials} isFullWidth mt={4}>
              Update
            </Button>
          </ModalBody>
        </ModalContent>
      </Modal>
    </>
  );
}
Example #18
Source File: Targets.js    From web-client with Apache License 2.0 4 votes vote down vote up
ProjectTargets = ({ project }) => {
    const query = useQuery();
    const urlPageNumber = query.get('page') !== null ? parseInt(query.get('page')) : 1;
    const [pageNumber, setPageNumber] = useState(urlPageNumber);

    const [numberPages, setNumberPages] = useState(1);
    const [targets, setTargets] = useState([]);

    const { isOpen: isAddTargetDialogOpen, onOpen: openAddTargetDialog, onClose: closeAddTargetDialog } = useDisclosure();

    const onDeleteButtonClick = (ev, targetId) => {
        ev.preventDefault();

        secureApiFetch(`/targets/${targetId}`, { method: 'DELETE' })
            .then(() => {
                reloadTargets();
            })
    }

    const onTargetFormSaved = () => {
        reloadTargets();
        closeAddTargetDialog();
    }

    const reloadTargets = useCallback(() => {
        setTargets([]);

        secureApiFetch(`/targets?projectId=${project.id}&page=${pageNumber - 1}`, { method: 'GET' })
            .then(resp => {
                if (resp.headers.has('X-Page-Count')) {
                    setNumberPages(resp.headers.get('X-Page-Count'))
                }
                return resp.json()
            })
            .then(data => {
                setTargets(data);
            });
    }, [pageNumber, project]);

    const onPrevPageClick = () => {
        setPageNumber(pageNumber - 1);
    }
    const onNextPageClick = () => {
        setPageNumber(pageNumber + 1);
    }

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

    return <section>
        <h4>
            <IconServer />Targets
            <RestrictedComponent roles={['administrator', 'superuser', 'user']}>
                <ButtonGroup>
                    <TargetModalDialog project={project} isOpen={isAddTargetDialogOpen} onSubmit={onTargetFormSaved} onCancel={closeAddTargetDialog} />
                    <CreateButton onClick={openAddTargetDialog}>Add target...</CreateButton>
                </ButtonGroup>
            </RestrictedComponent>
        </h4>
        {!targets ? <Loading /> :
            <>
                {numberPages > 1 && <Center>
                    <Pagination page={pageNumber - 1} total={numberPages} handlePrev={onPrevPageClick} handleNext={onNextPageClick} />
                </Center>}
                <Table>
                    <Thead>
                        <Tr>
                            <Th>Name</Th>
                            <Th>Sub-target</Th>
                            <Th>Kind</Th>
                            <Th>Vulnerable?</Th>
                            <Th>&nbsp;</Th>
                        </Tr>
                    </Thead>
                    <Tbody>
                        {targets.length === 0 && <NoResultsTableRow numColumns={4} />}
                        {targets.map((target, index) =>
                            <Tr key={index}>
                                <Td>
                                    {target.parent_id === null &&
                                        <HStack>
                                            <Link to={`/targets/${target.id}`}><TargetBadge name={target.name} /></Link>
                                        </HStack>
                                    }
                                    {target.parent_id !== null &&
                                        <>{target.parent_name ?? '-'}</>
                                    }
                                </Td>
                                <Td>{target.parent_id !== null ?
                                    <>
                                        <Link to={`/targets/${target.id}`}><TargetBadge name={target.name} /></Link>
                                    </> : '-'}</Td>
                                <Td>{target.kind} <Tags values={target.tags} /></Td>
                                <Td>{target.num_vulnerabilities > 0 ? `Yes (${target.num_vulnerabilities} vulnerabilities found)` : "No"}</Td>
                                <Td>
                                    <RestrictedComponent roles={['administrator', 'superuser', 'user']}>
                                        <DeleteIconButton onClick={ev => onDeleteButtonClick(ev, target.id)} />
                                    </RestrictedComponent>
                                </Td>
                            </Tr>
                        )}
                    </Tbody>
                </Table>
            </>
        }
    </section>
}
Example #19
Source File: ConferenceCard.js    From codeursenseine.com with MIT License 4 votes vote down vote up
ConferenceCard = ({ conference, speakers }) => {
  const { isOpen, onOpen, onClose } = useDisclosure();

  const capitalizeFirstLetter = (string) =>
    string.charAt(0).toUpperCase() + string.slice(1);

  if (conference?.childMdx?.frontmatter?.type === "break") {
    return (
      <Card variant="primary" mt={2}>
        <Stack align="center">
          <Text>{conference?.childMdx?.frontmatter?.title}</Text>
        </Stack>
      </Card>
    );
  }

  return (
    <Stack>
      <Grid
        templateColumns={["repeat(1, 1fr)", "repeat(1, 1fr) repeat(1, 4fr)"]}
        mt={3}
      >
        <Stack mr={3}>
          <Flex
            display={["none", "flex"]}
            flexDirection="column"
            justifyContent="space-between"
            h="100%"
            borderColor="blue.50"
            borderStyle="solid"
            borderTopWidth={1}
            borderBottomWidth={1}
          >
            <Text color="blue.600">
              {conference.childMdx.frontmatter.startHour}
            </Text>

            <Text color="blue.600">
              {conference.childMdx.frontmatter.endHour}
            </Text>
          </Flex>
          <Stack display={["block", "none"]} mb={2}>
            <Text color="blue.600">
              {`${conference.childMdx.frontmatter.startHour} - ${conference.childMdx.frontmatter.endHour}`}
            </Text>
          </Stack>
          {conference.childMdx.frontmatter.isKeynote && (
            <Badge colorScheme="brand" width="fit-content">
              Keynote
            </Badge>
          )}
        </Stack>
        <Card
          borderLeftWidth={2}
          borderLeftColor="brand.600"
          onClick={onOpen}
          w="full"
          isLink
        >
          <Heading fontSize="md">
            {conference.childMdx.frontmatter.title}
          </Heading>

          {speakers?.map((speaker) => (
            <SpeakerPreview
              key={speaker.childMdx.frontmatter.slug}
              speaker={speaker}
            />
          ))}

          <Center>
            <Button
              colorScheme="brand"
              variant="link"
              width="fit-content"
              mt={2}
            >
              Voir les détails et s'inscrire
            </Button>
          </Center>
        </Card>
      </Grid>

      <Drawer size="md" isOpen={isOpen} placement="right" onClose={onClose}>
        <DrawerOverlay>
          <DrawerContent>
            <DrawerCloseButton />
            <DrawerHeader>
              <Stack alignItems="center" display="flex" flexDirection="row">
                <Text fontSize="sm" mt={2}>
                  {capitalizeFirstLetter(
                    dayjs(conference.childMdx.frontmatter.eventDate).format(
                      "dddd D MMM"
                    )
                  )}{" "}
                  {`${conference.childMdx.frontmatter.startHour} - ${conference.childMdx.frontmatter.endHour}`}
                </Text>
                {conference.childMdx.frontmatter.isKeynote && (
                  <Badge
                    ml={3}
                    h="fit-content"
                    colorScheme="brand"
                    width="fit-content"
                  >
                    Keynote
                  </Badge>
                )}
              </Stack>
              <Text>{conference.childMdx.frontmatter.title}</Text>

              <Stack mt={3}>
                {speakers?.map((speaker) => (
                  <SpeakerPreview
                    key={speaker.childMdx.frontmatter.slug}
                    speaker={speaker}
                  />
                ))}
              </Stack>
            </DrawerHeader>

            <DrawerBody overflow="auto">
              <MDXRenderer>{conference.childMdx.body}</MDXRenderer>
            </DrawerBody>

            {conference.childMdx.frontmatter.meetupLink && (
              <DrawerFooter display="flex" flexDirection="column">
                <Button isFullWidth variant="outline" mb={3} onClick={onClose}>
                  Fermer
                </Button>
                <Button
                  colorScheme="brand"
                  as={Link}
                  target="_blank"
                  to={conference.childMdx.frontmatter.meetupLink}
                  isFullWidth
                >
                  S'inscrire
                </Button>
              </DrawerFooter>
            )}
          </DrawerContent>
        </DrawerOverlay>
      </Drawer>
    </Stack>
  );
}
Example #20
Source File: components.js    From idena-web with MIT License 4 votes vote down vote up
export function ReplenishStakeDrawer({onSuccess, onError, ...props}) {
  const {t, i18n} = useTranslation()

  const [{state}] = useIdentity()

  const {coinbase} = useAuthState()

  const {data: balanceData} = useQuery({
    queryKey: ['get-balance', coinbase],
    queryFn: ({queryKey: [, address]}) => callRpc('dna_getBalance', address),
    enabled: Boolean(coinbase),
    staleTime: (BLOCK_TIME / 2) * 1000,
    notifyOnChangeProps: 'tracked',
  })

  const {submit} = useReplenishStake({onSuccess, onError})

  const formatDna = toLocaleDna(i18n.language, {
    maximumFractionDigits: 5,
  })

  const isRisky = [
    IdentityStatus.Candidate,
    IdentityStatus.Newbie,
    IdentityStatus.Verified,
  ].includes(state)

  return (
    <Drawer {...props}>
      <DrawerHeader>
        <Stack spacing="4">
          <Center bg="blue.012" h="12" w="12" rounded="xl">
            <WalletIcon boxSize="6" color="blue.500" />
          </Center>
          <Heading
            color="brandGray.500"
            fontSize="lg"
            fontWeight={500}
            lineHeight="base"
          >
            {t('Add stake')}
          </Heading>
        </Stack>
      </DrawerHeader>
      <DrawerBody fontSize="md">
        <Stack spacing={30}>
          <Stack>
            <Text>
              {t(
                'Get quadratic staking rewards for locking iDNA in your identity stake.'
              )}
            </Text>
            <Text>
              {t('Current stake amount: {{amount}}', {
                amount: formatDna(balanceData?.stake),
                nsSeparator: '!!',
              })}
            </Text>
          </Stack>
          <Stack spacing="2.5">
            <form
              id="replenishStake"
              onSubmit={e => {
                e.preventDefault()

                const formData = new FormData(e.target)

                const amount = formData.get('amount')

                submit({amount})
              }}
            >
              <FormControl>
                <FormLabel mx={0} mb="3">
                  {t('Amount')}
                </FormLabel>
                <DnaInput name="amount" />
                <FormHelperText fontSize="md">
                  <Flex justify="space-between">
                    <Box as="span" color="muted">
                      {t('Available')}
                    </Box>
                    <Box as="span">{formatDna(balanceData?.balance)}</Box>
                  </Flex>
                </FormHelperText>
              </FormControl>
            </form>
          </Stack>
          {isRisky && (
            <ErrorAlert>
              {state === IdentityStatus.Verified
                ? t(
                    'You will lose 100% of the Stake if you fail the upcoming validation'
                  )
                : t(
                    'You will lose 100% of the Stake if you fail or miss the upcoming validation'
                  )}
            </ErrorAlert>
          )}
        </Stack>
      </DrawerBody>
      <DrawerFooter>
        <HStack>
          <SecondaryButton onClick={props.onClose}>
            {t('Not now')}
          </SecondaryButton>
          <PrimaryButton form="replenishStake" type="submit">
            {t('Add stake')}
          </PrimaryButton>
        </HStack>
      </DrawerFooter>
    </Drawer>
  )
}
Example #21
Source File: components.js    From idena-web with MIT License 4 votes vote down vote up
// eslint-disable-next-line react/prop-types
export function KillForm({isOpen, onClose}) {
  const {t} = useTranslation()
  const {privateKey, coinbase} = useAuthState()
  const [, {killMe}] = useIdentity()
  const [submitting, setSubmitting] = useState(false)
  const toast = useToast()

  const [to, setTo] = useState()

  const {
    data: {stake},
  } = useQuery(['get-balance', coinbase], () => fetchBalance(coinbase), {
    initialData: {balance: 0, stake: 0},
    enabled: !!coinbase,
  })

  const terminate = async () => {
    try {
      if (to !== coinbase)
        throw new Error(t('You must specify your own identity address'))

      setSubmitting(true)

      await killMe(privateKey)

      toast({
        status: 'success',
        // eslint-disable-next-line react/display-name
        render: () => <Toast title={t('Transaction sent')} />,
      })
      if (onClose) onClose()
    } catch (error) {
      toast({
        // eslint-disable-next-line react/display-name
        render: () => (
          <Toast
            title={error?.message ?? t('Error while sending transaction')}
            status="error"
          />
        ),
      })
    } finally {
      setSubmitting(false)
    }
  }

  return (
    <Drawer isOpen={isOpen} onClose={onClose}>
      <DrawerHeader mb={6}>
        <Center flexDirection="column">
          <Avatar address={coinbase} />
          <Heading
            fontSize="lg"
            fontWeight={500}
            color="brandGray.500"
            mt={4}
            mb={0}
          >
            {t('Terminate identity')}
          </Heading>
        </Center>
      </DrawerHeader>
      <DrawerBody>
        <Text fontSize="md" mb={6}>
          {t(`Terminate your identity and withdraw the stake. Your identity status
            will be reset to 'Not validated'.`)}
        </Text>
        <FormControlWithLabel label={t('Withraw stake, iDNA')}>
          <Input value={stake} isDisabled />
        </FormControlWithLabel>
        <Text fontSize="md" mb={6} mt={6}>
          {t(
            'Please enter your identity address to confirm termination. Stake will be transferred to the identity address.'
          )}
        </Text>
        <FormControlWithLabel label={t('Address')}>
          <Input value={to} onChange={e => setTo(e.target.value)} />
        </FormControlWithLabel>
      </DrawerBody>
      <DrawerFooter>
        <HStack justify="flex-end">
          <PrimaryButton
            onClick={terminate}
            isLoading={submitting}
            colorScheme="red"
            _hover={{
              bg: 'rgb(227 60 60)',
            }}
            _active={{
              bg: 'rgb(227 60 60)',
            }}
            _focus={{
              boxShadow: '0 0 0 3px rgb(255 102 102 /0.50)',
            }}
          >
            {t('Terminate')}
          </PrimaryButton>
        </HStack>
      </DrawerFooter>
    </Drawer>
  )
}
Example #22
Source File: containers.js    From idena-web with MIT License 4 votes vote down vote up
export function ReviewAdDrawer({
  ad,
  onDeployContract,
  onStartVoting,
  ...props
}) {
  const {t} = useTranslation()

  const coinbase = useCoinbase()

  const balance = useBalance(coinbase)

  const failToast = useFailToast()

  const [isPending, {on: setIsPendingOn, off: setIsPendingOff}] = useBoolean()

  const {submit} = useReviewAd({
    onBeforeSubmit: setIsPendingOn,
    onDeployContract,
    onStartVoting: React.useCallback(
      data => {
        onStartVoting(data)
        setIsPendingOff()
      },
      [onStartVoting, setIsPendingOff]
    ),
    onError: React.useCallback(
      error => {
        failToast(error)
        setIsPendingOff()
      },
      [failToast, setIsPendingOff]
    ),
  })

  const {data: deployAmount} = useDeployContractAmount()

  const {data: startAmount} = useStartAdVotingAmount()

  const formatDna = useFormatDna({maximumFractionDigits: 5})

  return (
    <AdDrawer
      isMining={isPending}
      closeOnOverlayClick={!isPending}
      closeOnEsc={!isPending}
      isCloseable={!isPending}
      {...props}
    >
      <DrawerHeader>
        <Stack spacing={4}>
          <Center
            alignSelf="flex-start"
            bg="blue.012"
            w={12}
            minH={12}
            rounded="xl"
          >
            <OracleIcon boxSize={6} color="blue.500" />
          </Center>
          <Heading color="gray.500" fontSize="lg" fontWeight={500}>
            {t('Send to Oracle Voting')}
          </Heading>
        </Stack>
      </DrawerHeader>
      <DrawerBody overflowY="auto" mx={-6} mb={10}>
        <Stack spacing={6} color="gray.500" fontSize="md" p={6} pt={0}>
          <Stack spacing={3}>
            <Text>
              {t(`Please keep in mind that you will not be able to edit the banner
              after it has been submitted for verification`)}
            </Text>
          </Stack>
          <Stack spacing={6} bg="gray.50" p={6} rounded="lg">
            <Stack isInline spacing={5} align="flex-start">
              <AdImage src={adImageThumbSrc(ad)} w="10" />
              <Box>
                <Text fontWeight={500}>{ad.title}</Text>
                <ExternalLink href={ad.url} maxW="48">
                  {ad.url}
                </ExternalLink>
              </Box>
            </Stack>
            <Stack spacing={3}>
              <HDivider />
              <InlineAdStatGroup labelWidth="20">
                <SmallInlineAdStat label={t('Language')} value={ad.language} />
                <SmallInlineAdStat label={t('Min stake')} value={ad.stake} />
                <SmallInlineAdStat label={t('Min age')} value={ad.age} />
                <SmallInlineAdStat label={t('OS')} value={ad.os} />
              </InlineAdStatGroup>
            </Stack>
          </Stack>
          <form
            id="reviewForm"
            onSubmit={async e => {
              e.preventDefault()

              const {thumb, media} = await db.table('ads').get(ad.id)

              const errors = validateAd({...ad, thumb, media})

              if (Object.values(errors).some(Boolean)) {
                failToast({
                  title: t('Unable to send invalid ad'),
                  description: t(`Please check {{fields}} fields`, {
                    fields: Object.entries(errors)
                      .filter(([, v]) => Boolean(v))
                      .map(([k]) => k)
                      .join(', '),
                  }),
                })
                return
              }

              if (deployAmount && startAmount) {
                const requiredAmount = deployAmount + startAmount

                if (balance > requiredAmount) {
                  try {
                    submit({
                      ...ad,
                      thumb: new Uint8Array(
                        await compressAdImage(await thumb.arrayBuffer(), {
                          width: 80,
                          height: 80,
                          type: thumb.type,
                        })
                      ),
                      media: new Uint8Array(
                        await compressAdImage(await media.arrayBuffer(), {
                          width: 320,
                          height: 320,
                          type: thumb.type,
                        })
                      ),
                    })
                  } catch (error) {
                    failToast({
                      title: t('Error compressing images'),
                      description: error?.message,
                    })
                  }
                } else {
                  failToast(
                    t(
                      `Insufficient funds to start reviewing ad. Please deposit at least {{missingAmount}}.`,
                      {
                        missingAmount: formatDna(
                          Math.abs(balance - requiredAmount)
                        ),
                      }
                    )
                  )
                }
              }
            }}
          >
            <Stack spacing={4}>
              <FormControl isDisabled isReadOnly>
                <Stack spacing={3}>
                  <FormLabel htmlFor="stake" mb={0}>
                    {t('Min stake, iDNA')}
                  </FormLabel>
                  <Input defaultValue={deployAmount} />
                </Stack>
              </FormControl>
              <FormControl isDisabled isReadOnly>
                <Stack spacing={3}>
                  <FormLabel htmlFor="oracleFee" mb={0}>
                    {t('Review fee, iDNA')}
                  </FormLabel>
                  <Input defaultValue={startAmount} />
                </Stack>
              </FormControl>
            </Stack>
          </form>
        </Stack>
      </DrawerBody>
      <DrawerFooter bg="white">
        <PrimaryButton
          type="submit"
          form="reviewForm"
          isLoading={isPending}
          loadingText={t('Mining...')}
        >
          {t('Send')}
        </PrimaryButton>
      </DrawerFooter>
    </AdDrawer>
  )
}
Example #23
Source File: index.js    From UpStats with MIT License 4 votes vote down vote up
export default function Home({ status, systems, config }) {
  console.log(status);
  console.log(systems);
  const [email, setEmail] = useState("");
  const toast = useToast();
  const handleSubmit = async (email) => {
    try {
      await http.post("/subs", { email: email });
      toast({
        title: "Success",
        description: "Successfully Subscribed ",
        status: "success",
        duration: 9000,
        isClosable: true,
      });
    } catch (ex) {
      toast({
        title: "Error",
        description: "Submit Unsuccessful",
        status: "error",
        duration: 9000,
        isClosable: true,
      });
    }
  };
  return (
    <>
      <Head>
        <meta charSet="UTF-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, viewport-fit=cover"
        />
        <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
        <link rel="icon" href="/favicon.ico" type="image/x-icon" />
        <title>UP Stats</title>
        <link rel="stylesheet" href="/main.css" />
      </Head>
      <main className="root">
        <header className="top-0">
          <nav>
            <div className="content-center p-4">
              {/* Nav Bar Logo */}
              <img className="nav-brand" src="assets/img/logo.jpg" />
            </div>
          </nav>
        </header>
        <section>
          <Center mt="5">
            <Box bg="blue" w="90%" p={4} color="white" borderRadius="md">
              {status.operational
                ? "All Systems Operational"
                : `${status.outageCount} Systems Outage`}
            </Box>
          </Center>
          <br />
          <VStack>
            {systems.map((system) => (
              <Flex
                id={system._id}
                borderRadius="md"
                boxShadow="lg"
                w="90%"
                p={3}
                bg="white"
              >
                <Text pl={3}>{system.name}</Text>
                <Spacer />
                {system.status === "up" && (
                  <CheckCircleIcon mr={5} mt="1" color="green" />
                )}

                {system.status === "down" && (
                  <WarningIcon mr={5} mt="1" color="red" />
                )}
              </Flex>
            ))}
          </VStack>
        </section>
        {config.mailing ? (
          <VStack p={10} m={10} borderWidth={1} borderRadius="lg">
            <h1 className="font-sans text-xl">Want to see Back in action?</h1>
            <p className="font-sans">
              Subscribe via Email and <br />
              Get notified about the System Status
            </p>
            <Center>
              <FormControl id="email" width="90%">
                <FormLabel>Email address</FormLabel>
                <Input
                  type="email"
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                />
                <Box
                  width="8em"
                  mt="3"
                  height="3em"
                  border="1px"
                  color="white"
                  bg="blue"
                  borderRadius="lg"
                  p="3"
                  onClick={() => handleSubmit(email)}
                >
                  <EmailIcon mr={3} />
                  Subscribe
                </Box>
              </FormControl>
            </Center>
          </VStack>
        ) : (
          ""
        )}
        <footer className="px-4 py-16 mx-auto max-w-7xl">
          <nav className="grid grid-cols-2 gap-12 mb-12 md:grid-cols-3 lg:grid-cols-5">
            <div>
              <p className="mb-4 text-sm font-medium text-primary">
                Handy Links
              </p>
              <a
                className="flex mb-3 text-sm font-medium text-gray-700 transition md:mb-2 hover:text-primary"
                href="https://github.com/ToolsHD/UPStats"
              >
                Opensource
              </a>
              <a
                className="flex mb-3 text-sm font-medium text-gray-700 transition md:mb-2 hover:text-primary"
                href="#"
              >
                Features
              </a>
              <a
                className="flex mb-3 text-sm font-medium text-gray-700 transition md:mb-2 hover:text-primary"
                href="#"
              >
                Pricing
              </a>
            </div>
          </nav>
          <div className="flex flex-col items-center justify-between md:flex-row">
            <a href="/" className="mb-4 md:mb-0">
              <img id="footer-img" src="assets/img/footer.jpg" />
              <span className="sr-only">UpStats</span>
            </a>
            <p className="text-sm text-center text-gray-600 md:text-left">
              © 2021 <a href="#">UP Stats</a>
            </p>
          </div>
        </footer>
        <div>
          <button onClick="topFunction()" id="scroll-to-top">
            <svg
              xmlns="http://www.w3.org/2000/svg"
              className="h-6 w-6"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth={2}
                d="M5 10l7-7m0 0l7 7m-7-7v18"
              />
            </svg>
          </button>
        </div>
      </main>
    </>
  );
}